diff --git a/DEPS b/DEPS
index 6a11fcf..dae274ce 100644
--- a/DEPS
+++ b/DEPS
@@ -40,11 +40,11 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling Skia
   # and whatever else without interference from each other.
-  'skia_revision': 'a0481b9f3fe41ac5cb1ea9eb6bd55b0e38661434',
+  'skia_revision': '6e834799946537370e6f3c10aa2745ed969b2a27',
   # 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': '87d4ee8cfb0bdc2b30aab32c8bbdc00e65c16397',
+  'v8_revision': 'a8190a51525dd6f0a74eba767d41e2f822b25054',
   # 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': '2f8fce497d967c866ae866d36cdc08d2bfa30ff7',
+  'catapult_revision': 'c48d544fa6f7ae1b22e0046be83eecd084690ae0',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libFuzzer
   # and whatever else without interference from each other.
@@ -493,7 +493,7 @@
       Var('chromium_git') + '/external/mockito/mockito.git' + '@' + 'de83ad4598ad4cf5ea53c69a8a8053780b04b850',
 
     'src/third_party/netty-tcnative/src':
-      Var('chromium_git') + '/external/netty-tcnative.git' + '@' + '2e0f9503f3d4efe6fc3f70077f22471e83ffb446',
+      Var('chromium_git') + '/external/netty-tcnative.git' + '@' + '2a25ec75d6889d32594a6f8b4d42962c15255d76',
 
     'src/third_party/netty4/src':
       Var('chromium_git') + '/external/netty4.git' + '@' + 'e0f26303b4ce635365be19414d0ac81f2ef6ba3c',
diff --git a/android_webview/browser/net/android_stream_reader_url_request_job.cc b/android_webview/browser/net/android_stream_reader_url_request_job.cc
index 820dc64..0140fa1 100644
--- a/android_webview/browser/net/android_stream_reader_url_request_job.cc
+++ b/android_webview/browser/net/android_stream_reader_url_request_job.cc
@@ -349,12 +349,6 @@
   NotifyHeadersComplete();
 }
 
-int AndroidStreamReaderURLRequestJob::GetResponseCode() const {
-  if (response_info_)
-    return response_info_->headers->response_code();
-  return URLRequestJob::GetResponseCode();
-}
-
 void AndroidStreamReaderURLRequestJob::GetResponseInfo(
     net::HttpResponseInfo* info) {
   if (response_info_)
diff --git a/android_webview/browser/net/android_stream_reader_url_request_job.h b/android_webview/browser/net/android_stream_reader_url_request_job.h
index 2ed14415..1053f27 100644
--- a/android_webview/browser/net/android_stream_reader_url_request_job.h
+++ b/android_webview/browser/net/android_stream_reader_url_request_job.h
@@ -100,7 +100,6 @@
   void SetExtraRequestHeaders(const net::HttpRequestHeaders& headers) override;
   bool GetMimeType(std::string* mime_type) const override;
   bool GetCharset(std::string* charset) override;
-  int GetResponseCode() const override;
   void GetResponseInfo(net::HttpResponseInfo* info) override;
 
  protected:
diff --git a/android_webview/glue/java/src/com/android/webview/chromium/WebViewChromiumFactoryProvider.java b/android_webview/glue/java/src/com/android/webview/chromium/WebViewChromiumFactoryProvider.java
index 0f3ab07..490a83f 100644
--- a/android_webview/glue/java/src/com/android/webview/chromium/WebViewChromiumFactoryProvider.java
+++ b/android_webview/glue/java/src/com/android/webview/chromium/WebViewChromiumFactoryProvider.java
@@ -401,13 +401,10 @@
         PathService.override(PathService.DIR_MODULE, "/system/lib/");
         PathService.override(DIR_RESOURCE_PAKS_ANDROID, "/system/framework/webview/paks");
 
-        final Context context = ContextUtils.getApplicationContext();
-        // Future calls to PlatformServiceBridge.getInstance() rely on it having been created here.
-        PlatformServiceBridge.getOrCreateInstance();
-
         // Make sure that ResourceProvider is initialized before starting the browser process.
         final PackageInfo webViewPackageInfo = WebViewFactory.getLoadedPackageInfo();
         final String webViewPackageName = webViewPackageInfo.packageName;
+        final Context context = ContextUtils.getApplicationContext();
         setUpResources(webViewPackageInfo, context);
         initPlatSupportLibrary();
         doNetworkInitializations(context);
diff --git a/android_webview/java/src/org/chromium/android_webview/PlatformServiceBridge.java b/android_webview/java/src/org/chromium/android_webview/PlatformServiceBridge.java
index 7957e96e..1356aa4 100644
--- a/android_webview/java/src/org/chromium/android_webview/PlatformServiceBridge.java
+++ b/android_webview/java/src/org/chromium/android_webview/PlatformServiceBridge.java
@@ -4,10 +4,8 @@
 
 package org.chromium.android_webview;
 
-import android.content.Context;
 import android.webkit.ValueCallback;
 
-import org.chromium.base.ContextUtils;
 import org.chromium.base.Log;
 import org.chromium.base.ThreadUtils;
 
@@ -22,53 +20,44 @@
     private static final String PLATFORM_SERVICE_BRIDGE =
             "com.android.webview.chromium.PlatformServiceBridgeGoogle";
 
-    // Only written by getOrCreateInstance on the UI thread (aside from injectInstance, for
-    // testing), but read by getInstance on arbitrary threads.
-    private static volatile PlatformServiceBridge sInstance;
+    private static PlatformServiceBridge sInstance;
+    private static final Object sInstanceLock = new Object();
 
     protected PlatformServiceBridge() {}
 
-    public static PlatformServiceBridge getOrCreateInstance() {
-        // Just to avoid race conditions on sInstance - nothing special about the UI thread.
-        ThreadUtils.assertOnUiThread();
-
-        if (sInstance != null) return sInstance;
-
-        // Try to get a specialized service bridge.
-        try {
-            Class<?> cls = Class.forName(PLATFORM_SERVICE_BRIDGE);
-            sInstance = (PlatformServiceBridge) cls.getDeclaredConstructor(Context.class)
-                                .newInstance(ContextUtils.getApplicationContext());
-            return sInstance;
-        } catch (ClassNotFoundException e) {
-            // This is not an error; it just means this device doesn't have specialized
-            // services.
-        } catch (IllegalAccessException | IllegalArgumentException | InstantiationException
-                | NoSuchMethodException e) {
-            Log.e(TAG, "Failed to get " + PLATFORM_SERVICE_BRIDGE + ": " + e);
-        } catch (InvocationTargetException e) {
-            Log.e(TAG, "Failed invocation to get " + PLATFORM_SERVICE_BRIDGE + ":", e.getCause());
-        }
-
-        // Otherwise, get the generic service bridge.
-        sInstance = new PlatformServiceBridge();
-
-        return sInstance;
-    }
-
     public static PlatformServiceBridge getInstance() {
-        if (sInstance == null) throw new IllegalStateException("PlatformServiceBridge not created");
-        return sInstance;
+        synchronized (sInstanceLock) {
+            if (sInstance != null) return sInstance;
+
+            // Try to get a specialized service bridge.
+            try {
+                Class<?> cls = Class.forName(PLATFORM_SERVICE_BRIDGE);
+                sInstance = (PlatformServiceBridge) cls.getDeclaredConstructor().newInstance();
+                return sInstance;
+            } catch (ClassNotFoundException e) {
+                // This is not an error; it just means this device doesn't have specialized
+                // services.
+            } catch (IllegalAccessException | IllegalArgumentException | InstantiationException
+                    | NoSuchMethodException e) {
+                Log.e(TAG, "Failed to get " + PLATFORM_SERVICE_BRIDGE + ": " + e);
+            } catch (InvocationTargetException e) {
+                Log.e(TAG, "Failed invocation to get " + PLATFORM_SERVICE_BRIDGE + ": ",
+                        e.getCause());
+            }
+
+            // Otherwise, get the generic service bridge.
+            sInstance = new PlatformServiceBridge();
+            return sInstance;
+        }
     }
 
     // Provide a mocked PlatformServiceBridge for testing.
     public static void injectInstance(PlatformServiceBridge testBridge) {
-        sInstance = testBridge;
-    }
-
-    // TODO(paulmiller): Remove after changing downstream users.
-    public static PlatformServiceBridge getInstance(Context context) {
-        return getInstance();
+        // Although reference assignments are atomic, we still wouldn't want to assign it in the
+        // middle of getInstance().
+        synchronized (sInstanceLock) {
+            sInstance = testBridge;
+        }
     }
 
     // Can WebView use Google Play Services (a.k.a. GMS)?
diff --git a/android_webview/java/src/org/chromium/android_webview/crash/AwMinidumpUploaderDelegate.java b/android_webview/java/src/org/chromium/android_webview/crash/AwMinidumpUploaderDelegate.java
index deeceede..2e373c6a 100644
--- a/android_webview/java/src/org/chromium/android_webview/crash/AwMinidumpUploaderDelegate.java
+++ b/android_webview/java/src/org/chromium/android_webview/crash/AwMinidumpUploaderDelegate.java
@@ -76,14 +76,13 @@
 
     @Override
     public void prepareToUploadMinidumps(final Runnable startUploads) {
-        PlatformServiceBridge.getOrCreateInstance().queryMetricsSetting(
-                new ValueCallback<Boolean>() {
-                    public void onReceiveValue(Boolean enabled) {
-                        ThreadUtils.assertOnUiThread();
-                        mPermittedByUser = enabled;
-                        startUploads.run();
-                    }
-                });
+        PlatformServiceBridge.getInstance().queryMetricsSetting(new ValueCallback<Boolean>() {
+            public void onReceiveValue(Boolean enabled) {
+                ThreadUtils.assertOnUiThread();
+                mPermittedByUser = enabled;
+                startUploads.run();
+            }
+        });
     }
 
     @Override
diff --git a/ash/accelerators/accelerator_controller_unittest.cc b/ash/accelerators/accelerator_controller_unittest.cc
index bcda4b6..955d304 100644
--- a/ash/accelerators/accelerator_controller_unittest.cc
+++ b/ash/accelerators/accelerator_controller_unittest.cc
@@ -21,7 +21,6 @@
 #include "ash/test/lock_state_controller_test_api.h"
 #include "ash/test/test_screenshot_delegate.h"
 #include "ash/test/test_session_state_animator.h"
-#include "ash/test/test_shelf_delegate.h"
 #include "ash/wm/lock_state_controller.h"
 #include "ash/wm/panels/panel_layout_manager.h"
 #include "ash/wm/window_positioning_utils.h"
@@ -255,14 +254,6 @@
   static bool is_exiting(ExitWarningHandler* ewh) {
     return ewh->state_ == ExitWarningHandler::EXITING;
   }
-  aura::Window* CreatePanel() {
-    aura::Window* window = CreateTestWindowInShellWithDelegateAndType(
-        NULL, ui::wm::WINDOW_TYPE_PANEL, 0, gfx::Rect(5, 5, 20, 20));
-    WmWindow* wm_window = WmWindow::Get(window);
-    test::TestShelfDelegate::instance()->AddShelfItem(wm_window);
-    PanelLayoutManager::Get(wm_window)->Relayout();
-    return window;
-  }
 
   void SetBrightnessControlDelegate(
       std::unique_ptr<BrightnessControlDelegate> delegate) {
diff --git a/ash/aura/DEPS b/ash/aura/DEPS
index 05abc5f..d6ccbabd 100644
--- a/ash/aura/DEPS
+++ b/ash/aura/DEPS
@@ -1,5 +1,6 @@
 specific_include_rules = {
   "shell_port_classic.cc": [
+    "+ash/host/ash_window_tree_host.h",
     "+ash/host/ash_window_tree_host_init_params.h"
   ],
 }
diff --git a/ash/aura/shell_port_classic.cc b/ash/aura/shell_port_classic.cc
index 9d87e86..e5e9760 100644
--- a/ash/aura/shell_port_classic.cc
+++ b/ash/aura/shell_port_classic.cc
@@ -11,6 +11,7 @@
 #include "ash/aura/key_event_watcher_aura.h"
 #include "ash/aura/pointer_watcher_adapter.h"
 #include "ash/display/window_tree_host_manager.h"
+#include "ash/host/ash_window_tree_host.h"
 #include "ash/host/ash_window_tree_host_init_params.h"
 #include "ash/keyboard/keyboard_ui.h"
 #include "ash/laser/laser_pointer_controller.h"
@@ -37,6 +38,7 @@
 #include "base/memory/ptr_util.h"
 #include "ui/aura/env.h"
 #include "ui/display/manager/display_manager.h"
+#include "ui/display/types/native_display_delegate.h"
 
 #if defined(USE_X11)
 #include "ash/wm/maximize_mode/scoped_disable_internal_mouse_and_keyboard_x11.h"
@@ -44,6 +46,8 @@
 
 #if defined(USE_OZONE)
 #include "ash/wm/maximize_mode/scoped_disable_internal_mouse_and_keyboard_ozone.h"
+#include "ui/display/types/native_display_delegate.h"
+#include "ui/ozone/public/ozone_platform.h"
 #endif
 
 namespace ash {
@@ -239,6 +243,12 @@
   pointer_watcher_adapter_ = base::MakeUnique<PointerWatcherAdapter>();
 }
 
+std::unique_ptr<AshWindowTreeHost> ShellPortClassic::CreateAshWindowTreeHost(
+    const AshWindowTreeHostInitParams& init_params) {
+  // A return value of null results in falling back to the default.
+  return nullptr;
+}
+
 void ShellPortClassic::CreatePrimaryHost() {
   Shell::Get()->window_tree_host_manager()->Start();
   AshWindowTreeHostInitParams ash_init_params;
@@ -249,6 +259,15 @@
   Shell::Get()->window_tree_host_manager()->InitHosts();
 }
 
+std::unique_ptr<display::NativeDisplayDelegate>
+ShellPortClassic::CreateNativeDisplayDelegate() {
+#if defined(USE_OZONE)
+  return ui::OzonePlatform::GetInstance()->CreateNativeDisplayDelegate();
+#else
+  return nullptr;
+#endif
+}
+
 std::unique_ptr<AcceleratorController>
 ShellPortClassic::CreateAcceleratorController() {
   DCHECK(!accelerator_controller_delegate_);
diff --git a/ash/aura/shell_port_classic.h b/ash/aura/shell_port_classic.h
index b5c7704..1a848d6 100644
--- a/ash/aura/shell_port_classic.h
+++ b/ash/aura/shell_port_classic.h
@@ -78,8 +78,12 @@
   void SetLaserPointerEnabled(bool enabled) override;
   void SetPartialMagnifierEnabled(bool enabled) override;
   void CreatePointerWatcherAdapter() override;
+  std::unique_ptr<AshWindowTreeHost> CreateAshWindowTreeHost(
+      const AshWindowTreeHostInitParams& init_params) override;
   void CreatePrimaryHost() override;
   void InitHosts(const ShellInitParams& init_params) override;
+  std::unique_ptr<display::NativeDisplayDelegate> CreateNativeDisplayDelegate()
+      override;
   std::unique_ptr<AcceleratorController> CreateAcceleratorController() override;
 
  private:
diff --git a/ash/devtools/ash_devtools_css_agent.cc b/ash/devtools/ash_devtools_css_agent.cc
index 45ac073..84c65d7 100644
--- a/ash/devtools/ash_devtools_css_agent.cc
+++ b/ash/devtools/ash_devtools_css_agent.cc
@@ -4,9 +4,9 @@
 
 #include "ash/devtools/ash_devtools_css_agent.h"
 
-#include "ash/wm_window.h"
 #include "base/strings/string_split.h"
 #include "base/strings/string_util.h"
+#include "ui/aura/window.h"
 
 namespace ash {
 namespace devtools {
@@ -163,7 +163,7 @@
   return ui::devtools::protocol::Response::OK();
 }
 
-void AshDevToolsCSSAgent::OnWindowBoundsChanged(WmWindow* window) {
+void AshDevToolsCSSAgent::OnWindowBoundsChanged(aura::Window* window) {
   InvalidateStyleSheet(dom_agent_->GetNodeIdFromWindow(window));
 }
 
@@ -192,9 +192,9 @@
 bool AshDevToolsCSSAgent::GetPropertiesForNodeId(int node_id,
                                                  gfx::Rect* bounds,
                                                  bool* visible) {
-  WmWindow* window = dom_agent_->GetWindowFromNodeId(node_id);
+  aura::Window* window = dom_agent_->GetWindowFromNodeId(node_id);
   if (window) {
-    *bounds = window->GetBounds();
+    *bounds = window->bounds();
     *visible = window->IsVisible();
     return true;
   }
@@ -216,7 +216,7 @@
 bool AshDevToolsCSSAgent::SetPropertiesForNodeId(int node_id,
                                                  const gfx::Rect& bounds,
                                                  bool visible) {
-  WmWindow* window = dom_agent_->GetWindowFromNodeId(node_id);
+  aura::Window* window = dom_agent_->GetWindowFromNodeId(node_id);
   if (window) {
     window->SetBounds(bounds);
     if (visible != window->IsVisible()) {
diff --git a/ash/devtools/ash_devtools_css_agent.h b/ash/devtools/ash_devtools_css_agent.h
index c4427623..f4027ed0 100644
--- a/ash/devtools/ash_devtools_css_agent.h
+++ b/ash/devtools/ash_devtools_css_agent.h
@@ -35,7 +35,7 @@
           result) override;
 
   // AshDevToolsDOMAgentObserver
-  void OnWindowBoundsChanged(WmWindow* window) override;
+  void OnWindowBoundsChanged(aura::Window* window) override;
   void OnWidgetBoundsChanged(views::Widget* widget) override;
   void OnViewBoundsChanged(views::View* view) override;
 
diff --git a/ash/devtools/ash_devtools_dom_agent.cc b/ash/devtools/ash_devtools_dom_agent.cc
index 3734a76..00272f5 100644
--- a/ash/devtools/ash_devtools_dom_agent.cc
+++ b/ash/devtools/ash_devtools_dom_agent.cc
@@ -7,12 +7,13 @@
 #include "ash/public/cpp/shell_window_ids.h"
 #include "ash/root_window_controller.h"
 #include "ash/shell.h"
-#include "ash/wm_window.h"
 #include "components/ui_devtools/devtools_server.h"
 #include "third_party/skia/include/core/SkColor.h"
+#include "ui/aura/window.h"
 #include "ui/display/display.h"
 #include "ui/views/background.h"
 #include "ui/views/border.h"
+#include "ui/wm/core/window_util.h"
 
 namespace ash {
 namespace devtools {
@@ -38,12 +39,12 @@
   return node;
 }
 
-std::unique_ptr<Array<std::string>> GetAttributes(const ash::WmWindow* window) {
+std::unique_ptr<Array<std::string>> GetAttributes(const aura::Window* window) {
   std::unique_ptr<Array<std::string>> attributes = Array<std::string>::create();
   attributes->addItem("name");
-  attributes->addItem(window->aura_window()->GetName());
+  attributes->addItem(window->GetName());
   attributes->addItem("active");
-  attributes->addItem(window->IsActive() ? "true" : "false");
+  attributes->addItem(::wm::IsActiveWindow(window) ? "true" : "false");
   return attributes;
 }
 
@@ -63,10 +64,9 @@
   return attributes;
 }
 
-WmWindow* FindPreviousSibling(WmWindow* window) {
-  std::vector<WmWindow*> siblings = window->GetParent()->GetChildren();
-  std::vector<WmWindow*>::iterator it =
-      std::find(siblings.begin(), siblings.end(), window);
+aura::Window* FindPreviousSibling(aura::Window* window) {
+  const aura::Window::Windows& siblings = window->parent()->children();
+  auto it = std::find(siblings.begin(), siblings.end(), window);
   DCHECK(it != siblings.end());
   // If this is the first child of its parent, the previous sibling is null
   return it == siblings.begin() ? nullptr : *std::prev(it);
@@ -99,8 +99,8 @@
                         MaskColor(rgba->getB()));
 }
 
-views::Widget* GetWidgetFromWmWindow(WmWindow* window) {
-  return views::Widget::GetWidgetForNativeView(window->aura_window());
+views::Widget* GetWidgetFromWindow(aura::Window* window) {
+  return views::Widget::GetWidgetForNativeView(window);
 }
 
 }  // namespace
@@ -146,7 +146,7 @@
   // Finally, We only trigger this  0 or 1 times as an old_parent will
   // either exist and only call this callback once, or not at all.
   if (params.receiver == params.old_parent)
-    RemoveWindowTree(WmWindow::Get(params.target), true);
+    RemoveWindowTree(params.target, true);
 }
 
 // Handles adding windows.
@@ -158,19 +158,19 @@
   // new_parent. If there is only a new_parent, OnWindowHierarchyChanging is
   // never called and the window is only added here.
   if (params.receiver == params.new_parent)
-    AddWindowTree(WmWindow::Get(params.target));
+    AddWindowTree(params.target);
 }
 
 void AshDevToolsDOMAgent::OnWindowStackingChanged(aura::Window* window) {
-  RemoveWindowTree(WmWindow::Get(window), false);
-  AddWindowTree(WmWindow::Get(window));
+  RemoveWindowTree(window, false);
+  AddWindowTree(window);
 }
 
 void AshDevToolsDOMAgent::OnWindowBoundsChanged(aura::Window* window,
                                                 const gfx::Rect& old_bounds,
                                                 const gfx::Rect& new_bounds) {
   for (auto& observer : observers_)
-    observer.OnWindowBoundsChanged(WmWindow::Get(window));
+    observer.OnWindowBoundsChanged(window);
 }
 
 void AshDevToolsDOMAgent::OnWillRemoveView(views::Widget* widget,
@@ -206,7 +206,7 @@
     observer.OnViewBoundsChanged(view);
 }
 
-WmWindow* AshDevToolsDOMAgent::GetWindowFromNodeId(int nodeId) {
+aura::Window* AshDevToolsDOMAgent::GetWindowFromNodeId(int nodeId) {
   return node_id_to_window_map_.count(nodeId) ? node_id_to_window_map_[nodeId]
                                               : nullptr;
 }
@@ -221,7 +221,7 @@
                                             : nullptr;
 }
 
-int AshDevToolsDOMAgent::GetNodeIdFromWindow(WmWindow* window) {
+int AshDevToolsDOMAgent::GetNodeIdFromWindow(aura::Window* window) {
   DCHECK(window_to_node_id_map_.count(window));
   return window_to_node_id_map_[window];
 }
@@ -249,26 +249,26 @@
 AshDevToolsDOMAgent::BuildInitialTree() {
   std::unique_ptr<Array<DOM::Node>> children = Array<DOM::Node>::create();
   for (aura::Window* window : Shell::GetAllRootWindows())
-    children->addItem(BuildTreeForWindow(WmWindow::Get(window)));
+    children->addItem(BuildTreeForWindow(window));
   return BuildNode("root", nullptr, std::move(children));
 }
 
 std::unique_ptr<DOM::Node> AshDevToolsDOMAgent::BuildTreeForWindow(
-    ash::WmWindow* window) {
+    aura::Window* window) {
   DCHECK(!window_to_node_id_map_.count(window));
   std::unique_ptr<Array<DOM::Node>> children = Array<DOM::Node>::create();
-  views::Widget* widget = GetWidgetFromWmWindow(window);
+  views::Widget* widget = GetWidgetFromWindow(window);
   if (widget)
     children->addItem(BuildTreeForRootWidget(widget));
-  for (ash::WmWindow* child : window->GetChildren()) {
+  for (aura::Window* child : window->children()) {
     if (!IsHighlightingWindow(child))
       children->addItem(BuildTreeForWindow(child));
   }
 
   std::unique_ptr<ui::devtools::protocol::DOM::Node> node =
       BuildNode("Window", GetAttributes(window), std::move(children));
-  if (!window->aura_window()->HasObserver(this))
-    window->aura_window()->AddObserver(this);
+  if (!window->HasObserver(this))
+    window->AddObserver(this);
   window_to_node_id_map_[window] = node->getNodeId();
   node_id_to_window_map_[node->getNodeId()] = window;
   return node;
@@ -303,48 +303,48 @@
   return node;
 }
 
-void AshDevToolsDOMAgent::AddWindowTree(WmWindow* window) {
+void AshDevToolsDOMAgent::AddWindowTree(aura::Window* window) {
   if (IsHighlightingWindow(window))
     return;
 
-  DCHECK(window_to_node_id_map_.count(window->GetParent()));
-  WmWindow* prev_sibling = FindPreviousSibling(window);
+  DCHECK(window_to_node_id_map_.count(window->parent()));
+  aura::Window* prev_sibling = FindPreviousSibling(window);
   frontend()->childNodeInserted(
-      window_to_node_id_map_[window->GetParent()],
+      window_to_node_id_map_[window->parent()],
       prev_sibling ? window_to_node_id_map_[prev_sibling] : 0,
       BuildTreeForWindow(window));
 }
 
-void AshDevToolsDOMAgent::RemoveWindowTree(WmWindow* window,
+void AshDevToolsDOMAgent::RemoveWindowTree(aura::Window* window,
                                            bool remove_observer) {
   DCHECK(window);
   if (IsHighlightingWindow(window))
     return;
 
-  if (GetWidgetFromWmWindow(window))
-    RemoveWidgetTree(GetWidgetFromWmWindow(window), remove_observer);
+  if (GetWidgetFromWindow(window))
+    RemoveWidgetTree(GetWidgetFromWindow(window), remove_observer);
 
-  for (ash::WmWindow* child : window->GetChildren())
+  for (aura::Window* child : window->children())
     RemoveWindowTree(child, remove_observer);
 
   RemoveWindowNode(window, remove_observer);
 }
 
-void AshDevToolsDOMAgent::RemoveWindowNode(WmWindow* window,
+void AshDevToolsDOMAgent::RemoveWindowNode(aura::Window* window,
                                            bool remove_observer) {
   WindowToNodeIdMap::iterator window_to_node_id_it =
       window_to_node_id_map_.find(window);
   DCHECK(window_to_node_id_it != window_to_node_id_map_.end());
 
   int node_id = window_to_node_id_it->second;
-  int parent_id = GetNodeIdFromWindow(window->GetParent());
+  int parent_id = GetNodeIdFromWindow(window->parent());
 
   NodeIdToWindowMap::iterator node_id_to_window_it =
       node_id_to_window_map_.find(node_id);
   DCHECK(node_id_to_window_it != node_id_to_window_map_.end());
 
   if (remove_observer)
-    window->aura_window()->RemoveObserver(this);
+    window->RemoveObserver(this);
 
   node_id_to_window_map_.erase(node_id_to_window_it);
   window_to_node_id_map_.erase(window_to_node_id_it);
@@ -366,7 +366,7 @@
   DCHECK(widget_to_node_id_it != widget_to_node_id_map_.end());
 
   int node_id = widget_to_node_id_it->second;
-  int parent_id = GetNodeIdFromWindow(WmWindow::Get(widget->GetNativeWindow()));
+  int parent_id = GetNodeIdFromWindow(widget->GetNativeWindow());
 
   if (remove_observer)
     widget->RemoveRemovalsObserver(this);
@@ -426,7 +426,7 @@
 
 void AshDevToolsDOMAgent::RemoveObservers() {
   for (auto& pair : window_to_node_id_map_)
-    pair.first->aura_window()->RemoveObserver(this);
+    pair.first->RemoveObserver(this);
   for (auto& pair : widget_to_node_id_map_)
     pair.first->RemoveRemovalsObserver(this);
   for (auto& pair : view_to_node_id_map_)
@@ -447,21 +447,20 @@
 
 AshDevToolsDOMAgent::WindowAndBoundsPair
 AshDevToolsDOMAgent::GetNodeWindowAndBounds(int node_id) {
-  WmWindow* window = GetWindowFromNodeId(node_id);
+  aura::Window* window = GetWindowFromNodeId(node_id);
   if (window)
     return std::make_pair(window, window->GetBoundsInScreen());
 
   views::Widget* widget = GetWidgetFromNodeId(node_id);
   if (widget) {
-    return std::make_pair(WmWindow::Get(widget->GetNativeWindow()),
+    return std::make_pair(widget->GetNativeWindow(),
                           widget->GetWindowBoundsInScreen());
   }
 
   views::View* view = GetViewFromNodeId(node_id);
   if (view) {
     gfx::Rect bounds = view->GetBoundsInScreen();
-    return std::make_pair(WmWindow::Get(view->GetWidget()->GetNativeWindow()),
-                          bounds);
+    return std::make_pair(view->GetWidget()->GetNativeWindow(), bounds);
   }
 
   return std::make_pair(nullptr, gfx::Rect());
@@ -494,9 +493,11 @@
   root_view->SetBorder(views::CreateSolidBorder(kBorderThickness, border));
   root_view->set_background(
       views::Background::CreateSolidBackground(background));
-  WmWindow::Get(widget_for_highlighting_->GetNativeWindow())
-      ->SetBoundsInScreen(window_and_bounds.second,
-                          window_and_bounds.first->GetDisplayNearestWindow());
+  display::Display display =
+      display::Screen::GetScreen()->GetDisplayNearestWindow(
+          window_and_bounds.first);
+  widget_for_highlighting_->GetNativeWindow()->SetBoundsInScreen(
+      window_and_bounds.second, display);
 }
 
 ui::devtools::protocol::Response AshDevToolsDOMAgent::HighlightNode(
@@ -524,9 +525,9 @@
   return ui::devtools::protocol::Response::OK();
 }
 
-bool AshDevToolsDOMAgent::IsHighlightingWindow(WmWindow* window) {
+bool AshDevToolsDOMAgent::IsHighlightingWindow(aura::Window* window) {
   return widget_for_highlighting_ &&
-         GetWidgetFromWmWindow(window) == widget_for_highlighting_.get();
+         GetWidgetFromWindow(window) == widget_for_highlighting_.get();
 }
 
 }  // namespace devtools
diff --git a/ash/devtools/ash_devtools_dom_agent.h b/ash/devtools/ash_devtools_dom_agent.h
index 12d2812..80e2404 100644
--- a/ash/devtools/ash_devtools_dom_agent.h
+++ b/ash/devtools/ash_devtools_dom_agent.h
@@ -17,15 +17,17 @@
 #include "ui/views/widget/widget_observer.h"
 #include "ui/views/widget/widget_removals_observer.h"
 
-namespace ash {
+namespace aura {
+class Window;
+}
 
-class WmWindow;
+namespace ash {
 
 namespace devtools {
 
 class ASH_EXPORT AshDevToolsDOMAgentObserver {
  public:
-  virtual void OnWindowBoundsChanged(WmWindow* window) {}
+  virtual void OnWindowBoundsChanged(aura::Window* window) {}
   virtual void OnWidgetBoundsChanged(views::Widget* widget) {}
   virtual void OnViewBoundsChanged(views::View* view) {}
 };
@@ -72,11 +74,11 @@
   void OnChildViewReordered(views::View* parent, views::View*) override;
   void OnViewBoundsChanged(views::View* view) override;
 
-  WmWindow* GetWindowFromNodeId(int nodeId);
+  aura::Window* GetWindowFromNodeId(int nodeId);
   views::Widget* GetWidgetFromNodeId(int nodeId);
   views::View* GetViewFromNodeId(int nodeId);
 
-  int GetNodeIdFromWindow(WmWindow* window);
+  int GetNodeIdFromWindow(aura::Window* window);
   int GetNodeIdFromWidget(views::Widget* widget);
   int GetNodeIdFromView(views::View* view);
 
@@ -86,19 +88,19 @@
  private:
   std::unique_ptr<ui::devtools::protocol::DOM::Node> BuildInitialTree();
   std::unique_ptr<ui::devtools::protocol::DOM::Node> BuildTreeForWindow(
-      WmWindow* window);
+      aura::Window* window);
   std::unique_ptr<ui::devtools::protocol::DOM::Node> BuildTreeForRootWidget(
       views::Widget* widget);
   std::unique_ptr<ui::devtools::protocol::DOM::Node> BuildTreeForView(
       views::View* view);
 
-  void AddWindowTree(WmWindow* window);
+  void AddWindowTree(aura::Window* window);
   // |remove_observer| ensures that we don't add a duplicate observer in any
   // observer callback. For example, |remove_observer| is false when rebuilding
   // the tree in OnWindowStackingChanged so that the observer is not removed and
   // re-added, thus causing endless calls on the observer.
-  void RemoveWindowTree(WmWindow* window, bool remove_observer);
-  void RemoveWindowNode(WmWindow* window, bool remove_observer);
+  void RemoveWindowTree(aura::Window* window, bool remove_observer);
+  void RemoveWindowNode(aura::Window* window, bool remove_observer);
 
   // Don't need AddWidgetTree because |widget| will always be inside a window,
   // so when windows are created, their widget nodes are created as well.
@@ -117,7 +119,7 @@
   void RemoveObservers();
   void Reset();
 
-  using WindowAndBoundsPair = std::pair<WmWindow*, gfx::Rect>;
+  using WindowAndBoundsPair = std::pair<aura::Window*, gfx::Rect>;
   WindowAndBoundsPair GetNodeWindowAndBounds(int node_id);
   void InitializeHighlightingWidget();
   void UpdateHighlight(const WindowAndBoundsPair& window_and_bounds,
@@ -127,13 +129,13 @@
       std::unique_ptr<ui::devtools::protocol::DOM::HighlightConfig>
           highlight_config,
       int node_id);
-  bool IsHighlightingWindow(WmWindow* window);
+  bool IsHighlightingWindow(aura::Window* window);
 
   std::unique_ptr<views::Widget> widget_for_highlighting_;
 
-  using WindowToNodeIdMap = std::unordered_map<WmWindow*, int>;
+  using WindowToNodeIdMap = std::unordered_map<aura::Window*, int>;
   WindowToNodeIdMap window_to_node_id_map_;
-  using NodeIdToWindowMap = std::unordered_map<int, WmWindow*>;
+  using NodeIdToWindowMap = std::unordered_map<int, aura::Window*>;
   NodeIdToWindowMap node_id_to_window_map_;
 
   using WidgetToNodeIdMap = std::unordered_map<views::Widget*, int>;
diff --git a/ash/devtools/ash_devtools_unittest.cc b/ash/devtools/ash_devtools_unittest.cc
index 29d7ca1..53b01c3 100644
--- a/ash/devtools/ash_devtools_unittest.cc
+++ b/ash/devtools/ash_devtools_unittest.cc
@@ -7,10 +7,8 @@
 #include "ash/public/cpp/shell_window_ids.h"
 #include "ash/root_window_controller.h"
 #include "ash/shell.h"
-#include "ash/shell_port.h"
-#include "ash/test/ash_test.h"
+#include "ash/test/ash_test_base.h"
 #include "ash/wm/widget_finder.h"
-#include "ash/wm_window.h"
 #include "base/memory/ptr_util.h"
 #include "base/strings/stringprintf.h"
 #include "ui/display/display.h"
@@ -81,12 +79,12 @@
   return nullptr;
 }
 
-bool Equals(WmWindow* window, DOM::Node* node) {
-  int children_count = static_cast<int>(window->GetChildren().size());
-  if (GetInternalWidgetForWindow(window->aura_window()))
+bool Equals(aura::Window* window, DOM::Node* node) {
+  int children_count = static_cast<int>(window->children().size());
+  if (GetInternalWidgetForWindow(window))
     children_count++;
   return "Window" == node->getNodeName() &&
-         window->aura_window()->GetName() == GetAttributeValue("name", node) &&
+         window->GetName() == GetAttributeValue("name", node) &&
          children_count == node->getChildNodeCount(kDefaultChildNodeCount);
 }
 
@@ -104,11 +102,11 @@
             node->getChildNodeCount(kDefaultChildNodeCount));
 }
 
-void Compare(WmWindow* window, DOM::Node* node) {
+void Compare(aura::Window* window, DOM::Node* node) {
   EXPECT_TRUE(Equals(window, node));
 }
 
-DOM::Node* FindInRoot(WmWindow* window, DOM::Node* root) {
+DOM::Node* FindInRoot(aura::Window* window, DOM::Node* root) {
   if (Equals(window, root))
     return root;
 
@@ -177,13 +175,13 @@
                                   ->get_color());
 }
 
-WmWindow* GetPrimaryRootWindow() {
-  return ShellPort::Get()->GetPrimaryRootWindow();
+aura::Window* GetPrimaryRootWindow() {
+  return Shell::Get()->GetPrimaryRootWindow();
 }
 
 }  // namespace
 
-class AshDevToolsTest : public AshTest {
+class AshDevToolsTest : public test::AshTestBase {
  public:
   AshDevToolsTest() {}
   ~AshDevToolsTest() override {}
@@ -192,16 +190,20 @@
     views::Widget* widget = new views::Widget;
     views::Widget::InitParams params;
     params.ownership = views::Widget::InitParams::NATIVE_WIDGET_OWNS_WIDGET;
-    ShellPort::Get()
-        ->GetPrimaryRootWindowController()
+    Shell::GetPrimaryRootWindowController()
         ->ConfigureWidgetInitParamsForContainer(
             widget, kShellWindowId_DefaultContainer, &params);
     widget->Init(params);
     return widget->native_widget_private();
   }
 
+  std::unique_ptr<views::Widget> CreateTestWidget(const gfx::Rect& bounds) {
+    return AshTestBase::CreateTestWidget(nullptr, kShellWindowId_Invalid,
+                                         bounds);
+  }
+
   void SetUp() override {
-    AshTest::SetUp();
+    AshTestBase::SetUp();
     fake_frontend_channel_ = base::MakeUnique<FakeFrontendChannel>();
     uber_dispatcher_ =
         base::MakeUnique<UberDispatcher>(fake_frontend_channel_.get());
@@ -218,7 +220,7 @@
     dom_agent_.reset();
     uber_dispatcher_.reset();
     fake_frontend_channel_.reset();
-    AshTest::TearDown();
+    AshTestBase::TearDown();
   }
 
   void ExpectChildNodeInserted(int parent_id, int prev_sibling_id) {
@@ -303,11 +305,10 @@
 TEST_F(AshDevToolsTest, GetDocumentWithWindowWidgetView) {
   std::unique_ptr<views::Widget> widget(
       CreateTestWidget(gfx::Rect(1, 1, 1, 1)));
-  WmWindow* parent_window = WmWindow::Get(widget->GetNativeWindow());
-  parent_window->aura_window()->SetName("parent_window");
-  std::unique_ptr<WindowOwner> child_owner(CreateChildWindow(parent_window));
-  WmWindow* child_window = child_owner->window();
-  child_window->aura_window()->SetName("child_window");
+  aura::Window* parent_window = widget->GetNativeWindow();
+  parent_window->SetName("parent_window");
+  std::unique_ptr<aura::Window> child_window = CreateChildWindow(parent_window);
+  child_window->SetName("child_window");
   widget->Show();
   views::View* child_view = new TestView("child_view");
   widget->GetRootView()->AddChildView(child_view);
@@ -321,7 +322,7 @@
   ASSERT_TRUE(parent_children);
   DOM::Node* widget_node = parent_children->get(0);
   Compare(widget.get(), widget_node);
-  Compare(child_window, parent_children->get(1));
+  Compare(child_window.get(), parent_children->get(1));
   Array<DOM::Node>* widget_children = widget_node->getChildren(nullptr);
   ASSERT_TRUE(widget_children);
   Compare(widget->GetRootView(), widget_children->get(0));
@@ -333,7 +334,7 @@
   views::internal::NativeWidgetPrivate* native_widget_private =
       CreateTestNativeWidget();
   views::Widget* widget = native_widget_private->GetWidget();
-  WmWindow* parent_window = WmWindow::Get(widget->GetNativeWindow());
+  aura::Window* parent_window = widget->GetNativeWindow();
 
   std::unique_ptr<ui::devtools::protocol::DOM::Node> root;
   dom_agent()->getDocument(&root);
@@ -351,14 +352,14 @@
   std::unique_ptr<ui::devtools::protocol::DOM::Node> root;
   dom_agent()->getDocument(&root);
 
-  WmWindow* root_window = GetPrimaryRootWindow();
-  WmWindow* parent_window = root_window->GetChildren()[0];
+  aura::Window* root_window = GetPrimaryRootWindow();
+  aura::Window* parent_window = root_window->children()[0];
   DOM::Node* parent_node = FindInRoot(parent_window, root.get());
   Array<DOM::Node>* parent_node_children = parent_node->getChildren(nullptr);
   DOM::Node* sibling_node =
       parent_node_children->get(parent_node_children->length() - 1);
 
-  std::unique_ptr<WindowOwner> child_owner(CreateChildWindow(parent_window));
+  std::unique_ptr<aura::Window> child(CreateChildWindow(parent_window));
   ExpectChildNodeInserted(parent_node->getNodeId(), sibling_node->getNodeId());
 }
 
@@ -367,10 +368,10 @@
   std::unique_ptr<ui::devtools::protocol::DOM::Node> root;
   dom_agent()->getDocument(&root);
 
-  WmWindow* root_window = GetPrimaryRootWindow();
-  WmWindow* rotation_window = root_window->GetChildren()[0];
-  WmWindow* parent_window = rotation_window->GetChildren()[0];
-  WmWindow* child_window = parent_window->GetChildren()[0];
+  aura::Window* root_window = GetPrimaryRootWindow();
+  aura::Window* rotation_window = root_window->children()[0];
+  aura::Window* parent_window = rotation_window->children()[0];
+  aura::Window* child_window = parent_window->children()[0];
   DOM::Node* root_node =
       root->getChildren(nullptr)->get(0)->getChildren(nullptr)->get(0);
   DOM::Node* parent_node = root_node->getChildren(nullptr)->get(0);
@@ -378,7 +379,7 @@
 
   Compare(parent_window, parent_node);
   Compare(child_window, child_node);
-  child_window->Destroy();
+  delete child_window;
   ExpectChildNodeRemoved(parent_node->getNodeId(), child_node->getNodeId());
 }
 
@@ -387,11 +388,11 @@
   std::unique_ptr<ui::devtools::protocol::DOM::Node> root;
   dom_agent()->getDocument(&root);
 
-  WmWindow* root_window = GetPrimaryRootWindow();
-  WmWindow* rotation_window = root_window->GetChildren()[0];
-  WmWindow* parent_window = rotation_window->GetChildren()[0];
-  WmWindow* target_window = rotation_window->GetChildren()[1];
-  WmWindow* child_window = parent_window->GetChildren()[0];
+  aura::Window* root_window = GetPrimaryRootWindow();
+  aura::Window* rotation_window = root_window->children()[0];
+  aura::Window* parent_window = rotation_window->children()[0];
+  aura::Window* target_window = rotation_window->children()[1];
+  aura::Window* child_window = parent_window->children()[0];
 
   DOM::Node* root_node =
       root->getChildren(nullptr)->get(0)->getChildren(nullptr)->get(0);
@@ -411,12 +412,11 @@
 }
 
 TEST_F(AshDevToolsTest, WindowReorganizedChildNodeRemovedAndInserted) {
-  WmWindow* root_window = GetPrimaryRootWindow();
-  WmWindow* rotation_window = root_window->GetChildren()[0];
-  WmWindow* parent_window = rotation_window->GetChildren()[0];
-  WmWindow* target_window = rotation_window->GetChildren()[1];
-  std::unique_ptr<WindowOwner> child_owner(CreateChildWindow(parent_window));
-  WmWindow* child_window = child_owner->window();
+  aura::Window* root_window = GetPrimaryRootWindow();
+  aura::Window* rotation_window = root_window->children()[0];
+  aura::Window* parent_window = rotation_window->children()[0];
+  aura::Window* target_window = rotation_window->children()[1];
+  std::unique_ptr<aura::Window> child_window(CreateChildWindow(parent_window));
 
   // Initialize DOMAgent
   std::unique_ptr<ui::devtools::protocol::DOM::Node> root;
@@ -434,9 +434,9 @@
 
   Compare(parent_window, parent_node);
   Compare(target_window, target_node);
-  Compare(child_window, child_node);
-  parent_window->RemoveChild(child_window);
-  target_window->AddChild(child_window);
+  Compare(child_window.get(), child_node);
+  parent_window->RemoveChild(child_window.get());
+  target_window->AddChild(child_window.get());
   ExpectChildNodeRemoved(parent_node->getNodeId(), child_node->getNodeId());
   ExpectChildNodeInserted(target_node->getNodeId(), sibling_node->getNodeId());
 }
@@ -446,10 +446,10 @@
   std::unique_ptr<ui::devtools::protocol::DOM::Node> root;
   dom_agent()->getDocument(&root);
 
-  WmWindow* root_window = GetPrimaryRootWindow();
-  WmWindow* parent_window = root_window->GetChildren()[0];
-  WmWindow* child_window = parent_window->GetChildren()[0];
-  WmWindow* target_window = parent_window->GetChildren()[1];
+  aura::Window* root_window = GetPrimaryRootWindow();
+  aura::Window* parent_window = root_window->children()[0];
+  aura::Window* child_window = parent_window->children()[0];
+  aura::Window* target_window = parent_window->children()[1];
 
   DOM::Node* parent_node =
       root->getChildren(nullptr)->get(0)->getChildren(nullptr)->get(0);
@@ -468,7 +468,7 @@
 TEST_F(AshDevToolsTest, ViewInserted) {
   std::unique_ptr<views::Widget> widget(
       CreateTestWidget(gfx::Rect(1, 1, 1, 1)));
-  WmWindow* window = WmWindow::Get(widget->GetNativeWindow());
+  aura::Window* window = widget->GetNativeWindow();
   widget->Show();
 
   // Initialize DOMAgent
@@ -495,7 +495,7 @@
   // Need to store |view| in unique_ptr because it is removed from the widget
   // and needs to be destroyed independently
   std::unique_ptr<views::View> child_view = base::MakeUnique<views::View>();
-  WmWindow* window = WmWindow::Get(widget->GetNativeWindow());
+  aura::Window* window = widget->GetNativeWindow();
   widget->Show();
   views::View* root_view = widget->GetRootView();
   root_view->AddChildView(child_view.get());
@@ -522,7 +522,7 @@
 TEST_F(AshDevToolsTest, ViewRearranged) {
   std::unique_ptr<views::Widget> widget(
       CreateTestWidget(gfx::Rect(1, 1, 1, 1)));
-  WmWindow* window = WmWindow::Get(widget->GetNativeWindow());
+  aura::Window* window = widget->GetNativeWindow();
   widget->Show();
   views::View* root_view = widget->GetRootView();
   views::View* parent_view = new views::View;
@@ -560,7 +560,7 @@
 TEST_F(AshDevToolsTest, ViewRearrangedRemovedAndInserted) {
   std::unique_ptr<views::Widget> widget(
       CreateTestWidget(gfx::Rect(1, 1, 1, 1)));
-  WmWindow* window = WmWindow::Get(widget->GetNativeWindow());
+  aura::Window* window = widget->GetNativeWindow();
   widget->Show();
   views::View* root_view = widget->GetRootView();
   views::View* parent_view = new views::View;
@@ -599,9 +599,8 @@
 TEST_F(AshDevToolsTest, WindowWidgetViewHighlight) {
   std::unique_ptr<views::Widget> widget(
       CreateTestWidget(gfx::Rect(0, 0, 400, 400)));
-  WmWindow* parent_window = WmWindow::Get(widget->GetNativeWindow());
-  std::unique_ptr<WindowOwner> child_owner(CreateChildWindow(parent_window));
-  WmWindow* window = child_owner->window();
+  aura::Window* parent_window = widget->GetNativeWindow();
+  std::unique_ptr<aura::Window> window(CreateChildWindow(parent_window));
   views::View* root_view = widget->GetRootView();
 
   std::unique_ptr<ui::devtools::protocol::DOM::Node> root;
@@ -638,30 +637,28 @@
 TEST_F(AshDevToolsTest, MultipleDisplayHighlight) {
   UpdateDisplay("300x400,500x500");
 
-  WmWindow::Windows root_windows = ShellPort::Get()->GetAllRootWindows();
-  std::unique_ptr<WindowOwner> window_owner(
-      CreateTestWindow(gfx::Rect(1, 2, 30, 40)));
-  WmWindow* window = window_owner->window();
+  aura::Window::Windows root_windows = Shell::GetAllRootWindows();
+  std::unique_ptr<aura::Window> window(
+      CreateTestWindowInShellWithBounds(gfx::Rect(1, 2, 30, 40)));
 
   std::unique_ptr<ui::devtools::protocol::DOM::Node> root;
   dom_agent()->getDocument(&root);
 
   EXPECT_EQ(root_windows[0], window->GetRootWindow());
-  HighlightNode(dom_agent()->GetNodeIdFromWindow(window));
+  HighlightNode(dom_agent()->GetNodeIdFromWindow(window.get()));
   ExpectHighlighted(window->GetBoundsInScreen(), 0);
 
   window->SetBoundsInScreen(gfx::Rect(500, 0, 50, 50), GetSecondaryDisplay());
   EXPECT_EQ(root_windows[1], window->GetRootWindow());
-  HighlightNode(dom_agent()->GetNodeIdFromWindow(window));
+  HighlightNode(dom_agent()->GetNodeIdFromWindow(window.get()));
   ExpectHighlighted(window->GetBoundsInScreen(), 1);
 }
 
 TEST_F(AshDevToolsTest, WindowWidgetViewGetMatchedStylesForNode) {
   std::unique_ptr<views::Widget> widget(
       CreateTestWidget(gfx::Rect(1, 1, 1, 1)));
-  WmWindow* parent_window = WmWindow::Get(widget->GetNativeWindow());
-  std::unique_ptr<WindowOwner> child_owner(CreateChildWindow(parent_window));
-  WmWindow* window = child_owner->window();
+  aura::Window* parent_window = widget->GetNativeWindow();
+  std::unique_ptr<aura::Window> window(CreateChildWindow(parent_window));
   gfx::Rect window_bounds(2, 2, 3, 3);
   gfx::Rect widget_bounds(50, 50, 100, 75);
   gfx::Rect view_bounds(4, 4, 3, 3);
@@ -686,9 +683,8 @@
 TEST_F(AshDevToolsTest, WindowWidgetViewStyleSheetChanged) {
   std::unique_ptr<views::Widget> widget(
       CreateTestWidget(gfx::Rect(1, 1, 1, 1)));
-  WmWindow* widget_window = WmWindow::Get(widget->GetNativeWindow());
-  std::unique_ptr<WindowOwner> child_owner(CreateChildWindow(widget_window));
-  WmWindow* child = child_owner->window();
+  aura::Window* widget_window = widget->GetNativeWindow();
+  std::unique_ptr<aura::Window> child(CreateChildWindow(widget_window));
 
   std::unique_ptr<ui::devtools::protocol::DOM::Node> root;
   dom_agent()->getDocument(&root);
@@ -718,9 +714,8 @@
 TEST_F(AshDevToolsTest, WindowWidgetViewSetStyleText) {
   std::unique_ptr<views::Widget> widget(
       CreateTestWidget(gfx::Rect(0, 0, 400, 400)));
-  WmWindow* parent_window = WmWindow::Get(widget->GetNativeWindow());
-  std::unique_ptr<WindowOwner> child_owner(CreateChildWindow(parent_window));
-  WmWindow* window = child_owner->window();
+  aura::Window* parent_window = widget->GetNativeWindow();
+  std::unique_ptr<aura::Window> window(CreateChildWindow(parent_window));
   views::View* root_view = widget->GetRootView();
 
   std::unique_ptr<ui::devtools::protocol::DOM::Node> root;
@@ -736,18 +731,18 @@
 
   SetStyleTexts(window_node,
                 "x: 25; y:35; width: 5; height: 20; visibility: 1;", true);
-  EXPECT_EQ(gfx::Rect(25, 35, 5, 20), window->GetBounds());
+  EXPECT_EQ(gfx::Rect(25, 35, 5, 20), window->bounds());
   EXPECT_TRUE(window->IsVisible());
 
   SetStyleTexts(window_node, "test_nothing_happens:1;", false);
-  EXPECT_EQ(gfx::Rect(25, 35, 5, 20), window->GetBounds());  // Not changed
+  EXPECT_EQ(gfx::Rect(25, 35, 5, 20), window->bounds());  // Not changed
 
   SetStyleTexts(window_node, "\nheight: 10;\nvisibility: 0;\n", true);
-  EXPECT_EQ(gfx::Rect(25, 35, 5, 10), window->GetBounds());
+  EXPECT_EQ(gfx::Rect(25, 35, 5, 10), window->bounds());
   EXPECT_FALSE(window->IsVisible());
 
   SetStyleTexts(window_node, "\nx: 10; y: 23; width: 52;\n  ", true);
-  EXPECT_EQ(gfx::Rect(10, 23, 52, 10), window->GetBounds());
+  EXPECT_EQ(gfx::Rect(10, 23, 52, 10), window->bounds());
 
   // Test different combinations on widget node
   DOM::Node* widget_node = parent_children->get(0);
diff --git a/ash/display/mirror_window_controller.cc b/ash/display/mirror_window_controller.cc
index 858dc66..55670a9 100644
--- a/ash/display/mirror_window_controller.cc
+++ b/ash/display/mirror_window_controller.cc
@@ -174,7 +174,7 @@
       AshWindowTreeHostInitParams init_params;
       init_params.initial_bounds = display_info.bounds_in_native();
       MirroringHostInfo* host_info = new MirroringHostInfo;
-      host_info->ash_host.reset(AshWindowTreeHost::Create(init_params));
+      host_info->ash_host = AshWindowTreeHost::Create(init_params);
       mirroring_host_info_map_[display_info.id()] = host_info;
 
       aura::WindowTreeHost* host = host_info->ash_host->AsWindowTreeHost();
diff --git a/ash/display/window_tree_host_manager.cc b/ash/display/window_tree_host_manager.cc
index fde5d13e..7f11547 100644
--- a/ash/display/window_tree_host_manager.cc
+++ b/ash/display/window_tree_host_manager.cc
@@ -813,7 +813,10 @@
   params_with_bounds.initial_bounds = display_info.bounds_in_native();
   params_with_bounds.offscreen =
       display.id() == display::DisplayManager::kUnifiedDisplayId;
-  AshWindowTreeHost* ash_host = AshWindowTreeHost::Create(params_with_bounds);
+  // The AshWindowTreeHost ends up owned by the RootWindowControllers created
+  // by this class.
+  AshWindowTreeHost* ash_host =
+      AshWindowTreeHost::Create(params_with_bounds).release();
   aura::WindowTreeHost* host = ash_host->AsWindowTreeHost();
   if (!input_method_) {  // Singleton input method instance for Ash.
     input_method_ = ui::CreateInputMethod(this, host->GetAcceleratedWidget());
diff --git a/ash/host/DEPS b/ash/host/DEPS
index 0d123b9..a02ef75 100644
--- a/ash/host/DEPS
+++ b/ash/host/DEPS
@@ -6,3 +6,9 @@
   "+ash/ash_switches.h",
   "+ui/ozone/public",  # For ozone interfaces
 ]
+
+specific_include_rules = {
+  "ash_window_tree_host.cc": [
+    "+ash/shell_port.h",
+  ],
+}
diff --git a/ash/host/ash_window_tree_host.cc b/ash/host/ash_window_tree_host.cc
index 939f097..31cdd01 100644
--- a/ash/host/ash_window_tree_host.cc
+++ b/ash/host/ash_window_tree_host.cc
@@ -6,6 +6,8 @@
 
 #include "ash/host/ash_window_tree_host_init_params.h"
 #include "ash/host/ash_window_tree_host_unified.h"
+#include "ash/shell_port.h"
+#include "base/memory/ptr_util.h"
 #include "ui/aura/client/screen_position_client.h"
 #include "ui/aura/window_tree_host.h"
 #include "ui/events/event.h"
@@ -21,6 +23,8 @@
 
 AshWindowTreeHost::AshWindowTreeHost() : input_method_handler_(nullptr) {}
 
+AshWindowTreeHost::~AshWindowTreeHost() = default;
+
 void AshWindowTreeHost::TranslateLocatedEvent(ui::LocatedEvent* event) {
   if (event->IsTouchEvent())
     return;
@@ -47,14 +51,22 @@
 }
 
 // static
-AshWindowTreeHost* AshWindowTreeHost::Create(
+std::unique_ptr<AshWindowTreeHost> AshWindowTreeHost::Create(
     const AshWindowTreeHostInitParams& init_params) {
-  if (init_params.offscreen)
-    return new AshWindowTreeHostUnified(init_params.initial_bounds);
+  std::unique_ptr<AshWindowTreeHost> ash_window_tree_host =
+      ShellPort::Get()->CreateAshWindowTreeHost(init_params);
+  if (ash_window_tree_host)
+    return ash_window_tree_host;
+
+  if (init_params.offscreen) {
+    return base::MakeUnique<AshWindowTreeHostUnified>(
+        init_params.initial_bounds);
+  }
 #if defined(USE_OZONE)
-  return new AshWindowTreeHostPlatform(init_params.initial_bounds);
+  return base::MakeUnique<AshWindowTreeHostPlatform>(
+      init_params.initial_bounds);
 #elif defined(USE_X11)
-  return new AshWindowTreeHostX11(init_params.initial_bounds);
+  return base::MakeUnique<AshWindowTreeHostX11>(init_params.initial_bounds);
 #else
 #error Unsupported platform.
 #endif
diff --git a/ash/host/ash_window_tree_host.h b/ash/host/ash_window_tree_host.h
index 2459aea..dfe20f5 100644
--- a/ash/host/ash_window_tree_host.h
+++ b/ash/host/ash_window_tree_host.h
@@ -29,10 +29,9 @@
 class ASH_EXPORT AshWindowTreeHost {
  public:
   AshWindowTreeHost();
-  virtual ~AshWindowTreeHost() {}
+  virtual ~AshWindowTreeHost();
 
-  // Creates a new AshWindowTreeHost. The caller owns the returned value.
-  static AshWindowTreeHost* Create(
+  static std::unique_ptr<AshWindowTreeHost> Create(
       const AshWindowTreeHostInitParams& init_params);
 
   void set_input_method_handler(InputMethodEventHandler* input_method_handler) {
diff --git a/ash/host/ash_window_tree_host_init_params.h b/ash/host/ash_window_tree_host_init_params.h
index cf59bef..4c85f95 100644
--- a/ash/host/ash_window_tree_host_init_params.h
+++ b/ash/host/ash_window_tree_host_init_params.h
@@ -5,14 +5,20 @@
 #ifndef ASH_HOST_WINDOW_TREE_HOST_INIT_PARAMS_H_
 #define ASH_HOST_WINDOW_TREE_HOST_INIT_PARAMS_H_
 
+#include <stdint.h>
+
 #include "ash/ash_export.h"
 #include "ui/gfx/geometry/rect.h"
 
 namespace ash {
 
 struct ASH_EXPORT AshWindowTreeHostInitParams {
+  // This corresponds to display::ManagedDisplayInfo::bounds_in_native.
   gfx::Rect initial_bounds;
   bool offscreen = false;
+  int64_t display_id = 0;
+  float device_scale_factor = 0.0f;
+  float ui_scale_factor = 0.0f;
 };
 
 }  // namespace ash
diff --git a/ash/metrics/user_metrics_recorder_unittest.cc b/ash/metrics/user_metrics_recorder_unittest.cc
index 84993be..e9f323c 100644
--- a/ash/metrics/user_metrics_recorder_unittest.cc
+++ b/ash/metrics/user_metrics_recorder_unittest.cc
@@ -12,12 +12,10 @@
 #include "ash/shell.h"
 #include "ash/shell_port.h"
 #include "ash/test/ash_test_base.h"
-#include "ash/test/test_shelf_delegate.h"
 #include "ash/test/test_system_tray_delegate.h"
 #include "ash/test/user_metrics_recorder_test_api.h"
 #include "ash/wm_window.h"
 #include "base/test/histogram_tester.h"
-#include "ui/aura/window.h"
 
 namespace ash {
 namespace {
@@ -54,9 +52,6 @@
   // environment.
   void SetUserInActiveDesktopEnvironment(bool is_active);
 
-  // Creates an aura::Window.
-  aura::Window* CreateTestWindow();
-
   test::UserMetricsRecorderTestAPI* user_metrics_recorder_test_api() {
     return user_metrics_recorder_test_api_.get();
   }
@@ -109,12 +104,6 @@
   }
 }
 
-aura::Window* UserMetricsRecorderTest::CreateTestWindow() {
-  aura::Window* window = CreateTestWindowInShellWithDelegateAndType(
-      nullptr, ui::wm::WINDOW_TYPE_NORMAL, 0, gfx::Rect());
-  return window;
-}
-
 // Verifies the return value of IsUserInActiveDesktopEnvironment() for the
 // different login status values.
 TEST_F(UserMetricsRecorderTest, VerifyIsUserInActiveDesktopEnvironmentValues) {
@@ -193,34 +182,27 @@
   if (Shell::GetAshConfig() == Config::MASH)
     return;
 
-  test::TestShelfDelegate* test_shelf_delegate =
-      test::TestShelfDelegate::instance();
   SetUserInActiveDesktopEnvironment(true);
 
   // Make sure the shelf contains the app list launcher button.
-  const ShelfItems& shelf_items = Shell::Get()->shelf_model()->items();
-  ASSERT_EQ(1u, shelf_items.size());
-  ASSERT_EQ(TYPE_APP_LIST, shelf_items[0].type);
+  ShelfModel* shelf_model = Shell::Get()->shelf_model();
+  ASSERT_EQ(1u, shelf_model->items().size());
+  ASSERT_EQ(TYPE_APP_LIST, shelf_model->items()[0].type);
 
-  aura::Window* pinned_window_with_app_id_1 = CreateTestWindow();
-  test_shelf_delegate->AddShelfItem(WmWindow::Get(pinned_window_with_app_id_1),
-                                    "app_id_1");
-  test_shelf_delegate->PinAppWithID("app_id_1");
+  ShelfItem shelf_item;
+  shelf_item.type = ash::TYPE_PINNED_APP;
+  shelf_item.app_launch_id = AppLaunchId("app_id_1");
+  shelf_model->Add(shelf_item);
+  shelf_item.app_launch_id = AppLaunchId("app_id_2");
+  shelf_model->Add(shelf_item);
 
-  aura::Window* pinned_window_with_app_id_2 = CreateTestWindow();
-  test_shelf_delegate->AddShelfItem(WmWindow::Get(pinned_window_with_app_id_2),
-                                    "app_id_2");
-  test_shelf_delegate->PinAppWithID("app_id_2");
-
-  aura::Window* unpinned_window_with_app_id_3 = CreateTestWindow();
-  test_shelf_delegate->AddShelfItem(
-      WmWindow::Get(unpinned_window_with_app_id_3), "app_id_3");
-
-  aura::Window* unpinned_window_4 = CreateTestWindow();
-  test_shelf_delegate->AddShelfItem(WmWindow::Get(unpinned_window_4));
-
-  aura::Window* unpinned_window_5 = CreateTestWindow();
-  test_shelf_delegate->AddShelfItem(WmWindow::Get(unpinned_window_5));
+  shelf_item.type = ash::TYPE_APP;
+  shelf_item.app_launch_id = AppLaunchId("app_id_3");
+  shelf_model->Add(shelf_item);
+  shelf_item.app_launch_id = AppLaunchId("app_id_4");
+  shelf_model->Add(shelf_item);
+  shelf_item.app_launch_id = AppLaunchId("app_id_5");
+  shelf_model->Add(shelf_item);
 
   user_metrics_recorder_test_api()->RecordPeriodicMetrics();
   histograms().ExpectBucketCount(kAsh_Shelf_NumberOfItems, 5, 1);
diff --git a/ash/mus/bridge/DEPS b/ash/mus/bridge/DEPS
new file mode 100644
index 0000000..984553aa6
--- /dev/null
+++ b/ash/mus/bridge/DEPS
@@ -0,0 +1,6 @@
+specific_include_rules = {
+  "shell_port_mash.cc": [
+    "+ash/host/ash_window_tree_host.h",
+    "+ash/host/ash_window_tree_host_init_params.h"
+  ],
+}
diff --git a/ash/mus/bridge/shell_port_mash.cc b/ash/mus/bridge/shell_port_mash.cc
index 1a78a0a5..d740d0bf 100644
--- a/ash/mus/bridge/shell_port_mash.cc
+++ b/ash/mus/bridge/shell_port_mash.cc
@@ -10,6 +10,7 @@
 #include "ash/accelerators/accelerator_controller_delegate_aura.h"
 #include "ash/aura/key_event_watcher_aura.h"
 #include "ash/aura/pointer_watcher_adapter.h"
+#include "ash/host/ash_window_tree_host.h"
 #include "ash/key_event_watcher.h"
 #include "ash/laser/laser_pointer_controller.h"
 #include "ash/magnifier/partial_magnification_controller.h"
@@ -54,6 +55,7 @@
 #include "ui/aura/window.h"
 #include "ui/display/manager/managed_display_info.h"
 #include "ui/display/screen.h"
+#include "ui/display/types/native_display_delegate.h"
 #include "ui/views/mus/pointer_watcher_event_router.h"
 
 namespace ash {
@@ -423,6 +425,11 @@
   }
 }
 
+std::unique_ptr<AshWindowTreeHost> ShellPortMash::CreateAshWindowTreeHost(
+    const AshWindowTreeHostInitParams& init_params) {
+  return nullptr;
+}
+
 void ShellPortMash::CreatePrimaryHost() {}
 
 void ShellPortMash::InitHosts(const ShellInitParams& init_params) {
@@ -430,6 +437,11 @@
       base::WrapUnique(init_params.primary_window_tree_host));
 }
 
+std::unique_ptr<display::NativeDisplayDelegate>
+ShellPortMash::CreateNativeDisplayDelegate() {
+  return nullptr;
+}
+
 std::unique_ptr<AcceleratorController>
 ShellPortMash::CreateAcceleratorController() {
   if (GetAshConfig() == Config::MUS) {
diff --git a/ash/mus/bridge/shell_port_mash.h b/ash/mus/bridge/shell_port_mash.h
index ac839c8..9b86c8f6f 100644
--- a/ash/mus/bridge/shell_port_mash.h
+++ b/ash/mus/bridge/shell_port_mash.h
@@ -104,8 +104,12 @@
   void SetLaserPointerEnabled(bool enabled) override;
   void SetPartialMagnifierEnabled(bool enabled) override;
   void CreatePointerWatcherAdapter() override;
+  std::unique_ptr<AshWindowTreeHost> CreateAshWindowTreeHost(
+      const AshWindowTreeHostInitParams& init_params) override;
   void CreatePrimaryHost() override;
   void InitHosts(const ShellInitParams& init_params) override;
+  std::unique_ptr<display::NativeDisplayDelegate> CreateNativeDisplayDelegate()
+      override;
   std::unique_ptr<AcceleratorController> CreateAcceleratorController() override;
 
  private:
diff --git a/ash/public/interfaces/session_controller.mojom b/ash/public/interfaces/session_controller.mojom
index 6a2e438..65ead11 100644
--- a/ash/public/interfaces/session_controller.mojom
+++ b/ash/public/interfaces/session_controller.mojom
@@ -84,6 +84,14 @@
   string display_name;
   string display_email;
   gfx.mojom.ImageSkia avatar;
+
+  // Whether the settings icon should be enabled in the system tray menu.
+  // Usually true after login, but can be false for specialized user sessions
+  // (e.g. adding supervised users).
+  bool should_enable_settings;
+
+  // Similar to |should_show_settings| but for the notification tray.
+  bool should_show_notification_tray;
 };
 
 // Matches ash::AddUserSessionPolicy.
diff --git a/ash/resources/ash_resources.grd b/ash/resources/ash_resources.grd
index c1f4be1..a8403e6 100644
--- a/ash/resources/ash_resources.grd
+++ b/ash/resources/ash_resources.grd
@@ -19,15 +19,6 @@
       <structure type="chrome_scaled_image" name="IDR_ASH_SHELF_ICON_TASK_MANAGER" file="common/shelf/task_manager.png" />
       <structure type="chrome_scaled_image" name="IDR_AURA_MULTI_WINDOW_RESIZE_H" file="common/multi_window_resize_horizontal.png" />
       <structure type="chrome_scaled_image" name="IDR_AURA_MULTI_WINDOW_RESIZE_V" file="common/multi_window_resize_vertical.png" />
-      <structure type="chrome_scaled_image" name="IDR_AURA_PHANTOM_WINDOW_BOTTOM" file="common/phantom_window_bottom.png" />
-      <structure type="chrome_scaled_image" name="IDR_AURA_PHANTOM_WINDOW_BOTTOM_LEFT" file="common/phantom_window_bottom_left.png" />
-      <structure type="chrome_scaled_image" name="IDR_AURA_PHANTOM_WINDOW_BOTTOM_RIGHT" file="common/phantom_window_bottom_right.png" />
-      <structure type="chrome_scaled_image" name="IDR_AURA_PHANTOM_WINDOW_CENTER" file="common/phantom_window_center.png" />
-      <structure type="chrome_scaled_image" name="IDR_AURA_PHANTOM_WINDOW_LEFT" file="common/phantom_window_left.png" />
-      <structure type="chrome_scaled_image" name="IDR_AURA_PHANTOM_WINDOW_RIGHT" file="common/phantom_window_right.png" />
-      <structure type="chrome_scaled_image" name="IDR_AURA_PHANTOM_WINDOW_TOP" file="common/phantom_window_top.png" />
-      <structure type="chrome_scaled_image" name="IDR_AURA_PHANTOM_WINDOW_TOP_LEFT" file="common/phantom_window_top_left.png" />
-      <structure type="chrome_scaled_image" name="IDR_AURA_PHANTOM_WINDOW_TOP_RIGHT" file="common/phantom_window_top_right.png" />
 
       <structure type="chrome_scaled_image" name="IDR_AURA_UBER_TRAY_LOCALE" file="cros/status/status_locale.png" />
       <structure type="chrome_scaled_image" name="IDR_AURA_UBER_TRAY_NETWORK_FAILED" file="cros/network/status_network_failed.png" />
diff --git a/ash/resources/default_100_percent/common/phantom_window_bottom.png b/ash/resources/default_100_percent/common/phantom_window_bottom.png
deleted file mode 100644
index b690bad..0000000
--- a/ash/resources/default_100_percent/common/phantom_window_bottom.png
+++ /dev/null
Binary files differ
diff --git a/ash/resources/default_100_percent/common/phantom_window_bottom_left.png b/ash/resources/default_100_percent/common/phantom_window_bottom_left.png
deleted file mode 100644
index 0158807..0000000
--- a/ash/resources/default_100_percent/common/phantom_window_bottom_left.png
+++ /dev/null
Binary files differ
diff --git a/ash/resources/default_100_percent/common/phantom_window_bottom_right.png b/ash/resources/default_100_percent/common/phantom_window_bottom_right.png
deleted file mode 100644
index df3d8fc..0000000
--- a/ash/resources/default_100_percent/common/phantom_window_bottom_right.png
+++ /dev/null
Binary files differ
diff --git a/ash/resources/default_100_percent/common/phantom_window_center.png b/ash/resources/default_100_percent/common/phantom_window_center.png
deleted file mode 100644
index fe802d5..0000000
--- a/ash/resources/default_100_percent/common/phantom_window_center.png
+++ /dev/null
Binary files differ
diff --git a/ash/resources/default_100_percent/common/phantom_window_left.png b/ash/resources/default_100_percent/common/phantom_window_left.png
deleted file mode 100644
index d4efcc0c..0000000
--- a/ash/resources/default_100_percent/common/phantom_window_left.png
+++ /dev/null
Binary files differ
diff --git a/ash/resources/default_100_percent/common/phantom_window_right.png b/ash/resources/default_100_percent/common/phantom_window_right.png
deleted file mode 100644
index f1d7c74..0000000
--- a/ash/resources/default_100_percent/common/phantom_window_right.png
+++ /dev/null
Binary files differ
diff --git a/ash/resources/default_100_percent/common/phantom_window_top.png b/ash/resources/default_100_percent/common/phantom_window_top.png
deleted file mode 100644
index e0d0f65..0000000
--- a/ash/resources/default_100_percent/common/phantom_window_top.png
+++ /dev/null
Binary files differ
diff --git a/ash/resources/default_100_percent/common/phantom_window_top_left.png b/ash/resources/default_100_percent/common/phantom_window_top_left.png
deleted file mode 100644
index fdd27407..0000000
--- a/ash/resources/default_100_percent/common/phantom_window_top_left.png
+++ /dev/null
Binary files differ
diff --git a/ash/resources/default_100_percent/common/phantom_window_top_right.png b/ash/resources/default_100_percent/common/phantom_window_top_right.png
deleted file mode 100644
index 6a181fb..0000000
--- a/ash/resources/default_100_percent/common/phantom_window_top_right.png
+++ /dev/null
Binary files differ
diff --git a/ash/resources/default_200_percent/common/phantom_window_bottom.png b/ash/resources/default_200_percent/common/phantom_window_bottom.png
deleted file mode 100644
index ecc8ac3d..0000000
--- a/ash/resources/default_200_percent/common/phantom_window_bottom.png
+++ /dev/null
Binary files differ
diff --git a/ash/resources/default_200_percent/common/phantom_window_bottom_left.png b/ash/resources/default_200_percent/common/phantom_window_bottom_left.png
deleted file mode 100644
index 15d21ea9..0000000
--- a/ash/resources/default_200_percent/common/phantom_window_bottom_left.png
+++ /dev/null
Binary files differ
diff --git a/ash/resources/default_200_percent/common/phantom_window_bottom_right.png b/ash/resources/default_200_percent/common/phantom_window_bottom_right.png
deleted file mode 100644
index 7e1e9b6d..0000000
--- a/ash/resources/default_200_percent/common/phantom_window_bottom_right.png
+++ /dev/null
Binary files differ
diff --git a/ash/resources/default_200_percent/common/phantom_window_center.png b/ash/resources/default_200_percent/common/phantom_window_center.png
deleted file mode 100644
index 8deb3b46..0000000
--- a/ash/resources/default_200_percent/common/phantom_window_center.png
+++ /dev/null
Binary files differ
diff --git a/ash/resources/default_200_percent/common/phantom_window_left.png b/ash/resources/default_200_percent/common/phantom_window_left.png
deleted file mode 100644
index 51fce9f..0000000
--- a/ash/resources/default_200_percent/common/phantom_window_left.png
+++ /dev/null
Binary files differ
diff --git a/ash/resources/default_200_percent/common/phantom_window_right.png b/ash/resources/default_200_percent/common/phantom_window_right.png
deleted file mode 100644
index db8656a..0000000
--- a/ash/resources/default_200_percent/common/phantom_window_right.png
+++ /dev/null
Binary files differ
diff --git a/ash/resources/default_200_percent/common/phantom_window_top.png b/ash/resources/default_200_percent/common/phantom_window_top.png
deleted file mode 100644
index 5186217..0000000
--- a/ash/resources/default_200_percent/common/phantom_window_top.png
+++ /dev/null
Binary files differ
diff --git a/ash/resources/default_200_percent/common/phantom_window_top_left.png b/ash/resources/default_200_percent/common/phantom_window_top_left.png
deleted file mode 100644
index 7c483fa..0000000
--- a/ash/resources/default_200_percent/common/phantom_window_top_left.png
+++ /dev/null
Binary files differ
diff --git a/ash/resources/default_200_percent/common/phantom_window_top_right.png b/ash/resources/default_200_percent/common/phantom_window_top_right.png
deleted file mode 100644
index f11c0240..0000000
--- a/ash/resources/default_200_percent/common/phantom_window_top_right.png
+++ /dev/null
Binary files differ
diff --git a/ash/session/session_controller.cc b/ash/session/session_controller.cc
index 041259cd..f2fe59c 100644
--- a/ash/session/session_controller.cc
+++ b/ash/session/session_controller.cc
@@ -96,6 +96,23 @@
   return state_;
 }
 
+bool SessionController::ShouldEnableSettings() const {
+  // Settings opens a web UI window, so it is not available at the lock screen.
+  if (!IsActiveUserSessionStarted() || IsScreenLocked() ||
+      IsInSecondaryLoginScreen()) {
+    return false;
+  }
+
+  return user_sessions_[0]->should_enable_settings;
+}
+
+bool SessionController::ShouldShowNotificationTray() const {
+  if (!IsActiveUserSessionStarted() || IsInSecondaryLoginScreen())
+    return false;
+
+  return user_sessions_[0]->should_show_notification_tray;
+}
+
 const std::vector<mojom::UserSessionPtr>& SessionController::GetUserSessions()
     const {
   return user_sessions_;
diff --git a/ash/session/session_controller.h b/ash/session/session_controller.h
index 975e218..afe6222c 100644
--- a/ash/session/session_controller.h
+++ b/ash/session/session_controller.h
@@ -69,6 +69,12 @@
   // Convenience function that returns true if session state is LOGIN_SECONDARY.
   bool IsInSecondaryLoginScreen() const;
 
+  // Returns true if the settings icon should be enabled in the system tray.
+  bool ShouldEnableSettings() const;
+
+  // Returns true if the notification tray should appear.
+  bool ShouldShowNotificationTray() const;
+
   // Gets the ash session state.
   session_manager::SessionState GetSessionState() const;
 
diff --git a/ash/shelf/shelf_application_menu_model.cc b/ash/shelf/shelf_application_menu_model.cc
index 503ce9b..d991f34 100644
--- a/ash/shelf/shelf_application_menu_model.cc
+++ b/ash/shelf/shelf_application_menu_model.cc
@@ -57,10 +57,10 @@
 
 void ShelfApplicationMenuModel::ExecuteCommand(int command_id,
                                                int event_flags) {
-  DCHECK(delegate_);
   DCHECK(IsCommandIdEnabled(command_id));
   // Have the delegate execute its own custom command id for the given item.
-  delegate_->ExecuteCommand(items_[command_id]->command_id, event_flags);
+  if (delegate_)
+    delegate_->ExecuteCommand(items_[command_id]->command_id, event_flags);
   RecordMenuItemSelectedMetrics(command_id, items_.size());
 }
 
diff --git a/ash/shelf/shelf_application_menu_model_unittest.cc b/ash/shelf/shelf_application_menu_model_unittest.cc
index 7a01001c..09dbd3c 100644
--- a/ash/shelf/shelf_application_menu_model_unittest.cc
+++ b/ash/shelf/shelf_application_menu_model_unittest.cc
@@ -6,7 +6,6 @@
 
 #include <utility>
 
-#include "ash/test/test_shelf_item_delegate.h"
 #include "base/macros.h"
 #include "base/memory/ptr_util.h"
 #include "base/strings/utf_string_conversions.h"
@@ -124,9 +123,8 @@
 
   std::vector<mojom::MenuItemPtr> items;
   items.push_back(ash::mojom::MenuItem::New());
-  test::TestShelfItemDelegate test_delegate(nullptr);
   base::string16 title = base::ASCIIToUTF16("title");
-  ShelfApplicationMenuModel menu(title, std::move(items), &test_delegate);
+  ShelfApplicationMenuModel menu(title, std::move(items), nullptr);
   menu.ExecuteCommand(0, 0);
 
   histogram_tester.ExpectTotalCount(kNumItemsEnabledHistogramName, 1);
diff --git a/ash/shelf/shelf_tooltip_manager_unittest.cc b/ash/shelf/shelf_tooltip_manager_unittest.cc
index 8dd94623..089e998 100644
--- a/ash/shelf/shelf_tooltip_manager_unittest.cc
+++ b/ash/shelf/shelf_tooltip_manager_unittest.cc
@@ -12,7 +12,6 @@
 #include "ash/shell.h"
 #include "ash/test/ash_test_base.h"
 #include "ash/test/shelf_view_test_api.h"
-#include "ash/test/test_shelf_item_delegate.h"
 #include "base/memory/ptr_util.h"
 #include "ui/events/event_constants.h"
 #include "ui/events/test/event_generator.h"
@@ -88,9 +87,6 @@
   ShelfItem item;
   item.type = TYPE_PINNED_APP;
   const int index = model->Add(item);
-  const ShelfID id = model->items()[index].id;
-  model->SetShelfItemDelegate(id,
-                              base::MakeUnique<TestShelfItemDelegate>(nullptr));
   // Note: There's no easy way to correlate shelf a model index/id to its view.
   tooltip_manager_->ShowTooltipWithDelay(
       shelf_view_->child_at(shelf_view_->child_count() - 1));
diff --git a/ash/shelf/shelf_unittest.cc b/ash/shelf/shelf_unittest.cc
index 3fa1d3c9..68f11f9 100644
--- a/ash/shelf/shelf_unittest.cc
+++ b/ash/shelf/shelf_unittest.cc
@@ -11,7 +11,6 @@
 #include "ash/shelf/wm_shelf.h"
 #include "ash/test/ash_test_base.h"
 #include "ash/test/shelf_view_test_api.h"
-#include "ash/test/test_shelf_item_delegate.h"
 
 namespace ash {
 
@@ -72,10 +71,6 @@
   item.status = STATUS_RUNNING;
   int index = shelf_model()->Add(item);
 
-  shelf_model()->SetShelfItemDelegate(
-      shelf_model()->items()[index].id,
-      base::MakeUnique<test::TestShelfItemDelegate>(nullptr));
-
   ASSERT_EQ(++button_count, test_api()->GetButtonCount());
   ShelfButton* button = test_api()->GetButton(index);
   button->AddState(ShelfButton::STATE_HOVERED);
diff --git a/ash/shelf/shelf_view_unittest.cc b/ash/shelf/shelf_view_unittest.cc
index c8ed571..0baab22 100644
--- a/ash/shelf/shelf_view_unittest.cc
+++ b/ash/shelf/shelf_view_unittest.cc
@@ -10,6 +10,7 @@
 #include <vector>
 
 #include "ash/public/cpp/config.h"
+#include "ash/public/cpp/shelf_item_delegate.h"
 #include "ash/public/cpp/shell_window_ids.h"
 #include "ash/root_window_controller.h"
 #include "ash/shelf/app_list_button.h"
@@ -32,8 +33,6 @@
 #include "ash/test/overflow_button_test_api.h"
 #include "ash/test/shelf_view_test_api.h"
 #include "ash/test/shell_test_api.h"
-#include "ash/test/test_shelf_delegate.h"
-#include "ash/test/test_shelf_item_delegate.h"
 #include "ash/test/test_shell_delegate.h"
 #include "ash/test/test_system_tray_delegate.h"
 #include "ash/wm_window.h"
@@ -138,60 +137,46 @@
   DISALLOW_COPY_AND_ASSIGN(WmShelfObserverIconTest);
 };
 
-// TestShelfItemDelegate which tracks whether it gets selected.
-class ShelfItemSelectionTracker : public TestShelfItemDelegate {
+// A ShelfItemDelegate that tracks selections and reports a custom action.
+class ShelfItemSelectionTracker : public ShelfItemDelegate {
  public:
-  ShelfItemSelectionTracker()
-      : TestShelfItemDelegate(NULL),
-        selected_(false),
-        item_selected_action_(SHELF_ACTION_NONE) {}
-
+  ShelfItemSelectionTracker() : ShelfItemDelegate(AppLaunchId()) {}
   ~ShelfItemSelectionTracker() override {}
 
-  // Resets to the initial state.
-  void Reset() { selected_ = false; }
-
+  size_t item_selected_count() const { return item_selected_count_; }
   void set_item_selected_action(ShelfAction item_selected_action) {
     item_selected_action_ = item_selected_action;
   }
 
-  // Returns true if the delegate was selected.
-  bool WasSelected() { return selected_; }
-
-  // TestShelfItemDelegate:
+  // ShelfItemDelegate:
   void ItemSelected(std::unique_ptr<ui::Event> event,
                     int64_t display_id,
                     ShelfLaunchSource source,
                     const ItemSelectedCallback& callback) override {
-    selected_ = true;
+    item_selected_count_++;
     callback.Run(item_selected_action_, base::nullopt);
   }
+  void ExecuteCommand(uint32_t command_id, int32_t event_flags) override {}
+  void Close() override {}
 
  private:
-  bool selected_;
-
-  // The action reported by ItemSelected.
-  ShelfAction item_selected_action_;
+  size_t item_selected_count_ = 0;
+  ShelfAction item_selected_action_ = SHELF_ACTION_NONE;
 
   DISALLOW_COPY_AND_ASSIGN(ShelfItemSelectionTracker);
 };
 
 TEST_F(WmShelfObserverIconTest, AddRemove) {
-  views::Widget::InitParams params(views::Widget::InitParams::TYPE_WINDOW);
-  params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
-  params.bounds = gfx::Rect(0, 0, 200, 200);
-  params.context = CurrentContext();
-  views::Widget widget;
-  widget.Init(params);
-
-  TestShelfDelegate::instance()->AddShelfItem(
-      WmWindow::Get(widget.GetNativeWindow()));
+  ShelfItem item;
+  item.type = TYPE_APP;
+  EXPECT_FALSE(observer()->icon_positions_changed());
+  const int shelf_item_index = Shell::Get()->shelf_model()->Add(item);
   shelf_view_test()->RunMessageLoopUntilAnimationsDone();
   EXPECT_TRUE(observer()->icon_positions_changed());
   observer()->Reset();
 
-  widget.Show();
-  widget.GetNativeWindow()->parent()->RemoveChild(widget.GetNativeWindow());
+  EXPECT_FALSE(observer()->icon_positions_changed());
+  Shell::Get()->shelf_model()->RemoveItemAt(shelf_item_index);
   shelf_view_test()->RunMessageLoopUntilAnimationsDone();
   EXPECT_TRUE(observer()->icon_positions_changed());
   observer()->Reset();
@@ -205,26 +190,26 @@
     return;
 
   UpdateDisplay("400x400,400x400");
+  observer()->Reset();
+
   WmWindow* second_root = ShellPort::Get()->GetAllRootWindows()[1];
   WmShelf* second_shelf = second_root->GetRootWindowController()->GetShelf();
   TestWmShelfObserver second_observer(second_shelf);
 
-  views::Widget::InitParams params(views::Widget::InitParams::TYPE_WINDOW);
-  params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
-  params.bounds = gfx::Rect(0, 0, 200, 200);
-  params.context = CurrentContext();
-  views::Widget widget;
-  widget.Init(params);
-
-  TestShelfDelegate::instance()->AddShelfItem(
-      WmWindow::Get(widget.GetNativeWindow()));
+  ShelfItem item;
+  item.type = TYPE_APP;
+  EXPECT_FALSE(observer()->icon_positions_changed());
+  EXPECT_FALSE(second_observer.icon_positions_changed());
+  const int shelf_item_index = Shell::Get()->shelf_model()->Add(item);
   shelf_view_test()->RunMessageLoopUntilAnimationsDone();
   EXPECT_TRUE(observer()->icon_positions_changed());
   EXPECT_TRUE(second_observer.icon_positions_changed());
   observer()->Reset();
   second_observer.Reset();
 
-  widget.GetNativeWindow()->parent()->RemoveChild(widget.GetNativeWindow());
+  EXPECT_FALSE(observer()->icon_positions_changed());
+  EXPECT_FALSE(second_observer.icon_positions_changed());
+  Shell::Get()->shelf_model()->RemoveItemAt(shelf_item_index);
   shelf_view_test()->RunMessageLoopUntilAnimationsDone();
   EXPECT_TRUE(observer()->icon_positions_changed());
   EXPECT_TRUE(second_observer.icon_positions_changed());
@@ -248,49 +233,6 @@
 ////////////////////////////////////////////////////////////////////////////////
 // ShelfView tests.
 
-// A ShelfDelegate test double that will always convert between ShelfIDs and app
-// ids. This does not support pinning and unpinning operations and the return
-// value of IsAppPinned(...) is configurable.
-class TestShelfDelegateForShelfView : public TestShelfDelegate {
- public:
-  TestShelfDelegateForShelfView() {}
-  ~TestShelfDelegateForShelfView() override {}
-
-  void set_is_app_pinned(bool is_pinned) { is_app_pinned_ = is_pinned; }
-
-  // ShelfDelegate overrides:
-  ShelfID GetShelfIDForAppID(const std::string& app_id) override {
-    unsigned id = kInvalidShelfID;
-    EXPECT_TRUE(base::StringToUint(app_id, &id));
-    return base::checked_cast<ShelfID>(id);
-  }
-
-  const std::string& GetAppIDForShelfID(ShelfID id) override {
-    // Use |app_id_| member variable because returning a reference to local
-    // variable is not allowed.
-    app_id_ = base::IntToString(id);
-    return app_id_;
-  }
-
-  void PinAppWithID(const std::string& app_id) override { NOTREACHED(); }
-
-  bool IsAppPinned(const std::string& app_id) override {
-    return is_app_pinned_;
-  }
-
-  void UnpinAppWithID(const std::string& app_id) override { NOTREACHED(); }
-
- private:
-  // Tracks whether apps are pinned or not.
-  bool is_app_pinned_ = false;
-
-  // Temp member variable for returning a value. See the comment in the
-  // GetAppIDForShelfID().
-  std::string app_id_;
-
-  DISALLOW_COPY_AND_ASSIGN(TestShelfDelegateForShelfView);
-};
-
 class ShelfViewTest : public AshTestBase {
  public:
   static const char*
@@ -312,82 +254,38 @@
     test_api_.reset(new ShelfViewTestAPI(shelf_view_));
     test_api_->SetAnimationDuration(1);  // Speeds up animation for test.
 
-    ReplaceShelfDelegate();
-
     // Add browser shortcut shelf item at index 0 for test.
-    AddBrowserShortcut();
+    AddItem(TYPE_BROWSER_SHORTCUT, true);
   }
 
   void TearDown() override {
     WebNotificationTray::DisableAnimationsForTest(false);  // Reenable animation
-
-    shelf_delegate_ = nullptr;
     test_api_.reset();
     AshTestBase::TearDown();
   }
 
  protected:
-  void CreateAndSetShelfItemDelegateForID(ShelfID id) {
-    model_->SetShelfItemDelegate(
-        id, base::MakeUnique<TestShelfItemDelegate>(nullptr));
-  }
-
-  ShelfID AddBrowserShortcut() {
-    ShelfItem browser_shortcut;
-    browser_shortcut.type = TYPE_BROWSER_SHORTCUT;
-
-    ShelfID id = model_->next_id();
-    model_->AddAt(browser_index_, browser_shortcut);
-    CreateAndSetShelfItemDelegateForID(id);
-    test_api_->RunMessageLoopUntilAnimationsDone();
-    return id;
-  }
-
-  ShelfID AddAppShortcut() {
+  // Add shelf items of various types, and optionally wait for animations.
+  ShelfID AddItem(ShelfItemType type, bool wait_for_animations) {
     ShelfItem item;
-    item.type = TYPE_PINNED_APP;
-    item.status = STATUS_CLOSED;
+    item.type = type;
+    if (type == TYPE_APP || type == TYPE_APP_PANEL)
+      item.status = STATUS_RUNNING;
 
     ShelfID id = model_->next_id();
+    item.app_launch_id = AppLaunchId(base::IntToString(id));
     model_->Add(item);
-    CreateAndSetShelfItemDelegateForID(id);
-    test_api_->RunMessageLoopUntilAnimationsDone();
+    // Set a delegate; some tests require one to select the item.
+    model_->SetShelfItemDelegate(id,
+                                 base::MakeUnique<ShelfItemSelectionTracker>());
+    if (wait_for_animations)
+      test_api_->RunMessageLoopUntilAnimationsDone();
     return id;
   }
-
-  ShelfID AddPanel() {
-    ShelfID id = AddPanelNoWait();
-    test_api_->RunMessageLoopUntilAnimationsDone();
-    return id;
-  }
-
-  ShelfID AddAppNoWait() {
-    ShelfItem item;
-    item.type = TYPE_APP;
-    item.status = STATUS_RUNNING;
-
-    ShelfID id = model_->next_id();
-    model_->Add(item);
-    CreateAndSetShelfItemDelegateForID(id);
-    return id;
-  }
-
-  ShelfID AddPanelNoWait() {
-    ShelfItem item;
-    item.type = TYPE_APP_PANEL;
-    item.status = STATUS_RUNNING;
-
-    ShelfID id = model_->next_id();
-    model_->Add(item);
-    CreateAndSetShelfItemDelegateForID(id);
-    return id;
-  }
-
-  ShelfID AddApp() {
-    ShelfID id = AddAppNoWait();
-    test_api_->RunMessageLoopUntilAnimationsDone();
-    return id;
-  }
+  ShelfID AddAppShortcut() { return AddItem(TYPE_PINNED_APP, true); }
+  ShelfID AddPanel() { return AddItem(TYPE_APP_PANEL, true); }
+  ShelfID AddAppNoWait() { return AddItem(TYPE_APP, false); }
+  ShelfID AddApp() { return AddItem(TYPE_APP, true); }
 
   void SetShelfItemTypeToAppShortcut(ShelfID id) {
     int index = model_->ItemIndexByID(id);
@@ -682,14 +580,6 @@
     return model_->items()[index].id;
   }
 
-  void ReplaceShelfDelegate() {
-    // Clear the value first to avoid TestShelfDelegate's singleton check.
-    test::ShellTestApi().SetShelfDelegate(nullptr);
-    shelf_delegate_ = new TestShelfDelegateForShelfView();
-    test_api_->SetShelfDelegate(shelf_delegate_);
-    test::ShellTestApi().SetShelfDelegate(base::WrapUnique(shelf_delegate_));
-  }
-
   // Returns the center coordinates for a button. Helper function for an event
   // generator.
   gfx::Point GetButtonCenter(ShelfID button_id) {
@@ -705,9 +595,6 @@
   ShelfView* shelf_view_;
   int browser_index_;
 
-  // Owned by ash::ShellPort.
-  TestShelfDelegateForShelfView* shelf_delegate_;
-
   std::unique_ptr<ShelfViewTestAPI> test_api_;
 
  private:
@@ -1209,18 +1096,15 @@
       browser_shelf_id,
       base::WrapUnique<ShelfItemSelectionTracker>(selection_tracker));
 
-  // A single click selects the item.
+  // A single click selects the item, but a double-click does not.
+  EXPECT_EQ(0u, selection_tracker->item_selected_count());
   SimulateClick(browser_index_);
-  EXPECT_TRUE(selection_tracker->WasSelected());
-
-  // A double-click does not select the item.
-  selection_tracker->Reset();
+  EXPECT_EQ(1u, selection_tracker->item_selected_count());
   SimulateDoubleClick(browser_index_);
-  EXPECT_FALSE(selection_tracker->WasSelected());
+  EXPECT_EQ(1u, selection_tracker->item_selected_count());
 }
 
-// Check that clicking an item and jittering the mouse a bit still selects the
-// item.
+// Check that very small mouse drags do not prevent shelf item selection.
 TEST_F(ShelfViewTest, ClickAndMoveSlightly) {
   std::vector<std::pair<ShelfID, views::View*>> id_map;
   SetupForDragTest(&id_map);
@@ -1228,8 +1112,7 @@
   ShelfID shelf_id = (id_map.begin() + 1)->first;
   views::View* button = (id_map.begin() + 1)->second;
 
-  // Replace the ShelfItemDelegate for |shelf_id| with one which tracks whether
-  // the shelf item gets selected.
+  // Install a ShelfItemDelegate that tracks when the shelf item is selected.
   ShelfItemSelectionTracker* selection_tracker = new ShelfItemSelectionTracker;
   model_->SetShelfItemDelegate(
       shelf_id, base::WrapUnique<ShelfItemSelectionTracker>(selection_tracker));
@@ -1243,26 +1126,26 @@
                              press_location_in_screen, ui::EventTimeForNow(),
                              ui::EF_LEFT_MOUSE_BUTTON, 0);
   button->OnMousePressed(click_event);
+  EXPECT_EQ(0u, selection_tracker->item_selected_count());
 
   ui::MouseEvent drag_event1(
       ui::ET_MOUSE_DRAGGED, press_location + gfx::Vector2d(0, 1),
       press_location_in_screen + gfx::Vector2d(0, 1), ui::EventTimeForNow(),
       ui::EF_LEFT_MOUSE_BUTTON, 0);
   button->OnMouseDragged(drag_event1);
-
   ui::MouseEvent drag_event2(
       ui::ET_MOUSE_DRAGGED, press_location + gfx::Vector2d(-1, 0),
       press_location_in_screen + gfx::Vector2d(-1, 0), ui::EventTimeForNow(),
       ui::EF_LEFT_MOUSE_BUTTON, 0);
   button->OnMouseDragged(drag_event2);
+  EXPECT_EQ(0u, selection_tracker->item_selected_count());
 
   ui::MouseEvent release_event(
       ui::ET_MOUSE_RELEASED, press_location + gfx::Vector2d(-1, 0),
       press_location_in_screen + gfx::Vector2d(-1, 0), ui::EventTimeForNow(),
       ui::EF_LEFT_MOUSE_BUTTON, 0);
   button->OnMouseReleased(release_event);
-
-  EXPECT_TRUE(selection_tracker->WasSelected());
+  EXPECT_EQ(1u, selection_tracker->item_selected_count());
 }
 
 // Confirm that item status changes are reflected in the buttons.
@@ -1552,7 +1435,6 @@
 
 // Checks the overflow bubble size when an item is ripped off and re-inserted.
 TEST_F(ShelfViewTest, OverflowBubbleSize) {
-  shelf_delegate_->set_is_app_pinned(true);
   AddButtonsUntilOverflow();
   // Add one more button to prevent the overflow bubble to disappear upon
   // dragging an item out on windows (flakiness, see crbug.com/436131).
@@ -2012,23 +1894,25 @@
 };
 
 // A ShelfItemDelegate that returns a menu for the shelf item.
-class ListMenuShelfItemDelegate : public TestShelfItemDelegate {
+class ListMenuShelfItemDelegate : public ShelfItemDelegate {
  public:
-  ListMenuShelfItemDelegate() : TestShelfItemDelegate(nullptr) {}
+  ListMenuShelfItemDelegate() : ShelfItemDelegate(AppLaunchId()) {}
   ~ListMenuShelfItemDelegate() override {}
 
  private:
-  // TestShelfItemDelegate:
+  // ShelfItemDelegate:
   void ItemSelected(std::unique_ptr<ui::Event> event,
                     int64_t display_id,
                     ShelfLaunchSource source,
                     const ItemSelectedCallback& callback) override {
     // Two items are needed to show a menu; the data in the items is not tested.
     std::vector<mojom::MenuItemPtr> items;
-    items.push_back(ash::mojom::MenuItem::New());
-    items.push_back(ash::mojom::MenuItem::New());
-    callback.Run(ash::SHELF_ACTION_NONE, std::move(items));
+    items.push_back(mojom::MenuItem::New());
+    items.push_back(mojom::MenuItem::New());
+    callback.Run(SHELF_ACTION_NONE, std::move(items));
   }
+  void ExecuteCommand(uint32_t command_id, int32_t event_flags) override {}
+  void Close() override {}
 
   DISALLOW_COPY_AND_ASSIGN(ListMenuShelfItemDelegate);
 };
diff --git a/ash/shelf/wm_shelf.cc b/ash/shelf/wm_shelf.cc
index e7373bbd..79ee471 100644
--- a/ash/shelf/wm_shelf.cc
+++ b/ash/shelf/wm_shelf.cc
@@ -10,7 +10,6 @@
 #include "ash/root_window_controller.h"
 #include "ash/shelf/shelf_bezel_event_handler.h"
 #include "ash/shelf/shelf_controller.h"
-#include "ash/shelf/shelf_delegate.h"
 #include "ash/shelf/shelf_layout_manager.h"
 #include "ash/shelf/shelf_locking_manager.h"
 #include "ash/shelf/shelf_model.h"
diff --git a/ash/shell_port.h b/ash/shell_port.h
index 9585d47..db553d2c 100644
--- a/ash/shell_port.h
+++ b/ash/shell_port.h
@@ -23,6 +23,7 @@
 namespace display {
 class Display;
 class ManagedDisplayInfo;
+class NativeDisplayDelegate;
 }
 
 namespace gfx {
@@ -37,6 +38,8 @@
 
 namespace ash {
 class AcceleratorController;
+class AshWindowTreeHost;
+struct AshWindowTreeHostInitParams;
 class ImmersiveFullscreenController;
 class KeyEventWatcher;
 class KeyboardUI;
@@ -204,6 +207,11 @@
 
   virtual void CreatePointerWatcherAdapter() = 0;
 
+  // Creates an AshWindowTreeHost. A return value of null results in a platform
+  // specific AshWindowTreeHost being created.
+  virtual std::unique_ptr<AshWindowTreeHost> CreateAshWindowTreeHost(
+      const AshWindowTreeHostInitParams& init_params) = 0;
+
  protected:
   ShellPort();
 
@@ -211,6 +219,8 @@
   // the corresponding RootWindowController.
   virtual void CreatePrimaryHost() = 0;
   virtual void InitHosts(const ShellInitParams& init_params) = 0;
+  virtual std::unique_ptr<display::NativeDisplayDelegate>
+  CreateNativeDisplayDelegate() = 0;
 
   // Called during startup to create the AcceleratorController.
   virtual std::unique_ptr<AcceleratorController>
diff --git a/ash/system/network/network_state_list_detailed_view.cc b/ash/system/network/network_state_list_detailed_view.cc
index 9bb2996..2fd64f3 100644
--- a/ash/system/network/network_state_list_detailed_view.cc
+++ b/ash/system/network/network_state_list_detailed_view.cc
@@ -11,6 +11,7 @@
 #include "ash/public/cpp/shell_window_ids.h"
 #include "ash/resources/vector_icons/vector_icons.h"
 #include "ash/root_window_controller.h"
+#include "ash/session/session_controller.h"
 #include "ash/shell.h"
 #include "ash/shell_port.h"
 #include "ash/strings/grit/ash_strings.h"
@@ -339,8 +340,8 @@
     // Allow the user to access settings only if user is logged in
     // and showing settings is allowed. There are situations (supervised user
     // creation flow) when session is started but UI flow continues within
-    // login UI, i.e., no browser window is yet avaialable.
-    if (!Shell::Get()->system_tray_delegate()->ShouldShowSettings())
+    // login UI, i.e., no browser window is yet available.
+    if (!Shell::Get()->session_controller()->ShouldEnableSettings())
       settings_button_->SetEnabled(false);
 
     tri_view()->AddView(TriView::Container::END, settings_button_);
diff --git a/ash/system/screen_layout_observer.cc b/ash/system/screen_layout_observer.cc
index c7ea0e5..0ead7c5 100644
--- a/ash/system/screen_layout_observer.cc
+++ b/ash/system/screen_layout_observer.cc
@@ -11,6 +11,7 @@
 #include "ash/display/screen_orientation_controller_chromeos.h"
 #include "ash/metrics/user_metrics_action.h"
 #include "ash/resources/grit/ash_resources.h"
+#include "ash/session/session_controller.h"
 #include "ash/shell.h"
 #include "ash/shell_port.h"
 #include "ash/strings/grit/ash_strings.h"
@@ -18,7 +19,6 @@
 #include "ash/system/system_notifier.h"
 #include "ash/system/tray/fixed_sized_image_view.h"
 #include "ash/system/tray/system_tray_controller.h"
-#include "ash/system/tray/system_tray_delegate.h"
 #include "ash/system/tray/tray_constants.h"
 #include "base/bind.h"
 #include "base/strings/string_util.h"
@@ -64,38 +64,13 @@
   return base::UTF8ToUTF16(display->size().ToString());
 }
 
-// Attempts to open the display settings, returns true if successful.
-bool OpenSettings() {
-  // switch is intentionally introduced without default, to cause an error when
-  // a new type of login status is introduced.
-  switch (Shell::Get()->system_tray_delegate()->GetUserLoginStatus()) {
-    case LoginStatus::NOT_LOGGED_IN:
-    case LoginStatus::LOCKED:
-      return false;
-
-    case LoginStatus::USER:
-    case LoginStatus::OWNER:
-    case LoginStatus::GUEST:
-    case LoginStatus::PUBLIC:
-    case LoginStatus::SUPERVISED:
-    case LoginStatus::KIOSK_APP:
-    case LoginStatus::ARC_KIOSK_APP:
-      SystemTrayDelegate* delegate = Shell::Get()->system_tray_delegate();
-      if (delegate->ShouldShowSettings()) {
-        Shell::Get()->system_tray_controller()->ShowDisplaySettings();
-        return true;
-      }
-      break;
-  }
-
-  return false;
-}
-
 // Callback to handle a user selecting the notification view.
 void OpenSettingsFromNotification() {
   ShellPort::Get()->RecordUserMetricsAction(
       UMA_STATUS_AREA_DISPLAY_NOTIFICATION_SELECTED);
-  if (OpenSettings()) {
+  // Settings may be blocked, e.g. at the lock screen.
+  if (Shell::Get()->session_controller()->ShouldEnableSettings()) {
+    Shell::Get()->system_tray_controller()->ShowDisplaySettings();
     ShellPort::Get()->RecordUserMetricsAction(
         UMA_STATUS_AREA_DISPLAY_NOTIFICATION_SHOW_SETTINGS);
   }
diff --git a/ash/system/tiles/tiles_default_view.cc b/ash/system/tiles/tiles_default_view.cc
index 52bf8c1..216d1b7c 100644
--- a/ash/system/tiles/tiles_default_view.cc
+++ b/ash/system/tiles/tiles_default_view.cc
@@ -14,7 +14,6 @@
 #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/system_tray_item.h"
 #include "ash/system/tray/tray_constants.h"
 #include "ash/system/tray/tray_popup_utils.h"
@@ -66,7 +65,7 @@
       this, TrayPopupInkDropStyle::HOST_CENTERED, kSystemMenuSettingsIcon,
       IDS_ASH_STATUS_TRAY_SETTINGS);
   if (disable_buttons ||
-      !Shell::Get()->system_tray_delegate()->ShouldShowSettings())
+      !Shell::Get()->session_controller()->ShouldEnableSettings())
     settings_button_->SetEnabled(false);
   AddChildView(settings_button_);
   AddChildView(TrayPopupUtils::CreateVerticalSeparator());
diff --git a/ash/system/tray/default_system_tray_delegate.cc b/ash/system/tray/default_system_tray_delegate.cc
index da18b14a..fa8bfd9 100644
--- a/ash/system/tray/default_system_tray_delegate.cc
+++ b/ash/system/tray/default_system_tray_delegate.cc
@@ -26,12 +26,4 @@
   return GetUserLoginStatus() == LoginStatus::SUPERVISED;
 }
 
-bool DefaultSystemTrayDelegate::ShouldShowSettings() const {
-  return true;
-}
-
-bool DefaultSystemTrayDelegate::ShouldShowNotificationTray() const {
-  return true;
-}
-
 }  // namespace ash
diff --git a/ash/system/tray/default_system_tray_delegate.h b/ash/system/tray/default_system_tray_delegate.h
index 4e26539..461f353 100644
--- a/ash/system/tray/default_system_tray_delegate.h
+++ b/ash/system/tray/default_system_tray_delegate.h
@@ -20,8 +20,6 @@
   LoginStatus GetUserLoginStatus() const override;
   std::string GetSupervisedUserManager() const override;
   bool IsUserSupervised() const override;
-  bool ShouldShowSettings() const override;
-  bool ShouldShowNotificationTray() const override;
 
  private:
   DISALLOW_COPY_AND_ASSIGN(DefaultSystemTrayDelegate);
diff --git a/ash/system/tray/system_tray_delegate.cc b/ash/system/tray/system_tray_delegate.cc
index f1ff267..10669a0a 100644
--- a/ash/system/tray/system_tray_delegate.cc
+++ b/ash/system/tray/system_tray_delegate.cc
@@ -51,14 +51,6 @@
   return false;
 }
 
-bool SystemTrayDelegate::ShouldShowSettings() const {
-  return false;
-}
-
-bool SystemTrayDelegate::ShouldShowNotificationTray() const {
-  return false;
-}
-
 void SystemTrayDelegate::ShowEnterpriseInfo() {}
 
 void SystemTrayDelegate::ShowUserLogin() {}
diff --git a/ash/system/tray/system_tray_delegate.h b/ash/system/tray/system_tray_delegate.h
index 4eace68e..8cb3f2c 100644
--- a/ash/system/tray/system_tray_delegate.h
+++ b/ash/system/tray/system_tray_delegate.h
@@ -86,12 +86,6 @@
   // crbug.com/443119
   virtual bool IsUserChild() const;
 
-  // Returns true if settings menu item should appear.
-  virtual bool ShouldShowSettings() const;
-
-  // Returns true if notification tray should appear.
-  virtual bool ShouldShowNotificationTray() const;
-
   // Shows information about enterprise enrolled devices.
   virtual void ShowEnterpriseInfo();
 
diff --git a/ash/system/web_notification/web_notification_tray.cc b/ash/system/web_notification/web_notification_tray.cc
index e26a544..20d91494 100644
--- a/ash/system/web_notification/web_notification_tray.cc
+++ b/ash/system/web_notification/web_notification_tray.cc
@@ -395,8 +395,9 @@
 
 // Private methods.
 
-bool WebNotificationTray::ShouldShowMessageCenter() {
-  return Shell::Get()->system_tray_delegate()->ShouldShowNotificationTray();
+bool WebNotificationTray::ShouldShowMessageCenter() const {
+  // Hidden at login screen, during supervised user creation, etc.
+  return Shell::Get()->session_controller()->ShouldShowNotificationTray();
 }
 
 bool WebNotificationTray::ShouldBlockShelfAutoHide() const {
@@ -496,7 +497,7 @@
 }
 
 bool WebNotificationTray::IsContextMenuEnabled() const {
-  return IsLoggedIn();
+  return ShouldShowMessageCenter();
 }
 
 message_center::MessageCenterTray* WebNotificationTray::GetMessageCenterTray() {
@@ -592,11 +593,11 @@
     counter_->SetVisible(false);
   }
 
-  SetVisible(IsLoggedIn() && ShouldShowMessageCenter());
+  SetVisible(ShouldShowMessageCenter());
   PreferredSizeChanged();
   Layout();
   SchedulePaint();
-  if (IsLoggedIn())
+  if (ShouldShowMessageCenter())
     system_tray_->SetNextFocusableView(this);
 }
 
@@ -612,12 +613,6 @@
   return message_center_tray_->message_center();
 }
 
-bool WebNotificationTray::IsLoggedIn() const {
-  return Shell::Get()->system_tray_delegate()->GetUserLoginStatus() !=
-             LoginStatus::NOT_LOGGED_IN &&
-         !Shell::Get()->session_controller()->IsInSecondaryLoginScreen();
-}
-
 // Methods for testing
 
 bool WebNotificationTray::IsPopupVisible() const {
diff --git a/ash/system/web_notification/web_notification_tray.h b/ash/system/web_notification/web_notification_tray.h
index 920baa4..9dd0109 100644
--- a/ash/system/web_notification/web_notification_tray.h
+++ b/ash/system/web_notification/web_notification_tray.h
@@ -134,7 +134,7 @@
 
   // Queries login status and the status area widget to determine visibility of
   // the message center.
-  bool ShouldShowMessageCenter();
+  bool ShouldShowMessageCenter() const;
 
   // Returns true if it should show the quiet mode menu.
   bool ShouldShowQuietModeMenu(const ui::Event& event);
@@ -149,10 +149,6 @@
     return message_center_bubble_.get();
   }
 
-  // Returns true if any user is logged in and the system is not at the screen
-  // for adding a secondary user.
-  bool IsLoggedIn() const;
-
   // Testing accessors.
   bool IsPopupVisible() const;
   message_center::MessageCenterBubble* GetMessageCenterBubbleForTest();
diff --git a/ash/test/ash_test_base.cc b/ash/test/ash_test_base.cc
index ec5972b..b319cd83 100644
--- a/ash/test/ash_test_base.cc
+++ b/ash/test/ash_test_base.cc
@@ -13,6 +13,7 @@
 #include "ash/display/window_tree_host_manager.h"
 #include "ash/ime/input_method_event_handler.h"
 #include "ash/public/cpp/config.h"
+#include "ash/public/cpp/window_properties.h"
 #include "ash/root_window_controller.h"
 #include "ash/session/session_controller.h"
 #include "ash/shell.h"
@@ -248,6 +249,20 @@
       new aura::test::ColorTestWindowDelegate(color), id, bounds);
 }
 
+std::unique_ptr<aura::Window> AshTestBase::CreateChildWindow(
+    aura::Window* parent,
+    const gfx::Rect& bounds,
+    int shell_window_id) {
+  std::unique_ptr<aura::Window> window =
+      base::MakeUnique<aura::Window>(nullptr, ui::wm::WINDOW_TYPE_NORMAL);
+  window->Init(ui::LAYER_NOT_DRAWN);
+  window->SetBounds(bounds);
+  window->set_id(shell_window_id);
+  parent->AddChild(window.get());
+  window->Show();
+  return window;
+}
+
 aura::Window* AshTestBase::CreateTestWindowInShellWithDelegate(
     aura::WindowDelegate* delegate,
     int id,
@@ -284,6 +299,9 @@
                       ui::mojom::kResizeBehaviorCanMaximize |
                           ui::mojom::kResizeBehaviorCanMinimize |
                           ui::mojom::kResizeBehaviorCanResize);
+  // Setting the item type triggers ShelfWindowWatcher to create a shelf item.
+  if (type == ui::wm::WINDOW_TYPE_PANEL)
+    window->SetProperty<int>(kShelfItemTypeKey, TYPE_APP_PANEL);
 
   return window;
 }
diff --git a/ash/test/ash_test_base.h b/ash/test/ash_test_base.h
index 21eeea6..4837d39 100644
--- a/ash/test/ash_test_base.h
+++ b/ash/test/ash_test_base.h
@@ -10,6 +10,7 @@
 #include <memory>
 #include <string>
 
+#include "ash/public/cpp/shell_window_ids.h"
 #include "base/macros.h"
 #include "base/message_loop/message_loop.h"
 #include "base/threading/thread.h"
@@ -98,6 +99,14 @@
   aura::Window* CreateTestWindowInShell(SkColor color,
                                         int id,
                                         const gfx::Rect& bounds);
+
+  // Creates a visible window parented to |parent| with the specified bounds and
+  // id.
+  std::unique_ptr<aura::Window> CreateChildWindow(
+      aura::Window* parent,
+      const gfx::Rect& bounds = gfx::Rect(),
+      int shell_window_id = kShellWindowId_Invalid);
+
   aura::Window* CreateTestWindowInShellWithDelegate(
       aura::WindowDelegate* delegate,
       int id,
diff --git a/ash/test/test_session_controller_client.cc b/ash/test/test_session_controller_client.cc
index 35fef7e..5d907cc90 100644
--- a/ash/test/test_session_controller_client.cc
+++ b/ash/test/test_session_controller_client.cc
@@ -104,6 +104,8 @@
       AccountId::FromUserEmail(GetUserIdFromEmail(display_email));
   session->display_name = "Über tray Über tray Über tray Über tray";
   session->display_email = display_email;
+  session->should_enable_settings = true;
+  session->should_show_notification_tray = true;
   controller_->UpdateUserSession(std::move(session));
 }
 
diff --git a/ash/test/test_shelf_delegate.cc b/ash/test/test_shelf_delegate.cc
index c438fe4..0fef1c7 100644
--- a/ash/test/test_shelf_delegate.cc
+++ b/ash/test/test_shelf_delegate.cc
@@ -4,64 +4,16 @@
 
 #include "ash/test/test_shelf_delegate.h"
 
-#include <utility>
-
-#include "ash/root_window_controller.h"
 #include "ash/shelf/shelf_model.h"
-#include "ash/shelf/wm_shelf.h"
 #include "ash/shell.h"
-#include "ash/shell_observer.h"
-#include "ash/test/test_shelf_item_delegate.h"
-#include "ash/wm/window_properties.h"
-#include "ash/wm_window.h"
-#include "base/memory/ptr_util.h"
-#include "ui/aura/window.h"
+#include "base/strings/string_util.h"
 
 namespace ash {
 namespace test {
 
-namespace {
-
-// Set the |type| of the item with the given |shelf_id|, if the item exists.
-void SetItemType(ShelfID shelf_id, ShelfItemType type) {
-  ShelfModel* model = Shell::Get()->shelf_model();
-  ash::ShelfItems::const_iterator item = model->ItemByID(shelf_id);
-  if (item != model->items().end()) {
-    ShelfItem pinned_item = *item;
-    pinned_item.type = type;
-    model->Set(item - model->items().begin(), pinned_item);
-  }
-}
-
-}  // namespace
-
 TestShelfDelegate* TestShelfDelegate::instance_ = nullptr;
 
-// A ShellObserver that sets the shelf alignment and auto hide behavior when the
-// shelf is created, to simulate ChromeLauncherController's behavior.
-class ShelfInitializer : public ShellObserver {
- public:
-  ShelfInitializer() { Shell::Get()->AddShellObserver(this); }
-  ~ShelfInitializer() override { Shell::Get()->RemoveShellObserver(this); }
-
-  // ShellObserver:
-  void OnShelfCreatedForRootWindow(WmWindow* root_window) override {
-    WmShelf* shelf = root_window->GetRootWindowController()->GetShelf();
-    // Do not override the custom initialization performed by some unit tests.
-    if (shelf->alignment() == SHELF_ALIGNMENT_BOTTOM_LOCKED &&
-        shelf->auto_hide_behavior() == SHELF_AUTO_HIDE_ALWAYS_HIDDEN) {
-      shelf->SetAlignment(SHELF_ALIGNMENT_BOTTOM);
-      shelf->SetAutoHideBehavior(SHELF_AUTO_HIDE_BEHAVIOR_NEVER);
-      shelf->UpdateVisibilityState();
-    }
-  }
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(ShelfInitializer);
-};
-
-TestShelfDelegate::TestShelfDelegate()
-    : shelf_initializer_(base::MakeUnique<ShelfInitializer>()) {
+TestShelfDelegate::TestShelfDelegate() {
   CHECK(!instance_);
   instance_ = this;
 }
@@ -70,57 +22,6 @@
   instance_ = nullptr;
 }
 
-void TestShelfDelegate::AddShelfItem(WmWindow* window) {
-  AddShelfItem(window, std::string());
-}
-
-void TestShelfDelegate::AddShelfItem(WmWindow* window,
-                                     const std::string& app_id) {
-  ShelfItem item;
-  if (!app_id.empty())
-    item.app_launch_id = AppLaunchId(app_id);
-  if (window->GetType() == ui::wm::WINDOW_TYPE_PANEL)
-    item.type = TYPE_APP_PANEL;
-  else
-    item.type = TYPE_APP;
-  ShelfModel* model = Shell::Get()->shelf_model();
-  ShelfID id = model->next_id();
-  item.status = STATUS_CLOSED;
-  model->Add(item);
-  window->aura_window()->AddObserver(this);
-
-  model->SetShelfItemDelegate(id,
-                              base::MakeUnique<TestShelfItemDelegate>(window));
-  window->aura_window()->SetProperty(kShelfIDKey, id);
-}
-
-void TestShelfDelegate::RemoveShelfItemForWindow(WmWindow* window) {
-  ShelfID shelf_id = window->aura_window()->GetProperty(kShelfIDKey);
-  if (shelf_id == 0)
-    return;
-  ShelfModel* model = Shell::Get()->shelf_model();
-  int index = model->ItemIndexByID(shelf_id);
-  DCHECK_NE(-1, index);
-  model->RemoveItemAt(index);
-  window->aura_window()->RemoveObserver(this);
-  const std::string& app_id = GetAppIDForShelfID(shelf_id);
-  if (IsAppPinned(app_id))
-    UnpinAppWithID(app_id);
-}
-
-void TestShelfDelegate::OnWindowDestroying(aura::Window* window) {
-  RemoveShelfItemForWindow(WmWindow::Get(window));
-}
-
-void TestShelfDelegate::OnWindowHierarchyChanging(
-    const HierarchyChangeParams& params) {
-  // The window may be legitimately reparented while staying open if it moves
-  // to another display or container. If the window does not have a new parent
-  // then remove the shelf item.
-  if (!params.new_parent)
-    RemoveShelfItemForWindow(WmWindow::Get(params.target));
-}
-
 ShelfID TestShelfDelegate::GetShelfIDForAppID(const std::string& app_id) {
   // Get shelf id for |app_id| and an empty |launch_id|.
   return GetShelfIDForAppIDAndLaunchID(app_id, std::string());
@@ -141,23 +42,57 @@
 
 const std::string& TestShelfDelegate::GetAppIDForShelfID(ShelfID id) {
   ShelfModel* model = Shell::Get()->shelf_model();
-  ash::ShelfItems::const_iterator item = model->ItemByID(id);
+  ShelfItems::const_iterator item = model->ItemByID(id);
   return item != model->items().end() ? item->app_launch_id.app_id()
                                       : base::EmptyString();
 }
 
 void TestShelfDelegate::PinAppWithID(const std::string& app_id) {
-  SetItemType(GetShelfIDForAppID(app_id), TYPE_PINNED_APP);
-  pinned_apps_.insert(app_id);
+  // If the app is already pinned, do nothing and return.
+  if (IsAppPinned(app_id))
+    return;
+
+  // Convert an existing item to be pinned, or create a new pinned item.
+  ShelfModel* model = Shell::Get()->shelf_model();
+  const int index = model->ItemIndexByID(GetShelfIDForAppID(app_id));
+  if (index >= 0) {
+    ShelfItem item = model->items()[index];
+    DCHECK_EQ(item.type, TYPE_APP);
+    DCHECK(!item.pinned_by_policy);
+    item.type = TYPE_PINNED_APP;
+    model->Set(index, item);
+  } else if (!app_id.empty()) {
+    ShelfItem item;
+    item.type = TYPE_PINNED_APP;
+    item.app_launch_id = AppLaunchId(app_id);
+    model->Add(item);
+  }
 }
 
 bool TestShelfDelegate::IsAppPinned(const std::string& app_id) {
-  return pinned_apps_.find(app_id) != pinned_apps_.end();
+  ShelfID shelf_id = GetShelfIDForAppID(app_id);
+  ShelfModel* model = Shell::Get()->shelf_model();
+  ShelfItems::const_iterator item = model->ItemByID(shelf_id);
+  return item != model->items().end() && item->type == TYPE_PINNED_APP;
 }
 
 void TestShelfDelegate::UnpinAppWithID(const std::string& app_id) {
-  SetItemType(GetShelfIDForAppID(app_id), TYPE_APP);
-  pinned_apps_.erase(app_id);
+  // If the app is already not pinned, do nothing and return.
+  if (!IsAppPinned(app_id))
+    return;
+
+  // Remove the item if it is closed, or mark it as unpinned.
+  ShelfModel* model = Shell::Get()->shelf_model();
+  const int index = model->ItemIndexByID(GetShelfIDForAppID(app_id));
+  ShelfItem item = model->items()[index];
+  DCHECK_EQ(item.type, TYPE_PINNED_APP);
+  DCHECK(!item.pinned_by_policy);
+  if (item.status == STATUS_CLOSED) {
+    model->RemoveItemAt(index);
+  } else {
+    item.type = TYPE_APP;
+    model->Set(index, item);
+  }
 }
 
 }  // namespace test
diff --git a/ash/test/test_shelf_delegate.h b/ash/test/test_shelf_delegate.h
index 5b5673b7..ddf1549 100644
--- a/ash/test/test_shelf_delegate.h
+++ b/ash/test/test_shelf_delegate.h
@@ -5,48 +5,22 @@
 #ifndef ASH_TEST_TEST_SHELF_DELEGATE_H_
 #define ASH_TEST_TEST_SHELF_DELEGATE_H_
 
-#include <memory>
-#include <set>
 #include <string>
 
 #include "ash/shelf/shelf_delegate.h"
 #include "base/macros.h"
-#include "ui/aura/window_observer.h"
 
 namespace ash {
-
-class WmWindow;
-
 namespace test {
 
-class ShelfInitializer;
-
 // Test implementation of ShelfDelegate.
-// Tests may create icons for windows by calling AddShelfItem().
-class TestShelfDelegate : public ShelfDelegate, public aura::WindowObserver {
+class TestShelfDelegate : public ShelfDelegate {
  public:
   TestShelfDelegate();
   ~TestShelfDelegate() override;
 
-  // Adds a ShelfItem for the given |window|. The ShelfItem's status will be
-  // STATUS_CLOSED.
-  void AddShelfItem(WmWindow* window);
-
-  // Adds a ShelfItem for the given |window| and |app_id|. The ShelfItem's
-  // status will be STATUS_CLOSED.
-  void AddShelfItem(WmWindow* window, const std::string& app_id);
-
-  // Removes the ShelfItem for the specified |window| and unpins it if it was
-  // pinned. The |window|'s ShelfID to app id mapping will be removed if it
-  // exists.
-  void RemoveShelfItemForWindow(WmWindow* window);
-
   static TestShelfDelegate* instance() { return instance_; }
 
-  // WindowObserver implementation
-  void OnWindowDestroying(aura::Window* window) override;
-  void OnWindowHierarchyChanging(const HierarchyChangeParams& params) override;
-
   // ShelfDelegate implementation.
   ShelfID GetShelfIDForAppID(const std::string& app_id) override;
   ShelfID GetShelfIDForAppIDAndLaunchID(const std::string& app_id,
@@ -59,10 +33,6 @@
  private:
   static TestShelfDelegate* instance_;
 
-  std::unique_ptr<ShelfInitializer> shelf_initializer_;
-
-  std::set<std::string> pinned_apps_;
-
   DISALLOW_COPY_AND_ASSIGN(TestShelfDelegate);
 };
 
diff --git a/ash/test/test_shell_delegate.cc b/ash/test/test_shell_delegate.cc
index 26c1964..27c12b0 100644
--- a/ash/test/test_shell_delegate.cc
+++ b/ash/test/test_shell_delegate.cc
@@ -10,7 +10,11 @@
 #include "ash/gpu_support_stub.h"
 #include "ash/palette_delegate.h"
 #include "ash/public/cpp/shell_window_ids.h"
+#include "ash/root_window_controller.h"
 #include "ash/session/session_state_delegate.h"
+#include "ash/shelf/wm_shelf.h"
+#include "ash/shell.h"
+#include "ash/shell_observer.h"
 #include "ash/system/tray/system_tray_notifier.h"
 #include "ash/test/test_keyboard_ui.h"
 #include "ash/test/test_session_state_delegate.h"
@@ -19,6 +23,7 @@
 #include "ash/test/test_wallpaper_delegate.h"
 #include "ash/wm/window_state.h"
 #include "ash/wm/window_util.h"
+#include "ash/wm_window.h"
 #include "base/logging.h"
 #include "base/memory/ptr_util.h"
 #include "ui/aura/window.h"
@@ -27,6 +32,29 @@
 namespace ash {
 namespace test {
 
+// A ShellObserver that sets the shelf alignment and auto hide behavior when the
+// shelf is created, to simulate ChromeLauncherController's behavior.
+class ShelfInitializer : public ShellObserver {
+ public:
+  ShelfInitializer() { Shell::Get()->AddShellObserver(this); }
+  ~ShelfInitializer() override { Shell::Get()->RemoveShellObserver(this); }
+
+  // ShellObserver:
+  void OnShelfCreatedForRootWindow(WmWindow* root_window) override {
+    WmShelf* shelf = root_window->GetRootWindowController()->GetShelf();
+    // Do not override the custom initialization performed by some unit tests.
+    if (shelf->alignment() == SHELF_ALIGNMENT_BOTTOM_LOCKED &&
+        shelf->auto_hide_behavior() == SHELF_AUTO_HIDE_ALWAYS_HIDDEN) {
+      shelf->SetAlignment(SHELF_ALIGNMENT_BOTTOM);
+      shelf->SetAutoHideBehavior(SHELF_AUTO_HIDE_BEHAVIOR_NEVER);
+      shelf->UpdateVisibilityState();
+    }
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(ShelfInitializer);
+};
+
 TestShellDelegate::TestShellDelegate()
     : num_exit_requests_(0),
       multi_profiles_enabled_(false),
@@ -74,6 +102,8 @@
 void TestShellDelegate::OpenUrlFromArc(const GURL& url) {}
 
 ShelfDelegate* TestShellDelegate::CreateShelfDelegate(ShelfModel* model) {
+  // Create a separate shelf initializer that mimics ChromeLauncherController.
+  shelf_initializer_ = base::MakeUnique<ShelfInitializer>();
   return new TestShelfDelegate();
 }
 
diff --git a/ash/test/test_shell_delegate.h b/ash/test/test_shell_delegate.h
index 296ea3fc..ab64ef4e9 100644
--- a/ash/test/test_shell_delegate.h
+++ b/ash/test/test_shell_delegate.h
@@ -19,6 +19,8 @@
 namespace ash {
 namespace test {
 
+class ShelfInitializer;
+
 class TestShellDelegate : public ShellDelegate {
  public:
   TestShellDelegate();
@@ -68,6 +70,7 @@
   bool multi_profiles_enabled_;
   bool force_maximize_on_first_run_;
   bool touchscreen_enabled_in_local_pref_;
+  std::unique_ptr<ShelfInitializer> shelf_initializer_;
 
   DISALLOW_COPY_AND_ASSIGN(TestShellDelegate);
 };
diff --git a/ash/wm/overview/window_selector_unittest.cc b/ash/wm/overview/window_selector_unittest.cc
index 3548346f..892bcd4 100644
--- a/ash/wm/overview/window_selector_unittest.cc
+++ b/ash/wm/overview/window_selector_unittest.cc
@@ -16,7 +16,6 @@
 #include "ash/test/shelf_view_test_api.h"
 #include "ash/test/shell_test_api.h"
 #include "ash/test/test_app_list_view_presenter_impl.h"
-#include "ash/test/test_shelf_delegate.h"
 #include "ash/wm/maximize_mode/maximize_mode_controller.h"
 #include "ash/wm/overview/window_grid.h"
 #include "ash/wm/overview/window_selector.h"
@@ -147,7 +146,6 @@
     aura::Window* window = CreateTestWindowInShellWithDelegateAndType(
         nullptr, ui::wm::WINDOW_TYPE_PANEL, 0, bounds);
     window->SetProperty(aura::client::kTopViewInset, kHeaderHeight);
-    test::TestShelfDelegate::instance()->AddShelfItem(WmWindow::Get(window));
     shelf_view_test()->RunMessageLoopUntilAnimationsDone();
     return window;
   }
diff --git a/ash/wm/panels/panel_layout_manager_unittest.cc b/ash/wm/panels/panel_layout_manager_unittest.cc
index 52c0804..1e4c026 100644
--- a/ash/wm/panels/panel_layout_manager_unittest.cc
+++ b/ash/wm/panels/panel_layout_manager_unittest.cc
@@ -18,7 +18,6 @@
 #include "ash/system/web_notification/web_notification_tray.h"
 #include "ash/test/ash_test_base.h"
 #include "ash/test/shelf_view_test_api.h"
-#include "ash/test/test_shelf_delegate.h"
 #include "ash/wm/mru_window_tracker.h"
 #include "ash/wm/window_properties.h"
 #include "ash/wm/window_state.h"
@@ -90,7 +89,6 @@
                                               const gfx::Rect& bounds) {
     aura::Window* window = CreateTestWindowInShellWithDelegateAndType(
         delegate, ui::wm::WINDOW_TYPE_PANEL, 0, bounds);
-    test::TestShelfDelegate::instance()->AddShelfItem(WmWindow::Get(window));
     shelf_view_test()->RunMessageLoopUntilAnimationsDone();
     return window;
   }
@@ -482,11 +480,15 @@
   wm::ActivateWindow(w1.get());
   shelf_view_test()->RunMessageLoopUntilAnimationsDone();
   EXPECT_TRUE(WindowIsAbove(w1.get(), w2.get()));
-  EXPECT_TRUE(WindowIsAbove(w2.get(), w3.get()));
+  // TODO(crbug.com/698887): investigate failure in Mash.
+  if (Shell::GetAshConfig() != Config::MASH)
+    EXPECT_TRUE(WindowIsAbove(w2.get(), w3.get()));
 
   wm::ActivateWindow(w2.get());
   shelf_view_test()->RunMessageLoopUntilAnimationsDone();
-  EXPECT_TRUE(WindowIsAbove(w1.get(), w3.get()));
+  // TODO(crbug.com/698887): investigate failure in Mash.
+  if (Shell::GetAshConfig() != Config::MASH)
+    EXPECT_TRUE(WindowIsAbove(w1.get(), w3.get()));
   EXPECT_TRUE(WindowIsAbove(w2.get(), w3.get()));
   EXPECT_TRUE(WindowIsAbove(w2.get(), w1.get()));
 
@@ -506,7 +508,7 @@
   EXPECT_TRUE(IsPanelCalloutVisible(w2.get()));
   EXPECT_TRUE(IsPanelCalloutVisible(w3.get()));
 
-  // TODO: investigate failure. http://crbug.com/698887.
+  // TODO(crbug.com/698887): investigate failure in Mash.
   if (Shell::GetAshConfig() == Config::MASH)
     return;
 
@@ -629,9 +631,14 @@
       shelf->GetScreenBoundsOfItemIconForWindow(WmWindow::Get(w1.get())).x();
   int icon_x2 =
       shelf->GetScreenBoundsOfItemIconForWindow(WmWindow::Get(w2.get())).x();
-  EXPECT_EQ(window_x2 - window_x1, window_x3 - window_x2);
+  // TODO(crbug.com/698887): investigate failure in Mash.
+  if (Shell::GetAshConfig() != Config::MASH)
+    EXPECT_EQ(window_x2 - window_x1, window_x3 - window_x2);
+  // New shelf items for panels are inserted before existing panel items.
+  EXPECT_LT(window_x2, window_x1);
+  EXPECT_LT(window_x3, window_x2);
   int spacing = window_x2 - window_x1;
-  EXPECT_GT(spacing, icon_x2 - icon_x1);
+  EXPECT_GT(std::abs(spacing), std::abs(icon_x2 - icon_x1));
 }
 
 TEST_F(PanelLayoutManagerTest, FanLargeWindow) {
@@ -645,10 +652,11 @@
   int window_x1 = w1->GetBoundsInRootWindow().CenterPoint().x();
   int window_x2 = w2->GetBoundsInRootWindow().CenterPoint().x();
   int window_x3 = w3->GetBoundsInRootWindow().CenterPoint().x();
-  // The distances may not be equidistant with a large panel but the panels
-  // should be in the correct order with respect to their midpoints.
-  EXPECT_GT(window_x2, window_x1);
-  EXPECT_GT(window_x3, window_x2);
+  // The distances between windows may not be equidistant with a large panel,
+  // but the windows should be placed relative to the order they were added.
+  // New shelf items for panels are inserted before existing panel items.
+  EXPECT_LT(window_x2, window_x1);
+  EXPECT_LT(window_x3, window_x2);
 }
 
 TEST_F(PanelLayoutManagerTest, MinimizeRestorePanel) {
diff --git a/ash/wm/panels/panel_window_resizer_unittest.cc b/ash/wm/panels/panel_window_resizer_unittest.cc
index 03636f7..5a7009f 100644
--- a/ash/wm/panels/panel_window_resizer_unittest.cc
+++ b/ash/wm/panels/panel_window_resizer_unittest.cc
@@ -17,7 +17,7 @@
 #include "ash/shell_port.h"
 #include "ash/test/ash_test_base.h"
 #include "ash/test/cursor_manager_test_api.h"
-#include "ash/test/test_shelf_delegate.h"
+#include "ash/test/shelf_view_test_api.h"
 #include "ash/wm/drag_window_resizer.h"
 #include "ash/wm/window_properties.h"
 #include "ash/wm/window_state.h"
@@ -42,7 +42,9 @@
   void SetUp() override {
     AshTestBase::SetUp();
     UpdateDisplay("600x400");
-    model_ = Shell::Get()->shelf_model();
+    shelf_view_test_.reset(new test::ShelfViewTestAPI(
+        GetPrimaryShelf()->GetShelfViewForTesting()));
+    shelf_view_test_->SetAnimationDuration(1);
   }
 
   void TearDown() override { AshTestBase::TearDown(); }
@@ -61,16 +63,14 @@
     gfx::Rect bounds(origin, gfx::Size(101, 101));
     aura::Window* window = CreateTestWindowInShellWithDelegateAndType(
         NULL, ui::wm::WINDOW_TYPE_PANEL, 0, bounds);
-    test::TestShelfDelegate::instance()->AddShelfItem(WmWindow::Get(window));
+    shelf_view_test_->RunMessageLoopUntilAnimationsDone();
     return window;
   }
 
   void DragStart(aura::Window* window) {
-    resizer_.reset(CreateWindowResizer(WmWindow::Get(window),
-                                       window->bounds().origin(), HTCAPTION,
-                                       aura::client::WINDOW_MOVE_SOURCE_MOUSE)
-                       .release());
-    ASSERT_TRUE(resizer_.get());
+    resizer_ =
+        CreateWindowResizer(WmWindow::Get(window), window->bounds().origin(),
+                            HTCAPTION, aura::client::WINDOW_MOVE_SOURCE_MOUSE);
   }
 
   void DragMove(int dx, int dy) {
@@ -87,7 +87,7 @@
     resizer_.reset();
   }
 
-  // Test dragging the panel slightly, then detaching, and then reattaching
+  // Test dragging the panel slightly, then detaching, and then reattaching,
   // dragging out by the vector (dx, dy).
   void DetachReattachTest(aura::Window* window, int dx, int dy) {
     EXPECT_TRUE(window->GetProperty(kPanelAttachedKey));
@@ -96,84 +96,81 @@
     DragStart(window);
     gfx::Rect initial_bounds = window->GetBoundsInScreen();
 
-    // Drag the panel slightly. The window should still be snapped to the
-    // launcher.
+    // Drag slightly, the panel window should remain attached to the shelf.
     DragMove(dx * 5, dy * 5);
     EXPECT_EQ(initial_bounds.x(), window->GetBoundsInScreen().x());
     EXPECT_EQ(initial_bounds.y(), window->GetBoundsInScreen().y());
 
-    // Drag further out and the window should now move to the cursor.
+    // Drag further out, the panel window should detach and move to the cursor.
     DragMove(dx * 100, dy * 100);
     EXPECT_EQ(initial_bounds.x() + dx * 100, window->GetBoundsInScreen().x());
     EXPECT_EQ(initial_bounds.y() + dy * 100, window->GetBoundsInScreen().y());
-
-    // The panel should be detached when the drag completes.
     DragEnd();
 
     EXPECT_FALSE(window->GetProperty(kPanelAttachedKey));
     EXPECT_EQ(kShellWindowId_DefaultContainer, window->parent()->id());
     EXPECT_EQ(root_window, window->GetRootWindow());
 
+    // Drag back towards the shelf, the panel window should re-attach.
     DragStart(window);
-    // Drag the panel down.
     DragMove(dx * -95, dy * -95);
-    // Release the mouse and the panel should be reattached.
     DragEnd();
 
-    // The panel should be reattached and have snapped to the launcher.
     EXPECT_TRUE(window->GetProperty(kPanelAttachedKey));
     EXPECT_EQ(initial_bounds.x(), window->GetBoundsInScreen().x());
     EXPECT_EQ(initial_bounds.y(), window->GetBoundsInScreen().y());
     EXPECT_EQ(kShellWindowId_PanelContainer, window->parent()->id());
   }
 
-  void TestWindowOrder(const std::vector<aura::Window*>& window_order) {
-    int panel_index = model_->FirstPanelIndex();
-    EXPECT_EQ((int)(panel_index + window_order.size()), model_->item_count());
-    for (std::vector<aura::Window *>::const_iterator
-             iter = window_order.begin();
-         iter != window_order.end(); ++iter, ++panel_index) {
-      ShelfID id = (*iter)->GetProperty(kShelfIDKey);
-      EXPECT_EQ(id, model_->items()[panel_index].id);
+  // Ensure |first| and its shelf item come before those of |second|:
+  // - |first| should be left of |second| in an LTR bottom-aligned shelf.
+  // - |first| should be right of |second| in an RTL bottom-aligned shelf.
+  // - |first| should be above |second| in a left- or right-aligned shelf.
+  void CheckWindowAndItemPlacement(aura::Window* first, aura::Window* second) {
+    WmShelf* shelf = GetPrimaryShelf();
+    const gfx::Rect first_item_bounds =
+        shelf->GetScreenBoundsOfItemIconForWindow(WmWindow::Get(first));
+    const gfx::Rect second_item_bounds =
+        shelf->GetScreenBoundsOfItemIconForWindow(WmWindow::Get(second));
+    if (!base::i18n::IsRTL()) {
+      EXPECT_TRUE((first->bounds().x() < second->bounds().x()) ||
+                  (first->bounds().y() < second->bounds().y()));
+      EXPECT_TRUE((first_item_bounds.x() < second_item_bounds.x()) ||
+                  (first_item_bounds.y() < second_item_bounds.y()));
+    } else {
+      EXPECT_TRUE((first->bounds().x() > second->bounds().x()) ||
+                  (first->bounds().y() < second->bounds().y()));
+      EXPECT_TRUE((first_item_bounds.x() > second_item_bounds.x()) ||
+                  (first_item_bounds.y() < second_item_bounds.y()));
     }
   }
 
-  // Test dragging panel window along the shelf and verify that panel icons
-  // are reordered appropriately.
+  // Test dragging panel window along the shelf and verify that panel icons are
+  // reordered appropriately. New shelf items for panels are inserted before
+  // existing panel items (eg. to the left in an LTR bottom-aligned shelf).
   void DragAlongShelfReorder(int dx, int dy) {
-    gfx::Point origin(0, 0);
-    std::unique_ptr<aura::Window> w1(CreatePanelWindow(origin));
-    std::unique_ptr<aura::Window> w2(CreatePanelWindow(origin));
-    std::vector<aura::Window*> window_order_original;
-    std::vector<aura::Window*> window_order_swapped;
-    window_order_original.push_back(w1.get());
-    window_order_original.push_back(w2.get());
-    window_order_swapped.push_back(w2.get());
-    window_order_swapped.push_back(w1.get());
-    TestWindowOrder(window_order_original);
+    std::unique_ptr<aura::Window> w1(CreatePanelWindow(gfx::Point()));
+    std::unique_ptr<aura::Window> w2(CreatePanelWindow(gfx::Point()));
+    CheckWindowAndItemPlacement(w2.get(), w1.get());
 
-    // Drag window #2 to the beginning of the shelf.
-    DragStart(w2.get());
+    // Drag window #1 to the beginning of the shelf, the items should swap.
+    DragStart(w1.get());
     DragMove(400 * dx, 400 * dy);
-    TestWindowOrder(window_order_swapped);
+    CheckWindowAndItemPlacement(w1.get(), w2.get());
     DragEnd();
+    CheckWindowAndItemPlacement(w1.get(), w2.get());
 
-    // Expect swapped window order.
-    TestWindowOrder(window_order_swapped);
-
-    // Drag window #2 back to the end.
-    DragStart(w2.get());
+    // Drag window #1 back to the end, the items should swap back.
+    DragStart(w1.get());
     DragMove(-400 * dx, -400 * dy);
-    TestWindowOrder(window_order_original);
+    CheckWindowAndItemPlacement(w2.get(), w1.get());
     DragEnd();
-
-    // Expect original order.
-    TestWindowOrder(window_order_original);
+    CheckWindowAndItemPlacement(w2.get(), w1.get());
   }
 
  private:
   std::unique_ptr<WindowResizer> resizer_;
-  ShelfModel* model_;
+  std::unique_ptr<test::ShelfViewTestAPI> shelf_view_test_;
 
   DISALLOW_COPY_AND_ASSIGN(PanelWindowResizerTest);
 };
@@ -559,7 +556,6 @@
 INSTANTIATE_TEST_CASE_P(NormalPanelPopup,
                         PanelWindowResizerTransientTest,
                         testing::Values(ui::wm::WINDOW_TYPE_NORMAL,
-                                        ui::wm::WINDOW_TYPE_PANEL,
                                         ui::wm::WINDOW_TYPE_POPUP));
 
 }  // namespace ash
diff --git a/ash/wm/window_cycle_controller_unittest.cc b/ash/wm/window_cycle_controller_unittest.cc
index 1e62240..d1959540 100644
--- a/ash/wm/window_cycle_controller_unittest.cc
+++ b/ash/wm/window_cycle_controller_unittest.cc
@@ -19,7 +19,6 @@
 #include "ash/test/shelf_view_test_api.h"
 #include "ash/test/test_app_list_view_presenter_impl.h"
 #include "ash/test/test_session_controller_client.h"
-#include "ash/test/test_shelf_delegate.h"
 #include "ash/test/test_shell_delegate.h"
 #include "ash/wm/window_cycle_list.h"
 #include "ash/wm/window_state.h"
@@ -102,7 +101,6 @@
     gfx::Rect rect(100, 100);
     aura::Window* window = CreateTestWindowInShellWithDelegateAndType(
         NULL, ui::wm::WINDOW_TYPE_PANEL, 0, rect);
-    test::TestShelfDelegate::instance()->AddShelfItem(WmWindow::Get(window));
     shelf_view_test_->RunMessageLoopUntilAnimationsDone();
     return window;
   }
diff --git a/ash/wm/workspace/phantom_window_controller.cc b/ash/wm/workspace/phantom_window_controller.cc
index d334e9c..6321290 100644
--- a/ash/wm/workspace/phantom_window_controller.cc
+++ b/ash/wm/workspace/phantom_window_controller.cc
@@ -7,16 +7,15 @@
 #include <math.h>
 
 #include "ash/public/cpp/shell_window_ids.h"
-#include "ash/resources/grit/ash_resources.h"
 #include "ash/root_window_controller.h"
 #include "ash/wm/root_window_finder.h"
 #include "ash/wm_window.h"
 #include "ui/compositor/layer.h"
 #include "ui/compositor/scoped_layer_animation_settings.h"
 #include "ui/views/background.h"
-#include "ui/views/painter.h"
 #include "ui/views/view.h"
 #include "ui/views/widget/widget.h"
+#include "ui/wm/core/shadow_controller.h"
 
 namespace ash {
 namespace {
@@ -28,46 +27,15 @@
 // relation to the size of the phantom window at the end of the animation.
 const float kStartBoundsRatio = 0.85f;
 
-// The amount of pixels that the phantom window's shadow should extend past
-// the bounds passed into Show().
-const int kShadowThickness = 15;
+// The elevation of the shadow for the phantom window should match that of an
+// active window.
+constexpr ::wm::ShadowElevation kShadowElevation =
+    ::wm::ShadowController::kActiveNormalShadowElevation;
 
-// The minimum size of a phantom window including the shadow. The minimum size
-// is derived from the size of the IDR_AURA_PHANTOM_WINDOW image assets.
-const int kMinSizeWithShadow = 100;
-
-// Adjusts the phantom window's bounds so that the bounds:
-// - Include the size of the shadow.
-// - Have a size equal to or larger than the minimum phantom window size.
-gfx::Rect GetAdjustedBounds(const gfx::Rect& bounds) {
-  int x_inset = std::max(
-      static_cast<int>(ceil((kMinSizeWithShadow - bounds.width()) / 2.0f)),
-      kShadowThickness);
-  int y_inset = std::max(
-      static_cast<int>(ceil((kMinSizeWithShadow - bounds.height()) / 2.0f)),
-      kShadowThickness);
-
-  gfx::Rect adjusted_bounds(bounds);
-  adjusted_bounds.Inset(-x_inset, -y_inset);
-  return adjusted_bounds;
-}
-
-// Starts an animation of |widget| to |new_bounds_in_screen|. No-op if |widget|
-// is NULL.
-void AnimateToBounds(views::Widget* widget,
-                     const gfx::Rect& new_bounds_in_screen) {
-  if (!widget)
-    return;
-
-  ui::ScopedLayerAnimationSettings scoped_setter(
-      WmWindow::Get(widget->GetNativeWindow())->GetLayer()->GetAnimator());
-  scoped_setter.SetTweenType(gfx::Tween::EASE_IN);
-  scoped_setter.SetPreemptionStrategy(
-      ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET);
-  scoped_setter.SetTransitionDuration(
-      base::TimeDelta::FromMilliseconds(kAnimationDurationMs));
-  widget->SetBounds(new_bounds_in_screen);
-}
+// The shadow ninebox requires a minimum size to work well. See
+// ui/wm/core/shadow.cc
+constexpr int kMinWidthWithShadow = 2 * static_cast<int>(kShadowElevation);
+constexpr int kMinHeightWithShadow = 4 * static_cast<int>(kShadowElevation);
 
 }  // namespace
 
@@ -79,17 +47,16 @@
 PhantomWindowController::~PhantomWindowController() {}
 
 void PhantomWindowController::Show(const gfx::Rect& bounds_in_screen) {
-  gfx::Rect adjusted_bounds_in_screen = GetAdjustedBounds(bounds_in_screen);
-  if (adjusted_bounds_in_screen == target_bounds_in_screen_)
+  if (bounds_in_screen == target_bounds_in_screen_)
     return;
-  target_bounds_in_screen_ = adjusted_bounds_in_screen;
+  target_bounds_in_screen_ = bounds_in_screen;
 
   gfx::Rect start_bounds_in_screen = target_bounds_in_screen_;
   int start_width = std::max(
-      kMinSizeWithShadow,
+      kMinWidthWithShadow,
       static_cast<int>(start_bounds_in_screen.width() * kStartBoundsRatio));
   int start_height = std::max(
-      kMinSizeWithShadow,
+      kMinHeightWithShadow,
       static_cast<int>(start_bounds_in_screen.height() * kStartBoundsRatio));
   start_bounds_in_screen.Inset(
       floor((start_bounds_in_screen.width() - start_width) / 2.0f),
@@ -97,8 +64,6 @@
   phantom_widget_ =
       CreatePhantomWidget(wm::GetRootWindowMatching(target_bounds_in_screen_),
                           start_bounds_in_screen);
-
-  AnimateToBounds(phantom_widget_.get(), target_bounds_in_screen_);
 }
 
 std::unique_ptr<views::Widget> PhantomWindowController::CreatePhantomWidget(
@@ -113,6 +78,9 @@
   params.keep_on_top = true;
   params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
   params.name = "PhantomWindow";
+  params.layer_type = ui::LAYER_SOLID_COLOR;
+  params.shadow_type = views::Widget::InitParams::SHADOW_TYPE_DROP;
+  params.shadow_elevation = ::wm::ShadowElevation::LARGE;
   root_window->GetRootWindowController()->ConfigureWidgetInitParamsForContainer(
       phantom_widget.get(), kShellWindowId_ShelfContainer, &params);
   phantom_widget->set_focus_on_creation(false);
@@ -127,23 +95,21 @@
     phantom_widget_window->GetParent()->StackChildAbove(phantom_widget_window,
                                                         window_);
   }
+  ui::Layer* widget_layer = phantom_widget_window->GetLayer();
+  widget_layer->SetColor(SkColorSetA(SK_ColorWHITE, 0.4 * 255));
 
-  const int kImages[] = IMAGE_GRID(IDR_AURA_PHANTOM_WINDOW);
-  views::View* content_view = new views::View;
-  content_view->set_background(views::Background::CreateBackgroundPainter(
-      views::Painter::CreateImageGridPainter(kImages)));
-  phantom_widget->SetContentsView(content_view);
-
-  // Show the widget after all the setups.
   phantom_widget->Show();
 
   // Fade the window in.
-  ui::Layer* widget_layer = phantom_widget_window->GetLayer();
   widget_layer->SetOpacity(0);
   ui::ScopedLayerAnimationSettings scoped_setter(widget_layer->GetAnimator());
   scoped_setter.SetTransitionDuration(
       base::TimeDelta::FromMilliseconds(kAnimationDurationMs));
+  scoped_setter.SetTweenType(gfx::Tween::EASE_IN);
+  scoped_setter.SetPreemptionStrategy(
+      ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET);
   widget_layer->SetOpacity(1);
+  phantom_widget->SetBounds(target_bounds_in_screen_);
 
   return phantom_widget;
 }
diff --git a/ash/wm/workspace_controller_unittest.cc b/ash/wm/workspace_controller_unittest.cc
index b2f18e21..1b53e6f 100644
--- a/ash/wm/workspace_controller_unittest.cc
+++ b/ash/wm/workspace_controller_unittest.cc
@@ -16,7 +16,6 @@
 #include "ash/system/status_area_widget.h"
 #include "ash/test/ash_test_base.h"
 #include "ash/test/shell_test_api.h"
-#include "ash/test/test_shelf_delegate.h"
 #include "ash/wm/panels/panel_layout_manager.h"
 #include "ash/wm/window_state.h"
 #include "ash/wm/window_state_aura.h"
@@ -120,7 +119,6 @@
     aura::Window* window = CreateTestWindowInShellWithDelegateAndType(
         delegate, ui::wm::WINDOW_TYPE_PANEL, 0, bounds);
     WmWindow* wm_window = WmWindow::Get(window);
-    test::TestShelfDelegate::instance()->AddShelfItem(wm_window);
     PanelLayoutManager::Get(wm_window)->Relayout();
     return window;
   }
diff --git a/base/android/java/src/org/chromium/base/ApiCompatibilityUtils.java b/base/android/java/src/org/chromium/base/ApiCompatibilityUtils.java
index 242d424..b369e4d 100644
--- a/base/android/java/src/org/chromium/base/ApiCompatibilityUtils.java
+++ b/base/android/java/src/org/chromium/base/ApiCompatibilityUtils.java
@@ -28,6 +28,8 @@
 import android.os.StatFs;
 import android.os.UserManager;
 import android.provider.Settings;
+import android.text.Html;
+import android.text.Spanned;
 import android.view.View;
 import android.view.ViewGroup.MarginLayoutParams;
 import android.view.Window;
@@ -281,6 +283,19 @@
         }
     }
 
+    /**
+     * @see android.text.Html#toHtml(Spanned, int)
+     * @param option is ignored on below N
+     */
+    @SuppressWarnings("deprecation")
+    public static String toHtml(Spanned spanned, int option) {
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
+            return Html.toHtml(spanned, option);
+        } else {
+            return Html.toHtml(spanned);
+        }
+    }
+
     // These methods have a new name, and the old name is deprecated.
 
     /**
diff --git a/cc/layers/heads_up_display_layer_impl.cc b/cc/layers/heads_up_display_layer_impl.cc
index 7340f18..bde1f0c 100644
--- a/cc/layers/heads_up_display_layer_impl.cc
+++ b/cc/layers/heads_up_display_layer_impl.cc
@@ -607,10 +607,6 @@
       status = "MSAA (content)";
       color = SK_ColorCYAN;
       break;
-    case GpuRasterizationStatus::OFF_CONTENT:
-      status = "off (content)";
-      color = SK_ColorYELLOW;
-      break;
   }
 
   if (status.empty())
diff --git a/cc/layers/picture_layer_impl_unittest.cc b/cc/layers/picture_layer_impl_unittest.cc
index 6ccf44a1..45458f7 100644
--- a/cc/layers/picture_layer_impl_unittest.cc
+++ b/cc/layers/picture_layer_impl_unittest.cc
@@ -2352,7 +2352,7 @@
   host_impl()->SetHasGpuRasterizationTrigger(true);
   host_impl()->SetContentIsSuitableForGpuRasterization(false);
   host_impl()->CommitComplete();
-  EXPECT_EQ(GpuRasterizationStatus::OFF_CONTENT,
+  EXPECT_EQ(GpuRasterizationStatus::ON,
             host_impl()->gpu_rasterization_status());
 }
 
diff --git a/cc/output/direct_renderer.cc b/cc/output/direct_renderer.cc
index e9b62d2..31f0d7a 100644
--- a/cc/output/direct_renderer.cc
+++ b/cc/output/direct_renderer.cc
@@ -174,31 +174,31 @@
     const RenderPassList& render_passes_in_draw_order) {
   render_pass_bypass_quads_.clear();
 
-  std::unordered_map<int, gfx::Size> render_passes_in_frame;
-  RenderPass* root_render_pass = render_passes_in_draw_order.back().get();
-  for (size_t i = 0; i < render_passes_in_draw_order.size(); ++i) {
-    RenderPass* pass = render_passes_in_draw_order[i].get();
+  auto& root_render_pass = render_passes_in_draw_order.back();
+
+  base::flat_map<int, gfx::Size> render_passes_in_frame;
+  for (const auto& pass : render_passes_in_draw_order) {
     if (pass != root_render_pass) {
-      if (const TileDrawQuad* tile_quad = CanPassBeDrawnDirectly(pass)) {
+      if (const TileDrawQuad* tile_quad = CanPassBeDrawnDirectly(pass.get())) {
+        // If the render pass is drawn directly, it will not be drawn from as
+        // a render pass so it's not added to the map.
         render_pass_bypass_quads_[pass->id] = *tile_quad;
         continue;
       }
     }
-    render_passes_in_frame.insert(
-        std::pair<int, gfx::Size>(pass->id, RenderPassTextureSize(pass)));
+    render_passes_in_frame[pass->id] = RenderPassTextureSize(pass.get());
   }
 
   std::vector<int> passes_to_delete;
-  for (auto pass_iter = render_pass_textures_.begin();
-       pass_iter != render_pass_textures_.end(); ++pass_iter) {
-    auto it = render_passes_in_frame.find(pass_iter->first);
+  for (const auto& pair : render_pass_textures_) {
+    auto it = render_passes_in_frame.find(pair.first);
     if (it == render_passes_in_frame.end()) {
-      passes_to_delete.push_back(pass_iter->first);
+      passes_to_delete.push_back(pair.first);
       continue;
     }
 
     gfx::Size required_size = it->second;
-    ScopedResource* texture = pass_iter->second.get();
+    ScopedResource* texture = pair.second.get();
     DCHECK(texture);
 
     bool size_appropriate = texture->size().width() >= required_size.width() &&
diff --git a/cc/output/direct_renderer.h b/cc/output/direct_renderer.h
index 864c1863..96e66133 100644
--- a/cc/output/direct_renderer.h
+++ b/cc/output/direct_renderer.h
@@ -10,6 +10,7 @@
 #include <vector>
 
 #include "base/callback.h"
+#include "base/containers/flat_map.h"
 #include "base/macros.h"
 #include "cc/base/filter_operations.h"
 #include "cc/cc_export.h"
@@ -198,10 +199,8 @@
   // DirectComposition layers needed to be used.
   int frames_since_using_dc_layers_ = 0;
 
-  // TODO(danakj): Just use a vector of pairs here? Hash map is way overkill.
-  std::unordered_map<int, std::unique_ptr<ScopedResource>>
-      render_pass_textures_;
-  std::unordered_map<int, TileDrawQuad> render_pass_bypass_quads_;
+  base::flat_map<int, std::unique_ptr<ScopedResource>> render_pass_textures_;
+  base::flat_map<int, TileDrawQuad> render_pass_bypass_quads_;
 
   RenderPassFilterList render_pass_filters_;
   RenderPassFilterList render_pass_background_filters_;
diff --git a/cc/trees/layer_tree_host_impl.cc b/cc/trees/layer_tree_host_impl.cc
index ca08b6f..098b7bd 100644
--- a/cc/trees/layer_tree_host_impl.cc
+++ b/cc/trees/layer_tree_host_impl.cc
@@ -1857,14 +1857,13 @@
     gpu_rasterization_status_ = GpuRasterizationStatus::OFF_DEVICE;
   } else if (!has_gpu_rasterization_trigger_) {
     gpu_rasterization_status_ = GpuRasterizationStatus::OFF_VIEWPORT;
-  } else if (content_is_suitable_for_gpu_rasterization_) {
-    use_gpu = true;
-    gpu_rasterization_status_ = GpuRasterizationStatus::ON;
-  } else if (using_msaa_for_complex_content) {
+  } else if (!content_is_suitable_for_gpu_rasterization_ &&
+             using_msaa_for_complex_content) {
     use_gpu = use_msaa = true;
     gpu_rasterization_status_ = GpuRasterizationStatus::MSAA_CONTENT;
   } else {
-    gpu_rasterization_status_ = GpuRasterizationStatus::OFF_CONTENT;
+    use_gpu = true;
+    gpu_rasterization_status_ = GpuRasterizationStatus::ON;
   }
 
   if (use_gpu && !use_gpu_rasterization_) {
diff --git a/cc/trees/layer_tree_host_impl.h b/cc/trees/layer_tree_host_impl.h
index 0b72dc4..001e901e 100644
--- a/cc/trees/layer_tree_host_impl.h
+++ b/cc/trees/layer_tree_host_impl.h
@@ -86,7 +86,6 @@
   OFF_DEVICE,
   OFF_VIEWPORT,
   MSAA_CONTENT,
-  OFF_CONTENT
 };
 
 // LayerTreeHost->Proxy callback interface.
diff --git a/cc/trees/layer_tree_host_impl_unittest.cc b/cc/trees/layer_tree_host_impl_unittest.cc
index 9d9a013..181db8f 100644
--- a/cc/trees/layer_tree_host_impl_unittest.cc
+++ b/cc/trees/layer_tree_host_impl_unittest.cc
@@ -11679,13 +11679,22 @@
 
 // Tests that SetContentIsSuitableForGpuRasterization behaves as expected.
 TEST_F(LayerTreeHostImplTest, GpuRasterizationStatusSuitability) {
+  std::unique_ptr<TestWebGraphicsContext3D> context_with_msaa =
+      TestWebGraphicsContext3D::Create();
+  context_with_msaa->SetMaxSamples(4);
+  context_with_msaa->set_gpu_rasterization(true);
+  LayerTreeSettings msaaSettings = DefaultSettings();
+  msaaSettings.gpu_rasterization_msaa_sample_count = 4;
+  EXPECT_TRUE(CreateHostImpl(msaaSettings, FakeCompositorFrameSink::Create3d(
+                                               std::move(context_with_msaa))));
+
   // Set initial state, before varying GPU rasterization suitability.
   host_impl_->SetHasGpuRasterizationTrigger(true);
   host_impl_->SetContentIsSuitableForGpuRasterization(false);
   host_impl_->CommitComplete();
-  EXPECT_EQ(GpuRasterizationStatus::OFF_CONTENT,
+  EXPECT_EQ(GpuRasterizationStatus::MSAA_CONTENT,
             host_impl_->gpu_rasterization_status());
-  EXPECT_FALSE(host_impl_->use_gpu_rasterization());
+  EXPECT_TRUE(host_impl_->use_msaa());
 
   // Toggle suitability on.
   host_impl_->SetContentIsSuitableForGpuRasterization(true);
@@ -11697,10 +11706,10 @@
   // And off.
   host_impl_->SetContentIsSuitableForGpuRasterization(false);
   host_impl_->CommitComplete();
-  EXPECT_EQ(GpuRasterizationStatus::OFF_CONTENT,
+  EXPECT_EQ(GpuRasterizationStatus::MSAA_CONTENT,
             host_impl_->gpu_rasterization_status());
-  EXPECT_FALSE(host_impl_->use_gpu_rasterization());
-  EXPECT_FALSE(host_impl_->use_msaa());
+  EXPECT_TRUE(host_impl_->use_gpu_rasterization());
+  EXPECT_TRUE(host_impl_->use_msaa());
 }
 
 // Tests that SetDeviceScaleFactor correctly impacts GPU rasterization.
@@ -11719,9 +11728,8 @@
   host_impl_->SetHasGpuRasterizationTrigger(true);
   host_impl_->SetContentIsSuitableForGpuRasterization(false);
   host_impl_->CommitComplete();
-  EXPECT_EQ(GpuRasterizationStatus::OFF_CONTENT,
-            host_impl_->gpu_rasterization_status());
-  EXPECT_FALSE(host_impl_->use_gpu_rasterization());
+  EXPECT_EQ(GpuRasterizationStatus::ON, host_impl_->gpu_rasterization_status());
+  EXPECT_TRUE(host_impl_->use_gpu_rasterization());
 
   // Set device scale factor to 2, which lowers the required MSAA samples from
   // 8 to 4.
@@ -11735,9 +11743,8 @@
   // Set device scale factor back to 1.
   host_impl_->active_tree()->SetDeviceScaleFactor(1.0f);
   host_impl_->CommitComplete();
-  EXPECT_EQ(GpuRasterizationStatus::OFF_CONTENT,
-            host_impl_->gpu_rasterization_status());
-  EXPECT_FALSE(host_impl_->use_gpu_rasterization());
+  EXPECT_EQ(GpuRasterizationStatus::ON, host_impl_->gpu_rasterization_status());
+  EXPECT_TRUE(host_impl_->use_gpu_rasterization());
   EXPECT_FALSE(host_impl_->use_msaa());
 }
 
@@ -11823,14 +11830,14 @@
   EXPECT_TRUE(host_impl_->use_gpu_rasterization());
 
   // Ensure that with the msaa_is_slow cap we don't raster unsuitable content
-  // with msaa.
+  // with msaa (we'll still use GPU raster, though).
   CreateHostImplWithMsaaIsSlow(true);
   host_impl_->SetHasGpuRasterizationTrigger(true);
   host_impl_->SetContentIsSuitableForGpuRasterization(false);
   host_impl_->CommitComplete();
-  EXPECT_EQ(GpuRasterizationStatus::OFF_CONTENT,
-            host_impl_->gpu_rasterization_status());
-  EXPECT_FALSE(host_impl_->use_gpu_rasterization());
+  EXPECT_EQ(GpuRasterizationStatus::ON, host_impl_->gpu_rasterization_status());
+  EXPECT_TRUE(host_impl_->use_gpu_rasterization());
+  EXPECT_FALSE(host_impl_->use_msaa());
 }
 
 // A mock output surface which lets us detect calls to ForceReclaimResources.
diff --git a/cc/trees/layer_tree_host_unittest.cc b/cc/trees/layer_tree_host_unittest.cc
index 2e7457a4..b549100 100644
--- a/cc/trees/layer_tree_host_unittest.cc
+++ b/cc/trees/layer_tree_host_unittest.cc
@@ -5300,15 +5300,15 @@
     // Ensure the suitability bit sticks.
     EXPECT_FALSE(layer_->IsSuitableForGpuRasterization());
 
-    EXPECT_FALSE(host_impl->pending_tree()->use_gpu_rasterization());
-    EXPECT_FALSE(host_impl->use_gpu_rasterization());
+    EXPECT_TRUE(host_impl->pending_tree()->use_gpu_rasterization());
+    EXPECT_TRUE(host_impl->use_gpu_rasterization());
   }
 
   void DidActivateTreeOnThread(LayerTreeHostImpl* host_impl) override {
     EXPECT_FALSE(layer_->IsSuitableForGpuRasterization());
 
-    EXPECT_FALSE(host_impl->active_tree()->use_gpu_rasterization());
-    EXPECT_FALSE(host_impl->use_gpu_rasterization());
+    EXPECT_TRUE(host_impl->active_tree()->use_gpu_rasterization());
+    EXPECT_TRUE(host_impl->use_gpu_rasterization());
     EndTest();
   }
 
@@ -5324,6 +5324,23 @@
 class LayerTreeHostTestGpuRasterizationReenabled
     : public LayerTreeHostWithGpuRasterizationTest {
  protected:
+  void InitializeSettings(LayerTreeSettings* settings) override {
+    settings->gpu_rasterization_msaa_sample_count = 4;
+  }
+
+  std::unique_ptr<TestCompositorFrameSink> CreateCompositorFrameSink(
+      scoped_refptr<ContextProvider> compositor_context_provider,
+      scoped_refptr<ContextProvider> worker_context_provider) override {
+    std::unique_ptr<TestWebGraphicsContext3D> context =
+        TestWebGraphicsContext3D::Create();
+    context->SetMaxSamples(4);
+    context->set_gpu_rasterization(true);
+    compositor_context_provider =
+        TestContextProvider::Create(std::move(context));
+    return LayerTreeTest::CreateCompositorFrameSink(compositor_context_provider,
+                                                    worker_context_provider);
+  }
+
   void SetupTree() override {
     LayerTreeHostTest::SetupTree();
 
@@ -5362,10 +5379,10 @@
 
   void CommitCompleteOnThread(LayerTreeHostImpl* host_impl) override {
     SCOPED_TRACE(base::StringPrintf("commit %d", num_commits_));
-    if (expected_gpu_enabled_) {
-      EXPECT_TRUE(host_impl->use_gpu_rasterization());
+    if (expected_use_msaa_) {
+      EXPECT_TRUE(host_impl->use_msaa());
     } else {
-      EXPECT_FALSE(host_impl->use_gpu_rasterization());
+      EXPECT_FALSE(host_impl->use_msaa());
     }
 
     ++num_commits_;
@@ -5380,7 +5397,7 @@
         layer_->set_force_unsuitable_for_gpu_rasterization(false);
         break;
       case 90:
-        expected_gpu_enabled_ = true;
+        expected_use_msaa_ = false;
         break;
     }
     PostSetNeedsCommitToMainThread();
@@ -5394,7 +5411,7 @@
   FakePictureLayer* layer_;
   FakeRecordingSource* recording_source_;
   int num_commits_ = 0;
-  bool expected_gpu_enabled_ = false;
+  bool expected_use_msaa_ = true;
 };
 
 MULTI_THREAD_TEST_F(LayerTreeHostTestGpuRasterizationReenabled);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrShellDelegate.java b/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrShellDelegate.java
index a6b95d0..11cbb723 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrShellDelegate.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrShellDelegate.java
@@ -78,11 +78,6 @@
     @IntDef({VR_NOT_AVAILABLE, VR_CARDBOARD, VR_DAYDREAM})
     private @interface VrSupportLevel {}
 
-    // TODO(bshe): These should be replaced by string provided by NDK. Currently, it only available
-    // in SDK and we don't want add dependency to SDK just to get these strings.
-    private static final String DAYDREAM_CATEGORY = "com.google.intent.category.DAYDREAM";
-    private static final String CARDBOARD_CATEGORY = "com.google.intent.category.CARDBOARD";
-
     // Linter and formatter disagree on how the line below should be formatted.
     /* package */
     static final String VR_ENTRY_RESULT_ACTION =
@@ -207,14 +202,6 @@
     }
 
     /**
-     * Whether or not the intent is a Daydream VR Intent.
-     */
-    public static boolean isDaydreamVrIntent(Intent intent) {
-        if (intent == null || intent.getCategories() == null) return false;
-        return intent.getCategories().contains(DAYDREAM_CATEGORY);
-    }
-
-    /**
      * Handles the result of the exit VR flow (DOFF).
      */
     public static void onExitVrResult(int resultCode) {
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd
index ef46b9f..a387ef7 100644
--- a/chrome/app/generated_resources.grd
+++ b/chrome/app/generated_resources.grd
@@ -12361,14 +12361,6 @@
       </message>
     </if>
 
-    <!-- Media Remoting strings. -->
-    <message name="IDS_MEDIA_REMOTING_CASTING_VIDEO_TEXT" desc="The text shown on the media player when the video is currently being streamed remotely.">
-      Casting Video...
-    </message>
-    <message name="IDS_MEDIA_REMOTING_CAST_ERROR_TEXT" desc="The text shown on the media player when there is an error when trying to stream the video remotely.">
-      Cast Error
-    </message>
-
     <!-- Consistent omnibox geolocation -->
     <if expr="is_android">
         <message name="IDS_SEARCH_GEOLOCATION_DISCLOSURE_INFOBAR_CONTROL_TEXT" desc="Text to put in the infobar disclosing Google Search's usage of location. The message contains a link to a settings page. The link text is a separate string in the translation console and appears here as a placeholder text. This version of the text is old but is being kept to allow us to compare performance of the new text.">
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index 834e0e99..5f06bfc 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -562,6 +562,20 @@
 };
 #endif  // OS_CHROMEOS
 
+#if defined(OS_CHROMEOS) || defined(OS_LINUX) || defined(OS_MACOSX) || \
+    defined(OS_WIN)
+const FeatureEntry::Choice kAppMenuIconChoices[] = {
+    {flags_ui::kGenericExperimentChoiceDefault, "", ""},
+    {flag_descriptions::kAppMenuIconOldBehavior, switches::kAppMenuIcon,
+     switches::kAppMenuIconOldBehavior},
+    {flag_descriptions::kAppMenuIconPersistentOpenedState,
+     switches::kAppMenuIcon, switches::kAppMenuIconPersistentOpenedState},
+    {flag_descriptions::kAppMenuIconPersistentClosedState,
+     switches::kAppMenuIcon, switches::kAppMenuIconPersistentClosedState},
+};
+#endif  // defined(OS_CHROMEOS) || defined(OS_LINUX) || defined(OS_MACOSX) ||
+        // defined(OS_WIN)
+
 #if defined(OS_ANDROID)
 const FeatureEntry::FeatureParam
     kContentSuggestionsCategoryOrderFeatureVariationGeneral[] = {
@@ -2635,6 +2649,9 @@
      flag_descriptions::kOmniboxEntitySuggestionsName,
      flag_descriptions::kOmniboxEntitySuggestionsDescription, kOsDesktop,
      FEATURE_VALUE_TYPE(omnibox::kOmniboxEntitySuggestions)},
+    {"app-menu-icon", flag_descriptions::kAppMenuIconName,
+     flag_descriptions::kAppMenuIconDescription, kOsDesktop,
+     MULTI_VALUE_TYPE(kAppMenuIconChoices)},
 #endif  // defined(OS_CHROMEOS) || defined(OS_LINUX) || defined(OS_MACOSX) ||
         // defined(OS_WIN)
 
diff --git a/chrome/browser/android/vr_shell/ui_scene_manager.cc b/chrome/browser/android/vr_shell/ui_scene_manager.cc
index dfd3fa6e..8030e673 100644
--- a/chrome/browser/android/vr_shell/ui_scene_manager.cc
+++ b/chrome/browser/android/vr_shell/ui_scene_manager.cc
@@ -62,6 +62,17 @@
   element->lock_to_fov = true;
   transient_security_warning_ = element.get();
   scene_->AddUiElement(std::move(element));
+
+  // Main web content quad.
+  element = base::MakeUnique<UiElement>();
+  element->id = id++;
+  element->name = "Content";
+  element->fill = vr_shell::Fill::CONTENT;
+  element->size = {(1.6f * (16 / 9)), 1.6f, 1};
+  element->translation = {0, 0, -2};
+  element->visible = false;
+  main_content_ = element.get();
+  scene_->AddUiElement(std::move(element));
 }
 
 UiSceneManager::~UiSceneManager() {}
@@ -72,6 +83,7 @@
 
 void UiSceneManager::SetWebVRMode(bool web_vr) {
   web_vr_mode_ = web_vr;
+  main_content_->visible = !web_vr_mode_;
   ConfigureSecurityWarnings();
 }
 
diff --git a/chrome/browser/android/vr_shell/ui_scene_manager.h b/chrome/browser/android/vr_shell/ui_scene_manager.h
index 529d047..e7b93580 100644
--- a/chrome/browser/android/vr_shell/ui_scene_manager.h
+++ b/chrome/browser/android/vr_shell/ui_scene_manager.h
@@ -34,6 +34,7 @@
   // UI elemenet pointers (not owned by the scene manager).
   UiElement* permanent_security_warning_ = nullptr;
   UiElement* transient_security_warning_ = nullptr;
+  UiElement* main_content_ = nullptr;
 
   bool web_vr_mode_ = false;
   bool secure_origin_ = false;
diff --git a/chrome/browser/chromeos/arc/arc_session_manager.cc b/chrome/browser/chromeos/arc/arc_session_manager.cc
index cfb02ac..6a46751a 100644
--- a/chrome/browser/chromeos/arc/arc_session_manager.cc
+++ b/chrome/browser/chromeos/arc/arc_session_manager.cc
@@ -6,7 +6,6 @@
 
 #include <utility>
 
-#include "ash/shelf/shelf_delegate.h"
 #include "base/bind.h"
 #include "base/callback_helpers.h"
 #include "base/command_line.h"
diff --git a/chrome/browser/chromeos/login/supervised/supervised_user_creation_flow.cc b/chrome/browser/chromeos/login/supervised/supervised_user_creation_flow.cc
index ff70fbbd..504d954 100644
--- a/chrome/browser/chromeos/login/supervised/supervised_user_creation_flow.cc
+++ b/chrome/browser/chromeos/login/supervised/supervised_user_creation_flow.cc
@@ -46,7 +46,7 @@
   return false;
 }
 
-bool SupervisedUserCreationFlow::ShouldShowSettings() {
+bool SupervisedUserCreationFlow::ShouldEnableSettings() {
   return false;
 }
 
diff --git a/chrome/browser/chromeos/login/supervised/supervised_user_creation_flow.h b/chrome/browser/chromeos/login/supervised/supervised_user_creation_flow.h
index 2c88141e..868d466 100644
--- a/chrome/browser/chromeos/login/supervised/supervised_user_creation_flow.h
+++ b/chrome/browser/chromeos/login/supervised/supervised_user_creation_flow.h
@@ -22,9 +22,10 @@
   explicit SupervisedUserCreationFlow(const AccountId& manager_id);
   ~SupervisedUserCreationFlow() override;
 
+  // UserFlow:
   bool CanLockScreen() override;
   bool CanStartArc() override;
-  bool ShouldShowSettings() override;
+  bool ShouldEnableSettings() override;
   bool ShouldShowNotificationTray() override;
   bool ShouldLaunchBrowser() override;
   bool ShouldSkipPostLoginScreens() override;
diff --git a/chrome/browser/chromeos/login/user_flow.cc b/chrome/browser/chromeos/login/user_flow.cc
index f0871e8..fcf1911 100644
--- a/chrome/browser/chromeos/login/user_flow.cc
+++ b/chrome/browser/chromeos/login/user_flow.cc
@@ -34,7 +34,7 @@
   return true;
 }
 
-bool DefaultUserFlow::ShouldShowSettings() {
+bool DefaultUserFlow::ShouldEnableSettings() {
   return true;
 }
 
@@ -80,7 +80,7 @@
 void ExtendedUserFlow::AppendAdditionalCommandLineSwitches() {
 }
 
-bool ExtendedUserFlow::ShouldShowSettings() {
+bool ExtendedUserFlow::ShouldEnableSettings() {
   return true;
 }
 
diff --git a/chrome/browser/chromeos/login/user_flow.h b/chrome/browser/chromeos/login/user_flow.h
index 23c9094ac..a11b004 100644
--- a/chrome/browser/chromeos/login/user_flow.h
+++ b/chrome/browser/chromeos/login/user_flow.h
@@ -29,8 +29,13 @@
   // Indicates if screen locking should be enabled or disabled for a flow.
   virtual bool CanLockScreen() = 0;
   virtual bool CanStartArc() = 0;
-  virtual bool ShouldShowSettings() = 0;
+
+  // Whether or not the settings icon should be enabled in the system tray menu.
+  virtual bool ShouldEnableSettings() = 0;
+
+  // Whether or not the notifications tray should be visible.
   virtual bool ShouldShowNotificationTray() = 0;
+
   virtual bool ShouldLaunchBrowser() = 0;
   virtual bool ShouldSkipPostLoginScreens() = 0;
   virtual bool SupportsEarlyRestartToApplyFlags() = 0;
@@ -55,10 +60,11 @@
  public:
   ~DefaultUserFlow() override;
 
+  // UserFlow:
   void AppendAdditionalCommandLineSwitches() override;
   bool CanLockScreen() override;
   bool CanStartArc() override;
-  bool ShouldShowSettings() override;
+  bool ShouldEnableSettings() override;
   bool ShouldShowNotificationTray() override;
   bool ShouldLaunchBrowser() override;
   bool ShouldSkipPostLoginScreens() override;
@@ -77,8 +83,9 @@
   explicit ExtendedUserFlow(const AccountId& account_id);
   ~ExtendedUserFlow() override;
 
+  // UserFlow:
   void AppendAdditionalCommandLineSwitches() override;
-  bool ShouldShowSettings() override;
+  bool ShouldEnableSettings() override;
   bool ShouldShowNotificationTray() override;
   void HandleOAuthTokenStatusChange(
       user_manager::User::OAuthTokenStatus status) override;
diff --git a/chrome/browser/download/download_item_model.cc b/chrome/browser/download/download_item_model.cc
index 8537abc..6238371 100644
--- a/chrome/browser/download/download_item_model.cc
+++ b/chrome/browser/download/download_item_model.cc
@@ -93,6 +93,7 @@
       static_cast<DownloadItemModelData*>(download->GetUserData(kKey));
   if (data == NULL) {
     data = new DownloadItemModelData();
+    data->should_show_in_shelf_ = !download->IsTransient();
     download->SetUserData(kKey, data);
   }
   return data;
@@ -592,7 +593,10 @@
 
 bool DownloadItemModel::ShouldShowInShelf() const {
   const DownloadItemModelData* data = DownloadItemModelData::Get(download_);
-  return !data || data->should_show_in_shelf_;
+  if (data)
+    return data->should_show_in_shelf_;
+
+  return !download_->IsTransient();
 }
 
 void DownloadItemModel::SetShouldShowInShelf(bool should_show) {
diff --git a/chrome/browser/download/download_item_model_unittest.cc b/chrome/browser/download/download_item_model_unittest.cc
index d39a6c37..1d2de5d3 100644
--- a/chrome/browser/download/download_item_model_unittest.cc
+++ b/chrome/browser/download/download_item_model_unittest.cc
@@ -366,15 +366,24 @@
 TEST_F(DownloadItemModelTest, ShouldShowInShelf) {
   SetupDownloadItemDefaults();
 
-  // By default the download item should be displayable on the shelf.
+  // By default the download item should be displayable on the shelf when it is
+  // not a transient download.
+  EXPECT_CALL(item(), IsTransient()).WillOnce(Return(false));
   EXPECT_TRUE(model().ShouldShowInShelf());
 
-  // Once explicitly set, ShouldShowInShelf() should return the explicit value.
-  model().SetShouldShowInShelf(false);
+  EXPECT_CALL(item(), IsTransient()).WillOnce(Return(true));
   EXPECT_FALSE(model().ShouldShowInShelf());
 
+  // Once explicitly set, ShouldShowInShelf() should return the explicit value
+  // regardless of whether it's a transient download, which should no longer
+  // be considered by the model after initializing it.
+  EXPECT_CALL(item(), IsTransient()).Times(1);
+
   model().SetShouldShowInShelf(true);
   EXPECT_TRUE(model().ShouldShowInShelf());
+
+  model().SetShouldShowInShelf(false);
+  EXPECT_FALSE(model().ShouldShowInShelf());
 }
 
 TEST_F(DownloadItemModelTest, DangerLevel) {
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc
index 18af4b8..b10057ec 100644
--- a/chrome/browser/flag_descriptions.cc
+++ b/chrome/browser/flag_descriptions.cc
@@ -2800,6 +2800,12 @@
 const char kPauseBackgroundTabsDescription[] =
     "Pause timers in background tabs after 5 minutes on desktop.";
 
+const char kAppMenuIconName[] = "App Menu Icon";
+const char kAppMenuIconDescription[] = "Changes the icon in the app menu.";
+const char kAppMenuIconOldBehavior[] = "Old Behavior";
+const char kAppMenuIconPersistentOpenedState[] = "Persistent Opened State";
+const char kAppMenuIconPersistentClosedState[] = "Persistent Closed State";
+
 #endif  // defined(OS_CHROMEOS) || defined(OS_LINUX) || defined(OS_MACOSX) ||
         // defined(OS_WIN)
 
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h
index 577f929..c22a1b7 100644
--- a/chrome/browser/flag_descriptions.h
+++ b/chrome/browser/flag_descriptions.h
@@ -3027,6 +3027,21 @@
 extern const char kPauseBackgroundTabsName[];
 extern const char kPauseBackgroundTabsDescription[];
 
+// Name of the flag to change the app menu icon.
+extern const char kAppMenuIconName[];
+
+// Description of the flag to change the app menu icon.
+extern const char kAppMenuIconDescription[];
+
+// Description of the app menu icon's old appearance.
+extern const char kAppMenuIconOldBehavior[];
+
+// Description of the app menu animated icon's persistent opened state.
+extern const char kAppMenuIconPersistentOpenedState[];
+
+// Description of the app menu animated icon's persistent closed state.
+extern const char kAppMenuIconPersistentClosedState[];
+
 #endif  // defined(OS_CHROMEOS) || defined(OS_LINUX) || defined(OS_MACOSX) ||
         // defined(OS_WIN)
 
diff --git a/chrome/browser/resources/chromeos/login/oobe_welcome.js b/chrome/browser/resources/chromeos/login/oobe_welcome.js
index 3d7dc53..9bf84888 100644
--- a/chrome/browser/resources/chromeos/login/oobe_welcome.js
+++ b/chrome/browser/resources/chromeos/login/oobe_welcome.js
@@ -114,7 +114,6 @@
       OncTypeVPN: loadTimeData.getString('OncTypeVPN'),
       OncTypeWiFi: loadTimeData.getString('OncTypeWiFi'),
       OncTypeWiMAX: loadTimeData.getString('OncTypeWiMAX'),
-      networkDisabled: loadTimeData.getString('networkDisabled'),
       networkListItemConnected:
           loadTimeData.getString('networkListItemConnected'),
       networkListItemConnecting:
diff --git a/chrome/browser/resources/chromeos/network_ui/network_ui.js b/chrome/browser/resources/chromeos/network_ui/network_ui.js
index 4319e5e..f3d3307 100644
--- a/chrome/browser/resources/chromeos/network_ui/network_ui.js
+++ b/chrome/browser/resources/chromeos/network_ui/network_ui.js
@@ -11,7 +11,6 @@
     OncTypeVPN: loadTimeData.getString('OncTypeVPN'),
     OncTypeWiFi: loadTimeData.getString('OncTypeWiFi'),
     OncTypeWiMAX: loadTimeData.getString('OncTypeWiMAX'),
-    networkDisabled: loadTimeData.getString('networkDisabled'),
     networkListItemConnected:
         loadTimeData.getString('networkListItemConnected'),
     networkListItemConnecting:
diff --git a/chrome/browser/resources/settings/internet_page/compiled_resources2.gyp b/chrome/browser/resources/settings/internet_page/compiled_resources2.gyp
index e06c64ae..7e645342 100644
--- a/chrome/browser/resources/settings/internet_page/compiled_resources2.gyp
+++ b/chrome/browser/resources/settings/internet_page/compiled_resources2.gyp
@@ -135,6 +135,7 @@
       'target_name': 'network_summary_item',
       'dependencies': [
         '<(DEPTH)/ui/webui/resources/cr_elements/network/compiled_resources2.gyp:cr_onc_types',
+        '<(DEPTH)/ui/webui/resources/cr_elements/policy/compiled_resources2.gyp:cr_policy_network_behavior',
         '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:assert',
         '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:i18n_behavior',
         '<(INTERFACES_GYP):networking_private_interface',
diff --git a/chrome/browser/resources/settings/internet_page/network_summary_item.html b/chrome/browser/resources/settings/internet_page/network_summary_item.html
index e188e09..cfdfdff0 100644
--- a/chrome/browser/resources/settings/internet_page/network_summary_item.html
+++ b/chrome/browser/resources/settings/internet_page/network_summary_item.html
@@ -1,5 +1,5 @@
-<link rel="import" href="chrome://resources/cr_elements/network/cr_network_list.html">
-<link rel="import" href="chrome://resources/cr_elements/network/cr_network_list_item.html">
+<link rel="import" href="chrome://resources/cr_elements/network/cr_network_icon.html">
+<link rel="import" href="chrome://resources/cr_elements/policy/cr_policy_indicator.html">
 <link rel="import" href="chrome://resources/html/i18n_behavior.html">
 <link rel="import" href="chrome://resources/html/polymer.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/iron-collapse/iron-collapse.html">
@@ -12,6 +12,10 @@
 <dom-module id="network-summary-item">
   <template>
     <style include="settings-shared">
+      cr-network-icon {
+        -webkit-padding-end: var(--settings-box-row-padding);
+      }
+
       network-siminfo {
         padding: 0 var(--settings-box-row-padding);
       }
@@ -22,23 +26,42 @@
         flex: auto;
       }
 
-      #details[no-flex] {
-        flex: none;
+      #networkName {
+        color: #333;
+        font-weight: 500;
+      }
+
+      #networkState {
+        color: var(--paper-grey-600);
+        font-size: inherit;
+        font-weight: 400;
       }
     </style>
     <div actionable class="settings-box two-line" on-tap="onShowDetailsTap_">
       <div id="details" no-flex$="[[showSimInfo_(deviceState)]]">
-        <cr-network-list-item item="[[activeNetworkState]]" class="flex">
-        </cr-network-list-item>
+        <cr-network-icon network-state="[[activeNetworkState]]">
+        </cr-network-icon>
+        <div class="flex">
+          <div id="networkName">[[getNetworkName_(activeNetworkState)]]</div>
+          <div id="networkState">
+            [[getNetworkStateText_(activeNetworkState, deviceState)]]
+          </div>
+        </div>
       </div>
 
       <template is="dom-if" if="[[showSimInfo_(deviceState)]]">
-        <network-siminfo editable class="flex"
+        <network-siminfo editable
             network-properties="[[getCellularState_(deviceState)]]"
             networking-private="[[networkingPrivate]]">
         </network-siminfo>
       </template>
 
+      <template is="dom-if" if="[[showPolicyIndicator_(activeNetworkState)]]">
+        <cr-policy-indicator indicator-type="[[getIndicatorTypeForSource(
+            activeNetworkState.Source)]]">
+        </cr-policy-indicator>
+      </template>
+
       <template is="dom-if" if="[[showDetailsIsVisible_(deviceState)]]">
         <button class="subpage-arrow" is="paper-icon-button-light"
             aria-label$="[[getDetailsA11yString_(activeNetworkState,
diff --git a/chrome/browser/resources/settings/internet_page/network_summary_item.js b/chrome/browser/resources/settings/internet_page/network_summary_item.js
index 377c807..0e0b204 100644
--- a/chrome/browser/resources/settings/internet_page/network_summary_item.js
+++ b/chrome/browser/resources/settings/internet_page/network_summary_item.js
@@ -13,7 +13,7 @@
 Polymer({
   is: 'network-summary-item',
 
-  behaviors: [I18nBehavior],
+  behaviors: [CrPolicyNetworkBehavior, I18nBehavior],
 
   properties: {
     /**
@@ -47,6 +47,60 @@
   },
 
   /**
+   * @return {string}
+   * @private
+   */
+  getNetworkName_: function() {
+    return CrOncStrings['OncType' + this.activeNetworkState.Type];
+  },
+
+  /**
+   * @return {string}
+   * @private
+   */
+  getNetworkStateText_: function() {
+    var network = this.activeNetworkState;
+    var state = network.ConnectionState;
+    var name = CrOnc.getNetworkName(network);
+    if (state)
+      return this.getConnectionStateText_(state, name);
+    if (this.deviceIsEnabled_(this.deviceState))
+      return CrOncStrings.networkListItemNotConnected;
+    return this.i18n('deviceOff');
+  },
+
+  /**
+   * @param {CrOnc.ConnectionState} state
+   * @param {string} name
+   * @return {string}
+   * @private
+   */
+  getConnectionStateText_: function(state, name) {
+    switch (state) {
+      case CrOnc.ConnectionState.CONNECTED:
+        return name;
+      case CrOnc.ConnectionState.CONNECTING:
+        if (name)
+          return CrOncStrings.networkListItemConnectingTo.replace('$1', name);
+        return CrOncStrings.networkListItemConnecting;
+      case CrOnc.ConnectionState.NOT_CONNECTED:
+        return CrOncStrings.networkListItemNotConnected;
+    }
+    assertNotReached();
+    return state;
+  },
+
+  /**
+   * @return {boolean}
+   * @private
+   */
+  showPolicyIndicator_: function() {
+    var network = this.activeNetworkState;
+    return network.ConnectionState == CrOnc.ConnectionState.CONNECTED ||
+        this.isPolicySource(network.Source);
+  },
+
+  /**
    * Show the <network-siminfo> element if this is a disabled and locked
    * cellular device.
    * @return {boolean}
diff --git a/chrome/browser/resources/settings/settings_ui/settings_ui.js b/chrome/browser/resources/settings/settings_ui/settings_ui.js
index e3e0e591..b129c5b5 100644
--- a/chrome/browser/resources/settings/settings_ui/settings_ui.js
+++ b/chrome/browser/resources/settings/settings_ui/settings_ui.js
@@ -112,7 +112,6 @@
       OncTypeVPN: loadTimeData.getString('OncTypeVPN'),
       OncTypeWiFi: loadTimeData.getString('OncTypeWiFi'),
       OncTypeWiMAX: loadTimeData.getString('OncTypeWiMAX'),
-      networkDisabled: loadTimeData.getString('networkDisabled'),
       networkListItemConnected:
           loadTimeData.getString('networkListItemConnected'),
       networkListItemConnecting:
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn
index 530dc71..403f89c 100644
--- a/chrome/browser/ui/BUILD.gn
+++ b/chrome/browser/ui/BUILD.gn
@@ -1891,6 +1891,8 @@
         "views/theme_copying_widget.h",
         "views/toolbar/app_menu.cc",
         "views/toolbar/app_menu.h",
+        "views/toolbar/app_menu_animation.cc",
+        "views/toolbar/app_menu_animation.h",
         "views/toolbar/app_menu_button.cc",
         "views/toolbar/app_menu_button.h",
         "views/toolbar/app_menu_observer.h",
diff --git a/chrome/browser/ui/ash/session_controller_client.cc b/chrome/browser/ui/ash/session_controller_client.cc
index 696beea..60d605c 100644
--- a/chrome/browser/ui/ash/session_controller_client.cc
+++ b/chrome/browser/ui/ash/session_controller_client.cc
@@ -12,6 +12,8 @@
 #include "base/bind.h"
 #include "base/logging.h"
 #include "base/strings/utf_string_conversions.h"
+#include "chrome/browser/chromeos/login/user_flow.h"
+#include "chrome/browser/chromeos/login/users/chrome_user_manager.h"
 #include "chrome/browser/chromeos/login/users/multi_profile_user_controller.h"
 #include "chrome/browser/chromeos/profiles/profile_helper.h"
 #include "chrome/browser/profiles/profile.h"
@@ -68,6 +70,12 @@
         IDR_PROFILE_PICTURE_LOADING);
   }
 
+  chromeos::UserFlow* const user_flow =
+      chromeos::ChromeUserManager::Get()->GetUserFlow(user.GetAccountId());
+  session->should_enable_settings = user_flow->ShouldEnableSettings();
+  session->should_show_notification_tray =
+      user_flow->ShouldShowNotificationTray();
+
   return session;
 }
 
diff --git a/chrome/browser/ui/ash/system_tray_delegate_chromeos.cc b/chrome/browser/ui/ash/system_tray_delegate_chromeos.cc
index 69aa6c3..b176b96 100644
--- a/chrome/browser/ui/ash/system_tray_delegate_chromeos.cc
+++ b/chrome/browser/ui/ash/system_tray_delegate_chromeos.cc
@@ -39,8 +39,6 @@
 #include "chrome/browser/chromeos/login/help_app_launcher.h"
 #include "chrome/browser/chromeos/login/login_wizard.h"
 #include "chrome/browser/chromeos/login/ui/user_adding_screen.h"
-#include "chrome/browser/chromeos/login/user_flow.h"
-#include "chrome/browser/chromeos/login/users/chrome_user_manager.h"
 #include "chrome/browser/chromeos/login/users/supervised_user_manager.h"
 #include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h"
 #include "chrome/browser/chromeos/policy/device_cloud_policy_manager_chromeos.h"
@@ -250,22 +248,6 @@
   return user_manager::UserManager::Get()->IsLoggedInAsChildUser();
 }
 
-bool SystemTrayDelegateChromeOS::ShouldShowSettings() const {
-  // Show setting button only when the user flow allows and it's not in the
-  // multi-profile login screen.
-  return ChromeUserManager::Get()->GetCurrentUserFlow()->ShouldShowSettings() &&
-         !IsSessionInSecondaryLoginScreen();
-}
-
-bool SystemTrayDelegateChromeOS::ShouldShowNotificationTray() const {
-  // Show notification tray only when the user flow allows and it's not in the
-  // multi-profile login screen.
-  return ChromeUserManager::Get()
-             ->GetCurrentUserFlow()
-             ->ShouldShowNotificationTray() &&
-         !IsSessionInSecondaryLoginScreen();
-}
-
 void SystemTrayDelegateChromeOS::ShowEnterpriseInfo() {
   // TODO(mash): Refactor out SessionStateDelegate and move to SystemTrayClient.
   ash::LoginStatus status = GetUserLoginStatus();
diff --git a/chrome/browser/ui/ash/system_tray_delegate_chromeos.h b/chrome/browser/ui/ash/system_tray_delegate_chromeos.h
index ca9086c..035a5b9f 100644
--- a/chrome/browser/ui/ash/system_tray_delegate_chromeos.h
+++ b/chrome/browser/ui/ash/system_tray_delegate_chromeos.h
@@ -60,8 +60,6 @@
   base::string16 GetSupervisedUserMessage() const override;
   bool IsUserSupervised() const override;
   bool IsUserChild() const override;
-  bool ShouldShowSettings() const override;
-  bool ShouldShowNotificationTray() const override;
   void ShowEnterpriseInfo() override;
   void ShowUserLogin() override;
   void GetCurrentIME(ash::IMEInfo* info) override;
diff --git a/chrome/browser/ui/toolbar/app_menu_icon_controller.cc b/chrome/browser/ui/toolbar/app_menu_icon_controller.cc
index 94409738..2d67da2 100644
--- a/chrome/browser/ui/toolbar/app_menu_icon_controller.cc
+++ b/chrome/browser/ui/toolbar/app_menu_icon_controller.cc
@@ -40,14 +40,7 @@
 // Checks if the app menu icon should be animated for the given upgrade level.
 bool ShouldAnimateUpgradeLevel(
     UpgradeDetector::UpgradeNotificationAnnoyanceLevel level) {
-  bool should_animate = true;
-  if (level == UpgradeDetector::UPGRADE_ANNOYANCE_LOW) {
-    // Only animate low severity upgrades once.
-    static bool should_animate_low_severity = true;
-    should_animate = should_animate_low_severity;
-    should_animate_low_severity = false;
-  }
-  return should_animate;
+  return level != UpgradeDetector::UPGRADE_ANNOYANCE_NONE;
 }
 
 // Returns true if we should show the upgrade recommended icon.
@@ -121,8 +114,7 @@
     return;
   }
 
-  delegate_->UpdateSeverity(IconType::NONE,
-                            Severity::NONE, true);
+  delegate_->UpdateSeverity(IconType::NONE, Severity::NONE, false);
 }
 
 #if defined(OS_WIN)
diff --git a/chrome/browser/ui/views/tabs/tab.cc b/chrome/browser/ui/views/tabs/tab.cc
index 36cc8cd5..9935918 100644
--- a/chrome/browser/ui/views/tabs/tab.cc
+++ b/chrome/browser/ui/views/tabs/tab.cc
@@ -14,7 +14,8 @@
 #include "base/metrics/user_metrics.h"
 #include "base/strings/utf_string_conversions.h"
 #include "build/build_config.h"
-#include "cc/paint/paint_shader.h"
+#include "cc/paint/paint_flags.h"
+#include "cc/paint/paint_recorder.h"
 #include "chrome/app/vector_icons/vector_icons.h"
 #include "chrome/browser/themes/theme_properties.h"
 #include "chrome/browser/ui/browser.h"
@@ -93,95 +94,9 @@
 // Inactive selected tabs have their throb value scaled by this.
 const double kSelectedTabThrobScale = 0.95 - kSelectedTabOpacity;
 
-// Max number of images to cache. This has to be at least two since rounding
-// errors may lead to tabs in the same tabstrip having different sizes.
-// 8 = normal/incognito, active/inactive, 2 sizes within tabstrip.
-const size_t kMaxImageCacheSize = 8;
-
 const char kTabCloseButtonName[] = "TabCloseButton";
 
 ////////////////////////////////////////////////////////////////////////////////
-// ImageCacheEntryMetadata
-//
-// All metadata necessary to uniquely identify a cached image.
-struct ImageCacheEntryMetadata {
-  ImageCacheEntryMetadata(SkColor fill_color,
-                          SkColor stroke_color,
-                          bool use_fill_and_stroke_images,
-                          float scale_factor,
-                          const gfx::Size& size);
-
-  ~ImageCacheEntryMetadata();
-
-  bool operator==(const ImageCacheEntryMetadata& rhs) const;
-
-  SkColor fill_color;
-  SkColor stroke_color;
-  bool use_fill_and_stroke_images;
-  float scale_factor;
-  gfx::Size size;
-};
-
-ImageCacheEntryMetadata::ImageCacheEntryMetadata(
-    SkColor fill_color,
-    SkColor stroke_color,
-    bool use_fill_and_stroke_images,
-    float scale_factor,
-    const gfx::Size& size)
-    : fill_color(fill_color),
-      stroke_color(stroke_color),
-      use_fill_and_stroke_images(use_fill_and_stroke_images),
-      scale_factor(scale_factor),
-      size(size) {}
-
-ImageCacheEntryMetadata::~ImageCacheEntryMetadata() {}
-
-bool ImageCacheEntryMetadata::operator==(
-    const ImageCacheEntryMetadata& rhs) const {
-  return fill_color == rhs.fill_color && stroke_color == rhs.stroke_color &&
-         use_fill_and_stroke_images == rhs.use_fill_and_stroke_images &&
-         scale_factor == rhs.scale_factor && size == rhs.size;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// ImageCacheEntry and cache management
-//
-// A cached image and the metadata used to generate it.
-struct ImageCacheEntry {
-  ImageCacheEntry(const ImageCacheEntryMetadata& metadata,
-                  const gfx::ImageSkia& fill_image,
-                  const gfx::ImageSkia& stroke_image);
-  ~ImageCacheEntry();
-
-  ImageCacheEntryMetadata metadata;
-  gfx::ImageSkia fill_image;
-  gfx::ImageSkia stroke_image;
-};
-
-ImageCacheEntry::ImageCacheEntry(const ImageCacheEntryMetadata& metadata,
-                                 const gfx::ImageSkia& fill_image,
-                                 const gfx::ImageSkia& stroke_image)
-    : metadata(metadata), fill_image(fill_image), stroke_image(stroke_image) {}
-
-ImageCacheEntry::~ImageCacheEntry() {}
-
-typedef std::list<ImageCacheEntry> ImageCache;
-
-// As the majority of the tabs are inactive, and painting tabs is slowish,
-// we cache a handful of the inactive tab backgrounds here.
-static ImageCache* g_image_cache = nullptr;
-
-// Performs a one-time initialization of static resources such as tab images.
-void InitTabResources() {
-  static bool initialized = false;
-  if (initialized)
-    return;
-
-  initialized = true;
-  g_image_cache = new ImageCache();
-}
-
-////////////////////////////////////////////////////////////////////////////////
 // Drawing and utility functions
 
 // Returns the width of the tab endcap at scale 1.  More precisely, this is the
@@ -534,7 +449,6 @@
       showing_close_button_(false),
       button_color_(SK_ColorTRANSPARENT) {
   DCHECK(controller);
-  InitTabResources();
 
   // So we get don't get enter/exit on children and don't prematurely stop the
   // hover.
@@ -1118,13 +1032,16 @@
 }
 
 void Tab::PaintTab(gfx::Canvas* canvas, const gfx::Path& clip) {
-  const int kActiveTabFillId =
-      GetThemeProvider()->HasCustomImage(IDR_THEME_TOOLBAR) ? IDR_THEME_TOOLBAR
-                                                            : 0;
-  const int y_offset = -GetLayoutInsets(TAB).top();
+  int active_tab_fill_id = 0;
+  int active_tab_y_offset = 0;
+  if (GetThemeProvider()->HasCustomImage(IDR_THEME_TOOLBAR)) {
+    active_tab_fill_id = IDR_THEME_TOOLBAR;
+    active_tab_y_offset = -GetLayoutInsets(TAB).top();
+  }
+
   if (IsActive()) {
-    PaintTabBackgroundUsingFillId(canvas, canvas, true, kActiveTabFillId,
-                                  y_offset);
+    PaintTabBackground(canvas, true /* active */, active_tab_fill_id,
+                       active_tab_y_offset, nullptr /* clip */);
   } else {
     PaintInactiveTabBackground(canvas, clip);
 
@@ -1132,8 +1049,8 @@
     if (throb_value > 0) {
       canvas->SaveLayerAlpha(gfx::ToRoundedInt(throb_value * 0xff),
                              GetLocalBounds());
-      PaintTabBackgroundUsingFillId(canvas, canvas, true, kActiveTabFillId,
-                                    y_offset);
+      PaintTabBackground(canvas, true /* active */, active_tab_fill_id,
+                         active_tab_y_offset, nullptr /* clip */);
       canvas->Restore();
     }
   }
@@ -1146,130 +1063,152 @@
                                      const gfx::Path& clip) {
   bool has_custom_image;
   int fill_id = controller_->GetBackgroundResourceId(&has_custom_image);
-  const ui::ThemeProvider* tp = GetThemeProvider();
 
-  // We only cache the image when it's the default image and we're not hovered,
-  // to avoid caching a background image that isn't the same for all tabs.
-  if (has_custom_image) {
-    // If the theme is providing a custom background image, then its top edge
-    // should be at the top of the tab. Otherwise, we assume that the background
-    // image is a composited foreground + frame image.  Note that if the theme
-    // is only providing a custom frame image, |has_custom_image| will be true,
-    // but we should use the |background_offset_| here.
-    const int y_offset =
-        tp->HasCustomImage(fill_id) ? 0 : background_offset_.y();
-    PaintTabBackgroundUsingFillId(canvas, canvas, false, fill_id, y_offset);
-    return;
-  }
-  if (hover_controller_.ShouldDraw()) {
-    PaintTabBackgroundUsingFillId(canvas, canvas, false, 0, 0);
-    return;
+  // The offset used to read from the image specified by |fill_id|.
+  int y_offset = 0;
+
+  if (!has_custom_image) {
+    fill_id = 0;
+  } else if (!GetThemeProvider()->HasCustomImage(fill_id)) {
+    // If there's a custom frame image but no custom image for the tab itself,
+    // then the tab's background will be the frame's image, so we need to
+    // provide an offset into the image to read from.
+    y_offset = background_offset_.y();
   }
 
-  // For efficiency, we don't use separate fill and stroke images unless we
-  // really need to clip the stroke and not the fill (for stacked tabs).  This
-  // saves memory and avoids an extra image draw at the cost of recalculating
-  // the images when MaySetClip() toggles.
-  const bool use_fill_and_stroke_images = controller_->MaySetClip();
-
-  const ImageCacheEntryMetadata metadata(
-      tp->GetColor(ThemeProperties::COLOR_BACKGROUND_TAB),
-      controller_->GetToolbarTopSeparatorColor(), use_fill_and_stroke_images,
-      canvas->image_scale(), size());
-  auto it = std::find_if(
-      g_image_cache->begin(), g_image_cache->end(),
-      [&metadata](const ImageCacheEntry& e) { return e.metadata == metadata; });
-  if (it == g_image_cache->end()) {
-    gfx::Canvas tmp_canvas(size(), canvas->image_scale(), false);
-    if (use_fill_and_stroke_images) {
-      gfx::Canvas tmp_fill_canvas(size(), canvas->image_scale(), false);
-      PaintTabBackgroundUsingFillId(&tmp_fill_canvas, &tmp_canvas, false, 0, 0);
-      g_image_cache->emplace_front(
-          metadata, gfx::ImageSkia(tmp_fill_canvas.ExtractImageRep()),
-          gfx::ImageSkia(tmp_canvas.ExtractImageRep()));
-    } else {
-      PaintTabBackgroundUsingFillId(&tmp_canvas, &tmp_canvas, false, 0, 0);
-      g_image_cache->emplace_front(
-          metadata, gfx::ImageSkia(),
-          gfx::ImageSkia(tmp_canvas.ExtractImageRep()));
-    }
-    if (g_image_cache->size() > kMaxImageCacheSize)
-      g_image_cache->pop_back();
-    it = g_image_cache->begin();
-  }
-
-  gfx::ScopedCanvas scoped_canvas(
-      use_fill_and_stroke_images ? canvas : nullptr);
-  if (use_fill_and_stroke_images) {
-    canvas->DrawImageInt(it->fill_image, 0, 0);
-    canvas->sk_canvas()->clipPath(clip, SkClipOp::kDifference, true);
-  }
-  canvas->DrawImageInt(it->stroke_image, 0, 0);
+  PaintTabBackground(canvas, false /* active */, fill_id, y_offset,
+                     controller_->MaySetClip() ? &clip : nullptr);
 }
 
-void Tab::PaintTabBackgroundUsingFillId(gfx::Canvas* fill_canvas,
-                                        gfx::Canvas* stroke_canvas,
-                                        bool is_active,
-                                        int fill_id,
-                                        int y_offset) {
-  gfx::Path fill;
+void Tab::PaintTabBackground(gfx::Canvas* canvas,
+                             bool active,
+                             int fill_id,
+                             int y_offset,
+                             const gfx::Path* clip) {
+  // |y_offset| is only set when |fill_id| is being used.
+  DCHECK(!y_offset || fill_id);
+
+  const ui::ThemeProvider* tp = GetThemeProvider();
+  const SkColor active_color = tp->GetColor(ThemeProperties::COLOR_TOOLBAR);
+  const SkColor inactive_color =
+      tp->GetColor(ThemeProperties::COLOR_BACKGROUND_TAB);
+  const SkColor stroke_color = controller_->GetToolbarTopSeparatorColor();
+  const bool paint_hover_effect = !active && hover_controller_.ShouldDraw();
+
+  // If there is a |fill_id| we don't try to cache. This could be improved
+  // but would require knowing then the image from the ThemeProvider had been
+  // changed, and invalidating when the tab's x-coordinate or background_offset_
+  // changed.
+  // Similarly, if |paint_hover_effect|, we don't try to cache since hover
+  // effects change on every invalidation and we would need to invalidate the
+  // cache based on the hover states.
+  if (fill_id || paint_hover_effect) {
+    gfx::Path fill_path = GetFillPath(canvas->image_scale(), size());
+    gfx::Path stroke_path =
+        GetBorderPath(canvas->image_scale(), false, false, size());
+    PaintTabBackgroundFill(canvas, fill_path, active, paint_hover_effect,
+                           active_color, inactive_color, fill_id, y_offset);
+    gfx::ScopedCanvas scoped_canvas(clip ? canvas : nullptr);
+    if (clip)
+      canvas->sk_canvas()->clipPath(*clip, SkClipOp::kDifference, true);
+    PaintTabBackgroundStroke(canvas, fill_path, stroke_path, active,
+                             stroke_color);
+    return;
+  }
+
+  BackgroundCache& cache =
+      active ? background_active_cache_ : background_inactive_cache_;
+  if (!cache.CacheKeyMatches(canvas->image_scale(), size(), active_color,
+                             inactive_color, stroke_color)) {
+    gfx::Path fill_path = GetFillPath(canvas->image_scale(), size());
+    gfx::Path stroke_path =
+        GetBorderPath(canvas->image_scale(), false, false, size());
+    cc::PaintRecorder recorder;
+
+    {
+      gfx::Canvas cache_canvas(
+          recorder.beginRecording(size().width(), size().height()),
+          canvas->image_scale());
+      PaintTabBackgroundFill(&cache_canvas, fill_path, active,
+                             paint_hover_effect, active_color, inactive_color,
+                             fill_id, y_offset);
+      cache.fill_record = recorder.finishRecordingAsPicture();
+    }
+    {
+      gfx::Canvas cache_canvas(
+          recorder.beginRecording(size().width(), size().height()),
+          canvas->image_scale());
+      PaintTabBackgroundStroke(&cache_canvas, fill_path, stroke_path, active,
+                               stroke_color);
+      cache.stroke_record = recorder.finishRecordingAsPicture();
+    }
+
+    cache.SetCacheKey(canvas->image_scale(), size(), active_color,
+                      inactive_color, stroke_color);
+  }
+
+  canvas->sk_canvas()->PlaybackPaintRecord(cache.fill_record);
+  gfx::ScopedCanvas scoped_canvas(clip ? canvas : nullptr);
+  if (clip)
+    canvas->sk_canvas()->clipPath(*clip, SkClipOp::kDifference, true);
+  canvas->sk_canvas()->PlaybackPaintRecord(cache.stroke_record);
+}
+
+void Tab::PaintTabBackgroundFill(gfx::Canvas* canvas,
+                                 const gfx::Path& fill_path,
+                                 bool active,
+                                 bool paint_hover_effect,
+                                 SkColor active_color,
+                                 SkColor inactive_color,
+                                 int fill_id,
+                                 int y_offset) {
+  gfx::ScopedCanvas scoped_canvas(canvas);
+  const float scale = canvas->UndoDeviceScaleFactor();
+
+  canvas->ClipPath(fill_path, true);
+  if (fill_id) {
+    gfx::ScopedCanvas scale_scoper(canvas);
+    canvas->sk_canvas()->scale(scale, scale);
+    canvas->TileImageInt(*GetThemeProvider()->GetImageSkiaNamed(fill_id),
+                         GetMirroredX() + background_offset_.x(), y_offset, 0,
+                         0, width(), height());
+  } else {
+    cc::PaintFlags flags;
+    flags.setAntiAlias(true);
+    flags.setColor(active ? active_color : inactive_color);
+    canvas->DrawRect(gfx::ScaleToEnclosingRect(GetLocalBounds(), scale), flags);
+  }
+
+  if (paint_hover_effect) {
+    SkPoint hover_location(gfx::PointToSkPoint(hover_controller_.location()));
+    hover_location.scale(SkFloatToScalar(scale));
+    const SkScalar kMinHoverRadius = 16;
+    const SkScalar radius =
+        std::max(SkFloatToScalar(width() / 4.f), kMinHoverRadius);
+    DrawHighlight(canvas, hover_location, radius * scale,
+                  SkColorSetA(active_color, hover_controller_.GetAlpha()));
+  }
+}
+
+void Tab::PaintTabBackgroundStroke(gfx::Canvas* canvas,
+                                   const gfx::Path& fill_path,
+                                   const gfx::Path& stroke_path,
+                                   bool active,
+                                   SkColor color) {
+  gfx::ScopedCanvas scoped_canvas(canvas);
+  const float scale = canvas->UndoDeviceScaleFactor();
+
+  if (!active) {
+    // Clip out the bottom line; this will be drawn for us by
+    // TabStrip::PaintChildren().
+    canvas->ClipRect(gfx::RectF(width() * scale, height() * scale - 1));
+  }
   cc::PaintFlags flags;
   flags.setAntiAlias(true);
-
-  // Draw the fill.
-  {
-    gfx::ScopedCanvas scoped_canvas(fill_canvas);
-    const float scale = fill_canvas->UndoDeviceScaleFactor();
-    const ui::ThemeProvider* tp = GetThemeProvider();
-    const SkColor toolbar_color = tp->GetColor(ThemeProperties::COLOR_TOOLBAR);
-
-    fill = GetFillPath(scale, size());
-    {
-      gfx::ScopedCanvas clip_scoper(fill_canvas);
-      fill_canvas->ClipPath(fill, true);
-      if (fill_id) {
-        gfx::ScopedCanvas scale_scoper(fill_canvas);
-        fill_canvas->sk_canvas()->scale(scale, scale);
-        fill_canvas->TileImageInt(*tp->GetImageSkiaNamed(fill_id),
-                                  GetMirroredX() + background_offset_.x(),
-                                  y_offset, 0, 0, width(), height());
-      } else {
-        flags.setColor(
-            is_active ? toolbar_color
-                      : tp->GetColor(ThemeProperties::COLOR_BACKGROUND_TAB));
-        fill_canvas->DrawRect(
-            gfx::ScaleToEnclosingRect(GetLocalBounds(), scale), flags);
-      }
-
-      if (!is_active && hover_controller_.ShouldDraw()) {
-        SkPoint hover_location(
-            gfx::PointToSkPoint(hover_controller_.location()));
-        hover_location.scale(SkFloatToScalar(scale));
-        const SkScalar kMinHoverRadius = 16;
-        const SkScalar radius =
-            std::max(SkFloatToScalar(width() / 4.f), kMinHoverRadius);
-        DrawHighlight(fill_canvas, hover_location, radius * scale,
-                      SkColorSetA(toolbar_color, hover_controller_.GetAlpha()));
-      }
-    }
-  }
-
-  // Draw the stroke.
-  {
-    gfx::ScopedCanvas scoped_canvas(stroke_canvas);
-    const float scale = stroke_canvas->UndoDeviceScaleFactor();
-
-    gfx::Path stroke = GetBorderPath(scale, false, false, size());
-    Op(stroke, fill, kDifference_SkPathOp, &stroke);
-    if (!is_active) {
-      // Clip out the bottom line; this will be drawn for us by
-      // TabStrip::PaintChildren().
-      stroke_canvas->ClipRect(
-          gfx::RectF(width() * scale, height() * scale - 1));
-    }
-    flags.setColor(controller_->GetToolbarTopSeparatorColor());
-    stroke_canvas->DrawPath(stroke, flags);
-  }
+  flags.setColor(color);
+  SkPath path;
+  Op(stroke_path, fill_path, kDifference_SkPathOp, &path);
+  canvas->DrawPath(path, flags);
 }
 
 void Tab::PaintPinnedTabTitleChangedIndicatorAndIcon(
@@ -1493,3 +1432,6 @@
   bounds.set_x(GetMirroredXForRect(bounds));
   SchedulePaintInRect(bounds);
 }
+
+Tab::BackgroundCache::BackgroundCache() = default;
+Tab::BackgroundCache::~BackgroundCache() = default;
diff --git a/chrome/browser/ui/views/tabs/tab.h b/chrome/browser/ui/views/tabs/tab.h
index 7b7bc644..380ce51 100644
--- a/chrome/browser/ui/views/tabs/tab.h
+++ b/chrome/browser/ui/views/tabs/tab.h
@@ -12,6 +12,7 @@
 #include "base/gtest_prod_util.h"
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
+#include "cc/paint/paint_record.h"
 #include "chrome/browser/ui/views/tabs/tab_renderer_data.h"
 #include "ui/base/layout.h"
 #include "ui/gfx/animation/animation_delegate.h"
@@ -235,11 +236,26 @@
   // Paints a tab background using the image defined by |fill_id| at the
   // provided offset. If |fill_id| is 0, it will fall back to using the solid
   // color defined by the theme provider and ignore the offset.
-  void PaintTabBackgroundUsingFillId(gfx::Canvas* fill_canvas,
-                                     gfx::Canvas* stroke_canvas,
-                                     bool is_active,
-                                     int fill_id,
-                                     int y_offset);
+  void PaintTabBackground(gfx::Canvas* canvas,
+                          bool active,
+                          int fill_id,
+                          int y_offset,
+                          const gfx::Path* clip);
+
+  // Helper methods for PaintTabBackground.
+  void PaintTabBackgroundFill(gfx::Canvas* canvas,
+                              const gfx::Path& fill_path,
+                              bool active,
+                              bool hover,
+                              SkColor active_color,
+                              SkColor inactive_color,
+                              int fill_id,
+                              int y_offset);
+  void PaintTabBackgroundStroke(gfx::Canvas* canvas,
+                                const gfx::Path& fill_path,
+                                const gfx::Path& stroke_path,
+                                bool active,
+                                SkColor color);
 
   // Paints the pinned tab title changed indicator and |favicon_|. |favicon_|
   // may be null. |favicon_draw_bounds| is |favicon_bounds_| adjusted for rtl
@@ -355,6 +371,50 @@
   // and thus may be null.
   gfx::ImageSkia favicon_;
 
+  class BackgroundCache {
+   public:
+    BackgroundCache();
+    ~BackgroundCache();
+
+    bool CacheKeyMatches(float scale,
+                         const gfx::Size& size,
+                         SkColor active_color,
+                         SkColor inactive_color,
+                         SkColor stroke_color) {
+      return scale_ == scale && size_ == size &&
+             active_color_ == active_color &&
+             inactive_color_ == inactive_color && stroke_color_ == stroke_color;
+    }
+
+    void SetCacheKey(float scale,
+                     const gfx::Size& size,
+                     SkColor active_color,
+                     SkColor inactive_color,
+                     SkColor stroke_color) {
+      scale_ = scale;
+      size_ = size;
+      active_color_ = active_color;
+      inactive_color_ = inactive_color;
+      stroke_color_ = stroke_color;
+    }
+
+    // The PaintRecords being cached based on the input parameters.
+    sk_sp<cc::PaintRecord> fill_record;
+    sk_sp<cc::PaintRecord> stroke_record;
+
+   private:
+    // Parameters used to construct the PaintRecords.
+    float scale_ = 0.f;
+    gfx::Size size_;
+    SkColor active_color_ = 0;
+    SkColor inactive_color_ = 0;
+    SkColor stroke_color_ = 0;
+  };
+
+  // Cache of the paint output for tab backgrounds.
+  BackgroundCache background_active_cache_;
+  BackgroundCache background_inactive_cache_;
+
   DISALLOW_COPY_AND_ASSIGN(Tab);
 };
 
diff --git a/chrome/browser/ui/views/toolbar/app_menu_animation.cc b/chrome/browser/ui/views/toolbar/app_menu_animation.cc
new file mode 100644
index 0000000..8d643ca
--- /dev/null
+++ b/chrome/browser/ui/views/toolbar/app_menu_animation.cc
@@ -0,0 +1,196 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/ui/views/toolbar/app_menu_animation.h"
+
+#include "base/memory/ptr_util.h"
+#include "cc/paint/paint_flags.h"
+#include "chrome/browser/ui/views/toolbar/app_menu_button.h"
+#include "ui/gfx/animation/tween.h"
+#include "ui/gfx/canvas.h"
+#include "ui/gfx/color_palette.h"
+#include "ui/gfx/color_utils.h"
+#include "ui/gfx/skia_util.h"
+
+namespace {
+
+// Duration of the open and close animations in ms.
+constexpr float kOpenDurationMs = 733.0f;
+constexpr float kCloseDurationMs = 283.0f;
+
+// Duration of the color animation in ms.
+constexpr float kColorDurationMs = 100.0f;
+
+// The % the top and bottom dots need to be offset from the middle.
+constexpr float kDotYOffset = 0.32f;
+
+// Value of the stroke when the icon is opened or closed.
+constexpr float kCloseStroke = 0.204f;
+constexpr float kOpenStroke = 0.136f;
+
+// Value of the width when the animation is fully opened.
+constexpr float kOpenWidth = 0.52f;
+
+// The delay of the color and dot animations in ms.
+constexpr float kColorDelayMs = 33.33f;
+constexpr float kDotDelayMs = 66.67f;
+
+// The % of time it takes for each dot to animate to its full width.
+constexpr float kTopWidthOpenInterval = 533.3f / kOpenDurationMs;
+constexpr float kMiddleWidthOpenInterval = 383.3f / kOpenDurationMs;
+constexpr float kBottomWidthOpenInterval = 400.0f / kOpenDurationMs;
+
+// The % of time it takes for each dot to animate to its final stroke.
+constexpr float kTopStrokeOpenInterval = 400.0f / kOpenDurationMs;
+constexpr float kMiddleStrokeOpenInterval = 283.3f / kOpenDurationMs;
+constexpr float kBottomStrokeOpenInterval = 266.7f / kOpenDurationMs;
+
+// The % of time it takes for each dot to animate its width and stroke.
+constexpr float kWidthStrokeCloseInterval = 150.0f / kCloseDurationMs;
+
+}  // namespace
+
+AppMenuAnimation::AppMenuDot::AppMenuDot(base::TimeDelta delay,
+                                         float width_open_interval,
+                                         float stroke_open_interval)
+    : delay_(delay),
+      width_open_interval_(width_open_interval),
+      stroke_open_interval_(stroke_open_interval) {}
+
+void AppMenuAnimation::AppMenuDot::Paint(const gfx::PointF& center_point,
+                                         SkColor start_color,
+                                         SkColor severity_color,
+                                         gfx::Canvas* canvas,
+                                         const gfx::Rect& bounds,
+                                         const gfx::SlideAnimation* animation) {
+  bool is_opening = animation->IsShowing();
+  float total_duration = is_opening ? kOpenDurationMs : kCloseDurationMs;
+  float width_duration =
+      is_opening ? width_open_interval_ : kWidthStrokeCloseInterval;
+  float stroke_duration =
+      is_opening ? stroke_open_interval_ : kWidthStrokeCloseInterval;
+
+  // When the animation is closing, each dot uses the remainder of the full
+  // delay period (2 * kDotDelayMs). The results should be (0->2x, 1x->1x,
+  // 2x->0).
+  base::TimeDelta delay =
+      is_opening ? delay_
+                 : base::TimeDelta::FromMilliseconds(kDotDelayMs * 2) - delay_;
+  float progress =
+      animation->GetCurrentValue() - (delay.InMillisecondsF() / total_duration);
+
+  float width_progress = 0.0;
+  float stroke_progress = 0.0;
+  float color_progress = 0.0;
+
+  if (progress > 0) {
+    width_progress = std::min(1.0f, progress / width_duration);
+    stroke_progress = std::min(1.0f, progress / stroke_duration);
+
+    if (is_opening) {
+      float color_delay_interval = kColorDelayMs / total_duration;
+      float color_duration_interval = kColorDurationMs / total_duration;
+      if (progress > color_delay_interval) {
+        color_progress = std::min(
+            1.0f, (progress - color_delay_interval) / color_duration_interval);
+      }
+    }
+  }
+
+  float dot_height =
+      gfx::Tween::FloatValueBetween(stroke_progress, kCloseStroke, kOpenStroke);
+  dot_height *= bounds.height();
+
+  float dot_width =
+      gfx::Tween::FloatValueBetween(width_progress, kCloseStroke, kOpenWidth);
+  dot_width *= bounds.width();
+
+  gfx::PointF point = center_point;
+  point.Offset(-dot_width / 2, -dot_height / 2);
+
+  SkColor color = is_opening ? gfx::Tween::ColorValueBetween(
+                                   color_progress, start_color, severity_color)
+                             : severity_color;
+
+  cc::PaintFlags flags;
+  flags.setColor(color);
+  flags.setStrokeWidth(bounds.height() * kCloseStroke);
+  flags.setStrokeCap(cc::PaintFlags::kRound_Cap);
+  flags.setStyle(cc::PaintFlags::kFill_Style);
+  flags.setAntiAlias(true);
+
+  gfx::SizeF dot_size = gfx::SizeF(dot_width, dot_height);
+  canvas->DrawRoundRect(gfx::RectF(point, dot_size), 2.0, flags);
+}
+
+AppMenuAnimation::AppMenuAnimation(AppMenuButton* owner,
+                                   bool should_animate_closed)
+    : owner_(owner),
+      should_animate_closed_(should_animate_closed),
+      animation_(base::MakeUnique<gfx::SlideAnimation>(this)),
+      bottom_dot_(base::TimeDelta(),
+                  kBottomWidthOpenInterval,
+                  kBottomStrokeOpenInterval),
+      middle_dot_(base::TimeDelta::FromMilliseconds(kDotDelayMs),
+                  kMiddleWidthOpenInterval,
+                  kMiddleStrokeOpenInterval),
+      top_dot_(base::TimeDelta::FromMilliseconds(kDotDelayMs * 2),
+               kTopWidthOpenInterval,
+               kTopStrokeOpenInterval),
+      start_color_(gfx::kPlaceholderColor),
+      severity_color_(gfx::kPlaceholderColor) {
+  animation_->SetSlideDuration(kOpenDurationMs);
+  animation_->SetTweenType(gfx::Tween::FAST_OUT_SLOW_IN);
+}
+
+AppMenuAnimation::~AppMenuAnimation() {}
+
+void AppMenuAnimation::PaintAppMenu(gfx::Canvas* canvas,
+                                    const gfx::Rect& bounds) {
+  gfx::PointF middle_point = gfx::PointF(bounds.CenterPoint());
+  float y_offset = kDotYOffset * bounds.height();
+  gfx::PointF top_point = middle_point;
+  top_point.Offset(0, -y_offset);
+
+  gfx::PointF bottom_point = middle_point;
+  bottom_point.Offset(0, y_offset);
+
+  middle_dot_.Paint(middle_point, start_color_, severity_color_, canvas, bounds,
+                    animation_.get());
+  top_dot_.Paint(top_point, start_color_, severity_color_, canvas, bounds,
+                 animation_.get());
+  bottom_dot_.Paint(bottom_point, start_color_, severity_color_, canvas, bounds,
+                    animation_.get());
+}
+
+void AppMenuAnimation::SetIconColors(SkColor start_color,
+                                     SkColor severity_color) {
+  start_color_ = start_color;
+  severity_color_ = severity_color;
+}
+
+void AppMenuAnimation::StartAnimation() {
+  if (!animation_->is_animating()) {
+    animation_->SetSlideDuration(kOpenDurationMs);
+    animation_->Show();
+    owner_->AppMenuAnimationStarted();
+  }
+}
+
+void AppMenuAnimation::AnimationEnded(const gfx::Animation* animation) {
+  if (animation_->IsShowing() && should_animate_closed_) {
+    animation_->SetSlideDuration(kCloseDurationMs);
+    animation_->Hide();
+    return;
+  }
+
+  if (!animation_->IsShowing())
+    start_color_ = severity_color_;
+
+  owner_->AppMenuAnimationEnded();
+}
+
+void AppMenuAnimation::AnimationProgressed(const gfx::Animation* animation) {
+  owner_->SchedulePaint();
+}
diff --git a/chrome/browser/ui/views/toolbar/app_menu_animation.h b/chrome/browser/ui/views/toolbar/app_menu_animation.h
new file mode 100644
index 0000000..1ff69ee
--- /dev/null
+++ b/chrome/browser/ui/views/toolbar/app_menu_animation.h
@@ -0,0 +1,93 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_UI_VIEWS_TOOLBAR_APP_MENU_ANIMATION_H_
+#define CHROME_BROWSER_UI_VIEWS_TOOLBAR_APP_MENU_ANIMATION_H_
+
+#include "base/time/time.h"
+#include "third_party/skia/include/core/SkColor.h"
+#include "ui/gfx/animation/animation_delegate.h"
+#include "ui/gfx/animation/slide_animation.h"
+
+namespace gfx {
+class Canvas;
+class PointF;
+}  // namespace gfx
+
+class AppMenuButton;
+
+// This class is used for animating and drawing the app menu icon.
+class AppMenuAnimation : public gfx::AnimationDelegate {
+ public:
+  AppMenuAnimation(AppMenuButton* owner, bool should_animate_closed);
+
+  ~AppMenuAnimation() override;
+
+  // Paints the app menu icon.
+  void PaintAppMenu(gfx::Canvas* canvas, const gfx::Rect& bounds);
+
+  // Updates the icon colors.
+  void SetIconColors(SkColor start_color, SkColor severity_color);
+
+  // Starts the animation if it's not already running.
+  void StartAnimation();
+
+  // gfx::AnimationDelegate:
+  void AnimationEnded(const gfx::Animation* animation) override;
+  void AnimationProgressed(const gfx::Animation* animation) override;
+
+ private:
+  // This class is used to represent and paint a dot on the app menu.
+  class AppMenuDot {
+   public:
+    AppMenuDot(base::TimeDelta delay,
+               float width_open_interval,
+               float stroke_open_interval);
+
+    // Paints the dot on the given |canvas| according to the progress of
+    // |animation|. The size of the dot is calculated to fit in |bounds|.
+    // |center_point| is the dot's position on the canvas. The dot's color is
+    // a transition from |start_color| to |final_color|.
+    void Paint(const gfx::PointF& center_point,
+               SkColor start_color,
+               SkColor final_color,
+               gfx::Canvas* canvas,
+               const gfx::Rect& bounds,
+               const gfx::SlideAnimation* animation);
+
+   private:
+    // The delay before the dot starts animating in ms.
+    const base::TimeDelta delay_;
+
+    // The percentage of the overall animation duration it takes to animate the
+    // width and stroke to their open state.
+    const float width_open_interval_;
+    const float stroke_open_interval_;
+
+    DISALLOW_COPY_AND_ASSIGN(AppMenuDot);
+  };
+
+  AppMenuButton* const owner_;
+
+  // True if the animation should close after it finishes opening.
+  const bool should_animate_closed_;
+
+  std::unique_ptr<gfx::SlideAnimation> animation_;
+
+  AppMenuDot bottom_dot_;
+  AppMenuDot middle_dot_;
+  AppMenuDot top_dot_;
+
+  // The starting color of the dots. The animation is expected to transition
+  // from this color to |severity_color_|.
+  SkColor start_color_;
+
+  // The severity color of the dots. This is final color at the end of the
+  // animation.
+  SkColor severity_color_;
+
+  DISALLOW_COPY_AND_ASSIGN(AppMenuAnimation);
+};
+
+#endif  // CHROME_BROWSER_UI_VIEWS_TOOLBAR_APP_MENU_ANIMATION_H_
diff --git a/chrome/browser/ui/views/toolbar/app_menu_button.cc b/chrome/browser/ui/views/toolbar/app_menu_button.cc
index 448dcc6..3004a94b 100644
--- a/chrome/browser/ui/views/toolbar/app_menu_button.cc
+++ b/chrome/browser/ui/views/toolbar/app_menu_button.cc
@@ -4,21 +4,27 @@
 
 #include "chrome/browser/ui/views/toolbar/app_menu_button.h"
 
+#include "base/command_line.h"
 #include "base/location.h"
+#include "base/memory/ptr_util.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/single_thread_task_runner.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "base/time/time.h"
+#include "cc/paint/paint_flags.h"
 #include "chrome/app/vector_icons/vector_icons.h"
 #include "chrome/browser/themes/theme_properties.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_otr_state.h"
 #include "chrome/browser/ui/layout_constants.h"
+#include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/browser/ui/toolbar/app_menu_model.h"
 #include "chrome/browser/ui/views/extensions/browser_action_drag_data.h"
 #include "chrome/browser/ui/views/toolbar/app_menu.h"
+#include "chrome/browser/ui/views/toolbar/app_menu_animation.h"
 #include "chrome/browser/ui/views/toolbar/toolbar_button.h"
 #include "chrome/browser/ui/views/toolbar/toolbar_view.h"
+#include "chrome/common/chrome_switches.h"
 #include "chrome/grit/theme_resources.h"
 #include "ui/base/resource/resource_bundle.h"
 #include "ui/base/theme_provider.h"
@@ -29,6 +35,10 @@
 #include "ui/views/controls/menu/menu_listener.h"
 #include "ui/views/metrics.h"
 
+namespace {
+const float kIconSize = 16;
+}  // namespace
+
 // static
 bool AppMenuButton::g_open_app_immediately_for_testing = false;
 
@@ -41,6 +51,19 @@
       weak_factory_(this) {
   SetInkDropMode(InkDropMode::ON);
   SetFocusPainter(nullptr);
+
+  base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
+  if (command_line->HasSwitch(switches::kAppMenuIcon)) {
+    std::string flag =
+        command_line->GetSwitchValueASCII(switches::kAppMenuIcon);
+    if (flag == switches::kAppMenuIconPersistentClosedState) {
+      Browser* browser = toolbar_view_->browser();
+      browser->tab_strip_model()->AddObserver(this);
+      animation_ = base::MakeUnique<AppMenuAnimation>(this, true);
+    } else if (flag == switches::kAppMenuIconPersistentOpenedState) {
+      animation_ = base::MakeUnique<AppMenuAnimation>(this, false);
+    }
+  }
 }
 
 AppMenuButton::~AppMenuButton() {}
@@ -50,7 +73,7 @@
                                 bool animate) {
   type_ = type;
   severity_ = severity;
-  UpdateIcon();
+  UpdateIcon(animate);
 }
 
 void AppMenuButton::ShowMenu(bool for_drop) {
@@ -85,6 +108,9 @@
     UMA_HISTOGRAM_TIMES("Toolbar.AppMenuTimeToAction",
                         base::TimeTicks::Now() - menu_open_time);
   }
+
+  if (severity_ != AppMenuIconController::Severity::NONE)
+    animation_->StartAnimation();
 }
 
 void AppMenuButton::CloseMenu() {
@@ -106,33 +132,70 @@
 }
 
 gfx::Size AppMenuButton::GetPreferredSize() const {
-  gfx::Rect rect(image()->GetPreferredSize());
+  gfx::Rect rect(gfx::Size(kIconSize, kIconSize));
   rect.Inset(gfx::Insets(-ToolbarButton::kInteriorPadding));
   return rect.size();
 }
 
-void AppMenuButton::UpdateIcon() {
-  SkColor color = gfx::kPlaceholderColor;
+void AppMenuButton::Layout() {
+  if (animation_) {
+    ink_drop_container()->SetBoundsRect(GetLocalBounds());
+    image()->SetBoundsRect(GetLocalBounds());
+    return;
+  }
+
+  views::MenuButton::Layout();
+}
+
+void AppMenuButton::OnPaint(gfx::Canvas* canvas) {
+  if (!animation_) {
+    views::MenuButton::OnPaint(canvas);
+    return;
+  }
+
+  gfx::Rect bounds = GetLocalBounds();
+  bounds.Inset(gfx::Insets(ToolbarButton::kInteriorPadding));
+  animation_->PaintAppMenu(canvas, bounds);
+}
+
+void AppMenuButton::TabInsertedAt(TabStripModel* tab_strip_model,
+                                  content::WebContents* contents,
+                                  int index,
+                                  bool foreground) {
+  if (severity_ != AppMenuIconController::Severity::NONE)
+    animation_->StartAnimation();
+}
+
+void AppMenuButton::UpdateIcon(bool should_animate) {
+  SkColor severity_color = gfx::kPlaceholderColor;
+  SkColor toolbar_icon_color =
+      GetThemeProvider()->GetColor(ThemeProperties::COLOR_TOOLBAR_BUTTON_ICON);
   const ui::NativeTheme* native_theme = GetNativeTheme();
   switch (severity_) {
     case AppMenuIconController::Severity::NONE:
-      color = GetThemeProvider()->GetColor(
-          ThemeProperties::COLOR_TOOLBAR_BUTTON_ICON);
+      severity_color = toolbar_icon_color;
       break;
     case AppMenuIconController::Severity::LOW:
-      color = native_theme->GetSystemColor(
+      severity_color = native_theme->GetSystemColor(
           ui::NativeTheme::kColorId_AlertSeverityLow);
       break;
     case AppMenuIconController::Severity::MEDIUM:
-      color = native_theme->GetSystemColor(
+      severity_color = native_theme->GetSystemColor(
           ui::NativeTheme::kColorId_AlertSeverityMedium);
       break;
     case AppMenuIconController::Severity::HIGH:
-      color = native_theme->GetSystemColor(
+      severity_color = native_theme->GetSystemColor(
           ui::NativeTheme::kColorId_AlertSeverityHigh);
       break;
   }
 
+  if (animation_) {
+    animation_->SetIconColors(toolbar_icon_color, severity_color);
+    if (should_animate)
+      animation_->StartAnimation();
+    return;
+  }
+
   const gfx::VectorIcon* icon_id = nullptr;
   switch (type_) {
     case AppMenuIconController::IconType::NONE:
@@ -148,7 +211,8 @@
       break;
   }
 
-  SetImage(views::Button::STATE_NORMAL, gfx::CreateVectorIcon(*icon_id, color));
+  SetImage(views::Button::STATE_NORMAL,
+           gfx::CreateVectorIcon(*icon_id, severity_color));
 }
 
 void AppMenuButton::SetTrailingMargin(int margin) {
@@ -157,6 +221,15 @@
   InvalidateLayout();
 }
 
+void AppMenuButton::AppMenuAnimationStarted() {
+  SetPaintToLayer();
+  layer()->SetFillsBoundsOpaquely(false);
+}
+
+void AppMenuButton::AppMenuAnimationEnded() {
+  DestroyLayer();
+}
+
 const char* AppMenuButton::GetClassName() const {
   return "AppMenuButton";
 }
diff --git a/chrome/browser/ui/views/toolbar/app_menu_button.h b/chrome/browser/ui/views/toolbar/app_menu_button.h
index 78eb36f..06167a7 100644
--- a/chrome/browser/ui/views/toolbar/app_menu_button.h
+++ b/chrome/browser/ui/views/toolbar/app_menu_button.h
@@ -9,6 +9,7 @@
 
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
+#include "chrome/browser/ui/tabs/tab_strip_model_observer.h"
 #include "chrome/browser/ui/toolbar/app_menu_icon_controller.h"
 #include "ui/views/controls/button/menu_button.h"
 #include "ui/views/controls/button/menu_button_listener.h"
@@ -22,9 +23,10 @@
 class MenuListener;
 }
 
+class AppMenuAnimation;
 class ToolbarView;
 
-class AppMenuButton : public views::MenuButton {
+class AppMenuButton : public views::MenuButton, public TabStripModelObserver {
  public:
   explicit AppMenuButton(ToolbarView* toolbar_view);
   ~AppMenuButton() override;
@@ -53,14 +55,28 @@
 
   // views::MenuButton:
   gfx::Size GetPreferredSize() const override;
+  void Layout() override;
+  void OnPaint(gfx::Canvas* canvas) override;
+
+  // TabStripObserver:
+  void TabInsertedAt(TabStripModel* tab_strip_model,
+                     content::WebContents* contents,
+                     int index,
+                     bool foreground) override;
 
   // Updates the presentation according to |severity_| and the theme provider.
-  void UpdateIcon();
+  // If |should_animate| is true, the icon should animate.
+  void UpdateIcon(bool should_animate);
 
   // Sets |margin_trailing_| when the browser is maximized and updates layout
   // to make the focus rectangle centered.
   void SetTrailingMargin(int margin);
 
+  // Methods called by AppMenuAnimation when the animation has started/ended.
+  // The layer is managed inside these methods.
+  void AppMenuAnimationStarted();
+  void AppMenuAnimationEnded();
+
   // Opens the app menu immediately during a drag-and-drop operation.
   // Used only in testing.
   static bool g_open_app_immediately_for_testing;
@@ -96,6 +112,9 @@
   std::unique_ptr<AppMenuModel> menu_model_;
   std::unique_ptr<AppMenu> menu_;
 
+  // Used for animating and drawing the app menu icon.
+  std::unique_ptr<AppMenuAnimation> animation_;
+
   // Any trailing margin to be applied. Used when the browser is in
   // a maximized state to extend to the full window width.
   int margin_trailing_;
diff --git a/chrome/browser/ui/views/toolbar/toolbar_view.cc b/chrome/browser/ui/views/toolbar/toolbar_view.cc
index b69095e..3c6d24d 100644
--- a/chrome/browser/ui/views/toolbar/toolbar_view.cc
+++ b/chrome/browser/ui/views/toolbar/toolbar_view.cc
@@ -744,7 +744,7 @@
       gfx::CreateVectorIcon(ui::kForwardArrowIcon, disabled_color));
   home_->SetImage(views::Button::STATE_NORMAL,
                   gfx::CreateVectorIcon(kNavigateHomeIcon, normal_color));
-  app_menu_button_->UpdateIcon();
+  app_menu_button_->UpdateIcon(false);
 
   back_->set_ink_drop_base_color(normal_color);
   forward_->set_ink_drop_base_color(normal_color);
diff --git a/chrome/browser/ui/webui/chromeos/network_element_localized_strings_provider.cc b/chrome/browser/ui/webui/chromeos/network_element_localized_strings_provider.cc
index d8b4409..9ed17e6 100644
--- a/chrome/browser/ui/webui/chromeos/network_element_localized_strings_provider.cc
+++ b/chrome/browser/ui/webui/chromeos/network_element_localized_strings_provider.cc
@@ -21,7 +21,6 @@
       {"OncTypeVPN", IDS_NETWORK_TYPE_VPN},
       {"OncTypeWiFi", IDS_NETWORK_TYPE_WIFI},
       {"OncTypeWiMAX", IDS_NETWORK_TYPE_WIMAX},
-      {"networkDisabled", IDS_SETTINGS_DEVICE_OFF},
       {"networkListItemConnected", IDS_STATUSBAR_NETWORK_DEVICE_CONNECTED},
       {"networkListItemConnecting", IDS_STATUSBAR_NETWORK_DEVICE_CONNECTING},
       {"networkListItemConnectingTo", IDS_NETWORK_LIST_CONNECTING_TO},
diff --git a/chrome/browser/ui/webui/md_downloads/downloads_list_tracker.cc b/chrome/browser/ui/webui/md_downloads/downloads_list_tracker.cc
index b85f1535..46a17b7 100644
--- a/chrome/browser/ui/webui/md_downloads/downloads_list_tracker.cc
+++ b/chrome/browser/ui/webui/md_downloads/downloads_list_tracker.cc
@@ -336,13 +336,12 @@
 }
 
 bool DownloadsListTracker::ShouldShow(const DownloadItem& item) const {
-  return !download_crx_util::IsExtensionDownload(item) &&
-      !item.IsTemporary() &&
-      !item.GetFileNameToReportUser().empty() &&
-      !item.GetTargetFilePath().empty() &&
-      !item.GetURL().is_empty() &&
-      DownloadItemModel(const_cast<DownloadItem*>(&item)).ShouldShowInShelf() &&
-      DownloadQuery::MatchesQuery(search_terms_, item);
+  return !download_crx_util::IsExtensionDownload(item) && !item.IsTemporary() &&
+         !item.IsTransient() && !item.GetFileNameToReportUser().empty() &&
+         !item.GetTargetFilePath().empty() && !item.GetURL().is_empty() &&
+         DownloadItemModel(const_cast<DownloadItem*>(&item))
+             .ShouldShowInShelf() &&
+         DownloadQuery::MatchesQuery(search_terms_, item);
 }
 
 bool DownloadsListTracker::StartTimeComparator::operator() (
diff --git a/chrome/browser/ui/webui/md_downloads/downloads_list_tracker_unittest.cc b/chrome/browser/ui/webui/md_downloads/downloads_list_tracker_unittest.cc
index 8e026382..a2bad3f 100644
--- a/chrome/browser/ui/webui/md_downloads/downloads_list_tracker_unittest.cc
+++ b/chrome/browser/ui/webui/md_downloads/downloads_list_tracker_unittest.cc
@@ -113,6 +113,7 @@
 
     ON_CALL(*new_item, GetId()).WillByDefault(Return(id));
     ON_CALL(*new_item, GetStartTime()).WillByDefault(Return(started));
+    ON_CALL(*new_item, IsTransient()).WillByDefault(Return(false));
 
     return new_item;
   }
@@ -355,3 +356,14 @@
   tracker()->OnDownloadUpdated(manager(), unsent_item);
   EXPECT_EQ(1u, web_ui()->call_data().size());
 }
+
+TEST_F(DownloadsListTrackerTest, IgnoreTransientDownloads) {
+  MockDownloadItem* transient_item = CreateNextItem();
+  ON_CALL(*transient_item, IsTransient()).WillByDefault(Return(true));
+
+  CreateTracker();
+  tracker()->StartAndSendChunk();
+
+  ASSERT_FALSE(web_ui()->call_data().empty());
+  EXPECT_EQ(0u, GetIds(*web_ui()->call_data()[0]->arg2()).size());
+}
diff --git a/chrome/browser/ui/webui/md_downloads/md_downloads_dom_handler_unittest.cc b/chrome/browser/ui/webui/md_downloads/md_downloads_dom_handler_unittest.cc
index 11bc7946..947dfe8 100644
--- a/chrome/browser/ui/webui/md_downloads/md_downloads_dom_handler_unittest.cc
+++ b/chrome/browser/ui/webui/md_downloads/md_downloads_dom_handler_unittest.cc
@@ -94,6 +94,7 @@
   // Safe, in-progress items should be passed over.
   testing::StrictMock<content::MockDownloadItem> in_progress;
   EXPECT_CALL(in_progress, IsDangerous()).WillOnce(testing::Return(false));
+  EXPECT_CALL(in_progress, IsTransient()).WillOnce(testing::Return(false));
   EXPECT_CALL(in_progress, GetState()).WillOnce(
       testing::Return(content::DownloadItem::IN_PROGRESS));
   downloads.push_back(&in_progress);
@@ -107,6 +108,7 @@
   // Completed items should be marked as hidden from the shelf.
   testing::StrictMock<content::MockDownloadItem> completed;
   EXPECT_CALL(completed, IsDangerous()).WillOnce(testing::Return(false));
+  EXPECT_CALL(completed, IsTransient()).WillRepeatedly(testing::Return(false));
   EXPECT_CALL(completed, GetState()).WillOnce(
       testing::Return(content::DownloadItem::COMPLETE));
   EXPECT_CALL(completed, GetId()).WillOnce(testing::Return(1));
diff --git a/chrome/common/chrome_switches.cc b/chrome/common/chrome_switches.cc
index 3bf58d9..3981bb5e 100644
--- a/chrome/common/chrome_switches.cc
+++ b/chrome/common/chrome_switches.cc
@@ -1146,6 +1146,16 @@
 extern const char kEnableInputImeAPI[] = "enable-input-ime-api";
 #endif
 
+#if defined(OS_CHROMEOS) || defined(OS_LINUX) || defined(OS_MACOSX) || \
+    defined(OS_WIN)
+extern const char kAppMenuIcon[] = "app-menu-icon";
+extern const char kAppMenuIconOldBehavior[] = "old-behavior";
+extern const char kAppMenuIconPersistentOpenedState[] =
+    "persistent-opened-state";
+extern const char kAppMenuIconPersistentClosedState[] =
+    "persistent-closed-state";
+#endif
+
 bool ExtensionsDisabled(const base::CommandLine& command_line) {
   return command_line.HasSwitch(switches::kDisableExtensions) ||
          command_line.HasSwitch(switches::kDisableExtensionsExcept);
diff --git a/chrome/common/chrome_switches.h b/chrome/common/chrome_switches.h
index 4f08189a..45b40b78 100644
--- a/chrome/common/chrome_switches.h
+++ b/chrome/common/chrome_switches.h
@@ -356,6 +356,14 @@
 extern const char kEnableInputImeAPI[];
 #endif
 
+#if defined(OS_CHROMEOS) || defined(OS_LINUX) || defined(OS_MACOSX) || \
+    defined(OS_WIN)
+extern const char kAppMenuIcon[];
+extern const char kAppMenuIconOldBehavior[];
+extern const char kAppMenuIconPersistentOpenedState[];
+extern const char kAppMenuIconPersistentClosedState[];
+#endif
+
 bool ExtensionsDisabled(const base::CommandLine& command_line);
 bool MdFeedbackEnabled();
 bool MdPolicyPageEnabled();
diff --git a/chrome/common/extensions/api/_api_features.json b/chrome/common/extensions/api/_api_features.json
index 7df3a10..ddbfe97 100644
--- a/chrome/common/extensions/api/_api_features.json
+++ b/chrome/common/extensions/api/_api_features.json
@@ -46,42 +46,6 @@
     // Any webpage can use the app API.
     "matches": ["<all_urls>"]
   },
-  "app.getDetails": {
-    "contexts": [
-      "blessed_extension",
-      "unblessed_extension",
-      "content_script",
-      "blessed_web_page",
-      "web_page"
-    ]
-  },
-  "app.getIsInstalled": {
-    "contexts": [
-      "blessed_extension",
-      "unblessed_extension",
-      "content_script",
-      "blessed_web_page",
-      "web_page"
-    ]
-  },
-  "app.installState": {
-    "contexts": [
-      "blessed_extension",
-      "unblessed_extension",
-      "content_script",
-      "blessed_web_page",
-      "web_page"
-    ]
-  },
-  "app.runningState": {
-    "contexts": [
-      "blessed_extension",
-      "unblessed_extension",
-      "content_script",
-      "blessed_web_page",
-      "web_page"
-    ]
-  },
   "appviewTag": {
     "internal": true,
     "dependencies": ["permission:appview"],
diff --git a/chrome/common/media/media_resource_provider.cc b/chrome/common/media/media_resource_provider.cc
index 61bd6be9..de872e1 100644
--- a/chrome/common/media/media_resource_provider.cc
+++ b/chrome/common/media/media_resource_provider.cc
@@ -24,12 +24,6 @@
     case media::BEAMFORMING_OFF_DEFAULT_AUDIO_INPUT_DEVICE_NAME:
       return IDS_BEAMFORMING_OFF_DEFAULT_AUDIO_INPUT_DEVICE_NAME;
 #endif
-#if BUILDFLAG(ENABLE_MEDIA_REMOTING)
-    case media::MEDIA_REMOTING_CAST_ERROR_TEXT:
-      return IDS_MEDIA_REMOTING_CAST_ERROR_TEXT;
-    case media::MEDIA_REMOTING_CASTING_VIDEO_TEXT:
-      return IDS_MEDIA_REMOTING_CASTING_VIDEO_TEXT;
-#endif
     default:
       NOTREACHED();
       return 0;
diff --git a/chrome/test/data/webui/settings/internet_page_tests.js b/chrome/test/data/webui/settings/internet_page_tests.js
index b4c35d5..70edfae 100644
--- a/chrome/test/data/webui/settings/internet_page_tests.js
+++ b/chrome/test/data/webui/settings/internet_page_tests.js
@@ -31,7 +31,6 @@
       OncTypeVPN: 'OncTypeVPN',
       OncTypeWiFi: 'OncTypeWiFi',
       OncTypeWiMAX: 'OncTypeWiMAX',
-      networkDisabled: 'networkDisabled',
       networkListItemConnected: 'networkListItemConnected',
       networkListItemConnecting: 'networkListItemConnecting',
       networkListItemConnectingTo: 'networkListItemConnectingTo',
diff --git a/chromecast/graphics/cast_focus_client_aura.cc b/chromecast/graphics/cast_focus_client_aura.cc
index 45e891d..49afd14 100644
--- a/chromecast/graphics/cast_focus_client_aura.cc
+++ b/chromecast/graphics/cast_focus_client_aura.cc
@@ -233,7 +233,7 @@
 
 void CastFocusClientAura::DeactivateWindow(aura::Window* window) {}
 
-aura::Window* CastFocusClientAura::GetActiveWindow() {
+const aura::Window* CastFocusClientAura::GetActiveWindow() const {
   return nullptr;
 }
 
diff --git a/chromecast/graphics/cast_focus_client_aura.h b/chromecast/graphics/cast_focus_client_aura.h
index f9d9796..72e00cf 100644
--- a/chromecast/graphics/cast_focus_client_aura.h
+++ b/chromecast/graphics/cast_focus_client_aura.h
@@ -40,7 +40,7 @@
       aura::client::ActivationChangeObserver* observer) override;
   void ActivateWindow(aura::Window* window) override;
   void DeactivateWindow(aura::Window* window) override;
-  aura::Window* GetActiveWindow() override;
+  const aura::Window* GetActiveWindow() const override;
   aura::Window* GetActivatableWindow(aura::Window* window) override;
   aura::Window* GetToplevelWindow(aura::Window* window) override;
   bool CanActivateWindow(aura::Window* window) const override;
diff --git a/components/domain_reliability/uploader_unittest.cc b/components/domain_reliability/uploader_unittest.cc
index 0b99fc0..ae037e9 100644
--- a/components/domain_reliability/uploader_unittest.cc
+++ b/components/domain_reliability/uploader_unittest.cc
@@ -33,7 +33,6 @@
 
 struct MockUploadResult {
   int net_error;
-  int response_code;
   scoped_refptr<net::HttpResponseHeaders> response_headers;
 };
 
@@ -95,10 +94,6 @@
       NotifyStartError(net::URLRequestStatus::FromError(result_.net_error));
   }
 
-  int GetResponseCode() const override {
-    return result_.response_code;
-  }
-
   void GetResponseInfo(net::HttpResponseInfo* info) override {
     info->headers = result_.response_headers;
   }
@@ -135,23 +130,12 @@
   void ExpectRequestAndReturnError(int net_error) {
     MockUploadResult result;
     result.net_error = net_error;
-    result.response_code = -1;
     results_.push_back(result);
   }
 
-  void ExpectRequestAndReturnResponseCode(int response_code) {
+  void ExpectRequestAndReturnResponseHeaders(const char* headers) {
     MockUploadResult result;
     result.net_error = net::OK;
-    result.response_code = response_code;
-    results_.push_back(result);
-  }
-
-  void ExpectRequestAndReturnResponseCodeAndHeaders(
-      int response_code,
-      const char* headers) {
-    MockUploadResult result;
-    result.net_error = net::OK;
-    result.response_code = response_code;
     result.response_headers = new net::HttpResponseHeaders(
         net::HttpUtil::AssembleRawHeaders(headers, strlen(headers)));
     results_.push_back(result);
@@ -226,7 +210,7 @@
 }
 
 TEST_F(DomainReliabilityUploaderTest, SuccessfulUpload) {
-  interceptor()->ExpectRequestAndReturnResponseCode(200);
+  interceptor()->ExpectRequestAndReturnResponseHeaders("HTTP/1.1 200\r\n\r\n");
 
   TestUploadCallback c;
   uploader()->UploadReport("{}", 0, GURL(kUploadURL), c.callback());
@@ -250,7 +234,7 @@
 }
 
 TEST_F(DomainReliabilityUploaderTest, ServerErrorUpload) {
-  interceptor()->ExpectRequestAndReturnResponseCode(500);
+  interceptor()->ExpectRequestAndReturnResponseHeaders("HTTP/1.1 500\r\n\r\n");
 
   TestUploadCallback c;
   uploader()->UploadReport("{}", 0, GURL(kUploadURL), c.callback());
@@ -262,8 +246,7 @@
 }
 
 TEST_F(DomainReliabilityUploaderTest, RetryAfterUpload) {
-  interceptor()->ExpectRequestAndReturnResponseCodeAndHeaders(
-      503,
+  interceptor()->ExpectRequestAndReturnResponseHeaders(
       "HTTP/1.1 503 Ugh\nRetry-After: 3600\n\n");
 
   TestUploadCallback c;
@@ -276,7 +259,7 @@
 }
 
 TEST_F(DomainReliabilityUploaderTest, UploadDepth1) {
-  interceptor()->ExpectRequestAndReturnResponseCode(200);
+  interceptor()->ExpectRequestAndReturnResponseHeaders("HTTP/1.1 200\r\n\r\n");
 
   TestUploadCallback c;
   uploader()->UploadReport("{}", 0, GURL(kUploadURL), c.callback());
@@ -289,7 +272,7 @@
 }
 
 TEST_F(DomainReliabilityUploaderTest, UploadDepth2) {
-  interceptor()->ExpectRequestAndReturnResponseCode(200);
+  interceptor()->ExpectRequestAndReturnResponseHeaders("HTTP/1.1 200\r\n\r\n");
 
   TestUploadCallback c;
   uploader()->UploadReport("{}", 1, GURL(kUploadURL), c.callback());
diff --git a/content/browser/background_fetch/background_fetch_context.cc b/content/browser/background_fetch/background_fetch_context.cc
index f27666e..c4496e14 100644
--- a/content/browser/background_fetch/background_fetch_context.cc
+++ b/content/browser/background_fetch/background_fetch_context.cc
@@ -171,28 +171,33 @@
       controller->registration_id();
 
   DCHECK_GT(active_fetches_.count(registration_id), 0u);
-
-  // TODO(peter): Fire `backgroundfetchabort` if the |controller|'s state is
-  // ABORTED, which does not require a sequence of the settled fetches.
-
-  // The `backgroundfetched` and/or `backgroundfetchfail` event will only be
-  // invoked for Background Fetch jobs which have been completed.
-  if (controller->state() != BackgroundFetchJobController::State::COMPLETED) {
-    DeleteRegistration(registration_id,
-                       std::vector<std::unique_ptr<BlobHandle>>());
-    return;
+  switch (controller->state()) {
+    case BackgroundFetchJobController::State::ABORTED:
+      event_dispatcher_->DispatchBackgroundFetchAbortEvent(
+          registration_id,
+          base::Bind(&BackgroundFetchContext::DeleteRegistration, this,
+                     registration_id,
+                     std::vector<std::unique_ptr<BlobHandle>>()));
+      return;
+    case BackgroundFetchJobController::State::COMPLETED:
+      data_manager_->GetSettledFetchesForRegistration(
+          registration_id,
+          base::BindOnce(&BackgroundFetchContext::DidGetSettledFetches, this,
+                         registration_id));
+      return;
+    case BackgroundFetchJobController::State::INITIALIZED:
+    case BackgroundFetchJobController::State::FETCHING:
+      // These cases should not happen. Fall through to the NOTREACHED() below.
+      break;
   }
 
-  // Get the sequence of settled fetches from the data manager.
-  data_manager_->GetSettledFetchesForRegistration(
-      registration_id,
-      base::BindOnce(&BackgroundFetchContext::DidGetSettledFetches, this,
-                     registration_id));
+  NOTREACHED();
 }
 
 void BackgroundFetchContext::DidGetSettledFetches(
     const BackgroundFetchRegistrationId& registration_id,
     blink::mojom::BackgroundFetchError error,
+    bool background_fetch_succeeded,
     std::vector<BackgroundFetchSettledFetch> settled_fetches,
     std::vector<std::unique_ptr<BlobHandle>> blob_handles) {
   if (error != blink::mojom::BackgroundFetchError::NONE) {
@@ -200,14 +205,20 @@
     return;
   }
 
-  // TODO(peter): Distinguish between the `backgroundfetched` and
-  // `backgroundfetchfail` events based on the status code of all fetches. We
-  // don't populate that field yet, so always assume it's successful for now.
-
-  event_dispatcher_->DispatchBackgroundFetchedEvent(
-      registration_id, std::move(settled_fetches),
-      base::Bind(&BackgroundFetchContext::DeleteRegistration, this,
-                 registration_id, std::move(blob_handles)));
+  // The `backgroundfetched` event will be invoked when all requests in the
+  // registration have completed successfully. In all other cases, the
+  // `backgroundfetchfail` event will be invoked instead.
+  if (background_fetch_succeeded) {
+    event_dispatcher_->DispatchBackgroundFetchedEvent(
+        registration_id, std::move(settled_fetches),
+        base::Bind(&BackgroundFetchContext::DeleteRegistration, this,
+                   registration_id, std::move(blob_handles)));
+  } else {
+    event_dispatcher_->DispatchBackgroundFetchFailEvent(
+        registration_id, std::move(settled_fetches),
+        base::Bind(&BackgroundFetchContext::DeleteRegistration, this,
+                   registration_id, std::move(blob_handles)));
+  }
 }
 
 void BackgroundFetchContext::DeleteRegistration(
diff --git a/content/browser/background_fetch/background_fetch_context.h b/content/browser/background_fetch/background_fetch_context.h
index 66df7e1..1dc154c7 100644
--- a/content/browser/background_fetch/background_fetch_context.h
+++ b/content/browser/background_fetch/background_fetch_context.h
@@ -113,6 +113,7 @@
   void DidGetSettledFetches(
       const BackgroundFetchRegistrationId& registration_id,
       blink::mojom::BackgroundFetchError error,
+      bool background_fetch_succeeded,
       std::vector<BackgroundFetchSettledFetch> settled_fetches,
       std::vector<std::unique_ptr<BlobHandle>> blob_handles);
 
diff --git a/content/browser/background_fetch/background_fetch_data_manager.cc b/content/browser/background_fetch/background_fetch_data_manager.cc
index 83e7509..2fcb85e 100644
--- a/content/browser/background_fetch/background_fetch_data_manager.cc
+++ b/content/browser/background_fetch/background_fetch_data_manager.cc
@@ -21,6 +21,14 @@
 
 namespace content {
 
+// Returns whether the response contained in the Background Fetch |request| is
+// considered OK. See https://fetch.spec.whatwg.org/#ok-status aka a successful
+// 2xx status per https://tools.ietf.org/html/rfc7231#section-6.3.
+bool IsOK(const BackgroundFetchRequestInfo& request) {
+  int status = request.GetResponseCode();
+  return status >= 200 && status < 300;
+}
+
 // The Registration Data class encapsulates the data stored for a particular
 // Background Fetch registration. This roughly matches the on-disk format that
 // will be adhered to in the future.
@@ -198,6 +206,8 @@
   const std::vector<scoped_refptr<BackgroundFetchRequestInfo>>& requests =
       registration_data->GetCompletedRequests();
 
+  bool background_fetch_succeeded = true;
+
   std::vector<BackgroundFetchSettledFetch> settled_fetches;
   settled_fetches.reserve(requests.size());
 
@@ -238,16 +248,23 @@
           blob_handles.push_back(std::move(blob_handle));
         }
       }
+    } else {
+      // TODO(crbug.com/711354): Consider Background Fetches as failed when the
+      // response cannot be relayed to the developer.
+      background_fetch_succeeded = false;
     }
 
     // TODO: settled_fetch.response.error
     settled_fetch.response.response_time = request->GetResponseTime();
     // TODO: settled_fetch.response.cors_exposed_header_names
 
+    background_fetch_succeeded = background_fetch_succeeded && IsOK(*request);
+
     settled_fetches.push_back(settled_fetch);
   }
 
   std::move(callback).Run(blink::mojom::BackgroundFetchError::NONE,
+                          background_fetch_succeeded,
                           std::move(settled_fetches), std::move(blob_handles));
 }
 
diff --git a/content/browser/background_fetch/background_fetch_data_manager.h b/content/browser/background_fetch/background_fetch_data_manager.h
index 0e9acd65..60b39ff 100644
--- a/content/browser/background_fetch/background_fetch_data_manager.h
+++ b/content/browser/background_fetch/background_fetch_data_manager.h
@@ -41,6 +41,7 @@
       base::OnceCallback<void(scoped_refptr<BackgroundFetchRequestInfo>)>;
   using SettledFetchesCallback =
       base::OnceCallback<void(blink::mojom::BackgroundFetchError,
+                              bool /* background_fetch_succeeded */,
                               std::vector<BackgroundFetchSettledFetch>,
                               std::vector<std::unique_ptr<BlobHandle>>)>;
 
diff --git a/content/browser/background_fetch/background_fetch_job_controller.cc b/content/browser/background_fetch/background_fetch_job_controller.cc
index 36a6fa3..e4dd6471 100644
--- a/content/browser/background_fetch/background_fetch_job_controller.cc
+++ b/content/browser/background_fetch/background_fetch_job_controller.cc
@@ -59,6 +59,7 @@
     // TODO(peter): The |download_parameters| should be populated with all the
     // properties set in the |fetch_request| structure.
 
+    download_parameters->set_transient(true);
     download_parameters->set_callback(base::Bind(&Core::DidStartRequest,
                                                  weak_ptr_factory_.GetWeakPtr(),
                                                  std::move(request)));
diff --git a/content/browser/background_fetch/background_fetch_service_unittest.cc b/content/browser/background_fetch/background_fetch_service_unittest.cc
index db41111..cbdc87ed 100644
--- a/content/browser/background_fetch/background_fetch_service_unittest.cc
+++ b/content/browser/background_fetch/background_fetch_service_unittest.cc
@@ -333,6 +333,7 @@
 
   constexpr int kFirstResponseCode = 200;
   constexpr int kSecondResponseCode = 201;
+  constexpr int kThirdResponseCode = 200;
 
   requests.push_back(CreateRequestWithProvidedResponse(
       "GET", "https://example.com/funny_cat.txt",
@@ -351,6 +352,14 @@
           .AddResponseHeader("Content-Type", "text/plain")
           .Build()));
 
+  requests.push_back(CreateRequestWithProvidedResponse(
+      "GET", "https://chrome.com/accessible_cross_origin_cat.txt",
+      TestResponseBuilder(kThirdResponseCode)
+          .SetResponseData("This cat originates from another origin.")
+          .AddResponseHeader("Access-Control-Allow-Origin", "*")
+          .AddResponseHeader("Content-Type", "text/plain")
+          .Build()));
+
   // Create the registration with the given |requests|.
   {
     BackgroundFetchOptions options;
@@ -395,6 +404,11 @@
         EXPECT_EQ(fetches[i].response.headers.count("Content-Type"), 1u);
         EXPECT_EQ(fetches[i].response.headers.count("X-Cat"), 0u);
         break;
+      case 2:
+        EXPECT_EQ(fetches[i].response.status_code, kThirdResponseCode);
+        EXPECT_EQ(fetches[i].response.headers.count("Content-Type"), 1u);
+        EXPECT_EQ(fetches[i].response.headers.count("X-Cat"), 0u);
+        break;
       default:
         NOTREACHED();
     }
@@ -413,6 +427,92 @@
   }
 }
 
+TEST_F(BackgroundFetchServiceTest, FetchFailEventDispatch) {
+  // This test verifies that the fail event will be fired when a response either
+  // has a non-OK status code, or the response cannot be accessed due to CORS.
+
+  BackgroundFetchRegistrationId registration_id;
+  ASSERT_TRUE(CreateRegistrationId(kExampleTag, &registration_id));
+
+  // base::RunLoop that we'll run until the event has been dispatched. If this
+  // test times out, it means that the event could not be dispatched.
+  base::RunLoop event_dispatched_loop;
+  embedded_worker_test_helper()->set_fetch_fail_event_closure(
+      event_dispatched_loop.QuitClosure());
+
+  std::vector<ServiceWorkerFetchRequest> requests;
+
+  constexpr int kFirstResponseCode = 404;
+  constexpr int kSecondResponseCode = 200;
+
+  requests.push_back(CreateRequestWithProvidedResponse(
+      "GET", "https://example.com/not_existing_cat.txt",
+      TestResponseBuilder(kFirstResponseCode).Build()));
+
+  requests.push_back(CreateRequestWithProvidedResponse(
+      "GET", "https://chrome.com/inaccessible_cross_origin_cat.txt",
+      TestResponseBuilder(kSecondResponseCode)
+          .SetResponseData(
+              "This is a cross-origin response not accessible to the reader.")
+          .AddResponseHeader("Content-Type", "text/plain")
+          .Build()));
+
+  // Create the registration with the given |requests|.
+  {
+    BackgroundFetchOptions options;
+
+    blink::mojom::BackgroundFetchError error;
+    BackgroundFetchRegistration registration;
+
+    // Create the first registration. This must succeed.
+    ASSERT_NO_FATAL_FAILURE(
+        Fetch(registration_id, requests, options, &error, &registration));
+    ASSERT_EQ(error, blink::mojom::BackgroundFetchError::NONE);
+  }
+
+  // Spin the |event_dispatched_loop| to wait for the dispatched event.
+  event_dispatched_loop.Run();
+
+  ASSERT_TRUE(embedded_worker_test_helper()->last_tag().has_value());
+  EXPECT_EQ(kExampleTag, embedded_worker_test_helper()->last_tag().value());
+
+  ASSERT_TRUE(embedded_worker_test_helper()->last_fetches().has_value());
+
+  std::vector<BackgroundFetchSettledFetch> fetches =
+      embedded_worker_test_helper()->last_fetches().value();
+  ASSERT_EQ(fetches.size(), requests.size());
+
+  for (size_t i = 0; i < fetches.size(); ++i) {
+    ASSERT_EQ(fetches[i].request.url, requests[i].url);
+    EXPECT_EQ(fetches[i].request.method, requests[i].method);
+
+    EXPECT_EQ(fetches[i].response.url_list[0], fetches[i].request.url);
+    EXPECT_EQ(fetches[i].response.response_type,
+              blink::kWebServiceWorkerResponseTypeDefault);
+
+    switch (i) {
+      case 0:
+        EXPECT_EQ(fetches[i].response.status_code, 404);
+        break;
+      case 1:
+        EXPECT_EQ(fetches[i].response.status_code, 0);
+        break;
+      default:
+        NOTREACHED();
+    }
+
+    EXPECT_TRUE(fetches[i].response.headers.empty());
+    EXPECT_TRUE(fetches[i].response.blob_uuid.empty());
+    EXPECT_EQ(fetches[i].response.blob_size, 0u);
+    EXPECT_FALSE(fetches[i].response.response_time.is_null());
+
+    // TODO(peter): change-detector tests for unsupported properties.
+    EXPECT_EQ(fetches[i].response.error,
+              blink::kWebServiceWorkerResponseErrorUnknown);
+    EXPECT_TRUE(fetches[i].response.cors_exposed_header_names.empty());
+  }
+}
+
 TEST_F(BackgroundFetchServiceTest, Abort) {
   // This test starts a new Background Fetch, completes the registration, and
   // then aborts the Background Fetch mid-process. Tests all of StartFetch(),
@@ -477,6 +577,56 @@
   ASSERT_EQ(error, blink::mojom::BackgroundFetchError::INVALID_TAG);
 }
 
+TEST_F(BackgroundFetchServiceTest, AbortEventDispatch) {
+  // Tests that the `backgroundfetchabort` event will be fired when a Background
+  // Fetch registration has been aborted by either the user or developer.
+
+  BackgroundFetchRegistrationId registration_id;
+  ASSERT_TRUE(CreateRegistrationId(kExampleTag, &registration_id));
+
+  // base::RunLoop that we'll run until the event has been dispatched. If this
+  // test times out, it means that the event could not be dispatched.
+  base::RunLoop event_dispatched_loop;
+  embedded_worker_test_helper()->set_abort_event_closure(
+      event_dispatched_loop.QuitClosure());
+
+  constexpr int kResponseCode = 200;
+
+  std::vector<ServiceWorkerFetchRequest> requests;
+  requests.push_back(CreateRequestWithProvidedResponse(
+      "GET", "https://example.com/funny_cat.txt",
+      TestResponseBuilder(kResponseCode)
+          .SetResponseData("Random data about a funny cat.")
+          .Build()));
+
+  // Create the registration with the given |requests|.
+  {
+    BackgroundFetchOptions options;
+
+    blink::mojom::BackgroundFetchError error;
+    BackgroundFetchRegistration registration;
+
+    // Create the first registration. This must succeed.
+    ASSERT_NO_FATAL_FAILURE(
+        Fetch(registration_id, requests, options, &error, &registration));
+    ASSERT_EQ(error, blink::mojom::BackgroundFetchError::NONE);
+  }
+
+  // Immediately abort the request created for the |registration_id|. Then wait
+  // for the `backgroundfetchabort` event to have been invoked.
+  {
+    blink::mojom::BackgroundFetchError error;
+
+    ASSERT_NO_FATAL_FAILURE(Abort(registration_id, &error));
+    ASSERT_EQ(error, blink::mojom::BackgroundFetchError::NONE);
+  }
+
+  event_dispatched_loop.Run();
+
+  ASSERT_TRUE(embedded_worker_test_helper()->last_tag().has_value());
+  EXPECT_EQ(kExampleTag, embedded_worker_test_helper()->last_tag().value());
+}
+
 TEST_F(BackgroundFetchServiceTest, GetTags) {
   // This test verifies that the list of active tags can be retrieved from the
   // service for a given Service Worker, as extracted from a registration.
diff --git a/content/browser/download/download_browsertest.cc b/content/browser/download/download_browsertest.cc
index 38ad2db6..be7caf06 100644
--- a/content/browser/download/download_browsertest.cc
+++ b/content/browser/download/download_browsertest.cc
@@ -323,10 +323,12 @@
 
   void Initialize(
       const InitializeCallback& callback,
+      const CancelRequestCallback& cancel_request_callback,
       const DownloadItem::ReceivedSlices& received_slices) override {
     DCHECK_CURRENTLY_ON(BrowserThread::FILE);
     active_files_++;
-    DownloadFileImpl::Initialize(callback, received_slices);
+    DownloadFileImpl::Initialize(callback, cancel_request_callback,
+                                 received_slices);
   }
 
   static void GetNumberActiveFiles(int* result) {
diff --git a/content/browser/download/download_file.h b/content/browser/download/download_file.h
index 224121a..bfbaaa5a 100644
--- a/content/browser/download/download_file.h
+++ b/content/browser/download/download_file.h
@@ -42,13 +42,18 @@
                               const base::FilePath& path)>
       RenameCompletionCallback;
 
+  // Used to drop the request, when the byte stream reader should be closed on
+  // FILE thread.
+  typedef base::Callback<void(int64_t offset)> CancelRequestCallback;
+
   virtual ~DownloadFile() {}
 
-  // Upon completion, |callback| will be called on the UI
+  // Upon completion, |initialize_callback| will be called on the UI
   // thread as per the comment above, passing DOWNLOAD_INTERRUPT_REASON_NONE
   // on success, or a network download interrupt reason on failure.
   virtual void Initialize(
-      const InitializeCallback& callback,
+      const InitializeCallback& initialize_callback,
+      const CancelRequestCallback& cancel_request_callback,
       const DownloadItem::ReceivedSlices& received_slices) = 0;
 
   // Add a byte stream reader to write into a slice of the file, used for
diff --git a/content/browser/download/download_file_impl.cc b/content/browser/download/download_file_impl.cc
index f65534b2..8e69416 100644
--- a/content/browser/download/download_file_impl.cc
+++ b/content/browser/download/download_file_impl.cc
@@ -128,12 +128,14 @@
 }
 
 void DownloadFileImpl::Initialize(
-    const InitializeCallback& callback,
+    const InitializeCallback& initialize_callback,
+    const CancelRequestCallback& cancel_request_callback,
     const DownloadItem::ReceivedSlices& received_slices) {
   DCHECK_CURRENTLY_ON(BrowserThread::FILE);
 
   update_timer_.reset(new base::RepeatingTimer());
   int64_t bytes_so_far = 0;
+  cancel_request_callback_ = cancel_request_callback;
   received_slices_ = received_slices;
   if (IsSparseFile()) {
     for (const auto& received_slice : received_slices_) {
@@ -148,8 +150,8 @@
       save_info_->hash_of_partial_file, std::move(save_info_->hash_state),
       IsSparseFile());
   if (result != DOWNLOAD_INTERRUPT_REASON_NONE) {
-    BrowserThread::PostTask(
-        BrowserThread::UI, FROM_HERE, base::Bind(callback, result));
+    BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
+                            base::Bind(initialize_callback, result));
     return;
   }
 
@@ -160,8 +162,8 @@
   SendUpdate();
 
   BrowserThread::PostTask(
-      BrowserThread::UI, FROM_HERE, base::Bind(
-          callback, DOWNLOAD_INTERRUPT_REASON_NONE));
+      BrowserThread::UI, FROM_HERE,
+      base::Bind(initialize_callback, DOWNLOAD_INTERRUPT_REASON_NONE));
 
   // Initial pull from the straw from all source streams.
   for (auto& source_stream : source_streams_)
@@ -328,6 +330,8 @@
     SendUpdate();
 
     // Null out callback so that we don't do any more stream processing.
+    // The request that writes to the pipe should be canceled after
+    // the download being interrupted.
     for (auto& stream : source_streams_) {
       ByteStreamReader* stream_reader = stream.second->stream_reader();
       if (stream_reader)
@@ -469,6 +473,8 @@
     // Signal successful completion or termination of the current stream.
     source_stream->stream_reader()->RegisterCallback(base::Closure());
     source_stream->set_finished(true);
+    if (should_terminate)
+      CancelRequestOnUIThread(source_stream->offset());
     if (source_stream->length() == DownloadSaveInfo::kLengthFullContent) {
       SetPotentialFileLength(source_stream->offset() +
                              source_stream->bytes_written());
@@ -641,6 +647,7 @@
           DCHECK_EQ(stream.second->bytes_written(), 0);
           stream.second->stream_reader()->RegisterCallback(base::Closure());
           stream.second->set_finished(true);
+          CancelRequestOnUIThread(stream.second->offset());
           num_active_streams_--;
         }
       }
@@ -680,6 +687,13 @@
   return ret;
 }
 
+void DownloadFileImpl::CancelRequestOnUIThread(int64_t offset) {
+  if (!cancel_request_callback_.is_null()) {
+    BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
+                            base::Bind(cancel_request_callback_, offset));
+  }
+}
+
 void DownloadFileImpl::DebugStates() const {
   DVLOG(1) << "### Debugging DownloadFile states:";
   DVLOG(1) << "Total source stream count = " << source_streams_.size();
diff --git a/content/browser/download/download_file_impl.h b/content/browser/download/download_file_impl.h
index b3ce7d9..664b713 100644
--- a/content/browser/download/download_file_impl.h
+++ b/content/browser/download/download_file_impl.h
@@ -53,7 +53,8 @@
   ~DownloadFileImpl() override;
 
   // DownloadFile functions.
-  void Initialize(const InitializeCallback& callback,
+  void Initialize(const InitializeCallback& initialize_callback,
+                  const CancelRequestCallback& cancel_request_callback,
                   const DownloadItem::ReceivedSlices& received_slices) override;
 
   void AddByteStream(std::unique_ptr<ByteStreamReader> stream_reader,
@@ -114,7 +115,6 @@
     ByteStreamReader* stream_reader() const { return stream_reader_.get(); }
     int64_t offset() const { return offset_; }
     int64_t length() const { return length_; }
-    void set_length(int64_t length) { length_ = length; }
     int64_t bytes_written() const { return bytes_written_; }
     bool is_finished() const { return finished_; }
     void set_finished(bool finish) { finished_ = finish; }
@@ -229,6 +229,9 @@
   // SourceStreams are ordered by their offsets
   SourceStream* FindPrecedingNeighbor(SourceStream* source_stream);
 
+  // See |cancel_request_callback_|.
+  void CancelRequestOnUIThread(int64_t offset);
+
   // Print the internal states for debugging.
   void DebugStates() const;
 
@@ -249,6 +252,10 @@
   // starting from offset.
   SourceStreams source_streams_;
 
+  // Used to cancel the request on UI thread, since the ByteStreamReader can't
+  // close the underlying resource writing to the pipe.
+  CancelRequestCallback cancel_request_callback_;
+
   // Used to trigger progress updates.
   std::unique_ptr<base::RepeatingTimer> update_timer_;
 
diff --git a/content/browser/download/download_file_unittest.cc b/content/browser/download/download_file_unittest.cc
index 4bc430e2..7de9f3d 100644
--- a/content/browser/download/download_file_unittest.cc
+++ b/content/browser/download/download_file_unittest.cc
@@ -243,7 +243,7 @@
         base::Bind(&DownloadFileTest::SetInterruptReasonCallback,
                    weak_ptr_factory.GetWeakPtr(), loop_runner.QuitClosure(),
                    &result),
-        received_slices);
+        DownloadFile::CancelRequestCallback(), received_slices);
     loop_runner.Run();
 
     ::testing::Mock::VerifyAndClearExpectations(input_stream_);
diff --git a/content/browser/download/download_item_impl.cc b/content/browser/download/download_item_impl.cc
index 1dab653e..6c9d1f3 100644
--- a/content/browser/download/download_item_impl.cc
+++ b/content/browser/download/download_item_impl.cc
@@ -1061,6 +1061,12 @@
   // notified when the download transitions to the IN_PROGRESS state.
 }
 
+void DownloadItemImpl::CancelRequestWithOffset(int64_t offset) {
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  if (job_)
+    job_->CancelRequestWithOffset(offset);
+}
+
 void DownloadItemImpl::NotifyRemoved() {
   for (auto& observer : observers_)
     observer.OnDownloadRemoved(this);
@@ -1313,6 +1319,8 @@
                  base::Unretained(download_file_.get()),
                  base::Bind(&DownloadItemImpl::OnDownloadFileInitialized,
                             weak_ptr_factory_.GetWeakPtr()),
+                 base::Bind(&DownloadItemImpl::CancelRequestWithOffset,
+                            weak_ptr_factory_.GetWeakPtr()),
                  received_slices_));
 }
 
diff --git a/content/browser/download/download_item_impl.h b/content/browser/download/download_item_impl.h
index 9b4fe74..4a6e319 100644
--- a/content/browser/download/download_item_impl.h
+++ b/content/browser/download/download_item_impl.h
@@ -507,6 +507,9 @@
   virtual void UpdateValidatorsOnResumption(
       const DownloadCreateInfo& new_create_info);
 
+  // Cancel a particular request that starts from |offset|.
+  void CancelRequestWithOffset(int64_t offset);
+
   static DownloadState InternalToExternalState(
       DownloadInternalState internal_state);
   static DownloadInternalState ExternalToInternalState(
diff --git a/content/browser/download/download_item_impl_unittest.cc b/content/browser/download/download_item_impl_unittest.cc
index 6c97c2f..6553d0d 100644
--- a/content/browser/download/download_item_impl_unittest.cc
+++ b/content/browser/download/download_item_impl_unittest.cc
@@ -310,7 +310,7 @@
     if (create_info_->result == DOWNLOAD_INTERRUPT_REASON_NONE) {
       mock_download_file = new StrictMock<MockDownloadFile>;
       download_file.reset(mock_download_file);
-      EXPECT_CALL(*mock_download_file, Initialize(_, _))
+      EXPECT_CALL(*mock_download_file, Initialize(_, _, _))
           .WillOnce(ScheduleCallbackWithParam(DOWNLOAD_INTERRUPT_REASON_NONE));
       EXPECT_CALL(*mock_download_file, FullPath())
           .WillRepeatedly(ReturnRefOfCopy(base::FilePath()));
@@ -602,7 +602,7 @@
   std::unique_ptr<DownloadRequestHandleInterface> request_handle(
       new NiceMock<MockRequestHandle>);
 
-  EXPECT_CALL(*mock_download_file, Initialize(_, _));
+  EXPECT_CALL(*mock_download_file, Initialize(_, _, _));
   EXPECT_CALL(*mock_delegate(), DetermineDownloadTarget(_, _));
   item->Start(std::move(download_file), std::move(request_handle),
               *create_info());
@@ -1069,7 +1069,7 @@
   MockDownloadFile* mock_download_file(new MockDownloadFile);
   std::unique_ptr<DownloadFile> download_file(mock_download_file);
   DownloadItemImpl* item = CreateDownloadItem();
-  EXPECT_CALL(*mock_download_file, Initialize(_, _));
+  EXPECT_CALL(*mock_download_file, Initialize(_, _, _));
   std::unique_ptr<DownloadRequestHandleInterface> request_handle(
       new NiceMock<MockRequestHandle>);
   EXPECT_CALL(*mock_delegate(), DetermineDownloadTarget(item, _));
@@ -1090,7 +1090,7 @@
 
   EXPECT_CALL(*file, Cancel());
   EXPECT_CALL(*request_handle, CancelRequest());
-  EXPECT_CALL(*file, Initialize(_, _))
+  EXPECT_CALL(*file, Initialize(_, _, _))
       .WillOnce(ScheduleCallbackWithParam(
           DOWNLOAD_INTERRUPT_REASON_FILE_ACCESS_DENIED));
 
@@ -2127,7 +2127,7 @@
 
   base::RunLoop download_start_loop;
   DownloadFile::InitializeCallback initialize_callback;
-  EXPECT_CALL(*file_, Initialize(_, _))
+  EXPECT_CALL(*file_, Initialize(_, _, _))
       .WillOnce(DoAll(SaveArg<0>(&initialize_callback),
                       ScheduleClosure(download_start_loop.QuitClosure())));
   item_->Start(std::move(file_), std::move(request_handle_), *create_info());
@@ -2180,7 +2180,7 @@
 
   base::RunLoop download_start_loop;
   DownloadFile::InitializeCallback initialize_callback;
-  EXPECT_CALL(*file_, Initialize(_, _))
+  EXPECT_CALL(*file_, Initialize(_, _, _))
       .WillOnce(DoAll(SaveArg<0>(&initialize_callback),
                       ScheduleClosure(download_start_loop.QuitClosure())));
 
@@ -2250,7 +2250,7 @@
 
   base::RunLoop download_start_loop;
   DownloadFile::InitializeCallback initialize_callback;
-  EXPECT_CALL(*file_, Initialize(_, _))
+  EXPECT_CALL(*file_, Initialize(_, _, _))
       .WillOnce(DoAll(SaveArg<0>(&initialize_callback),
                       ScheduleClosure(download_start_loop.QuitClosure())));
 
diff --git a/content/browser/download/download_job.cc b/content/browser/download/download_job.cc
index 763e8ed..1e3f3f58 100644
--- a/content/browser/download/download_job.cc
+++ b/content/browser/download/download_job.cc
@@ -66,4 +66,6 @@
   return false;
 }
 
+void DownloadJob::CancelRequestWithOffset(int64_t offset) {}
+
 }  // namespace content
diff --git a/content/browser/download/download_job.h b/content/browser/download/download_job.h
index d4db0ec..0998cea 100644
--- a/content/browser/download/download_job.h
+++ b/content/browser/download/download_job.h
@@ -43,6 +43,10 @@
   // Returns whether the download uses parallel requests.
   virtual bool UsesParallelRequests() const;
 
+  // Cancel a particular request starts from |offset|, while the download is not
+  // canceled. Used in parallel download.
+  virtual void CancelRequestWithOffset(int64_t offset);
+
  protected:
   void StartDownload() const;
   void Interrupt(DownloadInterruptReason reason);
diff --git a/content/browser/download/mock_download_file.cc b/content/browser/download/mock_download_file.cc
index 36282d51..180ea1b9 100644
--- a/content/browser/download/mock_download_file.cc
+++ b/content/browser/download/mock_download_file.cc
@@ -11,9 +11,11 @@
 namespace content {
 namespace {
 
-void SuccessRun(const DownloadFile::InitializeCallback& callback,
-                const DownloadItem::ReceivedSlices& received_slices) {
-  callback.Run(DOWNLOAD_INTERRUPT_REASON_NONE);
+void SuccessRun(
+    const DownloadFile::InitializeCallback& initialize_callback,
+    const DownloadFile::CancelRequestCallback& cancel_request_callback,
+    const DownloadItem::ReceivedSlices& received_slices) {
+  initialize_callback.Run(DOWNLOAD_INTERRUPT_REASON_NONE);
 }
 
 }  // namespace
@@ -21,7 +23,8 @@
 MockDownloadFile::MockDownloadFile() {
   // This is here because |Initialize()| is normally called right after
   // construction.
-  ON_CALL(*this, Initialize(_, _)).WillByDefault(::testing::Invoke(SuccessRun));
+  ON_CALL(*this, Initialize(_, _, _))
+      .WillByDefault(::testing::Invoke(SuccessRun));
 }
 
 MockDownloadFile::~MockDownloadFile() {
diff --git a/content/browser/download/mock_download_file.h b/content/browser/download/mock_download_file.h
index 81d3b260..738eee6 100644
--- a/content/browser/download/mock_download_file.h
+++ b/content/browser/download/mock_download_file.h
@@ -28,8 +28,9 @@
   virtual ~MockDownloadFile();
 
   // DownloadFile functions.
-  MOCK_METHOD2(Initialize,
+  MOCK_METHOD3(Initialize,
                void(const InitializeCallback&,
+                    const CancelRequestCallback&,
                     const DownloadItem::ReceivedSlices& received_slices));
   void AddByteStream(std::unique_ptr<ByteStreamReader> stream_reader,
                      int64_t offset,
diff --git a/content/browser/download/parallel_download_job.cc b/content/browser/download/parallel_download_job.cc
index 5a3af37..539f29be 100644
--- a/content/browser/download/parallel_download_job.cc
+++ b/content/browser/download/parallel_download_job.cc
@@ -97,6 +97,17 @@
   return true;
 }
 
+void ParallelDownloadJob::CancelRequestWithOffset(int64_t offset) {
+  if (initial_request_offset_ == offset) {
+    DownloadJobImpl::Cancel(false);
+    return;
+  }
+
+  auto it = workers_.find(offset);
+  if (it != workers_.end())
+    it->second->Cancel();
+}
+
 void ParallelDownloadJob::BuildParallelRequestAfterDelay() {
   DCHECK(workers_.empty());
   DCHECK(!requests_sent_);
diff --git a/content/browser/download/parallel_download_job.h b/content/browser/download/parallel_download_job.h
index 6ade0aeb..0a3d0fe 100644
--- a/content/browser/download/parallel_download_job.h
+++ b/content/browser/download/parallel_download_job.h
@@ -35,6 +35,7 @@
   void Pause() override;
   void Resume(bool resume_request) override;
   bool UsesParallelRequests() const override;
+  void CancelRequestWithOffset(int64_t offset) override;
 
  protected:
   // Virtual for testing.
diff --git a/content/browser/gpu/gpu_data_manager_testing_autogen.cc b/content/browser/gpu/gpu_data_manager_testing_autogen.cc
index b27901b..2680c7e 100644
--- a/content/browser/gpu/gpu_data_manager_testing_autogen.cc
+++ b/content/browser/gpu/gpu_data_manager_testing_autogen.cc
@@ -17,8 +17,7 @@
 
 const char kGpuDataManagerTestingVersion[] = "1.0";
 
-const size_t kGpuDataManagerTestingEntryCount = 10;
-const GpuControlList::Entry kGpuDataManagerTestingEntries[10] = {
+const GpuControlList::Entry kGpuDataManagerTestingEntries[] = {
     {
         1,  // id
         "GpuDataManagerImplPrivateTest.GpuSideBlacklisting.0",
@@ -280,4 +279,5 @@
         nullptr,  // exceptions
     },
 };
+const size_t kGpuDataManagerTestingEntryCount = 10;
 }  // namespace gpu
diff --git a/content/browser/renderer_host/input/passthrough_touch_event_queue.cc b/content/browser/renderer_host/input/passthrough_touch_event_queue.cc
index f7883a3..a13ccbf5 100644
--- a/content/browser/renderer_host/input/passthrough_touch_event_queue.cc
+++ b/content/browser/renderer_host/input/passthrough_touch_event_queue.cc
@@ -24,6 +24,10 @@
 namespace content {
 namespace {
 
+// A sanity check on touches received to ensure that touch movement outside
+// the platform slop region will cause scrolling.
+const double kMaxConceivablePlatformSlopRegionLengthDipsSquared = 60. * 60.;
+
 // Compare all properties of touch points to determine the state.
 bool HasPointChanged(const WebTouchPoint& point_1,
                      const WebTouchPoint& point_2) {
@@ -42,6 +46,59 @@
 
 }  // namespace
 
+// Provides touchmove slop suppression for a touch sequence until a
+// (unprevented) touch will trigger immediate scrolling.
+class TouchMoveSlopSuppressor {
+ public:
+  TouchMoveSlopSuppressor() : suppressing_touchmoves_(false) {}
+
+  bool FilterEvent(const WebTouchEvent& event) {
+    if (WebTouchEventTraits::IsTouchSequenceStart(event)) {
+      suppressing_touchmoves_ = true;
+      touch_start_location_ = gfx::PointF(event.touches[0].position);
+    }
+
+    if (event.GetType() == WebInputEvent::kTouchEnd ||
+        event.GetType() == WebInputEvent::kTouchCancel)
+      suppressing_touchmoves_ = false;
+
+    if (event.GetType() != WebInputEvent::kTouchMove)
+      return false;
+
+    if (suppressing_touchmoves_) {
+      if (event.touches_length > 1) {
+        suppressing_touchmoves_ = false;
+      } else if (event.moved_beyond_slop_region) {
+        suppressing_touchmoves_ = false;
+      } else {
+        // No sane slop region should be larger than 60 DIPs.
+        DCHECK_LT(
+            (gfx::PointF(event.touches[0].position) - touch_start_location_)
+                .LengthSquared(),
+            kMaxConceivablePlatformSlopRegionLengthDipsSquared);
+      }
+    }
+
+    return suppressing_touchmoves_;
+  }
+
+  void ConfirmTouchEvent(InputEventAckState ack_result) {
+    if (ack_result == INPUT_EVENT_ACK_STATE_CONSUMED)
+      suppressing_touchmoves_ = false;
+  }
+
+  bool suppressing_touchmoves() const { return suppressing_touchmoves_; }
+
+ private:
+  bool suppressing_touchmoves_;
+
+  // Sanity check that the upstream touch provider is properly reporting whether
+  // the touch sequence will cause scrolling.
+  gfx::PointF touch_start_location_;
+
+  DISALLOW_COPY_AND_ASSIGN(TouchMoveSlopSuppressor);
+};
+
 PassthroughTouchEventQueue::TouchEventWithLatencyInfoAndAckState::
     TouchEventWithLatencyInfoAndAckState(const TouchEventWithLatencyInfo& event)
     : TouchEventWithLatencyInfo(event),
@@ -59,6 +116,7 @@
       has_handlers_(true),
       maybe_has_handler_for_current_sequence_(false),
       drop_remaining_touches_in_sequence_(false),
+      touchmove_slop_suppressor_(new TouchMoveSlopSuppressor),
       send_touch_events_async_(false) {
   if (config.touch_ack_timeout_supported) {
     timeout_handler_.reset(
@@ -120,6 +178,8 @@
       timeout_handler_->ConfirmTouchEvent(unique_touch_event_id, ack_result))
     return;
 
+  touchmove_slop_suppressor_->ConfirmTouchEvent(ack_result);
+
   auto touch_event_iter = outstanding_touches_.begin();
   while (touch_event_iter != outstanding_touches_.end()) {
     if (unique_touch_event_id == touch_event_iter->event.unique_touch_event_id)
@@ -297,6 +357,9 @@
   if (timeout_handler_ && timeout_handler_->FilterEvent(event))
     return ACK_WITH_NO_CONSUMER_EXISTS;
 
+  if (touchmove_slop_suppressor_->FilterEvent(event))
+    return ACK_WITH_NOT_CONSUMED;
+
   if (drop_remaining_touches_in_sequence_ &&
       event.GetType() != WebInputEvent::kTouchCancel) {
     return ACK_WITH_NO_CONSUMER_EXISTS;
diff --git a/content/browser/renderer_host/input/passthrough_touch_event_queue.h b/content/browser/renderer_host/input/passthrough_touch_event_queue.h
index 598e9b8..561d0c20 100644
--- a/content/browser/renderer_host/input/passthrough_touch_event_queue.h
+++ b/content/browser/renderer_host/input/passthrough_touch_event_queue.h
@@ -12,6 +12,7 @@
 namespace content {
 
 class TouchTimeoutHandler;
+class TouchMoveSlopSuppressor;
 
 // A queue that processes a touch-event and forwards it on to the
 // renderer process immediately. This class assumes that queueing will
@@ -115,6 +116,10 @@
   // cancelled after a touch timeout.
   bool drop_remaining_touches_in_sequence_;
 
+  // Suppresses TouchMove's within a slop region when a sequence has not yet
+  // been preventDefaulted.
+  std::unique_ptr<TouchMoveSlopSuppressor> touchmove_slop_suppressor_;
+
   // Optional handler for timed-out touch event acks.
   std::unique_ptr<TouchTimeoutHandler> timeout_handler_;
 
diff --git a/content/browser/renderer_host/input/passthrough_touch_event_queue_unittest.cc b/content/browser/renderer_host/input/passthrough_touch_event_queue_unittest.cc
index 3d91716..833f0ab5 100644
--- a/content/browser/renderer_host/input/passthrough_touch_event_queue_unittest.cc
+++ b/content/browser/renderer_host/input/passthrough_touch_event_queue_unittest.cc
@@ -1250,37 +1250,32 @@
 
   // TouchMove's movedBeyondSlopRegion within the slop region is set to false.
   MoveTouchPoint(0, 0, kHalfSlopLengthDips);
-  EXPECT_EQ(1U, queued_event_count());
-  SendTouchEventAck(INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
-  EXPECT_EQ(1U, GetAndResetSentEventCount());
+  EXPECT_EQ(0U, queued_event_count());
+  EXPECT_EQ(0U, GetAndResetSentEventCount());
   EXPECT_EQ(1U, GetAndResetAckedEventCount());
   EXPECT_FALSE(acked_event().moved_beyond_slop_region);
 
   MoveTouchPoint(0, kHalfSlopLengthDips, 0);
-  EXPECT_EQ(1U, queued_event_count());
-  SendTouchEventAck(INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
-  EXPECT_EQ(1U, GetAndResetSentEventCount());
+  EXPECT_EQ(0U, queued_event_count());
+  EXPECT_EQ(0U, GetAndResetSentEventCount());
   EXPECT_EQ(1U, GetAndResetAckedEventCount());
   EXPECT_FALSE(acked_event().moved_beyond_slop_region);
 
   MoveTouchPoint(0, -kHalfSlopLengthDips, 0);
-  EXPECT_EQ(1U, queued_event_count());
-  SendTouchEventAck(INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
-  EXPECT_EQ(1U, GetAndResetSentEventCount());
+  EXPECT_EQ(0U, queued_event_count());
+  EXPECT_EQ(0U, GetAndResetSentEventCount());
   EXPECT_EQ(1U, GetAndResetAckedEventCount());
   EXPECT_FALSE(acked_event().moved_beyond_slop_region);
 
   MoveTouchPoint(0, -kSlopLengthDips, 0);
-  EXPECT_EQ(1U, queued_event_count());
-  SendTouchEventAck(INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
-  EXPECT_EQ(1U, GetAndResetSentEventCount());
+  EXPECT_EQ(0U, queued_event_count());
+  EXPECT_EQ(0U, GetAndResetSentEventCount());
   EXPECT_EQ(1U, GetAndResetAckedEventCount());
   EXPECT_FALSE(acked_event().moved_beyond_slop_region);
 
   MoveTouchPoint(0, 0, kSlopLengthDips);
-  EXPECT_EQ(1U, queued_event_count());
-  SendTouchEventAck(INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
-  EXPECT_EQ(1U, GetAndResetSentEventCount());
+  EXPECT_EQ(0U, queued_event_count());
+  EXPECT_EQ(0U, GetAndResetSentEventCount());
   EXPECT_EQ(1U, GetAndResetAckedEventCount());
   EXPECT_FALSE(acked_event().moved_beyond_slop_region);
 
@@ -1295,7 +1290,6 @@
   EXPECT_EQ(0U, GetAndResetAckedEventCount());
   SendTouchEventAck(INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
   EXPECT_EQ(1U, GetAndResetAckedEventCount());
-  EXPECT_TRUE(acked_event().moved_beyond_slop_region);
 }
 
 // Tests that even very small TouchMove's movedBeyondSlopRegion is set to true
diff --git a/content/browser/renderer_host/offscreen_canvas_provider_impl.cc b/content/browser/renderer_host/offscreen_canvas_provider_impl.cc
index 9d578ada..25915f91 100644
--- a/content/browser/renderer_host/offscreen_canvas_provider_impl.cc
+++ b/content/browser/renderer_host/offscreen_canvas_provider_impl.cc
@@ -10,7 +10,9 @@
 
 namespace content {
 
-OffscreenCanvasProviderImpl::OffscreenCanvasProviderImpl() = default;
+OffscreenCanvasProviderImpl::OffscreenCanvasProviderImpl(
+    uint32_t renderer_client_id)
+    : renderer_client_id_(renderer_client_id) {}
 
 OffscreenCanvasProviderImpl::~OffscreenCanvasProviderImpl() = default;
 
@@ -24,6 +26,16 @@
     const cc::FrameSinkId& frame_sink_id,
     cc::mojom::FrameSinkManagerClientPtr client,
     blink::mojom::OffscreenCanvasSurfaceRequest request) {
+  // TODO(kylechar): Kill the renderer too.
+  if (parent_frame_sink_id.client_id() != renderer_client_id_) {
+    DLOG(ERROR) << "Invalid parent client id " << parent_frame_sink_id;
+    return;
+  }
+  if (frame_sink_id.client_id() != renderer_client_id_) {
+    DLOG(ERROR) << "Invalid client id " << frame_sink_id;
+    return;
+  }
+
   OffscreenCanvasSurfaceImpl::Create(parent_frame_sink_id, frame_sink_id,
                                      std::move(client), std::move(request));
 }
@@ -32,6 +44,12 @@
     const cc::FrameSinkId& frame_sink_id,
     cc::mojom::MojoCompositorFrameSinkClientPtr client,
     cc::mojom::MojoCompositorFrameSinkRequest request) {
+  // TODO(kylechar): Kill the renderer too.
+  if (frame_sink_id.client_id() != renderer_client_id_) {
+    DLOG(ERROR) << "Invalid client id " << frame_sink_id;
+    return;
+  }
+
   // TODO(kylechar): Add test for bad |frame_sink_id|.
   auto* manager = OffscreenCanvasCompositorFrameSinkManager::GetInstance();
   auto* surface_impl = manager->GetSurfaceInstance(frame_sink_id);
diff --git a/content/browser/renderer_host/offscreen_canvas_provider_impl.h b/content/browser/renderer_host/offscreen_canvas_provider_impl.h
index be2c52c..251dc450 100644
--- a/content/browser/renderer_host/offscreen_canvas_provider_impl.h
+++ b/content/browser/renderer_host/offscreen_canvas_provider_impl.h
@@ -15,7 +15,7 @@
 class OffscreenCanvasProviderImpl
     : public blink::mojom::OffscreenCanvasProvider {
  public:
-  OffscreenCanvasProviderImpl();
+  explicit OffscreenCanvasProviderImpl(uint32_t renderer_client_id);
   ~OffscreenCanvasProviderImpl() override;
 
   void Add(blink::mojom::OffscreenCanvasProviderRequest request);
@@ -32,6 +32,9 @@
       cc::mojom::MojoCompositorFrameSinkRequest request) override;
 
  private:
+  // FrameSinkIds for offscreen canvas must use the renderer client id.
+  const uint32_t renderer_client_id_;
+
   mojo::BindingSet<blink::mojom::OffscreenCanvasProvider> bindings_;
 
   DISALLOW_COPY_AND_ASSIGN(OffscreenCanvasProviderImpl);
diff --git a/content/browser/renderer_host/render_process_host_impl.cc b/content/browser/renderer_host/render_process_host_impl.cc
index 9986ff6..e779da3 100644
--- a/content/browser/renderer_host/render_process_host_impl.cc
+++ b/content/browser/renderer_host/render_process_host_impl.cc
@@ -1363,8 +1363,10 @@
     blink::mojom::OffscreenCanvasProviderRequest request) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   if (!offscreen_canvas_provider_) {
+    // The client id gets converted to a uint32_t in FrameSinkId.
+    uint32_t renderer_client_id = base::checked_cast<uint32_t>(id_);
     offscreen_canvas_provider_ =
-        base::MakeUnique<OffscreenCanvasProviderImpl>();
+        base::MakeUnique<OffscreenCanvasProviderImpl>(renderer_client_id);
   }
   offscreen_canvas_provider_->Add(std::move(request));
 }
diff --git a/content/browser/renderer_host/render_widget_host_view_aura_unittest.cc b/content/browser/renderer_host/render_widget_host_view_aura_unittest.cc
index ce0f2d4..2924fb2 100644
--- a/content/browser/renderer_host/render_widget_host_view_aura_unittest.cc
+++ b/content/browser/renderer_host/render_widget_host_view_aura_unittest.cc
@@ -1692,7 +1692,7 @@
   EXPECT_TRUE(press.synchronous_handling_disabled());
   EXPECT_EQ(ui::MotionEvent::ACTION_DOWN, pointer_state().GetAction());
   EXPECT_EQ(1U, pointer_state().GetPointerCount());
-  EXPECT_EQ(3U, GetSentMessageCountAndResetSink());
+  EXPECT_EQ(2U, GetSentMessageCountAndResetSink());
 
   widget_host_->OnMessageReceived(ViewHostMsg_HasTouchEventHandlers(0, false));
 
diff --git a/content/browser/utility_process_host_impl.cc b/content/browser/utility_process_host_impl.cc
index 4c5b066..4cb3c3d 100644
--- a/content/browser/utility_process_host_impl.cc
+++ b/content/browser/utility_process_host_impl.cc
@@ -314,8 +314,13 @@
     // Browser command-line switches to propagate to the utility process.
     static const char* const kSwitchNames[] = {
       switches::kEnableNetworkService,
+      switches::kHostResolverRules,
+      switches::kIgnoreCertificateErrors,
+      switches::kLogNetLog,
       switches::kNoSandbox,
       switches::kProfilerTiming,
+      switches::kTestingFixedHttpPort,
+      switches::kTestingFixedHttpsPort,
 #if defined(OS_MACOSX)
       switches::kEnableSandboxLogging,
 #endif
diff --git a/content/network/DEPS b/content/network/DEPS
index 61742f9..c5ce9ee 100644
--- a/content/network/DEPS
+++ b/content/network/DEPS
@@ -7,6 +7,7 @@
   "+content/common/url_loader_factory.mojom.h",
   "+content/network",
   "+content/public/common/content_client.h",
+  "+content/public/common/content_switches.h",
   "+content/public/common/referrer.h",
   "+content/public/common/resource_response.h",
   "+services/service_manager/public",
diff --git a/content/network/network_context.cc b/content/network/network_context.cc
index fcca28c..040a678 100644
--- a/content/network/network_context.cc
+++ b/content/network/network_context.cc
@@ -7,8 +7,10 @@
 #include "base/command_line.h"
 #include "base/logging.h"
 #include "base/memory/ptr_util.h"
+#include "base/strings/string_number_conversions.h"
 #include "content/network/url_loader_impl.h"
 #include "content/public/common/content_client.h"
+#include "content/public/common/content_switches.h"
 #include "net/dns/host_resolver.h"
 #include "net/dns/mapped_host_resolver.h"
 #include "net/log/net_log_util.h"
@@ -21,31 +23,37 @@
 namespace content {
 
 namespace {
-// Logs network information to the specified file.
-const char kLogNetLog[] = "log-net-log";
-
-// Applies the specified mapping rules when resolving hosts. Please see the
-// comment of net::MappedHostResolver::AddRulesFromString() for rule format.
-const char kHostResolverRules[] = "host-resolver-rules";
-
-// Ignores certificate-related errors.
-const char kIgnoreCertificateErrors[] = "ignore-certificate-errors";
 
 std::unique_ptr<net::URLRequestContext> MakeURLRequestContext() {
   net::URLRequestContextBuilder builder;
   net::URLRequestContextBuilder::HttpNetworkSessionParams params;
   const base::CommandLine* command_line =
       base::CommandLine::ForCurrentProcess();
-  if (command_line->HasSwitch(kIgnoreCertificateErrors))
+  if (command_line->HasSwitch(switches::kIgnoreCertificateErrors))
     params.ignore_certificate_errors = true;
+
+  if (command_line->HasSwitch(switches::kTestingFixedHttpPort)) {
+    int value;
+    base::StringToInt(
+        command_line->GetSwitchValueASCII(switches::kTestingFixedHttpPort),
+        &value);
+    params.testing_fixed_http_port = value;
+  }
+  if (command_line->HasSwitch(switches::kTestingFixedHttpsPort)) {
+    int value;
+    base::StringToInt(
+        command_line->GetSwitchValueASCII(switches::kTestingFixedHttpsPort),
+        &value);
+    params.testing_fixed_https_port = value;
+  }
   builder.set_http_network_session_params(params);
-  if (command_line->HasSwitch(kHostResolverRules)) {
+  if (command_line->HasSwitch(switches::kHostResolverRules)) {
     std::unique_ptr<net::HostResolver> host_resolver(
         net::HostResolver::CreateDefaultResolver(nullptr));
     std::unique_ptr<net::MappedHostResolver> remapped_host_resolver(
         new net::MappedHostResolver(std::move(host_resolver)));
     remapped_host_resolver->SetRulesFromString(
-        command_line->GetSwitchValueASCII(kHostResolverRules));
+        command_line->GetSwitchValueASCII(switches::kHostResolverRules));
     builder.set_host_resolver(std::move(remapped_host_resolver));
   }
   builder.set_accept_language("en-us,en");
@@ -74,9 +82,10 @@
   MojoNetLog() {
     const base::CommandLine* command_line =
         base::CommandLine::ForCurrentProcess();
-    if (!command_line->HasSwitch(kLogNetLog))
+    if (!command_line->HasSwitch(switches::kLogNetLog))
       return;
-    base::FilePath log_path = command_line->GetSwitchValuePath(kLogNetLog);
+    base::FilePath log_path =
+        command_line->GetSwitchValuePath(switches::kLogNetLog);
     base::ScopedFILE file;
 #if defined(OS_WIN)
     file.reset(_wfopen(log_path.value().c_str(), L"w"));
diff --git a/content/public/common/services.md b/content/public/common/services.md
new file mode 100644
index 0000000..d467950
--- /dev/null
+++ b/content/public/common/services.md
@@ -0,0 +1,65 @@
+# Services in Content
+
+The //content layer implements the core process model for Chrome, including
+major process types: `browser`, `renderer`, `gpu`, `utility`, `plugin`. From the
+perspective of the service manager, each process type is a service, and each
+process instance is an instantiation of that service. For a renderer process,
+its `service_manager::Identity` is constructed as follows:
+
+```
+name: content_renderer
+userid: <guid, from BrowserContext that spawned this renderer>
+instance: <string, generated from the RenderProcesHost's ID>
+```
+
+These services express the set of capabilities they expose to one another using
+service manifests (see [Service Manager README](https://chromium.googlesource.com/chromium/src/+/master/services/service_manager/README.md)). For //content, the service manifests live in
+`//content/public/app/mojo`. 
+
+Every `content::BrowserContext` has a user id generated for it upon
+construction, and the services run with that BrowserContext use that user id as
+part of their instance identity. Where there are multiple instances of the same
+service for the same user, the instance field in the Identity disambiguates
+them.
+
+Launching code for each process type is currently ad-hoc & specific per type,
+and lives in `//content/browser`. In the medium-long term, we'll work to
+generalize this and move it all into the service manager. 
+Each content process type is launched by host code in `//content/browser`,
+though eventually all process launching will be moved to the service manager.
+
+The canonical service for each process type is represented by an implementation
+of the `service_manager::Service` interface which lives on the IO thread. This
+implementation is shared, and is a detail of `content::ServiceManagerConnection`
+which you will find in `//content/public/common`. This implementation receives
+the `OnStart()` and `OnBindInterface()` calls from the service manager.
+
+The rest of this document talks about things you might like to do and how to
+accomplish them.
+
+### Expose Mojo interfaces from one of the existing content-provided services.
+
+To expose interfaces at the service-level from one of the existing content-
+provided services, you will need to add a `content::ConnectionFilter` to the
+`content::ServiceManagerConnection` in the relevant process. See
+`//content/public/common/connection_filter.h`. You implement this interface to
+handle `OnBindInterface()` requests on the IO thread. You can construct a
+`service_manager::BinderRegistry` on any other thread and move it to the IO
+thread using `//content/public/common/connection_filter_impl.h`. When you add
+bind callbacks to the binder registry you can specify what task runner you
+would like incoming interface requests to be bound on.
+
+### Expose Mojo interfaces at the frame level between browser & renderer.
+
+You can add bind callbacks to the `service_manager::InterfaceRegistry` owned by
+the `RenderFrame` and the `RenderFrameHost`. See the various content client
+interfaces also for signals to embedders allowing them to add additional
+interfaces.
+
+### Expose a named service from an existing process.
+
+If you want to expose a named service (i.e. a service other than the ones
+provided by content) from a process provided by content, you can "embed" a
+service in one of the content-provided services. You do this by calling
+`AddEmbeddedService()` on `ServiceManagerConnection`.
+
diff --git a/content/public/test/test_file_error_injector.cc b/content/public/test/test_file_error_injector.cc
index 867d1a0..b635121 100644
--- a/content/public/test/test_file_error_injector.cc
+++ b/content/public/test/test_file_error_injector.cc
@@ -42,7 +42,8 @@
 
   ~DownloadFileWithError() override;
 
-  void Initialize(const InitializeCallback& callback,
+  void Initialize(const InitializeCallback& initialize_callback,
+                  const CancelRequestCallback& cancel_request_callback,
                   const DownloadItem::ReceivedSlices& received_slices) override;
 
   // DownloadFile interface.
@@ -133,10 +134,11 @@
 }
 
 void DownloadFileWithError::Initialize(
-    const InitializeCallback& callback,
+    const InitializeCallback& initialize_callback,
+    const CancelRequestCallback& cancel_request_callback,
     const DownloadItem::ReceivedSlices& received_slices) {
   DownloadInterruptReason error_to_return = DOWNLOAD_INTERRUPT_REASON_NONE;
-  InitializeCallback callback_to_use = callback;
+  InitializeCallback callback_to_use = initialize_callback;
 
   // Replace callback if the error needs to be overwritten.
   if (OverwriteError(
@@ -145,18 +147,18 @@
     if (DOWNLOAD_INTERRUPT_REASON_NONE != error_to_return) {
       // Don't execute a, probably successful, Initialize; just
       // return the error.
-      BrowserThread::PostTask(
-          BrowserThread::UI, FROM_HERE, base::Bind(
-              callback, error_to_return));
+      BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
+                              base::Bind(initialize_callback, error_to_return));
       return;
     }
 
     // Otherwise, just wrap the return.
-    callback_to_use = base::Bind(&InitializeErrorCallback, callback,
+    callback_to_use = base::Bind(&InitializeErrorCallback, initialize_callback,
                                  error_to_return);
   }
 
-  DownloadFileImpl::Initialize(callback_to_use, received_slices);
+  DownloadFileImpl::Initialize(callback_to_use, cancel_request_callback,
+                               received_slices);
 }
 
 DownloadInterruptReason DownloadFileWithError::WriteDataToFile(
diff --git a/content/renderer/media/media_stream_video_source.cc b/content/renderer/media/media_stream_video_source.cc
index af0e7ca16..0425cd3c 100644
--- a/content/renderer/media/media_stream_video_source.cc
+++ b/content/renderer/media/media_stream_video_source.cc
@@ -651,7 +651,8 @@
       VideoTrackAdapter::CalculateTargetSize(
           current_format_.frame_size, gfx::Size(max_width, max_height),
           min_aspect_ratio, max_aspect_ratio, &desired_size);
-      track.track->SetTargetSize(desired_size.width(), desired_size.height());
+      track.track->SetTargetSizeAndFrameRate(
+          desired_size.width(), desired_size.height(), max_frame_rate);
     }
 
     DVLOG(3) << "FinalizeAddTrackLegacy() result " << result;
@@ -687,7 +688,9 @@
                     track.adapter_settings->max_height),
           track.adapter_settings->min_aspect_ratio,
           track.adapter_settings->max_aspect_ratio, &desired_size);
-      track.track->SetTargetSize(desired_size.width(), desired_size.height());
+      track.track->SetTargetSizeAndFrameRate(
+          desired_size.width(), desired_size.height(),
+          track.adapter_settings->max_frame_rate);
     }
 
     if (!track.callback.is_null())
diff --git a/content/renderer/media/media_stream_video_track.cc b/content/renderer/media/media_stream_video_track.cc
index d5d966d..1d92473c 100644
--- a/content/renderer/media/media_stream_video_track.cc
+++ b/content/renderer/media/media_stream_video_track.cc
@@ -391,18 +391,24 @@
 void MediaStreamVideoTrack::GetSettings(
     blink::WebMediaStreamTrack::Settings& settings) {
   DCHECK(main_render_thread_checker_.CalledOnValidThread());
+  if (!source_)
+    return;
+
   if (width_ && height_) {
     settings.width = width_;
     settings.height = height_;
   }
 
-  if (!source_)
-    return;
+  // 0.0 means the track is using the source's frame rate.
+  if (frame_rate_ != 0.0) {
+    settings.frame_rate = frame_rate_;
+  }
 
   base::Optional<media::VideoCaptureFormat> format =
       source_->GetCurrentFormat();
   if (format) {
-    settings.frame_rate = format->frame_rate;
+    if (frame_rate_ == 0.0)
+      settings.frame_rate = format->frame_rate;
     settings.video_kind = GetVideoKindForFormat(*format);
   }
   switch (source_->device_info().device.video_facing) {
diff --git a/content/renderer/media/media_stream_video_track.h b/content/renderer/media/media_stream_video_track.h
index a6e85e6..6668585 100644
--- a/content/renderer/media/media_stream_video_track.h
+++ b/content/renderer/media/media_stream_video_track.h
@@ -113,9 +113,10 @@
 
   // Setting information about the track size.
   // Called from MediaStreamVideoSource at track initialization.
-  void SetTargetSize(int width, int height) {
+  void SetTargetSizeAndFrameRate(int width, int height, double frame_rate) {
     width_ = width;
     height_ = height;
+    frame_rate_ = frame_rate;
   }
 
  private:
@@ -159,9 +160,10 @@
   // This is used for tracking if all connected video sinks are secure.
   SecureDisplayLinkTracker<MediaStreamVideoSink> secure_tracker_;
 
-  // Remembering our desired video size.
+  // Remembering our desired video size and frame rate.
   int width_ = 0;
   int height_ = 0;
+  double frame_rate_ = 0.0;
 
   DISALLOW_COPY_AND_ASSIGN(MediaStreamVideoTrack);
 };
diff --git a/content/renderer/media/media_stream_video_track_unittest.cc b/content/renderer/media/media_stream_video_track_unittest.cc
index 8d25d3c..2f497054 100644
--- a/content/renderer/media/media_stream_video_track_unittest.cc
+++ b/content/renderer/media/media_stream_video_track_unittest.cc
@@ -17,6 +17,7 @@
 #include "content/renderer/media/media_stream_video_track.h"
 #include "content/renderer/media/mock_media_stream_video_sink.h"
 #include "content/renderer/media/mock_media_stream_video_source.h"
+#include "content/renderer/media/video_track_adapter.h"
 #include "media/base/video_frame.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/WebKit/public/web/WebHeap.h"
@@ -95,6 +96,21 @@
     return track;
   }
 
+  // Create a track that's associated with |mock_source_| and has the given
+  // |adapter_settings|.
+  blink::WebMediaStreamTrack CreateTrackWithSettings(
+      const VideoTrackAdapterSettings& adapter_settings) {
+    const bool enabled = true;
+    blink::WebMediaStreamTrack track = MediaStreamVideoTrack::CreateVideoTrack(
+        mock_source_, adapter_settings, base::Optional<bool>(), false, 0.0,
+        MediaStreamSource::ConstraintsCallback(), enabled);
+    if (!source_started_) {
+      mock_source_->StartMockedSource();
+      source_started_ = true;
+    }
+    return track;
+  }
+
   void UpdateVideoSourceToRespondToRequestRefreshFrame() {
     blink_source_.Reset();
     mock_source_ = IsOldVideoConstraints()
@@ -296,6 +312,41 @@
             settings.facing_mode);
 }
 
+TEST_F(MediaStreamVideoTrackTest, GetSettingsWithAdjustment) {
+  InitializeSource();
+  const int kAdjustedWidth = 600;
+  const int kAdjustedHeight = 400;
+  const double kAdjustedFrameRate = 20.0;
+  VideoTrackAdapterSettings adapter_settings(kAdjustedWidth, kAdjustedHeight,
+                                             0.0, 10000.0, kAdjustedFrameRate);
+  blink::WebMediaStreamTrack track = CreateTrackWithSettings(adapter_settings);
+  MediaStreamVideoTrack* const native_track =
+      MediaStreamVideoTrack::GetVideoTrack(track);
+  blink::WebMediaStreamTrack::Settings settings;
+  native_track->GetSettings(settings);
+  EXPECT_EQ(kAdjustedWidth, settings.width);
+  EXPECT_EQ(kAdjustedHeight, settings.height);
+  EXPECT_EQ(kAdjustedFrameRate, settings.frame_rate);
+  EXPECT_EQ(blink::WebMediaStreamTrack::FacingMode::kNone,
+            settings.facing_mode);
+}
+
+TEST_F(MediaStreamVideoTrackTest, GetSettingsStopped) {
+  InitializeSource();
+  blink::WebMediaStreamTrack track = CreateTrack();
+  MediaStreamVideoTrack* const native_track =
+      MediaStreamVideoTrack::GetVideoTrack(track);
+  native_track->Stop();
+  blink::WebMediaStreamTrack::Settings settings;
+  native_track->GetSettings(settings);
+  EXPECT_EQ(-1, settings.width);
+  EXPECT_EQ(-1, settings.height);
+  EXPECT_EQ(-1, settings.frame_rate);
+  EXPECT_EQ(blink::WebMediaStreamTrack::FacingMode::kNone,
+            settings.facing_mode);
+  EXPECT_TRUE(settings.device_id.IsNull());
+}
+
 // TODO(guidou): Remove this test. http://crbug.com/706408
 class MediaStreamVideoTrackOldConstraintsTest : public ::testing::Test {
  public:
diff --git a/content/renderer/render_frame_impl.cc b/content/renderer/render_frame_impl.cc
index c3e311a..5991bde2 100644
--- a/content/renderer/render_frame_impl.cc
+++ b/content/renderer/render_frame_impl.cc
@@ -279,7 +279,6 @@
 #endif
 
 #if BUILDFLAG(ENABLE_MEDIA_REMOTING)
-#include "content/renderer/image_downloader/single_image_downloader.h"  // nogncheck
 #include "media/remoting/adaptive_renderer_factory.h"     // nogncheck
 #include "media/remoting/remoting_cdm_controller.h"       // nogncheck
 #include "media/remoting/remoting_cdm_factory.h"          // nogncheck
@@ -2947,7 +2946,6 @@
   }
 
 #if BUILDFLAG(ENABLE_MEDIA_REMOTING)
-  auto* const remoting_controller_ptr = remoting_controller.get();
   media_renderer_factory =
       base::MakeUnique<media::remoting::AdaptiveRendererFactory>(
           std::move(media_renderer_factory), std::move(remoting_controller));
@@ -2966,10 +2964,6 @@
   media_player->SetUseFallbackPath(use_fallback_path);
 #endif  // defined(OS_ANDROID)
 
-#if BUILDFLAG(ENABLE_MEDIA_REMOTING)
-  remoting_controller_ptr->SetDownloadPosterCallback(base::Bind(
-      &SingleImageDownloader::DownloadImage, weak_factory_.GetWeakPtr()));
-#endif
   return media_player;
 }
 
diff --git a/device/geolocation/network_location_provider.cc b/device/geolocation/network_location_provider.cc
index 52aec681..64bb9d92 100644
--- a/device/geolocation/network_location_provider.cc
+++ b/device/geolocation/network_location_provider.cc
@@ -117,40 +117,46 @@
       access_token_(access_token),
       is_permission_granted_(false),
       is_new_data_available_(false),
+      request_(new NetworkLocationRequest(
+          url_context_getter,
+          url,
+          base::Bind(&NetworkLocationProvider::OnLocationResponse,
+                     base::Unretained(this)))),
       position_cache_(new PositionCache),
       weak_factory_(this) {
-  request_.reset(new NetworkLocationRequest(
-      url_context_getter, url,
-      base::Bind(&NetworkLocationProvider::OnLocationResponse,
-                 base::Unretained(this))));
+  DLOG_IF(WARNING, !url.is_valid())
+      << __func__ << " Bad URL: " << url.possibly_invalid_spec();
 }
 
 NetworkLocationProvider::~NetworkLocationProvider() {
-  StopProvider();
-}
-
-// LocationProvider implementation
-const Geoposition& NetworkLocationProvider::GetPosition() {
-  return position_;
+  DCHECK(thread_checker_.CalledOnValidThread());
+  if (IsStarted())
+    StopProvider();
 }
 
 void NetworkLocationProvider::SetUpdateCallback(
     const LocationProvider::LocationProviderUpdateCallback& callback) {
+  DCHECK(thread_checker_.CalledOnValidThread());
   location_provider_update_callback_ = callback;
 }
 
 void NetworkLocationProvider::OnPermissionGranted() {
   const bool was_permission_granted = is_permission_granted_;
   is_permission_granted_ = true;
-  if (!was_permission_granted && IsStarted()) {
+  if (!was_permission_granted && IsStarted())
     RequestPosition();
-  }
 }
 
 void NetworkLocationProvider::OnWifiDataUpdate() {
-  DCHECK(wifi_data_provider_manager_);
+  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK(IsStarted());
   is_wifi_data_complete_ = wifi_data_provider_manager_->GetData(&wifi_data_);
-  OnWifiDataUpdated();
+  if (!is_wifi_data_complete_)
+    return;
+
+  wifi_timestamp_ = base::Time::Now();
+  is_new_data_available_ = true;
+  RequestPosition();
 }
 
 void NetworkLocationProvider::OnLocationResponse(
@@ -158,12 +164,11 @@
     bool server_error,
     const base::string16& access_token,
     const WifiData& wifi_data) {
-  DCHECK(CalledOnValidThread());
+  DCHECK(thread_checker_.CalledOnValidThread());
   // Record the position and update our cache.
   position_ = position;
-  if (position.Validate()) {
+  if (position.Validate())
     position_cache_->CachePosition(wifi_data, position);
-  }
 
   // Record access_token if it's set.
   if (!access_token.empty() && access_token_ != access_token) {
@@ -177,19 +182,14 @@
 }
 
 bool NetworkLocationProvider::StartProvider(bool high_accuracy) {
-  DCHECK(CalledOnValidThread());
+  DCHECK(thread_checker_.CalledOnValidThread());
   if (IsStarted())
     return true;
-  DCHECK(!wifi_data_provider_manager_);
-  if (!request_->url().is_valid()) {
-    LOG(WARNING) << "StartProvider() : Failed, Bad URL: "
-                 << request_->url().possibly_invalid_spec();
+  if (!request_->url().is_valid())
     return false;
-  }
 
-  // Registers a callback with the data provider. The first call to Register
-  // will create a singleton data provider and it will be deleted when the last
-  // callback is removed with Unregister.
+  // Registers a callback with the data provider. The first call to Register()
+  // will create a singleton data provider that will be deleted on Unregister().
   wifi_data_provider_manager_ =
       WifiDataProviderManager::Register(&wifi_data_update_callback_);
 
@@ -197,44 +197,33 @@
       FROM_HERE, base::Bind(&NetworkLocationProvider::RequestPosition,
                             weak_factory_.GetWeakPtr()),
       base::TimeDelta::FromSeconds(kDataCompleteWaitSeconds));
-  // Get the wifi data.
-  is_wifi_data_complete_ = wifi_data_provider_manager_->GetData(&wifi_data_);
-  if (is_wifi_data_complete_)
-    OnWifiDataUpdated();
+
+  OnWifiDataUpdate();
   return true;
 }
 
-void NetworkLocationProvider::OnWifiDataUpdated() {
-  DCHECK(CalledOnValidThread());
-  wifi_timestamp_ = base::Time::Now();
-
-  is_new_data_available_ = is_wifi_data_complete_;
-  RequestPosition();
-}
-
 void NetworkLocationProvider::StopProvider() {
-  DCHECK(CalledOnValidThread());
-  if (IsStarted()) {
-    wifi_data_provider_manager_->Unregister(&wifi_data_update_callback_);
-  }
+  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK(IsStarted());
+  wifi_data_provider_manager_->Unregister(&wifi_data_update_callback_);
   wifi_data_provider_manager_ = nullptr;
   weak_factory_.InvalidateWeakPtrs();
 }
 
-// Other methods
-void NetworkLocationProvider::RequestPosition() {
-  DCHECK(CalledOnValidThread());
+const Geoposition& NetworkLocationProvider::GetPosition() {
+  return position_;
+}
 
-  // TODO(mcasas): consider not using HasWeakPtrs() https://crbug.com/629158.
-  if (weak_factory_.HasWeakPtrs() && !is_wifi_data_complete_)
+void NetworkLocationProvider::RequestPosition() {
+  DCHECK(thread_checker_.CalledOnValidThread());
+
+  if (!is_new_data_available_ || !is_wifi_data_complete_)
     return;
-  if (!is_new_data_available_)
-    return;
+  DCHECK(!wifi_timestamp_.is_null())
+      << "|wifi_timestamp_| must be set before looking up position";
 
   const Geoposition* cached_position =
       position_cache_->FindPosition(wifi_data_);
-  DCHECK(!wifi_timestamp_.is_null())
-      << "Timestamp must be set before looking up position";
   if (cached_position) {
     DCHECK(cached_position->Validate());
     // Record the position and update its timestamp.
@@ -255,16 +244,15 @@
   if (!is_permission_granted_)
     return;
 
-  weak_factory_.InvalidateWeakPtrs();
   is_new_data_available_ = false;
 
   // TODO(joth): Rather than cancel pending requests, we should create a new
   // NetworkLocationRequest for each and hold a set of pending requests.
-  if (request_->is_request_pending()) {
-    DVLOG(1) << "NetworkLocationProvider - pre-empting pending network request "
-                "with new data. Wifi APs: "
-             << wifi_data_.access_point_data.size();
-  }
+  DLOG_IF(WARNING, request_->is_request_pending())
+      << "NetworkLocationProvider - pre-empting pending network request "
+         "with new data. Wifi APs: "
+      << wifi_data_.access_point_data.size();
+
   request_->MakeRequest(access_token_, wifi_data_, wifi_timestamp_);
 }
 
diff --git a/device/geolocation/network_location_provider.h b/device/geolocation/network_location_provider.h
index dc3fb217..634da9a 100644
--- a/device/geolocation/network_location_provider.h
+++ b/device/geolocation/network_location_provider.h
@@ -15,8 +15,8 @@
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
 #include "base/strings/string16.h"
-#include "base/threading/non_thread_safe.h"
 #include "base/threading/thread.h"
+#include "base/threading/thread_checker.h"
 #include "device/geolocation/geolocation_export.h"
 #include "device/geolocation/geoposition.h"
 #include "device/geolocation/location_provider.h"
@@ -26,8 +26,7 @@
 namespace device {
 class AccessTokenStore;
 
-class NetworkLocationProvider : public base::NonThreadSafe,
-                                public LocationProvider {
+class NetworkLocationProvider : public LocationProvider {
  public:
   // Cache of recently resolved locations. Public for tests.
   class DEVICE_GEOLOCATION_EXPORT PositionCache {
@@ -71,23 +70,20 @@
   ~NetworkLocationProvider() override;
 
   // LocationProvider implementation
-  void SetUpdateCallback(
-      const LocationProviderUpdateCallback& callback) override;
+  void SetUpdateCallback(const LocationProviderUpdateCallback& cb) override;
   bool StartProvider(bool high_accuracy) override;
   void StopProvider() override;
   const Geoposition& GetPosition() override;
   void OnPermissionGranted() override;
 
  private:
-  // Satisfies a position request from cache or network.
+  // Tries to update |position_| request from cache or network.
   void RequestPosition();
 
-  // Gets called when new wifi data is available.
+  // Gets called when new wifi data is available, either via explicit request to
+  // or callback from |wifi_data_provider_manager_|.
   void OnWifiDataUpdate();
 
-  // Internal helper used by OnWifiDataUpdate.
-  void OnWifiDataUpdated();
-
   bool IsStarted() const;
 
   void OnLocationResponse(const Geoposition& position,
@@ -97,7 +93,8 @@
 
   const scoped_refptr<AccessTokenStore> access_token_store_;
 
-  // The wifi data provider, acquired via global factories.
+  // The wifi data provider, acquired via global factories. Valid between
+  // StartProvider() and StopProvider(), and checked via IsStarted().
   WifiDataProviderManager* wifi_data_provider_manager_;
 
   WifiDataProviderManager::WifiDataUpdateCallback wifi_data_update_callback_;
@@ -125,11 +122,13 @@
   bool is_new_data_available_;
 
   // The network location request object, and the url it uses.
-  std::unique_ptr<NetworkLocationRequest> request_;
+  const std::unique_ptr<NetworkLocationRequest> request_;
 
   // The cache of positions.
   const std::unique_ptr<PositionCache> position_cache_;
 
+  base::ThreadChecker thread_checker_;
+
   base::WeakPtrFactory<NetworkLocationProvider> weak_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(NetworkLocationProvider);
diff --git a/device/vr/openvr/openvr_device.cc b/device/vr/openvr/openvr_device.cc
index 88f7f4a..0ced4955 100644
--- a/device/vr/openvr/openvr_device.cc
+++ b/device/vr/openvr/openvr_device.cc
@@ -24,6 +24,15 @@
   return out;
 }
 
+std::vector<float> HmdVector3ToWebVR(const vr::HmdVector3_t& vec) {
+  std::vector<float> out;
+  out.resize(3);
+  out[0] = vec.v[0];
+  out[1] = vec.v[1];
+  out[2] = vec.v[2];
+  return out;
+}
+
 }  // namespace
 
 namespace device {
@@ -164,6 +173,9 @@
     pose->position.value()[0] = m[0][3];
     pose->position.value()[1] = m[1][3];
     pose->position.value()[2] = m[2][3];
+
+    pose->linearVelocity = HmdVector3ToWebVR(hmdPose.vVelocity);
+    pose->angularVelocity = HmdVector3ToWebVR(hmdPose.vAngularVelocity);
   }
 
   return std::move(pose);
diff --git a/extensions/browser/api/cast_channel/cast_socket.cc b/extensions/browser/api/cast_channel/cast_socket.cc
index 9efe8f5..2952fcc9 100644
--- a/extensions/browser/api/cast_channel/cast_socket.cc
+++ b/extensions/browser/api/cast_channel/cast_socket.cc
@@ -311,13 +311,18 @@
   DoConnectCallback();
 }
 
+void CastSocketImpl::ResetConnectLoopCallback() {
+  DCHECK(connect_loop_callback_.IsCancelled());
+  connect_loop_callback_.Reset(
+      base::Bind(&CastSocketImpl::DoConnectLoop, base::Unretained(this)));
+}
+
 void CastSocketImpl::PostTaskToStartConnectLoop(int result) {
   DCHECK(CalledOnValidThread());
-  DCHECK(connect_loop_callback_.IsCancelled());
-  connect_loop_callback_.Reset(base::Bind(&CastSocketImpl::DoConnectLoop,
-                                          base::Unretained(this), result));
+
+  ResetConnectLoopCallback();
   base::ThreadTaskRunnerHandle::Get()->PostTask(
-      FROM_HERE, connect_loop_callback_.callback());
+      FROM_HERE, base::Bind(connect_loop_callback_.callback(), result));
 }
 
 // This method performs the state machine transitions for connection flow.
@@ -467,9 +472,8 @@
   VLOG_WITH_CONNECTION(1) << "Sending challenge: "
                           << CastMessageToString(challenge_message);
 
-  transport_->SendMessage(
-      challenge_message,
-      base::Bind(&CastSocketImpl::DoConnectLoop, base::Unretained(this)));
+  ResetConnectLoopCallback();
+  transport_->SendMessage(challenge_message, connect_loop_callback_.callback());
 
   // Always return IO_PENDING since the result is always asynchronous.
   return net::ERR_IO_PENDING;
@@ -592,7 +596,6 @@
   // Cancel callbacks that we queued ourselves to re-enter the connect or read
   // loops.
   connect_loop_callback_.Cancel();
-  send_auth_challenge_callback_.Cancel();
   connect_timeout_callback_.Cancel();
   SetReadyState(READY_STATE_CLOSED);
 }
diff --git a/extensions/browser/api/cast_channel/cast_socket.h b/extensions/browser/api/cast_channel/cast_socket.h
index 9423a48..cfff93f 100644
--- a/extensions/browser/api/cast_channel/cast_socket.h
+++ b/extensions/browser/api/cast_channel/cast_socket.h
@@ -285,7 +285,12 @@
   int DoAuthChallengeReplyComplete(int result);
   /////////////////////////////////////////////////////////////////////////////
 
-  // Schedules asynchrous connection loop processing in the MessageLoop.
+  // Resets the cancellable callback used for async invocations of
+  // DoConnectLoop.
+  void ResetConnectLoopCallback();
+
+  // Posts a task to invoke |connect_loop_callback_| with |result| on the
+  // current message loop.
   void PostTaskToStartConnectLoop(int result);
 
   // Runs the external connection callback and resets it.
@@ -379,13 +384,12 @@
   // The current status of the channel.
   ReadyState ready_state_;
 
-  // Task invoked to (re)start the connect loop.  Canceled on entry to the
-  // connect loop.
-  base::CancelableClosure connect_loop_callback_;
-
-  // Task invoked to send the auth challenge.  Canceled when the auth challenge
-  // has been sent.
-  base::CancelableClosure send_auth_challenge_callback_;
+  // Callback which, when invoked, will re-enter the connection state machine.
+  // Oustanding callbacks will be cancelled when |this| is destroyed.
+  // The callback signature is based on net::CompletionCallback, which passes
+  // operation result codes as byte counts in the success case, or as
+  // net::Error enum values for error cases.
+  base::CancelableCallback<void(int)> connect_loop_callback_;
 
   // Cast message formatting and parsing layer.
   std::unique_ptr<CastTransport> transport_;
diff --git a/extensions/browser/api/cast_channel/cast_socket_unittest.cc b/extensions/browser/api/cast_channel/cast_socket_unittest.cc
index 5a857b2..29fbf778 100644
--- a/extensions/browser/api/cast_channel/cast_socket_unittest.cc
+++ b/extensions/browser/api/cast_channel/cast_socket_unittest.cc
@@ -638,6 +638,23 @@
   EXPECT_EQ(cast_channel::CHANNEL_ERROR_SOCKET_ERROR, socket_->error_state());
 }
 
+// Test connection error - connection is destroyed after the challenge is
+// sent, with the async result still lurking in the task queue.
+TEST_F(CastSocketTest, TestConnectDestroyedAfterChallengeSent) {
+  CreateCastSocketSecure();
+  socket_->SetupMockTransport();
+  socket_->SetupTcpConnect(net::SYNCHRONOUS, net::OK);
+  socket_->SetupSslConnect(net::SYNCHRONOUS, net::OK);
+  EXPECT_CALL(*socket_->GetMockTransport(),
+              SendMessage(EqualsProto(CreateAuthChallenge()), _))
+      .WillOnce(PostCompletionCallbackTask<1>(net::ERR_CONNECTION_RESET));
+  socket_->Connect(std::move(delegate_),
+                   base::Bind(&CompleteHandler::OnConnectComplete,
+                              base::Unretained(&handler_)));
+  socket_.reset();
+  RunPendingTasks();
+}
+
 // Test connection error - challenge reply receive fails
 TEST_F(CastSocketTest, TestConnectChallengeReplyReceiveError) {
   CreateCastSocketSecure();
diff --git a/extensions/browser/content_hash_fetcher.cc b/extensions/browser/content_hash_fetcher.cc
index 4ed26faf..b637ce90 100644
--- a/extensions/browser/content_hash_fetcher.cc
+++ b/extensions/browser/content_hash_fetcher.cc
@@ -52,7 +52,8 @@
     : public base::RefCountedThreadSafe<ContentHashFetcherJob>,
       public net::URLFetcherDelegate {
  public:
-  typedef base::Callback<void(ContentHashFetcherJob*)> CompletionCallback;
+  using CompletionCallback =
+      base::Callback<void(scoped_refptr<ContentHashFetcherJob>)>;
   ContentHashFetcherJob(net::URLRequestContextGetter* request_context,
                         const ContentVerifierKey& key,
                         const std::string& extension_id,
@@ -444,7 +445,7 @@
     if (cancelled_)
       return;
   }
-  callback_.Run(this);
+  callback_.Run(make_scoped_refptr(this));
 }
 
 // ----
@@ -512,8 +513,13 @@
   }
 }
 
-void ContentHashFetcher::JobFinished(ContentHashFetcherJob* job) {
+void ContentHashFetcher::JobFinished(scoped_refptr<ContentHashFetcherJob> job) {
   if (!job->IsCancelled()) {
+    // Note: Run can result in ContentHashFetcher::ExtensionUnloaded.
+    //
+    // TODO(lazyboy): Add a unit test to cover the case where Run can result in
+    // ContentHashFetcher::ExtensionUnloaded, once https://crbug.com/702300 is
+    // fixed.
     fetch_callback_.Run(job->extension_id(),
                         job->success(),
                         job->force(),
@@ -521,7 +527,7 @@
   }
 
   for (JobMap::iterator i = jobs_.begin(); i != jobs_.end(); ++i) {
-    if (i->second.get() == job) {
+    if (i->second.get() == job.get()) {
       jobs_.erase(i);
       break;
     }
diff --git a/extensions/browser/content_hash_fetcher.h b/extensions/browser/content_hash_fetcher.h
index 9a08fe4..b77aa13 100644
--- a/extensions/browser/content_hash_fetcher.h
+++ b/extensions/browser/content_hash_fetcher.h
@@ -61,7 +61,7 @@
 
  private:
   // Callback for when a job getting content hashes has completed.
-  void JobFinished(ContentHashFetcherJob* job);
+  void JobFinished(scoped_refptr<ContentHashFetcherJob> job);
 
   net::URLRequestContextGetter* context_getter_;
   ContentVerifierDelegate* delegate_;
diff --git a/extensions/common/url_pattern_unittest.cc b/extensions/common/url_pattern_unittest.cc
index 860d487..62419f6 100644
--- a/extensions/common/url_pattern_unittest.cc
+++ b/extensions/common/url_pattern_unittest.cc
@@ -17,13 +17,11 @@
 // See url_pattern.h for examples of valid and invalid patterns.
 
 static const int kAllSchemes =
-    URLPattern::SCHEME_HTTP |
-    URLPattern::SCHEME_HTTPS |
-    URLPattern::SCHEME_FILE |
-    URLPattern::SCHEME_FTP |
-    URLPattern::SCHEME_CHROMEUI |
-    URLPattern::SCHEME_EXTENSION |
-    URLPattern::SCHEME_FILESYSTEM;
+    URLPattern::SCHEME_HTTP | URLPattern::SCHEME_HTTPS |
+    URLPattern::SCHEME_FILE | URLPattern::SCHEME_FTP |
+    URLPattern::SCHEME_CHROMEUI | URLPattern::SCHEME_EXTENSION |
+    URLPattern::SCHEME_FILESYSTEM | URLPattern::SCHEME_WS |
+    URLPattern::SCHEME_WSS;
 
 TEST(ExtensionURLPatternTest, ParseInvalid) {
   const struct {
@@ -542,7 +540,7 @@
       URLPattern::SCHEME_FTP,
       "http://google.com/monkey").ConvertToExplicitSchemes());
 
-  ASSERT_EQ(7u, all_urls.size());
+  ASSERT_EQ(9u, all_urls.size());
   ASSERT_EQ(2u, all_schemes.size());
   ASSERT_EQ(1u, monkey.size());
 
@@ -551,6 +549,10 @@
   EXPECT_EQ("file:///*", all_urls[2].GetAsString());
   EXPECT_EQ("ftp://*/*", all_urls[3].GetAsString());
   EXPECT_EQ("chrome://*/*", all_urls[4].GetAsString());
+  EXPECT_EQ("chrome-extension://*/*", all_urls[5].GetAsString());
+  EXPECT_EQ("filesystem://*/*", all_urls[6].GetAsString());
+  EXPECT_EQ("ws://*/*", all_urls[7].GetAsString());
+  EXPECT_EQ("wss://*/*", all_urls[8].GetAsString());
 
   EXPECT_EQ("http://google.com/foo", all_schemes[0].GetAsString());
   EXPECT_EQ("https://google.com/foo", all_schemes[1].GetAsString());
diff --git a/gpu/config/gpu_control_list_testing_autogen.cc b/gpu/config/gpu_control_list_testing_autogen.cc
index fc93fbf..d7c17c1 100644
--- a/gpu/config/gpu_control_list_testing_autogen.cc
+++ b/gpu/config/gpu_control_list_testing_autogen.cc
@@ -17,8 +17,7 @@
 
 const char kGpuControlListTestingVersion[] = "1.0";
 
-const size_t kGpuControlListTestingEntryCount = 58;
-const GpuControlList::Entry kGpuControlListTestingEntries[58] = {
+const GpuControlList::Entry kGpuControlListTestingEntries[] = {
     {
         1,  // id
         "GpuControlListEntryTest.DetailedEntry",
@@ -1530,4 +1529,5 @@
         nullptr,  // exceptions
     },
 };
+const size_t kGpuControlListTestingEntryCount = 58;
 }  // namespace gpu
diff --git a/gpu/config/software_rendering_list.json b/gpu/config/software_rendering_list.json
index f3e6a67..dced8ff6 100644
--- a/gpu/config/software_rendering_list.json
+++ b/gpu/config/software_rendering_list.json
@@ -1,6 +1,6 @@
 {
   "name": "software rendering list",
-  "version": "13.2",
+  "version": "13.3",
   "entries": [
     {
       "id": 1,
@@ -1494,6 +1494,92 @@
       "features": [
         "webgl2"
       ]
+    },
+    {
+      "id": 141,
+      "description": "Disable use of D3D11/WebGL2 on Windows Vista and lower",
+      "os": {
+        "type": "win",
+        "version": {
+          "op": "<=",
+          "value": "6.0"
+        }
+      },
+      "features": [
+        "webgl2"
+      ]
+    },
+    {
+      "id": 142,
+      "description": "Disable D3D11/WebGL2 on older nVidia drivers",
+      "cr_bugs": [349929],
+      "os": {
+        "type": "win"
+      },
+      "vendor_id": "0x10de",
+      "driver_version": {
+        "op": "<=",
+        "value": "8.17.12.6973"
+      },
+      "features": [
+        "webgl2"
+      ]
+    },
+    {
+      "id": 143,
+      "description": "Disable use of D3D11/WebGL2 on Matrox video cards",
+      "cr_bugs": [395861],
+      "os": {
+        "type": "win"
+      },
+      "vendor_id": "0x102b",
+      "features": [
+        "webgl2"
+      ]
+    },
+    {
+      "id": 144,
+      "description": "Disable use of D3D11/WebGL2 on older AMD drivers",
+      "cr_bugs": [402134],
+      "os": {
+        "type": "win"
+      },
+      "vendor_id": "0x1002",
+      "driver_date": {
+        "op": "<",
+        "value": "2011.1"
+      },
+      "features": [
+        "webgl2"
+      ]
+    },
+    {
+      "id": 145,
+      "description": "Old Intel drivers cannot reliably support D3D11/WebGL2",
+      "cr_bugs": [363721],
+      "os": {
+        "type": "win"
+      },
+      "vendor_id": "0x8086",
+      "driver_version": {
+        "op": "<",
+        "value": "8.16"
+      },
+      "features": [
+        "webgl2"
+      ]
+    },
+    {
+      "id": 146,
+      "description": "Disable D3D11/WebGL2 on AMD switchable graphics",
+      "cr_bugs": [451420],
+      "os": {
+        "type": "win"
+      },
+      "multi_gpu_style": "amd_switchable",
+      "features": [
+        "webgl2"
+      ]
     }
   ],
   "comment": [
diff --git a/headless/public/util/deterministic_http_protocol_handler.cc b/headless/public/util/deterministic_http_protocol_handler.cc
index dd905b64..1f61f98 100644
--- a/headless/public/util/deterministic_http_protocol_handler.cc
+++ b/headless/public/util/deterministic_http_protocol_handler.cc
@@ -32,7 +32,6 @@
   void OnResourceLoadComplete(
       const Request* request,
       const GURL& final_url,
-      int http_response_code,
       scoped_refptr<net::HttpResponseHeaders> response_headers,
       const char* body,
       size_t body_size) override {}
diff --git a/headless/public/util/generic_url_request_job.cc b/headless/public/util/generic_url_request_job.cc
index b618913e..4cf9bdd 100644
--- a/headless/public/util/generic_url_request_job.cc
+++ b/headless/public/util/generic_url_request_job.cc
@@ -9,6 +9,7 @@
 
 #include "base/logging.h"
 #include "content/public/browser/devtools_agent_host.h"
+#include "content/public/browser/render_frame_host.h"
 #include "content/public/browser/resource_request_info.h"
 #include "content/public/browser/web_contents.h"
 #include "headless/public/util/url_request_dispatcher.h"
@@ -34,6 +35,8 @@
 
 }  // namespace
 
+uint64_t GenericURLRequestJob::next_request_id_ = 0;
+
 GenericURLRequestJob::GenericURLRequestJob(
     net::URLRequest* request,
     net::NetworkDelegate* network_delegate,
@@ -48,6 +51,7 @@
       delegate_(delegate),
       request_resource_info_(
           content::ResourceRequestInfo::ForRequest(request_)),
+      request_id_(next_request_id_++),
       weak_factory_(this) {}
 
 GenericURLRequestJob::~GenericURLRequestJob() {
@@ -110,12 +114,14 @@
   DCHECK(origin_task_runner_->RunsTasksOnCurrentThread());
   // TODO(alexclarke): Set user agent.
   // Pass cookies, the referrer and any extra headers into the fetch request.
-  extra_request_headers_.SetHeader(
-      net::HttpRequestHeaders::kCookie,
-      net::CookieStore::BuildCookieLine(cookie_list));
+  std::string cookie = net::CookieStore::BuildCookieLine(cookie_list);
+  if (!cookie.empty())
+    extra_request_headers_.SetHeader(net::HttpRequestHeaders::kCookie, cookie);
 
-  extra_request_headers_.SetHeader(net::HttpRequestHeaders::kReferer,
-                                   request_->referrer());
+  if (!request_->referrer().empty()) {
+    extra_request_headers_.SetHeader(net::HttpRequestHeaders::kReferer,
+                                     request_->referrer());
+  }
 
   done_callback.Run();
 }
@@ -128,21 +134,19 @@
 
 void GenericURLRequestJob::OnFetchComplete(
     const GURL& final_url,
-    int http_response_code,
     scoped_refptr<net::HttpResponseHeaders> response_headers,
     const char* body,
     size_t body_size) {
   DCHECK(origin_task_runner_->RunsTasksOnCurrentThread());
   response_time_ = base::TimeTicks::Now();
-  http_response_code_ = http_response_code;
   response_headers_ = response_headers;
   body_ = body;
   body_size_ = body_size;
 
   DispatchHeadersComplete();
 
-  delegate_->OnResourceLoadComplete(this, final_url, http_response_code,
-                                    response_headers_, body_, body_size_);
+  delegate_->OnResourceLoadComplete(this, final_url, response_headers_, body_,
+                                    body_size_);
 }
 
 int GenericURLRequestJob::ReadRawData(net::IOBuffer* buf, int buf_size) {
@@ -159,10 +163,6 @@
   return bytes_to_copy;
 }
 
-int GenericURLRequestJob::GetResponseCode() const {
-  return http_response_code_;
-}
-
 void GenericURLRequestJob::GetResponseInfo(net::HttpResponseInfo* info) {
   info->headers = response_headers_;
 }
@@ -185,12 +185,33 @@
   load_timing_info->receive_headers_end = response_time_;
 }
 
+uint64_t GenericURLRequestJob::GenericURLRequestJob::GetRequestId() const {
+  return request_id_;
+}
+
 const net::URLRequest* GenericURLRequestJob::GetURLRequest() const {
   return request_;
 }
 
 int GenericURLRequestJob::GetFrameTreeNodeId() const {
-  return request_resource_info_->GetFrameTreeNodeId();
+  // URLRequestUserData will be set for all renderer initiated resource
+  // requests, but not for browser side navigations.
+  int render_process_id;
+  int render_frame_id;
+  if (content::ResourceRequestInfo::GetRenderFrameForRequest(
+          request_, &render_process_id, &render_frame_id)) {
+    content::RenderFrameHost* render_frame_host =
+        content::RenderFrameHost::FromID(render_process_id, render_frame_id);
+    DCHECK(render_frame_host);
+    return render_frame_host->GetFrameTreeNodeId();
+  }
+  // ResourceRequestInfo::GetFrameTreeNodeId is only set for browser side
+  // navigations.
+  if (request_resource_info_)
+    return request_resource_info_->GetFrameTreeNodeId();
+
+  // This should only happen in tests.
+  return -1;
 }
 
 std::string GenericURLRequestJob::GetDevToolsAgentHostId() const {
@@ -200,6 +221,10 @@
 }
 
 Request::ResourceType GenericURLRequestJob::GetResourceType() const {
+  // This should only happen in some tests.
+  if (!request_resource_info_)
+    return Request::ResourceType::MAIN_FRAME;
+
   switch (request_resource_info_->GetResourceType()) {
     case content::RESOURCE_TYPE_MAIN_FRAME:
       return Request::ResourceType::MAIN_FRAME;
@@ -243,12 +268,11 @@
   }
 }
 
-namespace {
-std::string GetUploadData(net::URLRequest* request) {
-  if (!request->has_upload())
+std::string GenericURLRequestJob::GetPostData() const {
+  if (!request_->has_upload())
     return "";
 
-  const net::UploadDataStream* stream = request->get_upload();
+  const net::UploadDataStream* stream = request_->get_upload();
   if (!stream->GetElementReaders())
     return "";
 
@@ -257,7 +281,6 @@
       (*stream->GetElementReaders())[0]->AsBytesReader();
   return std::string(reader->bytes(), reader->length());
 }
-}  // namespace
 
 const Request* GenericURLRequestJob::GetRequest() const {
   return this;
@@ -271,9 +294,8 @@
     return;
   }
 
-  url_fetcher_->StartFetch(request_->url(), request_->method(),
-                           GetUploadData(request_), extra_request_headers_,
-                           this);
+  url_fetcher_->StartFetch(request_->url(), request_->method(), GetPostData(),
+                           extra_request_headers_, this);
 }
 
 void GenericURLRequestJob::BlockRequest(net::Error error) {
@@ -321,7 +343,6 @@
   mock_response_ = std::move(mock_response);
 
   OnFetchCompleteExtractHeaders(request_->url(),
-                                mock_response_->http_response_code,
                                 mock_response_->response_data.data(),
                                 mock_response_->response_data.size());
 }
diff --git a/headless/public/util/generic_url_request_job.h b/headless/public/util/generic_url_request_job.h
index da6a4972..8830934e 100644
--- a/headless/public/util/generic_url_request_job.h
+++ b/headless/public/util/generic_url_request_job.h
@@ -36,6 +36,8 @@
 // Wrapper around net::URLRequest with helpers to access select metadata.
 class Request {
  public:
+  virtual uint64_t GetRequestId() const = 0;
+
   virtual const net::URLRequest* GetURLRequest() const = 0;
 
   // The frame from which the request came from.
@@ -44,6 +46,9 @@
   // The devtools agent host id for the page where the request came from.
   virtual std::string GetDevToolsAgentHostId() const = 0;
 
+  // Gets the POST data, if any, from the net::URLRequest.
+  virtual std::string GetPostData() const = 0;
+
   enum class ResourceType {
     MAIN_FRAME = 0,
     SUB_FRAME = 1,
@@ -96,7 +101,6 @@
       const net::HttpRequestHeaders& request_headers) = 0;
 
   struct MockResponseData {
-    int http_response_code = 0;
     std::string response_data;
   };
 
@@ -140,7 +144,6 @@
     virtual void OnResourceLoadComplete(
         const Request* request,
         const GURL& final_url,
-        int http_response_code,
         scoped_refptr<net::HttpResponseHeaders> response_headers,
         const char* body,
         size_t body_size) = 0;
@@ -162,7 +165,6 @@
   void SetExtraRequestHeaders(const net::HttpRequestHeaders& headers) override;
   void Start() override;
   int ReadRawData(net::IOBuffer* buf, int buf_size) override;
-  int GetResponseCode() const override;
   void GetResponseInfo(net::HttpResponseInfo* info) override;
   bool GetMimeType(std::string* mime_type) const override;
   bool GetCharset(std::string* charset) override;
@@ -171,16 +173,17 @@
   // URLFetcher::FetchResultListener implementation:
   void OnFetchStartError(net::Error error) override;
   void OnFetchComplete(const GURL& final_url,
-                       int http_response_code,
                        scoped_refptr<net::HttpResponseHeaders> response_headers,
                        const char* body,
                        size_t body_size) override;
 
  protected:
   // Request implementation:
+  uint64_t GetRequestId() const override;
   const net::URLRequest* GetURLRequest() const override;
   int GetFrameTreeNodeId() const override;
   std::string GetDevToolsAgentHostId() const override;
+  std::string GetPostData() const override;
   ResourceType GetResourceType() const override;
 
   // PendingRequest implementation:
@@ -211,10 +214,11 @@
   Delegate* delegate_;          // Not owned.
   const content::ResourceRequestInfo* request_resource_info_;  // Not owned.
   const char* body_ = nullptr;  // Not owned.
-  int http_response_code_ = 0;
   size_t body_size_ = 0;
   size_t read_offset_ = 0;
   base::TimeTicks response_time_;
+  const uint64_t request_id_;
+  static uint64_t next_request_id_;
 
   base::WeakPtrFactory<GenericURLRequestJob> weak_factory_;
 
diff --git a/headless/public/util/generic_url_request_job_test.cc b/headless/public/util/generic_url_request_job_test.cc
index b4aec67..bb95a02 100644
--- a/headless/public/util/generic_url_request_job_test.cc
+++ b/headless/public/util/generic_url_request_job_test.cc
@@ -91,9 +91,6 @@
     ASSERT_TRUE(fetch_reply->GetAsDictionary(&reply_dictionary));
     std::string final_url;
     ASSERT_TRUE(reply_dictionary->GetString("url", &final_url));
-    int http_response_code;
-    ASSERT_TRUE(reply_dictionary->GetInteger("http_response_code",
-                                             &http_response_code));
     ASSERT_TRUE(reply_dictionary->GetString("data", &response_data_));
     base::DictionaryValue* reply_headers_dictionary;
     ASSERT_TRUE(
@@ -109,8 +106,8 @@
     }
 
     result_listener->OnFetchComplete(
-        GURL(final_url), http_response_code, std::move(response_headers),
-        response_data_.c_str(), response_data_.size());
+        GURL(final_url), std::move(response_headers), response_data_.c_str(),
+        response_data_.size());
   }
 
  private:
@@ -174,6 +171,24 @@
     return request;
   }
 
+  std::unique_ptr<net::URLRequest> CreateAndCompletePostJob(
+      const GURL& url,
+      const std::string& post_data,
+      const std::string& json_reply) {
+    json_fetch_reply_map_[url.spec()] = json_reply;
+
+    std::unique_ptr<net::URLRequest> request(url_request_context_.CreateRequest(
+        url, net::DEFAULT_PRIORITY, &request_delegate_));
+    request->set_method("POST");
+    request->set_upload(net::ElementsUploadDataStream::CreateWithReader(
+        base::MakeUnique<net::UploadBytesElementReader>(post_data.data(),
+                                                        post_data.size()),
+        0));
+    request->Start();
+    base::RunLoop().RunUntilIdle();
+    return request;
+  }
+
  protected:
   base::MessageLoop message_loop_;
   ExpeditedDispatcher dispatcher_;
@@ -193,7 +208,6 @@
   json_fetch_reply_map_["https://example.com/"] = R"(
       {
         "url": "https://example.com",
-        "http_response_code": 200,
         "data": "Reply",
         "headers": {
           "Content-Type": "text/html; charset=UTF-8"
@@ -215,7 +229,6 @@
         "method": "GET",
         "headers": {
           "Accept": "text/plain",
-          "Cookie": "",
           "Extra-Header": "Value",
           "Referer": "https://referrer.example.com/",
           "User-Agent": "TestBrowser"
@@ -229,7 +242,6 @@
   json_fetch_reply_map_["https://example.com/"] = R"(
       {
         "url": "https://example.com",
-        "http_response_code": 200,
         "data": "Reply",
         "headers": {
           "Content-Type": "text/html; charset=UTF-8"
@@ -259,7 +271,6 @@
         "post_data": "lorem ipsom",
         "headers": {
           "Accept": "text/plain",
-          "Cookie": "",
           "Extra-Header": "Value",
           "Referer": "https://referrer.example.com/",
           "User-Agent": "TestBrowser"
@@ -273,7 +284,6 @@
   std::string reply = R"(
       {
         "url": "https://example.com",
-        "http_response_code": 200,
         "data": "Reply",
         "headers": {
           "Content-Type": "text/html; charset=UTF-8"
@@ -303,7 +313,6 @@
   std::string reply = R"(
       {
         "url": "https://example.com",
-        "http_response_code": 200,
         "data": "Reply",
         "headers": {
           "Content-Type": "text/html; charset=UTF-8"
@@ -329,7 +338,6 @@
   std::string reply = R"(
       {
         "url": "https://example.com",
-        "http_response_code": 200,
         "data": "Reply",
         "headers": {
           "Content-Type": "text/html; charset=UTF-8"
@@ -416,7 +424,6 @@
   std::string reply = R"(
       {
         "url": "https://example.com",
-        "http_response_code": 200,
         "data": "Reply",
         "headers": {
           "Content-Type": "text/html; charset=UTF-8"
@@ -431,8 +438,7 @@
         "url": "https://example.com/",
         "method": "GET",
         "headers": {
-          "Cookie": "basic_cookie=1; secure_cookie=2; http_only_cookie=3",
-          "Referer": ""
+          "Cookie": "basic_cookie=1; secure_cookie=2; http_only_cookie=3"
         }
       })";
 
@@ -443,7 +449,6 @@
   std::string reply = R"(
       {
         "url": "https://example.com",
-        "http_response_code": 200,
         "data": "Reply",
         "headers": {
           "Content-Type": "text/html; charset=UTF-8"
@@ -465,7 +470,6 @@
   json_fetch_reply_map_["https://example.com/"] = R"(
       {
         "url": "https://example.com",
-        "http_response_code": 200,
         "data": "Welcome to example.com",
         "headers": {
           "Content-Type": "text/html; charset=UTF-8"
@@ -475,7 +479,6 @@
   json_fetch_reply_map_["https://othersite.com/"] = R"(
       {
         "url": "https://example.com",
-        "http_response_code": 200,
         "data": "Welcome to othersite.com",
         "headers": {
           "Content-Type": "text/html; charset=UTF-8"
@@ -525,7 +528,6 @@
   std::string reply = R"(
       {
         "url": "https://example.com",
-        "http_response_code": 200,
         "data": "Reply",
         "headers": {
           "Content-Type": "text/html; charset=UTF-8"
@@ -535,7 +537,6 @@
   job_delegate_.SetPolicy(base::Bind([](PendingRequest* pending_request) {
     std::unique_ptr<GenericURLRequestJob::MockResponseData> mock_response_data(
         new GenericURLRequestJob::MockResponseData());
-    mock_response_data->http_response_code = 404;
     mock_response_data->response_data = "HTTP/1.1 404 Not Found\r\n\r\n";
     pending_request->MockResponse(std::move(mock_response_data));
   }));
@@ -552,7 +553,6 @@
         "https://example.com/") {
       std::unique_ptr<GenericURLRequestJob::MockResponseData>
           mock_response_data(new GenericURLRequestJob::MockResponseData());
-      mock_response_data->http_response_code = 302;
       mock_response_data->response_data =
           "HTTP/1.1 302 Found\r\n"
           "Location: https://foo.com/\r\n\r\n";
@@ -565,7 +565,6 @@
   json_fetch_reply_map_["https://example.com/"] = R"(
       {
         "url": "https://example.com",
-        "http_response_code": 200,
         "data": "Welcome to example.com",
         "headers": {
           "Content-Type": "text/html; charset=UTF-8"
@@ -575,7 +574,6 @@
   json_fetch_reply_map_["https://foo.com/"] = R"(
       {
         "url": "https://example.com",
-        "http_response_code": 200,
         "data": "Welcome to foo.com",
         "headers": {
           "Content-Type": "text/html; charset=UTF-8"
@@ -609,4 +607,55 @@
   base::RunLoop().RunUntilIdle();
 }
 
+TEST_F(GenericURLRequestJobTest, RequestsHaveDistinctIds) {
+  std::string reply = R"(
+      {
+        "url": "https://example.com",
+        "http_response_code": 200,
+        "data": "Reply",
+        "headers": {
+          "Content-Type": "text/html; charset=UTF-8"
+        }
+      })";
+
+  std::set<uint64_t> ids;
+  job_delegate_.SetPolicy(base::Bind(
+      [](std::set<uint64_t>* ids, PendingRequest* pending_request) {
+        ids->insert(pending_request->GetRequest()->GetRequestId());
+        pending_request->AllowRequest();
+      },
+      &ids));
+
+  CreateAndCompleteGetJob(GURL("https://example.com"), reply);
+  CreateAndCompleteGetJob(GURL("https://example.com"), reply);
+  CreateAndCompleteGetJob(GURL("https://example.com"), reply);
+
+  // We expect three distinct ids.
+  EXPECT_EQ(3u, ids.size());
+}
+
+TEST_F(GenericURLRequestJobTest, GetPostData) {
+  std::string reply = R"(
+      {
+        "url": "https://example.com",
+        "http_response_code": 200,
+        "data": "Reply",
+        "headers": {
+          "Content-Type": "text/html; charset=UTF-8"
+        }
+      })";
+
+  std::string post_data;
+  job_delegate_.SetPolicy(base::Bind(
+      [](std::string* post_data, PendingRequest* pending_request) {
+        *post_data = pending_request->GetRequest()->GetPostData();
+        pending_request->AllowRequest();
+      },
+      &post_data));
+
+  CreateAndCompletePostJob(GURL("https://example.com"), "payload", reply);
+
+  EXPECT_EQ("payload", post_data);
+}
+
 }  // namespace headless
diff --git a/headless/public/util/http_url_fetcher.cc b/headless/public/util/http_url_fetcher.cc
index ac40607..f21052b 100644
--- a/headless/public/util/http_url_fetcher.cc
+++ b/headless/public/util/http_url_fetcher.cc
@@ -182,8 +182,7 @@
   // |request->response_info()| that we drop here.  Find a way to pipe it
   // through.
   result_listener_->OnFetchComplete(
-      request->url(), request->GetResponseCode(),
-      request->response_info().headers,
+      request->url(), request->response_info().headers,
       bytes_read_so_far_.c_str(), bytes_read_so_far_.size());
 }
 
diff --git a/headless/public/util/testing/generic_url_request_mocks.cc b/headless/public/util/testing/generic_url_request_mocks.cc
index 4a7d37de..c047e051 100644
--- a/headless/public/util/testing/generic_url_request_mocks.cc
+++ b/headless/public/util/testing/generic_url_request_mocks.cc
@@ -4,6 +4,8 @@
 
 #include "headless/public/util/testing/generic_url_request_mocks.h"
 
+#include <utility>
+
 #include "base/logging.h"
 #include "base/threading/thread_task_runner_handle.h"
 
@@ -29,7 +31,7 @@
 }
 
 void MockGenericURLRequestJobDelegate::SetPolicy(Policy policy) {
-  policy_ = policy;
+  policy_ = std::move(policy);
 }
 
 void MockGenericURLRequestJobDelegate::ApplyPolicy(
@@ -48,7 +50,6 @@
 void MockGenericURLRequestJobDelegate::OnResourceLoadComplete(
     const Request* request,
     const GURL& final_url,
-    int http_response_code,
     scoped_refptr<net::HttpResponseHeaders> response_headers,
     const char* body,
     size_t body_size) {}
diff --git a/headless/public/util/testing/generic_url_request_mocks.h b/headless/public/util/testing/generic_url_request_mocks.h
index 218c3ce..94e0e5c0 100644
--- a/headless/public/util/testing/generic_url_request_mocks.h
+++ b/headless/public/util/testing/generic_url_request_mocks.h
@@ -31,7 +31,6 @@
   void OnResourceLoadComplete(
       const Request* request,
       const GURL& final_url,
-      int http_response_code,
       scoped_refptr<net::HttpResponseHeaders> response_headers,
       const char* body,
       size_t body_size) override;
diff --git a/headless/public/util/url_fetcher.cc b/headless/public/util/url_fetcher.cc
index 8d8d33f..70256e6a 100644
--- a/headless/public/util/url_fetcher.cc
+++ b/headless/public/util/url_fetcher.cc
@@ -14,7 +14,6 @@
 
 void URLFetcher::ResultListener::OnFetchCompleteExtractHeaders(
     const GURL& final_url,
-    int http_response_code,
     const char* response_data,
     size_t response_data_size) {
   size_t read_offset = 0;
@@ -32,7 +31,7 @@
   }
 
   CHECK_LE(read_offset, response_data_size);
-  OnFetchComplete(final_url, http_response_code, std::move(response_headers),
+  OnFetchComplete(final_url, std::move(response_headers),
                   response_data + read_offset,
                   response_data_size - read_offset);
 }
diff --git a/headless/public/util/url_fetcher.h b/headless/public/util/url_fetcher.h
index df0cc0ff..9dfc08a 100644
--- a/headless/public/util/url_fetcher.h
+++ b/headless/public/util/url_fetcher.h
@@ -41,7 +41,6 @@
     // valid until the fetcher is destroyed,
     virtual void OnFetchComplete(
         const GURL& final_url,
-        int http_response_code,
         scoped_refptr<net::HttpResponseHeaders> response_headers,
         const char* body,
         size_t body_size) = 0;
@@ -49,7 +48,6 @@
     // Helper function which extracts the headers from |response_data| and calls
     // OnFetchComplete.
     void OnFetchCompleteExtractHeaders(const GURL& final_url,
-                                       int http_response_code,
                                        const char* response_data,
                                        size_t response_data_size);
 
diff --git a/ios/chrome/browser/payments/cells/autofill_profile_item.mm b/ios/chrome/browser/payments/cells/autofill_profile_item.mm
index 4e82bfa..3f2476e 100644
--- a/ios/chrome/browser/payments/cells/autofill_profile_item.mm
+++ b/ios/chrome/browser/payments/cells/autofill_profile_item.mm
@@ -131,7 +131,7 @@
 
 // Set constraints on subviews.
 - (void)setViewConstraints {
-  AddSameSizeConstraint(self.contentView, _stackView);
+  AddSameConstraints(self.contentView, _stackView);
 }
 
 #pragma mark - UIView
diff --git a/ios/chrome/browser/ui/authentication/signin_promo_item.mm b/ios/chrome/browser/ui/authentication/signin_promo_item.mm
index ed05eae..9a2a52e0 100644
--- a/ios/chrome/browser/ui/authentication/signin_promo_item.mm
+++ b/ios/chrome/browser/ui/authentication/signin_promo_item.mm
@@ -48,7 +48,7 @@
     _signinPromoView = [[SigninPromoView alloc] initWithFrame:self.bounds];
     _signinPromoView.translatesAutoresizingMaskIntoConstraints = NO;
     [contentView addSubview:_signinPromoView];
-    AddSameSizeConstraint(_signinPromoView, contentView);
+    AddSameConstraints(_signinPromoView, contentView);
   }
   return self;
 }
diff --git a/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_article_item.mm b/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_article_item.mm
index 8781014..214804e 100644
--- a/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_article_item.mm
+++ b/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_article_item.mm
@@ -283,7 +283,7 @@
     [_noImageIcon.heightAnchor constraintEqualToAnchor:_noImageIcon.widthAnchor]
   ]];
 
-  AddSameSizeConstraint(_contentImageView, _imageContainer);
+  AddSameConstraints(_contentImageView, _imageContainer);
 
   ApplyVisualConstraintsWithMetrics(
       @[
diff --git a/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_footer_item.mm b/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_footer_item.mm
index 8f1d90927..2c66da9 100644
--- a/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_footer_item.mm
+++ b/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_footer_item.mm
@@ -74,7 +74,7 @@
     [_button.heightAnchor
         constraintGreaterThanOrEqualToConstant:kMinimalCellHeight]
         .active = YES;
-    AddSameSizeConstraint(self.contentView, _button);
+    AddSameConstraints(self.contentView, _button);
   }
   return self;
 }
diff --git a/ios/chrome/browser/ui/elements/activity_overlay_coordinator.mm b/ios/chrome/browser/ui/elements/activity_overlay_coordinator.mm
index d275ad3a8..f56daeec 100644
--- a/ios/chrome/browser/ui/elements/activity_overlay_coordinator.mm
+++ b/ios/chrome/browser/ui/elements/activity_overlay_coordinator.mm
@@ -42,10 +42,8 @@
       addSubview:self.activityOverlayViewController.view];
   [self.activityOverlayViewController
       didMoveToParentViewController:self.baseViewController];
-  AddSameCenterConstraints(self.baseViewController.view,
-                           self.activityOverlayViewController.view);
-  AddSameSizeConstraint(self.baseViewController.view,
-                        self.activityOverlayViewController.view);
+  AddSameConstraints(self.baseViewController.view,
+                     self.activityOverlayViewController.view);
 }
 
 - (void)stop {
diff --git a/ios/chrome/browser/ui/favicon/favicon_view.mm b/ios/chrome/browser/ui/favicon/favicon_view.mm
index 9a5486f3..74962157 100644
--- a/ios/chrome/browser/ui/favicon/favicon_view.mm
+++ b/ios/chrome/browser/ui/favicon/favicon_view.mm
@@ -56,10 +56,8 @@
     [_faviconFallbackLabel setTranslatesAutoresizingMaskIntoConstraints:NO];
 
     // Both image and fallback label are centered and match the size of favicon.
-    AddSameCenterConstraints(_faviconImageView, self);
-    AddSameCenterConstraints(_faviconFallbackLabel, self);
-    AddSameSizeConstraint(_faviconFallbackLabel, self);
-    AddSameSizeConstraint(_faviconImageView, self);
+    AddSameConstraints(_faviconFallbackLabel, self);
+    AddSameConstraints(_faviconImageView, self);
   }
   return self;
 }
diff --git a/ios/chrome/browser/ui/history/favicon_view.mm b/ios/chrome/browser/ui/history/favicon_view.mm
index e2958eb..fca9135 100644
--- a/ios/chrome/browser/ui/history/favicon_view.mm
+++ b/ios/chrome/browser/ui/history/favicon_view.mm
@@ -48,10 +48,8 @@
 
     [_faviconImage setTranslatesAutoresizingMaskIntoConstraints:NO];
     [_faviconFallbackLabel setTranslatesAutoresizingMaskIntoConstraints:NO];
-    AddSameCenterConstraints(_faviconImage, self);
-    AddSameSizeConstraint(_faviconImage, self);
-    AddSameCenterConstraints(_faviconFallbackLabel, self);
-    AddSameSizeConstraint(_faviconFallbackLabel, self);
+    AddSameConstraints(_faviconImage, self);
+    AddSameConstraints(_faviconFallbackLabel, self);
     _faviconSizeConstraints = @[
       [self.widthAnchor constraintEqualToConstant:0],
       [self.heightAnchor constraintEqualToConstant:0],
diff --git a/ios/chrome/browser/ui/history/history_entry_item.mm b/ios/chrome/browser/ui/history/history_entry_item.mm
index 9136b33..e4806c6c 100644
--- a/ios/chrome/browser/ui/history/history_entry_item.mm
+++ b/ios/chrome/browser/ui/history/history_entry_item.mm
@@ -196,8 +196,7 @@
   FaviconView* faviconView = self.faviconViewProvider.faviconView;
   [cell.faviconViewContainer addSubview:faviconView];
   [faviconView setTranslatesAutoresizingMaskIntoConstraints:NO];
-  AddSameSizeConstraint(faviconView, cell.faviconViewContainer);
-  AddSameCenterConstraints(faviconView, cell.faviconViewContainer);
+  AddSameConstraints(faviconView, cell.faviconViewContainer);
 
   cell.textLabel.text = self.text;
   cell.detailTextLabel.text = self.detailText;
diff --git a/ios/chrome/browser/ui/reading_list/reading_list_toolbar.mm b/ios/chrome/browser/ui/reading_list/reading_list_toolbar.mm
index 9c1fba7d..680b251 100644
--- a/ios/chrome/browser/ui/reading_list/reading_list_toolbar.mm
+++ b/ios/chrome/browser/ui/reading_list/reading_list_toolbar.mm
@@ -190,7 +190,7 @@
 
     [self addSubview:_stackView];
     _stackView.translatesAutoresizingMaskIntoConstraints = NO;
-    AddSameSizeConstraint(_stackView, self);
+    AddSameConstraints(_stackView, self);
     _stackView.layoutMargins =
         UIEdgeInsetsMake(0, kHorizontalMargin, 0, kHorizontalMargin);
     _stackView.layoutMarginsRelativeArrangement = YES;
diff --git a/ios/chrome/browser/ui/side_swipe/card_side_swipe_view.mm b/ios/chrome/browser/ui/side_swipe/card_side_swipe_view.mm
index bc8f6c7..ddfdaf9 100644
--- a/ios/chrome/browser/ui/side_swipe/card_side_swipe_view.mm
+++ b/ios/chrome/browser/ui/side_swipe/card_side_swipe_view.mm
@@ -167,8 +167,8 @@
     [leftCard_ setTranslatesAutoresizingMaskIntoConstraints:NO];
     [self addSubview:rightCard_];
     [self addSubview:leftCard_];
-    AddSameSizeConstraint(rightCard_, self);
-    AddSameSizeConstraint(leftCard_, self);
+    AddSameConstraints(rightCard_, self);
+    AddSameConstraints(leftCard_, self);
   }
   return self;
 }
diff --git a/ios/chrome/browser/ui/uikit_ui_util.h b/ios/chrome/browser/ui/uikit_ui_util.h
index 406b660f..b34bef7 100644
--- a/ios/chrome/browser/ui/uikit_ui_util.h
+++ b/ios/chrome/browser/ui/uikit_ui_util.h
@@ -268,9 +268,9 @@
                               UIView* subview1,
                               UIView* subview2);
 
-// Adds constraints to make two views' sizes equal by pinning leading, trailing,
-// top and bottom anchors.
-void AddSameSizeConstraint(UIView* view1, UIView* view2);
+// Adds constraints to make two views' size and center equal by pinning leading,
+// trailing, top and bottom anchors.
+void AddSameConstraints(UIView* view1, UIView* view2);
 
 // Whether the |environment| has a compact horizontal size class.
 bool IsCompact(id<UITraitEnvironment> environment);
diff --git a/ios/chrome/browser/ui/uikit_ui_util.mm b/ios/chrome/browser/ui/uikit_ui_util.mm
index f0542c5..06aef01f 100644
--- a/ios/chrome/browser/ui/uikit_ui_util.mm
+++ b/ios/chrome/browser/ui/uikit_ui_util.mm
@@ -637,7 +637,7 @@
   AddSameCenterYConstraint(subview1, subview2);
 }
 
-void AddSameSizeConstraint(UIView* view1, UIView* view2) {
+void AddSameConstraints(UIView* view1, UIView* view2) {
   [NSLayoutConstraint activateConstraints:@[
     [view1.leadingAnchor constraintEqualToAnchor:view2.leadingAnchor],
     [view1.trailingAnchor constraintEqualToAnchor:view2.trailingAnchor],
diff --git a/ios/showcase/core/showcase_model.mm b/ios/showcase/core/showcase_model.mm
index 200d2ee..ee7d3da 100644
--- a/ios/showcase/core/showcase_model.mm
+++ b/ios/showcase/core/showcase_model.mm
@@ -42,6 +42,11 @@
       showcase::kUseCaseKey : @"Payment request picker view",
     },
     @{
+      showcase::kClassForDisplayKey : @"PaymentRequestSelectorViewController",
+      showcase::kClassForInstantiationKey : @"SCPaymentsSelectorCoordinator",
+      showcase::kUseCaseKey : @"Payment request selector view",
+    },
+    @{
       showcase::kClassForDisplayKey : @"RootContainerViewController",
       showcase::kClassForInstantiationKey : @"SCRootCoordinator",
       showcase::kUseCaseKey : @"Root container",
diff --git a/ios/showcase/payments/BUILD.gn b/ios/showcase/payments/BUILD.gn
index 787808f..a8a34db 100644
--- a/ios/showcase/payments/BUILD.gn
+++ b/ios/showcase/payments/BUILD.gn
@@ -8,6 +8,8 @@
     "sc_payments_editor_coordinator.mm",
     "sc_payments_picker_coordinator.h",
     "sc_payments_picker_coordinator.mm",
+    "sc_payments_selector_coordinator.h",
+    "sc_payments_selector_coordinator.mm",
   ]
   deps = [
     "//base",
@@ -29,6 +31,7 @@
   sources = [
     "sc_payments_editor_egtest.mm",
     "sc_payments_picker_egtest.mm",
+    "sc_payments_selector_egtest.mm",
   ]
   deps = [
     "//base",
@@ -37,6 +40,7 @@
     "//ios/chrome/browser/ui",
     "//ios/chrome/browser/ui/autofill:autofill_ui",
     "//ios/chrome/browser/ui/settings",
+    "//ios/chrome/test/earl_grey:test_support",
     "//ios/showcase/test",
     "//ios/third_party/earl_grey",
     "//ui/base",
diff --git a/ios/showcase/payments/sc_payments_selector_coordinator.h b/ios/showcase/payments/sc_payments_selector_coordinator.h
new file mode 100644
index 0000000..9ab7f4e
--- /dev/null
+++ b/ios/showcase/payments/sc_payments_selector_coordinator.h
@@ -0,0 +1,17 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IOS_SHOWCASE_PAYMENTS_SC_PAYMENTS_SELECTOR_COORDINATOR_H_
+#define IOS_SHOWCASE_PAYMENTS_SC_PAYMENTS_SELECTOR_COORDINATOR_H_
+
+#import <UIKit/UIKit.h>
+
+#import "ios/showcase/common/navigation_coordinator.h"
+
+// Coordinator responsible for creating and presenting a
+// PaymentRequestSelectorViewController.
+@interface SCPaymentsSelectorCoordinator : NSObject<NavigationCoordinator>
+@end
+
+#endif  // IOS_SHOWCASE_PAYMENTS_SC_PAYMENTS_SELECTOR_COORDINATOR_H_
diff --git a/ios/showcase/payments/sc_payments_selector_coordinator.mm b/ios/showcase/payments/sc_payments_selector_coordinator.mm
new file mode 100644
index 0000000..f543a7b
--- /dev/null
+++ b/ios/showcase/payments/sc_payments_selector_coordinator.mm
@@ -0,0 +1,109 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "ios/showcase/payments/sc_payments_selector_coordinator.h"
+
+#include "base/logging.h"
+#import "ios/chrome/browser/payments//cells/payments_text_item.h"
+#import "ios/chrome/browser/payments/cells/payments_has_accessory_type.h"
+#import "ios/chrome/browser/payments/payment_request_selector_view_controller.h"
+#import "ios/chrome/browser/payments/payment_request_selector_view_controller_data_source.h"
+#import "ios/chrome/browser/ui/collection_view/collection_view_model.h"
+#import "ios/showcase/common/protocol_alerter.h"
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+@interface SCPaymentsSelectorCoordinator ()<
+    PaymentRequestSelectorViewControllerDataSource>
+
+// Index for the currently selected item or NSUIntegerMax if there is none.
+@property(nonatomic, readwrite) NSUInteger selectedItemIndex;
+
+// The view controller to present.
+@property(nonatomic, strong)
+    PaymentRequestSelectorViewController* selectorViewController;
+
+// The selectable items created and managed by the
+// PaymentRequestSelectorViewControllerDataSource.
+@property(nonatomic, strong)
+    NSArray<CollectionViewItem<PaymentsHasAccessoryType>*>* items;
+
+// The alerter that conforms to PaymentRequestSelectorViewControllerDelegate
+// and displays a UIAlert every time delegate methods are called.
+@property(nonatomic, strong) ProtocolAlerter* alerter;
+
+@end
+
+@implementation SCPaymentsSelectorCoordinator
+
+@synthesize state = _state;
+@synthesize selectedItemIndex = _selectedItemIndex;
+@synthesize baseViewController = _baseViewController;
+@synthesize selectorViewController = _selectorViewController;
+@synthesize items = _items;
+@synthesize alerter = _alerter;
+
+- (void)start {
+  self.items = [self createItems];
+  self.selectedItemIndex = NSUIntegerMax;
+
+  self.alerter = [[ProtocolAlerter alloc] initWithProtocols:@[
+    @protocol(PaymentRequestSelectorViewControllerDelegate)
+  ]];
+  self.alerter.baseViewController = self.baseViewController;
+
+  self.selectorViewController = [[PaymentRequestSelectorViewController alloc]
+      initWithStyle:CollectionViewControllerStyleAppBar];
+  [self.selectorViewController setTitle:@"Select an item"];
+  [self.selectorViewController setDataSource:self];
+  [self.selectorViewController loadModel];
+  [self.selectorViewController
+      setDelegate:reinterpret_cast<
+                      id<PaymentRequestSelectorViewControllerDelegate>>(
+                      self.alerter)];
+  [self.baseViewController pushViewController:self.selectorViewController
+                                     animated:YES];
+}
+
+#pragma mark - PaymentRequestSelectorViewControllerDataSource
+
+- (CollectionViewItem*)headerItem {
+  return [self createItemWithText:@"Header item"];
+}
+
+- (NSArray<CollectionViewItem<PaymentsHasAccessoryType>*>*)selectableItems {
+  return self.items;
+}
+
+- (CollectionViewItem<PaymentsHasAccessoryType>*)selectableItemAtIndex:
+    (NSUInteger)index {
+  DCHECK(index < self.items.count);
+  return [self.items objectAtIndex:index];
+}
+
+- (CollectionViewItem*)addButtonItem {
+  return [self createItemWithText:@"Add an item"];
+}
+
+#pragma mark - Helper methods
+
+- (NSArray<CollectionViewItem<PaymentsHasAccessoryType>*>*)createItems {
+  return @[
+    [self createItemWithText:@"First selectable item"],
+    [self createItemWithText:@"Second selectable item"],
+    [self createItemWithText:@"Third selectable item"],
+    [self createItemWithText:@"Fourth selectable item"]
+  ];
+}
+
+- (CollectionViewItem<PaymentsHasAccessoryType>*)createItemWithText:
+    (NSString*)text {
+  PaymentsTextItem* item = [[PaymentsTextItem alloc] init];
+  item.text = text;
+  return item;
+}
+
+@end
diff --git a/ios/showcase/payments/sc_payments_selector_egtest.mm b/ios/showcase/payments/sc_payments_selector_egtest.mm
new file mode 100644
index 0000000..c4f3e68
--- /dev/null
+++ b/ios/showcase/payments/sc_payments_selector_egtest.mm
@@ -0,0 +1,140 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import <EarlGrey/EarlGrey.h>
+
+#import "ios/chrome/browser/payments/payment_request_selector_view_controller.h"
+#import "ios/chrome/test/earl_grey/chrome_matchers.h"
+#import "ios/showcase/test/showcase_eg_utils.h"
+#import "ios/showcase/test/showcase_test_case.h"
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+namespace {
+using ::showcase_utils::Open;
+using ::showcase_utils::Close;
+using ::chrome_test_util::ButtonWithAccessibilityLabel;
+
+// Returns the GREYMatcher for the header item.
+id<GREYMatcher> HeaderItem() {
+  return grey_allOf(grey_accessibilityLabel(@"Header item"),
+                    grey_kindOfClass([UILabel class]),
+                    grey_sufficientlyVisible(), nil);
+}
+
+// Returns the GREYMatcher for the selectable item with the given label.
+// |selected| states whether or not the item is selected.
+id<GREYMatcher> SelectableItemWithLabel(NSString* label, BOOL selected) {
+  id<GREYMatcher> matcher = grey_allOf(ButtonWithAccessibilityLabel(label),
+                                       grey_sufficientlyVisible(), nil);
+  if (selected) {
+    return grey_allOf(
+        matcher, grey_accessibilityTrait(UIAccessibilityTraitSelected), nil);
+  }
+  return matcher;
+}
+
+// Returns the GREYMatcher for the "Add" button.
+id<GREYMatcher> AddButton() {
+  return grey_allOf(ButtonWithAccessibilityLabel(@"Add an item"),
+                    grey_sufficientlyVisible(), nil);
+}
+
+}  // namespace
+
+// Tests for the payment request selector view controller.
+@interface SCPaymentsSelectorTestCase : ShowcaseTestCase
+@end
+
+@implementation SCPaymentsSelectorTestCase
+
+- (void)setUp {
+  [super setUp];
+  Open(@"PaymentRequestSelectorViewController");
+}
+
+- (void)tearDown {
+  Close();
+  [super tearDown];
+}
+
+// Tests if all the expected items are present and that none is selected.
+- (void)testVerifyItems {
+  [[EarlGrey selectElementWithMatcher:HeaderItem()]
+      assertWithMatcher:grey_notNil()];
+
+  [[EarlGrey selectElementWithMatcher:SelectableItemWithLabel(
+                                          @"First selectable item", NO)]
+      assertWithMatcher:grey_notNil()];
+  [[EarlGrey selectElementWithMatcher:SelectableItemWithLabel(
+                                          @"Second selectable item", NO)]
+      assertWithMatcher:grey_notNil()];
+  [[EarlGrey selectElementWithMatcher:SelectableItemWithLabel(
+                                          @"Third selectable item", NO)]
+      assertWithMatcher:grey_notNil()];
+  [[EarlGrey selectElementWithMatcher:SelectableItemWithLabel(
+                                          @"Fourth selectable item", NO)]
+      assertWithMatcher:grey_notNil()];
+
+  [[EarlGrey selectElementWithMatcher:AddButton()]
+      assertWithMatcher:grey_notNil()];
+}
+
+// Tests that selectable items can be selected.
+- (void)testCanSelectItems {
+  // Tap the first selectable item which is currently not selected.
+  [[EarlGrey selectElementWithMatcher:SelectableItemWithLabel(
+                                          @"First selectable item", NO)]
+      performAction:grey_tap()];
+
+  // Confirm the delegate is informed.
+  [[EarlGrey selectElementWithMatcher:grey_accessibilityLabel(
+                                          @"protocol_alerter_done")]
+      performAction:grey_tap()];
+
+  // Confirm the first selectable item is now selected. Tap it again.
+  [[EarlGrey selectElementWithMatcher:SelectableItemWithLabel(
+                                          @"First selectable item", YES)]
+      performAction:grey_tap()];
+
+  // Confirm the delegate is informed.
+  [[EarlGrey selectElementWithMatcher:grey_accessibilityLabel(
+                                          @"protocol_alerter_done")]
+      performAction:grey_tap()];
+
+  // Confirm the first selectable item is still selected.
+  [[EarlGrey selectElementWithMatcher:SelectableItemWithLabel(
+                                          @"First selectable item", YES)]
+      assertWithMatcher:grey_notNil()];
+
+  // Tap the second selectable item which is currently not selected.
+  [[EarlGrey selectElementWithMatcher:SelectableItemWithLabel(
+                                          @"Second selectable item", NO)]
+      performAction:grey_tap()];
+
+  // Confirm the delegate is informed.
+  [[EarlGrey selectElementWithMatcher:grey_accessibilityLabel(
+                                          @"protocol_alerter_done")]
+      performAction:grey_tap()];
+
+  // Confirm the second selectable item is now selected.
+  [[EarlGrey selectElementWithMatcher:SelectableItemWithLabel(
+                                          @"Second selectable item", YES)]
+      assertWithMatcher:grey_notNil()];
+}
+
+// Tests that item can be added.
+- (void)testCanAddItem {
+  // Tap the add button.
+  [[EarlGrey selectElementWithMatcher:AddButton()] performAction:grey_tap()];
+
+  // Confirm the delegate is informed.
+  [[EarlGrey selectElementWithMatcher:grey_accessibilityLabel(
+                                          @"protocol_alerter_done")]
+      performAction:grey_tap()];
+}
+
+@end
diff --git a/media/base/localized_strings.h b/media/base/localized_strings.h
index 0678f9b2..bf4a652f 100644
--- a/media/base/localized_strings.h
+++ b/media/base/localized_strings.h
@@ -28,10 +28,6 @@
   BEAMFORMING_ON_DEFAULT_AUDIO_INPUT_DEVICE_NAME,
   BEAMFORMING_OFF_DEFAULT_AUDIO_INPUT_DEVICE_NAME,
 #endif
-#if BUILDFLAG(ENABLE_MEDIA_REMOTING)
-  MEDIA_REMOTING_CAST_ERROR_TEXT,
-  MEDIA_REMOTING_CASTING_VIDEO_TEXT,
-#endif
 };
 
 // Implementations are expected to convert MessageIds to generated_resources.grd
diff --git a/media/base/media_observer.h b/media/base/media_observer.h
index 0181b1d..4bb3366 100644
--- a/media/base/media_observer.h
+++ b/media/base/media_observer.h
@@ -56,10 +56,6 @@
   virtual void OnPlaying() = 0;
   virtual void OnPaused() = 0;
 
-  // Called when a poster image URL is set, which happens when media is loaded
-  // or the poster attribute is changed.
-  virtual void OnSetPoster(const GURL& poster) = 0;
-
   // Set the MediaObserverClient.
   virtual void SetClient(MediaObserverClient* client) = 0;
 };
diff --git a/media/blink/webmediaplayer_impl.cc b/media/blink/webmediaplayer_impl.cc
index 172541b..0c886a34 100644
--- a/media/blink/webmediaplayer_impl.cc
+++ b/media/blink/webmediaplayer_impl.cc
@@ -1617,16 +1617,11 @@
 void WebMediaPlayerImpl::SetUseFallbackPath(bool use_fallback_path) {
   use_fallback_path_ = use_fallback_path;
 }
-#endif  // defined(OS_ANDROID)  // WMPI_CAST
 
 void WebMediaPlayerImpl::SetPoster(const blink::WebURL& poster) {
-#if defined(OS_ANDROID)
   cast_impl_.setPoster(poster);
-#endif
-
-  if (observer_)
-    observer_->OnSetPoster(poster);
 }
+#endif  // defined(OS_ANDROID)  // WMPI_CAST
 
 void WebMediaPlayerImpl::DataSourceInitialized(bool success) {
   DVLOG(1) << __func__;
diff --git a/media/blink/webmediaplayer_impl.h b/media/blink/webmediaplayer_impl.h
index 5be40d1fd..a7382f8 100644
--- a/media/blink/webmediaplayer_impl.h
+++ b/media/blink/webmediaplayer_impl.h
@@ -191,8 +191,6 @@
   void BecameDominantVisibleContent(bool isDominant) override;
   void SetIsEffectivelyFullscreen(bool isEffectivelyFullscreen) override;
 
-  void SetPoster(const blink::WebURL& poster) override;
-
   // WebMediaPlayerDelegate::Observer implementation.
   void OnFrameHidden() override;
   void OnFrameClosed() override;
@@ -220,6 +218,7 @@
   gfx::Size GetCanvasSize() const;
   void SetDeviceScaleFactor(float scale_factor);
   void SetUseFallbackPath(bool use_fallback_path);
+  void SetPoster(const blink::WebURL& poster) override;
 #endif
 
   // MediaObserverClient implementation.
diff --git a/media/capture/BUILD.gn b/media/capture/BUILD.gn
index 66ab197..a48ceee7 100644
--- a/media/capture/BUILD.gn
+++ b/media/capture/BUILD.gn
@@ -19,6 +19,10 @@
   defines = [ "CAPTURE_IMPLEMENTATION" ]
   sources = [
     "capture_export.h",
+    "video/video_capture_device_descriptor.cc",
+    "video/video_capture_device_descriptor.h",
+    "video/video_capture_device_info.cc",
+    "video/video_capture_device_info.h",
     "video_capture_types.cc",
     "video_capture_types.h",
   ]
@@ -86,12 +90,8 @@
     "video/video_capture_device.h",
     "video/video_capture_device_client.cc",
     "video/video_capture_device_client.h",
-    "video/video_capture_device_descriptor.cc",
-    "video/video_capture_device_descriptor.h",
     "video/video_capture_device_factory.cc",
     "video/video_capture_device_factory.h",
-    "video/video_capture_device_info.cc",
-    "video/video_capture_device_info.h",
     "video/video_capture_jpeg_decoder.h",
     "video/video_capture_system.h",
     "video/video_capture_system_impl.cc",
diff --git a/media/capture/mojo/video_capture_types.mojom b/media/capture/mojo/video_capture_types.mojom
index d020527..00170cd 100644
--- a/media/capture/mojo/video_capture_types.mojom
+++ b/media/capture/mojo/video_capture_types.mojom
@@ -67,3 +67,16 @@
   gfx.mojom.Size coded_size;
   gfx.mojom.Rect visible_rect;
 };
+
+struct VideoCaptureDeviceDescriptor {
+  string display_name;
+  string device_id;
+  string model_id;
+  VideoCaptureApi capture_api;
+  VideoCaptureTransportType transport_type;
+};
+
+struct VideoCaptureDeviceInfo {
+  VideoCaptureDeviceDescriptor descriptor;
+  array<VideoCaptureFormat> supported_formats;
+};
diff --git a/media/capture/mojo/video_capture_types.typemap b/media/capture/mojo/video_capture_types.typemap
index e6c4c44..32ed58a 100644
--- a/media/capture/mojo/video_capture_types.typemap
+++ b/media/capture/mojo/video_capture_types.typemap
@@ -4,7 +4,11 @@
 
 mojom = "//media/capture/mojo/video_capture_types.mojom"
 
-public_headers = [ "//media/capture/video_capture_types.h" ]
+public_headers = [
+  "//media/capture/video_capture_types.h",
+  "//media/capture/video/video_capture_device_descriptor.h",
+  "//media/capture/video/video_capture_device_info.h",
+]
 
 traits_headers = [
   "//media/capture/ipc/capture_param_traits_macros.h",
@@ -29,4 +33,6 @@
   "media.mojom.VideoCaptureFormat=media::VideoCaptureFormat",
   "media.mojom.VideoPixelStorage=media::VideoPixelStorage",
   "media.mojom.VideoCaptureParams=media::VideoCaptureParams",
+  "media.mojom.VideoCaptureDeviceDescriptor=media::VideoCaptureDeviceDescriptor",
+  "media.mojom.VideoCaptureDeviceInfo=media::VideoCaptureDeviceInfo",
 ]
diff --git a/media/capture/mojo/video_capture_types_typemap_traits.cc b/media/capture/mojo/video_capture_types_typemap_traits.cc
index ef27d0bf..ae16102 100644
--- a/media/capture/mojo/video_capture_types_typemap_traits.cc
+++ b/media/capture/mojo/video_capture_types_typemap_traits.cc
@@ -100,6 +100,113 @@
 }
 
 // static
+media::mojom::VideoCaptureApi
+EnumTraits<media::mojom::VideoCaptureApi, media::VideoCaptureApi>::ToMojom(
+    media::VideoCaptureApi input) {
+  switch (input) {
+    case media::VideoCaptureApi::LINUX_V4L2_SINGLE_PLANE:
+      return media::mojom::VideoCaptureApi::LINUX_V4L2_SINGLE_PLANE;
+    case media::VideoCaptureApi::WIN_MEDIA_FOUNDATION:
+      return media::mojom::VideoCaptureApi::WIN_MEDIA_FOUNDATION;
+    case media::VideoCaptureApi::WIN_DIRECT_SHOW:
+      return media::mojom::VideoCaptureApi::WIN_DIRECT_SHOW;
+    case media::VideoCaptureApi::MACOSX_AVFOUNDATION:
+      return media::mojom::VideoCaptureApi::MACOSX_AVFOUNDATION;
+    case media::VideoCaptureApi::MACOSX_DECKLINK:
+      return media::mojom::VideoCaptureApi::MACOSX_DECKLINK;
+    case media::VideoCaptureApi::ANDROID_API1:
+      return media::mojom::VideoCaptureApi::ANDROID_API1;
+    case media::VideoCaptureApi::ANDROID_API2_LEGACY:
+      return media::mojom::VideoCaptureApi::ANDROID_API2_LEGACY;
+    case media::VideoCaptureApi::ANDROID_API2_FULL:
+      return media::mojom::VideoCaptureApi::ANDROID_API2_FULL;
+    case media::VideoCaptureApi::ANDROID_API2_LIMITED:
+      return media::mojom::VideoCaptureApi::ANDROID_API2_LIMITED;
+    case media::VideoCaptureApi::ANDROID_TANGO:
+      return media::mojom::VideoCaptureApi::ANDROID_TANGO;
+    case media::VideoCaptureApi::UNKNOWN:
+      return media::mojom::VideoCaptureApi::UNKNOWN;
+  }
+  NOTREACHED();
+  return media::mojom::VideoCaptureApi::UNKNOWN;
+}
+
+// static
+bool EnumTraits<media::mojom::VideoCaptureApi, media::VideoCaptureApi>::
+    FromMojom(media::mojom::VideoCaptureApi input,
+              media::VideoCaptureApi* output) {
+  switch (input) {
+    case media::mojom::VideoCaptureApi::LINUX_V4L2_SINGLE_PLANE:
+      *output = media::VideoCaptureApi::LINUX_V4L2_SINGLE_PLANE;
+      return true;
+    case media::mojom::VideoCaptureApi::WIN_MEDIA_FOUNDATION:
+      *output = media::VideoCaptureApi::WIN_MEDIA_FOUNDATION;
+      return true;
+    case media::mojom::VideoCaptureApi::WIN_DIRECT_SHOW:
+      *output = media::VideoCaptureApi::WIN_DIRECT_SHOW;
+      return true;
+    case media::mojom::VideoCaptureApi::MACOSX_AVFOUNDATION:
+      *output = media::VideoCaptureApi::MACOSX_AVFOUNDATION;
+      return true;
+    case media::mojom::VideoCaptureApi::MACOSX_DECKLINK:
+      *output = media::VideoCaptureApi::MACOSX_DECKLINK;
+      return true;
+    case media::mojom::VideoCaptureApi::ANDROID_API1:
+      *output = media::VideoCaptureApi::ANDROID_API1;
+      return true;
+    case media::mojom::VideoCaptureApi::ANDROID_API2_LEGACY:
+      *output = media::VideoCaptureApi::ANDROID_API2_LEGACY;
+      return true;
+    case media::mojom::VideoCaptureApi::ANDROID_API2_FULL:
+      *output = media::VideoCaptureApi::ANDROID_API2_FULL;
+      return true;
+    case media::mojom::VideoCaptureApi::ANDROID_API2_LIMITED:
+      *output = media::VideoCaptureApi::ANDROID_API2_LIMITED;
+      return true;
+    case media::mojom::VideoCaptureApi::ANDROID_TANGO:
+      *output = media::VideoCaptureApi::ANDROID_TANGO;
+      return true;
+    case media::mojom::VideoCaptureApi::UNKNOWN:
+      *output = media::VideoCaptureApi::UNKNOWN;
+      return true;
+  }
+  NOTREACHED();
+  return false;
+}
+
+// static
+media::mojom::VideoCaptureTransportType EnumTraits<
+    media::mojom::VideoCaptureTransportType,
+    media::VideoCaptureTransportType>::ToMojom(media::VideoCaptureTransportType
+                                                   input) {
+  switch (input) {
+    case media::VideoCaptureTransportType::MACOSX_USB_OR_BUILT_IN:
+      return media::mojom::VideoCaptureTransportType::MACOSX_USB_OR_BUILT_IN;
+    case media::VideoCaptureTransportType::OTHER_TRANSPORT:
+      return media::mojom::VideoCaptureTransportType::OTHER_TRANSPORT;
+  }
+  NOTREACHED();
+  return media::mojom::VideoCaptureTransportType::OTHER_TRANSPORT;
+}
+
+// static
+bool EnumTraits<media::mojom::VideoCaptureTransportType,
+                media::VideoCaptureTransportType>::
+    FromMojom(media::mojom::VideoCaptureTransportType input,
+              media::VideoCaptureTransportType* output) {
+  switch (input) {
+    case media::mojom::VideoCaptureTransportType::MACOSX_USB_OR_BUILT_IN:
+      *output = media::VideoCaptureTransportType::MACOSX_USB_OR_BUILT_IN;
+      return true;
+    case media::mojom::VideoCaptureTransportType::OTHER_TRANSPORT:
+      *output = media::VideoCaptureTransportType::OTHER_TRANSPORT;
+      return true;
+  }
+  NOTREACHED();
+  return false;
+}
+
+// static
 bool StructTraits<media::mojom::VideoCaptureFormatDataView,
                   media::VideoCaptureFormat>::
     Read(media::mojom::VideoCaptureFormatDataView data,
@@ -128,4 +235,34 @@
   return true;
 }
 
+// static
+bool StructTraits<media::mojom::VideoCaptureDeviceDescriptorDataView,
+                  media::VideoCaptureDeviceDescriptor>::
+    Read(media::mojom::VideoCaptureDeviceDescriptorDataView data,
+         media::VideoCaptureDeviceDescriptor* output) {
+  if (!data.ReadDisplayName(&(output->display_name)))
+    return false;
+  if (!data.ReadDeviceId(&(output->device_id)))
+    return false;
+  if (!data.ReadModelId(&(output->model_id)))
+    return false;
+  if (!data.ReadCaptureApi(&(output->capture_api)))
+    return false;
+  if (!data.ReadTransportType(&(output->transport_type)))
+    return false;
+  return true;
+}
+
+// static
+bool StructTraits<media::mojom::VideoCaptureDeviceInfoDataView,
+                  media::VideoCaptureDeviceInfo>::
+    Read(media::mojom::VideoCaptureDeviceInfoDataView data,
+         media::VideoCaptureDeviceInfo* output) {
+  if (!data.ReadDescriptor(&(output->descriptor)))
+    return false;
+  if (!data.ReadSupportedFormats(&(output->supported_formats)))
+    return false;
+  return true;
+}
+
 }  // namespace mojo
diff --git a/media/capture/mojo/video_capture_types_typemap_traits.h b/media/capture/mojo/video_capture_types_typemap_traits.h
index 5caf816..d55896d5 100644
--- a/media/capture/mojo/video_capture_types_typemap_traits.h
+++ b/media/capture/mojo/video_capture_types_typemap_traits.h
@@ -5,8 +5,10 @@
 #ifndef MEDIA_CAPTURE_MOJO_VIDEO_CAPTURE_TYPES_TYPEMAP_TRAITS_H_
 #define MEDIA_CAPTURE_MOJO_VIDEO_CAPTURE_TYPES_TYPEMAP_TRAITS_H_
 
-#include "media/capture/video_capture_types.h"
 #include "media/capture/mojo/video_capture_types.mojom.h"
+#include "media/capture/video/video_capture_device_descriptor.h"
+#include "media/capture/video/video_capture_device_info.h"
+#include "media/capture/video_capture_types.h"
 
 namespace mojo {
 
@@ -39,6 +41,22 @@
 };
 
 template <>
+struct EnumTraits<media::mojom::VideoCaptureApi, media::VideoCaptureApi> {
+  static media::mojom::VideoCaptureApi ToMojom(media::VideoCaptureApi input);
+  static bool FromMojom(media::mojom::VideoCaptureApi input,
+                        media::VideoCaptureApi* output);
+};
+
+template <>
+struct EnumTraits<media::mojom::VideoCaptureTransportType,
+                  media::VideoCaptureTransportType> {
+  static media::mojom::VideoCaptureTransportType ToMojom(
+      media::VideoCaptureTransportType input);
+  static bool FromMojom(media::mojom::VideoCaptureTransportType input,
+                        media::VideoCaptureTransportType* output);
+};
+
+template <>
 struct StructTraits<media::mojom::VideoCaptureFormatDataView,
                     media::VideoCaptureFormat> {
   static const gfx::Size& frame_size(const media::VideoCaptureFormat& format) {
@@ -84,6 +102,55 @@
   static bool Read(media::mojom::VideoCaptureParamsDataView data,
                    media::VideoCaptureParams* out);
 };
+
+template <>
+struct StructTraits<media::mojom::VideoCaptureDeviceDescriptorDataView,
+                    media::VideoCaptureDeviceDescriptor> {
+  static const std::string& display_name(
+      const media::VideoCaptureDeviceDescriptor& input) {
+    return input.display_name;
+  }
+
+  static const std::string& device_id(
+      const media::VideoCaptureDeviceDescriptor& input) {
+    return input.device_id;
+  }
+
+  static const std::string& model_id(
+      const media::VideoCaptureDeviceDescriptor& input) {
+    return input.model_id;
+  }
+
+  static media::VideoCaptureApi capture_api(
+      const media::VideoCaptureDeviceDescriptor& input) {
+    return input.capture_api;
+  }
+
+  static media::VideoCaptureTransportType transport_type(
+      const media::VideoCaptureDeviceDescriptor& input) {
+    return input.transport_type;
+  }
+
+  static bool Read(media::mojom::VideoCaptureDeviceDescriptorDataView data,
+                   media::VideoCaptureDeviceDescriptor* output);
+};
+
+template <>
+struct StructTraits<media::mojom::VideoCaptureDeviceInfoDataView,
+                    media::VideoCaptureDeviceInfo> {
+  static const media::VideoCaptureDeviceDescriptor& descriptor(
+      const media::VideoCaptureDeviceInfo& input) {
+    return input.descriptor;
+  }
+
+  static const std::vector<media::VideoCaptureFormat>& supported_formats(
+      const media::VideoCaptureDeviceInfo& input) {
+    return input.supported_formats;
+  }
+
+  static bool Read(media::mojom::VideoCaptureDeviceInfoDataView data,
+                   media::VideoCaptureDeviceInfo* output);
+};
 }
 
 #endif  // MEDIA_CAPTURE_MOJO_VIDEO_CAPTURE_TYPES_TYPEMAP_TRAITS_H_
diff --git a/media/remoting/BUILD.gn b/media/remoting/BUILD.gn
index bf628d7..10ea07cc 100644
--- a/media/remoting/BUILD.gn
+++ b/media/remoting/BUILD.gn
@@ -42,8 +42,6 @@
     "courier_renderer.h",
     "demuxer_stream_adapter.cc",
     "demuxer_stream_adapter.h",
-    "interstitial.cc",
-    "interstitial.h",
     "metrics.cc",
     "metrics.h",
     "remoting_cdm.cc",
@@ -69,9 +67,7 @@
     "//media",
     "//media/mojo/interfaces:remoting",
     "//mojo/public/cpp/bindings",
-    "//skia",
     "//ui/gfx",
-    "//ui/vector_icons",
   ]
 }
 
diff --git a/media/remoting/DEPS b/media/remoting/DEPS
index 9f36c275..ef8ad28 100644
--- a/media/remoting/DEPS
+++ b/media/remoting/DEPS
@@ -1,4 +1,3 @@
 include_rules = [
   "+mojo/public",
-  "+ui/vector_icons",
 ]
diff --git a/media/remoting/courier_renderer.cc b/media/remoting/courier_renderer.cc
index 33a11e5..6bc07ecc 100644
--- a/media/remoting/courier_renderer.cc
+++ b/media/remoting/courier_renderer.cc
@@ -79,9 +79,6 @@
   // Note: The constructor is running on the main thread, but will be destroyed
   // on the media thread. Therefore, all weak pointers must be dereferenced on
   // the media thread.
-  controller_->SetShowInterstitialCallback(
-      base::Bind(&CourierRenderer::RenderInterstitialAndShow,
-                 media_task_runner_, weak_factory_.GetWeakPtr()));
   const RpcBroker::ReceiveMessageCallback receive_callback =
       base::Bind(&CourierRenderer::OnMessageReceivedOnMainThread,
                  media_task_runner_, weak_factory_.GetWeakPtr());
@@ -92,23 +89,14 @@
   VLOG(2) << __func__;
   DCHECK(media_task_runner_->BelongsToCurrentThread());
 
-  // Post task on main thread to unset the interstial callback.
-  main_task_runner_->PostTask(
-      FROM_HERE,
-      base::Bind(&RendererController::SetShowInterstitialCallback, controller_,
-                 RendererController::ShowInterstitialCallback()));
-
   // Post task on main thread to unregister message receiver.
   main_task_runner_->PostTask(
       FROM_HERE, base::Bind(&RpcBroker::UnregisterMessageReceiverCallback,
                             rpc_broker_, rpc_handle_));
 
-  // If the "between sessions" interstitial is not the one currently showing,
-  // paint a blank black frame to clear remoting messaging.
-  if (interstitial_type_ != InterstitialType::BETWEEN_SESSIONS) {
-    scoped_refptr<VideoFrame> frame =
-        VideoFrame::CreateBlackFrame(gfx::Size(1280, 720));
-    PaintInterstitial(frame, InterstitialType::BETWEEN_SESSIONS);
+  if (video_renderer_sink_) {
+    video_renderer_sink_->PaintSingleFrame(
+        VideoFrame::CreateBlackFrame(gfx::Size(1280, 720)));
   }
 }
 
@@ -697,35 +685,6 @@
     base::ResetAndReturn(&flush_cb_).Run();
 }
 
-// static
-void CourierRenderer::RenderInterstitialAndShow(
-    scoped_refptr<base::SingleThreadTaskRunner> media_task_runner,
-    base::WeakPtr<CourierRenderer> self,
-    const SkBitmap& background,
-    const gfx::Size& natural_size,
-    InterstitialType type) {
-  // Note: This is running on the main thread. |self| must only be dereferenced
-  // on the media thread.
-  scoped_refptr<VideoFrame> frame =
-      RenderInterstitialFrame(background, natural_size, type);
-  if (!frame) {
-    NOTREACHED();
-    return;
-  }
-  media_task_runner->PostTask(
-      FROM_HERE, base::Bind(&CourierRenderer::PaintInterstitial, self,
-                            std::move(frame), type));
-}
-
-void CourierRenderer::PaintInterstitial(scoped_refptr<VideoFrame> frame,
-                                        InterstitialType type) {
-  DCHECK(media_task_runner_->BelongsToCurrentThread());
-  interstitial_type_ = type;
-  if (!video_renderer_sink_)
-    return;
-  video_renderer_sink_->PaintSingleFrame(frame);
-}
-
 void CourierRenderer::OnMediaTimeUpdated() {
   DCHECK(media_task_runner_->BelongsToCurrentThread());
   if (!flush_cb_.is_null())
diff --git a/media/remoting/courier_renderer.h b/media/remoting/courier_renderer.h
index 969c1f33..d8ec41a 100644
--- a/media/remoting/courier_renderer.h
+++ b/media/remoting/courier_renderer.h
@@ -19,7 +19,6 @@
 #include "media/base/pipeline_status.h"
 #include "media/base/renderer.h"
 #include "media/mojo/interfaces/remoting.mojom.h"
-#include "media/remoting/interstitial.h"
 #include "media/remoting/metrics.h"
 #include "media/remoting/rpc_broker.h"
 #include "mojo/public/cpp/system/data_pipe.h"
@@ -37,10 +36,6 @@
 // A media::Renderer implementation that proxies all operations to a remote
 // renderer via RPCs. The CourierRenderer is instantiated by
 // AdaptiveRendererFactory when media remoting is meant to take place.
-//
-// While the media content is rendered remotely, the CourierRenderer emits
-// interstitial frames locally, to the VideoRendererSink, to indicate to the
-// user that remoting is taking place.
 class CourierRenderer : public Renderer {
  public:
   // The whole class except for constructor and GetMediaTime() runs on
@@ -72,16 +67,6 @@
       base::WeakPtr<CourierRenderer> self,
       std::unique_ptr<pb::RpcMessage> message);
 
-  // Called to render the interstitial on the main thread. Then, trampoline to
-  // the media thread to have the CourierRenderer pass the resulting VideoFrame
-  // to the VideoRendererSink.
-  static void RenderInterstitialAndShow(
-      scoped_refptr<base::SingleThreadTaskRunner> media_task_runner,
-      base::WeakPtr<CourierRenderer> self,
-      const SkBitmap& background,
-      const gfx::Size& natural_size,
-      InterstitialType type);
-
  public:
   // media::Renderer implementation.
   void Initialize(MediaResource* media_resource,
@@ -134,11 +119,6 @@
   void OnStatisticsUpdate(std::unique_ptr<pb::RpcMessage> message);
   void OnDurationChange(std::unique_ptr<pb::RpcMessage> message);
 
-  // Called to pass the newly-rendered interstitial VideoFrame to the
-  // VideoRendererSink.
-  void PaintInterstitial(scoped_refptr<VideoFrame> frame,
-                         InterstitialType type);
-
   // Called when |current_media_time_| is updated.
   void OnMediaTimeUpdated();
 
@@ -226,9 +206,6 @@
   // the data flow rates for metrics.
   base::RepeatingTimer data_flow_poll_timer_;
 
-  // Current type of the interstitial frame.
-  InterstitialType interstitial_type_ = InterstitialType::BETWEEN_SESSIONS;
-
   base::WeakPtrFactory<CourierRenderer> weak_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(CourierRenderer);
diff --git a/media/remoting/interstitial.cc b/media/remoting/interstitial.cc
deleted file mode 100644
index 2548a2d0..0000000
--- a/media/remoting/interstitial.cc
+++ /dev/null
@@ -1,165 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "media/remoting/interstitial.h"
-
-#include <algorithm>  // for std::max()
-
-#include "media/base/localized_strings.h"
-#include "media/base/video_frame.h"
-#include "media/base/video_util.h"
-#include "skia/ext/image_operations.h"
-#include "third_party/skia/include/core/SkBitmap.h"
-#include "third_party/skia/include/core/SkCanvas.h"
-#include "third_party/skia/include/core/SkTypeface.h"
-#include "third_party/skia/include/effects/SkBlurImageFilter.h"
-#include "ui/gfx/color_palette.h"
-#include "ui/gfx/geometry/size.h"
-#include "ui/gfx/paint_vector_icon.h"
-#include "ui/gfx/skbitmap_operations.h"
-#include "ui/vector_icons/vector_icons.h"
-
-namespace media {
-namespace remoting {
-
-namespace {
-
-// The interstitial frame size when |background_image| is empty or has low
-// resolution. The frame height may be adjusted according to the aspect ratio of
-// the |background_image|.
-constexpr int kDefaultFrameWidth = 1280;
-constexpr int kDefaultFrameHeight = 720;
-
-SkBitmap ResizeImage(const SkBitmap& image, const gfx::Size& scaled_size) {
-  DCHECK(!scaled_size.IsEmpty());
-
-  if (image.width() == scaled_size.width() &&
-      image.height() == scaled_size.height())
-    return image;
-
-  return skia::ImageOperations::Resize(
-      image, skia::ImageOperations::RESIZE_BEST, scaled_size.width(),
-      scaled_size.height());
-}
-
-void RenderCastMessage(const gfx::Size& canvas_size,
-                       InterstitialType type,
-                       SkCanvas* canvas) {
-  DCHECK(canvas);
-  if (type == InterstitialType::BETWEEN_SESSIONS)
-    return;
-
-  // Blur the background image.
-  constexpr SkScalar kSigma = SkIntToScalar(10);
-  SkPaint paint_blur;
-  paint_blur.setImageFilter(SkBlurImageFilter::Make(kSigma, kSigma, nullptr));
-  canvas->saveLayer(0, &paint_blur);
-  canvas->restore();
-
-  // Create SkPaint for text and icon bitmap.
-  // After |paint| draws, the new canvas should look like this:
-  //       _________________________________
-  //       |                                |
-  //       |                                |
-  //       |             [   ]              |
-  //       |        Casting Video...        |
-  //       |                                |
-  //       |________________________________|
-  //
-  // Both text and icon are centered horizontally. Together, they are
-  // centered vertically.
-  SkPaint paint;
-  paint.setAntiAlias(true);
-  paint.setFilterQuality(kHigh_SkFilterQuality);
-  paint.setColor(SK_ColorLTGRAY);
-  paint.setTypeface(SkTypeface::MakeFromName(
-      "sans", SkFontStyle::FromOldStyle(SkTypeface::kNormal)));
-  const SkScalar text_height = SkIntToScalar(canvas_size.height() / 18);
-  paint.setTextSize(text_height);
-
-  // Draw the appropriate text.
-  const std::string message =
-      (type == InterstitialType::IN_SESSION
-           ? GetLocalizedStringUTF8(MEDIA_REMOTING_CASTING_VIDEO_TEXT)
-           : GetLocalizedStringUTF8(MEDIA_REMOTING_CAST_ERROR_TEXT));
-  SkScalar display_text_width =
-      paint.measureText(message.data(), message.size());
-  SkScalar sk_text_offset_x =
-      SkScalarFloorToScalar((canvas_size.width() - display_text_width) / 2.0);
-  SkScalar sk_text_offset_y =
-      SkScalarFloorToScalar((canvas_size.height() / 2.0) + text_height);
-  canvas->drawText(message.data(), message.size(), sk_text_offset_x,
-                   sk_text_offset_y, paint);
-
-  // Draw the appropriate Cast icon.
-  const gfx::VectorIcon& current_icon = type == InterstitialType::IN_SESSION
-                                            ? ui::kMediaRouterActiveIcon
-                                            : ui::kMediaRouterWarningIcon;
-  gfx::ImageSkia icon_image = gfx::CreateVectorIcon(
-      current_icon, canvas_size.height() / 6, SK_ColorLTGRAY);
-  const SkBitmap* icon_bitmap = icon_image.bitmap();
-  SkScalar sk_image_offset_x = (canvas_size.width() - icon_image.width()) / 2.0;
-  SkScalar sk_image_offset_y =
-      (canvas_size.height() / 2.0) - icon_image.height();
-  canvas->drawBitmap(*icon_bitmap, sk_image_offset_x, sk_image_offset_y,
-                     &paint);
-}
-
-gfx::Size GetCanvasSize(const gfx::Size& image_size,
-                        const gfx::Size& natural_size) {
-  if (natural_size.IsEmpty())
-    return gfx::Size(kDefaultFrameWidth, kDefaultFrameHeight);
-  int width = std::max(image_size.width(), kDefaultFrameWidth) & ~1;
-  base::CheckedNumeric<int> height = width;
-  height *= natural_size.height();
-  height /= natural_size.width();
-  height &= ~1;
-  gfx::Size result = gfx::Size(width, height.ValueOrDefault(0));
-  return result.IsEmpty() ? gfx::Size(kDefaultFrameWidth, kDefaultFrameHeight)
-                          : result;
-}
-
-}  // namespace
-
-scoped_refptr<VideoFrame> RenderInterstitialFrame(const SkBitmap& image,
-                                                  const gfx::Size& natural_size,
-                                                  InterstitialType type) {
-  gfx::Size canvas_size =
-      GetCanvasSize(gfx::Size(image.width(), image.height()), natural_size);
-  SkBitmap canvas_bitmap;
-  canvas_bitmap.allocN32Pixels(canvas_size.width(), canvas_size.height());
-  canvas_bitmap.eraseColor(SK_ColorBLACK);
-  SkCanvas canvas(canvas_bitmap);
-
-  // Draw background image on the canvas.
-  if (!image.drawsNothing()) {
-    gfx::Rect centered_rect = ComputeLetterboxRegion(
-        gfx::Rect(canvas_size), gfx::Size(image.width(), image.height()));
-    SkBitmap processed_image = ResizeImage(image, centered_rect.size());
-    if (type != InterstitialType::BETWEEN_SESSIONS) {
-      color_utils::HSL shift = {-1, 0, 0.2};  // Make monochromatic.
-      processed_image =
-          SkBitmapOperations::CreateHSLShiftedBitmap(processed_image, shift);
-    }
-    canvas.writePixels(processed_image, centered_rect.x(), centered_rect.y());
-  }
-
-  RenderCastMessage(canvas_size, type, &canvas);
-
-  // Create a new VideoFrame, copy the bitmap, then return it.
-  scoped_refptr<VideoFrame> video_frame = VideoFrame::CreateFrame(
-      PIXEL_FORMAT_I420, canvas_size, gfx::Rect(canvas_size), canvas_size,
-      base::TimeDelta());
-  if (video_frame) {
-    SkAutoLockPixels pixel_lock(canvas_bitmap);
-    CopyRGBToVideoFrame(reinterpret_cast<uint8_t*>(canvas_bitmap.getPixels()),
-                        canvas_bitmap.rowBytes(),
-                        gfx::Rect(canvas_size.width(), canvas_size.height()),
-                        video_frame.get());
-  }
-  return video_frame;
-}
-
-}  // namespace remoting
-}  // namespace media
diff --git a/media/remoting/interstitial.h b/media/remoting/interstitial.h
deleted file mode 100644
index 0703480..0000000
--- a/media/remoting/interstitial.h
+++ /dev/null
@@ -1,45 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef MEDIA_REMOTING_INTERSTITIAL_H_
-#define MEDIA_REMOTING_INTERSTITIAL_H_
-
-#include "base/memory/ref_counted.h"
-
-class SkBitmap;
-
-namespace gfx {
-class Size;
-}
-
-namespace media {
-
-class VideoFrame;
-
-namespace remoting {
-
-enum InterstitialType {
-  BETWEEN_SESSIONS,             // Show background image only.
-  IN_SESSION,                   // Show MEDIA_REMOTING_CASTING_VIDEO_TEXT.
-  ENCRYPTED_MEDIA_FATAL_ERROR,  // Show MEDIA_REMOTING_CAST_ERROR_TEXT.
-};
-
-// Render an interstitial frame--a combination of |image| in the background
-// along with a text message describing what is going on--and return it in a
-// VideoFrame. |image| may be scaled accordingly without changing its aspect
-// ratio. When it has a different aspect ratio than |natural_size|, a scaled
-// |background_image| will be centered in the frame. When |image| is empty, a
-// blank black background will be used.
-//
-// Threading note: This *must* be called on the main thread, because it uses
-// Skia's font rendering facility, which loads/caches fonts on the main thread.
-// http://crbug.com/687473.
-scoped_refptr<VideoFrame> RenderInterstitialFrame(const SkBitmap& image,
-                                                  const gfx::Size& natural_size,
-                                                  InterstitialType type);
-
-}  // namespace remoting
-}  // namespace media
-
-#endif  // MEDIA_REMOTING_INTERSTITIAL_H_
diff --git a/media/remoting/renderer_controller.cc b/media/remoting/renderer_controller.cc
index 161ebcde..998fa99 100644
--- a/media/remoting/renderer_controller.cc
+++ b/media/remoting/renderer_controller.cc
@@ -55,7 +55,6 @@
   if (client_)
     client_->ActivateViewportIntersectionMonitoring(IsRemoteSinkAvailable());
 
-  UpdateInterstitial(base::nullopt);
   UpdateAndMaybeSwitch(start_trigger, stop_trigger);
 }
 
@@ -139,18 +138,6 @@
   UpdateAndMaybeSwitch(ENABLED_BY_PAGE, DISABLED_BY_PAGE);
 }
 
-void RendererController::OnSetPoster(const GURL& poster_url) {
-  DCHECK(thread_checker_.CalledOnValidThread());
-
-  if (poster_url != poster_url_) {
-    poster_url_ = poster_url;
-    if (poster_url_.is_empty())
-      UpdateInterstitial(SkBitmap());
-    else
-      DownloadPosterImage();
-  }
-}
-
 base::WeakPtr<RpcBroker> RendererController::GetRpcBroker() const {
   DCHECK(thread_checker_.CalledOnValidThread());
 
@@ -170,7 +157,6 @@
 void RendererController::OnMetadataChanged(const PipelineMetadata& metadata) {
   DCHECK(thread_checker_.CalledOnValidThread());
 
-  const gfx::Size old_size = pipeline_metadata_.natural_size;
   const bool was_audio_codec_supported = has_audio() && IsAudioCodecSupported();
   const bool was_video_codec_supported = has_video() && IsVideoCodecSupported();
   pipeline_metadata_ = metadata;
@@ -184,9 +170,6 @@
   if (has_audio())
     is_encrypted_ |= metadata.audio_decoder_config.is_encrypted();
 
-  if (pipeline_metadata_.natural_size != old_size)
-    UpdateInterstitial(base::nullopt);
-
   StartTrigger start_trigger = UNKNOWN_START_TRIGGER;
   if (!was_audio_codec_supported && is_audio_codec_supported)
     start_trigger = SUPPORTED_AUDIO_CODEC;
@@ -274,10 +257,9 @@
   const SharedSession::SessionState state = session_->state();
   if (is_encrypted_) {
     // Due to technical limitations when playing encrypted content, once a
-    // remoting session has been started, always return true here to indicate
-    // that the CourierRenderer should continue to be used. In the stopped
-    // states, CourierRenderer will display an interstitial to notify the user
-    // that local rendering cannot be resumed.
+    // remoting session has been started, playback cannot be resumed locally
+    // without reloading the page, so leave the CourierRenderer in-place to
+    // avoid having the default renderer attempt and fail to play the content.
     //
     // TODO(miu): Revisit this once more of the encrypted-remoting impl is
     // in-place. For example, this will prevent metrics from recording session
@@ -364,99 +346,11 @@
     DCHECK(!is_encrypted_);
     DCHECK_NE(stop_trigger, UNKNOWN_STOP_TRIGGER);
     metrics_recorder_.WillStopSession(stop_trigger);
-    // Update the interstitial one last time before switching back to the local
-    // Renderer.
-    UpdateInterstitial(base::nullopt);
     client_->SwitchRenderer(false);
     session_->StopRemoting(this);
   }
 }
 
-void RendererController::SetShowInterstitialCallback(
-    const ShowInterstitialCallback& cb) {
-  DCHECK(thread_checker_.CalledOnValidThread());
-  show_interstitial_cb_ = cb;
-  UpdateInterstitial(SkBitmap());
-  if (!poster_url_.is_empty())
-    DownloadPosterImage();
-}
-
-void RendererController::SetDownloadPosterCallback(
-    const DownloadPosterCallback& cb) {
-  DCHECK(thread_checker_.CalledOnValidThread());
-  DCHECK(download_poster_cb_.is_null());
-  download_poster_cb_ = cb;
-  if (!poster_url_.is_empty())
-    DownloadPosterImage();
-}
-
-void RendererController::UpdateInterstitial(
-    const base::Optional<SkBitmap>& image) {
-  DCHECK(thread_checker_.CalledOnValidThread());
-  if (show_interstitial_cb_.is_null())
-    return;
-
-  InterstitialType type = InterstitialType::BETWEEN_SESSIONS;
-  switch (remote_rendering_started_ ? session_->state()
-                                    : SharedSession::SESSION_STOPPING) {
-    case SharedSession::SESSION_STARTED:
-      type = InterstitialType::IN_SESSION;
-      break;
-    case SharedSession::SESSION_PERMANENTLY_STOPPED:
-      type = InterstitialType::ENCRYPTED_MEDIA_FATAL_ERROR;
-      break;
-    case SharedSession::SESSION_UNAVAILABLE:
-    case SharedSession::SESSION_CAN_START:
-    case SharedSession::SESSION_STARTING:
-    case SharedSession::SESSION_STOPPING:
-      break;
-  }
-
-  bool needs_update = false;
-  if (image.has_value()) {
-    interstitial_background_ = image.value();
-    needs_update = true;
-  }
-  if (interstitial_natural_size_ != pipeline_metadata_.natural_size) {
-    interstitial_natural_size_ = pipeline_metadata_.natural_size;
-    needs_update = true;
-  }
-  if (interstitial_type_ != type) {
-    interstitial_type_ = type;
-    needs_update = true;
-  }
-  if (!needs_update)
-    return;
-
-  show_interstitial_cb_.Run(interstitial_background_,
-                            interstitial_natural_size_, interstitial_type_);
-}
-
-void RendererController::DownloadPosterImage() {
-  if (download_poster_cb_.is_null() || show_interstitial_cb_.is_null())
-    return;
-  DCHECK(!poster_url_.is_empty());
-
-  const base::TimeTicks download_start_time = base::TimeTicks::Now();
-  download_poster_cb_.Run(
-      poster_url_,
-      base::Bind(&RendererController::OnPosterImageDownloaded,
-                 weak_factory_.GetWeakPtr(), poster_url_, download_start_time));
-}
-
-void RendererController::OnPosterImageDownloaded(
-    const GURL& download_url,
-    base::TimeTicks download_start_time,
-    const SkBitmap& image) {
-  DCHECK(thread_checker_.CalledOnValidThread());
-
-  metrics_recorder_.OnPosterImageDownloaded(
-      base::TimeTicks::Now() - download_start_time, !image.drawsNothing());
-  if (download_url != poster_url_)
-    return;  // The poster image URL has changed during the download.
-  UpdateInterstitial(image);
-}
-
 void RendererController::OnRendererFatalError(StopTrigger stop_trigger) {
   DCHECK(thread_checker_.CalledOnValidThread());
 
diff --git a/media/remoting/renderer_controller.h b/media/remoting/renderer_controller.h
index bc7d6e3..10b338f8 100644
--- a/media/remoting/renderer_controller.h
+++ b/media/remoting/renderer_controller.h
@@ -9,10 +9,8 @@
 #include "base/memory/weak_ptr.h"
 #include "base/optional.h"
 #include "media/base/media_observer.h"
-#include "media/remoting/interstitial.h"
 #include "media/remoting/metrics.h"
 #include "media/remoting/shared_session.h"
-#include "third_party/skia/include/core/SkBitmap.h"
 
 namespace media {
 namespace remoting {
@@ -43,20 +41,8 @@
   void OnRemotePlaybackDisabled(bool disabled) override;
   void OnPlaying() override;
   void OnPaused() override;
-  void OnSetPoster(const GURL& poster) override;
   void SetClient(MediaObserverClient* client) override;
 
-  using ShowInterstitialCallback = base::Callback<
-      void(const SkBitmap&, const gfx::Size&, InterstitialType type)>;
-  // Called by the CourierRenderer constructor to set the callback to draw and
-  // show remoting interstial.
-  void SetShowInterstitialCallback(const ShowInterstitialCallback& cb);
-  using DownloadPosterCallback =
-      base::Callback<void(const GURL&,
-                          const base::Callback<void(const SkBitmap&)>&)>;
-  // Set the callback to download poster image.
-  void SetDownloadPosterCallback(const DownloadPosterCallback& cb);
-
   base::WeakPtr<RendererController> GetWeakPtr() {
     return weak_factory_.GetWeakPtr();
   }
@@ -113,29 +99,6 @@
   void UpdateAndMaybeSwitch(StartTrigger start_trigger,
                             StopTrigger stop_trigger);
 
-  // Called to download the poster image. Called when:
-  // 1. Poster URL changes.
-  // 2. ShowInterstitialCallback is set.
-  // 3. DownloadPosterCallback is set.
-  void DownloadPosterImage();
-
-  // Called when poster image is downloaded.
-  void OnPosterImageDownloaded(const GURL& download_url,
-                               base::TimeTicks download_start_time,
-                               const SkBitmap& image);
-
-  // Update remoting interstitial with |image|. When |image| is not set,
-  // interstitial will be drawn on previously downloaded poster image (in
-  // CourierRenderer) or black background if none was downloaded before.
-  // Call this when:
-  // 1. SetShowInterstitialCallback() is called (CourierRenderer is created).
-  // 2. The remoting session is shut down (to update the status message in the
-  //    interstitial).
-  // 3. The size of the canvas is changed (to update the background image and
-  //    the position of the status message).
-  // 4. Poster image is downloaded (to update the background image).
-  void UpdateInterstitial(const base::Optional<SkBitmap>& image);
-
   // Indicates whether this media element is in full screen.
   bool is_fullscreen_ = false;
 
@@ -180,27 +143,6 @@
   // Current pipeline metadata.
   PipelineMetadata pipeline_metadata_;
 
-  // The callback to show the remoting interstitial. It is set shortly after
-  // remoting is started (when CourierRenderer is constructed, it calls
-  // SetShowInterstitialCallback()), and is reset shortly after remoting has
-  // ended.
-  ShowInterstitialCallback show_interstitial_cb_;
-
-  // The arguments passed in the last call to the interstitial callback. On each
-  // call to UpdateInterstitial(), one or more of these may be changed. If any
-  // change, the callback will be run.
-  SkBitmap interstitial_background_;
-  gfx::Size interstitial_natural_size_;
-  InterstitialType interstitial_type_ = InterstitialType::BETWEEN_SESSIONS;
-
-  // Current poster URL, whose image will feed into the local UI.
-  GURL poster_url_;
-
-  // The callback to download the poster image. Called when |poster_url_|
-  // changes during a remoting session or the show interstial callback is set.
-  // OnPosterImageDownloaded() will be called when download completes.
-  DownloadPosterCallback download_poster_cb_;
-
   // Records session events of interest.
   SessionMetricsRecorder metrics_recorder_;
 
diff --git a/mojo/public/tools/bindings/chromium_bindings_configuration.gni b/mojo/public/tools/bindings/chromium_bindings_configuration.gni
index ca36723f..8cd72da 100644
--- a/mojo/public/tools/bindings/chromium_bindings_configuration.gni
+++ b/mojo/public/tools/bindings/chromium_bindings_configuration.gni
@@ -34,7 +34,6 @@
   "//services/ui/gpu/interfaces/typemaps.gni",
   "//services/ui/public/interfaces/cursor/typemaps.gni",
   "//services/ui/public/interfaces/ime/typemaps.gni",
-  "//services/video_capture/public/interfaces/typemaps.gni",
   "//skia/public/interfaces/typemaps.gni",
   "//third_party/WebKit/public/public_typemaps.gni",
   "//ui/base/mojo/typemaps.gni",
diff --git a/net/spdy/spdy_framer.cc b/net/spdy/spdy_framer.cc
index c7411471..a96b361 100644
--- a/net/spdy/spdy_framer.cc
+++ b/net/spdy/spdy_framer.cc
@@ -1679,11 +1679,12 @@
 
 SpdyFramer::SpdyHeaderFrameIterator::~SpdyHeaderFrameIterator() {}
 
-SpdySerializedFrame SpdyFramer::SpdyHeaderFrameIterator::NextFrame() {
+bool SpdyFramer::SpdyHeaderFrameIterator::NextFrame(
+    ZeroCopyOutputBuffer* output) {
   if (!has_next_frame_) {
     SPDY_BUG << "SpdyFramer::SpdyHeaderFrameIterator::NextFrame called without "
              << "a next frame.";
-    return SpdySerializedFrame();
+    return false;
   }
 
   size_t size_without_block =
@@ -1712,12 +1713,13 @@
   if (is_first_frame_) {
     is_first_frame_ = false;
     headers_ir_->set_end_headers(!has_next_frame_);
-    return framer_->SerializeHeadersGivenEncoding(*headers_ir_, *encoding);
+    return framer_->SerializeHeadersGivenEncoding(*headers_ir_, *encoding,
+                                                  output);
   } else {
     SpdyContinuationIR continuation_ir(headers_ir_->stream_id());
     continuation_ir.set_end_headers(!has_next_frame_);
     continuation_ir.take_encoding(std::move(encoding));
-    return framer_->SerializeContinuation(continuation_ir);
+    return framer_->SerializeContinuation(continuation_ir, output);
   }
 }
 
@@ -2086,35 +2088,42 @@
   return builder.take();
 }
 
-SpdySerializedFrame SpdyFramer::SerializeHeadersGivenEncoding(
+bool SpdyFramer::SerializeHeadersGivenEncoding(
     const SpdyHeadersIR& headers,
-    const SpdyString& encoding) const {
+    const SpdyString& encoding,
+    ZeroCopyOutputBuffer* output) const {
   size_t frame_size = GetHeaderFrameSizeSansBlock(headers) + encoding.size();
-  SpdyFrameBuilder builder(frame_size);
-  builder.BeginNewFrame(*this, SpdyFrameType::HEADERS,
-                        SerializeHeaderFrameFlags(headers),
-                        headers.stream_id());
+  SpdyFrameBuilder builder(frame_size, output);
+  bool ret = builder.BeginNewFrame(
+      *this, SpdyFrameType::HEADERS, SerializeHeaderFrameFlags(headers),
+      headers.stream_id(), frame_size - GetFrameHeaderSize());
   DCHECK_EQ(GetFrameHeaderSize(), builder.length());
 
-  if (headers.padded()) {
-    builder.WriteUInt8(headers.padding_payload_len());
+  if (ret && headers.padded()) {
+    ret &= builder.WriteUInt8(headers.padding_payload_len());
   }
 
-  if (headers.has_priority()) {
+  if (ret && headers.has_priority()) {
     int weight = ClampHttp2Weight(headers.weight());
-    builder.WriteUInt32(PackStreamDependencyValues(headers.exclusive(),
-                                                   headers.parent_stream_id()));
+    ret &= builder.WriteUInt32(PackStreamDependencyValues(
+        headers.exclusive(), headers.parent_stream_id()));
     // Per RFC 7540 section 6.3, serialized weight value is actual value - 1.
-    builder.WriteUInt8(weight - 1);
+    ret &= builder.WriteUInt8(weight - 1);
   }
 
-  builder.WriteBytes(&encoding[0], encoding.size());
+  if (ret) {
+    ret &= builder.WriteBytes(encoding.data(), encoding.size());
+  }
 
-  if (headers.padding_payload_len() > 0) {
+  if (ret && headers.padding_payload_len() > 0) {
     SpdyString padding(headers.padding_payload_len(), 0);
-    builder.WriteBytes(padding.data(), padding.length());
+    ret &= builder.WriteBytes(padding.data(), padding.length());
   }
-  return builder.take();
+
+  if (!ret) {
+    DLOG(WARNING) << "Failed to build HEADERS. Not enough space in output";
+  }
+  return ret;
 }
 
 SpdySerializedFrame SpdyFramer::SerializeContinuation(
diff --git a/net/spdy/spdy_framer.h b/net/spdy/spdy_framer.h
index c08a57d..e969a35 100644
--- a/net/spdy/spdy_framer.h
+++ b/net/spdy/spdy_framer.h
@@ -403,7 +403,9 @@
     SpdyHeaderFrameIterator(const SpdyHeaderFrameIterator&) = delete;
     SpdyHeaderFrameIterator& operator=(const SpdyHeaderFrameIterator&) = delete;
 
-    SpdySerializedFrame NextFrame();
+    // Write the next frame to |output|. Return false if the write fails.
+    // |output| can't be nullptr.
+    bool NextFrame(ZeroCopyOutputBuffer* output);
     bool HasNextFrame() const { return has_next_frame_; }
 
    private:
@@ -731,9 +733,10 @@
 
   // Serializes a HEADERS frame from the given SpdyHeadersIR and encoded header
   // block. Does not need or use the SpdyHeaderBlock inside SpdyHeadersIR.
-  SpdySerializedFrame SerializeHeadersGivenEncoding(
-      const SpdyHeadersIR& headers,
-      const SpdyString& encoding) const;
+  // Return false if the serialization fails. |encoding| should not be empty.
+  bool SerializeHeadersGivenEncoding(const SpdyHeadersIR& headers,
+                                     const SpdyString& encoding,
+                                     ZeroCopyOutputBuffer* output) const;
 
   // Calculates the number of bytes required to serialize a SpdyHeadersIR, not
   // including the bytes to be used for the encoded header set.
diff --git a/net/spdy/spdy_framer_test.cc b/net/spdy/spdy_framer_test.cc
index f00705a..db731815 100644
--- a/net/spdy/spdy_framer_test.cc
+++ b/net/spdy/spdy_framer_test.cc
@@ -43,6 +43,10 @@
 
 const int64_t kSize = 64 * 1024;
 char output_buffer[kSize] = "";
+
+// frame_list_char is used to hold frames to be compared with output_buffer.
+const int64_t buffer_size = 64 * 1024;
+char frame_list_char[buffer_size] = "";
 }
 
 class MockDebugVisitor : public SpdyFramerDebugVisitorInterface {
@@ -247,16 +251,21 @@
 
   static SpdySerializedFrame SerializeHeaders(SpdyFramer* framer,
                                               const SpdyHeadersIR& headers) {
-    SpdySerializedFrame serialized_headers_old_version =
-        framer->SerializeHeaders(headers);
+    SpdySerializedFrame serialized_headers_old_version(
+        framer->SerializeHeaders(headers));
     framer->hpack_encoder_.reset(nullptr);
     auto* saved_debug_visitor = framer->debug_visitor_;
     framer->debug_visitor_ = nullptr;
 
     std::vector<SpdySerializedFrame> frame_list;
+    ArrayOutputBuffer frame_list_buffer(frame_list_char, buffer_size);
     SpdyFramer::SpdyHeaderFrameIterator it(framer, CloneSpdyHeadersIR(headers));
     while (it.HasNextFrame()) {
-      frame_list.push_back(it.NextFrame());
+      size_t size_before = frame_list_buffer.Size();
+      it.NextFrame(&frame_list_buffer);
+      frame_list.emplace_back(
+          SpdySerializedFrame(frame_list_buffer.Begin() + size_before,
+                              frame_list_buffer.Size() - size_before, false));
     }
     framer->debug_visitor_ = saved_debug_visitor;
 
@@ -267,9 +276,6 @@
   static SpdySerializedFrame SerializeHeaders(SpdyFramer* framer,
                                               const SpdyHeadersIR& headers,
                                               ArrayOutputBuffer* output) {
-    if (output == nullptr) {
-      return SerializeHeaders(framer, headers);
-    }
     output->Reset();
     EXPECT_TRUE(framer->SerializeHeaders(headers, output));
     SpdySerializedFrame serialized_headers_old_version(output->Begin(),
@@ -279,9 +285,14 @@
     framer->debug_visitor_ = nullptr;
 
     std::vector<SpdySerializedFrame> frame_list;
+    ArrayOutputBuffer frame_list_buffer(frame_list_char, buffer_size);
     SpdyFramer::SpdyHeaderFrameIterator it(framer, CloneSpdyHeadersIR(headers));
     while (it.HasNextFrame()) {
-      frame_list.push_back(it.NextFrame());
+      size_t size_before = frame_list_buffer.Size();
+      it.NextFrame(&frame_list_buffer);
+      frame_list.emplace_back(
+          SpdySerializedFrame(frame_list_buffer.Begin() + size_before,
+                              frame_list_buffer.Size() - size_before, false));
     }
     framer->debug_visitor_ = saved_debug_visitor;
 
@@ -747,8 +758,8 @@
   headers.SetHeader("alpha", "beta");
   headers.SetHeader("gamma", "charlie");
   headers.SetHeader("cookie", "key1=value1; key2=value2");
-  SpdySerializedFrame frame(SpdyFramerPeer::SerializeHeaders(
-      &framer, headers, use_output_ ? &output_ : nullptr));
+  SpdySerializedFrame frame(
+      SpdyFramerPeer::SerializeHeaders(&framer, headers, &output_));
 
   TestSpdyVisitor visitor(SpdyFramer::DISABLE_COMPRESSION);
   visitor.SimulateInFramer(reinterpret_cast<unsigned char*>(frame.data()),
@@ -766,8 +777,8 @@
   SpdyHeadersIR headers(1);
   headers.SetHeader("alpha", "beta");
   headers.SetHeader("gamma", "charlie");
-  SpdySerializedFrame frame(SpdyFramerPeer::SerializeHeaders(
-      &framer, headers, use_output_ ? &output_ : nullptr));
+  SpdySerializedFrame frame(
+      SpdyFramerPeer::SerializeHeaders(&framer, headers, &output_));
 
   TestSpdyVisitor visitor(SpdyFramer::DISABLE_COMPRESSION);
   visitor.SimulateInFramer(reinterpret_cast<unsigned char*>(frame.data()),
@@ -825,8 +836,8 @@
       headers.set_has_priority(true);
       headers.set_parent_stream_id(parent_stream_id);
       headers.set_exclusive(exclusive);
-      SpdySerializedFrame frame(SpdyFramerPeer::SerializeHeaders(
-          &framer, headers, use_output_ ? &output_ : nullptr));
+      SpdySerializedFrame frame(
+          SpdyFramerPeer::SerializeHeaders(&framer, headers, &output_));
 
       TestSpdyVisitor visitor(SpdyFramer::DISABLE_COMPRESSION);
       visitor.SimulateInFramer(reinterpret_cast<unsigned char*>(frame.data()),
@@ -1047,8 +1058,8 @@
 
   SpdyHeadersIR headers(0);
   headers.SetHeader("alpha", "beta");
-  SpdySerializedFrame frame(SpdyFramerPeer::SerializeHeaders(
-      &framer, headers, use_output_ ? &output_ : nullptr));
+  SpdySerializedFrame frame(
+      SpdyFramerPeer::SerializeHeaders(&framer, headers, &output_));
 
   // We shouldn't have to read the whole frame before we signal an error.
   EXPECT_CALL(visitor, OnError(testing::Eq(&framer)));
@@ -1296,7 +1307,7 @@
 
   SpdyFramer framer(SpdyFramer::ENABLE_COMPRESSION);
   SpdySerializedFrame frame1(
-      SpdyFramerPeer::SerializeHeaders(&framer, headers));
+      SpdyFramerPeer::SerializeHeaders(&framer, headers, &output_));
 }
 
 TEST_P(SpdyFramerTest, Basic) {
@@ -1467,8 +1478,8 @@
   SpdyHeadersIR headers(1);
   headers.SetHeader(kHeader1, kValue1);
   headers.SetHeader(kHeader2, kValue2);
-  SpdySerializedFrame headers_frame(SpdyFramerPeer::SerializeHeaders(
-      &framer, headers, use_output_ ? &output_ : nullptr));
+  SpdySerializedFrame headers_frame(
+      SpdyFramerPeer::SerializeHeaders(&framer, headers, &output_));
 
   const char bytes[] = "this is a test test test test test!";
   SpdyDataIR data_ir(1, SpdyStringPiece(bytes, arraysize(bytes)));
@@ -1986,8 +1997,8 @@
     SpdyHeadersIR headers(1);
     headers.SetHeader("bar", "foo");
     headers.SetHeader("foo", "bar");
-    SpdySerializedFrame frame(SpdyFramerPeer::SerializeHeaders(
-        &framer, headers, use_output_ ? &output_ : nullptr));
+    SpdySerializedFrame frame(
+        SpdyFramerPeer::SerializeHeaders(&framer, headers, &output_));
     CompareFrame(kDescription, frame, kH2FrameData, arraysize(kH2FrameData));
   }
 
@@ -2017,8 +2028,8 @@
     headers.set_fin(true);
     headers.SetHeader("", "foo");
     headers.SetHeader("foo", "bar");
-    SpdySerializedFrame frame(SpdyFramerPeer::SerializeHeaders(
-        &framer, headers, use_output_ ? &output_ : nullptr));
+    SpdySerializedFrame frame(
+        SpdyFramerPeer::SerializeHeaders(&framer, headers, &output_));
     CompareFrame(kDescription, frame, kH2FrameData, arraysize(kH2FrameData));
   }
 
@@ -2048,8 +2059,8 @@
     headers_ir.set_fin(true);
     headers_ir.SetHeader("bar", "foo");
     headers_ir.SetHeader("foo", "");
-    SpdySerializedFrame frame(SpdyFramerPeer::SerializeHeaders(
-        &framer, headers_ir, use_output_ ? &output_ : nullptr));
+    SpdySerializedFrame frame(
+        SpdyFramerPeer::SerializeHeaders(&framer, headers_ir, &output_));
     CompareFrame(kDescription, frame, kH2FrameData, arraysize(kH2FrameData));
   }
 
@@ -2084,8 +2095,8 @@
     headers_ir.set_weight(220);
     headers_ir.SetHeader("bar", "foo");
     headers_ir.SetHeader("foo", "");
-    SpdySerializedFrame frame(SpdyFramerPeer::SerializeHeaders(
-        &framer, headers_ir, use_output_ ? &output_ : nullptr));
+    SpdySerializedFrame frame(
+        SpdyFramerPeer::SerializeHeaders(&framer, headers_ir, &output_));
     CompareFrame(kDescription, frame, kH2FrameData, arraysize(kH2FrameData));
   }
 
@@ -2123,8 +2134,8 @@
     headers_ir.set_parent_stream_id(0);
     headers_ir.SetHeader("bar", "foo");
     headers_ir.SetHeader("foo", "");
-    SpdySerializedFrame frame(SpdyFramerPeer::SerializeHeaders(
-        &framer, headers_ir, use_output_ ? &output_ : nullptr));
+    SpdySerializedFrame frame(
+        SpdyFramerPeer::SerializeHeaders(&framer, headers_ir, &output_));
     CompareFrame(kDescription, frame, kV4FrameData, arraysize(kV4FrameData));
   }
 
@@ -2162,8 +2173,8 @@
     headers_ir.set_parent_stream_id(0x7fffffff);
     headers_ir.SetHeader("bar", "foo");
     headers_ir.SetHeader("foo", "");
-    SpdySerializedFrame frame(SpdyFramerPeer::SerializeHeaders(
-        &framer, headers_ir, use_output_ ? &output_ : nullptr));
+    SpdySerializedFrame frame(
+        SpdyFramerPeer::SerializeHeaders(&framer, headers_ir, &output_));
     CompareFrame(kDescription, frame, kV4FrameData, arraysize(kV4FrameData));
   }
 
@@ -2199,8 +2210,8 @@
     headers_ir.SetHeader("", "foo");
     headers_ir.SetHeader("foo", "bar");
     headers_ir.set_padding_len(6);
-    SpdySerializedFrame frame(SpdyFramerPeer::SerializeHeaders(
-        &framer, headers_ir, use_output_ ? &output_ : nullptr));
+    SpdySerializedFrame frame(
+        SpdyFramerPeer::SerializeHeaders(&framer, headers_ir, &output_));
     CompareFrame(kDescription, frame, kH2FrameData, arraysize(kH2FrameData));
   }
 }
@@ -2677,8 +2688,8 @@
   SpdyHeadersIR headers_ir(1);
   headers_ir.SetHeader("alpha", "beta");
   headers_ir.SetHeader("gamma", "delta");
-  SpdySerializedFrame control_frame(SpdyFramerPeer::SerializeHeaders(
-      &framer, headers_ir, use_output_ ? &output_ : nullptr));
+  SpdySerializedFrame control_frame(
+      SpdyFramerPeer::SerializeHeaders(&framer, headers_ir, &output_));
   TestSpdyVisitor visitor(SpdyFramer::ENABLE_COMPRESSION);
   visitor.SimulateInFramer(
       reinterpret_cast<unsigned char*>(control_frame.data()),
@@ -2696,8 +2707,8 @@
   headers_ir.set_fin(true);
   headers_ir.SetHeader("alpha", "beta");
   headers_ir.SetHeader("gamma", "delta");
-  SpdySerializedFrame control_frame(SpdyFramerPeer::SerializeHeaders(
-      &framer, headers_ir, use_output_ ? &output_ : nullptr));
+  SpdySerializedFrame control_frame(
+      SpdyFramerPeer::SerializeHeaders(&framer, headers_ir, &output_));
   TestSpdyVisitor visitor(SpdyFramer::ENABLE_COMPRESSION);
   visitor.SimulateInFramer(
       reinterpret_cast<unsigned char*>(control_frame.data()),
@@ -2719,8 +2730,8 @@
   const size_t kBigValueSize = TestSpdyVisitor::sent_control_frame_max_size();
   SpdyString big_value(kBigValueSize, 'x');
   headers.SetHeader("aa", big_value);
-  SpdySerializedFrame control_frame(SpdyFramerPeer::SerializeHeaders(
-      &framer, headers, use_output_ ? &output_ : nullptr));
+  SpdySerializedFrame control_frame(
+      SpdyFramerPeer::SerializeHeaders(&framer, headers, &output_));
   EXPECT_GT(control_frame.size(),
             TestSpdyVisitor::sent_control_frame_max_size());
 
@@ -2751,7 +2762,8 @@
   SpdyFramer::SpdyHeaderFrameIterator frame_it(&framer, std::move(headers));
 
   EXPECT_TRUE(frame_it.HasNextFrame());
-  SpdySerializedFrame headers_frame(frame_it.NextFrame());
+  EXPECT_TRUE(frame_it.NextFrame(&output_));
+  SpdySerializedFrame headers_frame(output_.Begin(), output_.Size(), false);
   EXPECT_EQ(headers_frame.size(),
             TestSpdyVisitor::sent_control_frame_max_size());
 
@@ -2765,8 +2777,10 @@
   EXPECT_EQ(0, visitor.continuation_count_);
   EXPECT_EQ(0, visitor.zero_length_control_frame_header_data_count_);
 
+  output_.Reset();
   EXPECT_TRUE(frame_it.HasNextFrame());
-  SpdySerializedFrame first_cont_frame(frame_it.NextFrame());
+  EXPECT_TRUE(frame_it.NextFrame(&output_));
+  SpdySerializedFrame first_cont_frame(output_.Begin(), output_.Size(), false);
   EXPECT_EQ(first_cont_frame.size(),
             TestSpdyVisitor::sent_control_frame_max_size());
 
@@ -2779,8 +2793,10 @@
   EXPECT_EQ(1, visitor.continuation_count_);
   EXPECT_EQ(0, visitor.zero_length_control_frame_header_data_count_);
 
+  output_.Reset();
   EXPECT_TRUE(frame_it.HasNextFrame());
-  SpdySerializedFrame second_cont_frame(frame_it.NextFrame());
+  EXPECT_TRUE(frame_it.NextFrame(&output_));
+  SpdySerializedFrame second_cont_frame(output_.Begin(), output_.Size(), false);
   EXPECT_LT(second_cont_frame.size(),
             TestSpdyVisitor::sent_control_frame_max_size());
 
@@ -2838,8 +2854,8 @@
   SpdyHeadersIR headers(1);
   headers.set_fin(true);
   headers.SetHeader("aa", big_value);
-  SpdySerializedFrame control_frame(SpdyFramerPeer::SerializeHeaders(
-      &framer, headers, use_output_ ? &output_ : nullptr));
+  SpdySerializedFrame control_frame(
+      SpdyFramerPeer::SerializeHeaders(&framer, headers, &output_));
   TestSpdyVisitor visitor(SpdyFramer::ENABLE_COMPRESSION);
   visitor.set_header_buffer_size(kHeaderBufferSize);
   visitor.SimulateInFramer(
@@ -3959,8 +3975,8 @@
       headers_ir.set_exclusive(true);
     }
     headers_ir.SetHeader("foo", "bar");
-    SpdySerializedFrame frame(SpdyFramerPeer::SerializeHeaders(
-        &framer, headers_ir, use_output_ ? &output_ : nullptr));
+    SpdySerializedFrame frame(
+        SpdyFramerPeer::SerializeHeaders(&framer, headers_ir, &output_));
     uint8_t set_flags = flags & ~HEADERS_FLAG_PADDED;
     SetFrameFlags(&frame, set_flags);
 
@@ -4110,7 +4126,7 @@
     headers_ir.SetHeader("foo", "bar");
     SpdySerializedFrame frame0;
     if (use_output_) {
-      ASSERT_TRUE(framer.SerializeHeaders(headers_ir, &output_));
+      EXPECT_TRUE(framer.SerializeHeaders(headers_ir, &output_));
       frame0 = SpdySerializedFrame(output_.Begin(), output_.Size(), false);
     } else {
       frame0 = framer.SerializeHeaders(headers_ir);
@@ -4571,8 +4587,8 @@
   headers.SetHeader("alpha", "beta");
   headers.SetHeader("gamma", "charlie");
   headers.SetHeader("cookie", "key1=value1; key2=value2");
-  SpdySerializedFrame headers_frame(SpdyFramerPeer::SerializeHeaders(
-      &framer, headers, use_output_ ? &output_ : nullptr));
+  SpdySerializedFrame headers_frame(
+      SpdyFramerPeer::SerializeHeaders(&framer, headers, &output_));
 
   const char four_score[] = "Four score and seven years ago";
   SpdyDataIR four_score_ir(1, four_score);
@@ -4624,7 +4640,7 @@
   headers.SetHeader("gamma", "charlie");
   headers.SetHeader("cookie", "key1=value1; key2=value2");
   SpdySerializedFrame headers_frame(
-      SpdyFramerPeer::SerializeHeaders(&framer, headers));
+      SpdyFramerPeer::SerializeHeaders(&framer, headers, &output_));
 
   // Put them in a single buffer (new variables here to make it easy to
   // change the order and type of frames).
diff --git a/services/video_capture/device_factory_media_to_mojo_adapter.cc b/services/video_capture/device_factory_media_to_mojo_adapter.cc
index 6e6b92d3..07f6db53 100644
--- a/services/video_capture/device_factory_media_to_mojo_adapter.cc
+++ b/services/video_capture/device_factory_media_to_mojo_adapter.cc
@@ -11,9 +11,9 @@
 #include "base/stl_util.h"
 #include "base/strings/stringprintf.h"
 #include "media/capture/video/fake_video_capture_device.h"
+#include "media/capture/video/video_capture_device_info.h"
 #include "mojo/public/cpp/bindings/strong_binding.h"
 #include "services/video_capture/device_media_to_mojo_adapter.h"
-#include "services/video_capture/public/cpp/capture_settings.h"
 
 namespace video_capture {
 
@@ -39,37 +39,9 @@
 
 DeviceFactoryMediaToMojoAdapter::~DeviceFactoryMediaToMojoAdapter() = default;
 
-void DeviceFactoryMediaToMojoAdapter::EnumerateDeviceDescriptors(
-    const EnumerateDeviceDescriptorsCallback& callback) {
-  media::VideoCaptureDeviceDescriptors descriptors;
-  device_factory_->GetDeviceDescriptors(&descriptors);
-  callback.Run(std::move(descriptors));
-}
-
-void DeviceFactoryMediaToMojoAdapter::GetSupportedFormats(
-    const std::string& device_id,
-    const GetSupportedFormatsCallback& callback) {
-  media::VideoCaptureDeviceDescriptor descriptor;
-  media::VideoCaptureFormats media_formats;
-  if (LookupDescriptorFromId(device_id, &descriptor))
-    device_factory_->GetSupportedFormats(descriptor, &media_formats);
-  std::vector<I420CaptureFormat> result;
-  for (const auto& media_format : media_formats) {
-    // The Video Capture Service requires devices to deliver frames either in
-    // I420 or MJPEG formats.
-    // TODO(chfremer): Add support for Y16 format. See crbug.com/624436.
-    if (media_format.pixel_format != media::PIXEL_FORMAT_I420 &&
-        media_format.pixel_format != media::PIXEL_FORMAT_MJPEG) {
-      continue;
-    }
-    I420CaptureFormat format;
-    format.frame_size = media_format.frame_size;
-    format.frame_rate = media_format.frame_rate;
-    if (base::ContainsValue(result, format))
-      continue;  // Result already contains this format
-    result.push_back(format);
-  }
-  callback.Run(std::move(result));
+void DeviceFactoryMediaToMojoAdapter::GetDeviceInfos(
+    const GetDeviceInfosCallback& callback) {
+  NOTIMPLEMENTED();
 }
 
 void DeviceFactoryMediaToMojoAdapter::CreateDevice(
diff --git a/services/video_capture/device_factory_media_to_mojo_adapter.h b/services/video_capture/device_factory_media_to_mojo_adapter.h
index 8fcfd0ff..1eb16054 100644
--- a/services/video_capture/device_factory_media_to_mojo_adapter.h
+++ b/services/video_capture/device_factory_media_to_mojo_adapter.h
@@ -30,11 +30,7 @@
   ~DeviceFactoryMediaToMojoAdapter() override;
 
   // mojom::DeviceFactory:
-  void EnumerateDeviceDescriptors(
-      const EnumerateDeviceDescriptorsCallback& callback) override;
-  void GetSupportedFormats(
-      const std::string& device_id,
-      const GetSupportedFormatsCallback& callback) override;
+  void GetDeviceInfos(const GetDeviceInfosCallback& callback) override;
   void CreateDevice(const std::string& device_id,
                     mojom::DeviceRequest device_request,
                     const CreateDeviceCallback& callback) override;
diff --git a/services/video_capture/device_media_to_mojo_adapter.cc b/services/video_capture/device_media_to_mojo_adapter.cc
index 6f6bf77..a68c87f 100644
--- a/services/video_capture/device_media_to_mojo_adapter.cc
+++ b/services/video_capture/device_media_to_mojo_adapter.cc
@@ -25,10 +25,9 @@
   Stop();
 }
 
-void DeviceMediaToMojoAdapter::Start(const CaptureSettings& requested_settings,
-                                     mojom::ReceiverPtr receiver) {
-  media::VideoCaptureParams params;
-  requested_settings.ConvertToMediaVideoCaptureParams(&params);
+void DeviceMediaToMojoAdapter::Start(
+    const media::VideoCaptureParams& requested_settings,
+    mojom::ReceiverPtr receiver) {
   receiver.set_connection_error_handler(
       base::Bind(&DeviceMediaToMojoAdapter::OnClientConnectionErrorOrClose,
                  base::Unretained(this)));
@@ -47,7 +46,7 @@
   auto device_client = base::MakeUnique<media::VideoCaptureDeviceClient>(
       std::move(media_receiver), buffer_pool, jpeg_decoder_factory_callback_);
 
-  device_->AllocateAndStart(params, std::move(device_client));
+  device_->AllocateAndStart(requested_settings, std::move(device_client));
   device_running_ = true;
 }
 
diff --git a/services/video_capture/device_media_to_mojo_adapter.h b/services/video_capture/device_media_to_mojo_adapter.h
index d8b215d..dd3a712 100644
--- a/services/video_capture/device_media_to_mojo_adapter.h
+++ b/services/video_capture/device_media_to_mojo_adapter.h
@@ -22,7 +22,7 @@
   ~DeviceMediaToMojoAdapter() override;
 
   // mojom::Device:
-  void Start(const CaptureSettings& requested_settings,
+  void Start(const media::VideoCaptureParams& requested_settings,
              mojom::ReceiverPtr receiver) override;
 
   void Stop();
diff --git a/services/video_capture/public/cpp/capture_settings.h b/services/video_capture/public/cpp/capture_settings.h
deleted file mode 100644
index 38d0ec32..0000000
--- a/services/video_capture/public/cpp/capture_settings.h
+++ /dev/null
@@ -1,47 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef SERVICES_VIDEO_CAPTURE_PUBLIC_CPP_CAPTURE_SETTINGS_H_
-#define SERVICES_VIDEO_CAPTURE_PUBLIC_CPP_CAPTURE_SETTINGS_H_
-
-#include "media/capture/video_capture_types.h"
-#include "ui/gfx/geometry/size.h"
-
-namespace video_capture {
-
-// Cpp equivalent of Mojo struct video_capture::mojom::CaptureFormat.
-struct I420CaptureFormat {
-  gfx::Size frame_size;
-  float frame_rate;
-
-  bool operator==(const I420CaptureFormat& other) const {
-    return frame_size == other.frame_size && frame_rate == other.frame_rate;
-  }
-
-  void ConvertToMediaVideoCaptureFormat(
-      media::VideoCaptureFormat* target) const {
-    target->frame_size = frame_size;
-    target->frame_rate = frame_rate;
-    target->pixel_format = media::PIXEL_FORMAT_I420;
-    target->pixel_storage = media::PIXEL_STORAGE_CPU;
-  }
-};
-
-// Cpp equivalent of Mojo struct video_capture::mojom::CaptureSettings.
-struct CaptureSettings {
-  I420CaptureFormat format;
-  media::ResolutionChangePolicy resolution_change_policy;
-  media::PowerLineFrequency power_line_frequency;
-
-  void ConvertToMediaVideoCaptureParams(
-      media::VideoCaptureParams* target) const {
-    format.ConvertToMediaVideoCaptureFormat(&(target->requested_format));
-    target->resolution_change_policy = resolution_change_policy;
-    target->power_line_frequency = power_line_frequency;
-  }
-};
-
-}  // namespace video_capture
-
-#endif  // SERVICES_VIDEO_CAPTURE_PUBLIC_CPP_CAPTURE_SETTINGS_H_
diff --git a/services/video_capture/public/interfaces/BUILD.gn b/services/video_capture/public/interfaces/BUILD.gn
index 443588a..0d200111 100644
--- a/services/video_capture/public/interfaces/BUILD.gn
+++ b/services/video_capture/public/interfaces/BUILD.gn
@@ -6,9 +6,7 @@
 
 mojom("interfaces") {
   sources = [
-    "capture_settings.mojom",
     "device.mojom",
-    "device_descriptor.mojom",
     "device_factory.mojom",
     "receiver.mojom",
     "service.mojom",
diff --git a/services/video_capture/public/interfaces/capture_settings.mojom b/services/video_capture/public/interfaces/capture_settings.mojom
deleted file mode 100644
index 2531824..0000000
--- a/services/video_capture/public/interfaces/capture_settings.mojom
+++ /dev/null
@@ -1,21 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-module video_capture.mojom;
-
-import "media/capture/mojo/video_capture_types.mojom";
-import "ui/gfx/geometry/mojo/geometry.mojom";
-
-// This format implies a pixel format of I420
-// and a storage type of Mojo Shared Memory.
-struct I420CaptureFormat {
-  gfx.mojom.Size frame_size;
-  float frame_rate;
-};
-
-struct CaptureSettings {
-  I420CaptureFormat format;
-  media.mojom.ResolutionChangePolicy resolution_change_policy;
-  media.mojom.PowerLineFrequency power_line_frequency;
-};
diff --git a/services/video_capture/public/interfaces/capture_settings.typemap b/services/video_capture/public/interfaces/capture_settings.typemap
deleted file mode 100644
index fa0fdef..0000000
--- a/services/video_capture/public/interfaces/capture_settings.typemap
+++ /dev/null
@@ -1,21 +0,0 @@
-# Copyright 2016 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-mojom = "//services/video_capture/public/interfaces/capture_settings.mojom"
-public_headers = [
-  "//media/capture/video_capture_types.h",
-  "//services/video_capture/public/cpp/capture_settings.h",
-]
-traits_headers =
-    [ "//services/video_capture/public/interfaces/capture_settings_traits.h" ]
-sources = [
-  "//services/video_capture/public/interfaces/capture_settings_traits.cc",
-]
-public_deps = [
-  "//media/capture:capture",
-]
-type_mappings = [
-  "video_capture.mojom.I420CaptureFormat=video_capture::I420CaptureFormat",
-  "video_capture.mojom.CaptureSettings=video_capture::CaptureSettings",
-]
diff --git a/services/video_capture/public/interfaces/capture_settings_traits.cc b/services/video_capture/public/interfaces/capture_settings_traits.cc
deleted file mode 100644
index d113c77..0000000
--- a/services/video_capture/public/interfaces/capture_settings_traits.cc
+++ /dev/null
@@ -1,37 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "services/video_capture/public/interfaces/capture_settings_traits.h"
-
-#include "media/capture/mojo/video_capture_types_typemap_traits.h"
-#include "ui/gfx/geometry/mojo/geometry_struct_traits.h"
-
-namespace mojo {
-
-// static
-bool StructTraits<video_capture::mojom::I420CaptureFormatDataView,
-                  video_capture::I420CaptureFormat>::
-    Read(video_capture::mojom::I420CaptureFormatDataView data,
-         video_capture::I420CaptureFormat* out) {
-  if (!data.ReadFrameSize(&out->frame_size))
-    return false;
-  out->frame_rate = data.frame_rate();
-  return true;
-}
-
-// static
-bool StructTraits<video_capture::mojom::CaptureSettingsDataView,
-                  video_capture::CaptureSettings>::
-    Read(video_capture::mojom::CaptureSettingsDataView data,
-         video_capture::CaptureSettings* out) {
-  if (!data.ReadFormat(&out->format))
-    return false;
-  if (!data.ReadResolutionChangePolicy(&out->resolution_change_policy))
-    return false;
-  if (!data.ReadPowerLineFrequency(&out->power_line_frequency))
-    return false;
-  return true;
-}
-
-}  // namespace mojo
diff --git a/services/video_capture/public/interfaces/capture_settings_traits.h b/services/video_capture/public/interfaces/capture_settings_traits.h
deleted file mode 100644
index 1074f71..0000000
--- a/services/video_capture/public/interfaces/capture_settings_traits.h
+++ /dev/null
@@ -1,53 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef SERVICES_VIDEO_CAPTURE_PUBLIC_INTERFACES_CAPTURE_SETTINGS_TRAITS_H_
-#define SERVICES_VIDEO_CAPTURE_PUBLIC_INTERFACES_CAPTURE_SETTINGS_TRAITS_H_
-
-#include "media/capture/video_capture_types.h"
-#include "mojo/common/common_custom_types_struct_traits.h"
-#include "services/video_capture/public/interfaces/device.mojom.h"
-
-namespace mojo {
-
-template <>
-struct StructTraits<video_capture::mojom::I420CaptureFormatDataView,
-                    video_capture::I420CaptureFormat> {
-  static const gfx::Size& frame_size(
-      const video_capture::I420CaptureFormat& input) {
-    return input.frame_size;
-  }
-
-  static float frame_rate(const video_capture::I420CaptureFormat& input) {
-    return input.frame_rate;
-  }
-
-  static bool Read(video_capture::mojom::I420CaptureFormatDataView data,
-                   video_capture::I420CaptureFormat* out);
-};
-
-template <>
-struct StructTraits<video_capture::mojom::CaptureSettingsDataView,
-                    video_capture::CaptureSettings> {
-  static const video_capture::I420CaptureFormat& format(
-      const video_capture::CaptureSettings& input) {
-    return input.format;
-  }
-
-  static media::ResolutionChangePolicy resolution_change_policy(
-      const video_capture::CaptureSettings& input) {
-    return input.resolution_change_policy;
-  }
-
-  static media::PowerLineFrequency power_line_frequency(
-      const video_capture::CaptureSettings& input) {
-    return input.power_line_frequency;
-  }
-
-  static bool Read(video_capture::mojom::CaptureSettingsDataView data,
-                   video_capture::CaptureSettings* out);
-};
-}
-
-#endif  // SERVICES_VIDEO_CAPTURE_PUBLIC_INTERFACES_CAPTURE_SETTINGS_TRAITS_H_
diff --git a/services/video_capture/public/interfaces/device.mojom b/services/video_capture/public/interfaces/device.mojom
index 5aa4a002..66c740f 100644
--- a/services/video_capture/public/interfaces/device.mojom
+++ b/services/video_capture/public/interfaces/device.mojom
@@ -5,14 +5,12 @@
 module video_capture.mojom;
 
 import "media/capture/mojo/video_capture_types.mojom";
-import "services/video_capture/public/interfaces/capture_settings.mojom";
 import "services/video_capture/public/interfaces/receiver.mojom";
 
 // Represents access to a video capture device available on the machine.
 // Note: Instead of offering an explicit Stop() method, the device
 // is stopped automatically when the message pipe corresponding to either the
-// Device or the given |receiver| is closed. The frames deliverd to |receiver|
-// are guaranteed to use I420 encoding and are backed by Mojo shared buffers.
+// Device or the given |receiver| is closed.
 interface Device {
-  Start(CaptureSettings requested_settings, Receiver receiver);
+  Start(media.mojom.VideoCaptureParams requested_settings, Receiver receiver);
 };
diff --git a/services/video_capture/public/interfaces/device_descriptor.mojom b/services/video_capture/public/interfaces/device_descriptor.mojom
deleted file mode 100644
index acc34f7..0000000
--- a/services/video_capture/public/interfaces/device_descriptor.mojom
+++ /dev/null
@@ -1,33 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-module video_capture.mojom;
-
-enum VideoCaptureApi {
-  LINUX_V4L2_SINGLE_PLANE,
-  WIN_MEDIA_FOUNDATION,
-  WIN_DIRECT_SHOW,
-  MACOSX_AVFOUNDATION,
-  MACOSX_DECKLINK,
-  ANDROID_API1,
-  ANDROID_API2_LEGACY,
-  ANDROID_API2_FULL,
-  ANDROID_API2_LIMITED,
-  ANDROID_TANGO,
-  UNKNOWN
-};
-
-enum VideoCaptureTransportType {
-  // For MACOSX_AVFOUNDATION Api, identifies devices that are built-in or USB.
-  MACOSX_USB_OR_BUILT_IN,
-  OTHER_TRANSPORT
-};
-
-struct DeviceDescriptor {
-  string display_name;
-  string device_id;
-  string model_id;
-  VideoCaptureApi capture_api;
-  VideoCaptureTransportType transport_type;
-};
diff --git a/services/video_capture/public/interfaces/device_descriptor.typemap b/services/video_capture/public/interfaces/device_descriptor.typemap
deleted file mode 100644
index 4398202..0000000
--- a/services/video_capture/public/interfaces/device_descriptor.typemap
+++ /dev/null
@@ -1,14 +0,0 @@
-# Copyright 2016 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-mojom = "//services/video_capture/public/interfaces/device_descriptor.mojom"
-public_headers = [ "//media/capture/video/video_capture_device_descriptor.h" ]
-traits_headers = [ "//services/video_capture/public/interfaces/device_descriptor_struct_traits.h" ]
-sources = [
-  "//services/video_capture/public/interfaces/device_descriptor_struct_traits.cc",
-]
-deps = [
-  "//media",
-]
-type_mappings = [ "video_capture.mojom.DeviceDescriptor=media::VideoCaptureDeviceDescriptor" ]
diff --git a/services/video_capture/public/interfaces/device_descriptor_struct_traits.cc b/services/video_capture/public/interfaces/device_descriptor_struct_traits.cc
deleted file mode 100644
index 16b134c..0000000
--- a/services/video_capture/public/interfaces/device_descriptor_struct_traits.cc
+++ /dev/null
@@ -1,141 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "services/video_capture/public/interfaces/device_descriptor_struct_traits.h"
-
-namespace mojo {
-
-// static
-video_capture::mojom::VideoCaptureApi
-EnumTraits<video_capture::mojom::VideoCaptureApi,
-           media::VideoCaptureApi>::ToMojom(media::VideoCaptureApi input) {
-  switch (input) {
-    case media::VideoCaptureApi::LINUX_V4L2_SINGLE_PLANE:
-      return video_capture::mojom::VideoCaptureApi::LINUX_V4L2_SINGLE_PLANE;
-    case media::VideoCaptureApi::WIN_MEDIA_FOUNDATION:
-      return video_capture::mojom::VideoCaptureApi::WIN_MEDIA_FOUNDATION;
-    case media::VideoCaptureApi::WIN_DIRECT_SHOW:
-      return video_capture::mojom::VideoCaptureApi::WIN_DIRECT_SHOW;
-    case media::VideoCaptureApi::MACOSX_AVFOUNDATION:
-      return video_capture::mojom::VideoCaptureApi::MACOSX_AVFOUNDATION;
-    case media::VideoCaptureApi::MACOSX_DECKLINK:
-      return video_capture::mojom::VideoCaptureApi::MACOSX_DECKLINK;
-    case media::VideoCaptureApi::ANDROID_API1:
-      return video_capture::mojom::VideoCaptureApi::ANDROID_API1;
-    case media::VideoCaptureApi::ANDROID_API2_LEGACY:
-      return video_capture::mojom::VideoCaptureApi::ANDROID_API2_LEGACY;
-    case media::VideoCaptureApi::ANDROID_API2_FULL:
-      return video_capture::mojom::VideoCaptureApi::ANDROID_API2_FULL;
-    case media::VideoCaptureApi::ANDROID_API2_LIMITED:
-      return video_capture::mojom::VideoCaptureApi::ANDROID_API2_LIMITED;
-    case media::VideoCaptureApi::ANDROID_TANGO:
-      return video_capture::mojom::VideoCaptureApi::ANDROID_TANGO;
-    case media::VideoCaptureApi::UNKNOWN:
-      return video_capture::mojom::VideoCaptureApi::UNKNOWN;
-  }
-  NOTREACHED();
-  return video_capture::mojom::VideoCaptureApi::UNKNOWN;
-}
-
-// static
-bool EnumTraits<video_capture::mojom::VideoCaptureApi, media::VideoCaptureApi>::
-    FromMojom(video_capture::mojom::VideoCaptureApi input,
-              media::VideoCaptureApi* output) {
-  switch (input) {
-    case video_capture::mojom::VideoCaptureApi::LINUX_V4L2_SINGLE_PLANE:
-      *output = media::VideoCaptureApi::LINUX_V4L2_SINGLE_PLANE;
-      return true;
-    case video_capture::mojom::VideoCaptureApi::WIN_MEDIA_FOUNDATION:
-      *output = media::VideoCaptureApi::WIN_MEDIA_FOUNDATION;
-      return true;
-    case video_capture::mojom::VideoCaptureApi::WIN_DIRECT_SHOW:
-      *output = media::VideoCaptureApi::WIN_DIRECT_SHOW;
-      return true;
-    case video_capture::mojom::VideoCaptureApi::MACOSX_AVFOUNDATION:
-      *output = media::VideoCaptureApi::MACOSX_AVFOUNDATION;
-      return true;
-    case video_capture::mojom::VideoCaptureApi::MACOSX_DECKLINK:
-      *output = media::VideoCaptureApi::MACOSX_DECKLINK;
-      return true;
-    case video_capture::mojom::VideoCaptureApi::ANDROID_API1:
-      *output = media::VideoCaptureApi::ANDROID_API1;
-      return true;
-    case video_capture::mojom::VideoCaptureApi::ANDROID_API2_LEGACY:
-      *output = media::VideoCaptureApi::ANDROID_API2_LEGACY;
-      return true;
-    case video_capture::mojom::VideoCaptureApi::ANDROID_API2_FULL:
-      *output = media::VideoCaptureApi::ANDROID_API2_FULL;
-      return true;
-    case video_capture::mojom::VideoCaptureApi::ANDROID_API2_LIMITED:
-      *output = media::VideoCaptureApi::ANDROID_API2_LIMITED;
-      return true;
-    case video_capture::mojom::VideoCaptureApi::ANDROID_TANGO:
-      *output = media::VideoCaptureApi::ANDROID_TANGO;
-      return true;
-    case video_capture::mojom::VideoCaptureApi::UNKNOWN:
-      *output = media::VideoCaptureApi::UNKNOWN;
-      return true;
-  }
-  NOTREACHED();
-  return false;
-}
-
-// static
-video_capture::mojom::VideoCaptureTransportType EnumTraits<
-    video_capture::mojom::VideoCaptureTransportType,
-    media::VideoCaptureTransportType>::ToMojom(media::VideoCaptureTransportType
-                                                   input) {
-  switch (input) {
-    case media::VideoCaptureTransportType::MACOSX_USB_OR_BUILT_IN:
-      return video_capture::mojom::VideoCaptureTransportType::
-          MACOSX_USB_OR_BUILT_IN;
-    case media::VideoCaptureTransportType::OTHER_TRANSPORT:
-      return video_capture::mojom::VideoCaptureTransportType::OTHER_TRANSPORT;
-  }
-  NOTREACHED();
-  return video_capture::mojom::VideoCaptureTransportType::OTHER_TRANSPORT;
-}
-
-// static
-bool EnumTraits<video_capture::mojom::VideoCaptureTransportType,
-                media::VideoCaptureTransportType>::
-    FromMojom(video_capture::mojom::VideoCaptureTransportType input,
-              media::VideoCaptureTransportType* output) {
-  switch (input) {
-    case video_capture::mojom::VideoCaptureTransportType::
-        MACOSX_USB_OR_BUILT_IN:
-      *output = media::VideoCaptureTransportType::MACOSX_USB_OR_BUILT_IN;
-      return true;
-    case video_capture::mojom::VideoCaptureTransportType::OTHER_TRANSPORT:
-      *output = media::VideoCaptureTransportType::OTHER_TRANSPORT;
-      return true;
-  }
-  NOTREACHED();
-  return false;
-}
-
-// static
-bool StructTraits<video_capture::mojom::DeviceDescriptorDataView,
-                  media::VideoCaptureDeviceDescriptor>::
-    Read(video_capture::mojom::DeviceDescriptorDataView data,
-         media::VideoCaptureDeviceDescriptor* output) {
-  if (!data.ReadDisplayName(&(output->display_name)))
-    return false;
-
-  if (!data.ReadDeviceId(&(output->device_id)))
-    return false;
-
-  if (!data.ReadModelId(&(output->model_id)))
-    return false;
-
-  if (!data.ReadCaptureApi(&(output->capture_api)))
-    return false;
-
-  if (!data.ReadTransportType(&(output->transport_type)))
-    return false;
-
-  return true;
-}
-
-}  // namespace mojo
diff --git a/services/video_capture/public/interfaces/device_descriptor_struct_traits.h b/services/video_capture/public/interfaces/device_descriptor_struct_traits.h
deleted file mode 100644
index 3332c92..0000000
--- a/services/video_capture/public/interfaces/device_descriptor_struct_traits.h
+++ /dev/null
@@ -1,65 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef SERVICES_VIDEO_CAPTURE_PUBLIC_INTERFACES_DEVICE_DESCRIPTOR_STRUCT_TRAITS_H_
-#define SERVICES_VIDEO_CAPTURE_PUBLIC_INTERFACES_DEVICE_DESCRIPTOR_STRUCT_TRAITS_H_
-
-#include "media/capture/video/video_capture_device_descriptor.h"
-#include "services/video_capture/public/interfaces/device_descriptor.mojom.h"
-
-namespace mojo {
-
-template <>
-struct EnumTraits<video_capture::mojom::VideoCaptureApi,
-                  media::VideoCaptureApi> {
-  static video_capture::mojom::VideoCaptureApi ToMojom(
-      media::VideoCaptureApi input);
-  static bool FromMojom(video_capture::mojom::VideoCaptureApi input,
-                        media::VideoCaptureApi* output);
-};
-
-template <>
-struct EnumTraits<video_capture::mojom::VideoCaptureTransportType,
-                  media::VideoCaptureTransportType> {
-  static video_capture::mojom::VideoCaptureTransportType ToMojom(
-      media::VideoCaptureTransportType input);
-  static bool FromMojom(video_capture::mojom::VideoCaptureTransportType input,
-                        media::VideoCaptureTransportType* output);
-};
-
-template <>
-struct StructTraits<video_capture::mojom::DeviceDescriptorDataView,
-                    media::VideoCaptureDeviceDescriptor> {
-  static const std::string& display_name(
-      const media::VideoCaptureDeviceDescriptor& input) {
-    return input.display_name;
-  }
-
-  static const std::string& device_id(
-      const media::VideoCaptureDeviceDescriptor& input) {
-    return input.device_id;
-  }
-
-  static const std::string& model_id(
-      const media::VideoCaptureDeviceDescriptor& input) {
-    return input.model_id;
-  }
-
-  static media::VideoCaptureApi capture_api(
-      const media::VideoCaptureDeviceDescriptor& input) {
-    return input.capture_api;
-  }
-
-  static media::VideoCaptureTransportType transport_type(
-      const media::VideoCaptureDeviceDescriptor& input) {
-    return input.transport_type;
-  }
-
-  static bool Read(video_capture::mojom::DeviceDescriptorDataView data,
-                   media::VideoCaptureDeviceDescriptor* output);
-};
-
-}  // namespace mojo
-
-#endif  // SERVICES_VIDEO_CAPTURE_PUBLIC_INTERFACES_DEVICE_DESCRIPTOR_STRUCT_TRAITS_H_
diff --git a/services/video_capture/public/interfaces/device_factory.mojom b/services/video_capture/public/interfaces/device_factory.mojom
index 4b6bd7a9..a66434b 100644
--- a/services/video_capture/public/interfaces/device_factory.mojom
+++ b/services/video_capture/public/interfaces/device_factory.mojom
@@ -5,9 +5,7 @@
 module video_capture.mojom;
 
 import "media/capture/mojo/video_capture_types.mojom";
-import "services/video_capture/public/interfaces/device_descriptor.mojom";
 import "services/video_capture/public/interfaces/device.mojom";
-import "services/video_capture/public/interfaces/capture_settings.mojom";
 
 enum DeviceAccessResultCode {
   NOT_INITIALIZED,
@@ -16,19 +14,15 @@
 };
 
 // Enables access to a set of video capture devices.
-// Typical operation is to first call EnumerateDeviceDescriptors() to obtain
-// information about available devices. The |device_id| of the descriptors can
-// subsequently be used to either obtain the supported formats for a device
-// using GetSupportedFormats(), or to create an instance of
+// Typical operation is to first call GetDeviceInfos() to obtain
+// information about available devices. The |device_id| of the infos can
+// subsequently be used to create an instance of
 // video_capture.mojom.Device using CreateDevice().
-// The factory guarantees that no two device descriptors it returns use the
+// The factory guarantees that no two device infos it returns use the
 // same |device_id|.
 interface DeviceFactory {
-  EnumerateDeviceDescriptors()
-      => (array<DeviceDescriptor> descriptors);
-
-  GetSupportedFormats(string device_id)
-      => (array<I420CaptureFormat> supported_formats);
+  GetDeviceInfos()
+      => (array<media.mojom.VideoCaptureDeviceInfo> device_infos);
 
   // Provides exclusive access to the device identified by |device_id|.
   // The access is valid until either the message pipe associated with
diff --git a/services/video_capture/public/interfaces/typemaps.gni b/services/video_capture/public/interfaces/typemaps.gni
deleted file mode 100644
index 7a1bfe0..0000000
--- a/services/video_capture/public/interfaces/typemaps.gni
+++ /dev/null
@@ -1,8 +0,0 @@
-# Copyright 2016 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-typemaps = [
-  "//services/video_capture/public/interfaces/device_descriptor.typemap",
-  "//services/video_capture/public/interfaces/capture_settings.typemap",
-]
diff --git a/services/video_capture/test/fake_device_descriptor_test.cc b/services/video_capture/test/fake_device_descriptor_test.cc
index 55b8919f..f3d00ae3 100644
--- a/services/video_capture/test/fake_device_descriptor_test.cc
+++ b/services/video_capture/test/fake_device_descriptor_test.cc
@@ -20,13 +20,14 @@
   video_capture::ServiceTest::SetUp();
 
   base::RunLoop wait_loop;
-  EXPECT_CALL(descriptor_receiver_, Run(_))
-      .WillOnce(Invoke([this, &wait_loop](
-          const std::vector<media::VideoCaptureDeviceDescriptor>& descriptors) {
-        fake_device_descriptor_ = descriptors[0];
-        wait_loop.Quit();
-      }));
-  factory_->EnumerateDeviceDescriptors(descriptor_receiver_.Get());
+  EXPECT_CALL(device_info_receiver_, Run(_))
+      .WillOnce(
+          Invoke([this, &wait_loop](
+                     const std::vector<media::VideoCaptureDeviceInfo>& infos) {
+            fake_device_info_ = infos[0];
+            wait_loop.Quit();
+          }));
+  factory_->GetDeviceInfos(device_info_receiver_.Get());
   wait_loop.Run();
 }
 
diff --git a/services/video_capture/test/fake_device_descriptor_test.h b/services/video_capture/test/fake_device_descriptor_test.h
index e8a670f6..67b0fdf 100644
--- a/services/video_capture/test/fake_device_descriptor_test.h
+++ b/services/video_capture/test/fake_device_descriptor_test.h
@@ -19,7 +19,7 @@
   void SetUp() override;
 
  protected:
-  media::VideoCaptureDeviceDescriptor fake_device_descriptor_;
+  media::VideoCaptureDeviceInfo fake_device_info_;
 };
 
 }  // namespace video_capture
diff --git a/services/video_capture/test/fake_device_descriptor_unittest.cc b/services/video_capture/test/fake_device_descriptor_unittest.cc
index 401efe8..4ef67ac 100644
--- a/services/video_capture/test/fake_device_descriptor_unittest.cc
+++ b/services/video_capture/test/fake_device_descriptor_unittest.cc
@@ -32,7 +32,8 @@
               Run(mojom::DeviceAccessResultCode::SUCCESS))
       .Times(1);
   factory_->CreateDevice(
-      fake_device_descriptor_.device_id, mojo::MakeRequest(&device_proxy_1),
+      fake_device_info_.descriptor.device_id,
+      mojo::MakeRequest(&device_proxy_1),
       base::Bind(&MockCreateDeviceProxyCallback::Run,
                  base::Unretained(&create_device_proxy_callback_1)));
   device_proxy_1.set_connection_error_handler(
@@ -48,7 +49,8 @@
       .Times(1)
       .WillOnce(InvokeWithoutArgs([&wait_loop]() { wait_loop.Quit(); }));
   factory_->CreateDevice(
-      fake_device_descriptor_.device_id, mojo::MakeRequest(&device_proxy_2),
+      fake_device_info_.descriptor.device_id,
+      mojo::MakeRequest(&device_proxy_2),
       base::Bind(&MockCreateDeviceProxyCallback::Run,
                  base::Unretained(&create_device_proxy_callback_2)));
   device_proxy_2.set_connection_error_handler(
@@ -64,22 +66,24 @@
        DISABLED_CanUseSecondRequestedProxy) {
   mojom::DevicePtr device_proxy_1;
   factory_->CreateDevice(
-      fake_device_descriptor_.device_id, mojo::MakeRequest(&device_proxy_1),
+      fake_device_info_.descriptor.device_id,
+      mojo::MakeRequest(&device_proxy_1),
       base::Bind([](mojom::DeviceAccessResultCode result_code) {}));
 
   base::RunLoop wait_loop;
   mojom::DevicePtr device_proxy_2;
   factory_->CreateDevice(
-      fake_device_descriptor_.device_id, mojo::MakeRequest(&device_proxy_2),
+      fake_device_info_.descriptor.device_id,
+      mojo::MakeRequest(&device_proxy_2),
       base::Bind(
           [](base::RunLoop* wait_loop,
              mojom::DeviceAccessResultCode result_code) { wait_loop->Quit(); },
           &wait_loop));
   wait_loop.Run();
 
-  CaptureSettings arbitrary_requested_settings;
-  arbitrary_requested_settings.format.frame_size.SetSize(640, 480);
-  arbitrary_requested_settings.format.frame_rate = 15;
+  media::VideoCaptureParams arbitrary_requested_settings;
+  arbitrary_requested_settings.requested_format.frame_size.SetSize(640, 480);
+  arbitrary_requested_settings.requested_format.frame_rate = 15;
   arbitrary_requested_settings.resolution_change_policy =
       media::RESOLUTION_POLICY_FIXED_RESOLUTION;
   arbitrary_requested_settings.power_line_frequency =
diff --git a/services/video_capture/test/fake_device_test.cc b/services/video_capture/test/fake_device_test.cc
index 744b9df..f4ef97d 100644
--- a/services/video_capture/test/fake_device_test.cc
+++ b/services/video_capture/test/fake_device_test.cc
@@ -18,26 +18,17 @@
 void FakeDeviceTest::SetUp() {
   FakeDeviceDescriptorTest::SetUp();
 
-  // Query factory for supported formats of fake device
-  base::RunLoop wait_loop;
-  EXPECT_CALL(supported_formats_receiver_, Run(_))
-      .WillOnce(Invoke(
-          [this, &wait_loop](const std::vector<I420CaptureFormat>& formats) {
-            fake_device_first_supported_format_ = formats[0];
-            wait_loop.Quit();
-          }));
-  factory_->GetSupportedFormats(fake_device_descriptor_.device_id,
-                                supported_formats_receiver_.Get());
-  wait_loop.Run();
+  ASSERT_LE(1u, fake_device_info_.supported_formats.size());
+  fake_device_first_supported_format_ = fake_device_info_.supported_formats[0];
 
-  requestable_settings_.format = fake_device_first_supported_format_;
+  requestable_settings_.requested_format = fake_device_first_supported_format_;
   requestable_settings_.resolution_change_policy =
       media::RESOLUTION_POLICY_FIXED_RESOLUTION;
   requestable_settings_.power_line_frequency =
       media::PowerLineFrequency::FREQUENCY_DEFAULT;
 
   factory_->CreateDevice(
-      std::move(fake_device_descriptor_.device_id),
+      std::move(fake_device_info_.descriptor.device_id),
       mojo::MakeRequest(&fake_device_proxy_),
       base::Bind([](mojom::DeviceAccessResultCode result_code) {
         ASSERT_EQ(mojom::DeviceAccessResultCode::SUCCESS, result_code);
diff --git a/services/video_capture/test/fake_device_test.h b/services/video_capture/test/fake_device_test.h
index af0bde2d..013c6d32 100644
--- a/services/video_capture/test/fake_device_test.h
+++ b/services/video_capture/test/fake_device_test.h
@@ -5,8 +5,7 @@
 #ifndef SERVICES_VIDEO_CAPTURE_TEST_FAKE_DEVICE_TEST_H_
 #define SERVICES_VIDEO_CAPTURE_TEST_FAKE_DEVICE_TEST_H_
 
-#include "base/test/mock_callback.h"
-#include "services/video_capture/public/cpp/capture_settings.h"
+#include "media/capture/video_capture_types.h"
 #include "services/video_capture/test/fake_device_descriptor_test.h"
 #include "testing/gmock/include/gmock/gmock.h"
 
@@ -22,10 +21,8 @@
   void SetUp() override;
 
  protected:
-  base::MockCallback<mojom::DeviceFactory::GetSupportedFormatsCallback>
-      supported_formats_receiver_;
-  I420CaptureFormat fake_device_first_supported_format_;
-  CaptureSettings requestable_settings_;
+  media::VideoCaptureFormat fake_device_first_supported_format_;
+  media::VideoCaptureParams requestable_settings_;
   mojom::DevicePtr fake_device_proxy_;
 };
 
diff --git a/services/video_capture/test/fake_device_unittest.cc b/services/video_capture/test/fake_device_unittest.cc
index 11b107ed3..6550909 100644
--- a/services/video_capture/test/fake_device_unittest.cc
+++ b/services/video_capture/test/fake_device_unittest.cc
@@ -6,7 +6,7 @@
 #include "base/run_loop.h"
 #include "media/base/video_frame.h"
 #include "media/mojo/common/media_type_converters.h"
-#include "services/video_capture/public/cpp/capture_settings.h"
+#include "services/video_capture/device_media_to_mojo_adapter.h"
 #include "services/video_capture/public/interfaces/device_factory.mojom.h"
 #include "services/video_capture/test/fake_device_test.h"
 #include "services/video_capture/test/mock_receiver.h"
@@ -21,7 +21,6 @@
   gfx::Size size;
   media::VideoPixelFormat pixel_format;
   media::VideoFrame::StorageType storage_type;
-  bool is_mappable;
   base::TimeDelta timestamp;
 };
 
@@ -78,7 +77,6 @@
             auto& frame_info = received_frame_infos[received_frame_count];
             frame_info.pixel_format = video_frame->format();
             frame_info.storage_type = video_frame->storage_type();
-            frame_info.is_mappable = video_frame->IsMappable();
             frame_info.size = video_frame->natural_size();
             frame_info.timestamp = video_frame->timestamp();
             received_frame_count += 1;
@@ -98,8 +96,6 @@
     // Service is expected to always use STORAGE_MOJO_SHARED_BUFFER
     EXPECT_EQ(media::VideoFrame::STORAGE_MOJO_SHARED_BUFFER,
               frame_info.storage_type);
-    EXPECT_TRUE(frame_info.is_mappable);
-    EXPECT_EQ(requestable_settings_.format.frame_size, frame_info.size);
     // Timestamps are expected to increase
     if (i > 0)
       EXPECT_GT(frame_info.timestamp, previous_timestamp);
diff --git a/services/video_capture/test/mock_device_factory.h b/services/video_capture/test/mock_device_factory.h
index 3db80dc..78fd5e5 100644
--- a/services/video_capture/test/mock_device_factory.h
+++ b/services/video_capture/test/mock_device_factory.h
@@ -10,7 +10,6 @@
 #include "media/capture/video/video_capture_device_factory.h"
 #include "mojo/public/cpp/bindings/binding.h"
 #include "services/video_capture/device_media_to_mojo_adapter.h"
-#include "services/video_capture/public/interfaces/device_descriptor.mojom.h"
 
 namespace video_capture {
 
diff --git a/services/video_capture/test/mock_device_test.cc b/services/video_capture/test/mock_device_test.cc
index d557e794..9b976347 100644
--- a/services/video_capture/test/mock_device_test.cc
+++ b/services/video_capture/test/mock_device_test.cc
@@ -67,8 +67,8 @@
       mock_descriptor.device_id, mojo::MakeRequest(&device_proxy_),
       base::Bind([](mojom::DeviceAccessResultCode result_code) {}));
 
-  requested_settings_.format.frame_size = gfx::Size(800, 600);
-  requested_settings_.format.frame_rate = 15;
+  requested_settings_.requested_format.frame_size = gfx::Size(800, 600);
+  requested_settings_.requested_format.frame_rate = 15;
   requested_settings_.resolution_change_policy =
       media::RESOLUTION_POLICY_FIXED_RESOLUTION;
   requested_settings_.power_line_frequency =
diff --git a/services/video_capture/test/mock_device_test.h b/services/video_capture/test/mock_device_test.h
index 4713861..1133118c 100644
--- a/services/video_capture/test/mock_device_test.h
+++ b/services/video_capture/test/mock_device_test.h
@@ -8,7 +8,6 @@
 #include "base/test/mock_callback.h"
 #include "media/capture/video/video_capture_device.h"
 #include "services/video_capture/device_factory_media_to_mojo_adapter.h"
-#include "services/video_capture/public/cpp/capture_settings.h"
 #include "services/video_capture/public/interfaces/service.mojom.h"
 #include "services/video_capture/test/mock_device_factory.h"
 #include "services/video_capture/test/mock_receiver.h"
@@ -37,6 +36,8 @@
                void(media::mojom::PhotoSettingsPtr* settings,
                     SetPhotoOptionsCallback* callback));
   MOCK_METHOD1(DoTakePhoto, void(TakePhotoCallback* callback));
+  MOCK_METHOD2(OnUtilizationReport,
+               void(int frame_feedback_id, double utilization));
 
   void AllocateAndStart(const media::VideoCaptureParams& params,
                         std::unique_ptr<Client> client) override;
@@ -60,14 +61,14 @@
 
   mojom::DeviceFactoryPtr factory_;
   std::unique_ptr<mojo::Binding<mojom::DeviceFactory>> mock_factory_binding_;
-  base::MockCallback<mojom::DeviceFactory::EnumerateDeviceDescriptorsCallback>
-      descriptor_receiver_;
+  base::MockCallback<mojom::DeviceFactory::GetDeviceInfosCallback>
+      device_infos_receiver_;
 
   MockDevice mock_device_;
   std::unique_ptr<MockReceiver> mock_receiver_;
   mojom::DevicePtr device_proxy_;
   mojom::ReceiverPtr mock_receiver_proxy_;
-  CaptureSettings requested_settings_;
+  media::VideoCaptureParams requested_settings_;
 
  private:
   std::unique_ptr<base::MessageLoop> message_loop_;
diff --git a/services/video_capture/test/service_test.h b/services/video_capture/test/service_test.h
index 9d5b4b34..3015e33 100644
--- a/services/video_capture/test/service_test.h
+++ b/services/video_capture/test/service_test.h
@@ -23,8 +23,8 @@
  protected:
   mojom::ServicePtr service_;
   mojom::DeviceFactoryPtr factory_;
-  base::MockCallback<mojom::DeviceFactory::EnumerateDeviceDescriptorsCallback>
-      descriptor_receiver_;
+  base::MockCallback<mojom::DeviceFactory::GetDeviceInfosCallback>
+      device_info_receiver_;
 };
 
 }  // namespace video_capture
diff --git a/services/video_capture/test/service_unittest.cc b/services/video_capture/test/service_unittest.cc
index 9a59275..bc74500 100644
--- a/services/video_capture/test/service_unittest.cc
+++ b/services/video_capture/test/service_unittest.cc
@@ -20,30 +20,30 @@
 using VideoCaptureServiceTest = ServiceTest;
 
 // Tests that an answer arrives from the service when calling
-// EnumerateDeviceDescriptors().
-TEST_F(VideoCaptureServiceTest,
-       DISABLED_EnumerateDeviceDescriptorsCallbackArrives) {
+// GetDeviceInfos().
+TEST_F(VideoCaptureServiceTest, DISABLED_GetDeviceInfosCallbackArrives) {
   base::RunLoop wait_loop;
-  EXPECT_CALL(descriptor_receiver_, Run(_))
+  EXPECT_CALL(device_info_receiver_, Run(_))
       .Times(Exactly(1))
       .WillOnce(InvokeWithoutArgs([&wait_loop]() { wait_loop.Quit(); }));
 
-  factory_->EnumerateDeviceDescriptors(descriptor_receiver_.Get());
+  factory_->GetDeviceInfos(device_info_receiver_.Get());
   wait_loop.Run();
 }
 
 TEST_F(VideoCaptureServiceTest, DISABLED_FakeDeviceFactoryEnumeratesOneDevice) {
   base::RunLoop wait_loop;
   size_t num_devices_enumerated = 0;
-  EXPECT_CALL(descriptor_receiver_, Run(_))
+  EXPECT_CALL(device_info_receiver_, Run(_))
       .Times(Exactly(1))
-      .WillOnce(Invoke([&wait_loop, &num_devices_enumerated](
-          const std::vector<media::VideoCaptureDeviceDescriptor>& descriptors) {
-        num_devices_enumerated = descriptors.size();
-        wait_loop.Quit();
-      }));
+      .WillOnce(
+          Invoke([&wait_loop, &num_devices_enumerated](
+                     const std::vector<media::VideoCaptureDeviceInfo>& infos) {
+            num_devices_enumerated = infos.size();
+            wait_loop.Quit();
+          }));
 
-  factory_->EnumerateDeviceDescriptors(descriptor_receiver_.Get());
+  factory_->GetDeviceInfos(device_info_receiver_.Get());
   wait_loop.Run();
   ASSERT_EQ(1u, num_devices_enumerated);
 }
diff --git a/testing/buildbot/filters/mojo.fyi.browser_tests.filter b/testing/buildbot/filters/mojo.fyi.browser_tests.filter
index 4ecf6f36..39e2b31 100644
--- a/testing/buildbot/filters/mojo.fyi.browser_tests.filter
+++ b/testing/buildbot/filters/mojo.fyi.browser_tests.filter
@@ -39,8 +39,6 @@
 ChromeRenderViewTest.ImagesBlockedByDefault
 ChromeRenderViewTest.JSBlockSentAfterPageLoad
 ChromeRenderViewTest.PluginsTemporarilyAllowed
-ChromeServiceWorkerFetchTest.EmbedPdfOtherOrigin
-ChromeServiceWorkerFetchTest.EmbedPdfSameOrigin
 ChromeServiceWorkerManifestFetchTest.OtherOrigin
 ChromeServiceWorkerManifestFetchTest.OtherOriginUseCredentials
 ChromeServiceWorkerManifestFetchTest.SameOrigin
diff --git a/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST.json b/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST.json
index 51c1ff34..580995a 100644
--- a/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST.json
+++ b/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST.json
@@ -71605,11 +71605,6 @@
      {}
     ]
    ],
-   "cssom/css-style-attribute-modifications-expected.txt": [
-    [
-     {}
-    ]
-   ],
    "cssom/cssom-fontfacerule-expected.txt": [
     [
      {}
@@ -72980,11 +72975,6 @@
      {}
     ]
    ],
-   "editing/run/bold-expected.txt": [
-    [
-     {}
-    ]
-   ],
    "editing/run/createlink-expected.txt": [
     [
      {}
@@ -73070,26 +73060,11 @@
      {}
     ]
    ],
-   "editing/run/justifycenter-expected.txt": [
-    [
-     {}
-    ]
-   ],
-   "editing/run/justifyfull-expected.txt": [
-    [
-     {}
-    ]
-   ],
    "editing/run/justifyleft-expected.txt": [
     [
      {}
     ]
    ],
-   "editing/run/justifyright-expected.txt": [
-    [
-     {}
-    ]
-   ],
    "editing/run/misc-expected.txt": [
     [
      {}
@@ -81975,6 +81950,16 @@
      {}
     ]
    ],
+   "html/rendering/non-replaced-elements/the-page/iframe-body-margin-attributes-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "html/rendering/non-replaced-elements/the-page/iframe-marginwidth-marginheight-expected.txt": [
+    [
+     {}
+    ]
+   ],
    "html/rendering/non-replaced-elements/the-page/support/body-marginwidth-marginheight.html": [
     [
      {}
@@ -83060,6 +83045,11 @@
      {}
     ]
    ],
+   "html/semantics/forms/textfieldselection/selection-after-content-change-expected.txt": [
+    [
+     {}
+    ]
+   ],
    "html/semantics/forms/the-button-element/.gitkeep": [
     [
      {}
@@ -91070,6 +91060,11 @@
      {}
     ]
    ],
+   "streams/readable-streams/floating-point-total-queue-size.sharedworker-expected.txt": [
+    [
+     {}
+    ]
+   ],
    "streams/readable-streams/garbage-collection.js": [
     [
      {}
@@ -91150,6 +91145,11 @@
      {}
     ]
    ],
+   "streams/writable-streams/aborting.sharedworker-expected.txt": [
+    [
+     {}
+    ]
+   ],
    "streams/writable-streams/bad-strategies.js": [
     [
      {}
@@ -91190,6 +91190,11 @@
      {}
     ]
    ],
+   "streams/writable-streams/close.sharedworker-expected.txt": [
+    [
+     {}
+    ]
+   ],
    "streams/writable-streams/constructor-expected.txt": [
     [
      {}
@@ -91210,6 +91215,11 @@
      {}
     ]
    ],
+   "streams/writable-streams/constructor.sharedworker-expected.txt": [
+    [
+     {}
+    ]
+   ],
    "streams/writable-streams/count-queuing-strategy.js": [
     [
      {}
@@ -91235,6 +91245,11 @@
      {}
     ]
    ],
+   "streams/writable-streams/error.sharedworker-expected.txt": [
+    [
+     {}
+    ]
+   ],
    "streams/writable-streams/floating-point-total-queue-size.js": [
     [
      {}
@@ -91265,6 +91280,11 @@
      {}
     ]
    ],
+   "streams/writable-streams/properties.sharedworker-expected.txt": [
+    [
+     {}
+    ]
+   ],
    "streams/writable-streams/reentrant-strategy.js": [
     [
      {}
@@ -169239,10 +169259,6 @@
    "a940a84552ddcd716af743e0e8746c7582b5c760",
    "testharness"
   ],
-  "cssom/css-style-attribute-modifications-expected.txt": [
-   "eac29a7197d541b3aaa449c2cfa845065a55ce38",
-   "support"
-  ],
   "cssom/css-style-attribute-modifications.html": [
    "9199534f3b6cc473832562b1701ade3a05dde172",
    "testharness"
@@ -170576,7 +170592,7 @@
    "support"
   ],
   "dom/nodes/Document-createEvent-expected.txt": [
-   "22d957287ad20dda1d66952115fb03a4888a2b5e",
+   "9a75495dc86848b23a0d24777cdea77997c95947",
    "support"
   ],
   "dom/nodes/Document-createEvent.html": [
@@ -171096,15 +171112,15 @@
    "support"
   ],
   "dom/nodes/ParentNode-querySelector-All-xht-expected.txt": [
-   "fd138bb82b31add986f3b01fd8171f2317dc0c21",
+   "94ab38fd1bb7c2c15998a9fef71b90ee8970164d",
    "support"
   ],
   "dom/nodes/ParentNode-querySelector-All-xht.xht": [
-   "ad28a6ca45cc102865b170dac5a9837a09ad5563",
+   "5469b8ad07ecbb07d5ca46d82c71aa4e470a5c2e",
    "testharness"
   ],
   "dom/nodes/ParentNode-querySelector-All.html": [
-   "c94c9d2b9d84260e9ef7ae36a77ffceaaf18fad1",
+   "83baf7fa751b086622742908845c7a4db2e65fcb",
    "testharness"
   ],
   "dom/nodes/ParentNode-querySelector-All.js": [
@@ -171900,17 +171916,13 @@
    "testharness"
   ],
   "editing/run/backcolor-expected.txt": [
-   "290a29950ec3506ba374ee5b4324d54a473c8b82",
+   "bb8888c8c50844dd4a54f5cd03ed519c5b2ed864",
    "support"
   ],
   "editing/run/backcolor.html": [
    "72840bfcf7e62249773e925f79ba196218964373",
    "testharness"
   ],
-  "editing/run/bold-expected.txt": [
-   "8523edde1c352ca2cf1df036e2497407aea465f9",
-   "support"
-  ],
   "editing/run/bold.html": [
    "afd5a6f83bea4869dd3e26c3155f42fa97825f31",
    "testharness"
@@ -171940,7 +171952,7 @@
    "testharness"
   ],
   "editing/run/fontsize-expected.txt": [
-   "3a1f269384cc7fedf672bbe6309c19e3ca775219",
+   "9448a3dcb19b8f6c9736822235eb5356fd93c6c4",
    "support"
   ],
   "editing/run/fontsize.html": [
@@ -171948,7 +171960,7 @@
    "testharness"
   ],
   "editing/run/forecolor-expected.txt": [
-   "feb85e1b410ac5cc789b57b498a7988c9f695190",
+   "d9e0dbb1ece5e99bf6daeae163d848dab4f422dd",
    "support"
   ],
   "editing/run/forecolor.html": [
@@ -171972,7 +171984,7 @@
    "testharness"
   ],
   "editing/run/hilitecolor-expected.txt": [
-   "8db6c739cc8f74a5c9ca2d922b8cf49e85670739",
+   "3d5c6f433c10b06fa53f996aa8634fe63ef7cda4",
    "support"
   ],
   "editing/run/hilitecolor.html": [
@@ -172055,18 +172067,10 @@
    "6a4b267457182ea6de8835db633c1420b84c1c05",
    "testharness"
   ],
-  "editing/run/justifycenter-expected.txt": [
-   "34386a044c514d33fca6f39fe7f8db0229febf22",
-   "support"
-  ],
   "editing/run/justifycenter.html": [
    "8cd4e2356ad9f624c3dd60fe3c11879144667ade",
    "testharness"
   ],
-  "editing/run/justifyfull-expected.txt": [
-   "1c0a838a1aeaa868666b46036786aa5c75cf0694",
-   "support"
-  ],
   "editing/run/justifyfull.html": [
    "86c11e290c9cd638d47772f5d768a85032959255",
    "testharness"
@@ -172079,10 +172083,6 @@
    "ae457fa7fd35d9f8a23c491e0c34035ecaecf910",
    "testharness"
   ],
-  "editing/run/justifyright-expected.txt": [
-   "23e3af866fcd43154f3c21ad6be2b6add58a560b",
-   "support"
-  ],
   "editing/run/justifyright.html": [
    "a2b6ddbde460033add9355db7667fa01808cf163",
    "testharness"
@@ -172112,7 +172112,7 @@
    "testharness"
   ],
   "editing/run/removeformat-expected.txt": [
-   "c0281af06ff6f77b3032fe82f091ae149a29f8d5",
+   "db6a9aef56a586417aeecef1f73e70278dda31f7",
    "support"
   ],
   "editing/run/removeformat.html": [
@@ -183271,10 +183271,18 @@
    "0dd816530943f3a6fa3235b1d481f70ca578b6e6",
    "reftest"
   ],
+  "html/rendering/non-replaced-elements/the-page/iframe-body-margin-attributes-expected.txt": [
+   "9766efdfb114461d84439266c13050c754f6f138",
+   "support"
+  ],
   "html/rendering/non-replaced-elements/the-page/iframe-body-margin-attributes.html": [
    "68e9c15f160415a652650331f403dd324cd402e9",
    "testharness"
   ],
+  "html/rendering/non-replaced-elements/the-page/iframe-marginwidth-marginheight-expected.txt": [
+   "c2273f5968d5e30c8846117dfb955dc31c2ac3ab",
+   "support"
+  ],
   "html/rendering/non-replaced-elements/the-page/iframe-marginwidth-marginheight.html": [
    "db8b96ffd3b16bc78d937b46860de8c22d857947",
    "testharness"
@@ -185119,6 +185127,10 @@
    "e4835db1c781cad4b259b782a57b452022a50d79",
    "testharness"
   ],
+  "html/semantics/forms/textfieldselection/selection-after-content-change-expected.txt": [
+   "158d99363f5aaf434fffe94941eb9f9436261265",
+   "support"
+  ],
   "html/semantics/forms/textfieldselection/selection-after-content-change.html": [
    "e256a498b2f958dcc6efde8393a79b61e793642a",
    "testharness"
@@ -202531,6 +202543,10 @@
    "3817418bce8608ad6305acf0119fb0f2694e5531",
    "testharness"
   ],
+  "streams/readable-streams/floating-point-total-queue-size.sharedworker-expected.txt": [
+   "5761d049d4a9ea1eb9ea9dd523ea653c6f97497c",
+   "support"
+  ],
   "streams/readable-streams/floating-point-total-queue-size.sharedworker.html": [
    "00af09f46d126d6d2944d13831896e648094d1a8",
    "testharness"
@@ -202691,6 +202707,10 @@
    "b69530ebf51ccaf781ff78172be2f4607ee22c86",
    "testharness"
   ],
+  "streams/writable-streams/aborting.sharedworker-expected.txt": [
+   "78ce21b210a6a8f73647ea919060bbbee6e0b49e",
+   "support"
+  ],
   "streams/writable-streams/aborting.sharedworker.html": [
    "9e792fad19cd10a96440478cb7e0486f41b70bf4",
    "testharness"
@@ -202803,6 +202823,10 @@
    "5461a766e8047c6d50b7943d99f8ebb4c140a547",
    "testharness"
   ],
+  "streams/writable-streams/close.sharedworker-expected.txt": [
+   "e59e0f69187bec32019ecdcd9cf7a97ebc0cf18f",
+   "support"
+  ],
   "streams/writable-streams/close.sharedworker.html": [
    "b2aeb127d5ae7087b42e3fc08faaa113c84e6fd8",
    "testharness"
@@ -202835,6 +202859,10 @@
    "025f934a714ce8c52df953ba570a527cbcb88399",
    "testharness"
   ],
+  "streams/writable-streams/constructor.sharedworker-expected.txt": [
+   "742d264da53440cac0d79cadaea4e503f374cf48",
+   "support"
+  ],
   "streams/writable-streams/constructor.sharedworker.html": [
    "f6ce1491f86ee048da0f6135440b7aa5359caa22",
    "testharness"
@@ -202887,6 +202915,10 @@
    "d8a0b8b68a7a59c9bf186336a6e22f34912fb7e5",
    "testharness"
   ],
+  "streams/writable-streams/error.sharedworker-expected.txt": [
+   "bc51f025fe06daa1a605ad5443cb3c47b994f70e",
+   "support"
+  ],
   "streams/writable-streams/error.sharedworker.html": [
    "0eaf67b6f635e95fe96a95082d4015cc9f427eef",
    "testharness"
@@ -202959,6 +202991,10 @@
    "2ef8fc878249c429a89e0748e6a98fac47c1a99a",
    "testharness"
   ],
+  "streams/writable-streams/properties.sharedworker-expected.txt": [
+   "5eda14d2b172954c097a528aa24205edf481eaea",
+   "support"
+  ],
   "streams/writable-streams/properties.sharedworker.html": [
    "5c855e897d1143092ecc10b58268e6a576882184",
    "testharness"
diff --git a/third_party/WebKit/LayoutTests/svg/dom/svgpath-getPathSegAtLength-expected.txt b/third_party/WebKit/LayoutTests/svg/dom/svgpath-getPathSegAtLength-expected.txt
index c680a6e..a9da2c9e 100644
--- a/third_party/WebKit/LayoutTests/svg/dom/svgpath-getPathSegAtLength-expected.txt
+++ b/third_party/WebKit/LayoutTests/svg/dom/svgpath-getPathSegAtLength-expected.txt
@@ -1,3 +1,4 @@
+CONSOLE WARNING: line 1: SVGPathElement.getPathSegAtLength is deprecated and will be removed in M62, around October 2017. See https://www.chromestatus.com/features/5638783282184192 for more details.
 Test SVG path.getPathSegAtLength().
 
 On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
diff --git a/third_party/WebKit/Source/bindings/bindings.gni b/third_party/WebKit/Source/bindings/bindings.gni
index 6a5c991..4c423556 100644
--- a/third_party/WebKit/Source/bindings/bindings.gni
+++ b/third_party/WebKit/Source/bindings/bindings.gni
@@ -107,6 +107,8 @@
                     "core/v8/ScriptPromiseResolver.h",
                     "core/v8/ScriptRegexp.cpp",
                     "core/v8/ScriptRegexp.h",
+                    "core/v8/StringResource.cpp",
+                    "core/v8/StringResource.h",
                     "core/v8/ScriptSourceCode.cpp",
                     "core/v8/ScriptSourceCode.h",
                     "core/v8/ScriptState.cpp",
@@ -196,7 +198,6 @@
                     "core/v8/V8ResizeObserverCallbackCustom.cpp",
                     "core/v8/V8ScriptRunner.cpp",
                     "core/v8/V8ScriptRunner.h",
-                    "core/v8/V8StringResource.cpp",
                     "core/v8/V8StringResource.h",
                     "core/v8/V8ThrowException.cpp",
                     "core/v8/V8ThrowException.h",
diff --git a/third_party/WebKit/Source/bindings/core/v8/DOMWrapperMap.h b/third_party/WebKit/Source/bindings/core/v8/DOMWrapperMap.h
index a413b2e8..655c8c3 100644
--- a/third_party/WebKit/Source/bindings/core/v8/DOMWrapperMap.h
+++ b/third_party/WebKit/Source/bindings/core/v8/DOMWrapperMap.h
@@ -106,7 +106,7 @@
     typedef typename Impl::iterator Iterator;
     static size_t Size(const Impl* impl) { return impl->size(); }
     static bool Empty(Impl* impl) { return impl->IsEmpty(); }
-    static void Swap(Impl& impl, Impl& other) { impl.Swap(other); }
+    static void Swap(Impl& impl, Impl& other) { impl.swap(other); }
     static Iterator Begin(Impl* impl) { return impl->begin(); }
     static Iterator End(Impl* impl) { return impl->end(); }
     static v8::PersistentContainerValue Value(Iterator& iter) {
diff --git a/third_party/WebKit/Source/bindings/core/v8/DOMWrapperWorld.cpp b/third_party/WebKit/Source/bindings/core/v8/DOMWrapperWorld.cpp
index b6c72dbb..48433a8 100644
--- a/third_party/WebKit/Source/bindings/core/v8/DOMWrapperWorld.cpp
+++ b/third_party/WebKit/Source/bindings/core/v8/DOMWrapperWorld.cpp
@@ -40,41 +40,6 @@
 
 namespace blink {
 
-class DOMObjectHolderBase {
-  USING_FAST_MALLOC(DOMObjectHolderBase);
-
- public:
-  DOMObjectHolderBase(v8::Isolate* isolate, v8::Local<v8::Value> wrapper)
-      : wrapper_(isolate, wrapper), world_(nullptr) {}
-  virtual ~DOMObjectHolderBase() {}
-
-  DOMWrapperWorld* World() const { return world_; }
-  void SetWorld(DOMWrapperWorld* world) { world_ = world; }
-  void SetWeak(
-      void (*callback)(const v8::WeakCallbackInfo<DOMObjectHolderBase>&)) {
-    wrapper_.SetWeak(this, callback);
-  }
-
- private:
-  ScopedPersistent<v8::Value> wrapper_;
-  DOMWrapperWorld* world_;
-};
-
-template <typename T>
-class DOMObjectHolder : public DOMObjectHolderBase {
- public:
-  static std::unique_ptr<DOMObjectHolder<T>>
-  Create(v8::Isolate* isolate, T* object, v8::Local<v8::Value> wrapper) {
-    return WTF::WrapUnique(new DOMObjectHolder(isolate, object, wrapper));
-  }
-
- private:
-  DOMObjectHolder(v8::Isolate* isolate, T* object, v8::Local<v8::Value> wrapper)
-      : DOMObjectHolderBase(isolate, wrapper), object_(object) {}
-
-  Persistent<T> object_;
-};
-
 unsigned DOMWrapperWorld::number_of_non_main_worlds_in_main_thread_ = 0;
 
 // This does not contain the main world because the WorldMap needs
@@ -273,18 +238,6 @@
     IsolatedWorldContentSecurityPolicies().erase(world_id);
 }
 
-template <typename T>
-void DOMWrapperWorld::RegisterDOMObjectHolder(v8::Isolate* isolate,
-                                              T* object,
-                                              v8::Local<v8::Value> wrapper) {
-  RegisterDOMObjectHolderInternal(
-      DOMObjectHolder<T>::Create(isolate, object, wrapper));
-}
-
-template void DOMWrapperWorld::RegisterDOMObjectHolder(v8::Isolate*,
-                                                       ScriptFunction*,
-                                                       v8::Local<v8::Value>);
-
 void DOMWrapperWorld::RegisterDOMObjectHolderInternal(
     std::unique_ptr<DOMObjectHolderBase> holder_base) {
   DCHECK(!dom_object_holders_.Contains(holder_base.get()));
diff --git a/third_party/WebKit/Source/bindings/core/v8/DOMWrapperWorld.h b/third_party/WebKit/Source/bindings/core/v8/DOMWrapperWorld.h
index 08c2601..c4f2cd85 100644
--- a/third_party/WebKit/Source/bindings/core/v8/DOMWrapperWorld.h
+++ b/third_party/WebKit/Source/bindings/core/v8/DOMWrapperWorld.h
@@ -134,9 +134,50 @@
   DOMDataStore& DomDataStore() const { return *dom_data_store_; }
 
   template <typename T>
-  void RegisterDOMObjectHolder(v8::Isolate*, T*, v8::Local<v8::Value>);
+  void RegisterDOMObjectHolder(v8::Isolate* isolate,
+                               T* object,
+                               v8::Local<v8::Value> wrapper) {
+    RegisterDOMObjectHolderInternal(
+        DOMObjectHolder<T>::Create(isolate, object, wrapper));
+  }
 
  private:
+  class DOMObjectHolderBase {
+    USING_FAST_MALLOC(DOMObjectHolderBase);
+
+   public:
+    DOMObjectHolderBase(v8::Isolate* isolate, v8::Local<v8::Value> wrapper)
+        : wrapper_(isolate, wrapper), world_(nullptr) {}
+    virtual ~DOMObjectHolderBase() {}
+
+    DOMWrapperWorld* World() const { return world_; }
+    void SetWorld(DOMWrapperWorld* world) { world_ = world; }
+    void SetWeak(v8::WeakCallbackInfo<DOMObjectHolderBase>::Callback callback) {
+      wrapper_.SetWeak(this, callback);
+    }
+
+   private:
+    ScopedPersistent<v8::Value> wrapper_;
+    DOMWrapperWorld* world_;
+  };
+
+  template <typename T>
+  class DOMObjectHolder : public DOMObjectHolderBase {
+   public:
+    static std::unique_ptr<DOMObjectHolder<T>>
+    Create(v8::Isolate* isolate, T* object, v8::Local<v8::Value> wrapper) {
+      return WTF::WrapUnique(new DOMObjectHolder(isolate, object, wrapper));
+    }
+
+   private:
+    DOMObjectHolder(v8::Isolate* isolate,
+                    T* object,
+                    v8::Local<v8::Value> wrapper)
+        : DOMObjectHolderBase(isolate, wrapper), object_(object) {}
+
+    Persistent<T> object_;
+  };
+
   DOMWrapperWorld(v8::Isolate*, WorldType, int world_id);
 
   static void WeakCallbackForDOMObjectHolder(
diff --git a/third_party/WebKit/Source/bindings/core/v8/V8StringResource.cpp b/third_party/WebKit/Source/bindings/core/v8/StringResource.cpp
similarity index 70%
rename from third_party/WebKit/Source/bindings/core/v8/V8StringResource.cpp
rename to third_party/WebKit/Source/bindings/core/v8/StringResource.cpp
index ee2cc84c..930dd59 100644
--- a/third_party/WebKit/Source/bindings/core/v8/V8StringResource.cpp
+++ b/third_party/WebKit/Source/bindings/core/v8/StringResource.cpp
@@ -1,29 +1,8 @@
-/*
- * Copyright (C) 2009 Google Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
- * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
- * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
- * THE POSSIBILITY OF SUCH DAMAGE.
- */
+// 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 "bindings/core/v8/V8StringResource.h"
+#include "bindings/core/v8/StringResource.h"
 
 #include "bindings/core/v8/V8Binding.h"
 
@@ -31,14 +10,14 @@
 
 template <class StringClass>
 struct StringTraits {
-  static const StringClass& FromStringResource(WebCoreStringResourceBase*);
+  static const StringClass& FromStringResource(StringResourceBase*);
   template <typename V8StringTrait>
   static StringClass FromV8String(v8::Local<v8::String>, int);
 };
 
 template <>
 struct StringTraits<String> {
-  static const String& FromStringResource(WebCoreStringResourceBase* resource) {
+  static const String& FromStringResource(StringResourceBase* resource) {
     return resource->WebcoreString();
   }
   template <typename V8StringTrait>
@@ -47,8 +26,7 @@
 
 template <>
 struct StringTraits<AtomicString> {
-  static const AtomicString& FromStringResource(
-      WebCoreStringResourceBase* resource) {
+  static const AtomicString& FromStringResource(StringResourceBase* resource) {
     return resource->GetAtomicString();
   }
   template <typename V8StringTrait>
@@ -76,7 +54,7 @@
 template <typename V8StringTrait>
 String StringTraits<String>::FromV8String(v8::Local<v8::String> v8_string,
                                           int length) {
-  DCHECK_EQ(v8_string->Length(), length);
+  DCHECK(v8_string->Length() == length);
   typename V8StringTrait::CharType* buffer;
   String result = String::CreateUninitialized(length, buffer);
   V8StringTrait::Write(v8_string, buffer, length);
@@ -87,7 +65,7 @@
 AtomicString StringTraits<AtomicString>::FromV8String(
     v8::Local<v8::String> v8_string,
     int length) {
-  DCHECK_EQ(v8_string->Length(), length);
+  DCHECK(v8_string->Length() == length);
   static const int kInlineBufferSize =
       32 / sizeof(typename V8StringTrait::CharType);
   if (length <= kInlineBufferSize) {
@@ -110,11 +88,11 @@
     v8::String::ExternalStringResourceBase* resource =
         v8_string->GetExternalStringResourceBase(&encoding);
     if (LIKELY(!!resource)) {
-      WebCoreStringResourceBase* base;
+      StringResourceBase* base;
       if (encoding == v8::String::ONE_BYTE_ENCODING)
-        base = static_cast<WebCoreStringResource8*>(resource);
+        base = static_cast<StringResource8*>(resource);
       else
-        base = static_cast<WebCoreStringResource16*>(resource);
+        base = static_cast<StringResource16*>(resource);
       return StringTraits<StringType>::FromStringResource(base);
     }
   }
@@ -133,13 +111,11 @@
     return result;
 
   if (result.Is8Bit()) {
-    WebCoreStringResource8* string_resource =
-        new WebCoreStringResource8(result);
+    StringResource8* string_resource = new StringResource8(result);
     if (UNLIKELY(!v8_string->MakeExternal(string_resource)))
       delete string_resource;
   } else {
-    WebCoreStringResource16* string_resource =
-        new WebCoreStringResource16(result);
+    StringResource16* string_resource = new StringResource16(result);
     if (UNLIKELY(!v8_string->MakeExternal(string_resource)))
       delete string_resource;
   }
diff --git a/third_party/WebKit/Source/bindings/core/v8/StringResource.h b/third_party/WebKit/Source/bindings/core/v8/StringResource.h
new file mode 100644
index 0000000..36032fb
--- /dev/null
+++ b/third_party/WebKit/Source/bindings/core/v8/StringResource.h
@@ -0,0 +1,138 @@
+// 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 StringResource_h
+#define StringResource_h
+
+#include "core/CoreExport.h"
+#include "platform/wtf/Allocator.h"
+#include "platform/wtf/Threading.h"
+#include "platform/wtf/text/AtomicString.h"
+#include "v8/include/v8.h"
+
+namespace blink {
+
+// StringResource is a helper class for V8ExternalString. It is used
+// to manage the life-cycle of the underlying buffer of the external string.
+class StringResourceBase {
+  USING_FAST_MALLOC(StringResourceBase);
+  WTF_MAKE_NONCOPYABLE(StringResourceBase);
+
+ public:
+  explicit StringResourceBase(const String& string) : plain_string_(string) {
+#if DCHECK_IS_ON()
+    thread_id_ = WTF::CurrentThread();
+#endif
+    DCHECK(!string.IsNull());
+    v8::Isolate::GetCurrent()->AdjustAmountOfExternalAllocatedMemory(
+        string.CharactersSizeInBytes());
+  }
+
+  explicit StringResourceBase(const AtomicString& string)
+      : plain_string_(string.GetString()), atomic_string_(string) {
+#if DCHECK_IS_ON()
+    thread_id_ = WTF::CurrentThread();
+#endif
+    DCHECK(!string.IsNull());
+    v8::Isolate::GetCurrent()->AdjustAmountOfExternalAllocatedMemory(
+        string.CharactersSizeInBytes());
+  }
+
+  virtual ~StringResourceBase() {
+#if DCHECK_IS_ON()
+    DCHECK(thread_id_ == WTF::CurrentThread());
+#endif
+    int64_t reduced_external_memory = plain_string_.CharactersSizeInBytes();
+    if (plain_string_.Impl() != atomic_string_.Impl() &&
+        !atomic_string_.IsNull())
+      reduced_external_memory += atomic_string_.CharactersSizeInBytes();
+    v8::Isolate::GetCurrent()->AdjustAmountOfExternalAllocatedMemory(
+        -reduced_external_memory);
+  }
+
+  const String& WebcoreString() { return plain_string_; }
+
+  const AtomicString& GetAtomicString() {
+#if DCHECK_IS_ON()
+    DCHECK(thread_id_ == WTF::CurrentThread());
+#endif
+    if (atomic_string_.IsNull()) {
+      atomic_string_ = AtomicString(plain_string_);
+      DCHECK(!atomic_string_.IsNull());
+      if (plain_string_.Impl() != atomic_string_.Impl()) {
+        v8::Isolate::GetCurrent()->AdjustAmountOfExternalAllocatedMemory(
+            atomic_string_.CharactersSizeInBytes());
+      }
+    }
+    return atomic_string_;
+  }
+
+ protected:
+  // A shallow copy of the string. Keeps the string buffer alive until the V8
+  // engine garbage collects it.
+  String plain_string_;
+  // If this string is atomic or has been made atomic earlier the
+  // atomic string is held here. In the case where the string starts
+  // off non-atomic and becomes atomic later it is necessary to keep
+  // the original string alive because v8 may keep derived pointers
+  // into that string.
+  AtomicString atomic_string_;
+
+ private:
+#if DCHECK_IS_ON()
+  WTF::ThreadIdentifier thread_id_;
+#endif
+};
+
+class StringResource16 final : public StringResourceBase,
+                               public v8::String::ExternalStringResource {
+  WTF_MAKE_NONCOPYABLE(StringResource16);
+
+ public:
+  explicit StringResource16(const String& string) : StringResourceBase(string) {
+    DCHECK(!string.Is8Bit());
+  }
+
+  explicit StringResource16(const AtomicString& string)
+      : StringResourceBase(string) {
+    DCHECK(!string.Is8Bit());
+  }
+
+  size_t length() const override { return plain_string_.Impl()->length(); }
+  const uint16_t* data() const override {
+    return reinterpret_cast<const uint16_t*>(
+        plain_string_.Impl()->Characters16());
+  }
+};
+
+class StringResource8 final : public StringResourceBase,
+                              public v8::String::ExternalOneByteStringResource {
+  WTF_MAKE_NONCOPYABLE(StringResource8);
+
+ public:
+  explicit StringResource8(const String& string) : StringResourceBase(string) {
+    DCHECK(string.Is8Bit());
+  }
+
+  explicit StringResource8(const AtomicString& string)
+      : StringResourceBase(string) {
+    DCHECK(string.Is8Bit());
+  }
+
+  size_t length() const override { return plain_string_.Impl()->length(); }
+  const char* data() const override {
+    return reinterpret_cast<const char*>(plain_string_.Impl()->Characters8());
+  }
+};
+
+enum ExternalMode { kExternalize, kDoNotExternalize };
+
+template <typename StringType>
+CORE_EXPORT StringType V8StringToWebCoreString(v8::Local<v8::String>,
+                                               ExternalMode);
+CORE_EXPORT String Int32ToWebCoreString(int value);
+
+}  // namespace blink
+
+#endif  // StringResource_h
diff --git a/third_party/WebKit/Source/bindings/core/v8/V8GlobalValueMap.h b/third_party/WebKit/Source/bindings/core/v8/V8GlobalValueMap.h
index f3ee3b4df..db4a2e5 100644
--- a/third_party/WebKit/Source/bindings/core/v8/V8GlobalValueMap.h
+++ b/third_party/WebKit/Source/bindings/core/v8/V8GlobalValueMap.h
@@ -33,7 +33,7 @@
   typedef typename Impl::iterator Iterator;
   static size_t Size(const Impl* impl) { return impl->size(); }
   static bool Empty(Impl* impl) { return impl->IsEmpty(); }
-  static void Swap(Impl& impl, Impl& other) { impl.Swap(other); }
+  static void Swap(Impl& impl, Impl& other) { impl.swap(other); }
   static Iterator Begin(Impl* impl) { return impl->begin(); }
   static Iterator End(Impl* impl) { return impl->end(); }
   static v8::PersistentContainerValue Value(Iterator& iter) {
diff --git a/third_party/WebKit/Source/bindings/core/v8/V8StringResource.h b/third_party/WebKit/Source/bindings/core/v8/V8StringResource.h
index 847bf761..980b5a5 100644
--- a/third_party/WebKit/Source/bindings/core/v8/V8StringResource.h
+++ b/third_party/WebKit/Source/bindings/core/v8/V8StringResource.h
@@ -27,6 +27,7 @@
 #define V8StringResource_h
 
 #include "bindings/core/v8/ExceptionState.h"
+#include "bindings/core/v8/StringResource.h"
 #include "core/CoreExport.h"
 #include "platform/wtf/Allocator.h"
 #include "platform/wtf/Threading.h"
@@ -35,130 +36,6 @@
 
 namespace blink {
 
-// WebCoreStringResource is a helper class for v8ExternalString. It is used
-// to manage the life-cycle of the underlying buffer of the external string.
-class WebCoreStringResourceBase {
-  USING_FAST_MALLOC(WebCoreStringResourceBase);
-  WTF_MAKE_NONCOPYABLE(WebCoreStringResourceBase);
-
- public:
-  explicit WebCoreStringResourceBase(const String& string)
-      : plain_string_(string) {
-#if DCHECK_IS_ON()
-    thread_id_ = WTF::CurrentThread();
-#endif
-    DCHECK(!string.IsNull());
-    v8::Isolate::GetCurrent()->AdjustAmountOfExternalAllocatedMemory(
-        string.CharactersSizeInBytes());
-  }
-
-  explicit WebCoreStringResourceBase(const AtomicString& string)
-      : plain_string_(string.GetString()), atomic_string_(string) {
-#if DCHECK_IS_ON()
-    thread_id_ = WTF::CurrentThread();
-#endif
-    DCHECK(!string.IsNull());
-    v8::Isolate::GetCurrent()->AdjustAmountOfExternalAllocatedMemory(
-        string.CharactersSizeInBytes());
-  }
-
-  virtual ~WebCoreStringResourceBase() {
-#if DCHECK_IS_ON()
-    DCHECK_EQ(thread_id_, WTF::CurrentThread());
-#endif
-    int64_t reduced_external_memory = plain_string_.CharactersSizeInBytes();
-    if (plain_string_.Impl() != atomic_string_.Impl() &&
-        !atomic_string_.IsNull())
-      reduced_external_memory += atomic_string_.CharactersSizeInBytes();
-    v8::Isolate::GetCurrent()->AdjustAmountOfExternalAllocatedMemory(
-        -reduced_external_memory);
-  }
-
-  const String& WebcoreString() { return plain_string_; }
-
-  const AtomicString& GetAtomicString() {
-#if DCHECK_IS_ON()
-    DCHECK_EQ(thread_id_, WTF::CurrentThread());
-#endif
-    if (atomic_string_.IsNull()) {
-      atomic_string_ = AtomicString(plain_string_);
-      DCHECK(!atomic_string_.IsNull());
-      if (plain_string_.Impl() != atomic_string_.Impl())
-        v8::Isolate::GetCurrent()->AdjustAmountOfExternalAllocatedMemory(
-            atomic_string_.CharactersSizeInBytes());
-    }
-    return atomic_string_;
-  }
-
- protected:
-  // A shallow copy of the string. Keeps the string buffer alive until the V8
-  // engine garbage collects it.
-  String plain_string_;
-  // If this string is atomic or has been made atomic earlier the
-  // atomic string is held here. In the case where the string starts
-  // off non-atomic and becomes atomic later it is necessary to keep
-  // the original string alive because v8 may keep derived pointers
-  // into that string.
-  AtomicString atomic_string_;
-
- private:
-#if DCHECK_IS_ON()
-  WTF::ThreadIdentifier thread_id_;
-#endif
-};
-
-class WebCoreStringResource16 final
-    : public WebCoreStringResourceBase,
-      public v8::String::ExternalStringResource {
-  WTF_MAKE_NONCOPYABLE(WebCoreStringResource16);
-
- public:
-  explicit WebCoreStringResource16(const String& string)
-      : WebCoreStringResourceBase(string) {
-    DCHECK(!string.Is8Bit());
-  }
-
-  explicit WebCoreStringResource16(const AtomicString& string)
-      : WebCoreStringResourceBase(string) {
-    DCHECK(!string.Is8Bit());
-  }
-
-  size_t length() const override { return plain_string_.Impl()->length(); }
-  const uint16_t* data() const override {
-    return reinterpret_cast<const uint16_t*>(
-        plain_string_.Impl()->Characters16());
-  }
-};
-
-class WebCoreStringResource8 final
-    : public WebCoreStringResourceBase,
-      public v8::String::ExternalOneByteStringResource {
-  WTF_MAKE_NONCOPYABLE(WebCoreStringResource8);
-
- public:
-  explicit WebCoreStringResource8(const String& string)
-      : WebCoreStringResourceBase(string) {
-    DCHECK(string.Is8Bit());
-  }
-
-  explicit WebCoreStringResource8(const AtomicString& string)
-      : WebCoreStringResourceBase(string) {
-    DCHECK(string.Is8Bit());
-  }
-
-  size_t length() const override { return plain_string_.Impl()->length(); }
-  const char* data() const override {
-    return reinterpret_cast<const char*>(plain_string_.Impl()->Characters8());
-  }
-};
-
-enum ExternalMode { kExternalize, kDoNotExternalize };
-
-template <typename StringType>
-CORE_EXPORT StringType V8StringToWebCoreString(v8::Local<v8::String>,
-                                               ExternalMode);
-CORE_EXPORT String Int32ToWebCoreString(int value);
-
 // V8StringResource is an adapter class that converts V8 values to Strings
 // or AtomicStrings as appropriate, using multiple typecast operators.
 enum V8StringResourceMode {
diff --git a/third_party/WebKit/Source/bindings/core/v8/V8ValueCache.cpp b/third_party/WebKit/Source/bindings/core/v8/V8ValueCache.cpp
index 88045e5e..da82a027 100644
--- a/third_party/WebKit/Source/bindings/core/v8/V8ValueCache.cpp
+++ b/third_party/WebKit/Source/bindings/core/v8/V8ValueCache.cpp
@@ -70,8 +70,7 @@
 static v8::Local<v8::String> MakeExternalString(v8::Isolate* isolate,
                                                 const String& string) {
   if (string.Is8Bit()) {
-    WebCoreStringResource8* string_resource =
-        new WebCoreStringResource8(string);
+    StringResource8* string_resource = new StringResource8(string);
     v8::Local<v8::String> new_string;
     if (!v8::String::NewExternalOneByte(isolate, string_resource)
              .ToLocal(&new_string)) {
@@ -81,8 +80,7 @@
     return new_string;
   }
 
-  WebCoreStringResource16* string_resource =
-      new WebCoreStringResource16(string);
+  StringResource16* string_resource = new StringResource16(string);
   v8::Local<v8::String> new_string;
   if (!v8::String::NewExternalTwoByte(isolate, string_resource)
            .ToLocal(&new_string)) {
diff --git a/third_party/WebKit/Source/core/animation/css/CSSAnimationUpdate.h b/third_party/WebKit/Source/core/animation/css/CSSAnimationUpdate.h
index 89356053..2854d0b 100644
--- a/third_party/WebKit/Source/core/animation/css/CSSAnimationUpdate.h
+++ b/third_party/WebKit/Source/core/animation/css/CSSAnimationUpdate.h
@@ -238,15 +238,15 @@
 
   void AdoptActiveInterpolationsForAnimations(
       ActiveInterpolationsMap& new_map) {
-    new_map.Swap(active_interpolations_for_animations_);
+    new_map.swap(active_interpolations_for_animations_);
   }
   void AdoptActiveInterpolationsForCustomTransitions(
       ActiveInterpolationsMap& new_map) {
-    new_map.Swap(active_interpolations_for_custom_transitions_);
+    new_map.swap(active_interpolations_for_custom_transitions_);
   }
   void AdoptActiveInterpolationsForStandardTransitions(
       ActiveInterpolationsMap& new_map) {
-    new_map.Swap(active_interpolations_for_standard_transitions_);
+    new_map.swap(active_interpolations_for_standard_transitions_);
   }
   const ActiveInterpolationsMap& ActiveInterpolationsForAnimations() const {
     return active_interpolations_for_animations_;
diff --git a/third_party/WebKit/Source/core/animation/css/CSSAnimations.cpp b/third_party/WebKit/Source/core/animation/css/CSSAnimations.cpp
index 8440cb6..3dacad96 100644
--- a/third_party/WebKit/Source/core/animation/css/CSSAnimations.cpp
+++ b/third_party/WebKit/Source/core/animation/css/CSSAnimations.cpp
@@ -437,7 +437,7 @@
   if (pending_update_.IsEmpty())
     return;
 
-  previous_active_interpolations_for_animations_.Swap(
+  previous_active_interpolations_for_animations_.swap(
       pending_update_.ActiveInterpolationsForAnimations());
 
   // FIXME: cancelling, pausing, unpausing animations all query
diff --git a/third_party/WebKit/Source/core/css/resolver/StyleRuleUsageTracker.cpp b/third_party/WebKit/Source/core/css/resolver/StyleRuleUsageTracker.cpp
index 7e13ff2f..fc90f85 100644
--- a/third_party/WebKit/Source/core/css/resolver/StyleRuleUsageTracker.cpp
+++ b/third_party/WebKit/Source/core/css/resolver/StyleRuleUsageTracker.cpp
@@ -11,7 +11,7 @@
 
 StyleRuleUsageTracker::RuleListByStyleSheet StyleRuleUsageTracker::TakeDelta() {
   RuleListByStyleSheet result;
-  result.Swap(used_rules_delta_);
+  result.swap(used_rules_delta_);
   return result;
 }
 
diff --git a/third_party/WebKit/Source/core/dom/Document.cpp b/third_party/WebKit/Source/core/dom/Document.cpp
index 3b0b38b..a289eda 100644
--- a/third_party/WebKit/Source/core/dom/Document.cpp
+++ b/third_party/WebKit/Source/core/dom/Document.cpp
@@ -2422,7 +2422,7 @@
     return;
 
   HeapHashSet<Member<SVGUseElement>> elements;
-  use_elements_needing_update_.Swap(elements);
+  use_elements_needing_update_.swap(elements);
   for (SVGUseElement* element : elements)
     element->BuildPendingResource();
 }
diff --git a/third_party/WebKit/Source/core/dom/IntersectionObserverController.cpp b/third_party/WebKit/Source/core/dom/IntersectionObserverController.cpp
index eec2bfb..89a91b6e 100644
--- a/third_party/WebKit/Source/core/dom/IntersectionObserverController.cpp
+++ b/third_party/WebKit/Source/core/dom/IntersectionObserverController.cpp
@@ -66,7 +66,7 @@
     return;
   }
   HeapHashSet<Member<IntersectionObserver>> observers;
-  pending_intersection_observers_.Swap(observers);
+  pending_intersection_observers_.swap(observers);
   for (auto& observer : observers)
     observer->Deliver();
 }
diff --git a/third_party/WebKit/Source/core/dom/MutationObserverInterestGroup.cpp b/third_party/WebKit/Source/core/dom/MutationObserverInterestGroup.cpp
index 7922dbb..0ca7aa9 100644
--- a/third_party/WebKit/Source/core/dom/MutationObserverInterestGroup.cpp
+++ b/third_party/WebKit/Source/core/dom/MutationObserverInterestGroup.cpp
@@ -56,7 +56,7 @@
     MutationRecordDeliveryOptions old_value_flag)
     : old_value_flag_(old_value_flag) {
   DCHECK(!observers.IsEmpty());
-  observers_.Swap(observers);
+  observers_.swap(observers);
 }
 
 bool MutationObserverInterestGroup::IsOldValueRequested() {
diff --git a/third_party/WebKit/Source/core/dom/shadow/DistributedNodes.cpp b/third_party/WebKit/Source/core/dom/shadow/DistributedNodes.cpp
index 5cdd66a49..93411f6 100644
--- a/third_party/WebKit/Source/core/dom/shadow/DistributedNodes.cpp
+++ b/third_party/WebKit/Source/core/dom/shadow/DistributedNodes.cpp
@@ -32,7 +32,7 @@
 
 void DistributedNodes::Swap(DistributedNodes& other) {
   nodes_.Swap(other.nodes_);
-  indices_.Swap(other.indices_);
+  indices_.swap(other.indices_);
 }
 
 void DistributedNodes::Append(Node* node) {
diff --git a/third_party/WebKit/Source/core/frame/Deprecation.cpp b/third_party/WebKit/Source/core/frame/Deprecation.cpp
index 15114d5c..7d27ec7 100644
--- a/third_party/WebKit/Source/core/frame/Deprecation.cpp
+++ b/third_party/WebKit/Source/core/frame/Deprecation.cpp
@@ -436,6 +436,10 @@
       return willBeRemoved("RTCPeerConnection.getStreamById()", M62,
                            "5751819573657600");
 
+    case UseCounter::kV8SVGPathElement_GetPathSegAtLength_Method:
+      return willBeRemoved("SVGPathElement.getPathSegAtLength", M62,
+                           "5638783282184192");
+
     // Features that aren't deprecated don't have a deprecation message.
     default:
       return String();
diff --git a/third_party/WebKit/Source/core/frame/FrameView.cpp b/third_party/WebKit/Source/core/frame/FrameView.cpp
index e5a5957b..75927b34 100644
--- a/third_party/WebKit/Source/core/frame/FrameView.cpp
+++ b/third_party/WebKit/Source/core/frame/FrameView.cpp
@@ -2463,7 +2463,7 @@
   // Need to swap because script will run inside the below loop and invalidate
   // the iterator.
   EmbeddedObjectSet objects;
-  objects.Swap(part_update_set_);
+  objects.swap(part_update_set_);
 
   for (const auto& embedded_object : objects) {
     LayoutEmbeddedObject& object = *embedded_object;
diff --git a/third_party/WebKit/Source/core/html/HTMLFrameOwnerElement.cpp b/third_party/WebKit/Source/core/html/HTMLFrameOwnerElement.cpp
index f7eb047..67e3927 100644
--- a/third_party/WebKit/Source/core/html/HTMLFrameOwnerElement.cpp
+++ b/third_party/WebKit/Source/core/html/HTMLFrameOwnerElement.cpp
@@ -76,7 +76,7 @@
 void HTMLFrameOwnerElement::UpdateSuspendScope::
     PerformDeferredWidgetTreeOperations() {
   FrameViewBaseToParentMap map;
-  WidgetNewParentMap().Swap(map);
+  WidgetNewParentMap().swap(map);
   for (const auto& frame_view_base : map) {
     FrameViewBase* child = frame_view_base.key.Get();
     FrameView* current_parent = ToFrameView(child->Parent());
@@ -93,7 +93,7 @@
 
   {
     FrameViewBaseSet set;
-    WidgetsPendingTemporaryRemovalFromParent().Swap(set);
+    WidgetsPendingTemporaryRemovalFromParent().swap(set);
     for (const auto& frame_view_base : set) {
       FrameView* current_parent = ToFrameView(frame_view_base->Parent());
       if (current_parent)
diff --git a/third_party/WebKit/Source/core/inspector/InspectorCSSAgent.cpp b/third_party/WebKit/Source/core/inspector/InspectorCSSAgent.cpp
index 009dd5c..991ca68 100644
--- a/third_party/WebKit/Source/core/inspector/InspectorCSSAgent.cpp
+++ b/third_party/WebKit/Source/core/inspector/InspectorCSSAgent.cpp
@@ -707,7 +707,7 @@
   if (!invalidated_documents_.size())
     return;
   HeapHashSet<Member<Document>> invalidated_documents;
-  invalidated_documents_.Swap(invalidated_documents);
+  invalidated_documents_.swap(invalidated_documents);
   for (Document* document : invalidated_documents)
     UpdateActiveStyleSheets(document);
 }
diff --git a/third_party/WebKit/Source/core/inspector/InspectorResourceContentLoader.cpp b/third_party/WebKit/Source/core/inspector/InspectorResourceContentLoader.cpp
index f25c8981..4844b95 100644
--- a/third_party/WebKit/Source/core/inspector/InspectorResourceContentLoader.cpp
+++ b/third_party/WebKit/Source/core/inspector/InspectorResourceContentLoader.cpp
@@ -206,7 +206,7 @@
 
 void InspectorResourceContentLoader::Stop() {
   HeapHashSet<Member<ResourceClient>> pending_resource_clients;
-  pending_resource_clients_.Swap(pending_resource_clients);
+  pending_resource_clients_.swap(pending_resource_clients);
   for (const auto& client : pending_resource_clients)
     client->loader_ = nullptr;
   resources_.Clear();
@@ -224,7 +224,7 @@
   if (!HasFinished())
     return;
   HashMap<int, Callbacks> callbacks;
-  callbacks.Swap(callbacks_);
+  callbacks.swap(callbacks_);
   for (const auto& key_value : callbacks) {
     for (const auto& callback : key_value.value)
       (*callback)();
diff --git a/third_party/WebKit/Source/core/inspector/NetworkResourcesData.cpp b/third_party/WebKit/Source/core/inspector/NetworkResourcesData.cpp
index 3a46dac3..5ee5dd90 100644
--- a/third_party/WebKit/Source/core/inspector/NetworkResourcesData.cpp
+++ b/third_party/WebKit/Source/core/inspector/NetworkResourcesData.cpp
@@ -392,7 +392,7 @@
         resource_data->LoaderId() == preserved_loader_id)
       preserved_map.Set(resource.key, resource.value);
   }
-  request_id_to_resource_data_map_.Swap(preserved_map);
+  request_id_to_resource_data_map_.swap(preserved_map);
 
   reused_xhr_replay_data_request_ids_.Clear();
 }
diff --git a/third_party/WebKit/Source/core/layout/LayoutObject.h b/third_party/WebKit/Source/core/layout/LayoutObject.h
index dbb06ae2..7c67bcc 100644
--- a/third_party/WebKit/Source/core/layout/LayoutObject.h
+++ b/third_party/WebKit/Source/core/layout/LayoutObject.h
@@ -1662,7 +1662,7 @@
   bool ShouldDoFullPaintInvalidation() const {
     return bitfields_.FullPaintInvalidationReason() != kPaintInvalidationNone;
   }
-  virtual void SetShouldDoFullPaintInvalidation(
+  void SetShouldDoFullPaintInvalidation(
       PaintInvalidationReason = kPaintInvalidationFull);
   void SetShouldDoFullPaintInvalidationWithoutGeometryChange(
       PaintInvalidationReason = kPaintInvalidationFull);
diff --git a/third_party/WebKit/Source/core/svg/SVGDocumentExtensions.cpp b/third_party/WebKit/Source/core/svg/SVGDocumentExtensions.cpp
index 3d9d7c37..7250533 100644
--- a/third_party/WebKit/Source/core/svg/SVGDocumentExtensions.cpp
+++ b/third_party/WebKit/Source/core/svg/SVGDocumentExtensions.cpp
@@ -62,7 +62,7 @@
   }
 
   SVGElementSet web_animations_pending_svg_elements;
-  web_animations_pending_svg_elements.Swap(
+  web_animations_pending_svg_elements.swap(
       web_animations_pending_svg_elements_);
 
   // TODO(alancutter): Make SVG animation effect application a separate document
diff --git a/third_party/WebKit/Source/core/svg/SVGPathElement.idl b/third_party/WebKit/Source/core/svg/SVGPathElement.idl
index 5acd7d87..ce21df9 100644
--- a/third_party/WebKit/Source/core/svg/SVGPathElement.idl
+++ b/third_party/WebKit/Source/core/svg/SVGPathElement.idl
@@ -27,5 +27,5 @@
 // https://svgwg.org/svg2-draft/paths.html#InterfaceSVGPathElement
 
 interface SVGPathElement : SVGGeometryElement {
-    [Measure] unsigned long getPathSegAtLength(float distance);
+    [DeprecateAs=V8SVGPathElement_GetPathSegAtLength_Method] unsigned long getPathSegAtLength(float distance);
 };
diff --git a/third_party/WebKit/Source/core/workers/WorkerGlobalScope.cpp b/third_party/WebKit/Source/core/workers/WorkerGlobalScope.cpp
index 15c1f3392..ef1511b3 100644
--- a/third_party/WebKit/Source/core/workers/WorkerGlobalScope.cpp
+++ b/third_party/WebKit/Source/core/workers/WorkerGlobalScope.cpp
@@ -93,13 +93,13 @@
   // is destroyed.
   closing_ = true;
   HeapHashSet<Member<V8AbstractEventListener>> listeners;
-  listeners.Swap(event_listeners_);
+  listeners.swap(event_listeners_);
   while (!listeners.IsEmpty()) {
     for (const auto& listener : listeners)
       listener->ClearListenerObject();
     listeners.Clear();
     // Pick up any additions made while iterating.
-    listeners.Swap(event_listeners_);
+    listeners.swap(event_listeners_);
   }
   RemoveAllEventListeners();
 
diff --git a/third_party/WebKit/Source/modules/media_controls/MediaControlsImplTest.cpp b/third_party/WebKit/Source/modules/media_controls/MediaControlsImplTest.cpp
index d54964c..4f172f31 100644
--- a/third_party/WebKit/Source/modules/media_controls/MediaControlsImplTest.cpp
+++ b/third_party/WebKit/Source/modules/media_controls/MediaControlsImplTest.cpp
@@ -77,24 +77,13 @@
 
 class MockLayoutObject : public LayoutObject {
  public:
-  MockLayoutObject() : LayoutObject(nullptr) {}
+  MockLayoutObject(Node* node) : LayoutObject(node) {}
 
   const char* GetName() const override { return "MockLayoutObject"; }
   void UpdateLayout() override {}
   FloatRect LocalBoundingBoxRectForAccessibility() const override {
     return FloatRect();
   }
-
-  void SetShouldDoFullPaintInvalidation(PaintInvalidationReason) {
-    full_paint_invalidation_call_count_++;
-  }
-
-  int FullPaintInvalidationCallCount() const {
-    return full_paint_invalidation_call_count_;
-  }
-
- private:
-  int full_paint_invalidation_call_count_ = 0;
 };
 
 class StubLocalFrameClient : public EmptyLocalFrameClient {
@@ -591,21 +580,27 @@
 
   Element* volume_slider = VolumeSliderElement();
 
-  MockLayoutObject layout_object;
+  MockLayoutObject layout_object(volume_slider);
   LayoutObject* prev_layout_object = volume_slider->GetLayoutObject();
   volume_slider->SetLayoutObject(&layout_object);
 
+  layout_object.ClearPaintInvalidationFlags();
+  EXPECT_FALSE(layout_object.ShouldDoFullPaintInvalidation());
   Event* event = Event::Create(EventTypeNames::input);
   volume_slider->DefaultEventHandler(event);
-  EXPECT_EQ(1, layout_object.FullPaintInvalidationCallCount());
+  EXPECT_TRUE(layout_object.ShouldDoFullPaintInvalidation());
 
+  layout_object.ClearPaintInvalidationFlags();
+  EXPECT_FALSE(layout_object.ShouldDoFullPaintInvalidation());
   event = Event::Create(EventTypeNames::input);
   volume_slider->DefaultEventHandler(event);
-  EXPECT_EQ(2, layout_object.FullPaintInvalidationCallCount());
+  EXPECT_TRUE(layout_object.ShouldDoFullPaintInvalidation());
 
+  layout_object.ClearPaintInvalidationFlags();
+  EXPECT_FALSE(layout_object.ShouldDoFullPaintInvalidation());
   event = Event::Create(EventTypeNames::input);
   volume_slider->DefaultEventHandler(event);
-  EXPECT_EQ(3, layout_object.FullPaintInvalidationCallCount());
+  EXPECT_TRUE(layout_object.ShouldDoFullPaintInvalidation());
 
   volume_slider->SetLayoutObject(prev_layout_object);
 }
diff --git a/third_party/WebKit/Source/modules/webaudio/DeferredTaskHandler.cpp b/third_party/WebKit/Source/modules/webaudio/DeferredTaskHandler.cpp
index 2461771..eee6e54 100644
--- a/third_party/WebKit/Source/modules/webaudio/DeferredTaskHandler.cpp
+++ b/third_party/WebKit/Source/modules/webaudio/DeferredTaskHandler.cpp
@@ -126,7 +126,7 @@
   DCHECK(IsGraphOwner());
 
   HashSet<AudioNodeOutput*> dirty_outputs;
-  dirty_audio_node_outputs_.Swap(dirty_outputs);
+  dirty_audio_node_outputs_.swap(dirty_outputs);
 
   // Note: the updating of rendering state may cause output nodes
   // further down the chain to be marked as dirty. These will not
diff --git a/third_party/WebKit/Source/modules/webdatabase/DatabaseThread.cpp b/third_party/WebKit/Source/modules/webdatabase/DatabaseThread.cpp
index 033a9d8..a09a664 100644
--- a/third_party/WebKit/Source/modules/webdatabase/DatabaseThread.cpp
+++ b/third_party/WebKit/Source/modules/webdatabase/DatabaseThread.cpp
@@ -106,7 +106,7 @@
     // As the call to close will modify the original set, we must take a copy to
     // iterate over.
     HashSet<CrossThreadPersistent<Database>> open_set_copy;
-    open_set_copy.Swap(open_database_set_);
+    open_set_copy.swap(open_database_set_);
     HashSet<CrossThreadPersistent<Database>>::iterator end =
         open_set_copy.end();
     for (HashSet<CrossThreadPersistent<Database>>::iterator it =
diff --git a/third_party/WebKit/Source/platform/LifecycleNotifier.h b/third_party/WebKit/Source/platform/LifecycleNotifier.h
index b69796a..c9830a84 100644
--- a/third_party/WebKit/Source/platform/LifecycleNotifier.h
+++ b/third_party/WebKit/Source/platform/LifecycleNotifier.h
@@ -134,7 +134,7 @@
   // Observer unregistration is allowed, but effectively a no-op.
   AutoReset<IterationState> scope(&iteration_state_, kAllowingRemoval);
   ObserverSet observers;
-  observers_.Swap(observers);
+  observers_.swap(observers);
   for (Observer* observer : observers) {
     DCHECK(observer->LifecycleContext() == Context());
     ContextDestroyedNotifier<Observer, T>::Call(observer, Context());
diff --git a/third_party/WebKit/Source/platform/audio/FFTFrameStub.cpp b/third_party/WebKit/Source/platform/audio/FFTFrameStub.cpp
index a3ef6b8..9c874cb 100644
--- a/third_party/WebKit/Source/platform/audio/FFTFrameStub.cpp
+++ b/third_party/WebKit/Source/platform/audio/FFTFrameStub.cpp
@@ -34,18 +34,18 @@
 namespace blink {
 
 // Normal constructor: allocates for a given fftSize.
-FFTFrame::FFTFrame(unsigned /*fftSize*/) : m_FFTSize(0), m_log2FFTSize(0) {
+FFTFrame::FFTFrame(unsigned /*fftSize*/) : fft_size_(0), log2fft_size_(0) {
   NOTREACHED();
 }
 
 // Creates a blank/empty frame (interpolate() must later be called).
-FFTFrame::FFTFrame() : m_FFTSize(0), m_log2FFTSize(0) {
+FFTFrame::FFTFrame() : fft_size_(0), log2fft_size_(0) {
   NOTREACHED();
 }
 
 // Copy constructor.
 FFTFrame::FFTFrame(const FFTFrame& frame)
-    : m_FFTSize(frame.m_FFTSize), m_log2FFTSize(frame.m_log2FFTSize) {
+    : fft_size_(frame.fft_size_), log2fft_size_(frame.log2fft_size_) {
   NOTREACHED();
 }
 
@@ -53,17 +53,17 @@
   NOTREACHED();
 }
 
-void FFTFrame::doFFT(const float* data) {
+void FFTFrame::DoFFT(const float* data) {
   NOTREACHED();
 }
 
-void FFTFrame::doInverseFFT(float* data) {
+void FFTFrame::DoInverseFFT(float* data) {
   NOTREACHED();
 }
 
-void FFTFrame::initialize() {}
+void FFTFrame::Initialize() {}
 
-void FFTFrame::cleanup() {
+void FFTFrame::Cleanup() {
   NOTREACHED();
 }
 
diff --git a/third_party/WebKit/Source/platform/graphics/paint/PaintController.cpp b/third_party/WebKit/Source/platform/graphics/paint/PaintController.cpp
index e26681df..8a89c97 100644
--- a/third_party/WebKit/Source/platform/graphics/paint/PaintController.cpp
+++ b/third_party/WebKit/Source/platform/graphics/paint/PaintController.cpp
@@ -540,7 +540,7 @@
   current_cache_generation_ =
       DisplayItemClient::CacheGenerationOrInvalidationReason::Next();
 
-  new_cached_subsequences_.Swap(current_cached_subsequences_);
+  new_cached_subsequences_.swap(current_cached_subsequences_);
   new_cached_subsequences_.Clear();
   last_cached_subsequence_end_ = 0;
   for (auto& item : current_cached_subsequences_) {
diff --git a/third_party/WebKit/Source/platform/heap/HeapTest.cpp b/third_party/WebKit/Source/platform/heap/HeapTest.cpp
index 461ec36f..45c819f 100644
--- a/third_party/WebKit/Source/platform/heap/HeapTest.cpp
+++ b/third_party/WebKit/Source/platform/heap/HeapTest.cpp
@@ -2676,11 +2676,11 @@
       // Swap set and set2 in a roundabout way.
       MemberSet& cset1 = container->set;
       MemberSet& cset2 = container->set2;
-      set->Swap(cset1);
-      set2->Swap(cset2);
-      set->Swap(cset2);
-      cset1.Swap(cset2);
-      cset2.Swap(*set2);
+      set->swap(cset1);
+      set2->swap(cset2);
+      set->swap(cset2);
+      cset1.swap(cset2);
+      cset2.swap(*set2);
 
       MemberCountedSet& c_counted_set = container->set3;
       set3->swap(c_counted_set);
@@ -2688,10 +2688,10 @@
       set3->swap(c_counted_set);
 
       // Triple swap.
-      container->map.Swap(*member_member2);
+      container->map.swap(*member_member2);
       MemberMember& contained_map = container->map;
-      member_member3->Swap(contained_map);
-      member_member3->Swap(*member_member);
+      member_member3->swap(contained_map);
+      member_member3->swap(*member_member);
 
       EXPECT_TRUE(member_member->at(one) == two);
       EXPECT_TRUE(member_member->at(two) == three);
@@ -2978,7 +2978,7 @@
 
     set1.insert(one);
     set2.insert(two);
-    set1.Swap(set2);
+    set1.swap(set2);
     ConservativelyCollectGarbage();
     EXPECT_TRUE(set1.Contains(two));
     EXPECT_TRUE(set2.Contains(one));
@@ -3029,7 +3029,7 @@
 
     set1.insert(one);
     set2.insert(two);
-    set1.Swap(set2);
+    set1.swap(set2);
     ConservativelyCollectGarbage();
     EXPECT_TRUE(set1.Contains(two));
     EXPECT_TRUE(set2.Contains(one));
diff --git a/third_party/WebKit/Source/platform/heap/ThreadState.cpp b/third_party/WebKit/Source/platform/heap/ThreadState.cpp
index 691f3260..438c7d2 100644
--- a/third_party/WebKit/Source/platform/heap/ThreadState.cpp
+++ b/third_party/WebKit/Source/platform/heap/ThreadState.cpp
@@ -1233,7 +1233,7 @@
 void ThreadState::ReleaseStaticPersistentNodes() {
   HashMap<PersistentNode*, ThreadState::PersistentClearCallback>
       static_persistents;
-  static_persistents.Swap(static_persistents_);
+  static_persistents.swap(static_persistents_);
 
   PersistentRegion* persistent_region = GetPersistentRegion();
   for (const auto& it : static_persistents)
diff --git a/third_party/WebKit/Source/platform/wtf/HashCountedSet.h b/third_party/WebKit/Source/platform/wtf/HashCountedSet.h
index 2d10c675..fe51fcb1 100644
--- a/third_party/WebKit/Source/platform/wtf/HashCountedSet.h
+++ b/third_party/WebKit/Source/platform/wtf/HashCountedSet.h
@@ -63,7 +63,7 @@
                   "HeapHashCountedSet<Member<T>> instead.");
   }
 
-  void swap(HashCountedSet& other) { impl_.Swap(other.impl_); }
+  void swap(HashCountedSet& other) { impl_.swap(other.impl_); }
 
   unsigned size() const { return impl_.size(); }
   unsigned capacity() const { return impl_.capacity(); }
diff --git a/third_party/WebKit/Source/platform/wtf/HashMap.h b/third_party/WebKit/Source/platform/wtf/HashMap.h
index f9af8eb..5b9a117 100644
--- a/third_party/WebKit/Source/platform/wtf/HashMap.h
+++ b/third_party/WebKit/Source/platform/wtf/HashMap.h
@@ -105,7 +105,7 @@
       const_iterator;
   typedef typename HashTableType::AddResult AddResult;
 
-  void Swap(HashMap& ref) { impl_.Swap(ref.impl_); }
+  void swap(HashMap& ref) { impl_.swap(ref.impl_); }
 
   unsigned size() const;
   unsigned Capacity() const;
diff --git a/third_party/WebKit/Source/platform/wtf/HashSet.h b/third_party/WebKit/Source/platform/wtf/HashSet.h
index aa4d64a6..4010427 100644
--- a/third_party/WebKit/Source/platform/wtf/HashSet.h
+++ b/third_party/WebKit/Source/platform/wtf/HashSet.h
@@ -78,7 +78,7 @@
   HashSet(std::initializer_list<ValueType> elements);
   HashSet& operator=(std::initializer_list<ValueType> elements);
 
-  void Swap(HashSet& ref) { impl_.Swap(ref.impl_); }
+  void swap(HashSet& ref) { impl_.swap(ref.impl_); }
 
   unsigned size() const;
   unsigned Capacity() const;
diff --git a/third_party/WebKit/Source/platform/wtf/HashTable.h b/third_party/WebKit/Source/platform/wtf/HashTable.h
index 8f53d82..dc6152cb 100644
--- a/third_party/WebKit/Source/platform/wtf/HashTable.h
+++ b/third_party/WebKit/Source/platform/wtf/HashTable.h
@@ -696,7 +696,7 @@
 
   HashTable(const HashTable&);
   HashTable(HashTable&&);
-  void Swap(HashTable&);
+  void swap(HashTable&);
   HashTable& operator=(const HashTable&);
   HashTable& operator=(HashTable&&);
 
@@ -1863,7 +1863,7 @@
       m_stats(HashTableStatsPtr<Allocator>::copy(other.m_stats))
 #endif
 {
-  Swap(other);
+  swap(other);
 }
 
 template <typename Key,
@@ -1879,7 +1879,7 @@
                HashFunctions,
                Traits,
                KeyTraits,
-               Allocator>::Swap(HashTable& other) {
+               Allocator>::swap(HashTable& other) {
   DCHECK(!AccessForbidden());
   std::swap(table_, other.table_);
   std::swap(table_size_, other.table_size_);
@@ -1911,7 +1911,7 @@
 HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits, Allocator>::
 operator=(const HashTable& other) {
   HashTable tmp(other);
-  Swap(tmp);
+  swap(tmp);
   return *this;
 }
 
@@ -1925,7 +1925,7 @@
 HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits, Allocator>&
 HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits, Allocator>::
 operator=(HashTable&& other) {
-  Swap(other);
+  swap(other);
   return *this;
 }
 
diff --git a/third_party/WebKit/Source/platform/wtf/LinkedHashSet.h b/third_party/WebKit/Source/platform/wtf/LinkedHashSet.h
index 0780218..8fdcad30 100644
--- a/third_party/WebKit/Source/platform/wtf/LinkedHashSet.h
+++ b/third_party/WebKit/Source/platform/wtf/LinkedHashSet.h
@@ -687,7 +687,7 @@
 
 template <typename T, typename U, typename V, typename W>
 inline void LinkedHashSet<T, U, V, W>::Swap(LinkedHashSet& other) {
-  impl_.Swap(other.impl_);
+  impl_.swap(other.impl_);
   SwapAnchor(anchor_, other.anchor_);
 }
 
diff --git a/third_party/WebKit/Source/platform/wtf/ListHashSet.h b/third_party/WebKit/Source/platform/wtf/ListHashSet.h
index 31b1e98..e99da9e 100644
--- a/third_party/WebKit/Source/platform/wtf/ListHashSet.h
+++ b/third_party/WebKit/Source/platform/wtf/ListHashSet.h
@@ -796,7 +796,7 @@
 
 template <typename T, size_t inlineCapacity, typename U, typename V>
 inline void ListHashSet<T, inlineCapacity, U, V>::Swap(ListHashSet& other) {
-  impl_.Swap(other.impl_);
+  impl_.swap(other.impl_);
   std::swap(head_, other.head_);
   std::swap(tail_, other.tail_);
   allocator_provider_.Swap(other.allocator_provider_);
diff --git a/third_party/WebKit/Source/web/tests/WebFrameTest.cpp b/third_party/WebKit/Source/web/tests/WebFrameTest.cpp
index 2a21287..797c2df 100644
--- a/third_party/WebKit/Source/web/tests/WebFrameTest.cpp
+++ b/third_party/WebKit/Source/web/tests/WebFrameTest.cpp
@@ -3777,6 +3777,7 @@
   web_view_helper.InitializeAndLoad(base_url_ + "block_bound.html", false,
                                     nullptr, nullptr, nullptr,
                                     ConfigureAndroid);
+  web_view_helper.Resize(WebSize(300, 300));
 
   IntRect rect_back = IntRect(0, 0, 200, 200);
   IntRect rect_left_top = IntRect(10, 10, 80, 80);
diff --git a/tools/chrome_proxy/webdriver/common.py b/tools/chrome_proxy/webdriver/common.py
index 9f2cb98..75769bf 100644
--- a/tools/chrome_proxy/webdriver/common.py
+++ b/tools/chrome_proxy/webdriver/common.py
@@ -674,71 +674,3 @@
     testRunner = unittest.runner.TextTestRunner(verbosity=2,
       failfast=flags.failfast, buffer=(not flags.disable_buffer))
     testRunner.run(tests)
-
-# Platform-specific decorators.
-# These decorators can be used to only run a test function for certain platforms
-# by annotating the function with them.
-
-def AndroidOnly(func):
-  def wrapper(*args, **kwargs):
-    if ParseFlags().android:
-      func(*args, **kwargs)
-    else:
-      args[0].skipTest('This test runs on Android only.')
-  return wrapper
-
-def NotAndroid(func):
-  def wrapper(*args, **kwargs):
-    if not ParseFlags().android:
-      func(*args, **kwargs)
-    else:
-      args[0].skipTest('This test does not run on Android.')
-  return wrapper
-
-def WindowsOnly(func):
-  def wrapper(*args, **kwargs):
-    if sys.platform == 'win32':
-      func(*args, **kwargs)
-    else:
-      args[0].skipTest('This test runs on Windows only.')
-  return wrapper
-
-def NotWindows(func):
-  def wrapper(*args, **kwargs):
-    if sys.platform != 'win32':
-      func(*args, **kwargs)
-    else:
-      args[0].skipTest('This test does not run on Windows.')
-  return wrapper
-
-def LinuxOnly(func):
-  def wrapper(*args, **kwargs):
-    if sys.platform.startswith('linux'):
-      func(*args, **kwargs)
-    else:
-      args[0].skipTest('This test runs on Linux only.')
-  return wrapper
-
-def NotLinux(func):
-  def wrapper(*args, **kwargs):
-    if sys.platform.startswith('linux'):
-      func(*args, **kwargs)
-    else:
-      args[0].skipTest('This test does not run on Linux.')
-  return wrapper
-
-def MacOnly(func):
-  def wrapper(*args, **kwargs):
-    if sys.platform == 'darwin':
-      func(*args, **kwargs)
-    else:
-      args[0].skipTest('This test runs on Mac OS only.')
-  return wrapper
-
-def NotMac(func):
-  def wrapper(*args, **kwargs):
-    if sys.platform == 'darwin':
-      func(*args, **kwargs)
-    else:
-      args[0].skipTest('This test does not run on Mac OS.')
-  return wrapper
diff --git a/tools/chrome_proxy/webdriver/compression_regression.py b/tools/chrome_proxy/webdriver/compression_regression.py
index 489a1ba..934fb93 100644
--- a/tools/chrome_proxy/webdriver/compression_regression.py
+++ b/tools/chrome_proxy/webdriver/compression_regression.py
@@ -11,7 +11,7 @@
 import common
 from common import TestDriver
 from common import IntegrationTest
-from common import NotAndroid
+from decorators import NotAndroid
 
 # The maximum number of data points that will be saved.
 MAX_DATA_POINTS = 365
diff --git a/tools/chrome_proxy/webdriver/data_use.py b/tools/chrome_proxy/webdriver/data_use.py
index b91c760e..7426c2b 100644
--- a/tools/chrome_proxy/webdriver/data_use.py
+++ b/tools/chrome_proxy/webdriver/data_use.py
@@ -7,7 +7,7 @@
 import common
 from common import TestDriver
 from common import IntegrationTest
-from common import NotAndroid
+from decorators import NotAndroid
 
 
 class DataUseAscription(IntegrationTest):
diff --git a/tools/chrome_proxy/webdriver/decorator_smoke.py b/tools/chrome_proxy/webdriver/decorator_smoke.py
index e9a6c75..bf2f82f 100644
--- a/tools/chrome_proxy/webdriver/decorator_smoke.py
+++ b/tools/chrome_proxy/webdriver/decorator_smoke.py
@@ -2,7 +2,7 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-from common import AndroidOnly
+from decorators import AndroidOnly
 from common import ParseFlags
 from common import IntegrationTest
 
diff --git a/tools/chrome_proxy/webdriver/decorators.py b/tools/chrome_proxy/webdriver/decorators.py
new file mode 100644
index 0000000..5da3650
--- /dev/null
+++ b/tools/chrome_proxy/webdriver/decorators.py
@@ -0,0 +1,74 @@
+# 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.
+
+from common import ParseFlags
+
+
+# Platform-specific decorators.
+# These decorators can be used to only run a test function for certain platforms
+# by annotating the function with them.
+
+def AndroidOnly(func):
+  def wrapper(*args, **kwargs):
+    if ParseFlags().android:
+      func(*args, **kwargs)
+    else:
+      args[0].skipTest('This test runs on Android only.')
+  return wrapper
+
+def NotAndroid(func):
+  def wrapper(*args, **kwargs):
+    if not ParseFlags().android:
+      func(*args, **kwargs)
+    else:
+      args[0].skipTest('This test does not run on Android.')
+  return wrapper
+
+def WindowsOnly(func):
+  def wrapper(*args, **kwargs):
+    if sys.platform == 'win32':
+      func(*args, **kwargs)
+    else:
+      args[0].skipTest('This test runs on Windows only.')
+  return wrapper
+
+def NotWindows(func):
+  def wrapper(*args, **kwargs):
+    if sys.platform != 'win32':
+      func(*args, **kwargs)
+    else:
+      args[0].skipTest('This test does not run on Windows.')
+  return wrapper
+
+def LinuxOnly(func):
+  def wrapper(*args, **kwargs):
+    if sys.platform.startswith('linux'):
+      func(*args, **kwargs)
+    else:
+      args[0].skipTest('This test runs on Linux only.')
+  return wrapper
+
+def NotLinux(func):
+  def wrapper(*args, **kwargs):
+    if sys.platform.startswith('linux'):
+      func(*args, **kwargs)
+    else:
+      args[0].skipTest('This test does not run on Linux.')
+  return wrapper
+
+def MacOnly(func):
+  def wrapper(*args, **kwargs):
+    if sys.platform == 'darwin':
+      func(*args, **kwargs)
+    else:
+      args[0].skipTest('This test runs on Mac OS only.')
+  return wrapper
+
+def NotMac(func):
+  def wrapper(*args, **kwargs):
+    if sys.platform == 'darwin':
+      func(*args, **kwargs)
+    else:
+      args[0].skipTest('This test does not run on Mac OS.')
+  return wrapper
diff --git a/tools/chrome_proxy/webdriver/quic.py b/tools/chrome_proxy/webdriver/quic.py
index 03f8f2c..280bfb92 100644
--- a/tools/chrome_proxy/webdriver/quic.py
+++ b/tools/chrome_proxy/webdriver/quic.py
@@ -2,6 +2,8 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
+import time
+
 import common
 from common import TestDriver
 from common import IntegrationTest
diff --git a/tools/chrome_proxy/webdriver/safebrowsing.py b/tools/chrome_proxy/webdriver/safebrowsing.py
index cdfe2ec..1560bb0 100644
--- a/tools/chrome_proxy/webdriver/safebrowsing.py
+++ b/tools/chrome_proxy/webdriver/safebrowsing.py
@@ -5,8 +5,8 @@
 import common
 from common import TestDriver
 from common import IntegrationTest
-from common import AndroidOnly
-from common import NotAndroid
+from decorators import AndroidOnly
+from decorators import NotAndroid
 
 
 class SafeBrowsing(IntegrationTest):
diff --git a/tools/chrome_proxy/webdriver/smoke.py b/tools/chrome_proxy/webdriver/smoke.py
index f29dc235..ad799d6 100644
--- a/tools/chrome_proxy/webdriver/smoke.py
+++ b/tools/chrome_proxy/webdriver/smoke.py
@@ -6,7 +6,7 @@
 import time
 from common import TestDriver
 from common import IntegrationTest
-from common import NotAndroid
+from decorators import NotAndroid
 
 
 class Smoke(IntegrationTest):
@@ -21,7 +21,7 @@
       t.LoadURL('http://check.googlezip.net/test.html')
       for response in t.GetHTTPResponses():
         self.assertNotHasChromeProxyViaHeader(response)
-  
+
   # Ensure Chrome uses DataSaver in normal mode.
   def testCheckPageWithNormalMode(self):
     with TestDriver() as t:
@@ -85,7 +85,7 @@
       responses = t.GetHTTPResponses()
       self.assertNotEqual(0, len(responses))
       for response in responses:
-        self.assertHasChromeProxyViaHeader(response)        
+        self.assertHasChromeProxyViaHeader(response)
 
 if __name__ == '__main__':
   IntegrationTest.RunAllTests()
diff --git a/tools/chrome_proxy/webdriver/video.py b/tools/chrome_proxy/webdriver/video.py
index 2d59f2b..a7803140 100644
--- a/tools/chrome_proxy/webdriver/video.py
+++ b/tools/chrome_proxy/webdriver/video.py
@@ -7,7 +7,7 @@
 import common
 from common import TestDriver
 from common import IntegrationTest
-from common import NotAndroid
+from decorators import NotAndroid
 
 
 class Video(IntegrationTest):
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index 1ab43ba4..52f9a6b 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -102099,6 +102099,7 @@
   <int value="313303258" label="WebPaymentsModifiers:disabled"/>
   <int value="316182183" label="MediaDocumentDownloadButton:disabled"/>
   <int value="323605372" label="ui-disable-compositor-animation-timelines"/>
+  <int value="324522065" label="app-menu-icon"/>
   <int value="324631366" label="enable-drive-search-in-app-launcher"/>
   <int value="327045548" label="SafeSearchUrlReporting:enabled"/>
   <int value="328722396" label="NTPCondensedLayout:disabled"/>
diff --git a/ui/accessibility/platform/ax_platform_node_win.cc b/ui/accessibility/platform/ax_platform_node_win.cc
index 42f2467..e703233 100644
--- a/ui/accessibility/platform/ax_platform_node_win.cc
+++ b/ui/accessibility/platform/ax_platform_node_win.cc
@@ -33,48 +33,100 @@
     if (!delegate_) \
       return E_FAIL;
 #define COM_OBJECT_VALIDATE_1_ARG(arg) \
-    if (!delegate_) return E_FAIL; \
-    if (!arg) return E_INVALIDARG
+  if (!delegate_)                      \
+    return E_FAIL;                     \
+  if (!arg)                            \
+    return E_INVALIDARG;
 #define COM_OBJECT_VALIDATE_2_ARGS(arg1, arg2) \
-    if (!delegate_) return E_FAIL; \
-    if (!arg1) return E_INVALIDARG; \
-    if (!arg2) return E_INVALIDARG
+  if (!delegate_)                              \
+    return E_FAIL;                             \
+  if (!arg1)                                   \
+    return E_INVALIDARG;                       \
+  if (!arg2)                                   \
+    return E_INVALIDARG;
 #define COM_OBJECT_VALIDATE_3_ARGS(arg1, arg2, arg3) \
-    if (!delegate_) return E_FAIL; \
-    if (!arg1) return E_INVALIDARG; \
-    if (!arg2) return E_INVALIDARG; \
-    if (!arg3) return E_INVALIDARG
+  if (!delegate_)                                    \
+    return E_FAIL;                                   \
+  if (!arg1)                                         \
+    return E_INVALIDARG;                             \
+  if (!arg2)                                         \
+    return E_INVALIDARG;                             \
+  if (!arg3)                                         \
+    return E_INVALIDARG;
 #define COM_OBJECT_VALIDATE_4_ARGS(arg1, arg2, arg3, arg4) \
-    if (!delegate_) return E_FAIL; \
-    if (!arg1) return E_INVALIDARG; \
-    if (!arg2) return E_INVALIDARG; \
-    if (!arg3) return E_INVALIDARG; \
-    if (!arg4) return E_INVALIDARG
-#define COM_OBJECT_VALIDATE_VAR_ID(var_id) \
-    if (!delegate_) return E_FAIL; \
-    if (!IsValidId(var_id)) return E_INVALIDARG
-#define COM_OBJECT_VALIDATE_VAR_ID_1_ARG(var_id, arg) \
-    if (!delegate_) return E_FAIL; \
-    if (!IsValidId(var_id)) return E_INVALIDARG; \
-    if (!arg) return E_INVALIDARG
-#define COM_OBJECT_VALIDATE_VAR_ID_2_ARGS(var_id, arg1, arg2) \
-    if (!delegate_) return E_FAIL; \
-    if (!IsValidId(var_id)) return E_INVALIDARG; \
-    if (!arg1) return E_INVALIDARG; \
-    if (!arg2) return E_INVALIDARG
-#define COM_OBJECT_VALIDATE_VAR_ID_3_ARGS(var_id, arg1, arg2, arg3) \
-    if (!delegate_) return E_FAIL; \
-    if (!IsValidId(var_id)) return E_INVALIDARG; \
-    if (!arg1) return E_INVALIDARG; \
-    if (!arg2) return E_INVALIDARG; \
-    if (!arg3) return E_INVALIDARG
-#define COM_OBJECT_VALIDATE_VAR_ID_4_ARGS(var_id, arg1, arg2, arg3, arg4) \
-    if (!delegate_) return E_FAIL; \
-    if (!IsValidId(var_id)) return E_INVALIDARG; \
-    if (!arg1) return E_INVALIDARG; \
-    if (!arg2) return E_INVALIDARG; \
-    if (!arg3) return E_INVALIDARG; \
-    if (!arg4) return E_INVALIDARG
+  if (!delegate_)                                          \
+    return E_FAIL;                                         \
+  if (!arg1)                                               \
+    return E_INVALIDARG;                                   \
+  if (!arg2)                                               \
+    return E_INVALIDARG;                                   \
+  if (!arg3)                                               \
+    return E_INVALIDARG;                                   \
+  if (!arg4)                                               \
+    return E_INVALIDARG;
+#define COM_OBJECT_VALIDATE_VAR_ID_AND_GET_TARGET(var_id, target) \
+  if (!delegate_)                                                 \
+    return E_FAIL;                                                \
+  target = GetTargetFromChildID(var_id);                          \
+  if (!target)                                                    \
+    return E_INVALIDARG;                                          \
+  if (!target->delegate_)                                         \
+    return E_INVALIDARG;
+#define COM_OBJECT_VALIDATE_VAR_ID_1_ARG_AND_GET_TARGET(var_id, arg, target) \
+  if (!delegate_)                                                            \
+    return E_FAIL;                                                           \
+  if (!arg)                                                                  \
+    return E_INVALIDARG;                                                     \
+  target = GetTargetFromChildID(var_id);                                     \
+  if (!target)                                                               \
+    return E_INVALIDARG;                                                     \
+  if (!target->delegate_)                                                    \
+    return E_INVALIDARG;
+#define COM_OBJECT_VALIDATE_VAR_ID_2_ARGS_AND_GET_TARGET(var_id, arg1, arg2, \
+                                                         target)             \
+  if (!delegate_)                                                            \
+    return E_FAIL;                                                           \
+  if (!arg1)                                                                 \
+    return E_INVALIDARG;                                                     \
+  if (!arg2)                                                                 \
+    return E_INVALIDARG;                                                     \
+  target = GetTargetFromChildID(var_id);                                     \
+  if (!target)                                                               \
+    return E_INVALIDARG;                                                     \
+  if (!target->delegate_)                                                    \
+    return E_INVALIDARG;
+#define COM_OBJECT_VALIDATE_VAR_ID_3_ARGS_AND_GET_TARGET(var_id, arg1, arg2, \
+                                                         arg3, target)       \
+  if (!delegate_)                                                            \
+    return E_FAIL;                                                           \
+  if (!arg1)                                                                 \
+    return E_INVALIDARG;                                                     \
+  if (!arg2)                                                                 \
+    return E_INVALIDARG;                                                     \
+  if (!arg3)                                                                 \
+    return E_INVALIDARG;                                                     \
+  target = GetTargetFromChildID(var_id);                                     \
+  if (!target)                                                               \
+    return E_INVALIDARG;                                                     \
+  if (!target->delegate_)                                                    \
+    return E_INVALIDARG;
+#define COM_OBJECT_VALIDATE_VAR_ID_4_ARGS_AND_GET_TARGET(var_id, arg1, arg2, \
+                                                         arg3, arg4, target) \
+  if (!delegate_)                                                            \
+    return E_FAIL;                                                           \
+  if (!arg1)                                                                 \
+    return E_INVALIDARG;                                                     \
+  if (!arg2)                                                                 \
+    return E_INVALIDARG;                                                     \
+  if (!arg3)                                                                 \
+    return E_INVALIDARG;                                                     \
+  if (!arg4)                                                                 \
+    return E_INVALIDARG;                                                     \
+  target = GetTargetFromChildID(var_id);                                     \
+  if (!target)                                                               \
+    return E_INVALIDARG;                                                     \
+  if (!target->delegate_)                                                    \
+    return E_INVALIDARG;
 
 namespace ui {
 
@@ -128,6 +180,8 @@
 // static
 AXPlatformNode* AXPlatformNode::FromNativeViewAccessible(
     gfx::NativeViewAccessible accessible) {
+  if (!accessible)
+    return nullptr;
   base::win::ScopedComPtr<AXPlatformNodeWin> ax_platform_node;
   accessible->QueryInterface(ax_platform_node.Receive());
   return ax_platform_node.get();
@@ -252,18 +306,23 @@
 }
 
 HRESULT AXPlatformNodeWin::accDoDefaultAction(VARIANT var_id) {
-  COM_OBJECT_VALIDATE_VAR_ID(var_id);
+  AXPlatformNodeWin* target;
+  COM_OBJECT_VALIDATE_VAR_ID_AND_GET_TARGET(var_id, target);
   AXActionData data;
   data.action = ui::AX_ACTION_DO_DEFAULT;
-  if (delegate_->AccessibilityPerformAction(data))
+
+  if (target->delegate_->AccessibilityPerformAction(data))
     return S_OK;
   return E_FAIL;
 }
 
 STDMETHODIMP AXPlatformNodeWin::accLocation(
     LONG* x_left, LONG* y_top, LONG* width, LONG* height, VARIANT var_id) {
-  COM_OBJECT_VALIDATE_VAR_ID_4_ARGS(var_id, x_left, y_top, width, height);
-  gfx::Rect bounds = delegate_->GetScreenBoundsRect();
+  AXPlatformNodeWin* target;
+  COM_OBJECT_VALIDATE_VAR_ID_4_ARGS_AND_GET_TARGET(var_id, x_left, y_top, width,
+                                                   height, target);
+
+  gfx::Rect bounds = target->delegate_->GetScreenBoundsRect();
   *x_left = bounds.x();
   *y_top = bounds.y();
   *width  = bounds.width();
@@ -277,7 +336,8 @@
 
 STDMETHODIMP AXPlatformNodeWin::accNavigate(
     LONG nav_dir, VARIANT start, VARIANT* end) {
-  COM_OBJECT_VALIDATE_VAR_ID_1_ARG(start, end);
+  AXPlatformNodeWin* target;
+  COM_OBJECT_VALIDATE_VAR_ID_1_ARG_AND_GET_TARGET(start, end, target);
   IAccessible* result = nullptr;
 
   if ((nav_dir == NAVDIR_LASTCHILD || nav_dir == NAVDIR_FIRSTCHILD) &&
@@ -337,41 +397,13 @@
 
 STDMETHODIMP AXPlatformNodeWin::get_accChild(VARIANT var_child,
                                              IDispatch** disp_child) {
-  COM_OBJECT_VALIDATE_1_ARG(disp_child);
-  LONG child_id = V_I4(&var_child);
-  if (child_id == CHILDID_SELF) {
-    *disp_child = this;
-    (*disp_child)->AddRef();
-    return S_OK;
-  }
-
-  if (child_id >= 1 && child_id <= delegate_->GetChildCount()) {
-    // Positive child ids are a 1-based child index, used by clients
-    // that want to enumerate all immediate children.
-    *disp_child = delegate_->ChildAtIndex(child_id - 1);
-    if (!(*disp_child))
-      return E_INVALIDARG;
-    (*disp_child)->AddRef();
-    return S_OK;
-  }
-
-  if (child_id >= 0)
-    return E_INVALIDARG;
-
-  // Negative child ids can be used to map to any descendant.
-  AXPlatformNodeWin* child = static_cast<AXPlatformNodeWin*>(
-      GetFromUniqueId(-child_id));
-  if (child && !IsDescendant(child))
-    child = nullptr;
-
-  if (child) {
-    *disp_child = child;
-    (*disp_child)->AddRef();
-    return S_OK;
-  }
-
   *disp_child = nullptr;
-  return E_INVALIDARG;
+  AXPlatformNodeWin* target;
+  COM_OBJECT_VALIDATE_VAR_ID_AND_GET_TARGET(var_child, target);
+
+  *disp_child = target;
+  (*disp_child)->AddRef();
+  return S_OK;
 }
 
 STDMETHODIMP AXPlatformNodeWin::get_accChildCount(LONG* child_count) {
@@ -382,9 +414,11 @@
 
 STDMETHODIMP AXPlatformNodeWin::get_accDefaultAction(
     VARIANT var_id, BSTR* def_action) {
-  COM_OBJECT_VALIDATE_VAR_ID_1_ARG(var_id, def_action);
+  AXPlatformNodeWin* target;
+  COM_OBJECT_VALIDATE_VAR_ID_1_ARG_AND_GET_TARGET(var_id, def_action, target);
+
   int action;
-  if (!GetIntAttribute(AX_ATTR_ACTION, &action)) {
+  if (!target->GetIntAttribute(AX_ATTR_ACTION, &action)) {
     *def_action = nullptr;
     return S_FALSE;
   }
@@ -403,8 +437,10 @@
 
 STDMETHODIMP AXPlatformNodeWin::get_accDescription(
     VARIANT var_id, BSTR* desc) {
-  COM_OBJECT_VALIDATE_VAR_ID_1_ARG(var_id, desc);
-  return GetStringAttributeAsBstr(ui::AX_ATTR_DESCRIPTION, desc);
+  AXPlatformNodeWin* target;
+  COM_OBJECT_VALIDATE_VAR_ID_1_ARG_AND_GET_TARGET(var_id, desc, target);
+
+  return target->GetStringAttributeAsBstr(ui::AX_ATTR_DESCRIPTION, desc);
 }
 
 STDMETHODIMP AXPlatformNodeWin::get_accFocus(VARIANT* focus_child) {
@@ -427,14 +463,18 @@
 
 STDMETHODIMP AXPlatformNodeWin::get_accKeyboardShortcut(
     VARIANT var_id, BSTR* acc_key) {
-  COM_OBJECT_VALIDATE_VAR_ID_1_ARG(var_id, acc_key);
-  return GetStringAttributeAsBstr(ui::AX_ATTR_SHORTCUT, acc_key);
+  AXPlatformNodeWin* target;
+  COM_OBJECT_VALIDATE_VAR_ID_1_ARG_AND_GET_TARGET(var_id, acc_key, target);
+
+  return target->GetStringAttributeAsBstr(ui::AX_ATTR_SHORTCUT, acc_key);
 }
 
 STDMETHODIMP AXPlatformNodeWin::get_accName(
     VARIANT var_id, BSTR* name) {
-  COM_OBJECT_VALIDATE_VAR_ID_1_ARG(var_id, name);
-  return GetStringAttributeAsBstr(ui::AX_ATTR_NAME, name);
+  AXPlatformNodeWin* target;
+  COM_OBJECT_VALIDATE_VAR_ID_1_ARG_AND_GET_TARGET(var_id, name, target);
+
+  return target->GetStringAttributeAsBstr(ui::AX_ATTR_NAME, name);
 }
 
 STDMETHODIMP AXPlatformNodeWin::get_accParent(
@@ -451,38 +491,42 @@
 
 STDMETHODIMP AXPlatformNodeWin::get_accRole(
     VARIANT var_id, VARIANT* role) {
-  COM_OBJECT_VALIDATE_VAR_ID_1_ARG(var_id, role);
+  AXPlatformNodeWin* target;
+  COM_OBJECT_VALIDATE_VAR_ID_1_ARG_AND_GET_TARGET(var_id, role, target);
   role->vt = VT_I4;
-  role->lVal = MSAARole();
+  role->lVal = target->MSAARole();
   return S_OK;
 }
 
 STDMETHODIMP AXPlatformNodeWin::get_accState(
     VARIANT var_id, VARIANT* state) {
-  COM_OBJECT_VALIDATE_VAR_ID_1_ARG(var_id, state);
+  AXPlatformNodeWin* target;
+  COM_OBJECT_VALIDATE_VAR_ID_1_ARG_AND_GET_TARGET(var_id, state, target);
   state->vt = VT_I4;
-  state->lVal = MSAAState();
+  state->lVal = target->MSAAState();
   return S_OK;
 }
 
 STDMETHODIMP AXPlatformNodeWin::get_accHelp(
     VARIANT var_id, BSTR* help) {
-  COM_OBJECT_VALIDATE_VAR_ID_1_ARG(var_id, help);
   return S_FALSE;
 }
 
 STDMETHODIMP AXPlatformNodeWin::get_accValue(VARIANT var_id, BSTR* value) {
-  COM_OBJECT_VALIDATE_VAR_ID_1_ARG(var_id, value);
-  return GetStringAttributeAsBstr(ui::AX_ATTR_VALUE, value);
+  AXPlatformNodeWin* target;
+  COM_OBJECT_VALIDATE_VAR_ID_1_ARG_AND_GET_TARGET(var_id, value, target);
+  return target->GetStringAttributeAsBstr(ui::AX_ATTR_VALUE, value);
 }
 
 STDMETHODIMP AXPlatformNodeWin::put_accValue(VARIANT var_id,
                                              BSTR new_value) {
+  AXPlatformNodeWin* target;
+  COM_OBJECT_VALIDATE_VAR_ID_AND_GET_TARGET(var_id, target);
+
   AXActionData data;
   data.action = ui::AX_ACTION_SET_VALUE;
   data.value = new_value;
-  COM_OBJECT_VALIDATE_VAR_ID(var_id);
-  if (delegate_->AccessibilityPerformAction(data))
+  if (target->delegate_->AccessibilityPerformAction(data))
     return S_OK;
   return E_FAIL;
 }
@@ -498,13 +542,14 @@
 
 STDMETHODIMP AXPlatformNodeWin::accSelect(
     LONG flagsSelect, VARIANT var_id) {
-  COM_OBJECT_VALIDATE_VAR_ID(var_id);
   return E_NOTIMPL;
 }
 
 STDMETHODIMP AXPlatformNodeWin::get_accHelpTopic(
     BSTR* help_file, VARIANT var_id, LONG* topic_id) {
-  COM_OBJECT_VALIDATE_VAR_ID_2_ARGS(var_id, help_file, topic_id);
+  AXPlatformNodeWin* target;
+  COM_OBJECT_VALIDATE_VAR_ID_2_ARGS_AND_GET_TARGET(var_id, help_file, topic_id,
+                                                   target);
   if (help_file) {
     *help_file = nullptr;
   }
@@ -516,7 +561,6 @@
 
 STDMETHODIMP AXPlatformNodeWin::put_accName(
     VARIANT var_id, BSTR put_name) {
-  COM_OBJECT_VALIDATE_VAR_ID(var_id);
   // Deprecated.
   return E_NOTIMPL;
 }
@@ -974,13 +1018,6 @@
 //
 // Private member functions.
 //
-
-bool AXPlatformNodeWin::IsValidId(const VARIANT& child) const {
-  // Since we have a separate IAccessible COM object for each node, we only
-  // support the CHILDID_SELF id.
-  return (VT_I4 == child.vt) && (CHILDID_SELF == child.lVal);
-}
-
 int AXPlatformNodeWin::MSAARole() {
   switch (GetData().role) {
     case ui::AX_ROLE_ALERT:
@@ -1219,4 +1256,35 @@
       AX_TEXT_AFFINITY_DOWNSTREAM));
 }
 
+AXPlatformNodeWin* AXPlatformNodeWin::GetTargetFromChildID(
+    const VARIANT& var_id) {
+  LONG child_id = V_I4(&var_id);
+  if (child_id == CHILDID_SELF) {
+    return this;
+  }
+
+  if (child_id >= 1 && child_id <= delegate_->GetChildCount()) {
+    // Positive child ids are a 1-based child index, used by clients
+    // that want to enumerate all immediate children.
+    AXPlatformNodeBase* base =
+        FromNativeViewAccessible(delegate_->ChildAtIndex(child_id - 1));
+    return static_cast<AXPlatformNodeWin*>(base);
+  }
+
+  if (child_id >= 0)
+    return nullptr;
+
+  // Negative child ids can be used to map to any descendant.
+  AXPlatformNode* node = GetFromUniqueId(-child_id);
+  if (!node)
+    return nullptr;
+
+  AXPlatformNodeBase* base =
+      FromNativeViewAccessible(node->GetNativeViewAccessible());
+  if (base && !IsDescendant(base))
+    base = nullptr;
+
+  return static_cast<AXPlatformNodeWin*>(base);
+}
+
 }  // namespace ui
diff --git a/ui/accessibility/platform/ax_platform_node_win.h b/ui/accessibility/platform/ax_platform_node_win.h
index 7daa45f..0ea5fcd 100644
--- a/ui/accessibility/platform/ax_platform_node_win.h
+++ b/ui/accessibility/platform/ax_platform_node_win.h
@@ -273,7 +273,6 @@
   void Dispose() override;
 
  private:
-  bool IsValidId(const VARIANT& child) const;
   int MSAARole();
   int MSAAState();
   int MSAAEvent(ui::AXEvent event);
@@ -302,6 +301,13 @@
                     IA2TextBoundaryType ia2_boundary,
                     LONG start_offset,
                     ui::TextBoundaryDirection direction);
+
+  // Many MSAA methods take a var_id parameter indicating that the operation
+  // should be performed on a particular child ID, rather than this object.
+  // This method tries to figure out the target object from |var_id| and
+  // returns a pointer to the target object if it exists, otherwise nullptr.
+  // Does not return a new reference.
+  AXPlatformNodeWin* GetTargetFromChildID(const VARIANT& var_id);
 };
 
 }  // namespace ui
diff --git a/ui/android/BUILD.gn b/ui/android/BUILD.gn
index 749a638..22deece 100644
--- a/ui/android/BUILD.gn
+++ b/ui/android/BUILD.gn
@@ -234,12 +234,14 @@
 
 junit_binary("ui_junit_tests") {
   java_files = [
+    "junit/src/org/chromium/ui/base/ClipboardTest.java",
     "junit/src/org/chromium/ui/base/SelectFileDialogTest.java",
     "junit/src/org/chromium/ui/text/SpanApplierTest.java",
   ]
   deps = [
     ":ui_java",
     "//base:base_java",
+    "//base:base_java_test_support",
   ]
 }
 
diff --git a/ui/android/java/src/org/chromium/ui/base/Clipboard.java b/ui/android/java/src/org/chromium/ui/base/Clipboard.java
index 0f3eb25..fddad5a 100644
--- a/ui/android/java/src/org/chromium/ui/base/Clipboard.java
+++ b/ui/android/java/src/org/chromium/ui/base/Clipboard.java
@@ -14,6 +14,7 @@
 import android.text.style.ParagraphStyle;
 import android.text.style.UpdateAppearance;
 
+import org.chromium.base.ApiCompatibilityUtils;
 import org.chromium.base.ContextUtils;
 import org.chromium.base.annotations.CalledByNative;
 import org.chromium.base.annotations.JNINamespace;
@@ -72,7 +73,7 @@
      */
     @SuppressWarnings("javadoc")
     @CalledByNative
-    public String getCoercedText() {
+    private String getCoercedText() {
         // getPrimaryClip() has been observed to throw unexpected exceptions for some devices (see
         // crbug.com/654802 and b/31501780)
         try {
@@ -97,6 +98,24 @@
         return false;
     }
 
+    public String clipDataToHtmlText(ClipData clipData) {
+        ClipDescription description = clipData.getDescription();
+        if (description.hasMimeType(ClipDescription.MIMETYPE_TEXT_HTML)) {
+            return clipData.getItemAt(0).getHtmlText();
+        }
+
+        if (description.hasMimeType(ClipDescription.MIMETYPE_TEXT_PLAIN)) {
+            CharSequence text = clipData.getItemAt(0).getText();
+            if (!(text instanceof Spanned)) return null;
+            Spanned spanned = (Spanned) text;
+            if (hasStyleSpan(spanned)) {
+                return ApiCompatibilityUtils.toHtml(
+                        spanned, Html.TO_HTML_PARAGRAPH_LINES_CONSECUTIVE);
+            }
+        }
+        return null;
+    }
+
     /**
      * Gets the HTML text of top item on the primary clip on the Android clipboard.
      *
@@ -104,26 +123,15 @@
      *         text or no entries on the primary clip.
      */
     @CalledByNative
-    public String getHTMLText() {
+    private String getHTMLText() {
         // getPrimaryClip() has been observed to throw unexpected exceptions for some devices (see
         // crbug/654802 and b/31501780)
         try {
             ClipData clipData = mClipboardManager.getPrimaryClip();
-            ClipDescription description = clipData.getDescription();
-            if (description.hasMimeType(ClipDescription.MIMETYPE_TEXT_HTML)) {
-                return clipData.getItemAt(0).getHtmlText();
-            }
-
-            if (description.hasMimeType(ClipDescription.MIMETYPE_TEXT_PLAIN)) {
-                Spanned spanned = (Spanned) clipData.getItemAt(0).getText();
-                if (hasStyleSpan(spanned)) {
-                    return Html.toHtml(spanned);
-                }
-            }
+            return clipDataToHtmlText(clipData);
         } catch (Exception e) {
             return null;
         }
-        return null;
     }
 
     /**
diff --git a/ui/android/junit/src/org/chromium/ui/base/ClipboardTest.java b/ui/android/junit/src/org/chromium/ui/base/ClipboardTest.java
new file mode 100644
index 0000000..3a99aeb
--- /dev/null
+++ b/ui/android/junit/src/org/chromium/ui/base/ClipboardTest.java
@@ -0,0 +1,59 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.ui.base;
+
+import android.content.ClipData;
+import android.content.Intent;
+import android.text.SpannableString;
+import android.text.style.RelativeSizeSpan;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Config;
+
+import org.chromium.base.ContextUtils;
+import org.chromium.testing.local.LocalRobolectricTestRunner;
+
+/**
+ * Tests logic in the Clipboard class.
+ */
+@RunWith(LocalRobolectricTestRunner.class)
+@Config(manifest = Config.NONE)
+public class ClipboardTest {
+    private static final String PLAIN_TEXT = "plain";
+    private static final String HTML_TEXT = "<span style=\"color: red;\">HTML</span>";
+
+    @Test
+    public void testClipDataToHtmlText() {
+        ContextUtils.initApplicationContextForTests(RuntimeEnvironment.application);
+        Clipboard clipboard = Clipboard.getInstance();
+
+        // HTML text
+        ClipData html = ClipData.newHtmlText("html", PLAIN_TEXT, HTML_TEXT);
+        assertEquals(HTML_TEXT, clipboard.clipDataToHtmlText(html));
+
+        // Plain text without span
+        ClipData plainTextNoSpan = ClipData.newPlainText("plain", PLAIN_TEXT);
+        assertNull(clipboard.clipDataToHtmlText(plainTextNoSpan));
+
+        // Plain text with span
+        SpannableString spanned = new SpannableString(PLAIN_TEXT);
+        spanned.setSpan(new RelativeSizeSpan(2f), 0, 5, 0);
+        ClipData plainTextSpan = ClipData.newPlainText("plain", spanned);
+        assertNotNull(clipboard.clipDataToHtmlText(plainTextSpan));
+
+        // Intent
+        Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
+        intent.addCategory(Intent.CATEGORY_OPENABLE);
+        intent.setType("*/*");
+        ClipData intentClip = ClipData.newIntent("intent", intent);
+        assertNull(clipboard.clipDataToHtmlText(intentClip));
+    }
+}
diff --git a/ui/views/controls/button/label_button.h b/ui/views/controls/button/label_button.h
index 6dade72..91b68fa 100644
--- a/ui/views/controls/button/label_button.h
+++ b/ui/views/controls/button/label_button.h
@@ -107,6 +107,9 @@
  protected:
   ImageView* image() const { return image_; }
   Label* label() const { return label_; }
+  InkDropContainerView* ink_drop_container() const {
+    return ink_drop_container_;
+  }
 
   bool explicitly_set_normal_color() const {
     return explicitly_set_colors_[STATE_NORMAL];
diff --git a/ui/views/controls/native/native_view_host.cc b/ui/views/controls/native/native_view_host.cc
index 452e5966..34f4af7f 100644
--- a/ui/views/controls/native/native_view_host.cc
+++ b/ui/views/controls/native/native_view_host.cc
@@ -167,7 +167,8 @@
 }
 
 void NativeViewHost::OnFocus() {
-  native_wrapper_->SetFocus();
+  if (native_view_)
+    native_wrapper_->SetFocus();
   NotifyAccessibilityEvent(ui::AX_EVENT_FOCUS, true);
 }
 
diff --git a/ui/webui/resources/cr_elements/network/cr_network_list.html b/ui/webui/resources/cr_elements/network/cr_network_list.html
index 7288de32..09c967b 100644
--- a/ui/webui/resources/cr_elements/network/cr_network_list.html
+++ b/ui/webui/resources/cr_elements/network/cr_network_list.html
@@ -37,7 +37,7 @@
       <iron-list id="networkList" selection-enabled items="[[listItems_]]"
           scroll-target="container" selected-item="{{selectedItem}}">
         <template>
-          <cr-network-list-item item="[[item]]" is-list-item
+          <cr-network-list-item item="[[item]]"
               show-buttons="[[showButtons]]" tabindex$="[[tabIndex]]">
           </cr-network-list-item>
         </template>
diff --git a/ui/webui/resources/cr_elements/network/cr_network_list_item.html b/ui/webui/resources/cr_elements/network/cr_network_list_item.html
index 01d0782..920d6cd 100644
--- a/ui/webui/resources/cr_elements/network/cr_network_list_item.html
+++ b/ui/webui/resources/cr_elements/network/cr_network_list_item.html
@@ -34,11 +34,6 @@
         justify-content: center;
       }
 
-      #itemName:not([is-list-item]) {
-        font-weight: 500;
-        color: #333;
-      }
-
       #networkStateText {
         color: var(--paper-grey-600);
         font-size: inherit;
@@ -68,23 +63,20 @@
       }
     </style>
     <div id="divOuter"
-        class="layout horizontal center flex" actionable$="[[isListItem]]">
+        class="layout horizontal center flex" actionable>
       <template is="dom-if" if="[[networkState]]">
-        <cr-network-icon is-list-item="[[isListItem]]"
-            network-state="[[networkState]]">
+        <cr-network-icon is-list-item network-state="[[networkState]]">
         </cr-network-icon>
       </template>
       <template is="dom-if" if="[[item.polymerIcon]]">
         <iron-icon icon="[[item.polymerIcon]]"></iron-icon>
       </template>
       <div id="divText" class="layout horizontal flex">
-        <div id="itemName" is-list-item$="[[isListItem]]">
-          [[ariaLabel]]
-        </div>
+        <div>[[ariaLabel]]</div>
         <div id="networkStateText"
-            hidden$="[[!isStateTextVisible_(networkState, isListItem)]]"
-            connected$="[[isStateTextConnected_(networkState, isListItem)]]">
-          [[getNetworkStateText_(networkState, isListItem)]]
+            hidden$="[[!isStateTextVisible_(networkState)]]"
+            connected$="[[isConnected_(networkState)]]">
+          [[getNetworkStateText_(networkState)]]
         </div>
       </div>
       <template is="dom-if" if="[[isPolicySource(networkState.Source)]]">
diff --git a/ui/webui/resources/cr_elements/network/cr_network_list_item.js b/ui/webui/resources/cr_elements/network/cr_network_list_item.js
index 919b357..5e3992a5 100644
--- a/ui/webui/resources/cr_elements/network/cr_network_list_item.js
+++ b/ui/webui/resources/cr_elements/network/cr_network_list_item.js
@@ -4,7 +4,7 @@
 
 /**
  * @fileoverview Polymer element for displaying information about a network
- * in a list or summary based on ONC state properties.
+ * in a list based on ONC state properties.
  */
 
 Polymer({
@@ -26,19 +26,6 @@
       observer: 'networkStateChanged_',
     },
 
-    /**
-     * Determines how the list item will be displayed:
-     *  True - Displays the network icon (with strength) and name
-     *  False - The element is a stand-alone item (e.g. part of a summary)
-     *      and displays the name of the network type plus the network name
-     *      and connection state.
-     */
-    isListItem: {
-      type: Boolean,
-      value: false,
-      reflectToAttribute: true,
-    },
-
     /** Whether to show any buttons for network items. Defaults to false. */
     showButtons: {
       type: Boolean,
@@ -61,7 +48,7 @@
       type: String,
       notify: true,
       reflectToAttribute: true,
-      computed: 'getItemName_(item, isListItem)',
+      computed: 'getItemName_(item)',
     },
   },
 
@@ -99,9 +86,7 @@
       return name;
     }
     var network = /** @type {!CrOnc.NetworkStateProperties} */ (this.item);
-    if (this.isListItem)
-      return CrOnc.getNetworkName(network);
-    return CrOncStrings['OncType' + network.Type];
+    return CrOnc.getNetworkName(network);
   },
 
   /**
@@ -110,16 +95,8 @@
    */
   isStateTextVisible_: function() {
     return !!this.networkState &&
-        (!this.isListItem || (this.networkState.ConnectionState !=
-                              CrOnc.ConnectionState.NOT_CONNECTED));
-  },
-
-  /**
-   * @return {boolean}
-   * @private
-   */
-  isStateTextConnected_: function() {
-    return this.isListItem && this.isConnected_();
+        (this.networkState.ConnectionState !=
+         CrOnc.ConnectionState.NOT_CONNECTED);
   },
 
   /**
@@ -130,41 +107,12 @@
   getNetworkStateText_: function() {
     if (!this.isStateTextVisible_())
       return '';
-    var network = this.networkState;
-    var state = network.ConnectionState;
-    var name = CrOnc.getNetworkName(network);
-    if (this.isListItem) {
-      if (state == CrOnc.ConnectionState.CONNECTED)
-        return CrOncStrings.networkListItemConnected;
-      if (state == CrOnc.ConnectionState.CONNECTING)
-        return CrOncStrings.networkListItemConnecting;
-      return '';
-    }
-    if (name && state)
-      return this.getConnectionStateText_(state, name);
-    return CrOncStrings.networkDisabled;
-  },
-
-  /**
-   * Returns the appropriate connection state text.
-   * @param {CrOnc.ConnectionState} state The connection state.
-   * @param {string} name The name of the network.
-   * @return {string}
-   * @private
-   */
-  getConnectionStateText_: function(state, name) {
-    switch (state) {
-      case CrOnc.ConnectionState.CONNECTED:
-        return name;
-      case CrOnc.ConnectionState.CONNECTING:
-        if (name)
-          return CrOncStrings.networkListItemConnectingTo.replace('$1', name);
-        return CrOncStrings.networkListItemConnecting;
-      case CrOnc.ConnectionState.NOT_CONNECTED:
-        return CrOncStrings.networkListItemNotConnected;
-    }
-    assertNotReached();
-    return state;
+    var state = this.networkState.ConnectionState;
+    if (state == CrOnc.ConnectionState.CONNECTED)
+      return CrOncStrings.networkListItemConnected;
+    if (state == CrOnc.ConnectionState.CONNECTING)
+      return CrOncStrings.networkListItemConnecting;
+    return '';
   },
 
   /**
diff --git a/ui/webui/resources/cr_elements/network/cr_onc_types.js b/ui/webui/resources/cr_elements/network/cr_onc_types.js
index d3a5b758..06303bd 100644
--- a/ui/webui/resources/cr_elements/network/cr_onc_types.js
+++ b/ui/webui/resources/cr_elements/network/cr_onc_types.js
@@ -25,7 +25,6 @@
  *   OncTypeVPN: string,
  *   OncTypeWiFi: string,
  *   OncTypeWiMAX: string,
- *   networkDisabled: string,
  *   networkListItemConnected: string,
  *   networkListItemConnecting: string,
  *   networkListItemConnectingTo: string,
diff --git a/ui/wm/core/default_activation_client.cc b/ui/wm/core/default_activation_client.cc
index 2564788..cab8cd95 100644
--- a/ui/wm/core/default_activation_client.cc
+++ b/ui/wm/core/default_activation_client.cc
@@ -68,7 +68,7 @@
 void DefaultActivationClient::ActivateWindowImpl(
     aura::client::ActivationChangeObserver::ActivationReason reason,
     aura::Window* window) {
-  aura::Window* last_active = GetActiveWindow();
+  aura::Window* last_active = ActivationClient::GetActiveWindow();
   if (last_active == window)
     return;
 
@@ -104,7 +104,7 @@
     ActivateWindow(last_active_);
 }
 
-aura::Window* DefaultActivationClient::GetActiveWindow() {
+const aura::Window* DefaultActivationClient::GetActiveWindow() const {
   if (active_windows_.empty())
     return nullptr;
   return active_windows_.back();
@@ -132,7 +132,7 @@
 
   if (window == GetActiveWindow()) {
     active_windows_.pop_back();
-    aura::Window* next_active = GetActiveWindow();
+    aura::Window* next_active = ActivationClient::GetActiveWindow();
     if (next_active && aura::client::GetActivationChangeObserver(next_active)) {
       aura::client::GetActivationChangeObserver(next_active)
           ->OnWindowActivated(aura::client::ActivationChangeObserver::
diff --git a/ui/wm/core/default_activation_client.h b/ui/wm/core/default_activation_client.h
index 073e281..1f8ccb5a 100644
--- a/ui/wm/core/default_activation_client.h
+++ b/ui/wm/core/default_activation_client.h
@@ -39,7 +39,7 @@
       aura::client::ActivationChangeObserver* observer) override;
   void ActivateWindow(aura::Window* window) override;
   void DeactivateWindow(aura::Window* window) override;
-  aura::Window* GetActiveWindow() override;
+  const aura::Window* GetActiveWindow() const override;
   aura::Window* GetActivatableWindow(aura::Window* window) override;
   aura::Window* GetToplevelWindow(aura::Window* window) override;
   bool CanActivateWindow(aura::Window* window) const override;
diff --git a/ui/wm/core/focus_controller.cc b/ui/wm/core/focus_controller.cc
index 594e66e..230de21 100644
--- a/ui/wm/core/focus_controller.cc
+++ b/ui/wm/core/focus_controller.cc
@@ -72,7 +72,7 @@
     FocusWindow(rules_->GetNextActivatableWindow(window));
 }
 
-aura::Window* FocusController::GetActiveWindow() {
+const aura::Window* FocusController::GetActiveWindow() const {
   return active_window_;
 }
 
diff --git a/ui/wm/core/focus_controller.h b/ui/wm/core/focus_controller.h
index 85858cf..66b2b8d 100644
--- a/ui/wm/core/focus_controller.h
+++ b/ui/wm/core/focus_controller.h
@@ -55,7 +55,7 @@
       aura::client::ActivationChangeObserver* observer) override;
   void ActivateWindow(aura::Window* window) override;
   void DeactivateWindow(aura::Window* window) override;
-  aura::Window* GetActiveWindow() override;
+  const aura::Window* GetActiveWindow() const override;
   aura::Window* GetActivatableWindow(aura::Window* window) override;
   aura::Window* GetToplevelWindow(aura::Window* window) override;
   bool CanActivateWindow(aura::Window* window) const override;
diff --git a/ui/wm/core/shadow_controller.cc b/ui/wm/core/shadow_controller.cc
index 6fc4366..d2b07863 100644
--- a/ui/wm/core/shadow_controller.cc
+++ b/ui/wm/core/shadow_controller.cc
@@ -19,7 +19,6 @@
 #include "ui/base/ui_base_types.h"
 #include "ui/compositor/layer.h"
 #include "ui/wm/core/shadow.h"
-#include "ui/wm/core/shadow_types.h"
 #include "ui/wm/core/window_util.h"
 #include "ui/wm/public/activation_client.h"
 
@@ -32,7 +31,6 @@
 
 namespace {
 
-constexpr ShadowElevation kActiveNormalShadowElevation = ShadowElevation::LARGE;
 constexpr ShadowElevation kInactiveNormalShadowElevation =
     ShadowElevation::MEDIUM;
 
@@ -67,7 +65,7 @@
     return elevation;
 
   if (IsActiveWindow(window))
-    return kActiveNormalShadowElevation;
+    return ShadowController::kActiveNormalShadowElevation;
 
   return GetDefaultShadowElevationForWindow(window);
 }
@@ -84,7 +82,7 @@
                   GetTransientChildren(losing_active).end(),
                   gaining_active);
     if (it != GetTransientChildren(losing_active).end())
-      return kActiveNormalShadowElevation;
+      return ShadowController::kActiveNormalShadowElevation;
   }
   return kInactiveNormalShadowElevation;
 }
diff --git a/ui/wm/core/shadow_controller.h b/ui/wm/core/shadow_controller.h
index c1106fe..d1bfafa 100644
--- a/ui/wm/core/shadow_controller.h
+++ b/ui/wm/core/shadow_controller.h
@@ -10,6 +10,7 @@
 #include "base/compiler_specific.h"
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
+#include "ui/wm/core/shadow_types.h"
 #include "ui/wm/public/activation_change_observer.h"
 #include "ui/wm/wm_export.h"
 
@@ -31,6 +32,9 @@
 class WM_EXPORT ShadowController :
     public aura::client::ActivationChangeObserver {
  public:
+  static constexpr ShadowElevation kActiveNormalShadowElevation =
+      ShadowElevation::LARGE;
+
   // Returns the shadow for the |window|, or NULL if no shadow exists.
   static Shadow* GetShadowForWindow(aura::Window* window);
 
diff --git a/ui/wm/core/window_util.cc b/ui/wm/core/window_util.cc
index 58e4885..7d72e58 100644
--- a/ui/wm/core/window_util.cc
+++ b/ui/wm/core/window_util.cc
@@ -67,11 +67,11 @@
       window);
 }
 
-bool IsActiveWindow(aura::Window* window) {
+bool IsActiveWindow(const aura::Window* window) {
   DCHECK(window);
   if (!window->GetRootWindow())
     return false;
-  aura::client::ActivationClient* client =
+  const aura::client::ActivationClient* client =
       aura::client::GetActivationClient(window->GetRootWindow());
   return client && client->GetActiveWindow() == window;
 }
diff --git a/ui/wm/core/window_util.h b/ui/wm/core/window_util.h
index 7bc66b4..1bd9cb8b 100644
--- a/ui/wm/core/window_util.h
+++ b/ui/wm/core/window_util.h
@@ -25,7 +25,7 @@
 
 WM_EXPORT void ActivateWindow(aura::Window* window);
 WM_EXPORT void DeactivateWindow(aura::Window* window);
-WM_EXPORT bool IsActiveWindow(aura::Window* window);
+WM_EXPORT bool IsActiveWindow(const aura::Window* window);
 WM_EXPORT bool CanActivateWindow(aura::Window* window);
 WM_EXPORT void SetWindowFullscreen(aura::Window* window, bool fullscreen);
 
diff --git a/ui/wm/public/activation_client.cc b/ui/wm/public/activation_client.cc
index 85636c0..fcf0173 100644
--- a/ui/wm/public/activation_client.cc
+++ b/ui/wm/public/activation_client.cc
@@ -21,9 +21,14 @@
   root_window->SetProperty(kRootWindowActivationClientKey, client);
 }
 
+const ActivationClient* GetActivationClient(const Window* root_window) {
+  return root_window ? root_window->GetProperty(kRootWindowActivationClientKey)
+                     : nullptr;
+}
+
 ActivationClient* GetActivationClient(Window* root_window) {
-  return root_window ?
-      root_window->GetProperty(kRootWindowActivationClientKey) : NULL;
+  return root_window ? root_window->GetProperty(kRootWindowActivationClientKey)
+                     : nullptr;
 }
 
 void SetHideOnDeactivate(Window* window, bool hide_on_deactivate) {
diff --git a/ui/wm/public/activation_client.h b/ui/wm/public/activation_client.h
index 0607ea1..401ceb5 100644
--- a/ui/wm/public/activation_client.h
+++ b/ui/wm/public/activation_client.h
@@ -28,7 +28,11 @@
   virtual void DeactivateWindow(Window* window) = 0;
 
   // Retrieves the active window, or NULL if there is none.
-  virtual Window* GetActiveWindow() = 0;
+  Window* GetActiveWindow() {
+    return const_cast<Window*>(
+        const_cast<const ActivationClient*>(this)->GetActiveWindow());
+  }
+  virtual const Window* GetActiveWindow() const = 0;
 
   // Retrieves the activatable window for |window|, or NULL if there is none.
   // Note that this is often but not always the toplevel window (see
@@ -52,6 +56,8 @@
 AURA_EXPORT void SetActivationClient(Window* root_window,
                                      ActivationClient* client);
 AURA_EXPORT ActivationClient* GetActivationClient(Window* root_window);
+AURA_EXPORT const ActivationClient* GetActivationClient(
+    const Window* root_window);
 
 // Some types of transient window are only visible when active.
 // The transient parents of these windows may have visual appearance properties