diff --git a/DEPS b/DEPS
index ffe3b05..13f354a 100644
--- a/DEPS
+++ b/DEPS
@@ -40,7 +40,7 @@
   # 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': '7fc4a2d2f0eb57f94f5ef9a0f759a099a4320a54',
+  'skia_revision': '7f302c4682f5d6eb9dc61f1fb1d12e1079024f70',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling V8
   # and whatever else without interference from each other.
@@ -205,7 +205,7 @@
     Var('chromium_git') + '/webm/libvpx.git' + '@' +  '91f87e75135cc9722ee72daf5154424f628a906e',
 
   'src/third_party/ffmpeg':
-    Var('chromium_git') + '/chromium/third_party/ffmpeg.git' + '@' + '38d84d205cd89cb9ce740735d2d31d4bc2a07abb',
+    Var('chromium_git') + '/chromium/third_party/ffmpeg.git' + '@' + '3f3ad2ea90df08f5907bd997e1ce22e1c19ce215',
 
   'src/third_party/usrsctp/usrsctplib':
     Var('chromium_git') + '/external/github.com/sctplab/usrsctp' + '@' + '8679f2b0bf063ac894dc473debefd61dbbebf622',
@@ -232,7 +232,7 @@
     Var('chromium_git') + '/native_client/src/third_party/scons-2.0.1.git' + '@' + '1c1550e17fc26355d08627fbdec13d8291227067',
 
   'src/third_party/webrtc':
-    Var('chromium_git') + '/external/webrtc/trunk/webrtc.git' + '@' + 'c78eb98bfddb7a54352a56cd039558d75fca7ee0', # commit position 16656
+    Var('chromium_git') + '/external/webrtc/trunk/webrtc.git' + '@' + '365b8a20ce38c37e5489ffcbd4f255558aa526bb', # commit position 16686
 
   'src/third_party/openmax_dl':
     Var('chromium_git') + '/external/webrtc/deps/third_party/openmax.git' + '@' +  Var('openmax_dl_revision'),
@@ -299,7 +299,7 @@
     Var('chromium_git') + '/external/github.com/cisco/openh264' + '@' + '0fd88df93c5dcaf858c57eb7892bd27763f0f0ac',
 
   'src/third_party/re2/src':
-    Var('chromium_git') + '/external/github.com/google/re2.git' + '@' + '596d73e6084a88c5394724978b10680dc929d197',
+    Var('chromium_git') + '/external/github.com/google/re2.git' + '@' + '193486d7164a40ce28d8ec64552df129c0558bad',
 
   # Used for building libFuzzers (only supports Linux).
   'src/third_party/libFuzzer/src':
diff --git a/ash/BUILD.gn b/ash/BUILD.gn
index c4f80f3..ec4f910 100644
--- a/ash/BUILD.gn
+++ b/ash/BUILD.gn
@@ -591,9 +591,7 @@
     "common/wm_transient_window_observer.h",
     "common/wm_window.cc",
     "common/wm_window.h",
-    "common/wm_window_observer.h",
     "common/wm_window_property.h",
-    "common/wm_window_tracker.h",
     "common/wm_window_user_data.h",
     "debug.cc",
     "debug.h",
diff --git a/ash/common/devtools/ash_devtools_dom_agent.cc b/ash/common/devtools/ash_devtools_dom_agent.cc
index cd803f59..fe2e631 100644
--- a/ash/common/devtools/ash_devtools_dom_agent.cc
+++ b/ash/common/devtools/ash_devtools_dom_agent.cc
@@ -138,41 +138,41 @@
 }
 
 // Handles removing windows.
-void AshDevToolsDOMAgent::OnWindowTreeChanging(WmWindow* window,
-                                               const TreeChangeParams& params) {
-  // Only trigger this when window == params.old_parent.
+void AshDevToolsDOMAgent::OnWindowHierarchyChanging(
+    const HierarchyChangeParams& params) {
+  // Only trigger this when params.receiver == params.old_parent.
   // Only removals are handled here. Removing a node can occur as a result of
-  // reorganizing a window or just destroying it. OnWindowTreeChanged
+  // reorganizing a window or just destroying it. OnWindowHierarchyChanged
   // is only called if there is a new_parent. The only case this method isn't
   // called is when adding a node because old_parent is then null.
   // 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 (window == params.old_parent)
-    RemoveWindowTree(params.target, true);
+  if (params.receiver == params.old_parent)
+    RemoveWindowTree(WmWindow::Get(params.target), true);
 }
 
 // Handles adding windows.
-void AshDevToolsDOMAgent::OnWindowTreeChanged(WmWindow* window,
-                                              const TreeChangeParams& params) {
-  // Only trigger this when window == params.new_parent.
+void AshDevToolsDOMAgent::OnWindowHierarchyChanged(
+    const HierarchyChangeParams& params) {
+  // Only trigger this when params.receiver == params.new_parent.
   // If there is an old_parent + new_parent, then this window's node was
-  // removed in OnWindowTreeChanging and will now be added to the new_parent.
-  // If there is only a new_parent, OnWindowTreeChanging is never called and
-  // the window is only added here.
-  if (window == params.new_parent)
-    AddWindowTree(params.target);
+  // removed in OnWindowHierarchyChanging and will now be added to the
+  // 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));
 }
 
-void AshDevToolsDOMAgent::OnWindowStackingChanged(WmWindow* window) {
-  RemoveWindowTree(window, false);
-  AddWindowTree(window);
+void AshDevToolsDOMAgent::OnWindowStackingChanged(aura::Window* window) {
+  RemoveWindowTree(WmWindow::Get(window), false);
+  AddWindowTree(WmWindow::Get(window));
 }
 
-void AshDevToolsDOMAgent::OnWindowBoundsChanged(WmWindow* window,
+void AshDevToolsDOMAgent::OnWindowBoundsChanged(aura::Window* window,
                                                 const gfx::Rect& old_bounds,
                                                 const gfx::Rect& new_bounds) {
   for (auto& observer : observers_)
-    observer.OnWindowBoundsChanged(window);
+    observer.OnWindowBoundsChanged(WmWindow::Get(window));
 }
 
 void AshDevToolsDOMAgent::OnWillRemoveView(views::Widget* widget,
@@ -267,8 +267,8 @@
 
   std::unique_ptr<ui::devtools::protocol::DOM::Node> node =
       BuildNode("Window", GetAttributes(window), std::move(children));
-  if (!window->HasObserver(this))
-    window->AddObserver(this);
+  if (!window->aura_window()->HasObserver(this))
+    window->aura_window()->AddObserver(this);
   window_to_node_id_map_[window] = node->getNodeId();
   node_id_to_window_map_[node->getNodeId()] = window;
   return node;
@@ -344,7 +344,7 @@
   DCHECK(node_id_to_window_it != node_id_to_window_map_.end());
 
   if (remove_observer)
-    window->RemoveObserver(this);
+    window->aura_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);
@@ -427,7 +427,7 @@
 
 void AshDevToolsDOMAgent::RemoveObservers() {
   for (auto& pair : window_to_node_id_map_)
-    pair.first->RemoveObserver(this);
+    pair.first->aura_window()->RemoveObserver(this);
   for (auto& pair : widget_to_node_id_map_)
     pair.first->RemoveRemovalsObserver(this);
   for (auto& pair : view_to_node_id_map_)
diff --git a/ash/common/devtools/ash_devtools_dom_agent.h b/ash/common/devtools/ash_devtools_dom_agent.h
index 194dc66..c66a04f2 100644
--- a/ash/common/devtools/ash_devtools_dom_agent.h
+++ b/ash/common/devtools/ash_devtools_dom_agent.h
@@ -6,11 +6,11 @@
 #define ASH_COMMON_DEVTOOLS_ASH_DEVTOOLS_DOM_AGENT_H_
 
 #include "ash/common/wm_shell.h"
-#include "ash/common/wm_window_observer.h"
 #include "base/compiler_specific.h"
 #include "base/observer_list.h"
 #include "components/ui_devtools/DOM.h"
 #include "components/ui_devtools/devtools_base_agent.h"
+#include "ui/aura/window_observer.h"
 #include "ui/views/view.h"
 #include "ui/views/view_observer.h"
 #include "ui/views/widget/widget.h"
@@ -30,7 +30,7 @@
 class ASH_EXPORT AshDevToolsDOMAgent
     : public NON_EXPORTED_BASE(ui::devtools::UiDevToolsBaseAgent<
                                ui::devtools::protocol::DOM::Metainfo>),
-      public WmWindowObserver,
+      public aura::WindowObserver,
       public views::WidgetObserver,
       public views::WidgetRemovalsObserver,
       public views::ViewObserver {
@@ -49,12 +49,10 @@
   ui::devtools::protocol::Response hideHighlight() override;
 
   // WindowObserver
-  void OnWindowTreeChanging(WmWindow* window,
-                            const TreeChangeParams& params) override;
-  void OnWindowTreeChanged(WmWindow* window,
-                           const TreeChangeParams& params) override;
-  void OnWindowStackingChanged(WmWindow* window) override;
-  void OnWindowBoundsChanged(WmWindow* window,
+  void OnWindowHierarchyChanging(const HierarchyChangeParams& params) override;
+  void OnWindowHierarchyChanged(const HierarchyChangeParams& params) override;
+  void OnWindowStackingChanged(aura::Window* window) override;
+  void OnWindowBoundsChanged(aura::Window* window,
                              const gfx::Rect& old_bounds,
                              const gfx::Rect& new_bounds) override;
 
diff --git a/ash/common/frame/custom_frame_view_ash.cc b/ash/common/frame/custom_frame_view_ash.cc
index ac441c4..d75b728 100644
--- a/ash/common/frame/custom_frame_view_ash.cc
+++ b/ash/common/frame/custom_frame_view_ash.cc
@@ -16,10 +16,11 @@
 #include "ash/common/wm_lookup.h"
 #include "ash/common/wm_shell.h"
 #include "ash/common/wm_window.h"
-#include "ash/common/wm_window_observer.h"
 #include "ash/common/wm_window_property.h"
 #include "ash/shared/immersive_fullscreen_controller.h"
 #include "ash/shared/immersive_fullscreen_controller_delegate.h"
+#include "ui/aura/window.h"
+#include "ui/aura/window_observer.h"
 #include "ui/gfx/geometry/rect.h"
 #include "ui/gfx/geometry/rect_conversions.h"
 #include "ui/gfx/geometry/size.h"
@@ -40,7 +41,7 @@
 // windows.
 class CustomFrameViewAshWindowStateDelegate : public wm::WindowStateDelegate,
                                               public wm::WindowStateObserver,
-                                              public WmWindowObserver {
+                                              public aura::WindowObserver {
  public:
   CustomFrameViewAshWindowStateDelegate(wm::WindowState* window_state,
                                         CustomFrameViewAsh* custom_frame_view,
@@ -53,7 +54,7 @@
     // TODO(pkotwicz): This is a hack. Remove ASAP. http://crbug.com/319048
     window_state_ = window_state;
     window_state_->AddObserver(this);
-    window_state_->window()->AddObserver(this);
+    window_state_->window()->aura_window()->AddObserver(this);
 
     if (!enable_immersive)
       return;
@@ -68,7 +69,7 @@
   ~CustomFrameViewAshWindowStateDelegate() override {
     if (window_state_) {
       window_state_->RemoveObserver(this);
-      window_state_->window()->RemoveObserver(this);
+      window_state_->window()->aura_window()->RemoveObserver(this);
     }
   }
 
@@ -86,8 +87,8 @@
     }
     return true;
   }
-  // Overridden from WmWindowObserver:
-  void OnWindowDestroying(WmWindow* window) override {
+  // Overridden from aura::WindowObserver:
+  void OnWindowDestroying(aura::Window* window) override {
     window_state_->RemoveObserver(this);
     window->RemoveObserver(this);
     window_state_ = nullptr;
diff --git a/ash/common/shelf/shelf_window_watcher.cc b/ash/common/shelf/shelf_window_watcher.cc
index accb7ce..7a00df9d 100644
--- a/ash/common/shelf/shelf_window_watcher.cc
+++ b/ash/common/shelf/shelf_window_watcher.cc
@@ -13,38 +13,57 @@
 #include "ash/common/wm/window_state.h"
 #include "ash/common/wm_shell.h"
 #include "ash/common/wm_window.h"
-#include "ash/common/wm_window_property.h"
 #include "ash/public/cpp/shell_window_ids.h"
+#include "ash/public/cpp/window_properties.h"
+#include "ash/shell.h"
+#include "ash/wm/window_properties.h"
+#include "ash/wm/window_state_aura.h"
+#include "ash/wm/window_util.h"
+#include "ui/aura/client/aura_constants.h"
+#include "ui/aura/env.h"
+#include "ui/aura/window.h"
 #include "ui/display/display.h"
 #include "ui/display/screen.h"
+#include "ui/wm/public/activation_client.h"
 
 namespace ash {
 namespace {
 
+// Returns the shelf item type, with special temporary behavior for Mash:
+// Mash provides a default shelf item type (TYPE_APP) for non-ignored windows.
+ShelfItemType GetShelfItemType(aura::Window* window) {
+  if (aura::Env::GetInstance()->mode() == aura::Env::Mode::LOCAL ||
+      window->GetProperty(kShelfItemTypeKey) != TYPE_UNDEFINED) {
+    return static_cast<ShelfItemType>(window->GetProperty(kShelfItemTypeKey));
+  }
+  return wm::GetWindowState(window)->ignored_by_shelf() ? TYPE_UNDEFINED
+                                                        : TYPE_APP;
+}
+
 // Update the ShelfItem from relevant window properties.
-void UpdateShelfItemForWindow(ShelfItem* item, WmWindow* window) {
-  item->type = static_cast<ShelfItemType>(
-      window->GetIntProperty(WmWindowProperty::SHELF_ITEM_TYPE));
+void UpdateShelfItemForWindow(ShelfItem* item, aura::Window* window) {
+  item->type = GetShelfItemType(window);
 
   item->status = STATUS_RUNNING;
-  if (window->IsActive())
+  if (wm::IsActiveWindow(window))
     item->status = STATUS_ACTIVE;
-  else if (window->GetBoolProperty(WmWindowProperty::DRAW_ATTENTION))
+  else if (window->GetProperty(aura::client::kDrawAttentionKey))
     item->status = STATUS_ATTENTION;
 
-  item->app_id = window->GetStringProperty(WmWindowProperty::APP_ID);
+  const std::string* app_id = window->GetProperty(aura::client::kAppIdKey);
+  item->app_id = app_id ? *app_id : std::string();
 
   // Prefer app icons over window icons, they're typically larger.
-  item->image = window->GetAppIcon();
-  if (item->image.isNull())
-    item->image = window->GetWindowIcon();
+  gfx::ImageSkia* image = window->GetProperty(aura::client::kAppIconKey);
+  if (!image || image->isNull())
+    image = window->GetProperty(aura::client::kWindowIconKey);
+  item->image = image ? *image : gfx::ImageSkia();
 
   item->title = window->GetTitle();
 
   // Do not show tooltips for visible attached app panel windows.
-  item->shows_tooltip =
-      item->type != TYPE_APP_PANEL || !window->IsVisible() ||
-      !window->GetBoolProperty(WmWindowProperty::PANEL_ATTACHED);
+  item->shows_tooltip = item->type != TYPE_APP_PANEL || !window->IsVisible() ||
+                        !window->GetProperty(kPanelAttachedKey);
 }
 
 }  // namespace
@@ -55,21 +74,18 @@
 
 ShelfWindowWatcher::ContainerWindowObserver::~ContainerWindowObserver() {}
 
-void ShelfWindowWatcher::ContainerWindowObserver::OnWindowTreeChanged(
-    WmWindow* window,
-    const TreeChangeParams& params) {
+void ShelfWindowWatcher::ContainerWindowObserver::OnWindowHierarchyChanged(
+    const HierarchyChangeParams& params) {
   if (!params.old_parent && params.new_parent &&
-      (params.new_parent->GetShellWindowId() ==
-           kShellWindowId_DefaultContainer ||
-       params.new_parent->GetShellWindowId() ==
-           kShellWindowId_PanelContainer)) {
+      (params.new_parent->id() == kShellWindowId_DefaultContainer ||
+       params.new_parent->id() == kShellWindowId_PanelContainer)) {
     // A new window was created in the default container or the panel container.
     window_watcher_->OnUserWindowAdded(params.target);
   }
 }
 
 void ShelfWindowWatcher::ContainerWindowObserver::OnWindowDestroying(
-    WmWindow* window) {
+    aura::Window* window) {
   window_watcher_->OnContainerWindowDestroying(window);
 }
 
@@ -82,25 +98,24 @@
 ShelfWindowWatcher::UserWindowObserver::~UserWindowObserver() {}
 
 void ShelfWindowWatcher::UserWindowObserver::OnWindowPropertyChanged(
-    WmWindow* window,
-    WmWindowProperty property) {
-  if (property == WmWindowProperty::APP_ICON ||
-      property == WmWindowProperty::APP_ID ||
-      property == WmWindowProperty::DRAW_ATTENTION ||
-      property == WmWindowProperty::PANEL_ATTACHED ||
-      property == WmWindowProperty::SHELF_ITEM_TYPE ||
-      property == WmWindowProperty::WINDOW_ICON) {
+    aura::Window* window,
+    const void* key,
+    intptr_t old) {
+  if (key == aura::client::kAppIconKey || key == aura::client::kAppIdKey ||
+      key == aura::client::kDrawAttentionKey ||
+      key == aura::client::kWindowIconKey || key == kPanelAttachedKey ||
+      key == kShelfItemTypeKey) {
     window_watcher_->OnUserWindowPropertyChanged(window);
   }
 }
 
 void ShelfWindowWatcher::UserWindowObserver::OnWindowDestroying(
-    WmWindow* window) {
+    aura::Window* window) {
   window_watcher_->OnUserWindowDestroying(window);
 }
 
 void ShelfWindowWatcher::UserWindowObserver::OnWindowVisibilityChanged(
-    WmWindow* window,
+    aura::Window* window,
     bool visible) {
   // OnWindowVisibilityChanged() is called for descendants too. We only care
   // about changes to the visibility of windows we know about.
@@ -112,7 +127,7 @@
 }
 
 void ShelfWindowWatcher::UserWindowObserver::OnWindowTitleChanged(
-    WmWindow* window) {
+    aura::Window* window) {
   window_watcher_->OnUserWindowPropertyChanged(window);
 }
 
@@ -124,7 +139,7 @@
       user_window_observer_(this),
       observed_container_windows_(&container_window_observer_),
       observed_user_windows_(&user_window_observer_) {
-  WmShell::Get()->AddActivationObserver(this);
+  Shell::GetInstance()->activation_client()->AddObserver(this);
   for (const auto& display : display::Screen::GetScreen()->GetAllDisplays())
     OnDisplayAdded(display);
   display::Screen::GetScreen()->AddObserver(this);
@@ -132,42 +147,41 @@
 
 ShelfWindowWatcher::~ShelfWindowWatcher() {
   display::Screen::GetScreen()->RemoveObserver(this);
-  WmShell::Get()->RemoveActivationObserver(this);
+  Shell::GetInstance()->activation_client()->RemoveObserver(this);
 }
 
-void ShelfWindowWatcher::AddShelfItem(WmWindow* window) {
+void ShelfWindowWatcher::AddShelfItem(aura::Window* window) {
   user_windows_with_items_.insert(window);
   ShelfItem item;
   ShelfID id = model_->next_id();
   UpdateShelfItemForWindow(&item, window);
-  window->SetIntProperty(WmWindowProperty::SHELF_ID, id);
+  window->SetProperty(kShelfIDKey, id);
   std::unique_ptr<ShelfItemDelegate> item_delegate(
-      new ShelfWindowWatcherItemDelegate(id, window));
+      new ShelfWindowWatcherItemDelegate(id, WmWindow::Get(window)));
   model_->SetShelfItemDelegate(id, std::move(item_delegate));
   // Panels are inserted on the left so as not to push all existing panels over.
   model_->AddAt(item.type == TYPE_APP_PANEL ? 0 : model_->item_count(), item);
 }
 
-void ShelfWindowWatcher::RemoveShelfItem(WmWindow* window) {
+void ShelfWindowWatcher::RemoveShelfItem(aura::Window* window) {
   user_windows_with_items_.erase(window);
-  int shelf_id = window->GetIntProperty(WmWindowProperty::SHELF_ID);
+  int shelf_id = window->GetProperty(kShelfIDKey);
   DCHECK_NE(shelf_id, kInvalidShelfID);
   int index = model_->ItemIndexByID(shelf_id);
   DCHECK_GE(index, 0);
   model_->RemoveItemAt(index);
-  window->SetIntProperty(WmWindowProperty::SHELF_ID, kInvalidShelfID);
+  window->SetProperty(kShelfIDKey, kInvalidShelfID);
 }
 
-void ShelfWindowWatcher::OnContainerWindowDestroying(WmWindow* container) {
+void ShelfWindowWatcher::OnContainerWindowDestroying(aura::Window* container) {
   observed_container_windows_.Remove(container);
 }
 
-int ShelfWindowWatcher::GetShelfItemIndexForWindow(WmWindow* window) const {
-  return model_->ItemIndexByID(
-      window->GetIntProperty(WmWindowProperty::SHELF_ID));
+int ShelfWindowWatcher::GetShelfItemIndexForWindow(aura::Window* window) const {
+  return model_->ItemIndexByID(window->GetProperty(kShelfIDKey));
 }
 
-void ShelfWindowWatcher::OnUserWindowAdded(WmWindow* window) {
+void ShelfWindowWatcher::OnUserWindowAdded(aura::Window* window) {
   // The window may already be tracked from a prior display or parent container.
   if (observed_user_windows_.IsObserving(window))
     return;
@@ -178,7 +192,7 @@
   OnUserWindowPropertyChanged(window);
 }
 
-void ShelfWindowWatcher::OnUserWindowDestroying(WmWindow* window) {
+void ShelfWindowWatcher::OnUserWindowDestroying(aura::Window* window) {
   if (observed_user_windows_.IsObserving(window))
     observed_user_windows_.Remove(window);
 
@@ -187,9 +201,8 @@
   DCHECK_EQ(0u, user_windows_with_items_.count(window));
 }
 
-void ShelfWindowWatcher::OnUserWindowPropertyChanged(WmWindow* window) {
-  if (window->GetIntProperty(WmWindowProperty::SHELF_ITEM_TYPE) ==
-      TYPE_UNDEFINED) {
+void ShelfWindowWatcher::OnUserWindowPropertyChanged(aura::Window* window) {
+  if (GetShelfItemType(window) == TYPE_UNDEFINED) {
     // Remove |window|'s ShelfItem if it was added by this ShelfWindowWatcher.
     if (user_windows_with_items_.count(window) > 0)
       RemoveShelfItem(window);
@@ -209,8 +222,9 @@
   AddShelfItem(window);
 }
 
-void ShelfWindowWatcher::OnWindowActivated(WmWindow* gained_active,
-                                           WmWindow* lost_active) {
+void ShelfWindowWatcher::OnWindowActivated(ActivationReason reason,
+                                           aura::Window* gained_active,
+                                           aura::Window* lost_active) {
   if (gained_active && user_windows_with_items_.count(gained_active) > 0)
     OnUserWindowPropertyChanged(gained_active);
   if (lost_active && user_windows_with_items_.count(lost_active) > 0)
@@ -219,20 +233,21 @@
 
 void ShelfWindowWatcher::OnDisplayAdded(const display::Display& new_display) {
   WmWindow* root = WmShell::Get()->GetRootWindowForDisplayId(new_display.id());
+  aura::Window* aura_root = WmWindow::GetAuraWindow(root);
 
   // When the primary root window's display is removed, the existing root window
   // is taken over by the new display, and the observer is already set.
-  WmWindow* default_container =
-      root->GetChildByShellWindowId(kShellWindowId_DefaultContainer);
+  aura::Window* default_container =
+      aura_root->GetChildById(kShellWindowId_DefaultContainer);
   if (!observed_container_windows_.IsObserving(default_container)) {
-    for (WmWindow* window : default_container->GetChildren())
+    for (aura::Window* window : default_container->children())
       OnUserWindowAdded(window);
     observed_container_windows_.Add(default_container);
   }
-  WmWindow* panel_container =
-      root->GetChildByShellWindowId(kShellWindowId_PanelContainer);
+  aura::Window* panel_container =
+      aura_root->GetChildById(kShellWindowId_PanelContainer);
   if (!observed_container_windows_.IsObserving(panel_container)) {
-    for (WmWindow* window : panel_container->GetChildren())
+    for (aura::Window* window : panel_container->children())
       OnUserWindowAdded(window);
     observed_container_windows_.Add(panel_container);
   }
diff --git a/ash/common/shelf/shelf_window_watcher.h b/ash/common/shelf/shelf_window_watcher.h
index 59564a1..c683f39 100644
--- a/ash/common/shelf/shelf_window_watcher.h
+++ b/ash/common/shelf/shelf_window_watcher.h
@@ -7,16 +7,15 @@
 
 #include <set>
 
-#include "ash/common/wm_activation_observer.h"
-#include "ash/common/wm_window_observer.h"
 #include "base/macros.h"
 #include "base/scoped_observer.h"
+#include "ui/aura/window_observer.h"
 #include "ui/display/display_observer.h"
+#include "ui/wm/public/activation_change_observer.h"
 
 namespace ash {
 
 class ShelfModel;
-class WmWindow;
 
 // ShelfWindowWatcher creates and handles a ShelfItem for windows in the default
 // container and panels in the panel container that have a valid ShelfItemType
@@ -24,7 +23,7 @@
 // the ShelfItem when the window is added to the default container and maintains
 // it until the window is closed, even if the window is transiently reparented
 // (e.g. during a drag).
-class ShelfWindowWatcher : public WmActivationObserver,
+class ShelfWindowWatcher : public aura::client::ActivationChangeObserver,
                            public display::DisplayObserver {
  public:
   explicit ShelfWindowWatcher(ShelfModel* model);
@@ -32,16 +31,15 @@
 
  private:
   // Observes for windows being added to a root window's default container.
-  class ContainerWindowObserver : public WmWindowObserver {
+  class ContainerWindowObserver : public aura::WindowObserver {
    public:
     explicit ContainerWindowObserver(ShelfWindowWatcher* window_watcher);
     ~ContainerWindowObserver() override;
 
    private:
-    // WmWindowObserver:
-    void OnWindowTreeChanged(WmWindow* window,
-                             const TreeChangeParams& params) override;
-    void OnWindowDestroying(WmWindow* window) override;
+    // aura::WindowObserver:
+    void OnWindowHierarchyChanged(const HierarchyChangeParams& params) override;
+    void OnWindowDestroying(aura::Window* window) override;
 
     ShelfWindowWatcher* window_watcher_;
 
@@ -50,18 +48,19 @@
 
   // Observes individual user windows to detect when they are closed or when
   // their shelf item properties have changed.
-  class UserWindowObserver : public WmWindowObserver {
+  class UserWindowObserver : public aura::WindowObserver {
    public:
     explicit UserWindowObserver(ShelfWindowWatcher* window_watcher);
     ~UserWindowObserver() override;
 
    private:
-    // WmWindowObserver:
-    void OnWindowPropertyChanged(WmWindow* window,
-                                 WmWindowProperty property) override;
-    void OnWindowDestroying(WmWindow* window) override;
-    void OnWindowVisibilityChanged(WmWindow* window, bool visible) override;
-    void OnWindowTitleChanged(WmWindow* window) override;
+    // aura::WindowObserver:
+    void OnWindowPropertyChanged(aura::Window* window,
+                                 const void* key,
+                                 intptr_t old) override;
+    void OnWindowDestroying(aura::Window* window) override;
+    void OnWindowVisibilityChanged(aura::Window* window, bool visible) override;
+    void OnWindowTitleChanged(aura::Window* window) override;
 
     ShelfWindowWatcher* window_watcher_;
 
@@ -69,30 +68,31 @@
   };
 
   // Creates a ShelfItem for |window|.
-  void AddShelfItem(WmWindow* window);
+  void AddShelfItem(aura::Window* window);
 
   // Removes a ShelfItem for |window|.
-  void RemoveShelfItem(WmWindow* window);
+  void RemoveShelfItem(aura::Window* window);
 
   // Returns the index of ShelfItem associated with |window|, or -1 if none.
-  int GetShelfItemIndexForWindow(WmWindow* window) const;
+  int GetShelfItemIndexForWindow(aura::Window* window) const;
 
   // Cleans up observers on |container|.
-  void OnContainerWindowDestroying(WmWindow* container);
+  void OnContainerWindowDestroying(aura::Window* container);
 
   // Adds a shelf item for new windows added to the default container that have
   // a valid ShelfItemType property value.
-  void OnUserWindowAdded(WmWindow* window);
+  void OnUserWindowAdded(aura::Window* window);
 
   // Adds, updates or removes the shelf item based on a property change.
-  void OnUserWindowPropertyChanged(WmWindow* window);
+  void OnUserWindowPropertyChanged(aura::Window* window);
 
   // Removes the shelf item when a window closes.
-  void OnUserWindowDestroying(WmWindow* window);
+  void OnUserWindowDestroying(aura::Window* window);
 
-  // WmActivationObserver:
-  void OnWindowActivated(WmWindow* gained_active,
-                         WmWindow* lost_active) override;
+  // aura::client::ActivationChangeObserver:
+  void OnWindowActivated(ActivationReason reason,
+                         aura::Window* gained_active,
+                         aura::Window* lost_active) override;
 
   // display::DisplayObserver overrides:
   void OnDisplayAdded(const display::Display& display) override;
@@ -105,11 +105,12 @@
   ContainerWindowObserver container_window_observer_;
   UserWindowObserver user_window_observer_;
 
-  ScopedObserver<WmWindow, ContainerWindowObserver> observed_container_windows_;
-  ScopedObserver<WmWindow, UserWindowObserver> observed_user_windows_;
+  ScopedObserver<aura::Window, ContainerWindowObserver>
+      observed_container_windows_;
+  ScopedObserver<aura::Window, UserWindowObserver> observed_user_windows_;
 
   // The set of windows with shelf items managed by this ShelfWindowWatcher.
-  std::set<WmWindow*> user_windows_with_items_;
+  std::set<aura::Window*> user_windows_with_items_;
 
   DISALLOW_COPY_AND_ASSIGN(ShelfWindowWatcher);
 };
diff --git a/ash/common/test/test_shelf_delegate.cc b/ash/common/test/test_shelf_delegate.cc
index d0f21f0c..24a1ad5 100644
--- a/ash/common/test/test_shelf_delegate.cc
+++ b/ash/common/test/test_shelf_delegate.cc
@@ -15,6 +15,7 @@
 #include "ash/common/wm_window_property.h"
 #include "ash/root_window_controller.h"
 #include "base/memory/ptr_util.h"
+#include "ui/aura/window.h"
 
 namespace ash {
 namespace test {
@@ -75,7 +76,7 @@
   ShelfID id = model->next_id();
   item.status = status;
   model->Add(item);
-  window->AddObserver(this);
+  window->aura_window()->AddObserver(this);
 
   model->SetShelfItemDelegate(id,
                               base::MakeUnique<TestShelfItemDelegate>(window));
@@ -90,7 +91,7 @@
   int index = model->ItemIndexByID(shelf_id);
   DCHECK_NE(-1, index);
   model->RemoveItemAt(index);
-  window->RemoveObserver(this);
+  window->aura_window()->RemoveObserver(this);
   if (HasShelfIDToAppIDMapping(shelf_id)) {
     const std::string& app_id = GetAppIDForShelfID(shelf_id);
     if (IsAppPinned(app_id))
@@ -100,17 +101,17 @@
   }
 }
 
-void TestShelfDelegate::OnWindowDestroying(WmWindow* window) {
-  RemoveShelfItemForWindow(window);
+void TestShelfDelegate::OnWindowDestroying(aura::Window* window) {
+  RemoveShelfItemForWindow(WmWindow::Get(window));
 }
 
-void TestShelfDelegate::OnWindowTreeChanging(WmWindow* window,
-                                             const TreeChangeParams& params) {
+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(params.target);
+    RemoveShelfItemForWindow(WmWindow::Get(params.target));
 }
 
 ShelfID TestShelfDelegate::GetShelfIDForAppID(const std::string& app_id) {
diff --git a/ash/common/test/test_shelf_delegate.h b/ash/common/test/test_shelf_delegate.h
index cb71bc5d..a334848 100644
--- a/ash/common/test/test_shelf_delegate.h
+++ b/ash/common/test/test_shelf_delegate.h
@@ -10,17 +10,20 @@
 #include <string>
 
 #include "ash/common/shelf/shelf_delegate.h"
-#include "ash/common/wm_window_observer.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 WmWindowObserver {
+class TestShelfDelegate : public ShelfDelegate, public aura::WindowObserver {
  public:
   TestShelfDelegate();
   ~TestShelfDelegate() override;
@@ -45,9 +48,8 @@
   static TestShelfDelegate* instance() { return instance_; }
 
   // WindowObserver implementation
-  void OnWindowDestroying(WmWindow* window) override;
-  void OnWindowTreeChanging(WmWindow* window,
-                            const TreeChangeParams& params) override;
+  void OnWindowDestroying(aura::Window* window) override;
+  void OnWindowHierarchyChanging(const HierarchyChangeParams& params) override;
 
   // ShelfDelegate implementation.
   ShelfID GetShelfIDForAppID(const std::string& app_id) override;
diff --git a/ash/common/wallpaper/wallpaper_widget_controller.cc b/ash/common/wallpaper/wallpaper_widget_controller.cc
index b86bf61..80952ff 100644
--- a/ash/common/wallpaper/wallpaper_widget_controller.cc
+++ b/ash/common/wallpaper/wallpaper_widget_controller.cc
@@ -67,7 +67,7 @@
       widget_parent_(WmLookup::Get()->GetWindowForWidget(widget)->GetParent()) {
   DCHECK(widget_);
   widget_->AddObserver(this);
-  widget_parent_->AddObserver(this);
+  widget_parent_->aura_window()->AddObserver(this);
 }
 
 WallpaperWidgetController::~WallpaperWidgetController() {
@@ -89,11 +89,11 @@
 
 bool WallpaperWidgetController::Reparent(WmWindow* root_window, int container) {
   if (widget_) {
-    widget_parent_->RemoveObserver(this);
+    widget_parent_->aura_window()->RemoveObserver(this);
     WmWindow* window = WmLookup::Get()->GetWindowForWidget(widget_);
     root_window->GetChildByShellWindowId(container)->AddChild(window);
     widget_parent_ = WmLookup::Get()->GetWindowForWidget(widget_)->GetParent();
-    widget_parent_->AddObserver(this);
+    widget_parent_->aura_window()->AddObserver(this);
     return true;
   }
   // Nothing to reparent.
@@ -101,13 +101,13 @@
 }
 
 void WallpaperWidgetController::RemoveObservers() {
-  widget_parent_->RemoveObserver(this);
+  widget_parent_->aura_window()->RemoveObserver(this);
   widget_->RemoveObserver(this);
   widget_ = nullptr;
 }
 
 void WallpaperWidgetController::OnWindowBoundsChanged(
-    WmWindow* window,
+    aura::Window* window,
     const gfx::Rect& old_bounds,
     const gfx::Rect& new_bounds) {
   SetBounds(new_bounds);
diff --git a/ash/common/wallpaper/wallpaper_widget_controller.h b/ash/common/wallpaper/wallpaper_widget_controller.h
index d125caf..f0c3378 100644
--- a/ash/common/wallpaper/wallpaper_widget_controller.h
+++ b/ash/common/wallpaper/wallpaper_widget_controller.h
@@ -8,8 +8,8 @@
 #include <memory>
 
 #include "ash/ash_export.h"
-#include "ash/common/wm_window_observer.h"
 #include "base/macros.h"
+#include "ui/aura/window_observer.h"
 #include "ui/views/widget/widget_observer.h"
 
 namespace ash {
@@ -22,7 +22,7 @@
 // When the animation completes the old WallpaperWidgetController is
 // destroyed. Exported for tests.
 class ASH_EXPORT WallpaperWidgetController : public views::WidgetObserver,
-                                             public WmWindowObserver {
+                                             public aura::WindowObserver {
  public:
   explicit WallpaperWidgetController(views::Widget* widget);
   ~WallpaperWidgetController() override;
@@ -48,8 +48,8 @@
  private:
   void RemoveObservers();
 
-  // WmWindowObserver:
-  void OnWindowBoundsChanged(WmWindow* window,
+  // aura::WindowObserver:
+  void OnWindowBoundsChanged(aura::Window* window,
                              const gfx::Rect& old_bounds,
                              const gfx::Rect& new_bounds) override;
 
diff --git a/ash/common/wm/always_on_top_controller.cc b/ash/common/wm/always_on_top_controller.cc
index 80a405a..0758e8a5 100644
--- a/ash/common/wm/always_on_top_controller.cc
+++ b/ash/common/wm/always_on_top_controller.cc
@@ -9,6 +9,8 @@
 #include "ash/common/wm_window_property.h"
 #include "ash/public/cpp/shell_window_ids.h"
 #include "base/memory/ptr_util.h"
+#include "ui/aura/client/aura_constants.h"
+#include "ui/aura/window.h"
 
 namespace ash {
 
@@ -19,12 +21,12 @@
       base::MakeUnique<WorkspaceLayoutManager>(viewport));
   // Container should be empty.
   DCHECK(always_on_top_container_->GetChildren().empty());
-  always_on_top_container_->AddObserver(this);
+  always_on_top_container_->aura_window()->AddObserver(this);
 }
 
 AlwaysOnTopController::~AlwaysOnTopController() {
   if (always_on_top_container_)
-    always_on_top_container_->RemoveObserver(this);
+    always_on_top_container_->aura_window()->RemoveObserver(this);
 }
 
 WmWindow* AlwaysOnTopController::GetContainer(WmWindow* window) const {
@@ -46,30 +48,30 @@
   always_on_top_container_->SetLayoutManager(std::move(layout_manager));
 }
 
-void AlwaysOnTopController::OnWindowTreeChanged(
-    WmWindow* window,
-    const TreeChangeParams& params) {
-  if (params.old_parent == always_on_top_container_)
+void AlwaysOnTopController::OnWindowHierarchyChanged(
+    const HierarchyChangeParams& params) {
+  if (WmWindow::Get(params.old_parent) == always_on_top_container_)
     params.target->RemoveObserver(this);
-  else if (params.new_parent == always_on_top_container_)
+  else if (WmWindow::Get(params.new_parent) == always_on_top_container_)
     params.target->AddObserver(this);
 }
 
-void AlwaysOnTopController::OnWindowPropertyChanged(WmWindow* window,
-                                                    WmWindowProperty property) {
-  if (window != always_on_top_container_ &&
-      property == WmWindowProperty::ALWAYS_ON_TOP) {
-    DCHECK(window->GetType() == ui::wm::WINDOW_TYPE_NORMAL ||
-           window->GetType() == ui::wm::WINDOW_TYPE_POPUP);
-    WmWindow* container = GetContainer(window);
-    if (window->GetParent() != container)
-      container->AddChild(window);
+void AlwaysOnTopController::OnWindowPropertyChanged(aura::Window* window,
+                                                    const void* key,
+                                                    intptr_t old) {
+  if (WmWindow::Get(window) != always_on_top_container_ &&
+      key == aura::client::kAlwaysOnTopKey) {
+    DCHECK(window->type() == ui::wm::WINDOW_TYPE_NORMAL ||
+           window->type() == ui::wm::WINDOW_TYPE_POPUP);
+    WmWindow* container = GetContainer(WmWindow::Get(window));
+    if (WmWindow::Get(window->parent()) != container)
+      container->AddChild(WmWindow::Get(window));
   }
 }
 
-void AlwaysOnTopController::OnWindowDestroying(WmWindow* window) {
-  if (window == always_on_top_container_) {
-    always_on_top_container_->RemoveObserver(this);
+void AlwaysOnTopController::OnWindowDestroying(aura::Window* window) {
+  if (WmWindow::Get(window) == always_on_top_container_) {
+    always_on_top_container_->aura_window()->RemoveObserver(this);
     always_on_top_container_ = nullptr;
   }
 }
diff --git a/ash/common/wm/always_on_top_controller.h b/ash/common/wm/always_on_top_controller.h
index cae200a..bdf1446 100644
--- a/ash/common/wm/always_on_top_controller.h
+++ b/ash/common/wm/always_on_top_controller.h
@@ -8,17 +8,19 @@
 #include <memory>
 
 #include "ash/ash_export.h"
-#include "ash/common/wm_window_observer.h"
 #include "base/macros.h"
+#include "ui/aura/window_observer.h"
 
 namespace ash {
+
+class WmWindow;
 class WorkspaceLayoutManager;
 
 // AlwaysOnTopController puts window into proper containers based on its
 // 'AlwaysOnTop' property. That is, putting a window into the worskpace
 // container if its "AlwaysOnTop" property is false. Otherwise, put it in
 // |always_on_top_container_|.
-class ASH_EXPORT AlwaysOnTopController : public WmWindowObserver {
+class ASH_EXPORT AlwaysOnTopController : public aura::WindowObserver {
  public:
   explicit AlwaysOnTopController(WmWindow* viewport);
   ~AlwaysOnTopController() override;
@@ -32,12 +34,12 @@
       std::unique_ptr<WorkspaceLayoutManager> layout_manager);
 
  private:
-  // Overridden from WmWindowObserver:
-  void OnWindowTreeChanged(WmWindow* window,
-                           const TreeChangeParams& params) override;
-  void OnWindowPropertyChanged(WmWindow* window,
-                               WmWindowProperty property) override;
-  void OnWindowDestroying(WmWindow* window) override;
+  // Overridden from aura::WindowObserver:
+  void OnWindowHierarchyChanged(const HierarchyChangeParams& params) override;
+  void OnWindowPropertyChanged(aura::Window* window,
+                               const void* key,
+                               intptr_t old) override;
+  void OnWindowDestroying(aura::Window* window) override;
 
   WmWindow* always_on_top_container_;
 
diff --git a/ash/common/wm/dock/docked_window_layout_manager.cc b/ash/common/wm/dock/docked_window_layout_manager.cc
index e8419aa..93bea20ca 100644
--- a/ash/common/wm/dock/docked_window_layout_manager.cc
+++ b/ash/common/wm/dock/docked_window_layout_manager.cc
@@ -20,6 +20,8 @@
 #include "ash/common/wm_window.h"
 #include "ash/public/cpp/shell_window_ids.h"
 #include "ash/root_window_controller.h"
+#include "ash/screen_util.h"
+#include "ash/wm/window_state_aura.h"
 #include "base/auto_reset.h"
 #include "base/metrics/histogram_macros.h"
 #include "grit/ash_resources.h"
@@ -29,6 +31,7 @@
 #include "ui/display/display.h"
 #include "ui/display/screen.h"
 #include "ui/views/background.h"
+#include "ui/wm/core/window_animations.h"
 
 namespace ash {
 
@@ -306,27 +309,32 @@
 
 ////////////////////////////////////////////////////////////////////////////////
 // A class that observes shelf for bounds changes.
-class DockedWindowLayoutManager::ShelfWindowObserver : public WmWindowObserver {
+class DockedWindowLayoutManager::ShelfWindowObserver
+    : public aura::WindowObserver {
  public:
   explicit ShelfWindowObserver(DockedWindowLayoutManager* docked_layout_manager)
       : docked_layout_manager_(docked_layout_manager) {
     DCHECK(docked_layout_manager_->shelf()->GetWindow());
-    docked_layout_manager_->shelf()->GetWindow()->AddObserver(this);
+    docked_layout_manager_->shelf()->GetWindow()->aura_window()->AddObserver(
+        this);
   }
 
   ~ShelfWindowObserver() override {
     if (docked_layout_manager_->shelf() &&
         docked_layout_manager_->shelf()->GetWindow()) {
-      docked_layout_manager_->shelf()->GetWindow()->RemoveObserver(this);
+      docked_layout_manager_->shelf()
+          ->GetWindow()
+          ->aura_window()
+          ->RemoveObserver(this);
     }
   }
 
-  // WmWindowObserver:
-  void OnWindowBoundsChanged(WmWindow* window,
+  // aura::WindowObserver:
+  void OnWindowBoundsChanged(aura::Window* window,
                              const gfx::Rect& old_bounds,
                              const gfx::Rect& new_bounds) override {
     shelf_bounds_in_screen_ =
-        window->GetParent()->ConvertRectToScreen(new_bounds);
+        ScreenUtil::ConvertRectToScreen(window->parent(), new_bounds);
 
     // When the shelf is auto-hidden, it has an invisible height of 3px used
     // as a hit region which is specific to Chrome OS MD (for non-MD, the 3
@@ -397,7 +405,7 @@
   shelf_observer_.reset();
   shelf_ = nullptr;
   for (WmWindow* child : dock_container_->GetChildren()) {
-    child->RemoveObserver(this);
+    child->aura_window()->RemoveObserver(this);
     child->GetWindowState()->RemoveObserver(this);
   }
   dock_container_->GetShell()->RemoveActivationObserver(this);
@@ -423,7 +431,7 @@
   // case it is already observed.
   wm::WindowState* dragged_state = dragged_window_->GetWindowState();
   if (dragged_window_->GetParent() != dock_container_) {
-    dragged_window_->AddObserver(this);
+    dragged_window_->aura_window()->AddObserver(this);
     dragged_state->AddObserver(this);
   } else if (!IsAnyWindowDocked() && dragged_state->drag_details() &&
              !(dragged_state->drag_details()->bounds_change &
@@ -476,7 +484,7 @@
   // Stop observing a window unless it is docked container's child in which
   // case it needs to keep being observed after the drag completes.
   if (dragged_window_->GetParent() != dock_container_) {
-    dragged_window_->RemoveObserver(this);
+    dragged_window_->aura_window()->RemoveObserver(this);
     dragged_window_->GetWindowState()->RemoveObserver(this);
     if (last_active_window_ == dragged_window_)
       last_active_window_ = nullptr;
@@ -645,7 +653,7 @@
                      : GetEdgeNearestWindow(child);
   }
   MaybeMinimizeChildrenExcept(child);
-  child->AddObserver(this);
+  child->aura_window()->AddObserver(this);
   child->GetWindowState()->AddObserver(this);
   Relayout();
   UpdateDockBounds(DockedWindowLayoutManagerObserver::CHILD_CHANGED);
@@ -671,7 +679,7 @@
   }
   if (last_active_window_ == child)
     last_active_window_ = nullptr;
-  child->RemoveObserver(this);
+  child->aura_window()->RemoveObserver(this);
   child->GetWindowState()->RemoveObserver(this);
   Relayout();
   UpdateDockBounds(DockedWindowLayoutManagerObserver::CHILD_CHANGED);
@@ -759,36 +767,36 @@
 // DockedWindowLayoutManager, WindowObserver implementation:
 
 void DockedWindowLayoutManager::OnWindowBoundsChanged(
-    WmWindow* window,
+    aura::Window* window,
     const gfx::Rect& old_bounds,
     const gfx::Rect& new_bounds) {
   // Only relayout if the dragged window would get docked.
-  if (window == dragged_window_ && is_dragged_window_docked_)
+  if (WmWindow::Get(window) == dragged_window_ && is_dragged_window_docked_)
     Relayout();
 }
 
-void DockedWindowLayoutManager::OnWindowVisibilityChanging(WmWindow* window,
+void DockedWindowLayoutManager::OnWindowVisibilityChanging(aura::Window* window,
                                                            bool visible) {
-  if (IsPopupOrTransient(window))
+  if (IsPopupOrTransient(WmWindow::Get(window)))
     return;
   int animation_type = ::wm::WINDOW_VISIBILITY_ANIMATION_TYPE_DEFAULT;
   if (visible) {
     animation_type = ::wm::WINDOW_VISIBILITY_ANIMATION_TYPE_DROP;
-    window->SetVisibilityAnimationDuration(
-        base::TimeDelta::FromMilliseconds(kFadeDurationMs));
-  } else if (window->GetWindowState()->IsMinimized()) {
+    ::wm::SetWindowVisibilityAnimationDuration(
+        window, base::TimeDelta::FromMilliseconds(kFadeDurationMs));
+  } else if (wm::GetWindowState(window)->IsMinimized()) {
     animation_type = wm::WINDOW_VISIBILITY_ANIMATION_TYPE_MINIMIZE;
   }
-  window->SetVisibilityAnimationType(animation_type);
+  ::wm::SetWindowVisibilityAnimationType(window, animation_type);
 }
 
-void DockedWindowLayoutManager::OnWindowDestroying(WmWindow* window) {
-  if (dragged_window_ == window) {
+void DockedWindowLayoutManager::OnWindowDestroying(aura::Window* window) {
+  if (dragged_window_ == WmWindow::Get(window)) {
     FinishDragging(DOCKED_ACTION_NONE, DOCKED_ACTION_SOURCE_UNKNOWN);
     DCHECK(!dragged_window_);
     DCHECK(!is_dragged_window_docked_);
   }
-  if (window == last_active_window_)
+  if (WmWindow::Get(window) == last_active_window_)
     last_active_window_ = nullptr;
   RecordUmaAction(DOCKED_ACTION_CLOSE, event_source_);
 }
diff --git a/ash/common/wm/dock/docked_window_layout_manager.h b/ash/common/wm/dock/docked_window_layout_manager.h
index d7e0977b..a3f5784d 100644
--- a/ash/common/wm/dock/docked_window_layout_manager.h
+++ b/ash/common/wm/dock/docked_window_layout_manager.h
@@ -14,11 +14,11 @@
 #include "ash/common/wm/window_state_observer.h"
 #include "ash/common/wm/wm_snap_to_pixel_layout_manager.h"
 #include "ash/common/wm_activation_observer.h"
-#include "ash/common/wm_window_observer.h"
 #include "base/compiler_specific.h"
 #include "base/macros.h"
 #include "base/observer_list.h"
 #include "base/time/time.h"
+#include "ui/aura/window_observer.h"
 #include "ui/display/display_observer.h"
 #include "ui/gfx/geometry/rect.h"
 #include "ui/keyboard/keyboard_controller_observer.h"
@@ -45,7 +45,7 @@
 class ASH_EXPORT DockedWindowLayoutManager
     : public wm::WmSnapToPixelLayoutManager,
       public display::DisplayObserver,
-      public WmWindowObserver,
+      public aura::WindowObserver,
       public WmActivationObserver,
       public ShellObserver,
       public keyboard::KeyboardControllerObserver,
@@ -143,12 +143,12 @@
   void OnPreWindowStateTypeChange(wm::WindowState* window_state,
                                   wm::WindowStateType old_type) override;
 
-  // WmWindowObserver:
-  void OnWindowBoundsChanged(WmWindow* window,
+  // aura::WindowObserver:
+  void OnWindowBoundsChanged(aura::Window* window,
                              const gfx::Rect& old_bounds,
                              const gfx::Rect& new_bounds) override;
-  void OnWindowVisibilityChanging(WmWindow* window, bool visible) override;
-  void OnWindowDestroying(WmWindow* window) override;
+  void OnWindowVisibilityChanging(aura::Window* window, bool visible) override;
+  void OnWindowDestroying(aura::Window* window) override;
 
   // WmActivationObserver:
   void OnWindowActivated(WmWindow* gained_active,
diff --git a/ash/common/wm/lock_layout_manager.cc b/ash/common/wm/lock_layout_manager.cc
index ebabf3f..d66c5d42 100644
--- a/ash/common/wm/lock_layout_manager.cc
+++ b/ash/common/wm/lock_layout_manager.cc
@@ -21,7 +21,7 @@
       root_window_(window->GetRootWindow()),
       is_observing_keyboard_(false) {
   WmShell::Get()->AddShellObserver(this);
-  root_window_->AddObserver(this);
+  root_window_->aura_window()->AddObserver(this);
   if (keyboard::KeyboardController::GetInstance()) {
     keyboard::KeyboardController::GetInstance()->AddObserver(this);
     is_observing_keyboard_ = true;
@@ -30,10 +30,10 @@
 
 LockLayoutManager::~LockLayoutManager() {
   if (root_window_)
-    root_window_->RemoveObserver(this);
+    root_window_->aura_window()->RemoveObserver(this);
 
   for (WmWindow* child : window_->GetChildren())
-    child->RemoveObserver(this);
+    child->aura_window()->RemoveObserver(this);
 
   WmShell::Get()->RemoveShellObserver(this);
 
@@ -49,7 +49,7 @@
 }
 
 void LockLayoutManager::OnWindowAddedToLayout(WmWindow* child) {
-  child->AddObserver(this);
+  child->aura_window()->AddObserver(this);
 
   // LockWindowState replaces default WindowState of a child.
   wm::WindowState* window_state = LockWindowState::SetLockWindowState(child);
@@ -58,7 +58,7 @@
 }
 
 void LockLayoutManager::OnWillRemoveWindowFromLayout(WmWindow* child) {
-  child->RemoveObserver(this);
+  child->aura_window()->RemoveObserver(this);
 }
 
 void LockLayoutManager::OnWindowRemovedFromLayout(WmWindow* child) {}
@@ -73,16 +73,16 @@
   window_state->OnWMEvent(&event);
 }
 
-void LockLayoutManager::OnWindowDestroying(WmWindow* window) {
+void LockLayoutManager::OnWindowDestroying(aura::Window* window) {
   window->RemoveObserver(this);
-  if (root_window_ == window)
+  if (root_window_ == WmWindow::Get(window))
     root_window_ = nullptr;
 }
 
-void LockLayoutManager::OnWindowBoundsChanged(WmWindow* window,
+void LockLayoutManager::OnWindowBoundsChanged(aura::Window* window,
                                               const gfx::Rect& old_bounds,
                                               const gfx::Rect& new_bounds) {
-  if (root_window_ == window) {
+  if (root_window_ == WmWindow::Get(window)) {
     const wm::WMEvent wm_event(wm::WM_EVENT_DISPLAY_BOUNDS_CHANGED);
     AdjustWindowsForWorkAreaChange(&wm_event);
   }
diff --git a/ash/common/wm/lock_layout_manager.h b/ash/common/wm/lock_layout_manager.h
index ba571e2..9ba7473 100644
--- a/ash/common/wm/lock_layout_manager.h
+++ b/ash/common/wm/lock_layout_manager.h
@@ -9,8 +9,8 @@
 #include "ash/common/shell_observer.h"
 #include "ash/common/wm/wm_snap_to_pixel_layout_manager.h"
 #include "ash/common/wm/wm_types.h"
-#include "ash/common/wm_window_observer.h"
 #include "base/macros.h"
+#include "ui/aura/window_observer.h"
 #include "ui/gfx/geometry/rect.h"
 #include "ui/keyboard/keyboard_controller.h"
 #include "ui/keyboard/keyboard_controller_observer.h"
@@ -34,7 +34,7 @@
 // with LockWindowState.
 class ASH_EXPORT LockLayoutManager
     : public wm::WmSnapToPixelLayoutManager,
-      public WmWindowObserver,
+      public aura::WindowObserver,
       public ShellObserver,
       public keyboard::KeyboardControllerObserver {
  public:
@@ -50,9 +50,9 @@
   void SetChildBounds(WmWindow* child,
                       const gfx::Rect& requested_bounds) override;
 
-  // Overriden from WmWindowObserver:
-  void OnWindowDestroying(WmWindow* window) override;
-  void OnWindowBoundsChanged(WmWindow* window,
+  // Overriden from aura::WindowObserver:
+  void OnWindowDestroying(aura::Window* window) override;
+  void OnWindowBoundsChanged(aura::Window* window,
                              const gfx::Rect& old_bounds,
                              const gfx::Rect& new_bounds) override;
 
diff --git a/ash/common/wm/maximize_mode/maximize_mode_window_manager.cc b/ash/common/wm/maximize_mode/maximize_mode_window_manager.cc
index 03dee3e..cea2689b 100644
--- a/ash/common/wm/maximize_mode/maximize_mode_window_manager.cc
+++ b/ash/common/wm/maximize_mode/maximize_mode_window_manager.cc
@@ -19,9 +19,12 @@
 #include "ash/common/wm_window_property.h"
 #include "ash/public/cpp/shell_window_ids.h"
 #include "ash/root_window_controller.h"
+#include "ash/shell.h"
+#include "ash/wm/window_state_aura.h"
 #include "base/command_line.h"
 #include "base/memory/ptr_util.h"
 #include "base/stl_util.h"
+#include "ui/aura/client/aura_constants.h"
 #include "ui/display/screen.h"
 
 namespace ash {
@@ -43,7 +46,7 @@
   // transforming windows which are currently in
   // overview: http://crbug.com/366605
   CancelOverview();
-  for (auto* window : added_windows_)
+  for (aura::Window* window : added_windows_)
     window->RemoveObserver(this);
   added_windows_.clear();
   WmShell::Get()->RemoveShellObserver(this);
@@ -62,7 +65,7 @@
   // and not yet tracked.
   if (!ShouldHandleWindow(window) ||
       base::ContainsKey(window_state_map_, window) ||
-      !IsContainerWindow(window->GetParent())) {
+      !IsContainerWindow(window->GetParent()->aura_window())) {
     return;
   }
 
@@ -72,7 +75,7 @@
 void MaximizeModeWindowManager::WindowStateDestroyed(WmWindow* window) {
   // At this time ForgetWindow() should already have been called. If not,
   // someone else must have replaced the "window manager's state object".
-  DCHECK(!window->HasObserver(this));
+  DCHECK(!window->aura_window()->HasObserver(this));
 
   auto it = window_state_map_.find(window);
   DCHECK(it != window_state_map_.end());
@@ -97,7 +100,7 @@
   SetDeferBoundsUpdates(false);
 }
 
-void MaximizeModeWindowManager::OnWindowDestroying(WmWindow* window) {
+void MaximizeModeWindowManager::OnWindowDestroying(aura::Window* window) {
   if (IsContainerWindow(window)) {
     // container window can be removed on display destruction.
     window->RemoveObserver(this);
@@ -109,16 +112,15 @@
   } else {
     // If a known window gets destroyed we need to remove all knowledge about
     // it.
-    ForgetWindow(window);
+    ForgetWindow(WmWindow::Get(window));
   }
 }
 
-void MaximizeModeWindowManager::OnWindowTreeChanged(
-    WmWindow* window,
-    const TreeChangeParams& params) {
+void MaximizeModeWindowManager::OnWindowHierarchyChanged(
+    const HierarchyChangeParams& params) {
   // A window can get removed and then re-added by a drag and drop operation.
   if (params.new_parent && IsContainerWindow(params.new_parent) &&
-      !base::ContainsKey(window_state_map_, params.target)) {
+      !base::ContainsKey(window_state_map_, WmWindow::Get(params.target))) {
     // Don't register the window if the window is invisible. Instead,
     // wait until it becomes visible because the client may update the
     // flag to control if the window should be added.
@@ -129,26 +131,28 @@
       }
       return;
     }
-    MaximizeAndTrackWindow(params.target);
+    MaximizeAndTrackWindow(WmWindow::Get(params.target));
     // When the state got added, the "WM_EVENT_ADDED_TO_WORKSPACE" event got
     // already sent and we have to notify our state again.
-    if (base::ContainsKey(window_state_map_, params.target)) {
+    if (base::ContainsKey(window_state_map_, WmWindow::Get(params.target))) {
       wm::WMEvent event(wm::WM_EVENT_ADDED_TO_WORKSPACE);
-      params.target->GetWindowState()->OnWMEvent(&event);
+      wm::GetWindowState(params.target)->OnWMEvent(&event);
     }
   }
 }
 
-void MaximizeModeWindowManager::OnWindowPropertyChanged(
-    WmWindow* window,
-    WmWindowProperty property) {
+void MaximizeModeWindowManager::OnWindowPropertyChanged(aura::Window* window,
+                                                        const void* key,
+                                                        intptr_t old) {
   // Stop managing |window| if the always-on-top property is added.
-  if (property == WmWindowProperty::ALWAYS_ON_TOP && window->IsAlwaysOnTop())
-    ForgetWindow(window);
+  if (key == aura::client::kAlwaysOnTopKey &&
+      window->GetProperty(aura::client::kAlwaysOnTopKey)) {
+    ForgetWindow(WmWindow::Get(window));
+  }
 }
 
 void MaximizeModeWindowManager::OnWindowBoundsChanged(
-    WmWindow* window,
+    aura::Window* window,
     const gfx::Rect& old_bounds,
     const gfx::Rect& new_bounds) {
   if (!IsContainerWindow(window))
@@ -158,22 +162,22 @@
     pair.second->UpdateWindowPosition(pair.first->GetWindowState());
 }
 
-void MaximizeModeWindowManager::OnWindowVisibilityChanged(WmWindow* window,
+void MaximizeModeWindowManager::OnWindowVisibilityChanged(aura::Window* window,
                                                           bool visible) {
   // Skip if it's already managed.
-  if (base::ContainsKey(window_state_map_, window))
+  if (base::ContainsKey(window_state_map_, WmWindow::Get(window)))
     return;
 
-  if (IsContainerWindow(window->GetParent()) &&
+  if (IsContainerWindow(window->parent()) &&
       base::ContainsValue(added_windows_, window) && visible) {
     added_windows_.erase(window);
     window->RemoveObserver(this);
-    MaximizeAndTrackWindow(window);
+    MaximizeAndTrackWindow(WmWindow::Get(window));
     // When the state got added, the "WM_EVENT_ADDED_TO_WORKSPACE" event got
     // already sent and we have to notify our state again.
-    if (base::ContainsKey(window_state_map_, window)) {
+    if (base::ContainsKey(window_state_map_, WmWindow::Get(window))) {
       wm::WMEvent event(wm::WM_EVENT_ADDED_TO_WORKSPACE);
-      window->GetWindowState()->OnWMEvent(&event);
+      wm::GetWindowState(window)->OnWMEvent(&event);
     }
   }
 }
@@ -231,7 +235,7 @@
     return;
 
   DCHECK(!base::ContainsKey(window_state_map_, window));
-  window->AddObserver(this);
+  window->aura_window()->AddObserver(this);
 
   // We create and remember a maximize mode state which will attach itself to
   // the provided state object.
@@ -245,7 +249,7 @@
   // earlier by someone else. However - at this point there is no other client
   // which replaces the state object and therefore this should not happen.
   DCHECK(it != window_state_map_.end());
-  window->RemoveObserver(this);
+  window->aura_window()->RemoveObserver(this);
 
   // By telling the state object to revert, it will switch back the old
   // State object and destroy itself, calling WindowStateDestroyed().
@@ -277,9 +281,9 @@
   DCHECK(observed_container_windows_.empty());
   // Observe window activations/creations in the default containers on all root
   // windows.
-  for (WmWindow* root : WmShell::Get()->GetAllRootWindows()) {
-    WmWindow* default_container =
-        root->GetChildByShellWindowId(kShellWindowId_DefaultContainer);
+  for (aura::Window* root : Shell::GetInstance()->GetAllRootWindows()) {
+    aura::Window* default_container =
+        root->GetChildById(kShellWindowId_DefaultContainer);
     DCHECK(!base::ContainsKey(observed_container_windows_, default_container));
     default_container->AddObserver(this);
     observed_container_windows_.insert(default_container);
@@ -287,7 +291,7 @@
 }
 
 void MaximizeModeWindowManager::RemoveWindowCreationObservers() {
-  for (WmWindow* window : observed_container_windows_)
+  for (aura::Window* window : observed_container_windows_)
     window->RemoveObserver(this);
   observed_container_windows_.clear();
 }
@@ -299,7 +303,7 @@
   EnableBackdropBehindTopWindowOnEachDisplay(true);
 }
 
-bool MaximizeModeWindowManager::IsContainerWindow(WmWindow* window) {
+bool MaximizeModeWindowManager::IsContainerWindow(aura::Window* window) {
   return base::ContainsKey(observed_container_windows_, window);
 }
 
diff --git a/ash/common/wm/maximize_mode/maximize_mode_window_manager.h b/ash/common/wm/maximize_mode/maximize_mode_window_manager.h
index a47ab2e..4033c522 100644
--- a/ash/common/wm/maximize_mode/maximize_mode_window_manager.h
+++ b/ash/common/wm/maximize_mode/maximize_mode_window_manager.h
@@ -13,8 +13,8 @@
 #include "ash/ash_export.h"
 #include "ash/common/shell_observer.h"
 #include "ash/common/wm/window_state.h"
-#include "ash/common/wm_window_observer.h"
 #include "base/macros.h"
+#include "ui/aura/window_observer.h"
 #include "ui/display/display_observer.h"
 
 namespace ash {
@@ -31,7 +31,7 @@
 // behind the window so that no other windows are visible and/or obscured.
 // With the destruction of the manager all windows will be restored to their
 // original state.
-class ASH_EXPORT MaximizeModeWindowManager : public WmWindowObserver,
+class ASH_EXPORT MaximizeModeWindowManager : public aura::WindowObserver,
                                              public display::DisplayObserver,
                                              public ShellObserver {
  public:
@@ -55,15 +55,15 @@
   void OnOverviewModeEnded() override;
 
   // Overridden from WindowObserver:
-  void OnWindowDestroying(WmWindow* window) override;
-  void OnWindowTreeChanged(WmWindow* window,
-                           const TreeChangeParams& params) override;
-  void OnWindowPropertyChanged(WmWindow* window,
-                               WmWindowProperty window_property) override;
-  void OnWindowBoundsChanged(WmWindow* window,
+  void OnWindowDestroying(aura::Window* window) override;
+  void OnWindowHierarchyChanged(const HierarchyChangeParams& params) override;
+  void OnWindowPropertyChanged(aura::Window* window,
+                               const void* key,
+                               intptr_t old) override;
+  void OnWindowBoundsChanged(aura::Window* window,
                              const gfx::Rect& old_bounds,
                              const gfx::Rect& new_bounds) override;
-  void OnWindowVisibilityChanged(WmWindow* window, bool visible) override;
+  void OnWindowVisibilityChanged(aura::Window* window, bool visible) override;
 
   // display::DisplayObserver overrides:
   void OnDisplayAdded(const display::Display& display) override;
@@ -114,7 +114,7 @@
   void DisplayConfigurationChanged();
 
   // Returns true when the |window| is a container window.
-  bool IsContainerWindow(WmWindow* window);
+  bool IsContainerWindow(aura::Window* window);
 
   // Add a backdrop behind the currently active window on each desktop.
   void EnableBackdropBehindTopWindowOnEachDisplay(bool enable);
@@ -123,10 +123,10 @@
   WindowToState window_state_map_;
 
   // All container windows which have to be tracked.
-  std::unordered_set<WmWindow*> observed_container_windows_;
+  std::unordered_set<aura::Window*> observed_container_windows_;
 
   // Windows added to the container, but not yet shown.
-  std::unordered_set<WmWindow*> added_windows_;
+  std::unordered_set<aura::Window*> added_windows_;
 
   // True if all backdrops are hidden.
   bool backdrops_hidden_;
diff --git a/ash/common/wm/maximize_mode/workspace_backdrop_delegate.cc b/ash/common/wm/maximize_mode/workspace_backdrop_delegate.cc
index c29c9db..3862e76 100644
--- a/ash/common/wm/maximize_mode/workspace_backdrop_delegate.cc
+++ b/ash/common/wm/maximize_mode/workspace_backdrop_delegate.cc
@@ -7,10 +7,10 @@
 #include "ash/common/wm/workspace/workspace_layout_manager_backdrop_delegate.h"
 #include "ash/common/wm_lookup.h"
 #include "ash/common/wm_window.h"
-#include "ash/common/wm_window_observer.h"
 #include "ash/public/cpp/shell_window_ids.h"
 #include "ash/root_window_controller.h"
 #include "base/auto_reset.h"
+#include "ui/aura/window_observer.h"
 #include "ui/compositor/layer.h"
 #include "ui/compositor/scoped_layer_animation_settings.h"
 #include "ui/views/background.h"
@@ -26,15 +26,16 @@
 
 }  // namespace
 
-class WorkspaceBackdropDelegate::WindowObserverImpl : public WmWindowObserver {
+class WorkspaceBackdropDelegate::WindowObserverImpl
+    : public aura::WindowObserver {
  public:
   explicit WindowObserverImpl(WorkspaceBackdropDelegate* delegate)
       : delegate_(delegate) {}
   ~WindowObserverImpl() override {}
 
  private:
-  // WmWindowObserver overrides:
-  void OnWindowBoundsChanged(WmWindow* window,
+  // aura::WindowObserver overrides:
+  void OnWindowBoundsChanged(aura::Window* window,
                              const gfx::Rect& old_bounds,
                              const gfx::Rect& new_bounds) override {
     // The container size has changed and the layer needs to be adapt to it.
@@ -73,11 +74,11 @@
   DCHECK(background_window_->GetBounds() == params.bounds);
   Show();
   RestackBackdrop();
-  container_->AddObserver(container_observer_.get());
+  container_->aura_window()->AddObserver(container_observer_.get());
 }
 
 WorkspaceBackdropDelegate::~WorkspaceBackdropDelegate() {
-  container_->RemoveObserver(container_observer_.get());
+  container_->aura_window()->RemoveObserver(container_observer_.get());
   // TODO: animations won't work right with mus: http://crbug.com/548396.
   ::wm::ScopedHidingAnimationSettings hiding_settings(
       background_->GetNativeView());
diff --git a/ash/common/wm/mru_window_tracker.cc b/ash/common/wm/mru_window_tracker.cc
index 8378500..df687d8 100644
--- a/ash/common/wm/mru_window_tracker.cc
+++ b/ash/common/wm/mru_window_tracker.cc
@@ -13,6 +13,7 @@
 #include "ash/common/wm_window.h"
 #include "ash/public/cpp/shell_window_ids.h"
 #include "base/bind.h"
+#include "ui/aura/window.h"
 
 namespace ash {
 
@@ -104,7 +105,7 @@
 MruWindowTracker::~MruWindowTracker() {
   WmShell::Get()->RemoveActivationObserver(this);
   for (WmWindow* window : mru_windows_)
-    window->RemoveObserver(this);
+    window->aura_window()->RemoveObserver(this);
 }
 
 MruWindowTracker::WindowList MruWindowTracker::BuildMruWindowList() const {
@@ -137,7 +138,7 @@
       std::find(mru_windows_.begin(), mru_windows_.end(), active_window);
   // Observe all newly tracked windows.
   if (iter == mru_windows_.end())
-    active_window->AddObserver(this);
+    active_window->aura_window()->AddObserver(this);
   else
     mru_windows_.erase(iter);
   mru_windows_.push_front(active_window);
@@ -149,11 +150,11 @@
     SetActiveWindow(gained_active);
 }
 
-void MruWindowTracker::OnWindowDestroyed(WmWindow* window) {
+void MruWindowTracker::OnWindowDestroyed(aura::Window* window) {
   // It's possible for OnWindowActivated() to be called after
   // OnWindowDestroying(). This means we need to override OnWindowDestroyed()
   // else we may end up with a deleted window in |mru_windows_|.
-  mru_windows_.remove(window);
+  mru_windows_.remove(WmWindow::Get(window));
   window->RemoveObserver(this);
 }
 
diff --git a/ash/common/wm/mru_window_tracker.h b/ash/common/wm/mru_window_tracker.h
index ccf0a23..1c820e3 100644
--- a/ash/common/wm/mru_window_tracker.h
+++ b/ash/common/wm/mru_window_tracker.h
@@ -10,8 +10,8 @@
 
 #include "ash/ash_export.h"
 #include "ash/common/wm_activation_observer.h"
-#include "ash/common/wm_window_observer.h"
 #include "base/macros.h"
+#include "ui/aura/window_observer.h"
 
 namespace ash {
 
@@ -20,7 +20,7 @@
 // Maintains a most recently used list of windows. This is used for window
 // cycling using Alt+Tab and overview mode.
 class ASH_EXPORT MruWindowTracker : public WmActivationObserver,
-                                    public WmWindowObserver {
+                                    public aura::WindowObserver {
  public:
   using WindowList = std::vector<WmWindow*>;
 
@@ -51,8 +51,8 @@
   void OnWindowActivated(WmWindow* gained_active,
                          WmWindow* lost_active) override;
 
-  // Overridden from WmWindowObserver:
-  void OnWindowDestroyed(WmWindow* window) override;
+  // Overridden from aura::WindowObserver:
+  void OnWindowDestroyed(aura::Window* window) override;
 
   // List of windows that have been activated in containers that we cycle
   // through, sorted by most recently used.
diff --git a/ash/common/wm/overview/window_grid.cc b/ash/common/wm/overview/window_grid.cc
index 7cea80b..c7c01134 100644
--- a/ash/common/wm/overview/window_grid.cc
+++ b/ash/common/wm/overview/window_grid.cc
@@ -25,6 +25,7 @@
 #include "ash/public/cpp/shelf_types.h"
 #include "ash/public/cpp/shell_window_ids.h"
 #include "ash/root_window_controller.h"
+#include "ash/wm/window_state_aura.h"
 #include "base/command_line.h"
 #include "base/i18n/string_search.h"
 #include "base/memory/ptr_util.h"
@@ -290,7 +291,7 @@
   }
 
   for (auto* window : windows_in_root) {
-    window_observer_.Add(window);
+    window_observer_.Add(window->aura_window());
     window_state_observer_.Add(window->GetWindowState());
     window_list_.push_back(
         base::MakeUnique<WindowSelectorItem>(window, window_selector_));
@@ -568,11 +569,11 @@
   selection_widget_->SetOpacity(0.f);
 }
 
-void WindowGrid::OnWindowDestroying(WmWindow* window) {
+void WindowGrid::OnWindowDestroying(aura::Window* window) {
   window_observer_.Remove(window);
-  window_state_observer_.Remove(window->GetWindowState());
+  window_state_observer_.Remove(wm::GetWindowState(window));
   auto iter = std::find_if(window_list_.begin(), window_list_.end(),
-                           WindowSelectorItemComparator(window));
+                           WindowSelectorItemComparator(WmWindow::Get(window)));
 
   DCHECK(iter != window_list_.end());
 
@@ -599,7 +600,7 @@
   PositionWindows(true);
 }
 
-void WindowGrid::OnWindowBoundsChanged(WmWindow* window,
+void WindowGrid::OnWindowBoundsChanged(aura::Window* window,
                                        const gfx::Rect& old_bounds,
                                        const gfx::Rect& new_bounds) {
   // During preparation, window bounds can change. Ignore bounds
@@ -608,11 +609,12 @@
     return;
 
   auto iter = std::find_if(window_list_.begin(), window_list_.end(),
-                           WindowSelectorItemComparator(window));
+                           WindowSelectorItemComparator(WmWindow::Get(window)));
   DCHECK(iter != window_list_.end());
 
   // Immediately finish any active bounds animation.
-  window->StopAnimatingProperty(ui::LayerAnimationElement::BOUNDS);
+  window->layer()->GetAnimator()->StopAnimatingProperty(
+      ui::LayerAnimationElement::BOUNDS);
   PositionWindows(false);
 }
 
diff --git a/ash/common/wm/overview/window_grid.h b/ash/common/wm/overview/window_grid.h
index a18f6a6..67f4f56 100644
--- a/ash/common/wm/overview/window_grid.h
+++ b/ash/common/wm/overview/window_grid.h
@@ -13,9 +13,9 @@
 
 #include "ash/common/wm/overview/window_selector.h"
 #include "ash/common/wm/window_state_observer.h"
-#include "ash/common/wm_window_observer.h"
 #include "base/macros.h"
 #include "base/scoped_observer.h"
+#include "ui/aura/window_observer.h"
 
 namespace views {
 class Widget;
@@ -47,7 +47,7 @@
 //    0, 1, 2, 3, 4, 5, 6
 // The selector is switched to the next window grid (if available) or wrapped if
 // it reaches the end of its movement sequence.
-class ASH_EXPORT WindowGrid : public WmWindowObserver,
+class ASH_EXPORT WindowGrid : public aura::WindowObserver,
                               public wm::WindowStateObserver {
  public:
   WindowGrid(WmWindow* root_window,
@@ -115,10 +115,10 @@
     return window_list_;
   }
 
-  // WmWindowObserver:
-  void OnWindowDestroying(WmWindow* window) override;
+  // aura::WindowObserver:
+  void OnWindowDestroying(aura::Window* window) override;
   // TODO(flackr): Handle window bounds changed in WindowSelectorItem.
-  void OnWindowBoundsChanged(WmWindow* window,
+  void OnWindowBoundsChanged(aura::Window* window,
                              const gfx::Rect& old_bounds,
                              const gfx::Rect& new_bounds) override;
 
@@ -169,7 +169,7 @@
   // Vector containing all the windows in this grid.
   std::vector<std::unique_ptr<WindowSelectorItem>> window_list_;
 
-  ScopedObserver<WmWindow, WindowGrid> window_observer_;
+  ScopedObserver<aura::Window, WindowGrid> window_observer_;
   ScopedObserver<wm::WindowState, WindowGrid> window_state_observer_;
 
   // Widget that darkens the screen background.
diff --git a/ash/common/wm/overview/window_selector.cc b/ash/common/wm/overview/window_selector.cc
index ea5c3af..8e1d743 100644
--- a/ash/common/wm/overview/window_selector.cc
+++ b/ash/common/wm/overview/window_selector.cc
@@ -239,7 +239,7 @@
 // calls to restoring_minimized_windows() on a partially constructed object.
 void WindowSelector::Init(const WindowList& windows) {
   if (restore_focus_window_)
-    restore_focus_window_->AddObserver(this);
+    restore_focus_window_->aura_window()->AddObserver(this);
 
   WmShell* shell = WmShell::Get();
 
@@ -260,7 +260,7 @@
     for (size_t i = 0; i < wm::kSwitchableWindowContainerIdsLength; ++i) {
       WmWindow* container =
           root->GetChildByShellWindowId(wm::kSwitchableWindowContainerIds[i]);
-      container->AddObserver(this);
+      container->aura_window()->AddObserver(this);
       observed_windows_.insert(container);
     }
 
@@ -372,12 +372,12 @@
 
 void WindowSelector::RemoveAllObservers() {
   for (WmWindow* window : observed_windows_)
-    window->RemoveObserver(this);
+    window->aura_window()->RemoveObserver(this);
 
   WmShell::Get()->RemoveActivationObserver(this);
   display::Screen::GetScreen()->RemoveObserver(this);
   if (restore_focus_window_)
-    restore_focus_window_->RemoveObserver(this);
+    restore_focus_window_->aura_window()->RemoveObserver(this);
 }
 
 void WindowSelector::CancelSelection() {
@@ -515,15 +515,15 @@
   RepositionTextFilterOnDisplayMetricsChange();
 }
 
-void WindowSelector::OnWindowTreeChanged(WmWindow* window,
-                                         const TreeChangeParams& params) {
+void WindowSelector::OnWindowHierarchyChanged(
+    const HierarchyChangeParams& params) {
   // Only care about newly added children of |observed_windows_|.
-  if (!observed_windows_.count(window) ||
-      !observed_windows_.count(params.new_parent)) {
+  if (!observed_windows_.count(WmWindow::Get(params.receiver)) ||
+      !observed_windows_.count(WmWindow::Get(params.new_parent))) {
     return;
   }
 
-  WmWindow* new_window = params.target;
+  WmWindow* new_window = WmWindow::Get(params.target);
   if (!IsSelectable(new_window))
     return;
 
@@ -538,10 +538,10 @@
   }
 }
 
-void WindowSelector::OnWindowDestroying(WmWindow* window) {
+void WindowSelector::OnWindowDestroying(aura::Window* window) {
   window->RemoveObserver(this);
-  observed_windows_.erase(window);
-  if (window == restore_focus_window_)
+  observed_windows_.erase(WmWindow::Get(window));
+  if (WmWindow::Get(window) == restore_focus_window_)
     restore_focus_window_ = nullptr;
 }
 
@@ -656,7 +656,7 @@
   // observed.
   if (observed_windows_.find(restore_focus_window_) ==
       observed_windows_.end()) {
-    restore_focus_window_->RemoveObserver(this);
+    restore_focus_window_->aura_window()->RemoveObserver(this);
   }
   restore_focus_window_ = nullptr;
 }
diff --git a/ash/common/wm/overview/window_selector.h b/ash/common/wm/overview/window_selector.h
index 5512f4d8..a5cb743 100644
--- a/ash/common/wm/overview/window_selector.h
+++ b/ash/common/wm/overview/window_selector.h
@@ -14,9 +14,9 @@
 
 #include "ash/ash_export.h"
 #include "ash/common/wm_activation_observer.h"
-#include "ash/common/wm_window_observer.h"
 #include "base/macros.h"
 #include "base/time/time.h"
+#include "ui/aura/window_observer.h"
 #include "ui/display/display_observer.h"
 #include "ui/gfx/image/image_skia.h"
 #include "ui/views/controls/textfield/textfield_controller.h"
@@ -35,7 +35,7 @@
 // The WindowSelector shows a grid of all of your windows, allowing to select
 // one by clicking or tapping on it.
 class ASH_EXPORT WindowSelector : public display::DisplayObserver,
-                                  public WmWindowObserver,
+                                  public aura::WindowObserver,
                                   public WmActivationObserver,
                                   public views::TextfieldController {
  public:
@@ -91,10 +91,9 @@
   void OnDisplayMetricsChanged(const display::Display& display,
                                uint32_t metrics) override;
 
-  // WmWindowObserver:
-  void OnWindowTreeChanged(WmWindow* window,
-                           const TreeChangeParams& params) override;
-  void OnWindowDestroying(WmWindow* window) override;
+  // aura::WindowObserver:
+  void OnWindowHierarchyChanged(const HierarchyChangeParams& params) override;
+  void OnWindowDestroying(aura::Window* window) override;
 
   // WmActivationObserver
   void OnWindowActivated(WmWindow* gained_active,
diff --git a/ash/common/wm/overview/window_selector_item.cc b/ash/common/wm/overview/window_selector_item.cc
index 0d79c4ce..2c4a137 100644
--- a/ash/common/wm/overview/window_selector_item.cc
+++ b/ash/common/wm/overview/window_selector_item.cc
@@ -417,11 +417,11 @@
       window_selector_(window_selector),
       background_view_(nullptr) {
   CreateWindowLabel(window->GetTitle());
-  GetWindow()->AddObserver(this);
+  GetWindow()->aura_window()->AddObserver(this);
 }
 
 WindowSelectorItem::~WindowSelectorItem() {
-  GetWindow()->RemoveObserver(this);
+  GetWindow()->aura_window()->RemoveObserver(this);
 }
 
 WmWindow* WindowSelectorItem::GetWindow() {
@@ -548,12 +548,12 @@
   window_selector_->SelectWindow(this);
 }
 
-void WindowSelectorItem::OnWindowDestroying(WmWindow* window) {
+void WindowSelectorItem::OnWindowDestroying(aura::Window* window) {
   window->RemoveObserver(this);
   transform_window_.OnWindowDestroyed();
 }
 
-void WindowSelectorItem::OnWindowTitleChanged(WmWindow* window) {
+void WindowSelectorItem::OnWindowTitleChanged(aura::Window* window) {
   // TODO(flackr): Maybe add the new title to a vector of titles so that we can
   // filter any of the titles the window had while in the overview session.
   label_view_->SetText(window->GetTitle());
diff --git a/ash/common/wm/overview/window_selector_item.h b/ash/common/wm/overview/window_selector_item.h
index 2d87598..097cc8b4 100644
--- a/ash/common/wm/overview/window_selector_item.h
+++ b/ash/common/wm/overview/window_selector_item.h
@@ -9,8 +9,8 @@
 
 #include "ash/ash_export.h"
 #include "ash/common/wm/overview/scoped_transform_overview_window.h"
-#include "ash/common/wm_window_observer.h"
 #include "base/macros.h"
+#include "ui/aura/window_observer.h"
 #include "ui/gfx/geometry/insets.h"
 #include "ui/gfx/geometry/rect.h"
 #include "ui/views/controls/button/button.h"
@@ -33,7 +33,7 @@
 
 // This class represents an item in overview mode.
 class ASH_EXPORT WindowSelectorItem : public views::ButtonListener,
-                                      public WmWindowObserver {
+                                      public aura::WindowObserver {
  public:
   // An image button with a close window icon.
   class OverviewCloseButton : public views::ImageButton {
@@ -117,9 +117,9 @@
   // views::ButtonListener:
   void ButtonPressed(views::Button* sender, const ui::Event& event) override;
 
-  // WmWindowObserver:
-  void OnWindowDestroying(WmWindow* window) override;
-  void OnWindowTitleChanged(WmWindow* window) override;
+  // aura::WindowObserver:
+  void OnWindowDestroying(aura::Window* window) override;
+  void OnWindowTitleChanged(aura::Window* window) override;
 
  private:
   class CaptionContainerView;
diff --git a/ash/common/wm/panels/panel_layout_manager.cc b/ash/common/wm/panels/panel_layout_manager.cc
index 6acd55a..964d946 100644
--- a/ash/common/wm/panels/panel_layout_manager.cc
+++ b/ash/common/wm/panels/panel_layout_manager.cc
@@ -20,6 +20,7 @@
 #include "ash/common/wm_window_property.h"
 #include "ash/public/cpp/shell_window_ids.h"
 #include "ash/root_window_controller.h"
+#include "ash/wm/window_properties.h"
 #include "base/auto_reset.h"
 #include "third_party/skia/include/core/SkColor.h"
 #include "third_party/skia/include/core/SkPath.h"
@@ -359,7 +360,7 @@
   panel_info.callout_widget = new PanelCalloutWidget(panel_container_);
   panel_info.slide_in = child != dragged_panel_;
   panel_windows_.push_back(panel_info);
-  child->AddObserver(this);
+  child->aura_window()->AddObserver(this);
   child->GetWindowState()->AddObserver(this);
   Relayout();
 }
@@ -377,8 +378,8 @@
     panel_windows_.erase(found);
   }
   if (restore_windows_on_shelf_visible_)
-    restore_windows_on_shelf_visible_->Remove(child);
-  child->RemoveObserver(this);
+    restore_windows_on_shelf_visible_->Remove(child->aura_window());
+  child->aura_window()->RemoveObserver(this);
   child->GetWindowState()->RemoveObserver(this);
 
   if (dragged_panel_ == child)
@@ -452,11 +453,12 @@
 /////////////////////////////////////////////////////////////////////////////
 // PanelLayoutManager, WindowObserver implementation:
 
-void PanelLayoutManager::OnWindowPropertyChanged(WmWindow* window,
-                                                 WmWindowProperty property) {
+void PanelLayoutManager::OnWindowPropertyChanged(aura::Window* window,
+                                                 const void* key,
+                                                 intptr_t old) {
   // Trigger a relayout to position the panels whenever the panel icon is set
   // or changes.
-  if (property == WmWindowProperty::SHELF_ID)
+  if (key == kShelfIDKey)
     Relayout();
 }
 
@@ -471,9 +473,11 @@
   if (restore_windows_on_shelf_visible_) {
     if (window_state->IsMinimized()) {
       MinimizePanel(window_state->window());
-      restore_windows_on_shelf_visible_->Remove(window_state->window());
+      restore_windows_on_shelf_visible_->Remove(
+          window_state->window()->aura_window());
     } else {
-      restore_windows_on_shelf_visible_->Add(window_state->window());
+      restore_windows_on_shelf_visible_->Add(
+          window_state->window()->aura_window());
     }
     return;
   }
@@ -515,17 +519,18 @@
   bool shelf_hidden = new_state == ash::SHELF_HIDDEN;
   if (!shelf_hidden) {
     if (restore_windows_on_shelf_visible_) {
-      std::unique_ptr<WmWindowTracker> restore_windows(
+      std::unique_ptr<aura::WindowTracker> restore_windows(
           std::move(restore_windows_on_shelf_visible_));
-      for (WmWindow* window : restore_windows->windows())
-        RestorePanel(window);
+      for (aura::Window* window : restore_windows->windows())
+        RestorePanel(WmWindow::Get(window));
     }
     return;
   }
 
   if (restore_windows_on_shelf_visible_)
     return;
-  std::unique_ptr<WmWindowTracker> minimized_windows(new WmWindowTracker);
+  std::unique_ptr<aura::WindowTracker> minimized_windows(
+      new aura::WindowTracker);
   for (PanelList::iterator iter = panel_windows_.begin();
        iter != panel_windows_.end();) {
     WmWindow* window = iter->window;
@@ -533,7 +538,7 @@
     // Advance the iterator before minimizing it: http://crbug.com/393047.
     ++iter;
     if (window != dragged_panel_ && window->IsVisible()) {
-      minimized_windows->Add(window);
+      minimized_windows->Add(window->aura_window());
       window->GetWindowState()->Minimize();
     }
   }
@@ -629,7 +634,7 @@
     // the dragged panel.
     if (panel != dragged_panel_ && restore_windows_on_shelf_visible_) {
       panel->GetWindowState()->Minimize();
-      restore_windows_on_shelf_visible_->Add(panel);
+      restore_windows_on_shelf_visible_->Add(panel->aura_window());
       continue;
     }
 
diff --git a/ash/common/wm/panels/panel_layout_manager.h b/ash/common/wm/panels/panel_layout_manager.h
index db78889c..ff1047e 100644
--- a/ash/common/wm/panels/panel_layout_manager.h
+++ b/ash/common/wm/panels/panel_layout_manager.h
@@ -15,11 +15,12 @@
 #include "ash/common/wm_activation_observer.h"
 #include "ash/common/wm_display_observer.h"
 #include "ash/common/wm_layout_manager.h"
-#include "ash/common/wm_window_observer.h"
-#include "ash/common/wm_window_tracker.h"
+#include "ash/root_window_controller.h"
 #include "base/compiler_specific.h"
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
+#include "ui/aura/window_observer.h"
+#include "ui/aura/window_tracker.h"
 #include "ui/keyboard/keyboard_controller.h"
 #include "ui/keyboard/keyboard_controller_observer.h"
 
@@ -54,7 +55,7 @@
       public WmActivationObserver,
       public WmDisplayObserver,
       public ShellObserver,
-      public WmWindowObserver,
+      public aura::WindowObserver,
       public keyboard::KeyboardControllerObserver,
       public WmShelfObserver {
  public:
@@ -95,9 +96,10 @@
   void OnOverviewModeEnded() override;
   void OnShelfAlignmentChanged(WmWindow* root_window) override;
 
-  // Overridden from WmWindowObserver
-  void OnWindowPropertyChanged(WmWindow* window,
-                               WmWindowProperty property) override;
+  // Overridden from aura::WindowObserver
+  void OnWindowPropertyChanged(aura::Window* window,
+                               const void* key,
+                               intptr_t old) override;
 
   // Overridden from wm::WindowStateObserver
   void OnPostWindowStateTypeChange(wm::WindowState* window_state,
@@ -188,7 +190,7 @@
   // When not NULL, the shelf is hidden (i.e. full screen) and this tracks the
   // set of panel windows which have been temporarily hidden and need to be
   // restored when the shelf becomes visible again.
-  std::unique_ptr<WmWindowTracker> restore_windows_on_shelf_visible_;
+  std::unique_ptr<aura::WindowTracker> restore_windows_on_shelf_visible_;
 
   // The last active panel. Used to maintain stacking order even if no panels
   // are currently focused.
diff --git a/ash/common/wm/root_window_layout_manager.cc b/ash/common/wm/root_window_layout_manager.cc
index dda5384..15ec3fbf 100644
--- a/ash/common/wm/root_window_layout_manager.cc
+++ b/ash/common/wm/root_window_layout_manager.cc
@@ -5,7 +5,8 @@
 #include "ash/common/wm/root_window_layout_manager.h"
 
 #include "ash/common/wm_window.h"
-#include "ash/common/wm_window_tracker.h"
+#include "ui/aura/window.h"
+#include "ui/aura/window_tracker.h"
 
 namespace ash {
 namespace wm {
@@ -26,16 +27,16 @@
 
   // Resize both our immediate children (the containers-of-containers animated
   // by PowerButtonController) and their children (the actual containers).
-  WmWindowTracker children_tracker(owner_->GetChildren());
+  aura::WindowTracker children_tracker(owner_->aura_window()->children());
   while (!children_tracker.windows().empty()) {
-    WmWindow* child = children_tracker.Pop();
+    aura::Window* child = children_tracker.Pop();
     // Skip descendants of top-level windows, i.e. only resize containers and
     // other windows without a delegate, such as ScreenDimmer windows.
     if (child->GetToplevelWindow())
       continue;
 
     child->SetBounds(fullscreen_bounds);
-    WmWindowTracker grandchildren_tracker(child->GetChildren());
+    aura::WindowTracker grandchildren_tracker(child->children());
     while (!grandchildren_tracker.windows().empty()) {
       child = grandchildren_tracker.Pop();
       if (!child->GetToplevelWindow())
diff --git a/ash/common/wm/system_modal_container_layout_manager.cc b/ash/common/wm/system_modal_container_layout_manager.cc
index e0b085f..ad52259 100644
--- a/ash/common/wm/system_modal_container_layout_manager.cc
+++ b/ash/common/wm/system_modal_container_layout_manager.cc
@@ -14,6 +14,8 @@
 #include "ash/public/cpp/shell_window_ids.h"
 #include "base/memory/ptr_util.h"
 #include "base/stl_util.h"
+#include "ui/aura/client/aura_constants.h"
+#include "ui/aura/window.h"
 #include "ui/keyboard/keyboard_controller.h"
 
 namespace ash {
@@ -87,14 +89,14 @@
   DCHECK_NE(GetModalType(child), ui::MODAL_TYPE_CHILD);
   DCHECK_NE(GetModalType(child), ui::MODAL_TYPE_WINDOW);
 
-  child->AddObserver(this);
+  child->aura_window()->AddObserver(this);
   if (GetModalType(child) == ui::MODAL_TYPE_SYSTEM && child->IsVisible())
     AddModalWindow(child);
 }
 
 void SystemModalContainerLayoutManager::OnWillRemoveWindowFromLayout(
     WmWindow* child) {
-  child->RemoveObserver(this);
+  child->aura_window()->RemoveObserver(this);
   windows_to_center_.erase(child);
   if (GetModalType(child) == ui::MODAL_TYPE_SYSTEM)
     RemoveModalWindow(child);
@@ -111,21 +113,23 @@
 }
 
 ////////////////////////////////////////////////////////////////////////////////
-// SystemModalContainerLayoutManager, WmWindowObserver implementation:
+// SystemModalContainerLayoutManager, aura::WindowObserver implementation:
 
 void SystemModalContainerLayoutManager::OnWindowPropertyChanged(
-    WmWindow* window,
-    WmWindowProperty property) {
-  if (property != WmWindowProperty::MODAL_TYPE || !window->IsVisible())
+    aura::Window* window,
+    const void* key,
+    intptr_t old) {
+  if (key != aura::client::kModalKey || !window->IsVisible())
     return;
 
-  if (GetModalType(window) == ui::MODAL_TYPE_SYSTEM) {
-    if (base::ContainsValue(modal_windows_, window))
+  WmWindow* wm_window = WmWindow::Get(window);
+  if (window->GetProperty(aura::client::kModalKey) == ui::MODAL_TYPE_SYSTEM) {
+    if (base::ContainsValue(modal_windows_, wm_window))
       return;
-    AddModalWindow(window);
+    AddModalWindow(wm_window);
   } else {
-    if (RemoveModalWindow(window))
-      WmShell::Get()->OnModalWindowRemoved(window);
+    if (RemoveModalWindow(wm_window))
+      WmShell::Get()->OnModalWindowRemoved(wm_window);
   }
 }
 
diff --git a/ash/common/wm/system_modal_container_layout_manager.h b/ash/common/wm/system_modal_container_layout_manager.h
index 7bf81c8..171b0f46 100644
--- a/ash/common/wm/system_modal_container_layout_manager.h
+++ b/ash/common/wm/system_modal_container_layout_manager.h
@@ -11,8 +11,8 @@
 
 #include "ash/ash_export.h"
 #include "ash/common/wm/wm_snap_to_pixel_layout_manager.h"
-#include "ash/common/wm_window_observer.h"
 #include "base/macros.h"
+#include "ui/aura/window_observer.h"
 #include "ui/keyboard/keyboard_controller_observer.h"
 
 namespace gfx {
@@ -27,7 +27,7 @@
 // when the container size changes.
 class ASH_EXPORT SystemModalContainerLayoutManager
     : public wm::WmSnapToPixelLayoutManager,
-      public WmWindowObserver,
+      public aura::WindowObserver,
       public keyboard::KeyboardControllerObserver {
  public:
   explicit SystemModalContainerLayoutManager(WmWindow* container);
@@ -43,9 +43,10 @@
   void SetChildBounds(WmWindow* child,
                       const gfx::Rect& requested_bounds) override;
 
-  // Overridden from WmWindowObserver:
-  void OnWindowPropertyChanged(WmWindow* window,
-                               WmWindowProperty property) override;
+  // Overridden from aura::WindowObserver:
+  void OnWindowPropertyChanged(aura::Window* window,
+                               const void* key,
+                               intptr_t old) override;
 
   // Overridden from keyboard::KeyboardControllerObserver:
   void OnKeyboardBoundsChanging(const gfx::Rect& new_bounds) override;
diff --git a/ash/common/wm/window_cycle_list.cc b/ash/common/wm/window_cycle_list.cc
index fd63499..78c7a77 100644
--- a/ash/common/wm/window_cycle_list.cc
+++ b/ash/common/wm/window_cycle_list.cc
@@ -62,14 +62,14 @@
 
 // This view represents a single WmWindow by displaying a title and a thumbnail
 // of the window's contents.
-class WindowPreviewView : public views::View, public WmWindowObserver {
+class WindowPreviewView : public views::View, public aura::WindowObserver {
  public:
   explicit WindowPreviewView(WmWindow* window)
       : window_title_(new views::Label),
         preview_background_(new views::View),
         mirror_view_(window->CreateViewWithRecreatedLayers().release()),
         window_observer_(this) {
-    window_observer_.Add(window);
+    window_observer_.Add(window->aura_window());
     window_title_->SetText(window->GetTitle());
     window_title_->SetHorizontalAlignment(gfx::ALIGN_LEFT);
     window_title_->SetEnabledColor(SK_ColorWHITE);
@@ -135,12 +135,12 @@
     node_data->SetName(window_title_->text());
   }
 
-  // WmWindowObserver:
-  void OnWindowDestroying(WmWindow* window) override {
+  // aura::WindowObserver:
+  void OnWindowDestroying(aura::Window* window) override {
     window_observer_.Remove(window);
   }
 
-  void OnWindowTitleChanged(WmWindow* window) override {
+  void OnWindowTitleChanged(aura::Window* window) override {
     window_title_->SetText(window->GetTitle());
   }
 
@@ -200,7 +200,7 @@
   // The view that actually renders a thumbnail version of the window.
   views::View* mirror_view_;
 
-  ScopedObserver<WmWindow, WmWindowObserver> window_observer_;
+  ScopedObserver<aura::Window, aura::WindowObserver> window_observer_;
 
   DISALLOW_COPY_AND_ASSIGN(WindowPreviewView);
 };
@@ -386,7 +386,7 @@
     WmShell::Get()->mru_window_tracker()->SetIgnoreActivations(true);
 
   for (WmWindow* window : windows_)
-    window->AddObserver(this);
+    window->aura_window()->AddObserver(this);
 
   if (ShouldShowUi()) {
     if (g_disable_initial_delay) {
@@ -403,7 +403,7 @@
     WmShell::Get()->mru_window_tracker()->SetIgnoreActivations(false);
 
   for (WmWindow* window : windows_)
-    window->RemoveObserver(this);
+    window->aura_window()->RemoveObserver(this);
 
   if (!windows_.empty() && user_did_accept_) {
     WmWindow* target_window = windows_[current_index_];
@@ -467,10 +467,11 @@
   g_disable_initial_delay = true;
 }
 
-void WindowCycleList::OnWindowDestroying(WmWindow* window) {
+void WindowCycleList::OnWindowDestroying(aura::Window* window) {
   window->RemoveObserver(this);
 
-  WindowList::iterator i = std::find(windows_.begin(), windows_.end(), window);
+  WindowList::iterator i =
+      std::find(windows_.begin(), windows_.end(), WmWindow::Get(window));
   // TODO(oshima): Change this back to DCHECK once crbug.com/483491 is fixed.
   CHECK(i != windows_.end());
   int removed_index = static_cast<int>(i - windows_.begin());
@@ -483,7 +484,8 @@
   if (cycle_view_) {
     WmWindow* new_target_window =
         windows_.empty() ? nullptr : windows_[current_index_];
-    cycle_view_->HandleWindowDestruction(window, new_target_window);
+    cycle_view_->HandleWindowDestruction(WmWindow::Get(window),
+                                         new_target_window);
     if (windows_.empty()) {
       // This deletes us.
       WmShell::Get()->window_cycle_controller()->CancelCycling();
diff --git a/ash/common/wm/window_cycle_list.h b/ash/common/wm/window_cycle_list.h
index 6a1a1a7..36e89409 100644
--- a/ash/common/wm/window_cycle_list.h
+++ b/ash/common/wm/window_cycle_list.h
@@ -10,10 +10,10 @@
 
 #include "ash/ash_export.h"
 #include "ash/common/wm/window_cycle_controller.h"
-#include "ash/common/wm_window_observer.h"
 #include "base/macros.h"
 #include "base/scoped_observer.h"
 #include "base/timer/timer.h"
+#include "ui/aura/window_observer.h"
 #include "ui/display/display_observer.h"
 
 namespace display {
@@ -30,7 +30,7 @@
 
 // Tracks a set of Windows that can be stepped through. This class is used by
 // the WindowCycleController.
-class ASH_EXPORT WindowCycleList : public WmWindowObserver,
+class ASH_EXPORT WindowCycleList : public aura::WindowObserver,
                                    public display::DisplayObserver {
  public:
   using WindowList = std::vector<WmWindow*>;
@@ -57,11 +57,11 @@
 
   const WindowList& windows() const { return windows_; }
 
-  // WmWindowObserver overrides:
+  // aura::WindowObserver overrides:
   // There is a chance a window is destroyed, for example by JS code. We need to
   // take care of that even if it is not intended for the user to close a window
   // while window cycling.
-  void OnWindowDestroying(WmWindow* window) override;
+  void OnWindowDestroying(aura::Window* window) override;
 
   // display::DisplayObserver overrides:
   void OnDisplayAdded(const display::Display& new_display) override;
diff --git a/ash/common/wm/window_dimmer.cc b/ash/common/wm/window_dimmer.cc
index bdd1109d..c90d806 100644
--- a/ash/common/wm/window_dimmer.cc
+++ b/ash/common/wm/window_dimmer.cc
@@ -9,6 +9,7 @@
 #include "ash/common/wm_shell.h"
 #include "ash/common/wm_window.h"
 #include "base/time/time.h"
+#include "ui/aura/window.h"
 #include "ui/compositor/layer.h"
 #include "ui/wm/core/window_animations.h"
 
@@ -30,12 +31,12 @@
       ::wm::WINDOW_VISIBILITY_ANIMATION_TYPE_FADE);
   window_->SetVisibilityAnimationDuration(
       base::TimeDelta::FromMilliseconds(kDefaultDimAnimationDurationMs));
-  window_->AddObserver(this);
+  window_->aura_window()->AddObserver(this);
 
   SetDimOpacity(kDefaultDimOpacity);
 
   parent->AddChild(window_);
-  parent->AddObserver(this);
+  parent->aura_window()->AddObserver(this);
   parent->StackChildAtTop(window_);
 
   window_->SetBounds(gfx::Rect(parent_->GetBounds().size()));
@@ -43,9 +44,9 @@
 
 WindowDimmer::~WindowDimmer() {
   if (parent_)
-    parent_->RemoveObserver(this);
+    parent_->aura_window()->RemoveObserver(this);
   if (window_) {
-    window_->RemoveObserver(this);
+    window_->aura_window()->RemoveObserver(this);
     window_->Destroy();
   }
 }
@@ -56,27 +57,28 @@
       SkColorSetA(SK_ColorBLACK, 255 * target_opacity));
 }
 
-void WindowDimmer::OnWindowBoundsChanged(WmWindow* window,
+void WindowDimmer::OnWindowBoundsChanged(aura::Window* window,
                                          const gfx::Rect& old_bounds,
                                          const gfx::Rect& new_bounds) {
-  if (window == parent_)
+  if (WmWindow::Get(window) == parent_)
     window_->SetBounds(gfx::Rect(new_bounds.size()));
 }
 
-void WindowDimmer::OnWindowDestroying(WmWindow* window) {
-  if (window == parent_) {
-    parent_->RemoveObserver(this);
+void WindowDimmer::OnWindowDestroying(aura::Window* window) {
+  if (WmWindow::Get(window) == parent_) {
+    parent_->aura_window()->RemoveObserver(this);
     parent_ = nullptr;
   } else {
-    DCHECK_EQ(window_, window);
-    window_->RemoveObserver(this);
+    DCHECK_EQ(window_, WmWindow::Get(window));
+    window_->aura_window()->RemoveObserver(this);
     window_ = nullptr;
   }
 }
 
-void WindowDimmer::OnWindowTreeChanging(WmWindow* window,
-                                        const TreeChangeParams& params) {
-  if (window == window_ && params.target == window) {
+void WindowDimmer::OnWindowHierarchyChanging(
+    const HierarchyChangeParams& params) {
+  if (WmWindow::Get(params.receiver) == window_ &&
+      params.target == params.receiver) {
     // This may happen on a display change or some unexpected condition. Hide
     // the window to ensure it isn't obscuring the wrong thing.
     window_->Hide();
diff --git a/ash/common/wm/window_dimmer.h b/ash/common/wm/window_dimmer.h
index 52505755..48ded97 100644
--- a/ash/common/wm/window_dimmer.h
+++ b/ash/common/wm/window_dimmer.h
@@ -6,11 +6,13 @@
 #define ASH_COMMON_WINDOW_DIMMER_H_
 
 #include "ash/ash_export.h"
-#include "ash/common/wm_window_observer.h"
 #include "base/macros.h"
+#include "ui/aura/window_observer.h"
 
 namespace ash {
 
+class WmWindow;
+
 // WindowDimmer creates a window whose opacity is animated by way of
 // SetDimOpacity() and whose size matches that of its parent. WindowDimmer is
 // intended to be used in cases where a certain set of windows need to appear
@@ -20,7 +22,7 @@
 // deleted if WindowDimmer is deleted. It is expected that WindowDimmer is
 // deleted when the parent window is deleted (such as happens with
 // WmWindowUserData).
-class ASH_EXPORT WindowDimmer : public WmWindowObserver {
+class ASH_EXPORT WindowDimmer : public aura::WindowObserver {
  public:
   // Creates a new WindowDimmer. The window() created by WindowDimmer is added
   // to |parent| and stacked above all other child windows.
@@ -33,13 +35,12 @@
   WmWindow* window() { return window_; }
 
   // NOTE: WindowDimmer is an observer for both |parent_| and |window_|.
-  // WmWindowObserver:
-  void OnWindowBoundsChanged(WmWindow* window,
+  // aura::WindowObserver:
+  void OnWindowBoundsChanged(aura::Window* window,
                              const gfx::Rect& old_bounds,
                              const gfx::Rect& new_bounds) override;
-  void OnWindowDestroying(WmWindow* window) override;
-  void OnWindowTreeChanging(WmWindow* window,
-                            const TreeChangeParams& params) override;
+  void OnWindowDestroying(aura::Window* window) override;
+  void OnWindowHierarchyChanging(const HierarchyChangeParams& params) override;
 
  private:
   WmWindow* parent_;
diff --git a/ash/common/wm/window_positioning_utils.cc b/ash/common/wm/window_positioning_utils.cc
index aac29493..075090e 100644
--- a/ash/common/wm/window_positioning_utils.cc
+++ b/ash/common/wm/window_positioning_utils.cc
@@ -13,8 +13,8 @@
 #include "ash/common/wm_lookup.h"
 #include "ash/common/wm_shell.h"
 #include "ash/common/wm_window.h"
-#include "ash/common/wm_window_tracker.h"
 #include "ash/root_window_controller.h"
+#include "ui/aura/window_tracker.h"
 #include "ui/display/display.h"
 #include "ui/display/types/display_constants.h"
 #include "ui/gfx/geometry/rect.h"
@@ -157,11 +157,11 @@
       WmWindow* focused = WmShell::Get()->GetFocusedWindow();
       WmWindow* active = WmShell::Get()->GetActiveWindow();
 
-      WmWindowTracker tracker;
+      aura::WindowTracker tracker;
       if (focused)
-        tracker.Add(focused);
+        tracker.Add(focused->aura_window());
       if (active && focused != active)
-        tracker.Add(active);
+        tracker.Add(active->aura_window());
 
       gfx::Point origin = bounds_in_screen.origin();
       const gfx::Point display_origin = display.bounds().origin();
@@ -177,11 +177,11 @@
       MoveAllTransientChildrenToNewRoot(display, window);
 
       // Restore focused/active window.
-      if (tracker.Contains(focused)) {
+      if (focused && tracker.Contains(focused->aura_window())) {
         focused->SetFocused();
         WmShell::Get()->set_root_window_for_new_windows(
             focused->GetRootWindow());
-      } else if (tracker.Contains(active)) {
+      } else if (active && tracker.Contains(active->aura_window())) {
         active->Activate();
       }
       // TODO(oshima): We should not have to update the bounds again
diff --git a/ash/common/wm/wm_toplevel_window_event_handler.cc b/ash/common/wm/wm_toplevel_window_event_handler.cc
index 75ee435..5e670b9 100644
--- a/ash/common/wm/wm_toplevel_window_event_handler.cc
+++ b/ash/common/wm/wm_toplevel_window_event_handler.cc
@@ -10,7 +10,8 @@
 #include "ash/common/wm/wm_event.h"
 #include "ash/common/wm_shell.h"
 #include "ash/common/wm_window.h"
-#include "ash/common/wm_window_observer.h"
+#include "ui/aura/window.h"
+#include "ui/aura/window_observer.h"
 #include "ui/base/hit_test.h"
 #include "ui/events/event.h"
 
@@ -66,7 +67,7 @@
 // the window is destroyed ResizerWindowDestroyed() is invoked back on the
 // WmToplevelWindowEventHandler to clean up.
 class WmToplevelWindowEventHandler::ScopedWindowResizer
-    : public WmWindowObserver,
+    : public aura::WindowObserver,
       public wm::WindowStateObserver {
  public:
   ScopedWindowResizer(WmToplevelWindowEventHandler* handler,
@@ -79,7 +80,7 @@
   WindowResizer* resizer() { return resizer_.get(); }
 
   // WindowObserver overrides:
-  void OnWindowDestroying(WmWindow* window) override;
+  void OnWindowDestroying(aura::Window* window) override;
 
   // WindowStateObserver overrides:
   void OnPreWindowStateTypeChange(wm::WindowState* window_state,
@@ -100,7 +101,7 @@
     std::unique_ptr<WindowResizer> resizer)
     : handler_(handler), resizer_(std::move(resizer)), grabbed_capture_(false) {
   WmWindow* target = resizer_->GetTarget();
-  target->AddObserver(this);
+  target->aura_window()->AddObserver(this);
   target->GetWindowState()->AddObserver(this);
 
   if (!target->HasCapture()) {
@@ -111,7 +112,7 @@
 
 WmToplevelWindowEventHandler::ScopedWindowResizer::~ScopedWindowResizer() {
   WmWindow* target = resizer_->GetTarget();
-  target->RemoveObserver(this);
+  target->aura_window()->RemoveObserver(this);
   target->GetWindowState()->RemoveObserver(this);
   if (grabbed_capture_)
     target->ReleaseCapture();
@@ -129,8 +130,8 @@
 }
 
 void WmToplevelWindowEventHandler::ScopedWindowResizer::OnWindowDestroying(
-    WmWindow* window) {
-  DCHECK_EQ(resizer_->GetTarget(), window);
+    aura::Window* window) {
+  DCHECK_EQ(resizer_->GetTarget(), WmWindow::Get(window));
   handler_->ResizerWindowDestroyed();
 }
 
diff --git a/ash/common/wm/workspace/multi_window_resize_controller.cc b/ash/common/wm/workspace/multi_window_resize_controller.cc
index a96fec8..dfeb77f 100644
--- a/ash/common/wm/workspace/multi_window_resize_controller.cc
+++ b/ash/common/wm/workspace/multi_window_resize_controller.cc
@@ -170,8 +170,8 @@
   }
 
   windows_ = windows;
-  windows_.window1->AddObserver(this);
-  windows_.window2->AddObserver(this);
+  windows_.window1->aura_window()->AddObserver(this);
+  windows_.window2->aura_window()->AddObserver(this);
   show_location_in_parent_ =
       window->ConvertPointToTarget(window->GetParent(), point_in_window);
   show_timer_.Start(FROM_HERE, base::TimeDelta::FromMilliseconds(kShowDelayMS),
@@ -184,11 +184,11 @@
     return;  // Ignore hides while actively resizing.
 
   if (windows_.window1) {
-    windows_.window1->RemoveObserver(this);
+    windows_.window1->aura_window()->RemoveObserver(this);
     windows_.window1 = NULL;
   }
   if (windows_.window2) {
-    windows_.window2->RemoveObserver(this);
+    windows_.window2->aura_window()->RemoveObserver(this);
     windows_.window2 = NULL;
   }
 
@@ -198,7 +198,7 @@
     return;
 
   for (size_t i = 0; i < windows_.other_windows.size(); ++i)
-    windows_.other_windows[i]->RemoveObserver(this);
+    windows_.other_windows[i]->aura_window()->RemoveObserver(this);
   mouse_watcher_.reset();
   resize_widget_.reset();
   windows_ = ResizeWindows();
@@ -208,7 +208,7 @@
   Hide();
 }
 
-void MultiWindowResizeController::OnWindowDestroying(WmWindow* window) {
+void MultiWindowResizeController::OnWindowDestroying(aura::Window* window) {
   // Have to explicitly reset the WindowResizer, otherwise Hide() does nothing.
   window_resizer_.reset();
   Hide();
@@ -411,7 +411,7 @@
   FindWindowsTouching(windows_.window2, windows_.direction,
                       &windows_.other_windows);
   for (size_t i = 0; i < windows_.other_windows.size(); ++i) {
-    windows_.other_windows[i]->AddObserver(this);
+    windows_.other_windows[i]->aura_window()->AddObserver(this);
     windows.push_back(windows_.other_windows[i]);
   }
   int component = windows_.direction == LEFT_RIGHT ? HTRIGHT : HTBOTTOM;
@@ -453,7 +453,7 @@
     // the |other_windows|. If we start another resize we'll recalculate the
     // |other_windows| and invoke AddObserver() as necessary.
     for (size_t i = 0; i < windows_.other_windows.size(); ++i)
-      windows_.other_windows[i]->RemoveObserver(this);
+      windows_.other_windows[i]->aura_window()->RemoveObserver(this);
     windows_.other_windows.clear();
 
     CreateMouseWatcher();
diff --git a/ash/common/wm/workspace/multi_window_resize_controller.h b/ash/common/wm/workspace/multi_window_resize_controller.h
index e7c4a9d..48bd35a6 100644
--- a/ash/common/wm/workspace/multi_window_resize_controller.h
+++ b/ash/common/wm/workspace/multi_window_resize_controller.h
@@ -9,9 +9,9 @@
 #include <vector>
 
 #include "ash/ash_export.h"
-#include "ash/common/wm_window_observer.h"
 #include "base/macros.h"
 #include "base/timer/timer.h"
+#include "ui/aura/window_observer.h"
 #include "ui/gfx/geometry/rect.h"
 #include "ui/views/mouse_watcher.h"
 
@@ -21,6 +21,7 @@
 
 namespace ash {
 class MultiWindowResizeControllerTest;
+class WmWindow;
 class WorkspaceWindowResizer;
 
 // Two directions resizes happen in.
@@ -34,7 +35,7 @@
 // MultiWindowResizeController is driven by WorkspaceEventFilter.
 class ASH_EXPORT MultiWindowResizeController
     : public views::MouseWatcherListener,
-      public WmWindowObserver {
+      public aura::WindowObserver {
  public:
   MultiWindowResizeController();
   ~MultiWindowResizeController() override;
@@ -50,7 +51,7 @@
   void MouseMovedOutOfHost() override;
 
   // WindowObserver overrides:
-  void OnWindowDestroying(WmWindow* window) override;
+  void OnWindowDestroying(aura::Window* window) override;
 
  private:
   friend class MultiWindowResizeControllerTest;
diff --git a/ash/common/wm/workspace/workspace_layout_manager.cc b/ash/common/wm/workspace/workspace_layout_manager.cc
index a1a3696..ee1fd9d 100644
--- a/ash/common/wm/workspace/workspace_layout_manager.cc
+++ b/ash/common/wm/workspace/workspace_layout_manager.cc
@@ -20,7 +20,9 @@
 #include "ash/common/wm_window_property.h"
 #include "ash/public/cpp/shell_window_ids.h"
 #include "ash/root_window_controller.h"
+#include "ash/wm/window_state_aura.h"
 #include "base/command_line.h"
+#include "ui/aura/client/aura_constants.h"
 #include "ui/base/ui_base_switches.h"
 #include "ui/compositor/layer.h"
 #include "ui/display/display.h"
@@ -39,7 +41,7 @@
       is_fullscreen_(wm::GetWindowForFullscreenMode(window) != nullptr) {
   shell_->AddShellObserver(this);
   shell_->AddActivationObserver(this);
-  root_window_->AddObserver(this);
+  root_window_->aura_window()->AddObserver(this);
   display::Screen::GetScreen()->AddObserver(this);
   DCHECK(window->GetBoolProperty(
       WmWindowProperty::SNAP_CHILDREN_TO_PIXEL_BOUNDARY));
@@ -47,11 +49,11 @@
 
 WorkspaceLayoutManager::~WorkspaceLayoutManager() {
   if (root_window_)
-    root_window_->RemoveObserver(this);
+    root_window_->aura_window()->RemoveObserver(this);
   for (WmWindow* window : windows_) {
     wm::WindowState* window_state = window->GetWindowState();
     window_state->RemoveObserver(this);
-    window->RemoveObserver(this);
+    window->aura_window()->RemoveObserver(this);
   }
   display::Screen::GetScreen()->RemoveObserver(this);
   shell_->RemoveActivationObserver(this);
@@ -73,7 +75,7 @@
   wm::WMEvent event(wm::WM_EVENT_ADDED_TO_WORKSPACE);
   window_state->OnWMEvent(&event);
   windows_.insert(child);
-  child->AddObserver(this);
+  child->aura_window()->AddObserver(this);
   window_state->AddObserver(this);
   UpdateShelfVisibility();
   UpdateFullscreenState();
@@ -86,7 +88,7 @@
 
 void WorkspaceLayoutManager::OnWillRemoveWindowFromLayout(WmWindow* child) {
   windows_.erase(child);
-  child->RemoveObserver(this);
+  child->aura_window()->RemoveObserver(this);
   child->GetWindowState()->RemoveObserver(this);
 
   if (child->GetTargetVisibility())
@@ -180,59 +182,59 @@
 //////////////////////////////////////////////////////////////////////////////
 // WorkspaceLayoutManager, aura::WindowObserver implementation:
 
-void WorkspaceLayoutManager::OnWindowTreeChanged(
-    WmWindow* window,
-    const WmWindowObserver::TreeChangeParams& params) {
-  if (!params.target->GetWindowState()->IsActive())
+void WorkspaceLayoutManager::OnWindowHierarchyChanged(
+    const HierarchyChangeParams& params) {
+  if (!wm::GetWindowState(params.target)->IsActive())
     return;
   // If the window is already tracked by the workspace this update would be
   // redundant as the fullscreen and shelf state would have been handled in
   // OnWindowAddedToLayout.
-  if (windows_.find(params.target) != windows_.end())
+  if (windows_.find(WmWindow::Get(params.target)) != windows_.end())
     return;
 
   // If the active window has moved to this root window then update the
   // fullscreen state.
   // TODO(flackr): Track the active window leaving this root window and update
   // the fullscreen state accordingly.
-  if (params.new_parent && params.new_parent->GetRootWindow() == root_window_) {
+  if (params.new_parent &&
+      WmWindow::Get(params.new_parent->GetRootWindow()) == root_window_) {
     UpdateFullscreenState();
     UpdateShelfVisibility();
   }
 }
 
-void WorkspaceLayoutManager::OnWindowPropertyChanged(
-    WmWindow* window,
-    WmWindowProperty property) {
-  if (property == WmWindowProperty::ALWAYS_ON_TOP &&
-      window->GetBoolProperty(WmWindowProperty::ALWAYS_ON_TOP)) {
+void WorkspaceLayoutManager::OnWindowPropertyChanged(aura::Window* window,
+                                                     const void* key,
+                                                     intptr_t old) {
+  if (key == aura::client::kAlwaysOnTopKey &&
+      window->GetProperty(aura::client::kAlwaysOnTopKey)) {
     WmWindow* container =
         root_window_controller_->always_on_top_controller()->GetContainer(
-            window);
-    if (window->GetParent() != container)
-      container->AddChild(window);
+            WmWindow::Get(window));
+    if (WmWindow::Get(window->parent()) != container)
+      container->AddChild(WmWindow::Get(window));
   }
 }
 
-void WorkspaceLayoutManager::OnWindowStackingChanged(WmWindow* window) {
+void WorkspaceLayoutManager::OnWindowStackingChanged(aura::Window* window) {
   UpdateShelfVisibility();
   UpdateFullscreenState();
   if (backdrop_delegate_)
-    backdrop_delegate_->OnWindowStackingChanged(window);
+    backdrop_delegate_->OnWindowStackingChanged(WmWindow::Get(window));
 }
 
-void WorkspaceLayoutManager::OnWindowDestroying(WmWindow* window) {
-  if (root_window_ == window) {
-    root_window_->RemoveObserver(this);
+void WorkspaceLayoutManager::OnWindowDestroying(aura::Window* window) {
+  if (root_window_ == WmWindow::Get(window)) {
+    root_window_->aura_window()->RemoveObserver(this);
     root_window_ = nullptr;
   }
 }
 
 void WorkspaceLayoutManager::OnWindowBoundsChanged(
-    WmWindow* window,
+    aura::Window* window,
     const gfx::Rect& old_bounds,
     const gfx::Rect& new_bounds) {
-  if (root_window_ == window) {
+  if (root_window_ == WmWindow::Get(window)) {
     const wm::WMEvent wm_event(wm::WM_EVENT_DISPLAY_BOUNDS_CHANGED);
     AdjustAllWindowsBoundsForWorkAreaChange(&wm_event);
   }
diff --git a/ash/common/wm/workspace/workspace_layout_manager.h b/ash/common/wm/workspace/workspace_layout_manager.h
index 80cefe83..85413a71 100644
--- a/ash/common/wm/workspace/workspace_layout_manager.h
+++ b/ash/common/wm/workspace/workspace_layout_manager.h
@@ -14,15 +14,17 @@
 #include "ash/common/wm/wm_types.h"
 #include "ash/common/wm_activation_observer.h"
 #include "ash/common/wm_layout_manager.h"
-#include "ash/common/wm_window_observer.h"
 #include "base/macros.h"
+#include "ui/aura/window_observer.h"
 #include "ui/display/display_observer.h"
 #include "ui/gfx/geometry/rect.h"
 #include "ui/keyboard/keyboard_controller_observer.h"
 
 namespace ash {
+
 class RootWindowController;
 class WmShell;
+class WmWindow;
 class WorkspaceLayoutManagerBackdropDelegate;
 
 namespace wm {
@@ -32,7 +34,7 @@
 // LayoutManager used on the window created for a workspace.
 class ASH_EXPORT WorkspaceLayoutManager
     : public WmLayoutManager,
-      public WmWindowObserver,
+      public aura::WindowObserver,
       public WmActivationObserver,
       public keyboard::KeyboardControllerObserver,
       public display::DisplayObserver,
@@ -58,15 +60,14 @@
   void SetChildBounds(WmWindow* child,
                       const gfx::Rect& requested_bounds) override;
 
-  // Overriden from WmWindowObserver:
-  void OnWindowTreeChanged(
-      WmWindow* window,
-      const WmWindowObserver::TreeChangeParams& params) override;
-  void OnWindowPropertyChanged(WmWindow* window,
-                               WmWindowProperty property) override;
-  void OnWindowStackingChanged(WmWindow* window) override;
-  void OnWindowDestroying(WmWindow* window) override;
-  void OnWindowBoundsChanged(WmWindow* window,
+  // Overriden from aura::WindowObserver:
+  void OnWindowHierarchyChanged(const HierarchyChangeParams& params) override;
+  void OnWindowPropertyChanged(aura::Window* window,
+                               const void* key,
+                               intptr_t old) override;
+  void OnWindowStackingChanged(aura::Window* window) override;
+  void OnWindowDestroying(aura::Window* window) override;
+  void OnWindowBoundsChanged(aura::Window* window,
                              const gfx::Rect& old_bounds,
                              const gfx::Rect& new_bounds) override;
 
diff --git a/ash/common/wm/workspace/workspace_layout_manager_unittest.cc b/ash/common/wm/workspace/workspace_layout_manager_unittest.cc
index a0c4b8ee..5836aa7 100644
--- a/ash/common/wm/workspace/workspace_layout_manager_unittest.cc
+++ b/ash/common/wm/workspace/workspace_layout_manager_unittest.cc
@@ -22,8 +22,10 @@
 #include "ash/common/wm/workspace/workspace_window_resizer.h"
 #include "ash/common/wm_lookup.h"
 #include "ash/common/wm_shell.h"
+#include "ash/common/wm_window.h"
 #include "ash/public/cpp/shell_window_ids.h"
 #include "ash/root_window_controller.h"
+#include "ash/wm/window_state_aura.h"
 #include "base/command_line.h"
 #include "base/run_loop.h"
 #include "ui/aura/env.h"
@@ -292,24 +294,25 @@
   EXPECT_EQ("295,0 30x40", window->GetBoundsInScreen().ToString());
 }
 
-// WmWindowObserver implementation used by
+// aura::WindowObserver implementation used by
 // DontClobberRestoreBoundsWindowObserver. This code mirrors what
 // BrowserFrameAsh does. In particular when this code sees the window was
 // maximized it changes the bounds of a secondary window. The secondary window
 // mirrors the status window.
-class DontClobberRestoreBoundsWindowObserver : public WmWindowObserver {
+class DontClobberRestoreBoundsWindowObserver : public aura::WindowObserver {
  public:
   DontClobberRestoreBoundsWindowObserver() : window_(nullptr) {}
 
   void set_window(WmWindow* window) { window_ = window; }
 
-  // WmWindowObserver:
-  void OnWindowPropertyChanged(WmWindow* window,
-                               WmWindowProperty property) override {
+  // aura::WindowObserver:
+  void OnWindowPropertyChanged(aura::Window* window,
+                               const void* key,
+                               intptr_t old) override {
     if (!window_)
       return;
 
-    if (window->GetWindowState()->IsMaximized()) {
+    if (wm::GetWindowState(window)->IsMaximized()) {
       WmWindow* w = window_;
       window_ = nullptr;
 
@@ -337,7 +340,7 @@
   window->SetBounds(gfx::Rect(10, 20, 30, 40));
   // NOTE: for this test to exercise the failure the observer needs to be added
   // before the parent set. This mimics what BrowserFrameAsh does.
-  window->AddObserver(&window_observer);
+  window->aura_window()->AddObserver(&window_observer);
   ParentWindowInPrimaryRootWindow(window);
   window->Show();
 
@@ -353,7 +356,7 @@
   window_observer.set_window(window2);
   window_state->Maximize();
   EXPECT_EQ("10,20 30x40", window_state->GetRestoreBoundsInScreen().ToString());
-  window->RemoveObserver(&window_observer);
+  window->aura_window()->RemoveObserver(&window_observer);
 }
 
 // Verifies when a window is maximized all descendant windows have a size.
@@ -618,8 +621,8 @@
   EXPECT_EQ(bounds.ToString(), window->GetBounds().ToString());
 }
 
-// A WmWindowObserver which sets the focus when the window becomes visible.
-class FocusDuringUnminimizeWindowObserver : public WmWindowObserver {
+// A aura::WindowObserver which sets the focus when the window becomes visible.
+class FocusDuringUnminimizeWindowObserver : public aura::WindowObserver {
  public:
   FocusDuringUnminimizeWindowObserver()
       : window_(nullptr), show_state_(ui::SHOW_STATE_END) {}
@@ -627,14 +630,14 @@
 
   void SetWindow(WmWindow* window) {
     if (window_)
-      window_->RemoveObserver(this);
+      window_->aura_window()->RemoveObserver(this);
     window_ = window;
     if (window_)
-      window_->AddObserver(this);
+      window_->aura_window()->AddObserver(this);
   }
 
-  // WmWindowObserver:
-  void OnWindowVisibilityChanged(WmWindow* window, bool visible) override {
+  // aura::WindowObserver:
+  void OnWindowVisibilityChanged(aura::Window* window, bool visible) override {
     if (window_) {
       if (visible)
         window_->SetFocused();
diff --git a/ash/common/wm/workspace/workspace_window_resizer.cc b/ash/common/wm/workspace/workspace_window_resizer.cc
index 32c89b0..bee0bb4 100644
--- a/ash/common/wm/workspace/workspace_window_resizer.cc
+++ b/ash/common/wm/workspace/workspace_window_resizer.cc
@@ -704,12 +704,12 @@
   // If we snapped to a window then check it first. That way we don't bounce
   // around when close to multiple edges.
   if (magnetism_window_) {
-    if (window_tracker_.Contains(magnetism_window_) &&
+    if (window_tracker_.Contains(magnetism_window_->aura_window()) &&
         matcher.ShouldAttach(magnetism_window_->GetBoundsInScreen(),
                              &magnetism_edge_)) {
       return true;
     }
-    window_tracker_.Remove(magnetism_window_);
+    window_tracker_.Remove(magnetism_window_->aura_window());
     magnetism_window_ = NULL;
   }
 
@@ -734,7 +734,7 @@
       if (matcher.ShouldAttach(other_state->window()->GetBoundsInScreen(),
                                &magnetism_edge_)) {
         magnetism_window_ = other_state->window();
-        window_tracker_.Add(magnetism_window_);
+        window_tracker_.Add(magnetism_window_->aura_window());
         return true;
       }
     }
diff --git a/ash/common/wm/workspace/workspace_window_resizer.h b/ash/common/wm/workspace/workspace_window_resizer.h
index b434663..03b027d 100644
--- a/ash/common/wm/workspace/workspace_window_resizer.h
+++ b/ash/common/wm/workspace/workspace_window_resizer.h
@@ -12,20 +12,20 @@
 
 #include "ash/common/wm/window_resizer.h"
 #include "ash/common/wm/workspace/magnetism_matcher.h"
-#include "ash/common/wm_window_tracker.h"
 #include "base/compiler_specific.h"
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
+#include "ui/aura/window_tracker.h"
 
 namespace ash {
 class DockedWindowLayoutManager;
 class PhantomWindowController;
 class TwoStepEdgeCycler;
 class WindowSize;
+class WmShell;
 
 namespace wm {
 class WindowState;
-class WmShell;
 }
 
 // WindowResizer implementation for workspaces. This enforces that windows are
@@ -209,7 +209,7 @@
   WmWindow* magnetism_window_;
 
   // Used to verify |magnetism_window_| is still valid.
-  WmWindowTracker window_tracker_;
+  aura::WindowTracker window_tracker_;
 
   // If |magnetism_window_| is non-NULL this indicates how the two windows
   // should attach.
diff --git a/ash/common/wm/workspace_controller.cc b/ash/common/wm/workspace_controller.cc
index d93bae8..09f742b 100644
--- a/ash/common/wm/workspace_controller.cc
+++ b/ash/common/wm/workspace_controller.cc
@@ -38,7 +38,7 @@
     : viewport_(viewport),
       event_handler_(WmShell::Get()->CreateWorkspaceEventHandler(viewport)),
       layout_manager_(new WorkspaceLayoutManager(viewport)) {
-  viewport_->AddObserver(this);
+  viewport_->aura_window()->AddObserver(this);
   viewport_->SetVisibilityAnimationTransition(::wm::ANIMATE_NONE);
   viewport_->SetLayoutManager(base::WrapUnique(layout_manager_));
 }
@@ -47,7 +47,7 @@
   if (!viewport_)
     return;
 
-  viewport_->RemoveObserver(this);
+  viewport_->aura_window()->RemoveObserver(this);
   viewport_->SetLayoutManager(nullptr);
 }
 
@@ -122,9 +122,9 @@
   layout_manager_->SetMaximizeBackdropDelegate(std::move(delegate));
 }
 
-void WorkspaceController::OnWindowDestroying(WmWindow* window) {
-  DCHECK_EQ(window, viewport_);
-  viewport_->RemoveObserver(this);
+void WorkspaceController::OnWindowDestroying(aura::Window* window) {
+  DCHECK_EQ(WmWindow::Get(window), viewport_);
+  viewport_->aura_window()->RemoveObserver(this);
   viewport_ = nullptr;
   // Destroy |event_handler_| too as it depends upon |window|.
   event_handler_.reset();
diff --git a/ash/common/wm/workspace_controller.h b/ash/common/wm/workspace_controller.h
index 2004810..d37fe68 100644
--- a/ash/common/wm/workspace_controller.h
+++ b/ash/common/wm/workspace_controller.h
@@ -9,8 +9,8 @@
 
 #include "ash/ash_export.h"
 #include "ash/common/wm/workspace/workspace_types.h"
-#include "ash/common/wm_window_observer.h"
 #include "base/macros.h"
+#include "ui/aura/window_observer.h"
 
 namespace ash {
 class WmWindow;
@@ -21,7 +21,7 @@
 
 // WorkspaceController acts as a central place that ties together all the
 // various workspace pieces.
-class ASH_EXPORT WorkspaceController : public WmWindowObserver {
+class ASH_EXPORT WorkspaceController : public aura::WindowObserver {
  public:
   // Installs WorkspaceLayoutManager on |viewport|.
   explicit WorkspaceController(WmWindow* viewport);
@@ -43,8 +43,8 @@
  private:
   friend class WorkspaceControllerTestHelper;
 
-  // WmWindowObserver:
-  void OnWindowDestroying(WmWindow* window) override;
+  // aura::WindowObserver:
+  void OnWindowDestroying(aura::Window* window) override;
 
   WmWindow* viewport_;
   std::unique_ptr<WorkspaceEventHandler> event_handler_;
diff --git a/ash/common/wm_window.cc b/ash/common/wm_window.cc
index 8dfa9cb..0fbde9b 100644
--- a/ash/common/wm_window.cc
+++ b/ash/common/wm_window.cc
@@ -11,7 +11,6 @@
 #include "ash/common/wm/window_state.h"
 #include "ash/common/wm_layout_manager.h"
 #include "ash/common/wm_transient_window_observer.h"
-#include "ash/common/wm_window_observer.h"
 #include "ash/common/wm_window_property.h"
 #include "ash/public/cpp/shell_window_ids.h"
 #include "ash/public/cpp/window_properties.h"
@@ -37,6 +36,7 @@
 #include "ui/aura/mus/window_tree_client.h"
 #include "ui/aura/window.h"
 #include "ui/aura/window_delegate.h"
+#include "ui/aura/window_observer.h"
 #include "ui/base/class_property.h"
 #include "ui/base/hit_test.h"
 #include "ui/compositor/layer_tree_owner.h"
@@ -856,18 +856,6 @@
   return base::MakeUnique<wm::WindowMirrorView>(this);
 }
 
-void WmWindow::AddObserver(WmWindowObserver* observer) {
-  observers_.AddObserver(observer);
-}
-
-void WmWindow::RemoveObserver(WmWindowObserver* observer) {
-  observers_.RemoveObserver(observer);
-}
-
-bool WmWindow::HasObserver(const WmWindowObserver* observer) const {
-  return observers_.HasObserver(observer);
-}
-
 void WmWindow::AddTransientWindowObserver(WmTransientWindowObserver* observer) {
   if (!added_transient_observer_) {
     added_transient_observer_ = true;
@@ -900,37 +888,12 @@
 
 WmWindow::WmWindow(aura::Window* window)
     : window_(window),
-      // Mirrors that of aura::Window.
-      observers_(base::ObserverList<WmWindowObserver>::NOTIFY_EXISTING_ONLY),
       use_empty_minimum_size_for_testing_(
           default_use_empty_minimum_size_for_testing_) {
   window_->AddObserver(this);
   window_->SetProperty(kWmWindowKey, this);
 }
 
-void WmWindow::OnWindowHierarchyChanging(const HierarchyChangeParams& params) {
-  WmWindowObserver::TreeChangeParams wm_params;
-  wm_params.target = Get(params.target);
-  wm_params.new_parent = Get(params.new_parent);
-  wm_params.old_parent = Get(params.old_parent);
-  for (auto& observer : observers_)
-    observer.OnWindowTreeChanging(this, wm_params);
-}
-
-void WmWindow::OnWindowHierarchyChanged(const HierarchyChangeParams& params) {
-  WmWindowObserver::TreeChangeParams wm_params;
-  wm_params.target = Get(params.target);
-  wm_params.new_parent = Get(params.new_parent);
-  wm_params.old_parent = Get(params.old_parent);
-  for (auto& observer : observers_)
-    observer.OnWindowTreeChanged(this, wm_params);
-}
-
-void WmWindow::OnWindowStackingChanged(aura::Window* window) {
-  for (auto& observer : observers_)
-    observer.OnWindowStackingChanged(this);
-}
-
 void WmWindow::OnWindowPropertyChanged(aura::Window* window,
                                        const void* key,
                                        intptr_t old) {
@@ -943,65 +906,6 @@
     GetWindowState()->set_in_immersive_fullscreen(enable);
     return;
   }
-  WmWindowProperty wm_property;
-  if (key == aura::client::kAlwaysOnTopKey) {
-    wm_property = WmWindowProperty::ALWAYS_ON_TOP;
-  } else if (key == aura::client::kAppIconKey) {
-    wm_property = WmWindowProperty::APP_ICON;
-  } else if (key == aura::client::kDrawAttentionKey) {
-    wm_property = WmWindowProperty::DRAW_ATTENTION;
-  } else if (key == aura::client::kModalKey) {
-    wm_property = WmWindowProperty::MODAL_TYPE;
-  } else if (key == kPanelAttachedKey) {
-    wm_property = WmWindowProperty::PANEL_ATTACHED;
-  } else if (key == kShelfIDKey) {
-    wm_property = WmWindowProperty::SHELF_ID;
-  } else if (key == kShelfItemTypeKey) {
-    wm_property = WmWindowProperty::SHELF_ITEM_TYPE;
-  } else if (key == kSnapChildrenToPixelBoundary) {
-    wm_property = WmWindowProperty::SNAP_CHILDREN_TO_PIXEL_BOUNDARY;
-  } else if (key == aura::client::kTopViewInset) {
-    wm_property = WmWindowProperty::TOP_VIEW_INSET;
-  } else if (key == aura::client::kWindowIconKey) {
-    wm_property = WmWindowProperty::WINDOW_ICON;
-  } else {
-    return;
-  }
-  for (auto& observer : observers_)
-    observer.OnWindowPropertyChanged(this, wm_property);
-}
-
-void WmWindow::OnWindowBoundsChanged(aura::Window* window,
-                                     const gfx::Rect& old_bounds,
-                                     const gfx::Rect& new_bounds) {
-  for (auto& observer : observers_)
-    observer.OnWindowBoundsChanged(this, old_bounds, new_bounds);
-}
-
-void WmWindow::OnWindowDestroying(aura::Window* window) {
-  for (auto& observer : observers_)
-    observer.OnWindowDestroying(this);
-}
-
-void WmWindow::OnWindowDestroyed(aura::Window* window) {
-  for (auto& observer : observers_)
-    observer.OnWindowDestroyed(this);
-}
-
-void WmWindow::OnWindowVisibilityChanging(aura::Window* window, bool visible) {
-  DCHECK_EQ(window, window_);
-  for (auto& observer : observers_)
-    observer.OnWindowVisibilityChanging(this, visible);
-}
-
-void WmWindow::OnWindowVisibilityChanged(aura::Window* window, bool visible) {
-  for (auto& observer : observers_)
-    observer.OnWindowVisibilityChanged(Get(window), visible);
-}
-
-void WmWindow::OnWindowTitleChanged(aura::Window* window) {
-  for (auto& observer : observers_)
-    observer.OnWindowTitleChanged(this);
 }
 
 void WmWindow::OnTransientChildAdded(aura::Window* window,
diff --git a/ash/common/wm_window.h b/ash/common/wm_window.h
index c855661..078dd0172 100644
--- a/ash/common/wm_window.h
+++ b/ash/common/wm_window.h
@@ -49,7 +49,6 @@
 class WmLayoutManager;
 class WmShell;
 class WmTransientWindowObserver;
-class WmWindowObserver;
 class WmWindowTestApi;
 enum class WmWindowProperty;
 
@@ -354,10 +353,6 @@
   // Returns a View that renders the contents of this window's layers.
   std::unique_ptr<views::View> CreateViewWithRecreatedLayers();
 
-  void AddObserver(WmWindowObserver* observer);
-  void RemoveObserver(WmWindowObserver* observer);
-  bool HasObserver(const WmWindowObserver* observer) const;
-
   void AddTransientWindowObserver(WmTransientWindowObserver* observer);
   void RemoveTransientWindowObserver(WmTransientWindowObserver* observer);
 
@@ -376,20 +371,9 @@
   explicit WmWindow(aura::Window* window);
 
   // aura::WindowObserver:
-  void OnWindowHierarchyChanging(const HierarchyChangeParams& params) override;
-  void OnWindowHierarchyChanged(const HierarchyChangeParams& params) override;
-  void OnWindowStackingChanged(aura::Window* window) override;
   void OnWindowPropertyChanged(aura::Window* window,
                                const void* key,
                                intptr_t old) override;
-  void OnWindowBoundsChanged(aura::Window* window,
-                             const gfx::Rect& old_bounds,
-                             const gfx::Rect& new_bounds) override;
-  void OnWindowDestroying(aura::Window* window) override;
-  void OnWindowDestroyed(aura::Window* window) override;
-  void OnWindowVisibilityChanging(aura::Window* window, bool visible) override;
-  void OnWindowVisibilityChanged(aura::Window* window, bool visible) override;
-  void OnWindowTitleChanged(aura::Window* window) override;
 
   // ::wm::TransientWindowObserver overrides:
   void OnTransientChildAdded(aura::Window* window,
@@ -399,8 +383,6 @@
 
   aura::Window* window_;
 
-  base::ObserverList<WmWindowObserver> observers_;
-
   bool added_transient_observer_ = false;
   base::ObserverList<WmTransientWindowObserver> transient_observers_;
 
diff --git a/ash/common/wm_window_observer.h b/ash/common/wm_window_observer.h
deleted file mode 100644
index 544fa3b..0000000
--- a/ash/common/wm_window_observer.h
+++ /dev/null
@@ -1,62 +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 ASH_COMMON_WM_WINDOW_OBSERVER_H_
-#define ASH_COMMON_WM_WINDOW_OBSERVER_H_
-
-#include <stdint.h>
-
-#include "ash/ash_export.h"
-
-namespace gfx {
-class Rect;
-}
-
-namespace ash {
-
-class WmWindow;
-enum class WmWindowProperty;
-
-class ASH_EXPORT WmWindowObserver {
- public:
-  struct TreeChangeParams {
-    WmWindow* target = nullptr;
-    WmWindow* old_parent = nullptr;
-    WmWindow* new_parent = nullptr;
-  };
-
-  // |window| is the window the observer was added to, which is not necessarily
-  // the window that was added/removed.
-  virtual void OnWindowTreeChanging(WmWindow* window,
-                                    const TreeChangeParams& params) {}
-  virtual void OnWindowTreeChanged(WmWindow* window,
-                                   const TreeChangeParams& params) {}
-
-  virtual void OnWindowPropertyChanged(WmWindow* window,
-                                       WmWindowProperty property) {}
-
-  virtual void OnWindowStackingChanged(WmWindow* window) {}
-
-  virtual void OnWindowDestroying(WmWindow* window) {}
-  virtual void OnWindowDestroyed(WmWindow* window) {}
-
-  virtual void OnWindowBoundsChanged(WmWindow* window,
-                                     const gfx::Rect& old_bounds,
-                                     const gfx::Rect& new_bounds) {}
-
-  virtual void OnWindowVisibilityChanging(WmWindow* window, bool visible) {}
-
-  // Behavior of this function matches that of
-  // aura::WindowObserver::OnWindowVisibilityChanged(), see it for details.
-  virtual void OnWindowVisibilityChanged(WmWindow* window, bool visible) {}
-
-  virtual void OnWindowTitleChanged(WmWindow* window) {}
-
- protected:
-  virtual ~WmWindowObserver() {}
-};
-
-}  // namespace ash
-
-#endif  // ASH_COMMON_WM_WINDOW_OBSERVER_H_
diff --git a/ash/common/wm_window_tracker.h b/ash/common/wm_window_tracker.h
deleted file mode 100644
index 65c1eb1..0000000
--- a/ash/common/wm_window_tracker.h
+++ /dev/null
@@ -1,18 +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 ASH_COMMON_WM_WINDOW_TRACKER_H_
-#define ASH_COMMON_WM_WINDOW_TRACKER_H_
-
-#include "ash/common/wm_window.h"
-#include "ash/common/wm_window_observer.h"
-#include "ui/base/window_tracker_template.h"
-
-namespace ash {
-
-using WmWindowTracker = ui::WindowTrackerTemplate<WmWindow, WmWindowObserver>;
-
-}  // namespace ash
-
-#endif  // ASH_COMMON_WM_WINDOW_TRACKER_H_
diff --git a/ash/common/wm_window_unittest.cc b/ash/common/wm_window_unittest.cc
index 58dd29d6..2cbe553 100644
--- a/ash/common/wm_window_unittest.cc
+++ b/ash/common/wm_window_unittest.cc
@@ -7,7 +7,8 @@
 #include <memory>
 
 #include "ash/common/test/ash_test.h"
-#include "ash/common/wm_window_observer.h"
+#include "ui/aura/window.h"
+#include "ui/aura/window_observer.h"
 
 namespace ash {
 
@@ -16,17 +17,17 @@
 namespace {
 
 // Tracks calls to OnWindowVisibilityChanged().
-class VisibilityObserver : public WmWindowObserver {
+class VisibilityObserver : public aura::WindowObserver {
  public:
-  // Attaches a WmWindowObserver to |window_to_add_observer_to| and sets
+  // Attaches a aura::WindowObserver to |window_to_add_observer_to| and sets
   // |last_observed_window_| and |last_observed_visible_value_| to the values
   // of the last call to OnWindowVisibilityChanged().
   explicit VisibilityObserver(WmWindow* window_to_add_observer_to)
       : window_to_add_observer_to_(window_to_add_observer_to) {
-    window_to_add_observer_to_->AddObserver(this);
+    window_to_add_observer_to_->aura_window()->AddObserver(this);
   }
   ~VisibilityObserver() override {
-    window_to_add_observer_to_->RemoveObserver(this);
+    window_to_add_observer_to_->aura_window()->RemoveObserver(this);
   }
 
   // The values last supplied to OnWindowVisibilityChanged().
@@ -35,9 +36,9 @@
     return last_observed_visible_value_;
   }
 
-  // WmWindowObserver:
-  void OnWindowVisibilityChanged(WmWindow* window, bool visible) override {
-    last_observed_window_ = window;
+  // aura::WindowObserver:
+  void OnWindowVisibilityChanged(aura::Window* window, bool visible) override {
+    last_observed_window_ = WmWindow::Get(window);
     last_observed_visible_value_ = visible;
   }
 
@@ -51,7 +52,8 @@
 
 }  // namespace
 
-// Verifies OnWindowVisibilityChanged() is called on a WmWindowObserver attached
+// Verifies OnWindowVisibilityChanged() is called on a aura::WindowObserver
+// attached
 // to the parent when the child window's visibility changes.
 TEST_F(WmWindowTest, OnWindowVisibilityChangedCalledOnAncestor) {
   std::unique_ptr<WindowOwner> window_owner = CreateTestWindow();
@@ -65,7 +67,8 @@
   EXPECT_FALSE(observer.last_observed_visible_value());
 }
 
-// Verifies OnWindowVisibilityChanged() is called on a WmWindowObserver attached
+// Verifies OnWindowVisibilityChanged() is called on a aura::WindowObserver
+// attached
 // to a child when the parent window's visibility changes.
 TEST_F(WmWindowTest, OnWindowVisibilityChangedCalledOnChild) {
   std::unique_ptr<WindowOwner> parent_window_owner = CreateTestWindow();
diff --git a/ash/common/wm_window_user_data.h b/ash/common/wm_window_user_data.h
index bafd19f..2a6abd23 100644
--- a/ash/common/wm_window_user_data.h
+++ b/ash/common/wm_window_user_data.h
@@ -10,17 +10,18 @@
 #include <utility>
 
 #include "ash/common/wm_window.h"
-#include "ash/common/wm_window_observer.h"
 #include "base/macros.h"
+#include "ui/aura/window.h"
+#include "ui/aura/window_observer.h"
 
 namespace ash {
 
 // WmWindowUserData provides a way to associate arbitrary objects with a
 // WmWindow. WmWindowUserData owns the data, deleting it either when
 // WmWindowUserData is deleted, or when the window the data is associated with
-// is destroyed (from WmWindowObserver::OnWindowDestroying()).
+// is destroyed (from aura::WindowObserver::OnWindowDestroying()).
 template <typename UserData>
-class WmWindowUserData : public WmWindowObserver {
+class WmWindowUserData : public aura::WindowObserver {
  public:
   WmWindowUserData() {}
 
@@ -28,7 +29,7 @@
 
   void clear() {
     for (auto& pair : window_to_data_)
-      pair.first->RemoveObserver(this);
+      pair.first->aura_window()->RemoveObserver(this);
     window_to_data_.clear();
   }
 
@@ -37,11 +38,11 @@
   void Set(WmWindow* window, std::unique_ptr<UserData> data) {
     if (!data) {
       if (window_to_data_.erase(window))
-        window->RemoveObserver(this);
+        window->aura_window()->RemoveObserver(this);
       return;
     }
     if (window_to_data_.count(window) == 0u)
-      window->AddObserver(this);
+      window->aura_window()->AddObserver(this);
     window_to_data_[window] = std::move(data);
   }
 
@@ -61,10 +62,10 @@
   }
 
  private:
-  // WmWindowObserver:
-  void OnWindowDestroying(WmWindow* window) override {
+  // aura::WindowObserver:
+  void OnWindowDestroying(aura::Window* window) override {
     window->RemoveObserver(this);
-    window_to_data_.erase(window);
+    window_to_data_.erase(WmWindow::Get(window));
   }
 
   std::map<WmWindow*, std::unique_ptr<UserData>> window_to_data_;
diff --git a/ash/display/screen_orientation_controller_chromeos.cc b/ash/display/screen_orientation_controller_chromeos.cc
index 45c8bcd..c38bef1 100644
--- a/ash/display/screen_orientation_controller_chromeos.cc
+++ b/ash/display/screen_orientation_controller_chromeos.cc
@@ -76,7 +76,7 @@
   WmShell::Get()->RemoveDisplayObserver(this);
   WmShell::Get()->RemoveActivationObserver(this);
   for (auto& windows : locking_windows_)
-    windows.first->RemoveObserver(this);
+    windows.first->aura_window()->RemoveObserver(this);
 }
 
 void ScreenOrientationController::AddObserver(Observer* observer) {
@@ -93,8 +93,8 @@
   if (locking_windows_.empty())
     WmShell::Get()->AddActivationObserver(this);
 
-  if (!requesting_window->HasObserver(this))
-    requesting_window->AddObserver(this);
+  if (!requesting_window->aura_window()->HasObserver(this))
+    requesting_window->aura_window()->AddObserver(this);
   locking_windows_[requesting_window] = lock_orientation;
 
   ApplyLockForActiveWindow();
@@ -104,13 +104,13 @@
   locking_windows_.erase(window);
   if (locking_windows_.empty())
     WmShell::Get()->RemoveActivationObserver(this);
-  window->RemoveObserver(this);
+  window->aura_window()->RemoveObserver(this);
   ApplyLockForActiveWindow();
 }
 
 void ScreenOrientationController::UnlockAll() {
   for (auto pair : locking_windows_)
-    pair.first->RemoveObserver(this);
+    pair.first->aura_window()->RemoveObserver(this);
   locking_windows_.clear();
   WmShell::Get()->RemoveActivationObserver(this);
   SetRotationLocked(false);
@@ -161,8 +161,8 @@
   ApplyLockForActiveWindow();
 }
 
-void ScreenOrientationController::OnWindowDestroying(WmWindow* window) {
-  UnlockOrientationForWindow(window);
+void ScreenOrientationController::OnWindowDestroying(aura::Window* window) {
+  UnlockOrientationForWindow(WmWindow::Get(window));
 }
 
 // Currently contents::WebContents will only be able to lock rotation while
@@ -172,9 +172,10 @@
 // down and mouse up. The rotation this triggers leads to a coordinate space
 // change in the middle of an event. Causes the tab to separate from the tab
 // strip.
-void ScreenOrientationController::OnWindowVisibilityChanged(WmWindow* window,
-                                                            bool visible) {
-  if (locking_windows_.find(window) == locking_windows_.end())
+void ScreenOrientationController::OnWindowVisibilityChanged(
+    aura::Window* window,
+    bool visible) {
+  if (locking_windows_.find(WmWindow::Get(window)) == locking_windows_.end())
     return;
   ApplyLockForActiveWindow();
 }
diff --git a/ash/display/screen_orientation_controller_chromeos.h b/ash/display/screen_orientation_controller_chromeos.h
index 7a09c66..e0d0e5bd 100644
--- a/ash/display/screen_orientation_controller_chromeos.h
+++ b/ash/display/screen_orientation_controller_chromeos.h
@@ -11,12 +11,12 @@
 #include "ash/common/shell_observer.h"
 #include "ash/common/wm_activation_observer.h"
 #include "ash/common/wm_display_observer.h"
-#include "ash/common/wm_window_observer.h"
 #include "base/macros.h"
 #include "base/observer_list.h"
 #include "chromeos/accelerometer/accelerometer_reader.h"
 #include "chromeos/accelerometer/accelerometer_types.h"
 #include "third_party/WebKit/public/platform/modules/screen_orientation/WebScreenOrientationLockType.h"
+#include "ui/aura/window_observer.h"
 #include "ui/display/display.h"
 
 namespace ash {
@@ -24,7 +24,7 @@
 // Implements ChromeOS specific functionality for ScreenOrientationProvider.
 class ASH_EXPORT ScreenOrientationController
     : public WmActivationObserver,
-      public WmWindowObserver,
+      public aura::WindowObserver,
       public chromeos::AccelerometerReader::Observer,
       public WmDisplayObserver,
       public ShellObserver {
@@ -80,9 +80,9 @@
   void OnWindowActivated(WmWindow* gained_active,
                          WmWindow* lost_active) override;
 
-  // WmWindowObserver:
-  void OnWindowDestroying(WmWindow* window) override;
-  void OnWindowVisibilityChanged(WmWindow* window, bool visible) override;
+  // aura::WindowObserver:
+  void OnWindowDestroying(aura::Window* window) override;
+  void OnWindowVisibilityChanged(aura::Window* window, bool visible) override;
 
   // chromeos::AccelerometerReader::Observer:
   void OnAccelerometerUpdated(
diff --git a/ash/root_window_controller.cc b/ash/root_window_controller.cc
index 953c520f..be538ba 100644
--- a/ash/root_window_controller.cc
+++ b/ash/root_window_controller.cc
@@ -597,22 +597,22 @@
 
   // Explicitly destroy top level windows. We do this because such windows may
   // query the RootWindow for state.
-  WmWindowTracker non_toplevel_windows;
+  aura::WindowTracker non_toplevel_windows;
   WmWindow* root = GetWindow();
-  non_toplevel_windows.Add(root);
+  non_toplevel_windows.Add(root->aura_window());
   while (!non_toplevel_windows.windows().empty()) {
-    WmWindow* non_toplevel_window = non_toplevel_windows.Pop();
-    WmWindowTracker toplevel_windows;
-    for (WmWindow* child : non_toplevel_window->GetChildren()) {
-      if (!ShouldDestroyWindowInCloseChildWindows(child))
+    aura::Window* non_toplevel_window = non_toplevel_windows.Pop();
+    aura::WindowTracker toplevel_windows;
+    for (aura::Window* child : non_toplevel_window->children()) {
+      if (!ShouldDestroyWindowInCloseChildWindows(WmWindow::Get(child)))
         continue;
-      if (child->HasNonClientArea())
+      if (child->delegate())
         toplevel_windows.Add(child);
       else
         non_toplevel_windows.Add(child);
     }
     while (!toplevel_windows.windows().empty())
-      toplevel_windows.Pop()->Destroy();
+      delete toplevel_windows.Pop();
   }
   // And then remove the containers.
   while (!root->GetChildren().empty()) {
diff --git a/ash/shelf/shelf_window_targeter.cc b/ash/shelf/shelf_window_targeter.cc
index e8198b2..24ba0e8 100644
--- a/ash/shelf/shelf_window_targeter.cc
+++ b/ash/shelf/shelf_window_targeter.cc
@@ -8,6 +8,7 @@
 #include "ash/common/shelf/wm_shelf.h"
 #include "ash/common/wm_window.h"
 #include "ash/public/cpp/shelf_types.h"
+#include "ui/aura/window.h"
 
 namespace ash {
 
@@ -29,7 +30,7 @@
                                      gfx::Insets()),
       shelf_(shelf) {
   WillChangeVisibilityState(shelf_->GetVisibilityState());
-  container->AddObserver(this);
+  container->aura_window()->AddObserver(this);
   shelf_->AddObserver(this);
 }
 
@@ -38,7 +39,7 @@
   DCHECK(!shelf_);
 }
 
-void ShelfWindowTargeter::OnWindowDestroying(WmWindow* window) {
+void ShelfWindowTargeter::OnWindowDestroying(aura::Window* window) {
   window->RemoveObserver(this);
   shelf_->RemoveObserver(this);
   shelf_ = nullptr;
diff --git a/ash/shelf/shelf_window_targeter.h b/ash/shelf/shelf_window_targeter.h
index 390bd51..fd14fe1 100644
--- a/ash/shelf/shelf_window_targeter.h
+++ b/ash/shelf/shelf_window_targeter.h
@@ -6,27 +6,28 @@
 #define ASH_SHELF_SHELF_WINDOW_TARGETER_H_
 
 #include "ash/common/shelf/wm_shelf_observer.h"
-#include "ash/common/wm_window_observer.h"
 #include "base/macros.h"
+#include "ui/aura/window_observer.h"
 #include "ui/wm/core/easy_resize_window_targeter.h"
 
 namespace ash {
 
 class WmShelf;
+class WmWindow;
 
 // ShelfWindowTargeter makes it easier to resize windows with the mouse when the
 // window-edge slightly overlaps with the shelf edge. The targeter also makes it
 // easier to drag the shelf out with touch while it is hidden.
 class ShelfWindowTargeter : public ::wm::EasyResizeWindowTargeter,
-                            public WmWindowObserver,
+                            public aura::WindowObserver,
                             public WmShelfObserver {
  public:
   ShelfWindowTargeter(WmWindow* container, WmShelf* shelf);
   ~ShelfWindowTargeter() override;
 
  private:
-  // WmWindowObserver:
-  void OnWindowDestroying(WmWindow* window) override;
+  // aura::WindowObserver:
+  void OnWindowDestroying(aura::Window* window) override;
 
   // WmShelfObserver:
   void WillChangeVisibilityState(ShelfVisibilityState new_state) override;
diff --git a/ash/wm/screen_pinning_controller.cc b/ash/wm/screen_pinning_controller.cc
index 8720048..72147115 100644
--- a/ash/wm/screen_pinning_controller.cc
+++ b/ash/wm/screen_pinning_controller.cc
@@ -12,7 +12,6 @@
 #include "ash/common/wm/window_state.h"
 #include "ash/common/wm_shell.h"
 #include "ash/common/wm_window.h"
-#include "ash/common/wm_window_observer.h"
 #include "ash/common/wm_window_user_data.h"
 #include "ash/display/window_tree_host_manager.h"
 #include "ash/public/cpp/shell_window_ids.h"
diff --git a/ash/wm/video_detector.cc b/ash/wm/video_detector.cc
index b1ccbc0..18d9704 100644
--- a/ash/wm/video_detector.cc
+++ b/ash/wm/video_detector.cc
@@ -82,7 +82,6 @@
     : state_(State::NOT_PLAYING),
       video_is_playing_(false),
       window_observer_manager_(this),
-      wm_window_observer_manager_(this),
       is_shutting_down_(false) {
   aura::Env::GetInstance()->AddObserver(this);
   WmShell::Get()->AddShellObserver(this);
@@ -129,6 +128,14 @@
     HandleVideoActivity(window, now);
 }
 
+void VideoDetector::OnWindowDestroying(aura::Window* window) {
+  if (fullscreen_root_windows_.count(window)) {
+    window_observer_manager_.Remove(window);
+    fullscreen_root_windows_.erase(window);
+    UpdateState();
+  }
+}
+
 void VideoDetector::OnWindowDestroyed(aura::Window* window) {
   window_infos_.erase(window);
   window_observer_manager_.Remove(window);
@@ -142,21 +149,15 @@
 
 void VideoDetector::OnFullscreenStateChanged(bool is_fullscreen,
                                              WmWindow* root_window) {
-  if (is_fullscreen && !fullscreen_root_windows_.count(root_window)) {
-    fullscreen_root_windows_.insert(root_window);
-    wm_window_observer_manager_.Add(root_window);
+  aura::Window* aura_window = root_window->aura_window();
+  if (is_fullscreen && !fullscreen_root_windows_.count(aura_window)) {
+    fullscreen_root_windows_.insert(aura_window);
+    if (!window_observer_manager_.IsObserving(aura_window))
+      window_observer_manager_.Add(aura_window);
     UpdateState();
-  } else if (!is_fullscreen && fullscreen_root_windows_.count(root_window)) {
-    fullscreen_root_windows_.erase(root_window);
-    wm_window_observer_manager_.Remove(root_window);
-    UpdateState();
-  }
-}
-
-void VideoDetector::OnWindowDestroying(WmWindow* window) {
-  if (fullscreen_root_windows_.count(window)) {
-    wm_window_observer_manager_.Remove(window);
-    fullscreen_root_windows_.erase(window);
+  } else if (!is_fullscreen && fullscreen_root_windows_.count(aura_window)) {
+    fullscreen_root_windows_.erase(aura_window);
+    window_observer_manager_.Remove(aura_window);
     UpdateState();
   }
 }
diff --git a/ash/wm/video_detector.h b/ash/wm/video_detector.h
index 2eb4287..5eb9804 100644
--- a/ash/wm/video_detector.h
+++ b/ash/wm/video_detector.h
@@ -11,7 +11,6 @@
 
 #include "ash/ash_export.h"
 #include "ash/common/shell_observer.h"
-#include "ash/common/wm_window_observer.h"
 #include "base/compiler_specific.h"
 #include "base/macros.h"
 #include "base/observer_list.h"
@@ -36,8 +35,7 @@
 // continuous scrolling of a page.
 class ASH_EXPORT VideoDetector : public aura::EnvObserver,
                                  public aura::WindowObserver,
-                                 public ShellObserver,
-                                 public WmWindowObserver {
+                                 public ShellObserver {
  public:
   // State of detected video activity.
   enum class State {
@@ -93,21 +91,17 @@
   // EnvObserver overrides.
   void OnWindowInitialized(aura::Window* window) override;
 
-  // WindowObserver overrides.
+  // aura::WindowObserver overrides.
   void OnDelegatedFrameDamage(aura::Window* window,
                               const gfx::Rect& region) override;
   void OnWindowDestroyed(aura::Window* window) override;
-  void OnWindowDestroying(aura::Window* window) override {}
+  void OnWindowDestroying(aura::Window* window) override;
 
   // ShellObserver overrides.
   void OnAppTerminating() override;
   void OnFullscreenStateChanged(bool is_fullscreen,
                                 WmWindow* root_window) override;
 
-  // WmWindowObserver overrides.
-  void OnWindowDestroyed(WmWindow* window) override {}
-  void OnWindowDestroying(WmWindow* window) override;
-
  private:
   // Called when video activity is observed in |window|.
   void HandleVideoActivity(aura::Window* window, base::TimeTicks now);
@@ -126,7 +120,7 @@
   bool video_is_playing_;
 
   // Currently-fullscreen root windows.
-  std::set<WmWindow*> fullscreen_root_windows_;
+  std::set<aura::Window*> fullscreen_root_windows_;
 
   // Maps from a window that we're tracking to information about it.
   class WindowInfo;
@@ -143,7 +137,6 @@
   base::TimeTicks now_for_test_;
 
   ScopedObserver<aura::Window, aura::WindowObserver> window_observer_manager_;
-  ScopedObserver<WmWindow, WmWindowObserver> wm_window_observer_manager_;
 
   bool is_shutting_down_;
 
diff --git a/cc/BUILD.gn b/cc/BUILD.gn
index c0bbd2b0..3fc669a 100644
--- a/cc/BUILD.gn
+++ b/cc/BUILD.gn
@@ -388,6 +388,8 @@
     "scheduler/scheduler_state_machine.cc",
     "scheduler/scheduler_state_machine.h",
     "scheduler/video_frame_controller.h",
+    "tiles/checker_image_tracker.cc",
+    "tiles/checker_image_tracker.h",
     "tiles/decoded_image_tracker.cc",
     "tiles/decoded_image_tracker.h",
     "tiles/eviction_tile_priority_queue.cc",
@@ -419,6 +421,7 @@
     "tiles/tile_draw_info.h",
     "tiles/tile_manager.cc",
     "tiles/tile_manager.h",
+    "tiles/tile_manager_settings.h",
     "tiles/tile_priority.cc",
     "tiles/tile_priority.h",
     "tiles/tile_task_manager.cc",
@@ -827,6 +830,7 @@
     "test/mock_helper_unittest.cc",
     "test/ordered_simple_task_runner_unittest.cc",
     "test/test_web_graphics_context_3d_unittest.cc",
+    "tiles/checker_image_tracker_unittest.cc",
     "tiles/decoded_image_tracker_unittest.cc",
     "tiles/gpu_image_decode_cache_unittest.cc",
     "tiles/image_controller_unittest.cc",
diff --git a/cc/layers/picture_layer_impl.cc b/cc/layers/picture_layer_impl.cc
index 5012061..626c4ae 100644
--- a/cc/layers/picture_layer_impl.cc
+++ b/cc/layers/picture_layer_impl.cc
@@ -1380,4 +1380,27 @@
          is_drawn_render_surface_layer_list_member();
 }
 
+void PictureLayerImpl::InvalidateRegionForImages(
+    const ImageIdFlatSet& images_to_invalidate) {
+  TRACE_EVENT_BEGIN0("cc", "PictureLayerImpl::InvalidateRegionForImages");
+
+  InvalidationRegion image_invalidation;
+  for (auto image_id : images_to_invalidate)
+    image_invalidation.Union(raster_source_->GetRectForImage(image_id));
+  Region invalidation;
+  image_invalidation.Swap(&invalidation);
+
+  if (invalidation.IsEmpty()) {
+    TRACE_EVENT_END1("cc", "PictureLayerImpl::InvalidateRegionForImages",
+                     "Invalidation", invalidation.ToString());
+    return;
+  }
+
+  invalidation_.Union(invalidation);
+  tilings_->UpdateTilingsForImplSideInvalidation(invalidation);
+  SetNeedsPushProperties();
+  TRACE_EVENT_END1("cc", "PictureLayerImpl::InvalidateRegionForImages",
+                   "Invalidation", invalidation.ToString());
+}
+
 }  // namespace cc
diff --git a/cc/layers/picture_layer_impl.h b/cc/layers/picture_layer_impl.h
index 94d16aa..93a703e0 100644
--- a/cc/layers/picture_layer_impl.h
+++ b/cc/layers/picture_layer_impl.h
@@ -16,6 +16,7 @@
 #include "cc/base/cc_export.h"
 #include "cc/layers/layer.h"
 #include "cc/layers/layer_impl.h"
+#include "cc/playback/image_id.h"
 #include "cc/tiles/picture_layer_tiling.h"
 #include "cc/tiles/picture_layer_tiling_set.h"
 #include "cc/tiles/tiling_set_eviction_queue.h"
@@ -98,6 +99,8 @@
     is_directly_composited_image_ = is_directly_composited_image;
   }
 
+  void InvalidateRegionForImages(const ImageIdFlatSet& images_to_invalidate);
+
  protected:
   PictureLayerImpl(LayerTreeImpl* tree_impl,
                    int id,
diff --git a/cc/playback/image_hijack_canvas.cc b/cc/playback/image_hijack_canvas.cc
index 8262d51..bd26d32 100644
--- a/cc/playback/image_hijack_canvas.cc
+++ b/cc/playback/image_hijack_canvas.cc
@@ -119,12 +119,20 @@
   SkPaint paint_;
 };
 
+const SkImage* GetImageInPaint(const SkPaint& paint) {
+  SkShader* shader = paint.getShader();
+  return shader ? shader->isAImage(nullptr, nullptr) : nullptr;
+}
+
 }  // namespace
 
 ImageHijackCanvas::ImageHijackCanvas(int width,
                                      int height,
-                                     ImageDecodeCache* image_decode_cache)
-    : SkNWayCanvas(width, height), image_decode_cache_(image_decode_cache) {}
+                                     ImageDecodeCache* image_decode_cache,
+                                     const ImageIdFlatSet* images_to_skip)
+    : SkNWayCanvas(width, height),
+      image_decode_cache_(image_decode_cache),
+      images_to_skip_(images_to_skip) {}
 
 void ImageHijackCanvas::onDrawPicture(const SkPicture* picture,
                                       const SkMatrix* matrix,
@@ -139,10 +147,14 @@
                                     SkScalar y,
                                     const SkPaint* paint) {
   if (!image->isLazyGenerated()) {
+    DCHECK(!ShouldSkipImage(image));
     SkNWayCanvas::onDrawImage(image, x, y, paint);
     return;
   }
 
+  if (ShouldSkipImage(image))
+    return;
+
   SkMatrix ctm = getTotalMatrix();
 
   ScopedDecodedImageLock scoped_lock(
@@ -173,10 +185,14 @@
                                         const SkPaint* paint,
                                         SrcRectConstraint constraint) {
   if (!image->isLazyGenerated()) {
+    DCHECK(!ShouldSkipImage(image));
     SkNWayCanvas::onDrawImageRect(image, src, dst, paint, constraint);
     return;
   }
 
+  if (ShouldSkipImage(image))
+    return;
+
   SkRect src_storage;
   if (!src) {
     src_storage = SkRect::MakeIWH(image->width(), image->height());
@@ -209,6 +225,9 @@
 }
 
 void ImageHijackCanvas::onDrawRect(const SkRect& r, const SkPaint& paint) {
+  if (ShouldSkipImageInPaint(paint))
+    return;
+
   base::Optional<ScopedImagePaint> image_paint =
       ScopedImagePaint::TryCreate(image_decode_cache_, getTotalMatrix(), paint);
   if (!image_paint.has_value()) {
@@ -219,6 +238,9 @@
 }
 
 void ImageHijackCanvas::onDrawPath(const SkPath& path, const SkPaint& paint) {
+  if (ShouldSkipImageInPaint(paint))
+    return;
+
   base::Optional<ScopedImagePaint> image_paint =
       ScopedImagePaint::TryCreate(image_decode_cache_, getTotalMatrix(), paint);
   if (!image_paint.has_value()) {
@@ -229,6 +251,9 @@
 }
 
 void ImageHijackCanvas::onDrawOval(const SkRect& r, const SkPaint& paint) {
+  if (ShouldSkipImageInPaint(paint))
+    return;
+
   base::Optional<ScopedImagePaint> image_paint =
       ScopedImagePaint::TryCreate(image_decode_cache_, getTotalMatrix(), paint);
   if (!image_paint.has_value()) {
@@ -243,6 +268,9 @@
                                   SkScalar sweep_angle,
                                   bool use_center,
                                   const SkPaint& paint) {
+  if (ShouldSkipImageInPaint(paint))
+    return;
+
   base::Optional<ScopedImagePaint> image_paint =
       ScopedImagePaint::TryCreate(image_decode_cache_, getTotalMatrix(), paint);
   if (!image_paint.has_value()) {
@@ -254,6 +282,9 @@
 }
 
 void ImageHijackCanvas::onDrawRRect(const SkRRect& rr, const SkPaint& paint) {
+  if (ShouldSkipImageInPaint(paint))
+    return;
+
   base::Optional<ScopedImagePaint> image_paint =
       ScopedImagePaint::TryCreate(image_decode_cache_, getTotalMatrix(), paint);
   if (!image_paint.has_value()) {
@@ -271,4 +302,13 @@
   NOTREACHED();
 }
 
+bool ImageHijackCanvas::ShouldSkipImage(const SkImage* image) const {
+  return images_to_skip_->find(image->uniqueID()) != images_to_skip_->end();
+}
+
+bool ImageHijackCanvas::ShouldSkipImageInPaint(const SkPaint& paint) const {
+  const SkImage* image = GetImageInPaint(paint);
+  return image ? ShouldSkipImage(image) : false;
+}
+
 }  // namespace cc
diff --git a/cc/playback/image_hijack_canvas.h b/cc/playback/image_hijack_canvas.h
index be9a6ba..2a43d52 100644
--- a/cc/playback/image_hijack_canvas.h
+++ b/cc/playback/image_hijack_canvas.h
@@ -5,8 +5,11 @@
 #ifndef CC_PLAYBACK_IMAGE_HIJACK_CANVAS_H_
 #define CC_PLAYBACK_IMAGE_HIJACK_CANVAS_H_
 
+#include <unordered_set>
+
 #include "base/macros.h"
 #include "cc/base/cc_export.h"
+#include "cc/playback/image_id.h"
 #include "third_party/skia/include/utils/SkNWayCanvas.h"
 
 namespace cc {
@@ -17,7 +20,8 @@
  public:
   ImageHijackCanvas(int width,
                     int height,
-                    ImageDecodeCache* image_decode_cache);
+                    ImageDecodeCache* image_decode_cache,
+                    const ImageIdFlatSet* images_to_skip);
 
  private:
   // Ensure that pictures are unpacked by this canvas, instead of being
@@ -48,7 +52,11 @@
                        const SkRect& dst,
                        const SkPaint* paint) override;
 
+  bool ShouldSkipImage(const SkImage* image) const;
+  bool ShouldSkipImageInPaint(const SkPaint& paint) const;
+
   ImageDecodeCache* image_decode_cache_;
+  const ImageIdFlatSet* images_to_skip_;
 
   DISALLOW_COPY_AND_ASSIGN(ImageHijackCanvas);
 };
diff --git a/cc/playback/image_hijack_canvas_unittest.cc b/cc/playback/image_hijack_canvas_unittest.cc
index 76186eea..951efb7 100644
--- a/cc/playback/image_hijack_canvas_unittest.cc
+++ b/cc/playback/image_hijack_canvas_unittest.cc
@@ -3,6 +3,7 @@
 // found in the LICENSE file.
 #include "cc/playback/image_hijack_canvas.h"
 
+#include "cc/test/skia_common.h"
 #include "cc/tiles/image_decode_cache.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -36,7 +37,8 @@
   // Use a strict mock so that if *any* ImageDecodeCache methods are called, we
   // will hit an error.
   testing::StrictMock<MockImageDecodeCache> image_decode_cache;
-  ImageHijackCanvas canvas(100, 100, &image_decode_cache);
+  ImageIdFlatSet images_to_skip;
+  ImageHijackCanvas canvas(100, 100, &image_decode_cache, &images_to_skip);
 
   // Use an SkBitmap backed image to ensure that the image is not
   // lazy-generated.
@@ -62,6 +64,24 @@
   canvas.drawRRect(SkRRect::MakeRect(paint_rect), image_paint);
 }
 
+TEST(ImageHijackCanvasTest, ImagesToSkipAreSkipped) {
+  // Use a strict mock so that if *any* ImageDecodeCache methods are called, we
+  // will hit an error.
+  testing::StrictMock<MockImageDecodeCache> image_decode_cache;
+  ImageIdFlatSet images_to_skip;
+  sk_sp<SkImage> image = CreateDiscardableImage(gfx::Size(10, 10));
+  images_to_skip.insert(image->uniqueID());
+  ImageHijackCanvas canvas(100, 100, &image_decode_cache, &images_to_skip);
+
+  SkPaint paint;
+  canvas.drawImage(image, 0, 0, &paint);
+  canvas.drawImageRect(image, SkRect::MakeXYWH(0, 0, 10, 10),
+                       SkRect::MakeXYWH(10, 10, 10, 10), &paint);
+  paint.setShader(image->makeShader(SkShader::kClamp_TileMode,
+                                    SkShader::kClamp_TileMode, nullptr));
+  canvas.drawRect(SkRect::MakeXYWH(10, 10, 10, 10), paint);
+}
+
 }  // namespace
 
 }  // namespace cc
diff --git a/cc/playback/image_id.h b/cc/playback/image_id.h
index c29810b..5103857f 100644
--- a/cc/playback/image_id.h
+++ b/cc/playback/image_id.h
@@ -5,9 +5,15 @@
 #ifndef CC_PLAYBACK_IMAGE_ID_H_
 #define CC_PLAYBACK_IMAGE_ID_H_
 
+#include <stdint.h>
+#include <unordered_set>
+
+#include "base/containers/flat_set.h"
+
 namespace cc {
 
 using ImageId = uint32_t;
+using ImageIdFlatSet = base::flat_set<ImageId>;
 
 }  // namespace cc
 
diff --git a/cc/playback/raster_source.cc b/cc/playback/raster_source.cc
index 9d64255..59ed14b 100644
--- a/cc/playback/raster_source.cc
+++ b/cc/playback/raster_source.cc
@@ -89,8 +89,8 @@
     RasterCommon(&canvas, nullptr);
   } else if (settings.use_image_hijack_canvas) {
     const SkImageInfo& info = raster_canvas->imageInfo();
-
-    ImageHijackCanvas canvas(info.width(), info.height(), image_decode_cache_);
+    ImageHijackCanvas canvas(info.width(), info.height(), image_decode_cache_,
+                             &settings.images_to_skip);
     // Before adding the canvas, make sure that the ImageHijackCanvas is aware
     // of the current transform and clip, which may affect the clip bounds.
     // Since we query the clip bounds of the current canvas to get the list of
@@ -311,4 +311,11 @@
       skip_images(false),
       use_image_hijack_canvas(true) {}
 
+RasterSource::PlaybackSettings::PlaybackSettings(const PlaybackSettings&) =
+    default;
+
+RasterSource::PlaybackSettings::PlaybackSettings(PlaybackSettings&&) = default;
+
+RasterSource::PlaybackSettings::~PlaybackSettings() = default;
+
 }  // namespace cc
diff --git a/cc/playback/raster_source.h b/cc/playback/raster_source.h
index ccfb613..aae19ea 100644
--- a/cc/playback/raster_source.h
+++ b/cc/playback/raster_source.h
@@ -31,6 +31,9 @@
  public:
   struct CC_EXPORT PlaybackSettings {
     PlaybackSettings();
+    PlaybackSettings(const PlaybackSettings&);
+    PlaybackSettings(PlaybackSettings&&);
+    ~PlaybackSettings();
 
     // If set to true, this indicates that the canvas has already been
     // rasterized into. This means that the canvas cannot be cleared safely.
@@ -42,6 +45,12 @@
     // If set to true, we will use an image hijack canvas, which enables
     // compositor image caching.
     bool use_image_hijack_canvas;
+
+    // If non-empty, an image hijack canvas will be used to skip these images
+    // during raster.
+    // TODO(khushalsagar): Consolidate more settings for playback here? See
+    // crbug.com/691076.
+    ImageIdFlatSet images_to_skip;
   };
 
   static scoped_refptr<RasterSource> CreateFromRecordingSource(
diff --git a/cc/test/fake_layer_tree_host_impl.cc b/cc/test/fake_layer_tree_host_impl.cc
index 63a32fd..f7909cf 100644
--- a/cc/test/fake_layer_tree_host_impl.cc
+++ b/cc/test/fake_layer_tree_host_impl.cc
@@ -25,6 +25,16 @@
     const LayerTreeSettings& settings,
     TaskRunnerProvider* task_runner_provider,
     TaskGraphRunner* task_graph_runner)
+    : FakeLayerTreeHostImpl(settings,
+                            task_runner_provider,
+                            task_graph_runner,
+                            nullptr) {}
+
+FakeLayerTreeHostImpl::FakeLayerTreeHostImpl(
+    const LayerTreeSettings& settings,
+    TaskRunnerProvider* task_runner_provider,
+    TaskGraphRunner* task_graph_runner,
+    scoped_refptr<base::SequencedTaskRunner> image_worker_task_runner)
     : LayerTreeHostImpl(settings,
                         &client_,
                         task_runner_provider,
@@ -32,7 +42,7 @@
                         task_graph_runner,
                         AnimationHost::CreateForTesting(ThreadInstance::IMPL),
                         0,
-                        nullptr),
+                        std::move(image_worker_task_runner)),
       notify_tile_state_changed_called_(false) {
   // Explicitly clear all debug settings.
   SetDebugState(LayerTreeDebugState());
diff --git a/cc/test/fake_layer_tree_host_impl.h b/cc/test/fake_layer_tree_host_impl.h
index 1a6e01b0..a67bcfe 100644
--- a/cc/test/fake_layer_tree_host_impl.h
+++ b/cc/test/fake_layer_tree_host_impl.h
@@ -21,6 +21,11 @@
   FakeLayerTreeHostImpl(const LayerTreeSettings& settings,
                         TaskRunnerProvider* task_runner_provider,
                         TaskGraphRunner* task_graph_runner);
+  FakeLayerTreeHostImpl(
+      const LayerTreeSettings& settings,
+      TaskRunnerProvider* task_runner_provider,
+      TaskGraphRunner* task_graph_runner,
+      scoped_refptr<base::SequencedTaskRunner> image_worker_task_runner);
   ~FakeLayerTreeHostImpl() override;
 
   void ForcePrepareToDraw() {
diff --git a/cc/test/fake_layer_tree_host_impl_client.h b/cc/test/fake_layer_tree_host_impl_client.h
index a2d1e44..4bcc5b0 100644
--- a/cc/test/fake_layer_tree_host_impl_client.h
+++ b/cc/test/fake_layer_tree_host_impl_client.h
@@ -35,6 +35,7 @@
   void DidPrepareTiles() override {}
   void DidCompletePageScaleAnimationOnImplThread() override {}
   void OnDrawForCompositorFrameSink(bool resourceless_software_draw) override {}
+  void NeedsImplSideInvalidation() override {}
 };
 
 }  // namespace cc
diff --git a/cc/test/fake_tile_manager.cc b/cc/test/fake_tile_manager.cc
index 24457b51..81c936f 100644
--- a/cc/test/fake_tile_manager.cc
+++ b/cc/test/fake_tile_manager.cc
@@ -36,8 +36,7 @@
                   base::ThreadTaskRunnerHandle::Get().get(),
                   nullptr,
                   std::numeric_limits<size_t>::max(),
-                  false /* use_partial_raster */,
-                  false /* check_tile_priority_inversion */),
+                  TileManagerSettings()),
       image_decode_cache_(
           ResourceFormat::RGBA_8888,
           LayerTreeSettings().software_decoded_image_budget_bytes) {
diff --git a/cc/test/fake_tile_manager_client.h b/cc/test/fake_tile_manager_client.h
index 8f08eec..2ae8998d 100644
--- a/cc/test/fake_tile_manager_client.h
+++ b/cc/test/fake_tile_manager_client.h
@@ -28,6 +28,7 @@
       TreePriority tree_priority) override;
   void SetIsLikelyToRequireADraw(bool is_likely_to_require_a_draw) override {}
   gfx::ColorSpace GetTileColorSpace() const override;
+  void RequestImplSideInvalidation() override {}
 };
 
 }  // namespace cc
diff --git a/cc/tiles/checker_image_tracker.cc b/cc/tiles/checker_image_tracker.cc
new file mode 100644
index 0000000..c081132
--- /dev/null
+++ b/cc/tiles/checker_image_tracker.cc
@@ -0,0 +1,152 @@
+// 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 "cc/tiles/checker_image_tracker.h"
+
+#include "base/bind.h"
+#include "base/trace_event/trace_event.h"
+
+namespace cc {
+namespace {
+// The minimum size of an image that we should consider checkering.
+size_t kMinImageSizeToCheckerBytes = 512 * 1024;
+
+size_t SafeSizeOfImage(const SkImage* image) {
+  base::CheckedNumeric<size_t> checked_size = 4;
+  checked_size *= image->width();
+  checked_size *= image->height();
+  return checked_size.ValueOrDefault(std::numeric_limits<size_t>::max());
+}
+
+}  // namespace
+
+CheckerImageTracker::CheckerImageTracker(ImageController* image_controller,
+                                         CheckerImageTrackerClient* client,
+                                         bool enable_checker_imaging)
+    : image_controller_(image_controller),
+      client_(client),
+      enable_checker_imaging_(enable_checker_imaging),
+      weak_factory_(this) {}
+
+CheckerImageTracker::~CheckerImageTracker() {
+  // Unlock all images pending decode requests.
+  for (auto it : image_id_to_decode_request_id_)
+    image_controller_->UnlockImageDecode(it.second);
+}
+
+void CheckerImageTracker::FilterImagesForCheckeringForTile(
+    std::vector<DrawImage>* images,
+    ImageIdFlatSet* checkered_images,
+    WhichTree tree) {
+  DCHECK(checkered_images->empty());
+
+  auto images_to_checker = std::remove_if(
+      images->begin(), images->end(),
+      [this, tree, &checkered_images](const DrawImage& draw_image) {
+        const sk_sp<const SkImage>& image = draw_image.image();
+        DCHECK(image->isLazyGenerated());
+        if (ShouldCheckerImage(image, tree)) {
+          ScheduleImageDecodeIfNecessary(image);
+          checkered_images->insert(image->uniqueID());
+          return true;
+        }
+        return false;
+      });
+  images->erase(images_to_checker, images->end());
+}
+
+const ImageIdFlatSet& CheckerImageTracker::TakeImagesToInvalidateOnSyncTree() {
+  DCHECK_EQ(invalidated_images_on_current_sync_tree_.size(), 0u)
+      << "Sync tree can not be invalidated more than once";
+
+  invalidated_images_on_current_sync_tree_.swap(images_pending_invalidation_);
+  images_pending_invalidation_.clear();
+  return invalidated_images_on_current_sync_tree_;
+}
+
+void CheckerImageTracker::DidActivateSyncTree() {
+  for (auto image_id : invalidated_images_on_current_sync_tree_) {
+    auto it = image_id_to_decode_request_id_.find(image_id);
+    image_controller_->UnlockImageDecode(it->second);
+    image_id_to_decode_request_id_.erase(it);
+  }
+
+  invalidated_images_on_current_sync_tree_.clear();
+}
+
+void CheckerImageTracker::DidFinishImageDecode(
+    ImageId image_id,
+    ImageController::ImageDecodeRequestId request_id) {
+  TRACE_EVENT_ASYNC_END0("cc", "CheckerImageTracker::DeferImageDecode",
+                         image_id);
+
+  DCHECK_NE(pending_image_decodes_.count(image_id), 0u);
+  pending_image_decodes_.erase(image_id);
+
+  images_decoded_once_.insert(image_id);
+  images_pending_invalidation_.insert(image_id);
+  client_->NeedsInvalidationForCheckerImagedTiles();
+}
+
+bool CheckerImageTracker::ShouldCheckerImage(const sk_sp<const SkImage>& image,
+                                             WhichTree tree) const {
+  TRACE_EVENT1("cc", "CheckerImageTracker::ShouldCheckerImage", "image_id",
+               image->uniqueID());
+
+  if (!enable_checker_imaging_)
+    return false;
+
+  // If the image was invalidated on the current sync tree and the tile is
+  // for the active tree, continue checkering it on the active tree to ensure
+  // the image update is atomic for the frame.
+  if (invalidated_images_on_current_sync_tree_.count(image->uniqueID()) != 0 &&
+      tree == WhichTree::ACTIVE_TREE) {
+    return true;
+  }
+
+  // If a decode request is pending for this image, continue checkering it.
+  if (pending_image_decodes_.find(image->uniqueID()) !=
+      pending_image_decodes_.end()) {
+    return true;
+  }
+
+  // If the image is pending invalidation, continue checkering it. All tiles
+  // for these images will be invalidated on the next pending tree.
+  if (images_pending_invalidation_.find(image->uniqueID()) !=
+      images_pending_invalidation_.end()) {
+    return true;
+  }
+
+  // If the image has been decoded once before, don't checker it again.
+  if (images_decoded_once_.find(image->uniqueID()) !=
+      images_decoded_once_.end()) {
+    return false;
+  }
+
+  return SafeSizeOfImage(image.get()) >= kMinImageSizeToCheckerBytes;
+}
+
+void CheckerImageTracker::ScheduleImageDecodeIfNecessary(
+    const sk_sp<const SkImage>& image) {
+  ImageId image_id = image->uniqueID();
+
+  // If the image has already been decoded, or a decode request is pending, we
+  // don't need to schedule another decode.
+  if (images_decoded_once_.count(image_id) != 0 ||
+      pending_image_decodes_.count(image_id) != 0) {
+    return;
+  }
+
+  TRACE_EVENT_ASYNC_BEGIN0("cc", "CheckerImageTracker::DeferImageDecode",
+                           image_id);
+  DCHECK_EQ(image_id_to_decode_request_id_.count(image_id), 0U);
+
+  image_id_to_decode_request_id_[image_id] =
+      image_controller_->QueueImageDecode(
+          image, base::Bind(&CheckerImageTracker::DidFinishImageDecode,
+                            weak_factory_.GetWeakPtr(), image_id));
+  pending_image_decodes_.insert(image_id);
+}
+
+}  // namespace cc
diff --git a/cc/tiles/checker_image_tracker.h b/cc/tiles/checker_image_tracker.h
new file mode 100644
index 0000000..af0bc0e
--- /dev/null
+++ b/cc/tiles/checker_image_tracker.h
@@ -0,0 +1,100 @@
+// 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 CC_TILES_CHECKER_IMAGE_TRACKER_H_
+#define CC_TILES_CHECKER_IMAGE_TRACKER_H_
+
+#include <unordered_map>
+#include <vector>
+
+#include "cc/base/cc_export.h"
+#include "cc/playback/image_id.h"
+#include "cc/tiles/image_controller.h"
+#include "third_party/skia/include/core/SkImage.h"
+
+namespace cc {
+
+class CC_EXPORT CheckerImageTrackerClient {
+ public:
+  virtual ~CheckerImageTrackerClient() = default;
+
+  virtual void NeedsInvalidationForCheckerImagedTiles() = 0;
+};
+
+// CheckerImageTracker is used to track the set of images in a frame which are
+// decoded asynchronously, using the ImageDecodeService, from the rasterization
+// of tiles which depend on them. Once decoded, these images are stored for
+// invalidation on the next sync tree. TakeImagesToInvalidateOnSyncTree will
+// return this set and maintain a copy to keeps these images locked until the
+// sync tree is activated.
+// Note: It is illegal to call TakeImagesToInvalidateOnSyncTree for the next
+// sync tree until the previous tree is activated.
+class CC_EXPORT CheckerImageTracker {
+ public:
+  CheckerImageTracker(ImageController* image_controller,
+                      CheckerImageTrackerClient* client,
+                      bool enable_checker_imaging);
+  ~CheckerImageTracker();
+
+  // Given the |images| for a tile, filters the images which will be deferred
+  // asynchronously using the image decoded service, eliminating them from
+  // |images| adds them to the |checkered_images| set, so they can be skipped
+  // during the rasterization of this tile.
+  // The entries remaining in |images| are for images for which a cached decode
+  // from the image decode service is available, or which must be decoded before
+  // before this tile can be rasterized.
+  void FilterImagesForCheckeringForTile(std::vector<DrawImage>* images,
+                                        ImageIdFlatSet* checkered_images,
+                                        WhichTree tree);
+
+  // Returns the set of images to invalidate on the sync tree.
+  const ImageIdFlatSet& TakeImagesToInvalidateOnSyncTree();
+
+  void DidActivateSyncTree();
+
+ private:
+  void DidFinishImageDecode(ImageId image_id,
+                            ImageController::ImageDecodeRequestId request_id);
+
+  // Returns true if the decode for |image| will be deferred to the image decode
+  // service and it should be be skipped during raster.
+  bool ShouldCheckerImage(const sk_sp<const SkImage>& image,
+                          WhichTree tree) const;
+
+  void ScheduleImageDecodeIfNecessary(const sk_sp<const SkImage>& image);
+
+  ImageController* image_controller_;
+  CheckerImageTrackerClient* client_;
+  const bool enable_checker_imaging_;
+
+  // A set of images which have been decoded and are pending invalidation for
+  // raster on the checkered tiles.
+  ImageIdFlatSet images_pending_invalidation_;
+
+  // A set of images which were invalidated on the current sync tree.
+  ImageIdFlatSet invalidated_images_on_current_sync_tree_;
+
+  // A set of images which are currently pending decode from the image decode
+  // service.
+  // TODO(khushalsagar): This should be a queue that gets re-built each time we
+  // do a PrepareTiles? See crbug.com/689184.
+  ImageIdFlatSet pending_image_decodes_;
+
+  // A set of images which have been decoded at least once from the
+  // ImageDecodeService and should not be checkered again.
+  // TODO(khushalsagar): Limit the size of this set.
+  // TODO(khushalsagar): Plumb navigation changes here to reset this. See
+  // crbug.com/693228.
+  std::unordered_set<ImageId> images_decoded_once_;
+
+  // A map of image id to image decode request id for images to be unlocked.
+  std::unordered_map<ImageId, ImageController::ImageDecodeRequestId>
+      image_id_to_decode_request_id_;
+
+  base::WeakPtrFactory<CheckerImageTracker> weak_factory_;
+};
+
+}  // namespace cc
+
+#endif  // CC_TILES_CHECKER_IMAGE_TRACKER_H_
diff --git a/cc/tiles/checker_image_tracker_unittest.cc b/cc/tiles/checker_image_tracker_unittest.cc
new file mode 100644
index 0000000..60a4843
--- /dev/null
+++ b/cc/tiles/checker_image_tracker_unittest.cc
@@ -0,0 +1,296 @@
+// 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 "cc/tiles/checker_image_tracker.h"
+
+#include "base/bind.h"
+#include "base/memory/ptr_util.h"
+#include "base/run_loop.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "cc/test/skia_common.h"
+#include "cc/tiles/image_controller.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace cc {
+namespace {
+
+const int kCheckerableImageDimension = 512;
+const int kNonCheckerableImageDimension = 16;
+
+class TestImageController : public ImageController {
+ public:
+  // We can use the same thread for the image worker because all use of it in
+  // the ImageController is over-ridden here.
+  TestImageController()
+      : ImageController(base::ThreadTaskRunnerHandle::Get().get(),
+                        base::ThreadTaskRunnerHandle::Get()) {}
+
+  ~TestImageController() override { DCHECK_EQ(locked_images_.size(), 0U); }
+
+  int num_of_locked_images() const { return locked_images_.size(); }
+
+  void UnlockImageDecode(ImageDecodeRequestId id) override {
+    DCHECK_EQ(locked_images_.count(id), 1U);
+    locked_images_.erase(id);
+  }
+
+  ImageDecodeRequestId QueueImageDecode(
+      sk_sp<const SkImage> image,
+      const ImageDecodedCallback& callback) override {
+    ImageDecodeRequestId request_id = next_image_request_id_++;
+
+    // The tracker should request a decode only once.
+    EXPECT_EQ(decodes_requested_.count(image->uniqueID()), 0u);
+    decodes_requested_.insert(image->uniqueID());
+
+    locked_images_.insert(request_id);
+
+    // Post the callback asynchronously to match the behaviour in
+    // ImageController.
+    worker_task_runner_->PostTask(FROM_HERE, base::Bind(callback, request_id));
+
+    return request_id;
+  }
+
+ private:
+  ImageDecodeRequestId next_image_request_id_ = 1U;
+  std::unordered_set<ImageDecodeRequestId> locked_images_;
+  ImageIdFlatSet decodes_requested_;
+};
+
+class CheckerImageTrackerTest : public testing::Test,
+                                public CheckerImageTrackerClient {
+ public:
+  enum class ImageType { CHECKERABLE, NON_CHECKERABLE };
+
+  void SetUpTracker(bool checker_images_enabled) {
+    checker_image_tracker_ = base::MakeUnique<CheckerImageTracker>(
+        &image_controller_, this, checker_images_enabled);
+  }
+
+  void TearDown() override { checker_image_tracker_.reset(); }
+
+  DrawImage CreateImage(ImageType image_type) {
+    int dimension = image_type == ImageType::CHECKERABLE
+                        ? kCheckerableImageDimension
+                        : kNonCheckerableImageDimension;
+    sk_sp<SkImage> image =
+        CreateDiscardableImage(gfx::Size(dimension, dimension));
+    return DrawImage(image, SkIRect::MakeWH(image->width(), image->height()),
+                     kNone_SkFilterQuality, SkMatrix::I());
+  }
+
+  // CheckerImageTrackerClient implementation.
+  void NeedsInvalidationForCheckerImagedTiles() override {
+    invalidation_request_pending_ = true;
+  }
+
+ protected:
+  TestImageController image_controller_;
+  std::unique_ptr<CheckerImageTracker> checker_image_tracker_;
+
+  bool invalidation_request_pending_ = false;
+};
+
+TEST_F(CheckerImageTrackerTest, CheckerImagesDisabled) {
+  // Ensures that the tracker doesn't filter any images for checkering if it is
+  // disabled.
+  SetUpTracker(false);
+
+  std::vector<DrawImage> draw_images;
+  ImageIdFlatSet checkered_images;
+  draw_images.push_back(CreateImage(ImageType::CHECKERABLE));
+  checker_image_tracker_->FilterImagesForCheckeringForTile(
+      &draw_images, &checkered_images, WhichTree::PENDING_TREE);
+  EXPECT_EQ(draw_images.size(), 1U);
+  EXPECT_EQ(checkered_images.size(), 0U);
+  EXPECT_EQ(image_controller_.num_of_locked_images(), 0);
+}
+
+TEST_F(CheckerImageTrackerTest, UpdatesImagesAtomically) {
+  // Ensures that the tracker updates images atomically for each frame.
+  SetUpTracker(true);
+
+  DrawImage checkerable_image = CreateImage(ImageType::CHECKERABLE);
+  DrawImage non_checkerable_image = CreateImage(ImageType::NON_CHECKERABLE);
+  ImageIdFlatSet checkered_images;
+  std::vector<DrawImage> draw_images;
+
+  // First request to filter images.
+  draw_images.push_back(checkerable_image);
+  draw_images.push_back(non_checkerable_image);
+  draw_images.push_back(checkerable_image);
+  checker_image_tracker_->FilterImagesForCheckeringForTile(
+      &draw_images, &checkered_images, WhichTree::PENDING_TREE);
+
+  EXPECT_EQ(draw_images.size(), 1U);
+  EXPECT_EQ(draw_images[0].image(), non_checkerable_image.image());
+  EXPECT_EQ(checkered_images.size(), 1U);
+  EXPECT_EQ(checkered_images.count(checkerable_image.image()->uniqueID()), 1U);
+  EXPECT_EQ(image_controller_.num_of_locked_images(), 1);
+
+  // Run pending task to indicate completion of decode request to the tracker.
+  // This should send an impl-side invalidation request to the client. The
+  // images must remain locked until the sync tree to which the invalidations
+  // are added is activated.
+  base::RunLoop().RunUntilIdle();
+  EXPECT_TRUE(invalidation_request_pending_);
+  EXPECT_EQ(image_controller_.num_of_locked_images(), 1);
+
+  // Continue checkering the image until the set of images to invalidate is
+  // pulled.
+  draw_images.clear();
+  draw_images.push_back(checkerable_image);
+  checkered_images.clear();
+  checker_image_tracker_->FilterImagesForCheckeringForTile(
+      &draw_images, &checkered_images, WhichTree::PENDING_TREE);
+  EXPECT_EQ(draw_images.size(), 0U);
+  EXPECT_EQ(checkered_images.size(), 1U);
+  EXPECT_EQ(image_controller_.num_of_locked_images(), 1);
+
+  ImageIdFlatSet invalidated_images =
+      checker_image_tracker_->TakeImagesToInvalidateOnSyncTree();
+  EXPECT_EQ(invalidated_images.size(), 1U);
+  EXPECT_EQ(invalidated_images.count(checkerable_image.image()->uniqueID()),
+            1U);
+
+  // Use the same set of draw images to ensure that they are not checkered on
+  // the pending tree now.
+  draw_images.clear();
+  draw_images.push_back(checkerable_image);
+  draw_images.push_back(non_checkerable_image);
+  checkered_images.clear();
+  checker_image_tracker_->FilterImagesForCheckeringForTile(
+      &draw_images, &checkered_images, WhichTree::PENDING_TREE);
+  EXPECT_EQ(draw_images.size(), 2U);
+  EXPECT_EQ(checkered_images.size(), 0U);
+
+  // Use this set to make the same request from the active tree, we should
+  // continue checkering this image on the active tree until activation.
+  draw_images.clear();
+  draw_images.push_back(checkerable_image);
+  draw_images.push_back(non_checkerable_image);
+  checkered_images.clear();
+  checker_image_tracker_->FilterImagesForCheckeringForTile(
+      &draw_images, &checkered_images, WhichTree::ACTIVE_TREE);
+  EXPECT_EQ(draw_images.size(), 1U);
+  EXPECT_EQ(draw_images[0].image(), non_checkerable_image.image());
+  EXPECT_EQ(checkered_images.size(), 1U);
+  EXPECT_EQ(checkered_images.count(checkerable_image.image()->uniqueID()), 1U);
+
+  // Activate the sync tree. The images should be unlocked upon activation.
+  EXPECT_EQ(image_controller_.num_of_locked_images(), 1);
+  checker_image_tracker_->DidActivateSyncTree();
+}
+
+TEST_F(CheckerImageTrackerTest, NoConsecutiveCheckeringForImage) {
+  // Ensures that if an image is decoded and invalidated once, it is not
+  // checkered again in subsequent frames.
+  SetUpTracker(true);
+
+  DrawImage checkerable_image = CreateImage(ImageType::CHECKERABLE);
+  DrawImage non_checkerable_image = CreateImage(ImageType::NON_CHECKERABLE);
+  ImageIdFlatSet checkered_images;
+  std::vector<DrawImage> draw_images;
+
+  draw_images.clear();
+  draw_images.push_back(checkerable_image);
+  checkered_images.clear();
+  checker_image_tracker_->FilterImagesForCheckeringForTile(
+      &draw_images, &checkered_images, WhichTree::PENDING_TREE);
+  EXPECT_EQ(draw_images.size(), 0U);
+  EXPECT_EQ(checkered_images.size(), 1U);
+
+  // Trigger decode completion, take images to invalidate and activate the sync
+  // tree.
+  base::RunLoop().RunUntilIdle();
+  checker_image_tracker_->TakeImagesToInvalidateOnSyncTree();
+  checker_image_tracker_->DidActivateSyncTree();
+
+  // Subsequent requests for this image should not be checkered.
+  draw_images.clear();
+  draw_images.push_back(checkerable_image);
+  checkered_images.clear();
+  checker_image_tracker_->FilterImagesForCheckeringForTile(
+      &draw_images, &checkered_images, WhichTree::PENDING_TREE);
+  EXPECT_EQ(draw_images.size(), 1U);
+  EXPECT_EQ(checkered_images.size(), 0U);
+}
+
+TEST_F(CheckerImageTrackerTest,
+       TracksCheckeredImagesSeperatelyInConsecutiveFrames) {
+  // Ensures that the set of images being checkered on the pending tree, and the
+  // active tree are tracked correctly.
+  SetUpTracker(true);
+
+  DrawImage checkerable_image1 = CreateImage(ImageType::CHECKERABLE);
+  ImageIdFlatSet checkered_images;
+  std::vector<DrawImage> draw_images;
+
+  // First request to filter images on the pending and active tree.
+  draw_images.push_back(checkerable_image1);
+  checker_image_tracker_->FilterImagesForCheckeringForTile(
+      &draw_images, &checkered_images, WhichTree::PENDING_TREE);
+  EXPECT_EQ(draw_images.size(), 0U);
+  EXPECT_EQ(checkered_images.size(), 1U);
+
+  // The image is also checkered on the active tree while a decode request is
+  // pending.
+  draw_images.clear();
+  checkered_images.clear();
+  draw_images.push_back(checkerable_image1);
+  checker_image_tracker_->FilterImagesForCheckeringForTile(
+      &draw_images, &checkered_images, WhichTree::ACTIVE_TREE);
+  EXPECT_EQ(draw_images.size(), 0U);
+  EXPECT_EQ(checkered_images.size(), 1U);
+
+  // Trigger decode completion and take images to invalidate on the sync tree.
+  base::RunLoop().RunUntilIdle();
+  EXPECT_TRUE(invalidation_request_pending_);
+  ImageIdFlatSet invalidated_images =
+      checker_image_tracker_->TakeImagesToInvalidateOnSyncTree();
+  EXPECT_EQ(invalidated_images.size(), 1U);
+  EXPECT_EQ(invalidated_images.count(checkerable_image1.image()->uniqueID()),
+            1U);
+
+  // Second request to filter the same image on the pending and active tree. It
+  // should be checkered on the active tree, but not the pending tree.
+  draw_images.clear();
+  checkered_images.clear();
+  draw_images.push_back(checkerable_image1);
+  checker_image_tracker_->FilterImagesForCheckeringForTile(
+      &draw_images, &checkered_images, WhichTree::PENDING_TREE);
+  EXPECT_EQ(draw_images.size(), 1U);
+  EXPECT_EQ(checkered_images.size(), 0U);
+
+  checker_image_tracker_->FilterImagesForCheckeringForTile(
+      &draw_images, &checkered_images, WhichTree::ACTIVE_TREE);
+  EXPECT_EQ(draw_images.size(), 0U);
+  EXPECT_EQ(checkered_images.size(), 1U);
+
+  // New checkerable image on the pending tree.
+  DrawImage checkerable_image2 = CreateImage(ImageType::CHECKERABLE);
+  draw_images.clear();
+  checkered_images.clear();
+  draw_images.push_back(checkerable_image2);
+  checker_image_tracker_->FilterImagesForCheckeringForTile(
+      &draw_images, &checkered_images, WhichTree::PENDING_TREE);
+  EXPECT_EQ(draw_images.size(), 0U);
+  EXPECT_EQ(checkered_images.size(), 1U);
+
+  // Activate the sync tree. The initial image should no longer be checkered on
+  // the active tree.
+  checker_image_tracker_->DidActivateSyncTree();
+
+  draw_images.clear();
+  checkered_images.clear();
+  draw_images.push_back(checkerable_image1);
+  checker_image_tracker_->FilterImagesForCheckeringForTile(
+      &draw_images, &checkered_images, WhichTree::ACTIVE_TREE);
+  EXPECT_EQ(draw_images.size(), 1U);
+  EXPECT_EQ(checkered_images.size(), 0U);
+}
+
+}  // namespace
+}  // namespace cc
diff --git a/cc/tiles/image_controller.cc b/cc/tiles/image_controller.cc
index f0d1bb9..5de6e348 100644
--- a/cc/tiles/image_controller.cc
+++ b/cc/tiles/image_controller.cc
@@ -20,8 +20,8 @@
 ImageController::ImageController(
     base::SequencedTaskRunner* origin_task_runner,
     scoped_refptr<base::SequencedTaskRunner> worker_task_runner)
-    : origin_task_runner_(origin_task_runner),
-      worker_task_runner_(std::move(worker_task_runner)),
+    : worker_task_runner_(std::move(worker_task_runner)),
+      origin_task_runner_(origin_task_runner),
       weak_ptr_factory_(this) {}
 
 ImageController::~ImageController() {
diff --git a/cc/tiles/image_controller.h b/cc/tiles/image_controller.h
index 7fb45b8..ecfa7f2 100644
--- a/cc/tiles/image_controller.h
+++ b/cc/tiles/image_controller.h
@@ -52,6 +52,9 @@
       sk_sp<const SkImage> image,
       const ImageDecodedCallback& callback);
 
+ protected:
+  scoped_refptr<base::SequencedTaskRunner> worker_task_runner_;
+
  private:
   struct ImageDecodeRequest {
     ImageDecodeRequest();
@@ -88,7 +91,6 @@
   std::unordered_map<ImageDecodeRequestId, DrawImage> requested_locked_images_;
 
   base::SequencedTaskRunner* origin_task_runner_ = nullptr;
-  scoped_refptr<base::SequencedTaskRunner> worker_task_runner_;
 
   // The variables defined below this lock (aside from weak_ptr_factory_) can
   // only be accessed when the lock is acquired.
diff --git a/cc/tiles/picture_layer_tiling.h b/cc/tiles/picture_layer_tiling.h
index 0c9b57a..e9c192c 100644
--- a/cc/tiles/picture_layer_tiling.h
+++ b/cc/tiles/picture_layer_tiling.h
@@ -135,6 +135,8 @@
     all_tiles_done_ = all_tiles_done;
   }
 
+  WhichTree tree() const { return tree_; }
+
   void VerifyNoTileNeedsRaster() const {
 #if DCHECK_IS_ON()
     for (const auto& tile_pair : tiles_) {
diff --git a/cc/tiles/picture_layer_tiling_set.cc b/cc/tiles/picture_layer_tiling_set.cc
index 82cf8e0..4817cbd 100644
--- a/cc/tiles/picture_layer_tiling_set.cc
+++ b/cc/tiles/picture_layer_tiling_set.cc
@@ -195,6 +195,15 @@
   }
 }
 
+void PictureLayerTilingSet::UpdateTilingsForImplSideInvalidation(
+    const Region& layer_invalidation) {
+  for (const auto& tiling : tilings_) {
+    tiling->Invalidate(layer_invalidation);
+    tiling->CreateMissingTilesInLiveTilesRect();
+  }
+  state_since_last_tile_priority_update_.invalidated = true;
+}
+
 void PictureLayerTilingSet::VerifyTilings(
     const PictureLayerTilingSet* pending_twin_set) const {
 #if DCHECK_IS_ON()
diff --git a/cc/tiles/picture_layer_tiling_set.h b/cc/tiles/picture_layer_tiling_set.h
index 211ae54..608c43c2 100644
--- a/cc/tiles/picture_layer_tiling_set.h
+++ b/cc/tiles/picture_layer_tiling_set.h
@@ -78,6 +78,8 @@
       scoped_refptr<RasterSource> raster_source,
       const Region& layer_invalidation);
 
+  void UpdateTilingsForImplSideInvalidation(const Region& layer_invalidation);
+
   PictureLayerTiling* AddTiling(float contents_scale,
                                 scoped_refptr<RasterSource> raster_source);
   size_t num_tilings() const { return tilings_.size(); }
diff --git a/cc/tiles/tile_manager.cc b/cc/tiles/tile_manager.cc
index 710bf36d..e43fce7 100644
--- a/cc/tiles/tile_manager.cc
+++ b/cc/tiles/tile_manager.cc
@@ -347,20 +347,22 @@
     base::SequencedTaskRunner* origin_task_runner,
     scoped_refptr<base::SequencedTaskRunner> image_worker_task_runner,
     size_t scheduled_raster_task_limit,
-    bool use_partial_raster,
-    bool check_tile_priority_inversion)
+    const TileManagerSettings& tile_manager_settings)
     : client_(client),
       task_runner_(origin_task_runner),
       resource_pool_(nullptr),
       tile_task_manager_(nullptr),
       scheduled_raster_task_limit_(scheduled_raster_task_limit),
-      use_partial_raster_(use_partial_raster),
+      tile_manager_settings_(tile_manager_settings),
       use_gpu_rasterization_(false),
       all_tiles_that_need_to_be_rasterized_are_scheduled_(true),
       did_check_for_completed_tasks_since_last_schedule_tasks_(true),
       did_oom_on_last_assign_(false),
       image_controller_(origin_task_runner,
                         std::move(image_worker_task_runner)),
+      checker_image_tracker_(&image_controller_,
+                             this,
+                             tile_manager_settings_.enable_checker_imaging),
       more_tiles_need_prepare_check_notifier_(
           task_runner_,
           base::Bind(&TileManager::CheckIfMoreTilesNeedToBePrepared,
@@ -371,7 +373,6 @@
       has_scheduled_tile_tasks_(false),
       prepare_tiles_count_(0u),
       next_tile_id_(0u),
-      check_tile_priority_inversion_(check_tile_priority_inversion),
       task_set_finished_weak_ptr_factory_(this),
       ready_to_draw_callback_weak_ptr_factory_(this) {}
 
@@ -738,7 +739,7 @@
   //    all_tiles_that_need_to_be_rasterized_are_scheduled_ is true)
   //  - Memory limit policy allows for any tiles to be scheduled at all (ie it's
   //    not ALLOW_NOTHING).
-  if (check_tile_priority_inversion_ &&
+  if (tile_manager_settings_.check_tile_priority_inversion &&
       all_tiles_that_need_to_be_rasterized_are_scheduled_ &&
       global_state_.memory_limit_policy != ALLOW_NOTHING) {
     TilePriority::PriorityBin highest_bin_found = TilePriority::NOW;
@@ -895,6 +896,8 @@
   for (const PrioritizedTile& prioritized_tile : tiles_to_process_for_images) {
     Tile* tile = prioritized_tile.tile();
 
+    // TODO(khushalsagar): Send these images to the ImageDecodeService, through
+    // the CheckerImageTracker as well. See crbug.com/691087.
     std::vector<DrawImage> images;
     prioritized_tile.raster_source()->GetDiscardableImagesInRect(
         tile->enclosing_layer_rect(), tile->contents_scale(), &images);
@@ -997,14 +1000,20 @@
   // Create and queue all image decode tasks that this tile depends on.
   TileTask::Vector decode_tasks;
   std::vector<DrawImage>& images = scheduled_draw_images_[tile->id()];
+  ImageIdFlatSet images_to_skip;
   images.clear();
   if (!playback_settings.skip_images) {
     prioritized_tile.raster_source()->GetDiscardableImagesInRect(
         tile->enclosing_layer_rect(), tile->contents_scale(), &images);
+    checker_image_tracker_.FilterImagesForCheckeringForTile(
+        &images, &images_to_skip, prioritized_tile.tile()->tiling()->tree());
   }
 
-  // We can skip the image hijack canvas if we have no images.
-  playback_settings.use_image_hijack_canvas = !images.empty();
+  // We can skip the image hijack canvas if we have no images, or no images to
+  // skip during raster.
+  playback_settings.use_image_hijack_canvas =
+      !images.empty() || !images_to_skip.empty();
+  playback_settings.images_to_skip = std::move(images_to_skip);
 
   // Get the tasks for the required images.
   ImageDecodeCache::TracingInfo tracing_info(
@@ -1271,6 +1280,18 @@
   }
 }
 
+const ImageIdFlatSet& TileManager::TakeImagesToInvalidateOnSyncTree() {
+  return checker_image_tracker_.TakeImagesToInvalidateOnSyncTree();
+}
+
+void TileManager::DidActivateSyncTree() {
+  checker_image_tracker_.DidActivateSyncTree();
+}
+
+void TileManager::NeedsInvalidationForCheckerImagedTiles() {
+  client_->RequestImplSideInvalidation();
+}
+
 ResourceFormat TileManager::DetermineResourceFormat(const Tile* tile) const {
   return raster_buffer_provider_->GetResourceFormat(!tile->is_opaque());
 }
@@ -1293,7 +1314,7 @@
 }
 
 bool TileManager::UsePartialRaster() const {
-  return use_partial_raster_ &&
+  return tile_manager_settings_.use_partial_raster &&
          raster_buffer_provider_->CanPartialRasterIntoProvidedResource();
 }
 
diff --git a/cc/tiles/tile_manager.h b/cc/tiles/tile_manager.h
index 90041452..e8b561c1 100644
--- a/cc/tiles/tile_manager.h
+++ b/cc/tiles/tile_manager.h
@@ -21,12 +21,14 @@
 #include "cc/raster/raster_buffer_provider.h"
 #include "cc/resources/memory_history.h"
 #include "cc/resources/resource_pool.h"
+#include "cc/tiles/checker_image_tracker.h"
 #include "cc/tiles/decoded_image_tracker.h"
 #include "cc/tiles/eviction_tile_priority_queue.h"
 #include "cc/tiles/image_controller.h"
 #include "cc/tiles/raster_tile_priority_queue.h"
 #include "cc/tiles/tile.h"
 #include "cc/tiles/tile_draw_info.h"
+#include "cc/tiles/tile_manager_settings.h"
 #include "cc/tiles/tile_task_manager.h"
 
 namespace base {
@@ -79,6 +81,11 @@
   // Requests the color space into which tiles should be rasterized.
   virtual gfx::ColorSpace GetTileColorSpace() const = 0;
 
+  // Requests that a pending tree be scheduled to invalidate content on the
+  // pending on active tree. This is currently used when tiles that are
+  // rasterized with missing images need to be invalidated.
+  virtual void RequestImplSideInvalidation() = 0;
+
  protected:
   virtual ~TileManagerClient() {}
 };
@@ -96,15 +103,14 @@
 // should no longer have any memory assigned to them. Tile objects are "owned"
 // by layers; they automatically register with the manager when they are
 // created, and unregister from the manager when they are deleted.
-class CC_EXPORT TileManager {
+class CC_EXPORT TileManager : CheckerImageTrackerClient {
  public:
   TileManager(TileManagerClient* client,
               base::SequencedTaskRunner* origin_task_runner,
               scoped_refptr<base::SequencedTaskRunner> image_worker_task_runner,
               size_t scheduled_raster_task_limit,
-              bool use_partial_raster,
-              bool check_tile_priority_inversion);
-  virtual ~TileManager();
+              const TileManagerSettings& tile_manager_settings);
+  ~TileManager() override;
 
   // Assigns tile memory and schedules work to prepare tiles for drawing.
   // - Runs client_->NotifyReadyToActivate() when all tiles required for
@@ -144,6 +150,9 @@
   bool IsReadyToActivate() const;
   bool IsReadyToDraw() const;
 
+  const ImageIdFlatSet& TakeImagesToInvalidateOnSyncTree();
+  void DidActivateSyncTree();
+
   std::unique_ptr<base::trace_event::ConvertableToTraceFormat>
   BasicStateAsValue() const;
   void BasicStateAsValueInto(base::trace_event::TracedValue* dict) const;
@@ -217,6 +226,9 @@
 
   void SetDecodedImageTracker(DecodedImageTracker* decoded_image_tracker);
 
+  // CheckerImageTrackerClient implementation.
+  void NeedsInvalidationForCheckerImagedTiles() override;
+
  protected:
   friend class Tile;
   // Must be called by tile during destruction.
@@ -316,7 +328,8 @@
   RasterBufferProvider* raster_buffer_provider_;
   GlobalStateThatImpactsTilePriority global_state_;
   size_t scheduled_raster_task_limit_;
-  const bool use_partial_raster_;
+
+  const TileManagerSettings tile_manager_settings_;
   bool use_gpu_rasterization_;
 
   std::unordered_map<Tile::Id, Tile*> tiles_;
@@ -328,6 +341,7 @@
   bool did_oom_on_last_assign_;
 
   ImageController image_controller_;
+  CheckerImageTracker checker_image_tracker_;
 
   RasterTaskCompletionStats flush_stats_;
 
@@ -353,7 +367,6 @@
 
   std::unordered_map<Tile::Id, std::vector<DrawImage>> scheduled_draw_images_;
   std::vector<scoped_refptr<TileTask>> locked_image_tasks_;
-  const bool check_tile_priority_inversion_;
 
   // We need two WeakPtrFactory objects as the invalidation pattern of each is
   // different. The |task_set_finished_weak_ptr_factory_| is invalidated any
diff --git a/cc/tiles/tile_manager_settings.h b/cc/tiles/tile_manager_settings.h
new file mode 100644
index 0000000..2b2051e
--- /dev/null
+++ b/cc/tiles/tile_manager_settings.h
@@ -0,0 +1,20 @@
+// 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 CC_TILES_TILE_MANAGER_SETTINGS_H_
+#define CC_TILES_TILE_MANAGER_SETTINGS_H_
+
+#include "cc/base/cc_export.h"
+
+namespace cc {
+
+struct CC_EXPORT TileManagerSettings {
+  bool use_partial_raster = false;
+  bool check_tile_priority_inversion = false;
+  bool enable_checker_imaging = false;
+};
+
+}  // namespace cc
+
+#endif  // CC_TILES_TILE_MANAGER_SETTINGS_H_
diff --git a/cc/tiles/tile_manager_unittest.cc b/cc/tiles/tile_manager_unittest.cc
index 70c496ef..1e2203f0 100644
--- a/cc/tiles/tile_manager_unittest.cc
+++ b/cc/tiles/tile_manager_unittest.cc
@@ -9,6 +9,7 @@
 #include "base/callback.h"
 #include "base/memory/ptr_util.h"
 #include "base/run_loop.h"
+#include "base/test/test_simple_task_runner.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "cc/playback/raster_source.h"
 #include "cc/playback/recording_source.h"
@@ -38,6 +39,7 @@
 #include "cc/trees/layer_tree_impl.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/skia/include/core/SkImageGenerator.h"
 #include "third_party/skia/include/core/SkRefCnt.h"
 #include "third_party/skia/include/core/SkSurface.h"
 
@@ -49,6 +51,35 @@
 namespace cc {
 namespace {
 
+// A version of simple task runner that lets the user control if all tasks
+// posted should run synchronously.
+class SynchronousSimpleTaskRunner : public base::TestSimpleTaskRunner {
+ public:
+  bool PostDelayedTask(const tracked_objects::Location& from_here,
+                       const base::Closure& task,
+                       base::TimeDelta delay) override {
+    TestSimpleTaskRunner::PostDelayedTask(from_here, task, delay);
+    if (run_tasks_synchronously_)
+      RunUntilIdle();
+    return true;
+  }
+
+  bool PostNonNestableDelayedTask(const tracked_objects::Location& from_here,
+                                  const base::Closure& task,
+                                  base::TimeDelta delay) override {
+    return PostDelayedTask(from_here, task, delay);
+  }
+
+  void set_run_tasks_synchronously(bool run_tasks_synchronously) {
+    run_tasks_synchronously_ = run_tasks_synchronously;
+  }
+
+ protected:
+  ~SynchronousSimpleTaskRunner() override = default;
+
+  bool run_tasks_synchronously_ = false;
+};
+
 class TileManagerTilePriorityQueueTest : public TestLayerTreeHostBase {
  public:
   LayerTreeSettings CreateSettings() override {
@@ -2263,5 +2294,94 @@
   EXPECT_TRUE(host_impl()->tile_manager()->IsReadyToActivate());
 }
 
+class CheckerImagingTileManagerTest : public TestLayerTreeHostBase {
+ public:
+  class MockImageGenerator : public SkImageGenerator {
+   public:
+    explicit MockImageGenerator(const gfx::Size& size)
+        : SkImageGenerator(
+              SkImageInfo::MakeN32Premul(size.width(), size.height())) {}
+
+   protected:
+    MOCK_METHOD5(onGetPixels,
+                 bool(const SkImageInfo&, void*, size_t, SkPMColor[], int*));
+  };
+
+  void TearDown() override {
+    // Allow all tasks on the image worker to run now. Any scheduled decodes
+    // will be aborted.
+    image_worker_task_runner()->set_run_tasks_synchronously(true);
+  }
+
+  LayerTreeSettings CreateSettings() override {
+    LayerTreeSettings settings;
+    settings.enable_checker_imaging = true;
+    settings.renderer_settings.buffer_to_texture_target_map =
+        DefaultBufferToTextureTargetMapForTesting();
+    return settings;
+  }
+
+  std::unique_ptr<FakeLayerTreeHostImpl> CreateHostImpl(
+      const LayerTreeSettings& settings,
+      TaskRunnerProvider* task_runner_provider,
+      TaskGraphRunner* task_graph_runner) override {
+    task_runner_ = make_scoped_refptr(new SynchronousSimpleTaskRunner);
+    return base::MakeUnique<FakeLayerTreeHostImpl>(
+        settings, task_runner_provider, task_graph_runner, task_runner_);
+  }
+
+  std::unique_ptr<TaskGraphRunner> CreateTaskGraphRunner() override {
+    return base::MakeUnique<SynchronousTaskGraphRunner>();
+  }
+
+  SynchronousSimpleTaskRunner* image_worker_task_runner() const {
+    return task_runner_.get();
+  }
+
+ private:
+  scoped_refptr<SynchronousSimpleTaskRunner> task_runner_;
+};
+
+TEST_F(CheckerImagingTileManagerTest,
+       NoImageDecodeDependencyForCheckeredTiles) {
+  const gfx::Size layer_bounds(512, 512);
+  SetupDefaultTrees(layer_bounds);
+
+  std::unique_ptr<FakeRecordingSource> recording_source =
+      FakeRecordingSource::CreateFilledRecordingSource(layer_bounds);
+  recording_source->SetGenerateDiscardableImagesMetadata(true);
+
+  sk_sp<SkImage> image = SkImage::MakeFromGenerator(
+      new testing::StrictMock<MockImageGenerator>(gfx::Size(512, 512)));
+  recording_source->add_draw_image(image, gfx::Point(0, 0));
+
+  recording_source->Rerecord();
+  scoped_refptr<RasterSource> raster_source =
+      RasterSource::CreateFromRecordingSource(recording_source.get(), false);
+
+  std::unique_ptr<PictureLayerImpl> layer_impl = PictureLayerImpl::Create(
+      host_impl()->active_tree(), 1, Layer::LayerMaskType::NOT_MASK);
+  layer_impl->set_is_drawn_render_surface_layer_list_member(true);
+  PictureLayerTilingSet* tiling_set = layer_impl->picture_layer_tiling_set();
+
+  PictureLayerTiling* tiling = tiling_set->AddTiling(1.0f, raster_source);
+  tiling->set_resolution(HIGH_RESOLUTION);
+  tiling->CreateAllTilesForTesting();
+  tiling->SetTilePriorityRectsForTesting(
+      gfx::Rect(layer_bounds),   // Visible rect.
+      gfx::Rect(layer_bounds),   // Skewport rect.
+      gfx::Rect(layer_bounds),   // Soon rect.
+      gfx::Rect(layer_bounds));  // Eventually rect.
+
+  // PrepareTiles and synchronously run all tasks added to the TaskGraph. Since
+  // we are using a strict mock for the SkImageGenerator, if the decode runs as
+  // a part of raster tasks, the test should fail.
+  host_impl()->tile_manager()->PrepareTiles(host_impl()->global_tile_state());
+  EXPECT_TRUE(host_impl()->tile_manager()->HasScheduledTileTasksForTesting());
+  static_cast<SynchronousTaskGraphRunner*>(task_graph_runner())->RunUntilIdle();
+  base::RunLoop().RunUntilIdle();
+  EXPECT_FALSE(host_impl()->tile_manager()->HasScheduledTileTasksForTesting());
+}
+
 }  // namespace
 }  // namespace cc
diff --git a/cc/trees/layer_tree_host_impl.cc b/cc/trees/layer_tree_host_impl.cc
index 27aae69..75194f6 100644
--- a/cc/trees/layer_tree_host_impl.cc
+++ b/cc/trees/layer_tree_host_impl.cc
@@ -236,8 +236,7 @@
                     is_synchronous_single_threaded_
                         ? std::numeric_limits<size_t>::max()
                         : settings.scheduled_raster_task_limit,
-                    settings.use_partial_raster,
-                    settings.check_tile_priority_inversion),
+                    settings.ToTileManagerSettings()),
       pinch_gesture_active_(false),
       pinch_gesture_end_should_clear_scrolling_layer_(false),
       fps_counter_(
@@ -353,6 +352,14 @@
 void LayerTreeHostImpl::CommitComplete() {
   TRACE_EVENT0("cc", "LayerTreeHostImpl::CommitComplete");
 
+  UpdateSyncTreeAfterCommitOrImplSideInvalidation();
+  micro_benchmark_controller_.DidCompleteCommit();
+}
+
+void LayerTreeHostImpl::UpdateSyncTreeAfterCommitOrImplSideInvalidation() {
+  sync_tree()->InvalidateRegionForImages(
+      tile_manager_.TakeImagesToInvalidateOnSyncTree());
+
   if (CommitToActiveTree()) {
     // We have to activate animations here or "IsActive()" is true on the layers
     // but the animations aren't activated yet so they get ignored by
@@ -394,8 +401,6 @@
     if (CommitToActiveTree())
       NotifyReadyToDraw();
   }
-
-  micro_benchmark_controller_.DidCompleteCommit();
 }
 
 bool LayerTreeHostImpl::CanDraw() const {
@@ -1055,6 +1060,14 @@
   viewport_damage_rect_.Union(damage_rect);
 }
 
+void LayerTreeHostImpl::InvalidateContentOnImplSide() {
+  DCHECK(!pending_tree_);
+
+  if (!CommitToActiveTree())
+    CreatePendingTree();
+  UpdateSyncTreeAfterCommitOrImplSideInvalidation();
+}
+
 DrawResult LayerTreeHostImpl::PrepareToDraw(FrameData* frame) {
   TRACE_EVENT1("cc", "LayerTreeHostImpl::PrepareToDraw", "SourceFrameNumber",
                active_tree_->source_frame_number());
@@ -1312,6 +1325,10 @@
   return sync_tree()->device_color_space();
 }
 
+void LayerTreeHostImpl::RequestImplSideInvalidation() {
+  client_->NeedsImplSideInvalidation();
+}
+
 void LayerTreeHostImpl::NotifyReadyToActivate() {
   client_->NotifyReadyToActivate();
 }
@@ -2037,6 +2054,7 @@
   if (!active_tree_->picture_layers().empty())
     DidModifyTilePriorities();
 
+  tile_manager_.DidActivateSyncTree();
   client_->OnCanDrawStateChanged(CanDraw());
   client_->DidActivateSyncTree();
   if (!tree_activation_callback_.is_null())
diff --git a/cc/trees/layer_tree_host_impl.h b/cc/trees/layer_tree_host_impl.h
index 4b6e88c..ca7a96a1 100644
--- a/cc/trees/layer_tree_host_impl.h
+++ b/cc/trees/layer_tree_host_impl.h
@@ -121,6 +121,8 @@
   virtual void OnDrawForCompositorFrameSink(
       bool resourceless_software_draw) = 0;
 
+  virtual void NeedsImplSideInvalidation() = 0;
+
  protected:
   virtual ~LayerTreeHostImplClient() {}
 };
@@ -249,6 +251,10 @@
   void SetFullViewportDamage();
   void SetViewportDamage(const gfx::Rect& damage_rect);
 
+  // Analogous to a commit, this function is used to create a sync tree and
+  // add impl-side invalidations to it.
+  void InvalidateContentOnImplSide();
+
   void SetTreeLayerFilterMutated(ElementId element_id,
                                  LayerTreeImpl* tree,
                                  const FilterOperations& filters);
@@ -343,6 +349,7 @@
       TreePriority tree_priority) override;
   void SetIsLikelyToRequireADraw(bool is_likely_to_require_a_draw) override;
   gfx::ColorSpace GetTileColorSpace() const override;
+  void RequestImplSideInvalidation() override;
 
   // ScrollbarAnimationControllerClient implementation.
   void PostDelayedScrollbarAnimationTask(const base::Closure& task,
@@ -629,6 +636,11 @@
 
   void AnimateInternal(bool active_tree);
 
+  // The function is called to update state on the sync tree after a commit
+  // finishes or after the sync tree was created to invalidate content on the
+  // impl thread.
+  void UpdateSyncTreeAfterCommitOrImplSideInvalidation();
+
   // Returns true if status changed.
   bool UpdateGpuRasterizationStatus();
   void UpdateTreeResourcesForGpuRasterizationIfNeeded();
diff --git a/cc/trees/layer_tree_host_impl_unittest.cc b/cc/trees/layer_tree_host_impl_unittest.cc
index c1f61444..ca412b7d 100644
--- a/cc/trees/layer_tree_host_impl_unittest.cc
+++ b/cc/trees/layer_tree_host_impl_unittest.cc
@@ -14,6 +14,7 @@
 #include "base/command_line.h"
 #include "base/location.h"
 #include "base/memory/ptr_util.h"
+#include "base/run_loop.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "cc/animation/animation_host.h"
 #include "cc/animation/animation_id_provider.h"
@@ -52,10 +53,12 @@
 #include "cc/test/fake_output_surface.h"
 #include "cc/test/fake_picture_layer_impl.h"
 #include "cc/test/fake_raster_source.h"
+#include "cc/test/fake_recording_source.h"
 #include "cc/test/fake_video_frame_provider.h"
 #include "cc/test/geometry_test_utils.h"
 #include "cc/test/layer_test_common.h"
 #include "cc/test/layer_tree_test.h"
+#include "cc/test/skia_common.h"
 #include "cc/test/test_compositor_frame_sink.h"
 #include "cc/test/test_task_graph_runner.h"
 #include "cc/test/test_web_graphics_context_3d.h"
@@ -102,7 +105,8 @@
         did_request_next_frame_(false),
         did_request_prepare_tiles_(false),
         did_complete_page_scale_animation_(false),
-        reduce_memory_result_(true) {
+        reduce_memory_result_(true),
+        did_request_impl_side_invalidation_(false) {
     media::InitializeMediaLibrary();
   }
 
@@ -170,6 +174,9 @@
     host_impl_->DidDrawAllLayers(*frame);
     last_on_draw_frame_ = std::move(frame);
   }
+  void NeedsImplSideInvalidation() override {
+    did_request_impl_side_invalidation_ = true;
+  }
 
   void set_reduce_memory_result(bool reduce_memory_result) {
     reduce_memory_result_ = reduce_memory_result;
@@ -192,10 +199,13 @@
       TaskRunnerProvider* task_runner_provider) {
     if (host_impl_)
       host_impl_->ReleaseCompositorFrameSink();
+    host_impl_.reset();
+    InitializeImageWorker(settings);
     host_impl_ = LayerTreeHostImpl::Create(
         settings, this, task_runner_provider, &stats_instrumentation_,
         &task_graph_runner_,
-        AnimationHost::CreateForTesting(ThreadInstance::IMPL), 0, nullptr);
+        AnimationHost::CreateForTesting(ThreadInstance::IMPL), 0,
+        image_worker_ ? image_worker_->task_runner() : nullptr);
     compositor_frame_sink_ = std::move(compositor_frame_sink);
     host_impl_->SetVisible(true);
     bool init = host_impl_->InitializeRenderer(compositor_frame_sink_.get());
@@ -493,6 +503,15 @@
     host_impl_->DidFinishImplFrame();
   }
 
+  void InitializeImageWorker(const LayerTreeSettings& settings) {
+    if (settings.enable_checker_imaging) {
+      image_worker_ = base::MakeUnique<base::Thread>("ImageWorker");
+      ASSERT_TRUE(image_worker_->Start());
+    } else {
+      image_worker_.reset();
+    }
+  }
+
   FakeImplTaskRunnerProvider task_runner_provider_;
   DebugScopedSetMainThreadBlocked always_main_thread_blocked_;
 
@@ -508,11 +527,13 @@
   bool did_request_prepare_tiles_;
   bool did_complete_page_scale_animation_;
   bool reduce_memory_result_;
+  bool did_request_impl_side_invalidation_;
   base::Closure animation_task_;
   base::TimeDelta requested_animation_delay_;
   std::unique_ptr<LayerTreeHostImpl::FrameData> last_on_draw_frame_;
   RenderPassList last_on_draw_render_passes_;
   scoped_refptr<AnimationTimeline> timeline_;
+  std::unique_ptr<base::Thread> image_worker_;
 };
 
 // A test fixture for new animation timelines tests.
@@ -11744,5 +11765,81 @@
   SetupMouseMoveAtTestScrollbarStates(false);
 }
 
+TEST_F(LayerTreeHostImplTest, CheckerImagingTileInvalidation) {
+  LayerTreeSettings settings = DefaultSettings();
+  settings.enable_checker_imaging = true;
+  settings.default_tile_size = gfx::Size(256, 256);
+  settings.max_untiled_layer_size = gfx::Size(256, 256);
+  CreateHostImpl(settings, CreateCompositorFrameSink());
+  gfx::Size layer_size = gfx::Size(750, 750);
+
+  std::unique_ptr<FakeRecordingSource> recording_source =
+      FakeRecordingSource::CreateFilledRecordingSource(layer_size);
+  recording_source->SetGenerateDiscardableImagesMetadata(true);
+  sk_sp<SkImage> checkerable_image =
+      CreateDiscardableImage(gfx::Size(500, 500));
+  recording_source->add_draw_image(checkerable_image, gfx::Point(0, 0));
+
+  SkColor non_solid_color = SkColorSetARGB(128, 45, 56, 67);
+  PaintFlags non_solid_flags;
+  non_solid_flags.setColor(non_solid_color);
+  recording_source->add_draw_rect_with_flags(gfx::Rect(510, 0, 200, 600),
+                                             non_solid_flags);
+  recording_source->add_draw_rect_with_flags(gfx::Rect(0, 510, 200, 400),
+                                             non_solid_flags);
+  recording_source->Rerecord();
+  scoped_refptr<FakeRasterSource> raster_source =
+      FakeRasterSource::CreateFromRecordingSource(recording_source.get(),
+                                                  false);
+
+  // Create the pending tree.
+  host_impl_->BeginCommit();
+  LayerTreeImpl* pending_tree = host_impl_->pending_tree();
+  host_impl_->SetViewportSize(layer_size);
+  pending_tree->SetRootLayerForTesting(
+      FakePictureLayerImpl::CreateWithRasterSource(pending_tree, 1,
+                                                   raster_source));
+  FakePictureLayerImpl* root =
+      static_cast<FakePictureLayerImpl*>(*pending_tree->begin());
+  root->SetBounds(layer_size);
+  root->SetDrawsContent(true);
+  pending_tree->BuildPropertyTreesForTesting();
+
+  // CompleteCommit which should perform a PrepareTiles, adding tilings for the
+  // root layer, each one having a raster task.
+  host_impl_->CommitComplete();
+  EXPECT_EQ(root->num_tilings(), 1U);
+  const PictureLayerTiling* tiling = root->tilings()->tiling_at(0);
+  EXPECT_EQ(tiling->AllTilesForTesting().size(), 9U);
+  for (auto* tile : tiling->AllTilesForTesting())
+    EXPECT_TRUE(tile->HasRasterTask());
+
+  // Activate the pending tree and ensure that all tiles are rasterized.
+  while (!did_notify_ready_to_activate_)
+    base::RunLoop().RunUntilIdle();
+  for (auto* tile : tiling->AllTilesForTesting())
+    EXPECT_FALSE(tile->HasRasterTask());
+
+  // PrepareTiles should have scheduled a decode with the ImageDecodeService,
+  // ensure that it requests an impl-side invalidation.
+  while (!did_request_impl_side_invalidation_)
+    base::RunLoop().RunUntilIdle();
+
+  // Invalidate content on impl-side and ensure that the correct tiles are
+  // invalidated on the pending tree.
+  host_impl_->InvalidateContentOnImplSide();
+  pending_tree = host_impl_->pending_tree();
+  root = static_cast<FakePictureLayerImpl*>(*pending_tree->begin());
+  for (auto* tile : root->tilings()->tiling_at(0)->AllTilesForTesting()) {
+    if (tile->tiling_i_index() < 2 && tile->tiling_j_index() < 2)
+      EXPECT_TRUE(tile->HasRasterTask());
+    else
+      EXPECT_FALSE(tile->HasRasterTask());
+  }
+  Region expected_invalidation(
+      raster_source->GetRectForImage(checkerable_image->uniqueID()));
+  EXPECT_EQ(expected_invalidation, *(root->GetPendingInvalidation()));
+}
+
 }  // namespace
 }  // namespace cc
diff --git a/cc/trees/layer_tree_impl.cc b/cc/trees/layer_tree_impl.cc
index a231d6f..2a05f4f 100644
--- a/cc/trees/layer_tree_impl.cc
+++ b/cc/trees/layer_tree_impl.cc
@@ -316,6 +316,17 @@
   }
 }
 
+void LayerTreeImpl::InvalidateRegionForImages(
+    const ImageIdFlatSet& images_to_invalidate) {
+  DCHECK(IsSyncTree());
+
+  if (images_to_invalidate.empty())
+    return;
+
+  for (auto* picture_layer : picture_layers_)
+    picture_layer->InvalidateRegionForImages(images_to_invalidate);
+}
+
 bool LayerTreeImpl::IsRootLayer(const LayerImpl* layer) const {
   return layer_list_.empty() ? false : layer_list_[0] == layer;
 }
diff --git a/cc/trees/layer_tree_impl.h b/cc/trees/layer_tree_impl.h
index dd29dfbf..a12b6b56 100644
--- a/cc/trees/layer_tree_impl.h
+++ b/cc/trees/layer_tree_impl.h
@@ -454,6 +454,8 @@
 
   void BuildLayerListForTesting();
 
+  void InvalidateRegionForImages(const ImageIdFlatSet& images_to_invalidate);
+
  protected:
   float ClampPageScaleFactorToLimits(float page_scale_factor) const;
   void PushPageScaleFactorAndLimits(const float* page_scale_factor,
diff --git a/cc/trees/layer_tree_settings.cc b/cc/trees/layer_tree_settings.cc
index 166d79c..6890bbb 100644
--- a/cc/trees/layer_tree_settings.cc
+++ b/cc/trees/layer_tree_settings.cc
@@ -95,4 +95,13 @@
   return scheduler_settings;
 }
 
+TileManagerSettings LayerTreeSettings::ToTileManagerSettings() const {
+  TileManagerSettings tile_manager_settings;
+  tile_manager_settings.use_partial_raster = use_partial_raster;
+  tile_manager_settings.check_tile_priority_inversion =
+      check_tile_priority_inversion;
+  tile_manager_settings.enable_checker_imaging = enable_checker_imaging;
+  return tile_manager_settings;
+}
+
 }  // namespace cc
diff --git a/cc/trees/layer_tree_settings.h b/cc/trees/layer_tree_settings.h
index d414879..cd41f948 100644
--- a/cc/trees/layer_tree_settings.h
+++ b/cc/trees/layer_tree_settings.h
@@ -15,6 +15,7 @@
 #include "cc/output/managed_memory_policy.h"
 #include "cc/output/renderer_settings.h"
 #include "cc/scheduler/scheduler_settings.h"
+#include "cc/tiles/tile_manager_settings.h"
 #include "third_party/skia/include/core/SkColor.h"
 #include "ui/gfx/geometry/size.h"
 
@@ -29,6 +30,7 @@
   bool operator==(const LayerTreeSettings& other) const;
 
   SchedulerSettings ToSchedulerSettings() const;
+  TileManagerSettings ToTileManagerSettings() const;
 
   RendererSettings renderer_settings;
   bool single_thread_proxy_scheduler = true;
@@ -95,6 +97,11 @@
   // tiles come before lower priority tiles.
   bool check_tile_priority_inversion = false;
 
+  // If set to true, the compositor may selectively defer image decodes to the
+  // Image Decode Service and raster tiles without images until the decode is
+  // ready.
+  bool enable_checker_imaging = false;
+
   LayerTreeDebugState initial_debug_state;
 };
 
diff --git a/cc/trees/proxy_impl.cc b/cc/trees/proxy_impl.cc
index 0a8620e..34b85e0 100644
--- a/cc/trees/proxy_impl.cc
+++ b/cc/trees/proxy_impl.cc
@@ -432,6 +432,13 @@
   scheduler_->OnDrawForCompositorFrameSink(resourceless_software_draw);
 }
 
+void ProxyImpl::NeedsImplSideInvalidation() {
+  DCHECK(IsImplThread());
+  // TODO(khushalsagar): Plumb this to the scheduler when
+  // https://codereview.chromium.org/2659123004/ lands. See crbug.com/686267.
+  NOTIMPLEMENTED();
+}
+
 void ProxyImpl::WillBeginImplFrame(const BeginFrameArgs& args) {
   DCHECK(IsImplThread());
   layer_tree_host_impl_->WillBeginImplFrame(args);
diff --git a/cc/trees/proxy_impl.h b/cc/trees/proxy_impl.h
index 0aab6133..bc4ac30d 100644
--- a/cc/trees/proxy_impl.h
+++ b/cc/trees/proxy_impl.h
@@ -90,6 +90,7 @@
   void DidPrepareTiles() override;
   void DidCompletePageScaleAnimationOnImplThread() override;
   void OnDrawForCompositorFrameSink(bool resourceless_software_draw) override;
+  void NeedsImplSideInvalidation() override;
 
   // SchedulerClient implementation
   void WillBeginImplFrame(const BeginFrameArgs& args) override;
diff --git a/cc/trees/single_thread_proxy.cc b/cc/trees/single_thread_proxy.cc
index 7aa7cfc..83853354 100644
--- a/cc/trees/single_thread_proxy.cc
+++ b/cc/trees/single_thread_proxy.cc
@@ -424,6 +424,12 @@
   NOTREACHED() << "Implemented by ThreadProxy for synchronous compositor.";
 }
 
+void SingleThreadProxy::NeedsImplSideInvalidation() {
+  // TODO(khushalsagar): Plumb this to the scheduler when
+  // https://codereview.chromium.org/2659123004/ lands. See crbug.com/686267.
+  NOTIMPLEMENTED();
+}
+
 void SingleThreadProxy::CompositeImmediately(base::TimeTicks frame_begin_time) {
   TRACE_EVENT0("cc,benchmark", "SingleThreadProxy::CompositeImmediately");
   DCHECK(task_runner_provider_->IsMainThread());
diff --git a/cc/trees/single_thread_proxy.h b/cc/trees/single_thread_proxy.h
index fbdd70e..444f167 100644
--- a/cc/trees/single_thread_proxy.h
+++ b/cc/trees/single_thread_proxy.h
@@ -95,6 +95,7 @@
   void DidPrepareTiles() override;
   void DidCompletePageScaleAnimationOnImplThread() override;
   void OnDrawForCompositorFrameSink(bool resourceless_software_draw) override;
+  void NeedsImplSideInvalidation() override;
 
   void RequestNewCompositorFrameSink();
 
diff --git a/chrome/android/java/res/layout/account_chooser_dialog_item.xml b/chrome/android/java/res/layout/account_chooser_dialog_item.xml
index 1af2fb6..500f6c37 100644
--- a/chrome/android/java/res/layout/account_chooser_dialog_item.xml
+++ b/chrome/android/java/res/layout/account_chooser_dialog_item.xml
@@ -18,10 +18,11 @@
         android:layout_height="40dp"
         android:contentDescription="@null"/>
     <LinearLayout
-        android:layout_width="wrap_content"
+        android:layout_width="0dp"
         android:layout_height="wrap_content"
         android:layout_margin="8dp"
         android:layout_marginStart="16dp"
+        android:layout_weight="1"
         android:orientation="vertical">
         <TextView
             android:id="@+id/main_name"
@@ -42,11 +43,6 @@
             android:textColor="@color/descriptive_text_color"
             android:textSize="@dimen/account_chooser_dialog_title_descriptive_text_size"/>
     </LinearLayout>
-    <!-- Needed to make the following ImageButton align to the right. -->
-    <Space
-        android:layout_width="0dp"
-        android:layout_height="0dp"
-        android:layout_weight="1" />
     <ImageButton
         android:id="@+id/psl_info_btn"
         android:layout_height="wrap_content"
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd
index 89bde79..237b55a 100644
--- a/chrome/app/generated_resources.grd
+++ b/chrome/app/generated_resources.grd
@@ -5519,6 +5519,12 @@
       <message name="IDS_FLAGS_WEBVR_DESCRIPTION" desc="Description for the flag to enable WebVR APIs.">
         Enabling this option allows web applications to access experimental Virtual Reality APIs.
       </message>
+      <message name="IDS_FLAGS_WEBVR_EXPERIMENTAL_RENDERING_NAME" desc="Name of the 'Enable WebVR experimental optimizations' flag.">
+        WebVR experimental rendering optimizations
+      </message>
+      <message name="IDS_FLAGS_WEBVR_EXPERIMENTAL_RENDERING_DESCRIPTION" desc="Description for the flag to enable experimental WebVR rendering optimizations.">
+        Enabling this option activates experimental rendering path optimizations for WebVR.
+      </message>
       <message name="IDS_FLAGS_GAMEPAD_EXTENSIONS_NAME" desc="Name of the flag which allows users to enable experimental extensions to the Gamepad API.">
         Gamepad Extensions
       </message>
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index 7cb46b7..90c3140 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -1623,6 +1623,10 @@
     {"enable-webvr", IDS_FLAGS_WEBVR_NAME, IDS_FLAGS_WEBVR_DESCRIPTION, kOsAll,
      SINGLE_VALUE_TYPE(switches::kEnableWebVR)},
 #if defined(ENABLE_WEBVR)
+    {"enable-webvr-experimental-rendering",
+     IDS_FLAGS_WEBVR_EXPERIMENTAL_RENDERING_NAME,
+     IDS_FLAGS_WEBVR_EXPERIMENTAL_RENDERING_DESCRIPTION, kOsAndroid,
+     FEATURE_VALUE_TYPE(features::kWebVRExperimentalRendering)},
     {"enable-vr-shell", IDS_FLAGS_ENABLE_VR_SHELL_NAME,
      IDS_FLAGS_ENABLE_VR_SHELL_DESCRIPTION, kOsAndroid,
      FEATURE_VALUE_TYPE(features::kVrShell)},
diff --git a/chrome/browser/chromeos/arc/arc_service_launcher.cc b/chrome/browser/chromeos/arc/arc_service_launcher.cc
index 52541dbe..cc6f0e5 100644
--- a/chrome/browser/chromeos/arc/arc_service_launcher.cc
+++ b/chrome/browser/chromeos/arc/arc_service_launcher.cc
@@ -100,8 +100,6 @@
   arc_service_manager_->AddService(
       base::MakeUnique<ArcBootErrorNotification>(arc_bridge_service));
   arc_service_manager_->AddService(
-      base::MakeUnique<ArcBootPhaseMonitorBridge>(arc_bridge_service));
-  arc_service_manager_->AddService(
       base::MakeUnique<ArcClipboardBridge>(arc_bridge_service));
   arc_service_manager_->AddService(base::MakeUnique<ArcCrashCollectorBridge>(
       arc_bridge_service, arc_service_manager_->blocking_task_runner()));
@@ -145,6 +143,10 @@
 
 void ArcServiceLauncher::OnPrimaryUserProfilePrepared(Profile* profile) {
   DCHECK(arc_service_manager_);
+  // List in lexicographical order
+  arc_service_manager_->AddService(base::MakeUnique<ArcBootPhaseMonitorBridge>(
+      arc_service_manager_->arc_bridge_service(),
+      multi_user_util::GetAccountIdFromProfile(profile)));
   arc_service_manager_->AddService(base::MakeUnique<ArcNotificationManager>(
       arc_service_manager_->arc_bridge_service(),
       multi_user_util::GetAccountIdFromProfile(profile)));
diff --git a/chrome/browser/chromeos/arc/boot_phase_monitor/arc_boot_phase_monitor_bridge.cc b/chrome/browser/chromeos/arc/boot_phase_monitor/arc_boot_phase_monitor_bridge.cc
index 458e823..9792fdf 100644
--- a/chrome/browser/chromeos/arc/boot_phase_monitor/arc_boot_phase_monitor_bridge.cc
+++ b/chrome/browser/chromeos/arc/boot_phase_monitor/arc_boot_phase_monitor_bridge.cc
@@ -4,17 +4,30 @@
 
 #include "chrome/browser/chromeos/arc/boot_phase_monitor/arc_boot_phase_monitor_bridge.h"
 
+#include "base/bind.h"
 #include "base/logging.h"
 #include "chrome/browser/chromeos/arc/boot_phase_monitor/arc_instance_throttle.h"
+#include "chrome/browser/ui/ash/multi_user/multi_user_util.h"
+#include "chromeos/cryptohome/cryptohome_parameters.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
 #include "chromeos/dbus/session_manager_client.h"
 #include "components/arc/arc_bridge_service.h"
 
+namespace {
+
+void OnEmitArcBooted(bool success) {
+  if (!success)
+    VLOG(1) << "Failed to emit arc booted signal.";
+}
+
+}  // namespace
+
 namespace arc {
 
 ArcBootPhaseMonitorBridge::ArcBootPhaseMonitorBridge(
-    ArcBridgeService* bridge_service)
-    : ArcService(bridge_service), binding_(this) {
+    ArcBridgeService* bridge_service,
+    const AccountId& account_id)
+    : ArcService(bridge_service), account_id_(account_id), binding_(this) {
   DCHECK(thread_checker_.CalledOnValidThread());
   arc_bridge_service()->boot_phase_monitor()->AddObserver(this);
 }
@@ -42,7 +55,8 @@
 
   chromeos::SessionManagerClient* session_manager_client =
       chromeos::DBusThreadManager::Get()->GetSessionManagerClient();
-  session_manager_client->EmitArcBooted();
+  session_manager_client->EmitArcBooted(cryptohome::Identification(account_id_),
+                                        base::Bind(&OnEmitArcBooted));
 
   // Start monitoring window activation changes to prioritize/throttle the
   // container when needed.
diff --git a/chrome/browser/chromeos/arc/boot_phase_monitor/arc_boot_phase_monitor_bridge.h b/chrome/browser/chromeos/arc/boot_phase_monitor/arc_boot_phase_monitor_bridge.h
index 407f450b..4e36365 100644
--- a/chrome/browser/chromeos/arc/boot_phase_monitor/arc_boot_phase_monitor_bridge.h
+++ b/chrome/browser/chromeos/arc/boot_phase_monitor/arc_boot_phase_monitor_bridge.h
@@ -12,6 +12,7 @@
 #include "components/arc/arc_service.h"
 #include "components/arc/common/boot_phase_monitor.mojom.h"
 #include "components/arc/instance_holder.h"
+#include "components/signin/core/account_id/account_id.h"
 #include "mojo/public/cpp/bindings/binding.h"
 
 namespace arc {
@@ -25,7 +26,8 @@
       public InstanceHolder<mojom::BootPhaseMonitorInstance>::Observer,
       public mojom::BootPhaseMonitorHost {
  public:
-  explicit ArcBootPhaseMonitorBridge(ArcBridgeService* bridge_service);
+  ArcBootPhaseMonitorBridge(ArcBridgeService* bridge_service,
+                            const AccountId& account_id);
   ~ArcBootPhaseMonitorBridge() override;
 
   // InstanceHolder<mojom::BootPhaseMonitorInstance>::Observer
@@ -36,6 +38,7 @@
   void OnBootCompleted() override;
 
  private:
+  const AccountId account_id_;
   mojo::Binding<mojom::BootPhaseMonitorHost> binding_;
   std::unique_ptr<ArcInstanceThrottle> throttle_;
 
diff --git a/chrome/browser/chromeos/language_preferences.cc b/chrome/browser/chromeos/language_preferences.cc
index e7ae62e..f78c717 100644
--- a/chrome/browser/chromeos/language_preferences.cc
+++ b/chrome/browser/chromeos/language_preferences.cc
@@ -17,6 +17,7 @@
 // ---------------------------------------------------------------------------
 // For keyboard stuff
 // ---------------------------------------------------------------------------
+const bool kXkbAutoRepeatEnabled = true;
 const int kXkbAutoRepeatDelayInMs = 500;
 const int kXkbAutoRepeatIntervalInMs = 50;
 const char kPreferredKeyboardLayout[] = "PreferredKeyboardLayout";
diff --git a/chrome/browser/chromeos/language_preferences.h b/chrome/browser/chromeos/language_preferences.h
index 00bb32d..e406df4 100644
--- a/chrome/browser/chromeos/language_preferences.h
+++ b/chrome/browser/chromeos/language_preferences.h
@@ -25,6 +25,8 @@
 // ---------------------------------------------------------------------------
 // For keyboard stuff
 // ---------------------------------------------------------------------------
+// A flag indicating whether the keyboard auto repeat is enabled.
+extern const bool kXkbAutoRepeatEnabled;
 // A delay between the first and the start of the rest.
 extern const int kXkbAutoRepeatDelayInMs;
 // An interval between the repeated keys.
diff --git a/chrome/browser/chromeos/preferences.cc b/chrome/browser/chromeos/preferences.cc
index df889bd3..1103be6 100644
--- a/chrome/browser/chromeos/preferences.cc
+++ b/chrome/browser/chromeos/preferences.cc
@@ -270,7 +270,7 @@
   registry->RegisterBooleanPref(prefs::kLanguageSendFunctionKeys, false);
   registry->RegisterBooleanPref(
       prefs::kLanguageXkbAutoRepeatEnabled,
-      true,
+      language_prefs::kXkbAutoRepeatEnabled,
       user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
   registry->RegisterIntegerPref(
       prefs::kLanguageXkbAutoRepeatDelay,
@@ -622,6 +622,9 @@
       input_method::InputMethodManager::Get()
           ->GetImeKeyboard()
           ->SetAutoRepeatEnabled(enabled);
+
+      user_manager::known_user::SetBooleanPref(
+          user_->GetAccountId(), prefs::kLanguageXkbAutoRepeatEnabled, enabled);
     }
   }
   if (reason != REASON_PREF_CHANGED ||
@@ -786,6 +789,13 @@
   input_method::InputMethodManager::Get()
       ->GetImeKeyboard()
       ->SetAutoRepeatRate(rate);
+
+  user_manager::known_user::SetIntegerPref(user_->GetAccountId(),
+                                           prefs::kLanguageXkbAutoRepeatDelay,
+                                           rate.initial_delay_in_ms);
+  user_manager::known_user::SetIntegerPref(
+      user_->GetAccountId(), prefs::kLanguageXkbAutoRepeatInterval,
+      rate.repeat_interval_in_ms);
 }
 
 void Preferences::OnTouchHudProjectionToggled(bool enabled) {
diff --git a/chrome/browser/chromeos/settings/device_settings_test_helper.cc b/chrome/browser/chromeos/settings/device_settings_test_helper.cc
index 792004f..6ce8971 100644
--- a/chrome/browser/chromeos/settings/device_settings_test_helper.cc
+++ b/chrome/browser/chromeos/settings/device_settings_test_helper.cc
@@ -200,7 +200,9 @@
     login_manager::ContainerCpuRestrictionState restriction_state,
     const ArcCallback& callback) {}
 
-void DeviceSettingsTestHelper::EmitArcBooted() {}
+void DeviceSettingsTestHelper::EmitArcBooted(
+    const cryptohome::Identification& cryptohome_id,
+    const ArcCallback& callback) {}
 
 void DeviceSettingsTestHelper::GetArcStartTime(
     const GetArcStartTimeCallback& callback) {}
diff --git a/chrome/browser/chromeos/settings/device_settings_test_helper.h b/chrome/browser/chromeos/settings/device_settings_test_helper.h
index 384f598..30a54160 100644
--- a/chrome/browser/chromeos/settings/device_settings_test_helper.h
+++ b/chrome/browser/chromeos/settings/device_settings_test_helper.h
@@ -130,7 +130,8 @@
   void SetArcCpuRestriction(
       login_manager::ContainerCpuRestrictionState restriction_state,
       const ArcCallback& callback) override;
-  void EmitArcBooted() override;
+  void EmitArcBooted(const cryptohome::Identification& cryptohome_id,
+                     const ArcCallback& callback) override;
   void GetArcStartTime(const GetArcStartTimeCallback& callback) override;
   void RemoveArcData(const cryptohome::Identification& cryptohome_id,
                      const ArcCallback& callback) override;
diff --git a/chrome/browser/extensions/extension_action_icon_factory_unittest.cc b/chrome/browser/extensions/extension_action_icon_factory_unittest.cc
index 34ea3c6c..692e9df 100644
--- a/chrome/browser/extensions/extension_action_icon_factory_unittest.cc
+++ b/chrome/browser/extensions/extension_action_icon_factory_unittest.cc
@@ -21,7 +21,7 @@
 #include "chrome/common/chrome_paths.h"
 #include "chrome/grit/theme_resources.h"
 #include "chrome/test/base/testing_profile.h"
-#include "content/public/test/test_browser_thread.h"
+#include "content/public/test/test_browser_thread_bundle.h"
 #include "extensions/common/extension.h"
 #include "skia/ext/image_operations.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -38,8 +38,6 @@
 #include "chrome/browser/chromeos/settings/device_settings_service.h"
 #endif
 
-using content::BrowserThread;
-
 namespace extensions {
 namespace {
 
@@ -88,12 +86,7 @@
     : public testing::TestWithParam<ui::MaterialDesignController::Mode>,
       public ExtensionActionIconFactory::Observer {
  public:
-  ExtensionActionIconFactoryTest()
-      : quit_in_icon_updated_(false),
-        ui_thread_(BrowserThread::UI, &ui_loop_),
-        file_thread_(BrowserThread::FILE),
-        io_thread_(BrowserThread::IO) {
-  }
+  ExtensionActionIconFactoryTest() : quit_in_icon_updated_(false) {}
 
   ~ExtensionActionIconFactoryTest() override {}
 
@@ -138,8 +131,6 @@
 
   // testing::Test overrides:
   void SetUp() override {
-    file_thread_.Start();
-    io_thread_.Start();
     profile_.reset(new TestingProfile);
     base::CommandLine command_line(base::CommandLine::NO_PROGRAM);
     extension_service_ = static_cast<extensions::TestExtensionSystem*>(
@@ -173,11 +164,8 @@
   TestingProfile* profile() { return profile_.get(); }
 
  private:
+  content::TestBrowserThreadBundle test_browser_thread_bundle_;
   bool quit_in_icon_updated_;
-  base::MessageLoop ui_loop_;
-  content::TestBrowserThread ui_thread_;
-  content::TestBrowserThread file_thread_;
-  content::TestBrowserThread io_thread_;
   std::unique_ptr<TestingProfile> profile_;
   ExtensionService* extension_service_;
   std::unique_ptr<ui::test::MaterialDesignControllerTestAPI>
diff --git a/chrome/browser/extensions/extension_icon_manager_unittest.cc b/chrome/browser/extensions/extension_icon_manager_unittest.cc
index e6b37f8a..f4f6790 100644
--- a/chrome/browser/extensions/extension_icon_manager_unittest.cc
+++ b/chrome/browser/extensions/extension_icon_manager_unittest.cc
@@ -2,6 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "chrome/browser/extensions/extension_icon_manager.h"
+
 #include "base/command_line.h"
 #include "base/json/json_file_value_serializer.h"
 #include "base/macros.h"
@@ -13,11 +15,10 @@
 #include "base/test/scoped_command_line.h"
 #include "base/values.h"
 #include "build/build_config.h"
-#include "chrome/browser/extensions/extension_icon_manager.h"
 #include "chrome/common/chrome_paths.h"
 #include "chrome/test/base/testing_profile.h"
 #include "components/crx_file/id_util.h"
-#include "content/public/test/test_browser_thread.h"
+#include "content/public/test/test_browser_thread_bundle.h"
 #include "extensions/common/extension.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/base/layout.h"
@@ -58,18 +59,11 @@
   DISALLOW_COPY_AND_ASSIGN(ScopedSetDeviceScaleFactor);
 };
 
-using content::BrowserThread;
-
 // Our test class that takes care of managing the necessary threads for loading
 // extension icons, and waiting for those loads to happen.
 class ExtensionIconManagerTest : public testing::Test {
  public:
-  ExtensionIconManagerTest() :
-      unwaited_image_loads_(0),
-      waiting_(false),
-      ui_thread_(BrowserThread::UI, &ui_loop_),
-      file_thread_(BrowserThread::FILE),
-      io_thread_(BrowserThread::IO) {}
+  ExtensionIconManagerTest() : unwaited_image_loads_(0), waiting_(false) {}
 
   ~ExtensionIconManagerTest() override {}
 
@@ -91,10 +85,7 @@
   }
 
  private:
-  void SetUp() override {
-    file_thread_.Start();
-    io_thread_.Start();
-  }
+  content::TestBrowserThreadBundle test_browser_thread_bundle_;
 
   // The number of observed image loads that have not been waited for.
   int unwaited_image_loads_;
@@ -102,11 +93,6 @@
   // Whether we are currently waiting for an image load.
   bool waiting_;
 
-  base::MessageLoop ui_loop_;
-  content::TestBrowserThread ui_thread_;
-  content::TestBrowserThread file_thread_;
-  content::TestBrowserThread io_thread_;
-
   DISALLOW_COPY_AND_ASSIGN(ExtensionIconManagerTest);
 };
 
diff --git a/chrome/browser/extensions/menu_manager_unittest.cc b/chrome/browser/extensions/menu_manager_unittest.cc
index aeb909c..a4840e9 100644
--- a/chrome/browser/extensions/menu_manager_unittest.cc
+++ b/chrome/browser/extensions/menu_manager_unittest.cc
@@ -13,6 +13,7 @@
 #include "base/memory/ptr_util.h"
 #include "base/run_loop.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/threading/thread_task_runner_handle.h"
 #include "base/values.h"
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/extensions/extension_system_factory.h"
@@ -25,7 +26,7 @@
 #include "components/sync_preferences/pref_service_syncable.h"
 #include "content/public/browser/notification_service.h"
 #include "content/public/common/context_menu_params.h"
-#include "content/public/test/test_browser_thread.h"
+#include "content/public/test/test_browser_thread_bundle.h"
 #include "extensions/browser/event_router.h"
 #include "extensions/browser/event_router_factory.h"
 #include "extensions/browser/extension_registry.h"
@@ -34,7 +35,6 @@
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
-using content::BrowserThread;
 using testing::_;
 using testing::AtLeast;
 using testing::DeleteArg;
@@ -50,12 +50,10 @@
 class MenuManagerTest : public testing::Test {
  public:
   MenuManagerTest()
-      : ui_thread_(BrowserThread::UI, &message_loop_),
-        file_thread_(BrowserThread::FILE, &message_loop_),
-        profile_(new TestingProfile()),
+      : profile_(new TestingProfile()),
         manager_(profile_.get(),
                  ExtensionSystem::Get(profile_.get())->state_store()),
-        prefs_(message_loop_.task_runner().get()),
+        prefs_(base::ThreadTaskRunnerHandle::Get()),
         next_id_(1) {}
 
   void TearDown() override {
@@ -94,9 +92,7 @@
   }
 
  protected:
-  base::MessageLoopForUI message_loop_;
-  content::TestBrowserThread ui_thread_;
-  content::TestBrowserThread file_thread_;
+  content::TestBrowserThreadBundle test_browser_thread_bundle_;
   std::unique_ptr<TestingProfile> profile_;
 
   MenuManager manager_;
diff --git a/chrome/browser/safe_browsing/download_protection_service.cc b/chrome/browser/safe_browsing/download_protection_service.cc
index 2b9a6d2..cdd7d73 100644
--- a/chrome/browser/safe_browsing/download_protection_service.cc
+++ b/chrome/browser/safe_browsing/download_protection_service.cc
@@ -1877,12 +1877,26 @@
   UMA_HISTOGRAM_BOOLEAN(
       "SafeBrowsing.ReferrerHasInvalidTabID.DownloadAttribution",
       download_tab_id == -1);
+  // We look for the referrer chain that leads to the download url first.
   SafeBrowsingNavigationObserverManager::AttributionResult result =
       navigation_observer_manager_->IdentifyReferrerChainForDownload(
           download_url,
           download_tab_id,
           kDownloadAttributionUserGestureLimit,
           referrer_chain.get());
+
+  // If no navigation event is found, this download is not triggered by regular
+  // navigation (e.g. html5 file apis, etc). We look for the referrer chain
+  // based on relevant WebContents instead.
+  if (result ==
+          SafeBrowsingNavigationObserverManager::NAVIGATION_EVENT_NOT_FOUND &&
+      web_contents && web_contents->GetLastCommittedURL().is_valid()) {
+    result =
+        navigation_observer_manager_->IdentifyReferrerChainByDownloadWebContent(
+            web_contents, kDownloadAttributionUserGestureLimit,
+            referrer_chain.get());
+  }
+
   UMA_HISTOGRAM_COUNTS_100(
       "SafeBrowsing.ReferrerURLChainSize.DownloadAttribution",
       referrer_chain->size());
@@ -1908,7 +1922,7 @@
       "SafeBrowsing.ReferrerHasInvalidTabID.DownloadAttribution",
       tab_id == -1);
   SafeBrowsingNavigationObserverManager::AttributionResult result =
-      navigation_observer_manager_->IdentifyReferrerChainForPPAPIDownload(
+      navigation_observer_manager_->IdentifyReferrerChainForDownloadHostingPage(
           initiating_frame_url, initiating_main_frame_url, tab_id,
           has_user_gesture, kDownloadAttributionUserGestureLimit,
           out_request->mutable_referrer_chain());
diff --git a/chrome/browser/safe_browsing/safe_browsing_navigation_observer_browsertest.cc b/chrome/browser/safe_browsing/safe_browsing_navigation_observer_browsertest.cc
index edde27aa..55590dd 100644
--- a/chrome/browser/safe_browsing/safe_browsing_navigation_observer_browsertest.cc
+++ b/chrome/browser/safe_browsing/safe_browsing_navigation_observer_browsertest.cc
@@ -30,6 +30,7 @@
 #include "url/url_canon.h"
 
 using content::DownloadItem;
+using content::DownloadManager;
 
 namespace safe_browsing {
 
@@ -67,6 +68,63 @@
     "/safe_browsing/download_protection/navigation_observer/"
     "page_before_landing_referrer.html";
 
+class DownloadItemCreatedObserver : public DownloadManager::Observer {
+ public:
+  explicit DownloadItemCreatedObserver(DownloadManager* manager)
+      : manager_(manager) {
+    manager->AddObserver(this);
+  }
+
+  ~DownloadItemCreatedObserver() override {
+    if (manager_)
+      manager_->RemoveObserver(this);
+  }
+
+  // Wait for the first download item created after object creation.
+  void WaitForDownloadItem(std::vector<DownloadItem*>* items_seen) {
+    if (!manager_) {
+      // The manager went away before we were asked to wait; return
+      // what we have, even if it's null.
+      *items_seen = items_seen_;
+      return;
+    }
+
+    if (items_seen_.empty()) {
+      base::RunLoop run_loop;
+      quit_waiting_callback_ = run_loop.QuitClosure();
+      run_loop.Run();
+      quit_waiting_callback_ = base::Closure();
+    }
+
+    *items_seen = items_seen_;
+    return;
+  }
+
+ private:
+  // DownloadManager::Observer
+  void OnDownloadCreated(DownloadManager* manager,
+                         DownloadItem* item) override {
+    DCHECK_EQ(manager, manager_);
+    items_seen_.push_back(item);
+
+    if (!quit_waiting_callback_.is_null())
+      quit_waiting_callback_.Run();
+  }
+
+  void ManagerGoingDown(DownloadManager* manager) override {
+    manager_->RemoveObserver(this);
+    manager_ = NULL;
+    if (!quit_waiting_callback_.is_null())
+      quit_waiting_callback_.Run();
+  }
+
+  base::Closure quit_waiting_callback_;
+  DownloadManager* manager_;
+  std::vector<DownloadItem*> items_seen_;
+
+  DISALLOW_COPY_AND_ASSIGN(DownloadItemCreatedObserver);
+};
+
 // Test class to help create SafeBrowsingNavigationObservers for each
 // WebContents before they are actually installed through AttachTabHelper.
 class TestNavigationObserverManager
@@ -206,6 +264,23 @@
     }
   }
 
+  void TriggerDownloadViaHtml5FileApi(bool has_user_gesture) {
+    if (has_user_gesture)
+      SimulateUserGesture();
+
+    std::vector<DownloadItem*> items;
+    content::DownloadManager* manager =
+        content::BrowserContext::GetDownloadManager(browser()->profile());
+    content::WebContents* current_web_contents =
+        browser()->tab_strip_model()->GetActiveWebContents();
+    ASSERT_TRUE(
+        content::ExecuteScript(current_web_contents, "downloadViaFileApi()"));
+    manager->GetAllDownloads(&items);
+    if (items.size() == 0U) {
+      DownloadItemCreatedObserver(manager).WaitForDownloadItem(&items);
+    }
+  }
+
   void VerifyNavigationEvent(const GURL& expected_source_url,
                              const GURL& expected_source_main_frame_url,
                              const GURL& expected_original_request_url,
@@ -280,13 +355,18 @@
       ReferrerChain* referrer_chain) {
     int download_tab_id =
         SessionTabHelper::IdForTab(download->GetWebContents());
-    // IdentifyReferrerChain should return SUCCESS(1), SUCCESS_LANDING_PAGE(2),
-    // or SUCCESS_LANDING_REFERRER(3) in all these tests.
-    EXPECT_LE(observer_manager_->IdentifyReferrerChainForDownload(
-                  download->GetURL(), download_tab_id,
-                  2,  // kDownloadAttributionUserGestureLimit
-                  referrer_chain),
-              SafeBrowsingNavigationObserverManager::SUCCESS_LANDING_REFERRER);
+    auto result = observer_manager_->IdentifyReferrerChainForDownload(
+        download->GetURL(), download_tab_id,
+        2,  // kDownloadAttributionUserGestureLimit
+        referrer_chain);
+    if (result ==
+        SafeBrowsingNavigationObserverManager::NAVIGATION_EVENT_NOT_FOUND) {
+      DCHECK_EQ(0, referrer_chain->size());
+      observer_manager_->IdentifyReferrerChainByDownloadWebContent(
+          download->GetWebContents(),
+          2,  // kDownloadAttributionUserGestureLimit
+          referrer_chain);
+    }
   }
 
   // Identify referrer chain of a PPAPI download and populate |referrer_chain|.
@@ -297,10 +377,10 @@
     int tab_id = SessionTabHelper::IdForTab(web_contents);
     bool has_user_gesture = observer_manager_->HasUserGesture(web_contents);
     observer_manager_->OnUserGestureConsumed(web_contents, base::Time::Now());
-    EXPECT_LE(observer_manager_->IdentifyReferrerChainForPPAPIDownload(
+    EXPECT_LE(observer_manager_->IdentifyReferrerChainForDownloadHostingPage(
                   initiating_frame_url, web_contents->GetLastCommittedURL(),
                   tab_id, has_user_gesture,
-                  2,  // kDownloadAttributionUserGestureLimit)
+                  2,  // kDownloadAttributionUserGestureLimit
                   referrer_chain),
               SafeBrowsingNavigationObserverManager::SUCCESS_LANDING_REFERRER);
   }
@@ -1077,63 +1157,6 @@
                            referrer_chain.Get(2));
 }
 
-// TODO(jialiul): Need to figure out why this test is failing on Windows and
-// flaky on other platforms.
-#define MAYBE_DownloadViaHTML5FileApi DISABLED_DownloadViaHTML5FileApi
-// Download via html5 file API.
-IN_PROC_BROWSER_TEST_F(SBNavigationObserverBrowserTest,
-                       MAYBE_DownloadViaHTML5FileApi) {
-  GURL initial_url = embedded_test_server()->GetURL(kSingleFrameTestURL);
-  ClickTestLink("html5_file_api", 1, initial_url);
-  std::string download_url_str =
-      base::StringPrintf("filesystem:%stemporary/test.exe",
-                         embedded_test_server()->base_url().spec().c_str());
-  GURL download_url = GURL(download_url_str);
-  std::string test_server_ip(embedded_test_server()->host_port_pair().host());
-  auto* nav_list = navigation_event_list();
-  ASSERT_TRUE(nav_list);
-  ASSERT_EQ(2U, nav_list->Size());
-  VerifyNavigationEvent(GURL(),       // source_url
-                        GURL(),       // source_main_frame_url
-                        initial_url,  // original_request_url
-                        initial_url,  // destination_url
-                        true,         // is_user_initiated,
-                        true,         // has_committed
-                        false,        // has_server_redirect
-                        nav_list->Get(0));
-  VerifyNavigationEvent(initial_url,   // source_url
-                        initial_url,   // source_main_frame_url
-                        download_url,  // original_request_url
-                        download_url,  // destination_url
-                        true,          // is_user_initiated,
-                        false,         // has_committed
-                        false,         // has_server_redirect
-                        nav_list->Get(1));
-  VerifyHostToIpMap();
-
-  ReferrerChain referrer_chain;
-  IdentifyReferrerChainForDownload(GetDownload(), &referrer_chain);
-  ASSERT_EQ(2, referrer_chain.size());
-  VerifyReferrerChainEntry(download_url,                      // url
-                           GURL(),                            // main_frame_url
-                           ReferrerChainEntry::DOWNLOAD_URL,  // type
-                           "",                                // ip_address
-                           initial_url,                       // referrer_url
-                           GURL(),               // referrer_main_frame_url
-                           false,                // is_retargeting
-                           std::vector<GURL>(),  // server redirects
-                           referrer_chain.Get(0));
-  VerifyReferrerChainEntry(initial_url,                       // url
-                           GURL(),                            // main_frame_url
-                           ReferrerChainEntry::LANDING_PAGE,  // type
-                           test_server_ip,                    // ip_address
-                           GURL(),                            // referrer_url
-                           GURL(),               // referrer_main_frame_url
-                           false,                // is_retargeting
-                           std::vector<GURL>(),  // server redirects
-                           referrer_chain.Get(1));
-}
-
 // Click a link in a subframe and start download.
 IN_PROC_BROWSER_TEST_F(SBNavigationObserverBrowserTest,
                        SubFrameDirectDownload) {
@@ -1881,4 +1904,71 @@
   EXPECT_NE(yesterday, ip_map->at(test_server_host).front().timestamp);
 }
 
+// Download via html5 file API with user gesture.
+IN_PROC_BROWSER_TEST_F(SBNavigationObserverBrowserTest,
+                       DownloadViaHTML5FileApiWithUserGesture) {
+  GURL hosting_url = embedded_test_server()->GetURL(kSingleFrameTestURL);
+  // Trigger download by user gesture.
+  TriggerDownloadViaHtml5FileApi(true /* has_user_gesture */);
+  std::string test_server_ip(embedded_test_server()->host_port_pair().host());
+  auto nav_list = navigation_event_list();
+  ASSERT_TRUE(nav_list);
+  ASSERT_EQ(1U, nav_list->Size());
+  VerifyNavigationEvent(GURL(),       // source_url
+                        GURL(),       // source_main_frame_url
+                        hosting_url,  // original_request_url
+                        hosting_url,  // destination_url
+                        true,         // is_user_initiated,
+                        true,         // has_committed
+                        false,        // has_server_redirect
+                        nav_list->Get(0));
+  VerifyHostToIpMap();
+  ReferrerChain referrer_chain;
+  IdentifyReferrerChainForDownload(GetDownload(), &referrer_chain);
+  ASSERT_EQ(1, referrer_chain.size());
+
+  VerifyReferrerChainEntry(hosting_url,                       // url
+                           GURL(),                            // main_frame_url
+                           ReferrerChainEntry::LANDING_PAGE,  // type
+                           test_server_ip,                    // ip_address
+                           GURL(),                            // referrer_url
+                           GURL(),               // referrer_main_frame_url
+                           false,                // is_retargeting
+                           std::vector<GURL>(),  // server redirects
+                           referrer_chain.Get(0));
+}
+
+// Download via html5 file API without user gesture.
+IN_PROC_BROWSER_TEST_F(SBNavigationObserverBrowserTest,
+                       DownloadViaHTML5FileApiWithoutUserGesture) {
+  GURL hosting_url = embedded_test_server()->GetURL(kSingleFrameTestURL);
+  // Trigger download without user gesture.
+  TriggerDownloadViaHtml5FileApi(false /* has_user_gesture */);
+  std::string test_server_ip(embedded_test_server()->host_port_pair().host());
+  auto nav_list = navigation_event_list();
+  ASSERT_TRUE(nav_list);
+  ASSERT_EQ(1U, nav_list->Size());
+  VerifyNavigationEvent(GURL(),       // source_url
+                        GURL(),       // source_main_frame_url
+                        hosting_url,  // original_request_url
+                        hosting_url,  // destination_url
+                        true,         // is_user_initiated,
+                        true,         // has_committed
+                        false,        // has_server_redirect
+                        nav_list->Get(0));
+  VerifyHostToIpMap();
+  ReferrerChain referrer_chain;
+  IdentifyReferrerChainForDownload(GetDownload(), &referrer_chain);
+  ASSERT_EQ(1, referrer_chain.size());
+
+  VerifyReferrerChainEntry(hosting_url,  // url
+                           GURL(),       // main_frame_url
+                           ReferrerChainEntry::CLIENT_REDIRECT,  // type
+                           test_server_ip,                       // ip_address
+                           GURL(),                               // referrer_url
+                           GURL(),               // referrer_main_frame_url
+                           false,                // is_retargeting
+                           std::vector<GURL>(),  // server redirects
+                           referrer_chain.Get(0));
+}
 }  // namespace safe_browsing
diff --git a/chrome/browser/safe_browsing/safe_browsing_navigation_observer_manager.cc b/chrome/browser/safe_browsing/safe_browsing_navigation_observer_manager.cc
index cf29a28..b6608fa 100644
--- a/chrome/browser/safe_browsing/safe_browsing_navigation_observer_manager.cc
+++ b/chrome/browser/safe_browsing/safe_browsing_navigation_observer_manager.cc
@@ -334,20 +334,37 @@
 }
 
 SafeBrowsingNavigationObserverManager::AttributionResult
-SafeBrowsingNavigationObserverManager::IdentifyReferrerChainForPPAPIDownload(
-    const GURL& initiating_frame_url,
-    const GURL& initiating_main_frame_url,
-    int tab_id,
-    bool has_user_gesture,
-    int user_gesture_count_limit,
-    ReferrerChain* out_referrer_chain) {
+SafeBrowsingNavigationObserverManager::
+    IdentifyReferrerChainByDownloadWebContent(
+        content::WebContents* web_contents,
+        int user_gesture_count_limit,
+        ReferrerChain* out_referrer_chain) {
+  if (!web_contents || !web_contents->GetLastCommittedURL().is_valid())
+    return INVALID_URL;
+  bool has_user_gesture = HasUserGesture(web_contents);
+  int tab_id = SessionTabHelper::IdForTab(web_contents);
+  return IdentifyReferrerChainForDownloadHostingPage(
+      web_contents->GetLastCommittedURL(), GURL(), tab_id, has_user_gesture,
+      user_gesture_count_limit, out_referrer_chain);
+}
+
+SafeBrowsingNavigationObserverManager::AttributionResult
+SafeBrowsingNavigationObserverManager::
+    IdentifyReferrerChainForDownloadHostingPage(
+        const GURL& initiating_frame_url,
+        const GURL& initiating_main_frame_url,
+        int tab_id,
+        bool has_user_gesture,
+        int user_gesture_count_limit,
+        ReferrerChain* out_referrer_chain) {
   if (!initiating_frame_url.is_valid())
     return INVALID_URL;
 
   NavigationEvent* nav_event = navigation_event_list_.FindNavigationEvent(
-      initiating_frame_url, GURL(), tab_id);
+      initiating_frame_url, initiating_main_frame_url, tab_id);
   if (!nav_event) {
-    // We cannot find a single navigation event related to this download.
+    // We cannot find a single navigation event related to this download hosting
+    // page.
     return NAVIGATION_EVENT_NOT_FOUND;
   }
 
diff --git a/chrome/browser/safe_browsing/safe_browsing_navigation_observer_manager.h b/chrome/browser/safe_browsing/safe_browsing_navigation_observer_manager.h
index 7c4407a..cbd499b 100644
--- a/chrome/browser/safe_browsing/safe_browsing_navigation_observer_manager.h
+++ b/chrome/browser/safe_browsing/safe_browsing_navigation_observer_manager.h
@@ -151,8 +151,8 @@
   void CleanUpStaleNavigationFootprints();
 
   // Based on the |target_url| and |target_tab_id|, trace back the observed
-  // NavigationEvents in navigation_map_ to identify the sequence of navigations
-  // leading to the target, with the coverage limited to
+  // NavigationEvents in navigation_event_list_ to identify the sequence of
+  // navigations leading to the target, with the coverage limited to
   // |user_gesture_count_limit| number of user gestures. Then convert these
   // identified NavigationEvents into ReferrerChainEntrys and append them to
   // |out_referrer_chain|.
@@ -162,15 +162,26 @@
       int user_gesture_count_limit,
       ReferrerChain* out_referrer_chain);
 
+  // Based on the |web_contents| associated with a download, trace back the
+  // observed NavigationEvents in navigation_event_list_ to identify the
+  // sequence of navigations leading to the download hosting page, with the
+  // coverage limited to |user_gesture_count_limit| number of user gestures.
+  // Then convert these identified NavigationEvents into ReferrerChainEntrys
+  // and append them to |out_referrer_chain|.
+  AttributionResult IdentifyReferrerChainByDownloadWebContent(
+      content::WebContents* web_contents,
+      int user_gesture_count_limit,
+      ReferrerChain* out_referrer_chain);
+
   // Based on the |initiating_frame_url| and its associated |tab_id|, trace back
-  // the observed NavigationEvents in navigation_map_ to identify the sequence
-  // of navigations leading to this |initiating_frame_url|. If this initiating
+  // the observed NavigationEvents in navigation_event_list_ to identify those
+  // navigations leading to this |initiating_frame_url|. If this initiating
   // frame has a user gesture, we trace back with the coverage limited to
   // |user_gesture_count_limit|-1 number of user gestures, otherwise we trace
   // back |user_gesture_count_limit| number of user gestures. We then convert
   // these identified NavigationEvents into ReferrerChainEntrys and append them
   // to |out_referrer_chain|.
-  AttributionResult IdentifyReferrerChainForPPAPIDownload(
+  AttributionResult IdentifyReferrerChainForDownloadHostingPage(
       const GURL& initiating_frame_url,
       const GURL& initiating_main_frame_url,
       int tab_id,
@@ -210,7 +221,7 @@
 
   HostToIpMap* host_to_ip_map() { return &host_to_ip_map_; }
 
-  // Remove stale entries from navigation_map_ if they are older than
+  // Remove stale entries from navigation_event_list_ if they are older than
   // kNavigationFootprintTTLInSecond (2 minutes).
   void CleanUpNavigationEvents();
 
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn
index 92cca038..43f3cc6 100644
--- a/chrome/browser/ui/BUILD.gn
+++ b/chrome/browser/ui/BUILD.gn
@@ -2095,6 +2095,8 @@
       "views/sad_tab_view.h",
       "views/tab_contents/chrome_web_contents_view_delegate_views.cc",
       "views/tab_contents/chrome_web_contents_view_delegate_views.h",
+      "views/theme_profile_key.cc",
+      "views/theme_profile_key.h",
       "window_sizer/window_sizer_aura.cc",
     ]
     deps += [
diff --git a/chrome/browser/ui/ash/launcher/multi_profile_browser_status_monitor.cc b/chrome/browser/ui/ash/launcher/multi_profile_browser_status_monitor.cc
index 5396b3a..bd6bb91 100644
--- a/chrome/browser/ui/ash/launcher/multi_profile_browser_status_monitor.cc
+++ b/chrome/browser/ui/ash/launcher/multi_profile_browser_status_monitor.cc
@@ -6,7 +6,6 @@
 
 #include "ash/common/shelf/shelf_item_types.h"
 #include "ash/common/wm_window.h"
-#include "ash/common/wm_window_observer.h"
 #include "ash/common/wm_window_property.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_manager.h"
diff --git a/chrome/browser/ui/views/chrome_browser_main_extra_parts_views_linux.cc b/chrome/browser/ui/views/chrome_browser_main_extra_parts_views_linux.cc
index eca7168a..0aac8ac 100644
--- a/chrome/browser/ui/views/chrome_browser_main_extra_parts_views_linux.cc
+++ b/chrome/browser/ui/views/chrome_browser_main_extra_parts_views_linux.cc
@@ -12,6 +12,7 @@
 #include "chrome/browser/ui/browser_list.h"
 #include "chrome/browser/ui/libgtkui/gtk_ui.h"
 #include "chrome/browser/ui/views/frame/browser_view.h"
+#include "chrome/browser/ui/views/theme_profile_key.h"
 #include "chrome/common/pref_names.h"
 #include "components/prefs/pref_service.h"
 #include "ui/aura/env.h"
@@ -33,14 +34,7 @@
   if (!window)
     return nullptr;
 
-  Profile* profile = nullptr;
-  // Window types not listed here (such as tooltips) will never use Chrome
-  // theming.
-  if (window->type() == ui::wm::WINDOW_TYPE_NORMAL ||
-      window->type() == ui::wm::WINDOW_TYPE_POPUP) {
-    profile = reinterpret_cast<Profile*>(
-        window->GetNativeWindowProperty(Profile::kProfileKey));
-  }
+  Profile* profile = GetThemeProfileForWindow(window);
 
   // If using the system (GTK) theme, don't use an Aura NativeTheme at all.
   // NB: ThemeService::UsingSystemTheme() might lag behind this pref. See
diff --git a/chrome/browser/ui/views/chrome_views_delegate.cc b/chrome/browser/ui/views/chrome_views_delegate.cc
index 10ebf3b..d791ed48 100644
--- a/chrome/browser/ui/views/chrome_views_delegate.cc
+++ b/chrome/browser/ui/views/chrome_views_delegate.cc
@@ -51,6 +51,7 @@
 
 #if defined(USE_AURA)
 #include "chrome/browser/ui/aura/accessibility/automation_manager_aura.h"
+#include "chrome/browser/ui/views/theme_profile_key.h"
 #include "ui/aura/window.h"
 #include "ui/aura/window_event_dispatcher.h"
 #endif
@@ -451,9 +452,19 @@
   // While the majority of the time, context wasn't plumbed through due to the
   // existence of a global WindowParentingClient, if this window is toplevel,
   // it's possible that there is no contextual state that we can use.
-  if (params->parent == NULL && params->context == NULL && !params->child) {
-    params->native_widget = new views::DesktopNativeWidgetAura(delegate);
-  } else if (use_non_toplevel_window) {
+  gfx::NativeWindow parent_or_context =
+      params->parent ? params->parent : params->context;
+  Profile* profile = nullptr;
+  if (parent_or_context)
+    profile = GetThemeProfileForWindow(parent_or_context);
+  aura::Window* window = nullptr;
+  if ((!params->parent && !params->context && !params->child) ||
+      !use_non_toplevel_window) {
+    views::DesktopNativeWidgetAura* native_widget =
+        new views::DesktopNativeWidgetAura(delegate);
+    params->native_widget = native_widget;
+    window = native_widget->GetNativeWindow();
+  } else {
     views::NativeWidgetAura* native_widget =
         new views::NativeWidgetAura(delegate);
     if (params->parent) {
@@ -463,9 +474,9 @@
                                              parent_profile);
     }
     params->native_widget = native_widget;
-  } else {
-    params->native_widget = new views::DesktopNativeWidgetAura(delegate);
+    window = native_widget->GetNativeWindow();
   }
+  SetThemeProfileForWindow(window, profile);
 #endif
 }
 
diff --git a/chrome/browser/ui/views/frame/browser_view.cc b/chrome/browser/ui/views/frame/browser_view.cc
index a58f71b0..196f424 100644
--- a/chrome/browser/ui/views/frame/browser_view.cc
+++ b/chrome/browser/ui/views/frame/browser_view.cc
@@ -155,6 +155,7 @@
 #endif  // !defined(OS_CHROMEOS)
 
 #if defined(USE_AURA)
+#include "chrome/browser/ui/views/theme_profile_key.h"
 #include "ui/aura/client/window_parenting_client.h"
 #include "ui/aura/window.h"
 #include "ui/aura/window_tree_host.h"
@@ -174,9 +175,6 @@
 #include "chrome/browser/ui/views/sync/one_click_signin_dialog_view.h"
 #endif
 
-#if defined(OS_LINUX)
-#endif
-
 using base::TimeDelta;
 using base::UserMetricsAction;
 using content::NativeWebKeyboardEvent;
@@ -2031,6 +2029,13 @@
   GetWidget()->SetNativeWindowProperty(Profile::kProfileKey,
                                        browser_->profile());
 
+#if defined(USE_AURA)
+  // Stow a pointer to the browser's original profile onto the window handle so
+  // that windows will be styled with the appropriate NativeTheme.
+  SetThemeProfileForWindow(GetNativeWindow(),
+                           browser_->profile()->GetOriginalProfile());
+#endif
+
   LoadAccelerators();
 
   contents_web_view_ = new ContentsWebView(browser_->profile());
diff --git a/chrome/browser/ui/views/payments/editor_view_controller.cc b/chrome/browser/ui/views/payments/editor_view_controller.cc
index 38eeee77..2b4c1efce 100644
--- a/chrome/browser/ui/views/payments/editor_view_controller.cc
+++ b/chrome/browser/ui/views/payments/editor_view_controller.cc
@@ -18,6 +18,7 @@
 #include "components/payments/payment_request.h"
 #include "components/strings/grit/components_strings.h"
 #include "ui/base/l10n/l10n_util.h"
+#include "ui/native_theme/native_theme.h"
 #include "ui/views/border.h"
 #include "ui/views/controls/button/label_button.h"
 #include "ui/views/controls/button/md_text_button.h"
@@ -77,10 +78,34 @@
       std::move(content_view));
 }
 
+// Adds the "required fields" label in disabled text, to obtain this result.
+// +---------------------------------------------------------+
+// | "* indicates required fields"           | CANCEL | DONE |
+// +---------------------------------------------------------+
+std::unique_ptr<views::View> EditorViewController::CreateLeadingFooterView() {
+  std::unique_ptr<views::View> content_view = base::MakeUnique<views::View>();
+
+  views::BoxLayout* layout =
+      new views::BoxLayout(views::BoxLayout::kHorizontal, 0, 0, 0);
+  layout->set_main_axis_alignment(views::BoxLayout::MAIN_AXIS_ALIGNMENT_START);
+  layout->set_cross_axis_alignment(
+      views::BoxLayout::CROSS_AXIS_ALIGNMENT_START);
+  content_view->SetLayoutManager(layout);
+
+  // Adds the "* indicates a required field" label in "disabled" grey text.
+  std::unique_ptr<views::Label> label = base::MakeUnique<views::Label>(
+      l10n_util::GetStringUTF16(IDS_PAYMENTS_REQUIRED_FIELD_MESSAGE));
+  label->SetDisabledColor(label->GetNativeTheme()->GetSystemColor(
+      ui::NativeTheme::kColorId_LabelDisabledColor));
+  label->SetEnabled(false);
+  content_view->AddChildView(label.release());
+  return content_view;
+}
+
 std::unique_ptr<views::Button> EditorViewController::CreatePrimaryButton() {
   std::unique_ptr<views::Button> button(
       views::MdTextButton::CreateSecondaryUiBlueButton(
-          this, l10n_util::GetStringUTF16(IDS_PASSWORD_MANAGER_SAVE_BUTTON)));
+          this, l10n_util::GetStringUTF16(IDS_DONE)));
   button->set_tag(static_cast<int>(EditorViewControllerTags::SAVE_BUTTON));
   button->set_id(static_cast<int>(DialogViewID::EDITOR_SAVE_BUTTON));
   return button;
diff --git a/chrome/browser/ui/views/payments/editor_view_controller.h b/chrome/browser/ui/views/payments/editor_view_controller.h
index 09ab46d9..3001efd 100644
--- a/chrome/browser/ui/views/payments/editor_view_controller.h
+++ b/chrome/browser/ui/views/payments/editor_view_controller.h
@@ -82,6 +82,7 @@
 
   // PaymentRequestSheetController:
   std::unique_ptr<views::View> CreateView() override;
+  std::unique_ptr<views::View> CreateLeadingFooterView() override;
 
   virtual std::unique_ptr<views::View> CreateHeaderView() = 0;
   // Returns the field definitions used to build the UI.
diff --git a/chrome/browser/ui/views/payments/payment_request_sheet_controller.cc b/chrome/browser/ui/views/payments/payment_request_sheet_controller.cc
index 0df7ba0..09c3050f 100644
--- a/chrome/browser/ui/views/payments/payment_request_sheet_controller.cc
+++ b/chrome/browser/ui/views/payments/payment_request_sheet_controller.cc
@@ -13,7 +13,6 @@
 #include "ui/views/layout/box_layout.h"
 #include "ui/views/layout/grid_layout.h"
 
-
 namespace payments {
 
 PaymentRequestSheetController::PaymentRequestSheetController(
@@ -54,9 +53,7 @@
   views::GridLayout* layout = new views::GridLayout(view.get());
   view->SetLayoutManager(layout);
 
-  constexpr int kTopInsetSize = 9;
-  constexpr int kBottomInsetSize = 18;
-  layout->SetInsets(kTopInsetSize, 0, kBottomInsetSize, 0);
+  // Note: each view is responsible for its own padding (insets).
   views::ColumnSet* columns = layout->AddColumnSet(0);
   columns->AddColumn(views::GridLayout::FILL, views::GridLayout::CENTER,
                      1, views::GridLayout::USE_PREF, 0, 0);
@@ -89,24 +86,25 @@
   columns->AddColumn(views::GridLayout::TRAILING, views::GridLayout::CENTER,
                      0, views::GridLayout::USE_PREF, 0, 0);
 
+  // The horizontal distance between the right/left edges of the dialog and the
+  // elements.
+  constexpr int kFooterHorizontalInset = 16;
+  // The vertical distance between footer elements and the top/bottom border
+  // (the bottom border is the edge of the dialog).
+  constexpr int kFooterVerticalInset = 16;
+  layout->SetInsets(kFooterVerticalInset, kFooterHorizontalInset,
+                    kFooterVerticalInset, kFooterHorizontalInset);
+
   layout->StartRow(0, 0);
-  std::unique_ptr<views::View> leading_buttons_container =
-      base::MakeUnique<views::View>();
 
-  // TODO(anthonyvd): Add the other buttons that can eventually go into this
-  // footer.
-
-  layout->AddView(leading_buttons_container.release());
+  layout->AddView(CreateLeadingFooterView().release());
 
   std::unique_ptr<views::View> trailing_buttons_container =
       base::MakeUnique<views::View>();
 
   constexpr int kButtonSpacing = 10;
   trailing_buttons_container->SetLayoutManager(new views::BoxLayout(
-      views::BoxLayout::kHorizontal,
-      kPaymentRequestRowHorizontalInsets,
-      kPaymentRequestRowVerticalInsets,
-      kButtonSpacing));
+      views::BoxLayout::kHorizontal, 0, 0, kButtonSpacing));
 
   std::unique_ptr<views::Button> primary_button = CreatePrimaryButton();
   if (primary_button)
@@ -122,4 +120,9 @@
   return container;
 }
 
+std::unique_ptr<views::View>
+PaymentRequestSheetController::CreateLeadingFooterView() {
+  return base::MakeUnique<views::View>();
+}
+
 }  // namespace payments
diff --git a/chrome/browser/ui/views/payments/payment_request_sheet_controller.h b/chrome/browser/ui/views/payments/payment_request_sheet_controller.h
index a3d2497..d7c73e7 100644
--- a/chrome/browser/ui/views/payments/payment_request_sheet_controller.h
+++ b/chrome/browser/ui/views/payments/payment_request_sheet_controller.h
@@ -33,6 +33,9 @@
   ~PaymentRequestSheetController() override {}
 
   virtual std::unique_ptr<views::View> CreateView() = 0;
+  // A leading view to complement the button(s). See CreateFooterView for how
+  // this is used and what insets are already applied.
+  virtual std::unique_ptr<views::View> CreateLeadingFooterView();
 
   // The PaymentRequest object associated with this instance of the dialog.
   // Caller should not take ownership of the result.
diff --git a/chrome/browser/ui/views/payments/payment_request_views_util.cc b/chrome/browser/ui/views/payments/payment_request_views_util.cc
index 74e5b02..017a3ae 100644
--- a/chrome/browser/ui/views/payments/payment_request_views_util.cc
+++ b/chrome/browser/ui/views/payments/payment_request_views_util.cc
@@ -88,13 +88,23 @@
   std::unique_ptr<views::View> container = base::MakeUnique<views::View>();
   views::GridLayout* layout = new views::GridLayout(container.get());
   container->SetLayoutManager(layout);
-  layout->SetInsets(0, kPaymentRequestRowHorizontalInsets,
-                    0, kPaymentRequestRowHorizontalInsets);
+
+  constexpr int kHeaderTopVerticalInset = 14;
+  constexpr int kHeaderBottomVerticalInset = 8;
+  constexpr int kHeaderHorizontalInset = 16;
+  // Top, left, bottom, right.
+  layout->SetInsets(kHeaderTopVerticalInset, kHeaderHorizontalInset,
+                    kHeaderBottomVerticalInset, kHeaderHorizontalInset);
 
   views::ColumnSet* columns = layout->AddColumnSet(0);
   // A column for the optional back arrow.
   columns->AddColumn(views::GridLayout::LEADING, views::GridLayout::CENTER,
                      0, views::GridLayout::USE_PREF, 0, 0);
+
+  constexpr int kPaddingBetweenArrowAndTitle = 16;
+  if (show_back_arrow)
+    columns->AddPaddingColumn(0, kPaddingBetweenArrowAndTitle);
+
   // A column for the title.
   columns->AddColumn(views::GridLayout::FILL, views::GridLayout::CENTER,
                      1, views::GridLayout::USE_PREF, 0, 0);
@@ -105,7 +115,8 @@
   } else {
     views::VectorIconButton* back_arrow = new views::VectorIconButton(delegate);
     back_arrow->SetIcon(ui::kBackArrowIcon);
-    back_arrow->SetSize(back_arrow->GetPreferredSize());
+    constexpr int kBackArrowSize = 16;
+    back_arrow->SetSize(gfx::Size(kBackArrowSize, kBackArrowSize));
     back_arrow->set_tag(static_cast<int>(
         PaymentRequestCommonTags::BACK_BUTTON_TAG));
     layout->AddView(back_arrow);
@@ -113,6 +124,8 @@
 
   views::Label* title_label = new views::Label(title);
   title_label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
+  title_label->SetFontList(
+      title_label->GetDefaultFontList().DeriveWithSizeDelta(2));
   layout->AddView(title_label);
 
   return container;
diff --git a/chrome/browser/ui/views/payments/payment_request_views_util.h b/chrome/browser/ui/views/payments/payment_request_views_util.h
index 016e9c7..424771b 100644
--- a/chrome/browser/ui/views/payments/payment_request_views_util.h
+++ b/chrome/browser/ui/views/payments/payment_request_views_util.h
@@ -23,7 +23,7 @@
 
 namespace payments {
 
-constexpr int kPaymentRequestRowHorizontalInsets = 14;
+constexpr int kPaymentRequestRowHorizontalInsets = 16;
 constexpr int kPaymentRequestRowVerticalInsets = 8;
 // Extra inset relative to the header when a right edge should line up with the
 // close button's X rather than its invisible right edge.
@@ -40,10 +40,10 @@
 
 // Creates and returns a header for all the sheets in the PaymentRequest dialog.
 // The header contains an optional back arrow button (if |show_back_arrow| is
-// true), a |title| label, and a right-aligned X close button. |delegate|
-// becomes the delegate for the back and close buttons.
+// true), a |title| label. |delegate| becomes the delegate for the back and
+// close buttons.
 // +---------------------------+
-// | <- | Title            | X |
+// | <- | Title                |
 // +---------------------------+
 std::unique_ptr<views::View> CreateSheetHeaderView(
     bool show_back_arrow,
diff --git a/chrome/browser/ui/views/theme_profile_key.cc b/chrome/browser/ui/views/theme_profile_key.cc
new file mode 100644
index 0000000..e35d3da2
--- /dev/null
+++ b/chrome/browser/ui/views/theme_profile_key.cc
@@ -0,0 +1,24 @@
+// 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/theme_profile_key.h"
+
+#include "ui/aura/window.h"
+#include "ui/base/class_property.h"
+
+DECLARE_UI_CLASS_PROPERTY_TYPE(Profile*);
+
+namespace {
+
+DEFINE_UI_CLASS_PROPERTY_KEY(Profile*, kThemeProfileKey, nullptr);
+
+}  // anonymous namespace
+
+void SetThemeProfileForWindow(aura::Window* window, Profile* profile) {
+  window->SetProperty(kThemeProfileKey, profile);
+}
+
+Profile* GetThemeProfileForWindow(aura::Window* window) {
+  return window->GetProperty(kThemeProfileKey);
+}
diff --git a/chrome/browser/ui/views/theme_profile_key.h b/chrome/browser/ui/views/theme_profile_key.h
new file mode 100644
index 0000000..ce16480
--- /dev/null
+++ b/chrome/browser/ui/views/theme_profile_key.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 CHROME_BROWSER_UI_VIEWS_THEME_PROFILE_KEY_H_
+#define CHROME_BROWSER_UI_VIEWS_THEME_PROFILE_KEY_H_
+
+namespace aura {
+class Window;
+}
+
+class Profile;
+
+void SetThemeProfileForWindow(aura::Window* window, Profile* profile);
+Profile* GetThemeProfileForWindow(aura::Window*);
+
+#endif  // CHROME_BROWSER_UI_VIEWS_THEME_PROFILE_KEY_H_
diff --git a/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.cc
index 43e5176..d939564 100644
--- a/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.cc
@@ -35,6 +35,7 @@
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/chromeos/app_mode/kiosk_app_manager.h"
 #include "chrome/browser/chromeos/input_method/input_method_util.h"
+#include "chrome/browser/chromeos/language_preferences.h"
 #include "chrome/browser/chromeos/login/error_screens_histogram_helper.h"
 #include "chrome/browser/chromeos/login/hwid_checker.h"
 #include "chrome/browser/chromeos/login/lock/screen_locker.h"
@@ -1438,6 +1439,7 @@
         account_id);
   } else {
     SetUserInputMethod(account_id.GetUserEmail(), ime_state_.get());
+    SetKeyboardSettings(account_id);
     WallpaperManager::Get()->SetUserWallpaperDelayed(account_id);
 
     bool use_24hour_clock = false;
@@ -1613,4 +1615,32 @@
   }
 }
 
+void SigninScreenHandler::SetKeyboardSettings(const AccountId& account_id) {
+  bool auto_repeat_enabled = language_prefs::kXkbAutoRepeatEnabled;
+  if (user_manager::known_user::GetBooleanPref(
+          account_id, prefs::kLanguageXkbAutoRepeatEnabled,
+          &auto_repeat_enabled) &&
+      !auto_repeat_enabled) {
+    input_method::InputMethodManager::Get()
+        ->GetImeKeyboard()
+        ->SetAutoRepeatEnabled(false);
+    return;
+  }
+
+  int auto_repeat_delay = language_prefs::kXkbAutoRepeatDelayInMs;
+  int auto_repeat_interval = language_prefs::kXkbAutoRepeatIntervalInMs;
+  user_manager::known_user::GetIntegerPref(
+      account_id, prefs::kLanguageXkbAutoRepeatDelay, &auto_repeat_delay);
+  user_manager::known_user::GetIntegerPref(
+      account_id, prefs::kLanguageXkbAutoRepeatInterval, &auto_repeat_interval);
+  input_method::AutoRepeatRate rate;
+  rate.initial_delay_in_ms = auto_repeat_delay;
+  rate.repeat_interval_in_ms = auto_repeat_interval;
+  input_method::InputMethodManager::Get()
+      ->GetImeKeyboard()
+      ->SetAutoRepeatEnabled(true);
+  input_method::InputMethodManager::Get()->GetImeKeyboard()->SetAutoRepeatRate(
+      rate);
+}
+
 }  // namespace chromeos
diff --git a/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.h b/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.h
index b2e4f30..b978a55 100644
--- a/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.h
+++ b/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.h
@@ -441,6 +441,9 @@
   // Called when the cros property controlling allowed input methods changes.
   void OnAllowedInputMethodsChanged();
 
+  // Update the keyboard settings for |account_id|.
+  void SetKeyboardSettings(const AccountId& account_id);
+
   // Current UI state of the signin screen.
   UIState ui_state_ = UI_STATE_UNKNOWN;
 
diff --git a/chrome/test/data/safe_browsing/download_protection/navigation_observer/navigation_observer_tests.html b/chrome/test/data/safe_browsing/download_protection/navigation_observer/navigation_observer_tests.html
index 904b1c6..d8131247 100644
--- a/chrome/test/data/safe_browsing/download_protection/navigation_observer/navigation_observer_tests.html
+++ b/chrome/test/data/safe_browsing/download_protection/navigation_observer/navigation_observer_tests.html
@@ -53,7 +53,11 @@
                 fileEntry.createWriter(
                   function(writer){
                     writer.onwriteend = function(){
-                      window.location.href = fileEntry.toURL();
+                      var save_link = document.createElementNS("http://www.w3.org/1999/xhtml", "a");
+                      save_link.href = fileEntry.toURL();
+                      save_link.download = filename;
+                      var event = new MouseEvent("click");
+                      save_link.dispatchEvent(event);
                     };
                     writer.onerror = errorize;
                     writer.write(blob);
@@ -71,7 +75,6 @@
           },
           errorize);
     }
-
     </script>
   </head>
   <body>
@@ -121,15 +124,11 @@
 
     <script>
       var request = location.origin + "/server-redirect?" + location.origin +
-                    "/safe_browsing/download_protection/signed.exe"
+                    "/safe_browsing/download_protection/signed.exe";
       document.getElementById("new_tab_download_with_server_redirect")
               .setAttribute('href', request);
     </script>
 
-    <a id="html5_file_api" href="" onclick="downloadViaFileApi()">
-      Download via HTML5 file system API
-    </a><br>
-
     <a id="sub_frame_download_attribution" href="navigation_observer_multi_frame_tests.html">
       Download in subframe.
     </a><br>
@@ -141,5 +140,10 @@
     <a id="attribution_within_two_user_gestures" href="page_before_landing_referrer.html">
       Attribution should not trace back more than 2 user gestures.
     </a><br>
+
+    <button id="html5_file_api" onclick="downloadViaFileApi()">
+      Download via HTML5 file system API without trigger navigation
+    </button><br>
+
   </body>
 </html>
diff --git a/chrome/test/media_router/media_router_base_browsertest.cc b/chrome/test/media_router/media_router_base_browsertest.cc
index c482015e..9550333 100644
--- a/chrome/test/media_router/media_router_base_browsertest.cc
+++ b/chrome/test/media_router/media_router_base_browsertest.cc
@@ -21,8 +21,6 @@
 
 
 namespace {
-// Command line argument to specify CRX extension location.
-const char kExtensionCrx[] = "extension-crx";
 // Command line argument to specify unpacked extension location.
 const char kExtensionUnpacked[] = "extension-unpacked";
 }  // namespace
@@ -50,8 +48,8 @@
 
 void MediaRouterBaseBrowserTest::SetUpOnMainThread() {
   ExtensionBrowserTest::SetUpOnMainThread();
-  extensions::ProcessManager* process_manager =
-      extensions::ProcessManager::Get(browser()->profile());
+  extensions::ProcessManager* process_manager = extensions::ProcessManager::Get(
+      browser()->profile()->GetOriginalProfile());
   DCHECK(process_manager);
   process_manager->AddObserver(this);
   InstallAndEnableMRExtension();
@@ -68,12 +66,8 @@
 }
 
 void MediaRouterBaseBrowserTest::InstallAndEnableMRExtension() {
-  if (is_unpacked()) {
-    const extensions::Extension* extension = LoadExtension(extension_unpacked_);
-    extension_id_ = extension->id();
-  } else {
-    NOTIMPLEMENTED();
-  }
+  const extensions::Extension* extension = LoadExtension(extension_unpacked_);
+  extension_id_ = extension->id();
 }
 
 void MediaRouterBaseBrowserTest::UninstallMRExtension() {
@@ -117,12 +111,10 @@
 void MediaRouterBaseBrowserTest::ParseCommandLine() {
   DVLOG(0) << "ParseCommandLine";
   base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
-
-  extension_crx_ = command_line->GetSwitchValuePath(kExtensionCrx);
   extension_unpacked_ = command_line->GetSwitchValuePath(kExtensionUnpacked);
 
   // Check if there is mr_extension folder under PRODUCT_DIR folder.
-  if (extension_crx_.empty() && extension_unpacked_.empty()) {
+  if (extension_unpacked_.empty()) {
     base::FilePath base_dir;
     ASSERT_TRUE(PathService::Get(base::DIR_MODULE, &base_dir));
     base::FilePath extension_path =
@@ -132,8 +124,12 @@
     }
   }
 
-  // Exactly one of these two arguments should be provided.
-  ASSERT_NE(extension_crx_.empty(), extension_unpacked_.empty());
+  // An unpacked component extension must be provided.
+  ASSERT_FALSE(extension_unpacked_.empty());
+}
+
+Browser* MediaRouterBaseBrowserTest::browser() {
+  return ExtensionBrowserTest::browser();
 }
 
 }  // namespace media_router
diff --git a/chrome/test/media_router/media_router_base_browsertest.h b/chrome/test/media_router/media_router_base_browsertest.h
index cbfc9e52..ab63b78 100644
--- a/chrome/test/media_router/media_router_base_browsertest.h
+++ b/chrome/test/media_router/media_router_base_browsertest.h
@@ -43,8 +43,8 @@
   void SetUpOnMainThread() override;
   void TearDownOnMainThread() override;
 
-  void InstallAndEnableMRExtension();
-  void UninstallMRExtension();
+  virtual void InstallAndEnableMRExtension();
+  virtual void UninstallMRExtension();
 
   virtual void ParseCommandLine();
 
@@ -61,14 +61,15 @@
   // Wait for a specific time.
   void Wait(base::TimeDelta timeout);
 
-  bool is_unpacked() const { return !extension_unpacked_.empty(); }
-
   bool is_extension_host_created() const { return extension_host_created_; }
 
   bool is_incognito() { return profile()->IsOffTheRecord(); }
 
-  // These values are initialized via flags.
-  base::FilePath extension_crx_;
+  // Returns the superclass' browser(). Marked virtual so that it can be
+  // overridden by MediaRouterIntegrationIncognitoBrowserTest.
+  virtual Browser* browser();
+
+  // |extension_unpacked_| is initialized via a flag.
   base::FilePath extension_unpacked_;
 
   base::WaitableEvent extension_load_event_;
diff --git a/chrome/test/media_router/media_router_integration_browsertest.cc b/chrome/test/media_router/media_router_integration_browsertest.cc
index 35fb3ec..301e668 100644
--- a/chrome/test/media_router/media_router_integration_browsertest.cc
+++ b/chrome/test/media_router/media_router_integration_browsertest.cc
@@ -28,6 +28,7 @@
 #include "net/base/filename_util.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
+using content::WebContents;
 
 namespace media_router {
 
@@ -45,7 +46,10 @@
 const char kStartSessionScript[] = "startSession();";
 const char kTerminateSessionScript[] =
     "terminateSessionAndWaitForStateChange();";
-const char kWaitDeviceScript[] = "waitUntilDeviceAvailable();";
+const char kCloseSessionScript[] = "closeConnectionAndWaitForStateChange();";
+const char kReconnectSessionScript[] = "reconnectSession('%s');";
+const char kCheckSendMessageFailedScript[] = "checkSendMessageFailed('%s');";
+const char kWaitSinkScript[] = "waitUntilDeviceAvailable();";
 const char kSendMessageAndExpectResponseScript[] =
     "sendMessageAndExpectResponse('%s');";
 const char kSendMessageAndExpectConnectionCloseOnErrorScript[] =
@@ -104,7 +108,7 @@
     "}"
     "domAutomationController.send(false);";
 
-std::string GetStartedConnectionId(content::WebContents* web_contents) {
+std::string GetStartedConnectionId(WebContents* web_contents) {
   std::string session_id;
   CHECK(content::ExecuteScriptAndExtractString(
       web_contents, "window.domAutomationController.send(startedConnection.id)",
@@ -112,7 +116,7 @@
   return session_id;
 }
 
-std::string GetDefaultRequestSessionId(content::WebContents* web_contents) {
+std::string GetDefaultRequestSessionId(WebContents* web_contents) {
   std::string session_id;
   CHECK(content::ExecuteScriptAndExtractString(
       web_contents,
@@ -135,7 +139,7 @@
 }
 
 void MediaRouterIntegrationBrowserTest::ExecuteJavaScriptAPI(
-    content::WebContents* web_contents,
+    WebContents* web_contents,
     const std::string& script) {
   std::string result(ExecuteScriptAndExtractString(web_contents, script));
 
@@ -158,6 +162,32 @@
   ASSERT_TRUE(passed) << error_message;
 }
 
+WebContents* MediaRouterIntegrationBrowserTest::StartSessionWithTestPageNow() {
+  OpenTestPage(FILE_PATH_LITERAL("basic_test.html"));
+  WebContents* web_contents = GetActiveWebContents();
+  CHECK(web_contents);
+  StartSession(web_contents);
+  return web_contents;
+}
+
+WebContents*
+MediaRouterIntegrationBrowserTest::StartSessionWithTestPageAndSink() {
+  OpenTestPage(FILE_PATH_LITERAL("basic_test.html"));
+  WebContents* web_contents = GetActiveWebContents();
+  CHECK(web_contents);
+  ExecuteJavaScriptAPI(web_contents, kWaitSinkScript);
+  StartSession(web_contents);
+  return web_contents;
+}
+
+WebContents*
+MediaRouterIntegrationBrowserTest::StartSessionWithTestPageAndChooseSink() {
+  WebContents* web_contents = StartSessionWithTestPageAndSink();
+  WaitUntilSinkDiscoveredOnUI();
+  ChooseSink(web_contents, kTestSinkName);
+  return web_contents;
+}
+
 void MediaRouterIntegrationBrowserTest::OpenTestPage(
     base::FilePath::StringPieceType file_name) {
   base::FilePath full_path = GetResourceFile(file_name);
@@ -174,7 +204,7 @@
 }
 
 void MediaRouterIntegrationBrowserTest::StartSession(
-    content::WebContents* web_contents) {
+    WebContents* web_contents) {
   test_navigation_observer_.reset(
       new content::TestNavigationObserver(web_contents, 1));
   test_navigation_observer_->StartWatchingNewWebContents();
@@ -184,9 +214,9 @@
 }
 
 void MediaRouterIntegrationBrowserTest::ChooseSink(
-    content::WebContents* web_contents,
+    WebContents* web_contents,
     const std::string& sink_name) {
-  content::WebContents* dialog_contents = GetMRDialog(web_contents);
+  WebContents* dialog_contents = GetMRDialog(web_contents);
   std::string script = base::StringPrintf(
       kChooseSinkScript, sink_name.c_str());
   // Execute javascript to choose sink, but don't wait until it finishes.
@@ -195,7 +225,7 @@
 }
 
 void MediaRouterIntegrationBrowserTest::CheckStartFailed(
-    content::WebContents* web_contents,
+    WebContents* web_contents,
     const std::string& error_name,
     const std::string& error_message_substring) {
   std::string script(base::StringPrintf(kCheckStartFailedScript,
@@ -205,30 +235,29 @@
 }
 
 void MediaRouterIntegrationBrowserTest::ClickDialog() {
-  content::WebContents* web_contents =
-      browser()->tab_strip_model()->GetActiveWebContents();
-  content::WebContents* dialog_contents = GetMRDialog(web_contents);
+  WebContents* web_contents = GetActiveWebContents();
+  WebContents* dialog_contents = GetMRDialog(web_contents);
   ASSERT_TRUE(content::ExecuteScript(dialog_contents, kClickDialog));
 }
-content::WebContents* MediaRouterIntegrationBrowserTest::GetMRDialog(
-    content::WebContents* web_contents) {
+WebContents* MediaRouterIntegrationBrowserTest::GetMRDialog(
+    WebContents* web_contents) {
   MediaRouterDialogControllerImpl* controller =
       MediaRouterDialogControllerImpl::GetOrCreateForWebContents(web_contents);
-  content::WebContents* dialog_contents = controller->GetMediaRouterDialog();
+  WebContents* dialog_contents = controller->GetMediaRouterDialog();
   CHECK(dialog_contents);
   WaitUntilDialogFullyLoaded(dialog_contents);
   return dialog_contents;
 }
 
 bool MediaRouterIntegrationBrowserTest::IsDialogClosed(
-    content::WebContents* web_contents) {
+    WebContents* web_contents) {
   MediaRouterDialogControllerImpl* controller =
       MediaRouterDialogControllerImpl::GetOrCreateForWebContents(web_contents);
   return !controller->GetMediaRouterDialog();
 }
 
 void MediaRouterIntegrationBrowserTest::WaitUntilDialogClosed(
-    content::WebContents* web_contents) {
+    WebContents* web_contents) {
   ASSERT_TRUE(ConditionalWait(
       base::TimeDelta::FromSeconds(5), base::TimeDelta::FromSeconds(1),
       base::Bind(&MediaRouterIntegrationBrowserTest::IsDialogClosed,
@@ -236,7 +265,7 @@
 }
 
 void MediaRouterIntegrationBrowserTest::CheckDialogRemainsOpen(
-    content::WebContents* web_contents) {
+    WebContents* web_contents) {
   ASSERT_FALSE(ConditionalWait(
       base::TimeDelta::FromSeconds(5), base::TimeDelta::FromSeconds(1),
       base::Bind(&MediaRouterIntegrationBrowserTest::IsDialogClosed,
@@ -260,8 +289,8 @@
                          test_data_str.c_str()));
 }
 
-content::WebContents* MediaRouterIntegrationBrowserTest::OpenMRDialog(
-    content::WebContents* web_contents) {
+WebContents* MediaRouterIntegrationBrowserTest::OpenMRDialog(
+    WebContents* web_contents) {
   MediaRouterDialogControllerImpl* controller =
       MediaRouterDialogControllerImpl::GetOrCreateForWebContents(web_contents);
   test_navigation_observer_.reset(
@@ -270,7 +299,7 @@
   CHECK(controller->ShowMediaRouterDialog());
   test_navigation_observer_->Wait();
   test_navigation_observer_->StopWatchingNewWebContents();
-  content::WebContents* dialog_contents = controller->GetMediaRouterDialog();
+  WebContents* dialog_contents = controller->GetMediaRouterDialog();
   CHECK(dialog_contents);
   WaitUntilDialogFullyLoaded(dialog_contents);
   return dialog_contents;
@@ -320,9 +349,8 @@
 
 std::string MediaRouterIntegrationBrowserTest::GetRouteId(
     const std::string& sink_name) {
-  content::WebContents* web_contents =
-      browser()->tab_strip_model()->GetActiveWebContents();
-  content::WebContents* dialog_contents = GetMRDialog(web_contents);
+  WebContents* web_contents = GetActiveWebContents();
+  WebContents* dialog_contents = GetMRDialog(web_contents);
   std::string script = base::StringPrintf(kGetSinkIdScript, sink_name.c_str());
   std::string sink_id = ExecuteScriptAndExtractString(dialog_contents, script);
   DVLOG(0) << "sink id: " << sink_id;
@@ -340,9 +368,8 @@
 }
 
 bool MediaRouterIntegrationBrowserTest::IsUIShowingIssue() {
-  content::WebContents* web_contents =
-      browser()->tab_strip_model()->GetActiveWebContents();
-  content::WebContents* dialog_contents = GetMRDialog(web_contents);
+  WebContents* web_contents = GetActiveWebContents();
+  WebContents* dialog_contents = GetMRDialog(web_contents);
   std::string script = base::StringPrintf(
       "domAutomationController.send(window.document.getElementById("
       "'media-router-container').issue != undefined)");
@@ -360,9 +387,8 @@
 }
 
 std::string MediaRouterIntegrationBrowserTest::GetIssueTitle() {
-  content::WebContents* web_contents =
-      browser()->tab_strip_model()->GetActiveWebContents();
-  content::WebContents* dialog_contents = GetMRDialog(web_contents);
+  WebContents* web_contents = GetActiveWebContents();
+  WebContents* dialog_contents = GetMRDialog(web_contents);
   std::string script = base::StringPrintf(
       "domAutomationController.send(window.document.getElementById("
       "'media-router-container').issue.title)");
@@ -373,11 +399,10 @@
   // After execute js script to close route on UI, the dialog will dispear
   // after 3s. But sometimes it takes more than 3s to close the route, so
   // we need to re-open the dialog if it is closed.
-  content::WebContents* web_contents =
-      browser()->tab_strip_model()->GetActiveWebContents();
+  WebContents* web_contents = GetActiveWebContents();
   MediaRouterDialogControllerImpl* controller =
       MediaRouterDialogControllerImpl::GetOrCreateForWebContents(web_contents);
-  content::WebContents* dialog_contents = controller->GetMediaRouterDialog();
+  WebContents* dialog_contents = controller->GetMediaRouterDialog();
   if (!dialog_contents) {
     VLOG(0) << "Media router dialog was closed, reopen it again.";
     OpenMRDialog(web_contents);
@@ -386,9 +411,8 @@
 }
 
 void MediaRouterIntegrationBrowserTest::CloseRouteOnUI() {
-  content::WebContents* web_contents =
-      browser()->tab_strip_model()->GetActiveWebContents();
-  content::WebContents* dialog_contents = GetMRDialog(web_contents);
+  WebContents* web_contents = GetActiveWebContents();
+  WebContents* dialog_contents = GetMRDialog(web_contents);
   ASSERT_TRUE(content::ExecuteScript(dialog_contents, kCloseRouteScript));
   ASSERT_TRUE(ConditionalWait(
       base::TimeDelta::FromSeconds(10), base::TimeDelta::FromSeconds(1),
@@ -397,9 +421,8 @@
 }
 
 bool MediaRouterIntegrationBrowserTest::IsSinkDiscoveredOnUI() {
-  content::WebContents* web_contents =
-        browser()->tab_strip_model()->GetActiveWebContents();
-  content::WebContents* dialog_contents = GetMRDialog(web_contents);
+  WebContents* web_contents = GetActiveWebContents();
+  WebContents* dialog_contents = GetMRDialog(web_contents);
   std::string script = base::StringPrintf(kFindSinkScript, receiver().c_str());
   return ExecuteScriptAndExtractBool(dialog_contents, script);
 }
@@ -414,12 +437,12 @@
 }
 
 bool MediaRouterIntegrationBrowserTest::IsDialogLoaded(
-    content::WebContents* dialog_contents) {
+    WebContents* dialog_contents) {
   return ExecuteScriptAndExtractBool(dialog_contents, kCheckDialogLoadedScript);
 }
 
 void MediaRouterIntegrationBrowserTest::WaitUntilDialogFullyLoaded(
-    content::WebContents* dialog_contents) {
+    WebContents* dialog_contents) {
   ASSERT_TRUE(ConditionalWait(
       base::TimeDelta::FromSeconds(30), base::TimeDelta::FromSeconds(1),
       base::Bind(&MediaRouterIntegrationBrowserTest::IsDialogLoaded,
@@ -435,105 +458,38 @@
     receiver_ = kTestSinkName;
 }
 
-IN_PROC_BROWSER_TEST_F(MediaRouterIntegrationBrowserTest, MANUAL_Basic) {
-  OpenTestPage(FILE_PATH_LITERAL("basic_test.html"));
-  content::WebContents* web_contents =
-      browser()->tab_strip_model()->GetActiveWebContents();
-  ASSERT_TRUE(web_contents);
-  ExecuteJavaScriptAPI(web_contents, kWaitDeviceScript);
-  StartSession(web_contents);
-  WaitUntilSinkDiscoveredOnUI();
-  ChooseSink(web_contents, kTestSinkName);
+void MediaRouterIntegrationBrowserTest::CheckSessionValidity(
+    WebContents* web_contents) {
   ExecuteJavaScriptAPI(web_contents, kCheckSessionScript);
   std::string session_id(GetStartedConnectionId(web_contents));
   EXPECT_FALSE(session_id.empty());
-
   std::string default_request_session_id(
       GetDefaultRequestSessionId(web_contents));
   EXPECT_EQ(session_id, default_request_session_id);
+}
 
+MediaRouterDialogControllerImpl*
+MediaRouterIntegrationBrowserTest::GetControllerForShownDialog(
+    WebContents* web_contents) {
+  MediaRouterDialogControllerImpl* controller =
+      MediaRouterDialogControllerImpl::GetOrCreateForWebContents(web_contents);
+  EXPECT_TRUE(controller->IsShowingMediaRouterDialog());
+  return controller;
+}
+
+WebContents* MediaRouterIntegrationBrowserTest::GetActiveWebContents() {
+  return browser()->tab_strip_model()->GetActiveWebContents();
+}
+
+void MediaRouterIntegrationBrowserTest::RunBasicTest() {
+  WebContents* web_contents = StartSessionWithTestPageAndChooseSink();
+  CheckSessionValidity(web_contents);
   ExecuteJavaScriptAPI(web_contents, kTerminateSessionScript);
 }
 
-IN_PROC_BROWSER_TEST_F(MediaRouterIntegrationBrowserTest,
-                       MANUAL_SendAndOnMessage) {
-  OpenTestPage(FILE_PATH_LITERAL("basic_test.html"));
-  content::WebContents* web_contents =
-      browser()->tab_strip_model()->GetActiveWebContents();
-  ASSERT_TRUE(web_contents);
-  ExecuteJavaScriptAPI(web_contents, kWaitDeviceScript);
-  StartSession(web_contents);
-  WaitUntilSinkDiscoveredOnUI();
-  ChooseSink(web_contents, kTestSinkName);
-  ExecuteJavaScriptAPI(web_contents, kCheckSessionScript);
-  std::string session_id(GetStartedConnectionId(web_contents));
-  EXPECT_FALSE(session_id.empty());
-
-  ExecuteJavaScriptAPI(
-      web_contents,
-      base::StringPrintf(kSendMessageAndExpectResponseScript, "foo"));
-}
-
-IN_PROC_BROWSER_TEST_F(MediaRouterIntegrationBrowserTest, MANUAL_OnClose) {
-  SetTestData(FILE_PATH_LITERAL("close_route_with_error_on_send.json"));
-  OpenTestPage(FILE_PATH_LITERAL("basic_test.html"));
-  content::WebContents* web_contents =
-      browser()->tab_strip_model()->GetActiveWebContents();
-  ASSERT_TRUE(web_contents);
-  ExecuteJavaScriptAPI(web_contents, kWaitDeviceScript);
-  StartSession(web_contents);
-  WaitUntilSinkDiscoveredOnUI();
-  ChooseSink(web_contents, kTestSinkName);
-  ExecuteJavaScriptAPI(web_contents, kCheckSessionScript);
-  std::string session_id(GetStartedConnectionId(web_contents));
-  EXPECT_FALSE(session_id.empty());
-
-  ExecuteJavaScriptAPI(
-      web_contents,
-      base::StringPrintf("%s",
-                         kSendMessageAndExpectConnectionCloseOnErrorScript));
-}
-
-IN_PROC_BROWSER_TEST_F(MediaRouterIntegrationBrowserTest,
-                       MANUAL_Fail_NoProvider) {
-  SetTestData(FILE_PATH_LITERAL("no_provider.json"));
-  OpenTestPage(FILE_PATH_LITERAL("basic_test.html"));
-  content::WebContents* web_contents =
-      browser()->tab_strip_model()->GetActiveWebContents();
-  ASSERT_TRUE(web_contents);
-  ExecuteJavaScriptAPI(web_contents, kWaitDeviceScript);
-  StartSession(web_contents);
-  WaitUntilSinkDiscoveredOnUI();
-  ChooseSink(web_contents, kTestSinkName);
-  CheckStartFailed(web_contents, "UnknownError",
-      "No provider supports createRoute with source");
-}
-
-IN_PROC_BROWSER_TEST_F(MediaRouterIntegrationBrowserTest,
-                       MANUAL_Fail_CreateRoute) {
-  SetTestData(FILE_PATH_LITERAL("fail_create_route.json"));
-  OpenTestPage(FILE_PATH_LITERAL("basic_test.html"));
-  content::WebContents* web_contents =
-      browser()->tab_strip_model()->GetActiveWebContents();
-  ASSERT_TRUE(web_contents);
-  ExecuteJavaScriptAPI(web_contents, kWaitDeviceScript);
-  StartSession(web_contents);
-  WaitUntilSinkDiscoveredOnUI();
-  ChooseSink(web_contents, kTestSinkName);
-  CheckStartFailed(web_contents, "UnknownError", "Unknown sink");
-}
-
-IN_PROC_BROWSER_TEST_F(MediaRouterIntegrationBrowserTest,
-                       MANUAL_ReconnectSession) {
-  OpenTestPage(FILE_PATH_LITERAL("basic_test.html"));
-  content::WebContents* web_contents =
-      browser()->tab_strip_model()->GetActiveWebContents();
-  ASSERT_TRUE(web_contents);
-  ExecuteJavaScriptAPI(web_contents, kWaitDeviceScript);
-  StartSession(web_contents);
-  WaitUntilSinkDiscoveredOnUI();
-  ChooseSink(web_contents, kTestSinkName);
-  ExecuteJavaScriptAPI(web_contents, kCheckSessionScript);
+void MediaRouterIntegrationBrowserTest::RunReconnectSessionTest() {
+  WebContents* web_contents = StartSessionWithTestPageAndChooseSink();
+  CheckSessionValidity(web_contents);
   std::string session_id(GetStartedConnectionId(web_contents));
 
   // Wait a few seconds for MediaRouter to receive updates containing the
@@ -541,13 +497,12 @@
   Wait(base::TimeDelta::FromSeconds(3));
 
   OpenTestPageInNewTab(FILE_PATH_LITERAL("basic_test.html"));
-  content::WebContents* new_web_contents =
-      browser()->tab_strip_model()->GetActiveWebContents();
+  WebContents* new_web_contents = GetActiveWebContents();
   ASSERT_TRUE(new_web_contents);
   ASSERT_NE(web_contents, new_web_contents);
   ExecuteJavaScriptAPI(
       new_web_contents,
-      base::StringPrintf("reconnectSession('%s');", session_id.c_str()));
+      base::StringPrintf(kReconnectSessionScript, session_id.c_str()));
   std::string reconnected_session_id;
   ASSERT_TRUE(content::ExecuteScriptAndExtractString(
       new_web_contents,
@@ -556,18 +511,64 @@
   ASSERT_EQ(session_id, reconnected_session_id);
 }
 
+IN_PROC_BROWSER_TEST_F(MediaRouterIntegrationBrowserTest, MANUAL_Basic) {
+  RunBasicTest();
+}
+
+IN_PROC_BROWSER_TEST_F(MediaRouterIntegrationBrowserTest,
+                       MANUAL_SendAndOnMessage) {
+  WebContents* web_contents = StartSessionWithTestPageAndChooseSink();
+  CheckSessionValidity(web_contents);
+  ExecuteJavaScriptAPI(
+      web_contents,
+      base::StringPrintf(kSendMessageAndExpectResponseScript, "foo"));
+}
+
+IN_PROC_BROWSER_TEST_F(MediaRouterIntegrationBrowserTest, MANUAL_CloseOnError) {
+  SetTestData(FILE_PATH_LITERAL("close_route_with_error_on_send.json"));
+  WebContents* web_contents = StartSessionWithTestPageAndChooseSink();
+  CheckSessionValidity(web_contents);
+  ExecuteJavaScriptAPI(web_contents,
+                       kSendMessageAndExpectConnectionCloseOnErrorScript);
+}
+
+IN_PROC_BROWSER_TEST_F(MediaRouterIntegrationBrowserTest,
+                       MANUAL_Fail_SendMessage) {
+  WebContents* web_contents = StartSessionWithTestPageAndChooseSink();
+  CheckSessionValidity(web_contents);
+  ExecuteJavaScriptAPI(web_contents, kCloseSessionScript);
+
+  // Wait a few seconds for MediaRouter to receive status updates.
+  Wait(base::TimeDelta::FromSeconds(3));
+  ExecuteJavaScriptAPI(
+      web_contents,
+      base::StringPrintf(kCheckSendMessageFailedScript, "closed"));
+}
+
+IN_PROC_BROWSER_TEST_F(MediaRouterIntegrationBrowserTest,
+                       MANUAL_Fail_NoProvider) {
+  SetTestData(FILE_PATH_LITERAL("no_provider.json"));
+  WebContents* web_contents = StartSessionWithTestPageAndChooseSink();
+  CheckStartFailed(web_contents, "UnknownError",
+                   "No provider supports createRoute with source");
+}
+
+IN_PROC_BROWSER_TEST_F(MediaRouterIntegrationBrowserTest,
+                       MANUAL_Fail_CreateRoute) {
+  SetTestData(FILE_PATH_LITERAL("fail_create_route.json"));
+  WebContents* web_contents = StartSessionWithTestPageAndChooseSink();
+  CheckStartFailed(web_contents, "UnknownError", "Unknown sink");
+}
+
+IN_PROC_BROWSER_TEST_F(MediaRouterIntegrationBrowserTest,
+                       MANUAL_ReconnectSession) {
+  RunReconnectSessionTest();
+}
+
 IN_PROC_BROWSER_TEST_F(MediaRouterIntegrationBrowserTest,
                        MANUAL_Fail_ReconnectSession) {
-  OpenTestPage(FILE_PATH_LITERAL("basic_test.html"));
-  content::WebContents* web_contents =
-      browser()->tab_strip_model()->GetActiveWebContents();
-  ASSERT_TRUE(web_contents);
-  ExecuteJavaScriptAPI(web_contents, kWaitDeviceScript);
-  content::TestNavigationObserver test_navigation_observer(web_contents, 1);
-  StartSession(web_contents);
-  WaitUntilSinkDiscoveredOnUI();
-  ChooseSink(web_contents, kTestSinkName);
-  ExecuteJavaScriptAPI(web_contents, kCheckSessionScript);
+  WebContents* web_contents = StartSessionWithTestPageAndChooseSink();
+  CheckSessionValidity(web_contents);
   std::string session_id(GetStartedConnectionId(web_contents));
 
   // Wait a few seconds for MediaRouter to receive updates containing the
@@ -575,9 +576,8 @@
   Wait(base::TimeDelta::FromSeconds(3));
 
   SetTestData(FILE_PATH_LITERAL("fail_reconnect_session.json"));
-  OpenTestPage(FILE_PATH_LITERAL("fail_reconnect_session.html"));
-  content::WebContents* new_web_contents =
-      browser()->tab_strip_model()->GetActiveWebContents();
+  OpenTestPageInNewTab(FILE_PATH_LITERAL("fail_reconnect_session.html"));
+  WebContents* new_web_contents = GetActiveWebContents();
   ASSERT_TRUE(new_web_contents);
   ExecuteJavaScriptAPI(
       new_web_contents,
@@ -587,54 +587,54 @@
 
 IN_PROC_BROWSER_TEST_F(MediaRouterIntegrationBrowserTest,
                        MANUAL_Fail_StartCancelled) {
-  OpenTestPage(FILE_PATH_LITERAL("basic_test.html"));
-  content::WebContents* web_contents =
-      browser()->tab_strip_model()->GetActiveWebContents();
-  ASSERT_TRUE(web_contents);
-  ExecuteJavaScriptAPI(web_contents, kWaitDeviceScript);
-  content::TestNavigationObserver test_navigation_observer(web_contents, 1);
-  StartSession(web_contents);
-
-  MediaRouterDialogControllerImpl* controller =
-      MediaRouterDialogControllerImpl::GetOrCreateForWebContents(web_contents);
-  EXPECT_TRUE(controller->IsShowingMediaRouterDialog());
-  controller->HideMediaRouterDialog();
+  WebContents* web_contents = StartSessionWithTestPageAndSink();
+  GetControllerForShownDialog(web_contents)->HideMediaRouterDialog();
   CheckStartFailed(web_contents, "NotAllowedError", "Dialog closed.");
 }
 
 IN_PROC_BROWSER_TEST_F(MediaRouterIntegrationBrowserTest,
                        MANUAL_Fail_StartCancelledNoSinks) {
   SetTestData(FILE_PATH_LITERAL("no_sinks.json"));
-  OpenTestPage(FILE_PATH_LITERAL("basic_test.html"));
-  content::WebContents* web_contents =
-      browser()->tab_strip_model()->GetActiveWebContents();
-  ASSERT_TRUE(web_contents);
-  content::TestNavigationObserver test_navigation_observer(web_contents, 1);
-  StartSession(web_contents);
-
-  MediaRouterDialogControllerImpl* controller =
-      MediaRouterDialogControllerImpl::GetOrCreateForWebContents(web_contents);
-  EXPECT_TRUE(controller->IsShowingMediaRouterDialog());
-  controller->HideMediaRouterDialog();
+  WebContents* web_contents = StartSessionWithTestPageNow();
+  GetControllerForShownDialog(web_contents)->HideMediaRouterDialog();
   CheckStartFailed(web_contents, "NotFoundError", "No screens found.");
 }
 
 IN_PROC_BROWSER_TEST_F(MediaRouterIntegrationBrowserTest,
                        MANUAL_Fail_StartCancelledNoSupportedSinks) {
   SetTestData(FILE_PATH_LITERAL("no_supported_sinks.json"));
-  OpenTestPage(FILE_PATH_LITERAL("basic_test.html"));
-  content::WebContents* web_contents =
-      browser()->tab_strip_model()->GetActiveWebContents();
-  ASSERT_TRUE(web_contents);
-  content::TestNavigationObserver test_navigation_observer(web_contents, 1);
-  StartSession(web_contents);
-
-  MediaRouterDialogControllerImpl* controller =
-      MediaRouterDialogControllerImpl::GetOrCreateForWebContents(web_contents);
-  EXPECT_TRUE(controller->IsShowingMediaRouterDialog());
+  WebContents* web_contents = StartSessionWithTestPageNow();
   WaitUntilSinkDiscoveredOnUI();
-  controller->HideMediaRouterDialog();
+  GetControllerForShownDialog(web_contents)->HideMediaRouterDialog();
   CheckStartFailed(web_contents, "NotFoundError", "No screens found.");
 }
 
+void MediaRouterIntegrationIncognitoBrowserTest::InstallAndEnableMRExtension() {
+  const extensions::Extension* extension =
+      LoadExtensionIncognito(extension_unpacked_);
+  incognito_extension_id_ = extension->id();
+}
+
+void MediaRouterIntegrationIncognitoBrowserTest::UninstallMRExtension() {
+  if (!incognito_extension_id_.empty()) {
+    UninstallExtension(incognito_extension_id_);
+  }
+}
+
+Browser* MediaRouterIntegrationIncognitoBrowserTest::browser() {
+  if (!incognito_browser_)
+    incognito_browser_ = CreateIncognitoBrowser();
+  return incognito_browser_;
+}
+
+IN_PROC_BROWSER_TEST_F(MediaRouterIntegrationIncognitoBrowserTest,
+                       MANUAL_Basic) {
+  RunBasicTest();
+}
+
+IN_PROC_BROWSER_TEST_F(MediaRouterIntegrationIncognitoBrowserTest,
+                       MANUAL_ReconnectSession) {
+  RunReconnectSessionTest();
+}
+
 }  // namespace media_router
diff --git a/chrome/test/media_router/media_router_integration_browsertest.h b/chrome/test/media_router/media_router_integration_browsertest.h
index 37fd02f..c55a8b79 100644
--- a/chrome/test/media_router/media_router_integration_browsertest.h
+++ b/chrome/test/media_router/media_router_integration_browsertest.h
@@ -74,6 +74,17 @@
 
   void CheckDialogRemainsOpen(content::WebContents* web_contents);
 
+  // Opens "basic_test.html," and starts a session.
+  content::WebContents* StartSessionWithTestPageNow();
+  // Opens "basic_test.html," waits for sinks to be available, and starts a
+  // session.
+  content::WebContents* StartSessionWithTestPageAndSink();
+
+  // Opens "basic_test.html," waits for sinks to be available, starts a session,
+  // and chooses a sink with the name |kTestSinkName|. Also checks that the
+  // session has successfully started if |should_succeed| is true.
+  content::WebContents* StartSessionWithTestPageAndChooseSink();
+
   void OpenTestPage(base::FilePath::StringPieceType file);
   void OpenTestPageInNewTab(base::FilePath::StringPieceType file);
 
@@ -125,6 +136,26 @@
   // Wait until media router dialog is fully loaded.
   void WaitUntilDialogFullyLoaded(content::WebContents* dialog_contents);
 
+  // Checks that the session started for |web_contents| has connected and is the
+  // default session.
+  void CheckSessionValidity(content::WebContents* web_contents);
+
+  // Checks that a Media Router dialog is shown for |web_contents|, and returns
+  // its controller.
+  MediaRouterDialogControllerImpl* GetControllerForShownDialog(
+      content::WebContents* web_contents);
+
+  // Returns the active WebContents for the current window.
+  content::WebContents* GetActiveWebContents();
+
+  // Runs a basic test in which a session is created through the MediaRouter
+  // dialog, then terminated.
+  void RunBasicTest();
+
+  // Runs a test in which we start a session and reconnect to it from another
+  // tab.
+  void RunReconnectSessionTest();
+
   std::string receiver() const { return receiver_; }
 
  private:
@@ -141,6 +172,18 @@
   std::string receiver_;
 };
 
+class MediaRouterIntegrationIncognitoBrowserTest
+    : public MediaRouterIntegrationBrowserTest {
+ public:
+  void InstallAndEnableMRExtension() override;
+  void UninstallMRExtension() override;
+  Browser* browser() override;
+
+ private:
+  Browser* incognito_browser_ = nullptr;
+  std::string incognito_extension_id_;
+};
+
 }  // namespace media_router
 
 #endif  // CHROME_TEST_MEDIA_ROUTER_MEDIA_ROUTER_INTEGRATION_BROWSERTEST_H_
diff --git a/chrome/test/media_router/resources/common.js b/chrome/test/media_router/resources/common.js
index d7f4241..9e69d91 100644
--- a/chrome/test/media_router/resources/common.js
+++ b/chrome/test/media_router/resources/common.js
@@ -30,7 +30,7 @@
 };
 
 /**
- * Waits until one device is available.
+ * Waits until one sink is available.
  */
 function waitUntilDeviceAvailable() {
   startSessionRequest.getAvailability(presentationUrl).then(
@@ -44,8 +44,8 @@
           sendResult(true, '');
       }
     }
-  }).catch(function(){
-    sendResult(false, 'got error');
+  }).catch(function(e) {
+    sendResult(false, 'got error: ' + e);
   });
 }
 
@@ -140,6 +140,49 @@
   }
 }
 
+/**
+ * Closes |startedConnection| and waits for its onclose event.
+ */
+function closeConnectionAndWaitForStateChange() {
+  if (startedConnection) {
+    if (startedConnection.state == 'closed') {
+      sendResult(false, 'startedConnection is unexpectedly closed.');
+    }
+    startedConnection.onclose = function() {
+      sendResult(true, '');
+    };
+    startedConnection.close();
+  } else {
+    sendResult(false, 'startedConnection does not exist.');
+  }
+}
+
+/**
+ * Sends a message to |startedConnection| and expects InvalidStateError to be
+ * thrown. Requires |startedConnection.state| to not equal |initialState|.
+ */
+function checkSendMessageFailed(initialState) {
+  if (!startedConnection) {
+    sendResult(false, 'startedConnection does not exist.');
+    return;
+  }
+  if (startedConnection.state != initialState) {
+    sendResult(false, 'startedConnection.state is "' + startedConnection.state +
+               '", but we expected "' + initialState + '".');
+    return;
+  }
+
+  try {
+    startedConnection.send('test message');
+  } catch (e) {
+    if (e.name == 'InvalidStateError') {
+      sendResult(true, '');
+    } else {
+      sendResult(false, 'Got an unexpected error: ' + e.name);
+    }
+  }
+  sendResult(false, 'Expected InvalidStateError but it was never thrown.');
+}
 
 /**
  * Sends a message, and expects the connection to close on error.
diff --git a/chromeos/dbus/fake_session_manager_client.cc b/chromeos/dbus/fake_session_manager_client.cc
index 253609d2..5cc0066 100644
--- a/chromeos/dbus/fake_session_manager_client.cc
+++ b/chromeos/dbus/fake_session_manager_client.cc
@@ -189,7 +189,12 @@
       FROM_HERE, base::Bind(callback, arc_available_));
 }
 
-void FakeSessionManagerClient::EmitArcBooted() {}
+void FakeSessionManagerClient::EmitArcBooted(
+    const cryptohome::Identification& cryptohome_id,
+    const ArcCallback& callback) {
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE, base::Bind(callback, arc_available_));
+}
 
 void FakeSessionManagerClient::GetArcStartTime(
     const GetArcStartTimeCallback& callback) {
diff --git a/chromeos/dbus/fake_session_manager_client.h b/chromeos/dbus/fake_session_manager_client.h
index 89bcf87..237cf7c 100644
--- a/chromeos/dbus/fake_session_manager_client.h
+++ b/chromeos/dbus/fake_session_manager_client.h
@@ -74,7 +74,8 @@
   void SetArcCpuRestriction(
       login_manager::ContainerCpuRestrictionState restriction_state,
       const ArcCallback& callback) override;
-  void EmitArcBooted() override;
+  void EmitArcBooted(const cryptohome::Identification& cryptohome_id,
+                     const ArcCallback& callback) override;
   void GetArcStartTime(const GetArcStartTimeCallback& callback) override;
   void RemoveArcData(const cryptohome::Identification& cryptohome_id,
                      const ArcCallback& callback) override;
diff --git a/chromeos/dbus/mock_session_manager_client.h b/chromeos/dbus/mock_session_manager_client.h
index 627498c5..8fd00570 100644
--- a/chromeos/dbus/mock_session_manager_client.h
+++ b/chromeos/dbus/mock_session_manager_client.h
@@ -73,7 +73,8 @@
   MOCK_METHOD2(SetArcCpuRestriction,
                void(login_manager::ContainerCpuRestrictionState,
                     const ArcCallback&));
-  MOCK_METHOD0(EmitArcBooted, void(void));
+  MOCK_METHOD2(EmitArcBooted,
+               void(const cryptohome::Identification&, const ArcCallback&));
   MOCK_METHOD1(GetArcStartTime, void(const GetArcStartTimeCallback&));
   MOCK_METHOD2(RemoveArcData,
                void(const cryptohome::Identification&, const ArcCallback&));
diff --git a/chromeos/dbus/session_manager_client.cc b/chromeos/dbus/session_manager_client.cc
index 02d0a1b..dd5c642a 100644
--- a/chromeos/dbus/session_manager_client.cc
+++ b/chromeos/dbus/session_manager_client.cc
@@ -362,9 +362,17 @@
                    callback));
   }
 
-  void EmitArcBooted() override {
-    SimpleMethodCallToSessionManager(
-        login_manager::kSessionManagerEmitArcBooted);
+  void EmitArcBooted(const cryptohome::Identification& cryptohome_id,
+                     const ArcCallback& callback) override {
+    dbus::MethodCall method_call(login_manager::kSessionManagerInterface,
+                                 login_manager::kSessionManagerEmitArcBooted);
+    dbus::MessageWriter writer(&method_call);
+    writer.AppendString(cryptohome_id.id());
+    session_manager_proxy_->CallMethod(
+        &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
+        base::Bind(&SessionManagerClientImpl::OnArcMethod,
+                   weak_ptr_factory_.GetWeakPtr(),
+                   login_manager::kSessionManagerEmitArcBooted, callback));
   }
 
   void GetArcStartTime(const GetArcStartTimeCallback& callback) override {
@@ -962,7 +970,10 @@
     callback.Run(false);
   }
 
-  void EmitArcBooted() override {}
+  void EmitArcBooted(const cryptohome::Identification& cryptohome_id,
+                     const ArcCallback& callback) override {
+    callback.Run(false);
+  }
 
   void StopArcInstance(const ArcCallback& callback) override {
     callback.Run(false);
diff --git a/chromeos/dbus/session_manager_client.h b/chromeos/dbus/session_manager_client.h
index 781143e..372890a4 100644
--- a/chromeos/dbus/session_manager_client.h
+++ b/chromeos/dbus/session_manager_client.h
@@ -270,7 +270,8 @@
       const ArcCallback& callback) = 0;
 
   // Emits the "arc-booted" upstart signal.
-  virtual void EmitArcBooted() = 0;
+  virtual void EmitArcBooted(const cryptohome::Identification& cryptohome_id,
+                             const ArcCallback& callback) = 0;
 
   // Asynchronously retrieves the timestamp which ARC instance is invoked or
   // returns false if there is no ARC instance or ARC is not available.
diff --git a/components/subresource_filter/content/browser/BUILD.gn b/components/subresource_filter/content/browser/BUILD.gn
index b55d108..6388aab 100644
--- a/components/subresource_filter/content/browser/BUILD.gn
+++ b/components/subresource_filter/content/browser/BUILD.gn
@@ -6,8 +6,6 @@
   sources = [
     "content_ruleset_service_delegate.cc",
     "content_ruleset_service_delegate.h",
-    "content_subresource_filter_driver.cc",
-    "content_subresource_filter_driver.h",
     "content_subresource_filter_driver_factory.cc",
     "content_subresource_filter_driver_factory.h",
     "verified_ruleset_dealer.cc",
diff --git a/components/subresource_filter/content/browser/content_subresource_filter_driver.cc b/components/subresource_filter/content/browser/content_subresource_filter_driver.cc
deleted file mode 100644
index 59714f1..0000000
--- a/components/subresource_filter/content/browser/content_subresource_filter_driver.cc
+++ /dev/null
@@ -1,29 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/subresource_filter/content/browser/content_subresource_filter_driver.h"
-
-#include "components/subresource_filter/content/common/subresource_filter_messages.h"
-#include "content/public/browser/render_frame_host.h"
-
-namespace subresource_filter {
-
-ContentSubresourceFilterDriver::ContentSubresourceFilterDriver(
-    content::RenderFrameHost* render_frame_host)
-    : render_frame_host_(render_frame_host) {}
-
-ContentSubresourceFilterDriver::~ContentSubresourceFilterDriver() {}
-
-void ContentSubresourceFilterDriver::ActivateForNextCommittedLoad(
-    ActivationLevel activation_level,
-    bool measure_performance) {
-  // Must use legacy IPC to ensure the activation message arrives in-order, i.e.
-  // before the load is committed on the renderer side.
-  render_frame_host_->Send(
-      new SubresourceFilterMsg_ActivateForNextCommittedLoad(
-          render_frame_host_->GetRoutingID(), activation_level,
-          measure_performance));
-}
-
-}  // namespace subresource_filter
diff --git a/components/subresource_filter/content/browser/content_subresource_filter_driver.h b/components/subresource_filter/content/browser/content_subresource_filter_driver.h
deleted file mode 100644
index f194dc79..0000000
--- a/components/subresource_filter/content/browser/content_subresource_filter_driver.h
+++ /dev/null
@@ -1,39 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_SUBRESOURCE_FILTER_CONTENT_BROWSER_CONTENT_SUBRESOURCE_FILTER_DRIVER_H_
-#define COMPONENTS_SUBRESOURCE_FILTER_CONTENT_BROWSER_CONTENT_SUBRESOURCE_FILTER_DRIVER_H_
-
-#include "base/macros.h"
-#include "components/subresource_filter/core/common/activation_level.h"
-
-namespace content {
-class RenderFrameHost;
-}  // namespace content
-
-namespace subresource_filter {
-
-// The content-layer-specific driver for the subresource filter component. There
-// is one instance per RenderFrameHost.
-class ContentSubresourceFilterDriver {
- public:
-  explicit ContentSubresourceFilterDriver(
-      content::RenderFrameHost* render_frame_host);
-  virtual ~ContentSubresourceFilterDriver();
-
-  // Instructs the agent on the renderer side to set up subresource filtering at
-  // the specified |activation_level| for the next load committed in this frame.
-  virtual void ActivateForNextCommittedLoad(ActivationLevel activation_level,
-                                            bool measure_performance);
-
- private:
-  // The RenderFrameHost that this driver belongs to.
-  content::RenderFrameHost* render_frame_host_;
-
-  DISALLOW_COPY_AND_ASSIGN(ContentSubresourceFilterDriver);
-};
-
-}  // namespace subresource_filter
-
-#endif  // COMPONENTS_SUBRESOURCE_FILTER_CONTENT_BROWSER_CONTENT_SUBRESOURCE_FILTER_DRIVER_H_
diff --git a/components/subresource_filter/content/browser/content_subresource_filter_driver_factory.cc b/components/subresource_filter/content/browser/content_subresource_filter_driver_factory.cc
index b7b6509..12b21a1 100644
--- a/components/subresource_filter/content/browser/content_subresource_filter_driver_factory.cc
+++ b/components/subresource_filter/content/browser/content_subresource_filter_driver_factory.cc
@@ -7,7 +7,6 @@
 #include "base/metrics/histogram_macros.h"
 #include "base/rand_util.h"
 #include "base/time/time.h"
-#include "components/subresource_filter/content/browser/content_subresource_filter_driver.h"
 #include "components/subresource_filter/content/common/subresource_filter_messages.h"
 #include "components/subresource_filter/core/browser/subresource_filter_client.h"
 #include "components/subresource_filter/core/browser/subresource_filter_features.h"
@@ -77,25 +76,11 @@
     : content::WebContentsObserver(web_contents),
       client_(std::move(client)),
       activation_level_(ActivationLevel::DISABLED),
-      measure_performance_(false) {
-  content::RenderFrameHost* main_frame_host = web_contents->GetMainFrame();
-  if (main_frame_host && main_frame_host->IsRenderFrameLive())
-    CreateDriverForFrameHostIfNeeded(main_frame_host);
-}
+      measure_performance_(false) {}
 
 ContentSubresourceFilterDriverFactory::
     ~ContentSubresourceFilterDriverFactory() {}
 
-void ContentSubresourceFilterDriverFactory::CreateDriverForFrameHostIfNeeded(
-    content::RenderFrameHost* render_frame_host) {
-  auto iterator_and_inserted =
-      frame_drivers_.insert(std::make_pair(render_frame_host, nullptr));
-  if (iterator_and_inserted.second) {
-    iterator_and_inserted.first->second.reset(
-        new ContentSubresourceFilterDriver(render_frame_host));
-  }
-}
-
 void ContentSubresourceFilterDriverFactory::OnFirstSubresourceLoadDisallowed() {
   if (ShouldSuppressNotifications())
     return;
@@ -179,10 +164,10 @@
   // filtering for the subsequent error page load. This is probably harmless,
   // but not sending an activation message is even cleaner.
   if (activation_level_ != ActivationLevel::DISABLED && !failed_navigation) {
-    auto* driver = DriverFromFrameHost(render_frame_host);
-    DCHECK(driver);
-    driver->ActivateForNextCommittedLoad(GetMaximumActivationLevel(),
-                                         measure_performance_);
+    render_frame_host->Send(
+        new SubresourceFilterMsg_ActivateForNextCommittedLoad(
+            render_frame_host->GetRoutingID(), activation_level_,
+            measure_performance_));
   }
 }
 
@@ -193,21 +178,6 @@
   web_contents()->GetController().Reload(content::ReloadType::NORMAL, true);
 }
 
-void ContentSubresourceFilterDriverFactory::SetDriverForFrameHostForTesting(
-    content::RenderFrameHost* render_frame_host,
-    std::unique_ptr<ContentSubresourceFilterDriver> driver) {
-  auto iterator_and_inserted =
-      frame_drivers_.insert(std::make_pair(render_frame_host, nullptr));
-  iterator_and_inserted.first->second = std::move(driver);
-}
-
-ContentSubresourceFilterDriver*
-ContentSubresourceFilterDriverFactory::DriverFromFrameHost(
-    content::RenderFrameHost* render_frame_host) {
-  auto iterator = frame_drivers_.find(render_frame_host);
-  return iterator == frame_drivers_.end() ? nullptr : iterator->second.get();
-}
-
 void ContentSubresourceFilterDriverFactory::ResetActivationState() {
   navigation_chain_.clear();
   activation_list_matches_.clear();
@@ -232,16 +202,6 @@
     navigation_chain_.push_back(navigation_handle->GetURL());
 }
 
-void ContentSubresourceFilterDriverFactory::RenderFrameCreated(
-    content::RenderFrameHost* render_frame_host) {
-  CreateDriverForFrameHostIfNeeded(render_frame_host);
-}
-
-void ContentSubresourceFilterDriverFactory::RenderFrameDeleted(
-    content::RenderFrameHost* render_frame_host) {
-  frame_drivers_.erase(render_frame_host);
-}
-
 void ContentSubresourceFilterDriverFactory::ReadyToCommitNavigation(
     content::NavigationHandle* navigation_handle) {
   DCHECK(!navigation_handle->IsSamePage());
diff --git a/components/subresource_filter/content/browser/content_subresource_filter_driver_factory.h b/components/subresource_filter/content/browser/content_subresource_filter_driver_factory.h
index 0572c0b..06e8544da 100644
--- a/components/subresource_filter/content/browser/content_subresource_filter_driver_factory.h
+++ b/components/subresource_filter/content/browser/content_subresource_filter_driver_factory.h
@@ -31,7 +31,6 @@
 
 namespace subresource_filter {
 
-class ContentSubresourceFilterDriver;
 class SubresourceFilterClient;
 enum class ActivationLevel;
 enum class ActivationList;
@@ -41,7 +40,8 @@
     std::unordered_map<std::string, std::set<ActivationList>>;
 
 // Controls the activation of subresource filtering for each page load in a
-// WebContents and manufactures the per-frame ContentSubresourceFilterDrivers.
+// WebContents and is responsible for sending the activation signal to all the
+// per-frame SubresourceFilterAgents on the renderer side.
 class ContentSubresourceFilterDriverFactory
     : public base::SupportsUserData::Data,
       public content::WebContentsObserver {
@@ -79,19 +79,6 @@
   friend class ContentSubresourceFilterDriverFactoryTest;
   friend class safe_browsing::SafeBrowsingServiceTest;
 
-  typedef std::map<content::RenderFrameHost*,
-                   std::unique_ptr<ContentSubresourceFilterDriver>>
-      FrameHostToOwnedDriverMap;
-
-  void SetDriverForFrameHostForTesting(
-      content::RenderFrameHost* render_frame_host,
-      std::unique_ptr<ContentSubresourceFilterDriver> driver);
-
-  void CreateDriverForFrameHostIfNeeded(
-      content::RenderFrameHost* render_frame_host);
-  ContentSubresourceFilterDriver* DriverFromFrameHost(
-      content::RenderFrameHost* render_frame_host);
-
   void ResetActivationState();
 
   void OnFirstSubresourceLoadDisallowed();
@@ -105,8 +92,6 @@
       content::NavigationHandle* navigation_handle) override;
   void DidRedirectNavigation(
       content::NavigationHandle* navigation_handle) override;
-  void RenderFrameCreated(content::RenderFrameHost* render_frame_host) override;
-  void RenderFrameDeleted(content::RenderFrameHost* render_frame_host) override;
   void ReadyToCommitNavigation(
       content::NavigationHandle* navigation_handle) override;
   void DidFinishLoad(content::RenderFrameHost* render_frame_host,
@@ -135,7 +120,6 @@
   void AddActivationListMatch(const GURL& url, ActivationList match_type);
   void RecordRedirectChainMatchPattern() const;
 
-  FrameHostToOwnedDriverMap frame_drivers_;
   std::unique_ptr<SubresourceFilterClient> client_;
 
   HostPathSet whitelisted_hosts_;
diff --git a/components/subresource_filter/content/renderer/subresource_filter_agent.h b/components/subresource_filter/content/renderer/subresource_filter_agent.h
index 7e3c99e..3269183d 100644
--- a/components/subresource_filter/content/renderer/subresource_filter_agent.h
+++ b/components/subresource_filter/content/renderer/subresource_filter_agent.h
@@ -23,10 +23,10 @@
 class UnverifiedRulesetDealer;
 class WebDocumentSubresourceFilterImpl;
 
-// The renderer-side agent of the ContentSubresourceFilterDriver. There is one
-// instance per RenderFrame, responsible for setting up the subresource filter
-// for the ongoing provisional document load in the frame when instructed to do
-// so by the driver.
+// The renderer-side agent of ContentSubresourceFilterDriverFactory. There is
+// one instance per RenderFrame, responsible for setting up the subresource
+// filter for the ongoing provisional document load in the frame when instructed
+// to do so by the driver.
 class SubresourceFilterAgent
     : public content::RenderFrameObserver,
       public base::SupportsWeakPtr<SubresourceFilterAgent> {
diff --git a/content/child/runtime_features.cc b/content/child/runtime_features.cc
index 3285accb..c2ac56c 100644
--- a/content/child/runtime_features.cc
+++ b/content/child/runtime_features.cc
@@ -209,6 +209,9 @@
   if (command_line.HasSwitch(switches::kEnableWebVR))
     WebRuntimeFeatures::enableWebVR(true);
 
+  WebRuntimeFeatures::enableWebVRExperimentalRendering(
+      base::FeatureList::IsEnabled(features::kWebVRExperimentalRendering));
+
   if (command_line.HasSwitch(switches::kDisablePresentationAPI))
     WebRuntimeFeatures::enablePresentationAPI(false);
 
diff --git a/content/public/common/content_features.cc b/content/public/common/content_features.cc
index 0c3057a..97ab33f 100644
--- a/content/public/common/content_features.cc
+++ b/content/public/common/content_features.cc
@@ -259,6 +259,10 @@
 // https://wicg.github.io/webusb
 const base::Feature kWebUsb{"WebUSB", base::FEATURE_ENABLED_BY_DEFAULT};
 
+// Enables WebVR experimental rendering optimizations.
+const base::Feature kWebVRExperimentalRendering{
+    "WebVRExperimentalRendering", base::FEATURE_DISABLED_BY_DEFAULT};
+
 // Make sendBeacon throw for a Blob with a non simple type.
 const base::Feature kSendBeaconThrowForBlobWithNonSimpleType{
     "SendBeaconThrowForBlobWithNonSimpleType",
diff --git a/content/public/common/content_features.h b/content/public/common/content_features.h
index f447a60..5875a89 100644
--- a/content/public/common/content_features.h
+++ b/content/public/common/content_features.h
@@ -68,6 +68,7 @@
 CONTENT_EXPORT extern const base::Feature kWebRtcUseEchoCanceller3;
 CONTENT_EXPORT extern const base::Feature kWebRtcUseGpuMemoryBufferVideoFrames;
 CONTENT_EXPORT extern const base::Feature kWebUsb;
+CONTENT_EXPORT extern const base::Feature kWebVRExperimentalRendering;
 CONTENT_EXPORT
 extern const base::Feature kSendBeaconThrowForBlobWithNonSimpleType;
 
diff --git a/content/renderer/renderer_blink_platform_impl.cc b/content/renderer/renderer_blink_platform_impl.cc
index 02cff756..ed61cd8 100644
--- a/content/renderer/renderer_blink_platform_impl.cc
+++ b/content/renderer/renderer_blink_platform_impl.cc
@@ -1013,13 +1013,16 @@
 
   bool is_software_rendering = gpu_channel_host->gpu_info().software_rendering;
 
-  // This is an offscreen context, which doesn't use the default frame buffer,
-  // so don't request any alpha, depth, stencil, antialiasing.
+  // This is an offscreen context. Generally it won't use the default
+  // frame buffer, in that case don't request any alpha, depth, stencil,
+  // antialiasing. But we do need those attributes for the "own
+  // offscreen surface" optimization which supports directly drawing
+  // to a custom surface backed frame buffer.
   gpu::gles2::ContextCreationAttribHelper attributes;
-  attributes.alpha_size = -1;
-  attributes.depth_size = 0;
-  attributes.stencil_size = 0;
-  attributes.samples = 0;
+  attributes.alpha_size = web_attributes.supportAlpha ? 8 : -1;
+  attributes.depth_size = web_attributes.supportDepth ? 24 : 0;
+  attributes.stencil_size = web_attributes.supportStencil ? 8 : 0;
+  attributes.samples = web_attributes.supportAntialias ? 4 : 0;
   attributes.sample_buffers = 0;
   attributes.bind_generates_resource = false;
   // Prefer discrete GPU for WebGL.
diff --git a/extensions/browser/content_hash_fetcher.cc b/extensions/browser/content_hash_fetcher.cc
index 7962630b..1f73cb6 100644
--- a/extensions/browser/content_hash_fetcher.cc
+++ b/extensions/browser/content_hash_fetcher.cc
@@ -18,8 +18,7 @@
 #include "base/memory/ref_counted.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/synchronization/lock.h"
-#include "base/task_runner_util.h"
-#include "base/threading/sequenced_worker_pool.h"
+#include "base/task_scheduler/post_task.h"
 #include "base/timer/elapsed_timer.h"
 #include "base/version.h"
 #include "content/public/browser/browser_thread.h"
@@ -196,11 +195,10 @@
 void ContentHashFetcherJob::Start() {
   base::FilePath verified_contents_path =
       file_util::GetVerifiedContentsPath(extension_path_);
-  base::PostTaskAndReplyWithResult(
-      content::BrowserThread::GetBlockingPool(),
-      FROM_HERE,
-      base::Bind(&ContentHashFetcherJob::LoadVerifiedContents,
-                 this,
+  base::PostTaskWithTraitsAndReplyWithResult(
+      FROM_HERE, base::TaskTraits().MayBlock().WithPriority(
+                     base::TaskPriority::USER_VISIBLE),
+      base::Bind(&ContentHashFetcherJob::LoadVerifiedContents, this,
                  verified_contents_path),
       base::Bind(&ContentHashFetcherJob::DoneCheckingForVerifiedContents,
                  this));
@@ -289,12 +287,12 @@
     base::FilePath destination =
         file_util::GetVerifiedContentsPath(extension_path_);
     size_t size = response->size();
-    base::PostTaskAndReplyWithResult(
-        content::BrowserThread::GetBlockingPool(),
-        FROM_HERE,
+    base::PostTaskWithTraitsAndReplyWithResult(
+        FROM_HERE, base::TaskTraits().MayBlock().WithPriority(
+                       base::TaskPriority::USER_VISIBLE),
         base::Bind(&WriteFileHelper, destination, base::Passed(&response)),
-        base::Bind(
-            &ContentHashFetcherJob::OnVerifiedContentsWritten, this, size));
+        base::Bind(&ContentHashFetcherJob::OnVerifiedContentsWritten, this,
+                   size));
   } else {
     DoneFetchingVerifiedContents(false);
   }
diff --git a/extensions/browser/extension_icon_image_unittest.cc b/extensions/browser/extension_icon_image_unittest.cc
index e48afcf..5b624c0a 100644
--- a/extensions/browser/extension_icon_image_unittest.cc
+++ b/extensions/browser/extension_icon_image_unittest.cc
@@ -12,7 +12,7 @@
 #include "base/path_service.h"
 #include "base/run_loop.h"
 #include "content/public/test/test_browser_context.h"
-#include "content/public/test/test_browser_thread.h"
+#include "content/public/test/test_browser_thread_bundle.h"
 #include "extensions/browser/extensions_test.h"
 #include "extensions/browser/image_loader.h"
 #include "extensions/browser/test_image_loader.h"
@@ -26,8 +26,6 @@
 #include "ui/gfx/image/image_skia_source.h"
 #include "ui/gfx/skia_util.h"
 
-using content::BrowserThread;
-
 namespace extensions {
 namespace {
 
@@ -71,11 +69,7 @@
                                public IconImage::Observer {
  public:
   ExtensionIconImageTest()
-      : image_loaded_count_(0),
-        quit_in_image_loaded_(false),
-        ui_thread_(BrowserThread::UI, &ui_loop_),
-        file_thread_(BrowserThread::FILE),
-        io_thread_(BrowserThread::IO) {}
+      : image_loaded_count_(0), quit_in_image_loaded_(false) {}
 
   ~ExtensionIconImageTest() override {}
 
@@ -119,12 +113,6 @@
                              Extension::NO_FLAGS, &error);
   }
 
-  // testing::Test overrides:
-  void SetUp() override {
-    file_thread_.Start();
-    io_thread_.Start();
-  }
-
   // IconImage::Delegate overrides:
   void OnExtensionIconImageChanged(IconImage* image) override {
     image_loaded_count_++;
@@ -137,12 +125,9 @@
   }
 
  private:
+  content::TestBrowserThreadBundle test_browser_thread_bundle_;
   int image_loaded_count_;
   bool quit_in_image_loaded_;
-  base::MessageLoop ui_loop_;
-  content::TestBrowserThread ui_thread_;
-  content::TestBrowserThread file_thread_;
-  content::TestBrowserThread io_thread_;
 
   DISALLOW_COPY_AND_ASSIGN(ExtensionIconImageTest);
 };
diff --git a/extensions/browser/image_loader.cc b/extensions/browser/image_loader.cc
index 7326163..c2b1fff 100644
--- a/extensions/browser/image_loader.cc
+++ b/extensions/browser/image_loader.cc
@@ -13,6 +13,7 @@
 #include "base/compiler_specific.h"
 #include "base/files/file_util.h"
 #include "base/strings/string_number_conversions.h"
+#include "base/task_scheduler/post_task.h"
 #include "base/threading/sequenced_worker_pool.h"
 #include "content/public/browser/browser_thread.h"
 #include "extensions/browser/component_extension_resource_manager.h"
@@ -76,10 +77,8 @@
   *bitmap = *image.bitmap();
 }
 
-void LoadImageOnBlockingPool(const ImageLoader::ImageRepresentation& image_info,
-                             SkBitmap* bitmap) {
-  DCHECK(BrowserThread::GetBlockingPool()->RunsTasksOnCurrentThread());
-
+void LoadImageBlocking(const ImageLoader::ImageRepresentation& image_info,
+                       SkBitmap* bitmap) {
   // Read the file from disk.
   std::string file_contents;
   base::FilePath path = image_info.resource.GetFilePath();
@@ -175,10 +174,9 @@
 namespace {
 
 // Need to be after ImageRepresentation and LoadResult are defined.
-std::vector<ImageLoader::LoadResult> LoadImagesOnBlockingPool(
+std::vector<ImageLoader::LoadResult> LoadImagesBlocking(
     const std::vector<ImageLoader::ImageRepresentation>& info_list,
     const std::vector<SkBitmap>& bitmaps) {
-  DCHECK(BrowserThread::GetBlockingPool()->RunsTasksOnCurrentThread());
   std::vector<ImageLoader::LoadResult> load_result;
 
   for (size_t i = 0; i < info_list.size(); ++i) {
@@ -190,7 +188,7 @@
 
     SkBitmap bitmap;
     if (bitmaps[i].isNull())
-      LoadImageOnBlockingPool(image, &bitmap);
+      LoadImageBlocking(image, &bitmap);
     else
       bitmap = bitmaps[i];
 
@@ -268,14 +266,13 @@
     const ImageLoaderImageCallback& callback) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   DCHECK(!BrowserThread::GetBlockingPool()->RunsTasksOnCurrentThread());
-  base::PostTaskAndReplyWithResult(
-      BrowserThread::GetBlockingPool(),
-      FROM_HERE,
-      base::Bind(LoadImagesOnBlockingPool,
-                 info_list,
+  base::PostTaskWithTraitsAndReplyWithResult(
+      FROM_HERE, base::TaskTraits().MayBlock().WithPriority(
+                     base::TaskPriority::USER_VISIBLE),
+      base::Bind(LoadImagesBlocking, info_list,
                  LoadResourceBitmaps(extension, info_list)),
-      base::Bind(
-          &ImageLoader::ReplyBack, weak_ptr_factory_.GetWeakPtr(), callback));
+      base::Bind(&ImageLoader::ReplyBack, weak_ptr_factory_.GetWeakPtr(),
+                 callback));
 }
 
 void ImageLoader::LoadImageFamilyAsync(
@@ -284,15 +281,13 @@
     const ImageLoaderImageFamilyCallback& callback) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   DCHECK(!BrowserThread::GetBlockingPool()->RunsTasksOnCurrentThread());
-  base::PostTaskAndReplyWithResult(
-      BrowserThread::GetBlockingPool(),
-      FROM_HERE,
-      base::Bind(LoadImagesOnBlockingPool,
-                 info_list,
+  base::PostTaskWithTraitsAndReplyWithResult(
+      FROM_HERE, base::TaskTraits().MayBlock().WithPriority(
+                     base::TaskPriority::USER_VISIBLE),
+      base::Bind(LoadImagesBlocking, info_list,
                  LoadResourceBitmaps(extension, info_list)),
       base::Bind(&ImageLoader::ReplyBackWithImageFamily,
-                 weak_ptr_factory_.GetWeakPtr(),
-                 callback));
+                 weak_ptr_factory_.GetWeakPtr(), callback));
 }
 
 void ImageLoader::ReplyBack(const ImageLoaderImageCallback& callback,
diff --git a/extensions/browser/image_loader_unittest.cc b/extensions/browser/image_loader_unittest.cc
index 5f1afc0..fe21d30 100644
--- a/extensions/browser/image_loader_unittest.cc
+++ b/extensions/browser/image_loader_unittest.cc
@@ -14,7 +14,7 @@
 #include "base/run_loop.h"
 #include "base/strings/string_util.h"
 #include "content/public/test/test_browser_context.h"
-#include "content/public/test/test_browser_thread.h"
+#include "content/public/test/test_browser_thread_bundle.h"
 #include "extensions/browser/extension_registry.h"
 #include "extensions/browser/extensions_browser_client.h"
 #include "extensions/browser/extensions_test.h"
@@ -32,18 +32,11 @@
 #include "ui/gfx/image/image_family.h"
 #include "ui/gfx/image/image_skia.h"
 
-using content::BrowserThread;
-
 namespace extensions {
 
 class ImageLoaderTest : public ExtensionsTest {
  public:
-  ImageLoaderTest()
-      : image_loaded_count_(0),
-        quit_in_image_loaded_(false),
-        ui_thread_(BrowserThread::UI, &ui_loop_),
-        file_thread_(BrowserThread::FILE),
-        io_thread_(BrowserThread::IO) {}
+  ImageLoaderTest() : image_loaded_count_(0), quit_in_image_loaded_(false) {}
 
   void OnImageLoaded(const gfx::Image& image) {
     image_loaded_count_++;
@@ -103,18 +96,9 @@
   gfx::ImageFamily image_family_;
 
  private:
-  void SetUp() override {
-    testing::Test::SetUp();
-    file_thread_.Start();
-    io_thread_.Start();
-  }
-
+  content::TestBrowserThreadBundle test_browser_thread_bundle_;
   int image_loaded_count_;
   bool quit_in_image_loaded_;
-  base::MessageLoop ui_loop_;
-  content::TestBrowserThread ui_thread_;
-  content::TestBrowserThread file_thread_;
-  content::TestBrowserThread io_thread_;
 };
 
 // Tests loading an image works correctly.
diff --git a/gpu/ipc/service/gpu_command_buffer_stub.cc b/gpu/ipc/service/gpu_command_buffer_stub.cc
index 9222b38..6977c82 100644
--- a/gpu/ipc/service/gpu_command_buffer_stub.cc
+++ b/gpu/ipc/service/gpu_command_buffer_stub.cc
@@ -634,7 +634,32 @@
   decoder_->set_engine(executor_.get());
 
   if (offscreen) {
-    surface_ = default_surface;
+    if (init_params.attribs.depth_size > 0) {
+      surface_format.SetDepthBits(init_params.attribs.depth_size);
+    }
+    if (init_params.attribs.samples > 0) {
+      surface_format.SetSamples(init_params.attribs.samples);
+    }
+    if (init_params.attribs.stencil_size > 0) {
+      surface_format.SetStencilBits(init_params.attribs.stencil_size);
+    }
+    // Currently, we can't separately control alpha channel for surfaces,
+    // it's generally enabled by default except for RGB565 and (on desktop)
+    // smaller-than-32bit formats.
+    //
+    // TODO(klausw): use init_params.attribs.alpha_size here if possible.
+    if (!surface_format.IsCompatible(default_surface->GetFormat())) {
+      DVLOG(1) << __FUNCTION__ << ": Hit the OwnOffscreenSurface path";
+      use_virtualized_gl_context_ = false;
+      surface_ = gl::init::CreateOffscreenGLSurfaceWithFormat(gfx::Size(),
+                                                              surface_format);
+      if (!surface_) {
+        DLOG(ERROR) << "Failed to create surface.";
+        return false;
+      }
+    } else {
+      surface_ = default_surface;
+    }
   } else {
     surface_ = ImageTransportSurface::CreateNativeSurface(
         AsWeakPtr(), surface_handle_, surface_format);
diff --git a/services/ui/demo/BUILD.gn b/services/ui/demo/BUILD.gn
index f49992d..837da1f 100644
--- a/services/ui/demo/BUILD.gn
+++ b/services/ui/demo/BUILD.gn
@@ -12,6 +12,8 @@
   sources = [
     "mus_demo.cc",
     "mus_demo.h",
+    "mus_demo_internal.cc",
+    "mus_demo_internal.h",
     "window_tree_data.cc",
     "window_tree_data.h",
   ]
diff --git a/services/ui/demo/main.cc b/services/ui/demo/main.cc
index ecf56bd..20142861 100644
--- a/services/ui/demo/main.cc
+++ b/services/ui/demo/main.cc
@@ -4,9 +4,9 @@
 
 #include "services/service_manager/public/c/main.h"
 #include "services/service_manager/public/cpp/service_runner.h"
-#include "services/ui/demo/mus_demo.h"
+#include "services/ui/demo/mus_demo_internal.h"
 
 MojoResult ServiceMain(MojoHandle service_request_handle) {
-  service_manager::ServiceRunner runner(new ui::demo::MusDemo);
+  service_manager::ServiceRunner runner(new ui::demo::MusDemoInternal);
   return runner.Run(service_request_handle);
 }
diff --git a/services/ui/demo/mus_demo.cc b/services/ui/demo/mus_demo.cc
index e529794..a4d55b04 100644
--- a/services/ui/demo/mus_demo.cc
+++ b/services/ui/demo/mus_demo.cc
@@ -6,7 +6,6 @@
 
 #include "base/memory/ptr_util.h"
 #include "services/service_manager/public/cpp/connector.h"
-#include "services/service_manager/public/cpp/service_context.h"
 #include "services/ui/demo/window_tree_data.h"
 #include "services/ui/public/cpp/gpu/gpu.h"
 #include "ui/aura/client/default_capture_client.h"
@@ -21,19 +20,28 @@
 namespace ui {
 namespace demo {
 
-namespace {
-
-// Size of square in pixels to draw.
-const int kSquareSize = 300;
-
-}
-
 MusDemo::MusDemo() {}
 
 MusDemo::~MusDemo() {
   display::Screen::SetScreenInstance(nullptr);
 }
 
+void MusDemo::AddPrimaryDisplay(const display::Display& display) {
+  screen_->display_list().AddDisplay(display,
+                                     display::DisplayList::Type::PRIMARY);
+}
+
+void MusDemo::InitWindowTreeData(
+    std::unique_ptr<aura::WindowTreeHostMus> window_tree_host) {
+  DCHECK(window_tree_data_);
+  DCHECK(!window_tree_data_->IsInitialized());
+  window_tree_data_->Init(std::move(window_tree_host));
+}
+
+void MusDemo::CleanupWindowTreeData() {
+  window_tree_data_.reset();
+}
+
 void MusDemo::OnStart() {
   screen_ = base::MakeUnique<display::ScreenBase>();
   display::Screen::SetScreenInstance(screen_.get());
@@ -43,11 +51,7 @@
   property_converter_ = base::MakeUnique<aura::PropertyConverter>();
   wm_state_ = base::MakeUnique<::wm::WMState>();
 
-  window_tree_client_ = base::MakeUnique<aura::WindowTreeClient>(
-      context()->connector(), this, this);
-  window_tree_client_->ConnectAsWindowManager();
-
-  window_tree_data_ = base::MakeUnique<WindowTreeData>(kSquareSize);
+  OnStartImpl(window_tree_client_, window_tree_data_);
 
   env_->SetWindowTreeClient(window_tree_client_.get());
 }
@@ -59,7 +63,6 @@
 
 void MusDemo::OnEmbed(
     std::unique_ptr<aura::WindowTreeHostMus> window_tree_host) {
-  // Not called for the WindowManager.
   NOTREACHED();
 }
 
@@ -68,13 +71,12 @@
 }
 
 void MusDemo::OnEmbedRootDestroyed(aura::WindowTreeHostMus* window_tree_host) {
-  // Not called for the WindowManager.
   NOTREACHED();
 }
 
 void MusDemo::OnLostConnection(aura::WindowTreeClient* client) {
   window_tree_client_.reset();
-  window_tree_data_.reset();
+  CleanupWindowTreeData();
 }
 
 void MusDemo::OnPointerEventObserved(const PointerEvent& event,
@@ -84,72 +86,5 @@
   return property_converter_.get();
 }
 
-void MusDemo::SetWindowManagerClient(aura::WindowManagerClient* client) {}
-
-bool MusDemo::OnWmSetBounds(aura::Window* window, gfx::Rect* bounds) {
-  return true;
-}
-
-bool MusDemo::OnWmSetProperty(aura::Window* window,
-                              const std::string& name,
-                              std::unique_ptr<std::vector<uint8_t>>* new_data) {
-  return true;
-}
-
-void MusDemo::OnWmSetCanFocus(aura::Window* window, bool can_focus) {}
-
-aura::Window* MusDemo::OnWmCreateTopLevelWindow(
-    mojom::WindowType window_type,
-    std::map<std::string, std::vector<uint8_t>>* properties) {
-  NOTREACHED();
-  return nullptr;
-}
-
-void MusDemo::OnWmClientJankinessChanged(
-    const std::set<aura::Window*>& client_windows,
-    bool janky) {
-  // Don't care
-}
-
-void MusDemo::OnWmWillCreateDisplay(const display::Display& display) {
-  screen_->display_list().AddDisplay(display,
-                                     display::DisplayList::Type::PRIMARY);
-}
-
-void MusDemo::OnWmNewDisplay(
-    std::unique_ptr<aura::WindowTreeHostMus> window_tree_host,
-    const display::Display& display) {
-  DCHECK(!window_tree_data_->IsInitialized());  // Only support one display.
-  window_tree_data_->Init(std::move(window_tree_host));
-}
-
-void MusDemo::OnWmDisplayRemoved(aura::WindowTreeHostMus* window_tree_host) {
-  window_tree_data_.reset();
-}
-
-void MusDemo::OnWmDisplayModified(const display::Display& display) {}
-
-mojom::EventResult MusDemo::OnAccelerator(uint32_t id, const Event& event) {
-  return mojom::EventResult::UNHANDLED;
-}
-
-void MusDemo::OnWmPerformMoveLoop(aura::Window* window,
-                                  mojom::MoveLoopSource source,
-                                  const gfx::Point& cursor_location,
-                                  const base::Callback<void(bool)>& on_done) {
-  // Don't care
-}
-
-void MusDemo::OnWmCancelMoveLoop(aura::Window* window) {}
-
-void MusDemo::OnWmSetClientArea(
-    aura::Window* window,
-    const gfx::Insets& insets,
-    const std::vector<gfx::Rect>& additional_client_areas) {}
-
-bool MusDemo::IsWindowActive(aura::Window* window) { return false; }
-
-void MusDemo::OnWmDeactivateWindow(aura::Window* window) {}
-
 }  // namespace demo
-}  // namespace aura
+}  // namespace ui
diff --git a/services/ui/demo/mus_demo.h b/services/ui/demo/mus_demo.h
index 58bb6f5..fc2ce736 100644
--- a/services/ui/demo/mus_demo.h
+++ b/services/ui/demo/mus_demo.h
@@ -5,17 +5,12 @@
 #ifndef SERVICES_UI_DEMO_MUS_DEMO_H_
 #define SERVICES_UI_DEMO_MUS_DEMO_H_
 
-#include <map>
 #include <memory>
-#include <set>
-#include <string>
-#include <vector>
 
 #include "base/callback.h"
 #include "base/macros.h"
 #include "base/timer/timer.h"
 #include "services/service_manager/public/cpp/service.h"
-#include "ui/aura/mus/window_manager_delegate.h"
 #include "ui/aura/mus/window_tree_client_delegate.h"
 #include "ui/display/screen_base.h"
 
@@ -42,13 +37,22 @@
 // the window. Provides a simple way to demonstrate that the graphic stack works
 // as intended.
 class MusDemo : public service_manager::Service,
-                public aura::WindowTreeClientDelegate,
-                public aura::WindowManagerDelegate {
+                public aura::WindowTreeClientDelegate {
  public:
   MusDemo();
   ~MusDemo() override;
 
+ protected:
+  void AddPrimaryDisplay(const display::Display& display);
+  void InitWindowTreeData(
+      std::unique_ptr<aura::WindowTreeHostMus> window_tree_host);
+  void CleanupWindowTreeData();
+
  private:
+  virtual void OnStartImpl(
+      std::unique_ptr<aura::WindowTreeClient>& window_tree_client,
+      std::unique_ptr<WindowTreeData>& window_tree_data) = 0;
+
   // service_manager::Service:
   void OnStart() override;
   bool OnConnect(const service_manager::ServiceInfo& remote_info,
@@ -64,38 +68,6 @@
                               aura::Window* target) override;
   aura::PropertyConverter* GetPropertyConverter() override;
 
-  // aura::WindowManagerDelegate:
-  void SetWindowManagerClient(aura::WindowManagerClient* client) override;
-  bool OnWmSetBounds(aura::Window* window, gfx::Rect* bounds) override;
-  bool OnWmSetProperty(
-      aura::Window* window,
-      const std::string& name,
-      std::unique_ptr<std::vector<uint8_t>>* new_data) override;
-  void OnWmSetCanFocus(aura::Window* window, bool can_focus) override;
-  aura::Window* OnWmCreateTopLevelWindow(
-      ui::mojom::WindowType window_type,
-      std::map<std::string, std::vector<uint8_t>>* properties) override;
-  void OnWmClientJankinessChanged(const std::set<aura::Window*>& client_windows,
-                                  bool janky) override;
-  void OnWmWillCreateDisplay(const display::Display& display) override;
-  void OnWmNewDisplay(std::unique_ptr<aura::WindowTreeHostMus> window_tree_host,
-                      const display::Display& display) override;
-  void OnWmDisplayRemoved(aura::WindowTreeHostMus* window_tree_host) override;
-  void OnWmDisplayModified(const display::Display& display) override;
-  ui::mojom::EventResult OnAccelerator(uint32_t id,
-                                       const ui::Event& event) override;
-  void OnWmPerformMoveLoop(aura::Window* window,
-                           ui::mojom::MoveLoopSource source,
-                           const gfx::Point& cursor_location,
-                           const base::Callback<void(bool)>& on_done) override;
-  void OnWmCancelMoveLoop(aura::Window* window) override;
-  void OnWmSetClientArea(
-      aura::Window* window,
-      const gfx::Insets& insets,
-      const std::vector<gfx::Rect>& additional_client_areas) override;
-  bool IsWindowActive(aura::Window* window) override;
-  void OnWmDeactivateWindow(aura::Window* window) override;
-
   std::unique_ptr<aura::WindowTreeClient> window_tree_client_;
   std::unique_ptr<aura::Env> env_;
   std::unique_ptr<display::ScreenBase> screen_;
@@ -110,6 +82,6 @@
 };
 
 }  // namespace demo
-}  // namespace aura
+}  // namespace ui
 
 #endif  // SERVICES_UI_DEMO_MUS_DEMO_H_
diff --git a/services/ui/demo/mus_demo_internal.cc b/services/ui/demo/mus_demo_internal.cc
new file mode 100644
index 0000000..9f5eeaed3
--- /dev/null
+++ b/services/ui/demo/mus_demo_internal.cc
@@ -0,0 +1,107 @@
+// 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 "services/ui/demo/mus_demo_internal.h"
+
+#include "services/service_manager/public/cpp/service_context.h"
+#include "services/ui/demo/window_tree_data.h"
+#include "ui/aura/mus/window_tree_client.h"
+#include "ui/aura/mus/window_tree_host_mus.h"
+
+namespace ui {
+namespace demo {
+
+namespace {
+
+// Size of square in pixels to draw.
+const int kSquareSize = 300;
+}
+
+MusDemoInternal::MusDemoInternal() {}
+
+MusDemoInternal::~MusDemoInternal() {}
+
+void MusDemoInternal::OnStartImpl(
+    std::unique_ptr<aura::WindowTreeClient>& window_tree_client,
+    std::unique_ptr<WindowTreeData>& window_tree_data) {
+  window_tree_client = base::MakeUnique<aura::WindowTreeClient>(
+      context()->connector(), this, this);
+  window_tree_client->ConnectAsWindowManager();
+  window_tree_data = base::MakeUnique<WindowTreeData>(kSquareSize);
+}
+
+void MusDemoInternal::SetWindowManagerClient(
+    aura::WindowManagerClient* client) {}
+
+bool MusDemoInternal::OnWmSetBounds(aura::Window* window, gfx::Rect* bounds) {
+  return true;
+}
+
+bool MusDemoInternal::OnWmSetProperty(
+    aura::Window* window,
+    const std::string& name,
+    std::unique_ptr<std::vector<uint8_t>>* new_data) {
+  return true;
+}
+
+void MusDemoInternal::OnWmSetCanFocus(aura::Window* window, bool can_focus) {}
+
+aura::Window* MusDemoInternal::OnWmCreateTopLevelWindow(
+    mojom::WindowType window_type,
+    std::map<std::string, std::vector<uint8_t>>* properties) {
+  NOTREACHED();
+  return nullptr;
+}
+
+void MusDemoInternal::OnWmClientJankinessChanged(
+    const std::set<aura::Window*>& client_windows,
+    bool janky) {
+  // Don't care
+}
+
+void MusDemoInternal::OnWmWillCreateDisplay(const display::Display& display) {
+  AddPrimaryDisplay(display);
+}
+
+void MusDemoInternal::OnWmNewDisplay(
+    std::unique_ptr<aura::WindowTreeHostMus> window_tree_host,
+    const display::Display& display) {
+  InitWindowTreeData(std::move(window_tree_host));
+}
+
+void MusDemoInternal::OnWmDisplayRemoved(
+    aura::WindowTreeHostMus* window_tree_host) {
+  CleanupWindowTreeData();
+}
+
+void MusDemoInternal::OnWmDisplayModified(const display::Display& display) {}
+
+mojom::EventResult MusDemoInternal::OnAccelerator(uint32_t id,
+                                                  const Event& event) {
+  return mojom::EventResult::UNHANDLED;
+}
+
+void MusDemoInternal::OnWmPerformMoveLoop(
+    aura::Window* window,
+    mojom::MoveLoopSource source,
+    const gfx::Point& cursor_location,
+    const base::Callback<void(bool)>& on_done) {
+  // Don't care
+}
+
+void MusDemoInternal::OnWmCancelMoveLoop(aura::Window* window) {}
+
+void MusDemoInternal::OnWmSetClientArea(
+    aura::Window* window,
+    const gfx::Insets& insets,
+    const std::vector<gfx::Rect>& additional_client_areas) {}
+
+bool MusDemoInternal::IsWindowActive(aura::Window* window) {
+  return false;
+}
+
+void MusDemoInternal::OnWmDeactivateWindow(aura::Window* window) {}
+
+}  // namespace demo
+}  // namespace ui
diff --git a/services/ui/demo/mus_demo_internal.h b/services/ui/demo/mus_demo_internal.h
new file mode 100644
index 0000000..c486c16f
--- /dev/null
+++ b/services/ui/demo/mus_demo_internal.h
@@ -0,0 +1,66 @@
+// 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 SERVICES_UI_DEMO_MUS_DEMO_INTERNAL_H_
+#define SERVICES_UI_DEMO_MUS_DEMO_INTERNAL_H_
+
+#include <map>
+#include <memory>
+#include <set>
+#include <string>
+#include <vector>
+
+#include "services/ui/demo/mus_demo.h"
+#include "ui/aura/mus/window_manager_delegate.h"
+
+namespace ui {
+namespace demo {
+
+class MusDemoInternal : public MusDemo, public aura::WindowManagerDelegate {
+ public:
+  MusDemoInternal();
+  ~MusDemoInternal() final;
+
+ private:
+  void OnStartImpl(std::unique_ptr<aura::WindowTreeClient>& window_tree_client,
+                   std::unique_ptr<WindowTreeData>& window_tree_data) final;
+
+  // aura::WindowManagerDelegate:
+  void SetWindowManagerClient(aura::WindowManagerClient* client) final;
+  bool OnWmSetBounds(aura::Window* window, gfx::Rect* bounds) final;
+  bool OnWmSetProperty(aura::Window* window,
+                       const std::string& name,
+                       std::unique_ptr<std::vector<uint8_t>>* new_data) final;
+  void OnWmSetCanFocus(aura::Window* window, bool can_focus) final;
+  aura::Window* OnWmCreateTopLevelWindow(
+      ui::mojom::WindowType window_type,
+      std::map<std::string, std::vector<uint8_t>>* properties) final;
+  void OnWmClientJankinessChanged(const std::set<aura::Window*>& client_windows,
+                                  bool janky) final;
+  void OnWmWillCreateDisplay(const display::Display& display) final;
+  void OnWmNewDisplay(std::unique_ptr<aura::WindowTreeHostMus> window_tree_host,
+                      const display::Display& display) final;
+  void OnWmDisplayRemoved(aura::WindowTreeHostMus* window_tree_host) final;
+  void OnWmDisplayModified(const display::Display& display) final;
+  ui::mojom::EventResult OnAccelerator(uint32_t id,
+                                       const ui::Event& event) final;
+  void OnWmPerformMoveLoop(aura::Window* window,
+                           ui::mojom::MoveLoopSource source,
+                           const gfx::Point& cursor_location,
+                           const base::Callback<void(bool)>& on_done) final;
+  void OnWmCancelMoveLoop(aura::Window* window) final;
+  void OnWmSetClientArea(
+      aura::Window* window,
+      const gfx::Insets& insets,
+      const std::vector<gfx::Rect>& additional_client_areas) final;
+  bool IsWindowActive(aura::Window* window) final;
+  void OnWmDeactivateWindow(aura::Window* window) final;
+
+  DISALLOW_COPY_AND_ASSIGN(MusDemoInternal);
+};
+
+}  // namespace demo
+}  // namespace ui
+
+#endif  // SERVICES_UI_DEMO_MUS_DEMO_INTERNAL_H_
diff --git a/third_party/WebKit/LayoutTests/TestExpectations b/third_party/WebKit/LayoutTests/TestExpectations
index 13a3833..9e21d45e 100644
--- a/third_party/WebKit/LayoutTests/TestExpectations
+++ b/third_party/WebKit/LayoutTests/TestExpectations
@@ -845,8 +845,6 @@
 crbug.com/638693 virtual/threaded/animations/display-inline-style-adjust.html [ Pass Crash Failure ]
 crbug.com/421283 html/marquee/marquee-scrollamount.html [ Pass Failure ]
 
-crbug.com/659123 [ Mac ] fast/css/text-overflow-ellipsis-button.html [ Pass Failure ]
-
 # TODO(oshima): Mac Android are currently not supported.
 crbug.com/567837 [ Mac Android ] virtual/scalefactor200withzoom/fast/hidpi/static [ Skip ]
 
@@ -1729,8 +1727,6 @@
 crbug.com/572723 inspector/sources/debugger/debugger-disable-enable.html [ Pass Failure Timeout ]
 crbug.com/572723 inspector/sources/debugger/debugger-uncaught-promise-on-pause.html [ Timeout Pass ]
 
-crbug.com/155836 fast/text/emphasis-ellipsis-complextext.html [ Failure Pass ]
-
 crbug.com/577380 [ Linux Debug ] http/tests/serviceworker/chromium/registration-stress.html [ Failure ]
 crbug.com/577380 [ Linux Debug ] virtual/mojo-loading/http/tests/serviceworker/chromium/registration-stress.html [ Failure ]
 
@@ -2253,9 +2249,6 @@
 crbug.com/664819 virtual/mojo-loading/http/tests/security/isolatedWorld/events.html [ Pass Failure ]
 crbug.com/664839 virtual/mojo-loading/http/tests/security/link-crossorigin-preload-no-cors.html [ Pass Failure ]
 
-crbug.com/686478 fast/text/ellipsis-with-list-marker-in-ltr-flow.html [ Pass Failure ]
-crbug.com/686478 fast/text/ellipsis-with-list-marker-in-rtl-flow.html [ Pass Failure ]
-
 # Possible duplicate of crbug.com/498539
 # crbug.com/664843 inspector/elements/styles-4/styles-update-from-js.html [ Pass Failure ]
 
diff --git a/third_party/WebKit/LayoutTests/fast/css/invalidation/sheet-ruleset-invalidation.html b/third_party/WebKit/LayoutTests/fast/css/invalidation/sheet-ruleset-invalidation.html
index e8a7c78..d513ff27 100644
--- a/third_party/WebKit/LayoutTests/fast/css/invalidation/sheet-ruleset-invalidation.html
+++ b/third_party/WebKit/LayoutTests/fast/css/invalidation/sheet-ruleset-invalidation.html
@@ -8,13 +8,39 @@
     <div></div>
     <div></div>
     <div></div>
+    <div id="found">
+        <div></div>
+    </div>
     <span></span>
 </div>
 <script>
     test(() => {
-        assert_true(!!window.internals, "Test requires window.internals.");
+        assert_true(!!window.internals, "Tests require window.internals.");
+    }, "Test for prerequisites.");
+
+    function applyRuleAndReturnAffectedElementCount(ruleString) {
         document.body.offsetTop;
-        document.styleSheets[0].insertRule("span{background:green}", 0);
-        assert_equals(internals.updateStyleAndReturnAffectedElementCount(), 1, "Check that only the span is affected.");
-    }, "Inserting a style rule with a type selector should only invalidate elements with that type.");
+        document.styleSheets[0].insertRule(ruleString, 0);
+        var recalcCount = internals.updateStyleAndReturnAffectedElementCount();
+        document.styleSheets[0].removeRule();
+        return recalcCount;
+    }
+
+    test(() => {
+        assert_equals(applyRuleAndReturnAffectedElementCount(
+            "span { background: green }"), 1,
+            "Check that only the span is affected.");
+    }, "A style rule with a type selector should only invalidate elements with that type.");
+
+    test(() => {
+        assert_equals(applyRuleAndReturnAffectedElementCount(
+            "#notfound div { background: red }"), 0,
+            "Check that none of divs are recalculated.");
+    }, "A type selector scoped in an unknown id should not invalidate any elements.");
+
+    test(() => {
+        assert_equals(applyRuleAndReturnAffectedElementCount(
+            "#found div { background: red }"), 1,
+            "Check that only one of the divs is recalculated.");
+    }, "A type selector scoped by a known id should only invalidate descendants of the element with that id.");
 </script>
diff --git a/third_party/WebKit/LayoutTests/inspector/user-metrics-expected.txt b/third_party/WebKit/LayoutTests/inspector/user-metrics-expected.txt
index cc4b3cc..b6e9f68 100644
--- a/third_party/WebKit/LayoutTests/inspector/user-metrics-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector/user-metrics-expected.txt
@@ -8,6 +8,7 @@
     ConnectToNodeJSDirectly : 20
     ConnectToNodeJSFromFrontend : 19
     ConsoleEvaluated : 8
+    CpuThrottlingEnabled : 21
     DOMPropertiesExpanded : 16
     DeviceModeEnabled : 10
     FileSavedInWorkspace : 9
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/filters/feBlend-all-modes-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/svg/filters/feBlend-all-modes-expected.txt
index 07426239..012b8c4f 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/filters/feBlend-all-modes-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/linux/svg/filters/feBlend-all-modes-expected.txt
@@ -5,340 +5,340 @@
     LayoutBlockFlow {BODY} at (8,8) size 784x330
       LayoutBlockFlow {DIV} at (0,0) size 400x110
         LayoutSVGRoot {svg} at (0,0) size 50x50
-          LayoutSVGResourceFilter {filter} [id="f_normal"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
+          LayoutSVGResourceFilter {filter} [id="f_normal0"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
             [feBlend mode="normal"]
               [feFlood flood-color="#FF0000" flood-opacity="1.00"]
               [feFlood flood-color="#00FF00" flood-opacity="1.00"]
           LayoutSVGRect {rect} at (0,0) size 50x50 [fill={[type=SOLID] [color=#000000]}] [x=0.00] [y=0.00] [width=50.00] [height=50.00]
-            [filter="f_normal"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
+            [filter="f_normal0"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
         LayoutSVGRoot {svg} at (50,0) size 50x50
-          LayoutSVGResourceFilter {filter} [id="f_multiply"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
+          LayoutSVGResourceFilter {filter} [id="f_multiply0"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
             [feBlend mode="multiply"]
               [feFlood flood-color="#FF0000" flood-opacity="1.00"]
               [feFlood flood-color="#00FF00" flood-opacity="1.00"]
           LayoutSVGRect {rect} at (0,0) size 50x50 [fill={[type=SOLID] [color=#000000]}] [x=0.00] [y=0.00] [width=50.00] [height=50.00]
-            [filter="f_multiply"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
+            [filter="f_multiply0"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
         LayoutSVGRoot {svg} at (100,0) size 50x50
-          LayoutSVGResourceFilter {filter} [id="f_screen"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
+          LayoutSVGResourceFilter {filter} [id="f_screen0"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
             [feBlend mode="screen"]
               [feFlood flood-color="#FF0000" flood-opacity="1.00"]
               [feFlood flood-color="#00FF00" flood-opacity="1.00"]
           LayoutSVGRect {rect} at (0,0) size 50x50 [fill={[type=SOLID] [color=#000000]}] [x=0.00] [y=0.00] [width=50.00] [height=50.00]
-            [filter="f_screen"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
+            [filter="f_screen0"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
         LayoutSVGRoot {svg} at (150,0) size 50x50
-          LayoutSVGResourceFilter {filter} [id="f_darken"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
+          LayoutSVGResourceFilter {filter} [id="f_darken0"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
             [feBlend mode="darken"]
               [feFlood flood-color="#FF0000" flood-opacity="1.00"]
               [feFlood flood-color="#00FF00" flood-opacity="1.00"]
           LayoutSVGRect {rect} at (0,0) size 50x50 [fill={[type=SOLID] [color=#000000]}] [x=0.00] [y=0.00] [width=50.00] [height=50.00]
-            [filter="f_darken"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
+            [filter="f_darken0"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
         LayoutSVGRoot {svg} at (200,0) size 50x50
-          LayoutSVGResourceFilter {filter} [id="f_lighten"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
+          LayoutSVGResourceFilter {filter} [id="f_lighten0"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
             [feBlend mode="lighten"]
               [feFlood flood-color="#FF0000" flood-opacity="1.00"]
               [feFlood flood-color="#00FF00" flood-opacity="1.00"]
           LayoutSVGRect {rect} at (0,0) size 50x50 [fill={[type=SOLID] [color=#000000]}] [x=0.00] [y=0.00] [width=50.00] [height=50.00]
-            [filter="f_lighten"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
+            [filter="f_lighten0"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
         LayoutSVGRoot {svg} at (250,0) size 50x50
-          LayoutSVGResourceFilter {filter} [id="f_overlay"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
+          LayoutSVGResourceFilter {filter} [id="f_overlay0"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
             [feBlend mode="overlay"]
               [feFlood flood-color="#FF0000" flood-opacity="1.00"]
               [feFlood flood-color="#00FF00" flood-opacity="1.00"]
           LayoutSVGRect {rect} at (0,0) size 50x50 [fill={[type=SOLID] [color=#000000]}] [x=0.00] [y=0.00] [width=50.00] [height=50.00]
-            [filter="f_overlay"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
+            [filter="f_overlay0"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
         LayoutSVGRoot {svg} at (300,0) size 50x50
-          LayoutSVGResourceFilter {filter} [id="f_color-dodge"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
+          LayoutSVGResourceFilter {filter} [id="f_color-dodge0"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
             [feBlend mode="color-dodge"]
               [feFlood flood-color="#FF0000" flood-opacity="1.00"]
               [feFlood flood-color="#00FF00" flood-opacity="1.00"]
           LayoutSVGRect {rect} at (0,0) size 50x50 [fill={[type=SOLID] [color=#000000]}] [x=0.00] [y=0.00] [width=50.00] [height=50.00]
-            [filter="f_color-dodge"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
+            [filter="f_color-dodge0"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
         LayoutSVGRoot {svg} at (350,0) size 50x50
-          LayoutSVGResourceFilter {filter} [id="f_color-burn"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
+          LayoutSVGResourceFilter {filter} [id="f_color-burn0"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
             [feBlend mode="color-burn"]
               [feFlood flood-color="#FF0000" flood-opacity="1.00"]
               [feFlood flood-color="#00FF00" flood-opacity="1.00"]
           LayoutSVGRect {rect} at (0,0) size 50x50 [fill={[type=SOLID] [color=#000000]}] [x=0.00] [y=0.00] [width=50.00] [height=50.00]
-            [filter="f_color-burn"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
+            [filter="f_color-burn0"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
         LayoutSVGRoot {svg} at (0,55) size 50x50
-          LayoutSVGResourceFilter {filter} [id="f_hard-light"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
+          LayoutSVGResourceFilter {filter} [id="f_hard-light0"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
             [feBlend mode="hard-light"]
               [feFlood flood-color="#FF0000" flood-opacity="1.00"]
               [feFlood flood-color="#00FF00" flood-opacity="1.00"]
           LayoutSVGRect {rect} at (0,0) size 50x50 [fill={[type=SOLID] [color=#000000]}] [x=0.00] [y=0.00] [width=50.00] [height=50.00]
-            [filter="f_hard-light"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
+            [filter="f_hard-light0"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
         LayoutSVGRoot {svg} at (50,55) size 50x50
-          LayoutSVGResourceFilter {filter} [id="f_soft-light"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
+          LayoutSVGResourceFilter {filter} [id="f_soft-light0"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
             [feBlend mode="soft-light"]
               [feFlood flood-color="#FF0000" flood-opacity="1.00"]
               [feFlood flood-color="#00FF00" flood-opacity="1.00"]
           LayoutSVGRect {rect} at (0,0) size 50x50 [fill={[type=SOLID] [color=#000000]}] [x=0.00] [y=0.00] [width=50.00] [height=50.00]
-            [filter="f_soft-light"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
+            [filter="f_soft-light0"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
         LayoutSVGRoot {svg} at (100,55) size 50x50
-          LayoutSVGResourceFilter {filter} [id="f_difference"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
+          LayoutSVGResourceFilter {filter} [id="f_difference0"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
             [feBlend mode="difference"]
               [feFlood flood-color="#FF0000" flood-opacity="1.00"]
               [feFlood flood-color="#00FF00" flood-opacity="1.00"]
           LayoutSVGRect {rect} at (0,0) size 50x50 [fill={[type=SOLID] [color=#000000]}] [x=0.00] [y=0.00] [width=50.00] [height=50.00]
-            [filter="f_difference"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
+            [filter="f_difference0"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
         LayoutSVGRoot {svg} at (150,55) size 50x50
-          LayoutSVGResourceFilter {filter} [id="f_exclusion"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
+          LayoutSVGResourceFilter {filter} [id="f_exclusion0"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
             [feBlend mode="exclusion"]
               [feFlood flood-color="#FF0000" flood-opacity="1.00"]
               [feFlood flood-color="#00FF00" flood-opacity="1.00"]
           LayoutSVGRect {rect} at (0,0) size 50x50 [fill={[type=SOLID] [color=#000000]}] [x=0.00] [y=0.00] [width=50.00] [height=50.00]
-            [filter="f_exclusion"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
+            [filter="f_exclusion0"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
         LayoutSVGRoot {svg} at (200,55) size 50x50
-          LayoutSVGResourceFilter {filter} [id="f_hue"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
+          LayoutSVGResourceFilter {filter} [id="f_hue0"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
             [feBlend mode="hue"]
               [feFlood flood-color="#FF0000" flood-opacity="1.00"]
               [feFlood flood-color="#00FF00" flood-opacity="1.00"]
           LayoutSVGRect {rect} at (0,0) size 50x50 [fill={[type=SOLID] [color=#000000]}] [x=0.00] [y=0.00] [width=50.00] [height=50.00]
-            [filter="f_hue"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
+            [filter="f_hue0"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
         LayoutSVGRoot {svg} at (250,55) size 50x50
-          LayoutSVGResourceFilter {filter} [id="f_saturation"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
+          LayoutSVGResourceFilter {filter} [id="f_saturation0"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
             [feBlend mode="saturation"]
               [feFlood flood-color="#FF0000" flood-opacity="1.00"]
               [feFlood flood-color="#00FF00" flood-opacity="1.00"]
           LayoutSVGRect {rect} at (0,0) size 50x50 [fill={[type=SOLID] [color=#000000]}] [x=0.00] [y=0.00] [width=50.00] [height=50.00]
-            [filter="f_saturation"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
+            [filter="f_saturation0"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
         LayoutSVGRoot {svg} at (300,55) size 50x50
-          LayoutSVGResourceFilter {filter} [id="f_color"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
+          LayoutSVGResourceFilter {filter} [id="f_color0"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
             [feBlend mode="color"]
               [feFlood flood-color="#FF0000" flood-opacity="1.00"]
               [feFlood flood-color="#00FF00" flood-opacity="1.00"]
           LayoutSVGRect {rect} at (0,0) size 50x50 [fill={[type=SOLID] [color=#000000]}] [x=0.00] [y=0.00] [width=50.00] [height=50.00]
-            [filter="f_color"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
+            [filter="f_color0"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
         LayoutSVGRoot {svg} at (350,55) size 50x50
-          LayoutSVGResourceFilter {filter} [id="f_luminosity"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
+          LayoutSVGResourceFilter {filter} [id="f_luminosity0"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
             [feBlend mode="luminosity"]
               [feFlood flood-color="#FF0000" flood-opacity="1.00"]
               [feFlood flood-color="#00FF00" flood-opacity="1.00"]
           LayoutSVGRect {rect} at (0,0) size 50x50 [fill={[type=SOLID] [color=#000000]}] [x=0.00] [y=0.00] [width=50.00] [height=50.00]
-            [filter="f_luminosity"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
+            [filter="f_luminosity0"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
       LayoutBlockFlow {DIV} at (0,110) size 400x110
         LayoutSVGRoot {svg} at (0,0) size 50x50
-          LayoutSVGResourceFilter {filter} [id="f_normal"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
+          LayoutSVGResourceFilter {filter} [id="f_normal1"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
             [feBlend mode="normal"]
               [feFlood flood-color="#3340CC" flood-opacity="1.00"]
               [feFlood flood-color="#99C066" flood-opacity="1.00"]
           LayoutSVGRect {rect} at (0,0) size 50x50 [fill={[type=SOLID] [color=#000000]}] [x=0.00] [y=0.00] [width=50.00] [height=50.00]
-            [filter="f_normal"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
+            [filter="f_normal1"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
         LayoutSVGRoot {svg} at (50,0) size 50x50
-          LayoutSVGResourceFilter {filter} [id="f_multiply"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
+          LayoutSVGResourceFilter {filter} [id="f_multiply1"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
             [feBlend mode="multiply"]
               [feFlood flood-color="#3340CC" flood-opacity="1.00"]
               [feFlood flood-color="#99C066" flood-opacity="1.00"]
           LayoutSVGRect {rect} at (0,0) size 50x50 [fill={[type=SOLID] [color=#000000]}] [x=0.00] [y=0.00] [width=50.00] [height=50.00]
-            [filter="f_multiply"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
+            [filter="f_multiply1"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
         LayoutSVGRoot {svg} at (100,0) size 50x50
-          LayoutSVGResourceFilter {filter} [id="f_screen"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
+          LayoutSVGResourceFilter {filter} [id="f_screen1"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
             [feBlend mode="screen"]
               [feFlood flood-color="#3340CC" flood-opacity="1.00"]
               [feFlood flood-color="#99C066" flood-opacity="1.00"]
           LayoutSVGRect {rect} at (0,0) size 50x50 [fill={[type=SOLID] [color=#000000]}] [x=0.00] [y=0.00] [width=50.00] [height=50.00]
-            [filter="f_screen"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
+            [filter="f_screen1"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
         LayoutSVGRoot {svg} at (150,0) size 50x50
-          LayoutSVGResourceFilter {filter} [id="f_darken"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
+          LayoutSVGResourceFilter {filter} [id="f_darken1"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
             [feBlend mode="darken"]
               [feFlood flood-color="#3340CC" flood-opacity="1.00"]
               [feFlood flood-color="#99C066" flood-opacity="1.00"]
           LayoutSVGRect {rect} at (0,0) size 50x50 [fill={[type=SOLID] [color=#000000]}] [x=0.00] [y=0.00] [width=50.00] [height=50.00]
-            [filter="f_darken"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
+            [filter="f_darken1"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
         LayoutSVGRoot {svg} at (200,0) size 50x50
-          LayoutSVGResourceFilter {filter} [id="f_lighten"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
+          LayoutSVGResourceFilter {filter} [id="f_lighten1"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
             [feBlend mode="lighten"]
               [feFlood flood-color="#3340CC" flood-opacity="1.00"]
               [feFlood flood-color="#99C066" flood-opacity="1.00"]
           LayoutSVGRect {rect} at (0,0) size 50x50 [fill={[type=SOLID] [color=#000000]}] [x=0.00] [y=0.00] [width=50.00] [height=50.00]
-            [filter="f_lighten"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
+            [filter="f_lighten1"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
         LayoutSVGRoot {svg} at (250,0) size 50x50
-          LayoutSVGResourceFilter {filter} [id="f_overlay"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
+          LayoutSVGResourceFilter {filter} [id="f_overlay1"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
             [feBlend mode="overlay"]
               [feFlood flood-color="#3340CC" flood-opacity="1.00"]
               [feFlood flood-color="#99C066" flood-opacity="1.00"]
           LayoutSVGRect {rect} at (0,0) size 50x50 [fill={[type=SOLID] [color=#000000]}] [x=0.00] [y=0.00] [width=50.00] [height=50.00]
-            [filter="f_overlay"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
+            [filter="f_overlay1"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
         LayoutSVGRoot {svg} at (300,0) size 50x50
-          LayoutSVGResourceFilter {filter} [id="f_color-dodge"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
+          LayoutSVGResourceFilter {filter} [id="f_color-dodge1"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
             [feBlend mode="color-dodge"]
               [feFlood flood-color="#3340CC" flood-opacity="1.00"]
               [feFlood flood-color="#99C066" flood-opacity="1.00"]
           LayoutSVGRect {rect} at (0,0) size 50x50 [fill={[type=SOLID] [color=#000000]}] [x=0.00] [y=0.00] [width=50.00] [height=50.00]
-            [filter="f_color-dodge"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
+            [filter="f_color-dodge1"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
         LayoutSVGRoot {svg} at (350,0) size 50x50
-          LayoutSVGResourceFilter {filter} [id="f_color-burn"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
+          LayoutSVGResourceFilter {filter} [id="f_color-burn1"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
             [feBlend mode="color-burn"]
               [feFlood flood-color="#3340CC" flood-opacity="1.00"]
               [feFlood flood-color="#99C066" flood-opacity="1.00"]
           LayoutSVGRect {rect} at (0,0) size 50x50 [fill={[type=SOLID] [color=#000000]}] [x=0.00] [y=0.00] [width=50.00] [height=50.00]
-            [filter="f_color-burn"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
+            [filter="f_color-burn1"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
         LayoutSVGRoot {svg} at (0,55) size 50x50
-          LayoutSVGResourceFilter {filter} [id="f_hard-light"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
+          LayoutSVGResourceFilter {filter} [id="f_hard-light1"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
             [feBlend mode="hard-light"]
               [feFlood flood-color="#3340CC" flood-opacity="1.00"]
               [feFlood flood-color="#99C066" flood-opacity="1.00"]
           LayoutSVGRect {rect} at (0,0) size 50x50 [fill={[type=SOLID] [color=#000000]}] [x=0.00] [y=0.00] [width=50.00] [height=50.00]
-            [filter="f_hard-light"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
+            [filter="f_hard-light1"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
         LayoutSVGRoot {svg} at (50,55) size 50x50
-          LayoutSVGResourceFilter {filter} [id="f_soft-light"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
+          LayoutSVGResourceFilter {filter} [id="f_soft-light1"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
             [feBlend mode="soft-light"]
               [feFlood flood-color="#3340CC" flood-opacity="1.00"]
               [feFlood flood-color="#99C066" flood-opacity="1.00"]
           LayoutSVGRect {rect} at (0,0) size 50x50 [fill={[type=SOLID] [color=#000000]}] [x=0.00] [y=0.00] [width=50.00] [height=50.00]
-            [filter="f_soft-light"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
+            [filter="f_soft-light1"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
         LayoutSVGRoot {svg} at (100,55) size 50x50
-          LayoutSVGResourceFilter {filter} [id="f_difference"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
+          LayoutSVGResourceFilter {filter} [id="f_difference1"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
             [feBlend mode="difference"]
               [feFlood flood-color="#3340CC" flood-opacity="1.00"]
               [feFlood flood-color="#99C066" flood-opacity="1.00"]
           LayoutSVGRect {rect} at (0,0) size 50x50 [fill={[type=SOLID] [color=#000000]}] [x=0.00] [y=0.00] [width=50.00] [height=50.00]
-            [filter="f_difference"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
+            [filter="f_difference1"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
         LayoutSVGRoot {svg} at (150,55) size 50x50
-          LayoutSVGResourceFilter {filter} [id="f_exclusion"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
+          LayoutSVGResourceFilter {filter} [id="f_exclusion1"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
             [feBlend mode="exclusion"]
               [feFlood flood-color="#3340CC" flood-opacity="1.00"]
               [feFlood flood-color="#99C066" flood-opacity="1.00"]
           LayoutSVGRect {rect} at (0,0) size 50x50 [fill={[type=SOLID] [color=#000000]}] [x=0.00] [y=0.00] [width=50.00] [height=50.00]
-            [filter="f_exclusion"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
+            [filter="f_exclusion1"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
         LayoutSVGRoot {svg} at (200,55) size 50x50
-          LayoutSVGResourceFilter {filter} [id="f_hue"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
+          LayoutSVGResourceFilter {filter} [id="f_hue1"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
             [feBlend mode="hue"]
               [feFlood flood-color="#3340CC" flood-opacity="1.00"]
               [feFlood flood-color="#99C066" flood-opacity="1.00"]
           LayoutSVGRect {rect} at (0,0) size 50x50 [fill={[type=SOLID] [color=#000000]}] [x=0.00] [y=0.00] [width=50.00] [height=50.00]
-            [filter="f_hue"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
+            [filter="f_hue1"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
         LayoutSVGRoot {svg} at (250,55) size 50x50
-          LayoutSVGResourceFilter {filter} [id="f_saturation"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
+          LayoutSVGResourceFilter {filter} [id="f_saturation1"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
             [feBlend mode="saturation"]
               [feFlood flood-color="#3340CC" flood-opacity="1.00"]
               [feFlood flood-color="#99C066" flood-opacity="1.00"]
           LayoutSVGRect {rect} at (0,0) size 50x50 [fill={[type=SOLID] [color=#000000]}] [x=0.00] [y=0.00] [width=50.00] [height=50.00]
-            [filter="f_saturation"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
+            [filter="f_saturation1"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
         LayoutSVGRoot {svg} at (300,55) size 50x50
-          LayoutSVGResourceFilter {filter} [id="f_color"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
+          LayoutSVGResourceFilter {filter} [id="f_color1"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
             [feBlend mode="color"]
               [feFlood flood-color="#3340CC" flood-opacity="1.00"]
               [feFlood flood-color="#99C066" flood-opacity="1.00"]
           LayoutSVGRect {rect} at (0,0) size 50x50 [fill={[type=SOLID] [color=#000000]}] [x=0.00] [y=0.00] [width=50.00] [height=50.00]
-            [filter="f_color"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
+            [filter="f_color1"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
         LayoutSVGRoot {svg} at (350,55) size 50x50
-          LayoutSVGResourceFilter {filter} [id="f_luminosity"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
+          LayoutSVGResourceFilter {filter} [id="f_luminosity1"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
             [feBlend mode="luminosity"]
               [feFlood flood-color="#3340CC" flood-opacity="1.00"]
               [feFlood flood-color="#99C066" flood-opacity="1.00"]
           LayoutSVGRect {rect} at (0,0) size 50x50 [fill={[type=SOLID] [color=#000000]}] [x=0.00] [y=0.00] [width=50.00] [height=50.00]
-            [filter="f_luminosity"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
+            [filter="f_luminosity1"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
       LayoutBlockFlow {DIV} at (0,220) size 400x110
         LayoutSVGRoot {svg} at (0,0) size 50x50
-          LayoutSVGResourceFilter {filter} [id="f_normal"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
+          LayoutSVGResourceFilter {filter} [id="f_normal2"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
             [feBlend mode="normal"]
               [feFlood flood-color="#3340CC80" flood-opacity="1.00"]
               [feFlood flood-color="#99C06680" flood-opacity="1.00"]
           LayoutSVGRect {rect} at (0,0) size 50x50 [fill={[type=SOLID] [color=#000000]}] [x=0.00] [y=0.00] [width=50.00] [height=50.00]
-            [filter="f_normal"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
+            [filter="f_normal2"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
         LayoutSVGRoot {svg} at (50,0) size 50x50
-          LayoutSVGResourceFilter {filter} [id="f_multiply"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
+          LayoutSVGResourceFilter {filter} [id="f_multiply2"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
             [feBlend mode="multiply"]
               [feFlood flood-color="#3340CC80" flood-opacity="1.00"]
               [feFlood flood-color="#99C06680" flood-opacity="1.00"]
           LayoutSVGRect {rect} at (0,0) size 50x50 [fill={[type=SOLID] [color=#000000]}] [x=0.00] [y=0.00] [width=50.00] [height=50.00]
-            [filter="f_multiply"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
+            [filter="f_multiply2"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
         LayoutSVGRoot {svg} at (100,0) size 50x50
-          LayoutSVGResourceFilter {filter} [id="f_screen"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
+          LayoutSVGResourceFilter {filter} [id="f_screen2"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
             [feBlend mode="screen"]
               [feFlood flood-color="#3340CC80" flood-opacity="1.00"]
               [feFlood flood-color="#99C06680" flood-opacity="1.00"]
           LayoutSVGRect {rect} at (0,0) size 50x50 [fill={[type=SOLID] [color=#000000]}] [x=0.00] [y=0.00] [width=50.00] [height=50.00]
-            [filter="f_screen"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
+            [filter="f_screen2"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
         LayoutSVGRoot {svg} at (150,0) size 50x50
-          LayoutSVGResourceFilter {filter} [id="f_darken"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
+          LayoutSVGResourceFilter {filter} [id="f_darken2"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
             [feBlend mode="darken"]
               [feFlood flood-color="#3340CC80" flood-opacity="1.00"]
               [feFlood flood-color="#99C06680" flood-opacity="1.00"]
           LayoutSVGRect {rect} at (0,0) size 50x50 [fill={[type=SOLID] [color=#000000]}] [x=0.00] [y=0.00] [width=50.00] [height=50.00]
-            [filter="f_darken"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
+            [filter="f_darken2"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
         LayoutSVGRoot {svg} at (200,0) size 50x50
-          LayoutSVGResourceFilter {filter} [id="f_lighten"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
+          LayoutSVGResourceFilter {filter} [id="f_lighten2"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
             [feBlend mode="lighten"]
               [feFlood flood-color="#3340CC80" flood-opacity="1.00"]
               [feFlood flood-color="#99C06680" flood-opacity="1.00"]
           LayoutSVGRect {rect} at (0,0) size 50x50 [fill={[type=SOLID] [color=#000000]}] [x=0.00] [y=0.00] [width=50.00] [height=50.00]
-            [filter="f_lighten"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
+            [filter="f_lighten2"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
         LayoutSVGRoot {svg} at (250,0) size 50x50
-          LayoutSVGResourceFilter {filter} [id="f_overlay"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
+          LayoutSVGResourceFilter {filter} [id="f_overlay2"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
             [feBlend mode="overlay"]
               [feFlood flood-color="#3340CC80" flood-opacity="1.00"]
               [feFlood flood-color="#99C06680" flood-opacity="1.00"]
           LayoutSVGRect {rect} at (0,0) size 50x50 [fill={[type=SOLID] [color=#000000]}] [x=0.00] [y=0.00] [width=50.00] [height=50.00]
-            [filter="f_overlay"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
+            [filter="f_overlay2"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
         LayoutSVGRoot {svg} at (300,0) size 50x50
-          LayoutSVGResourceFilter {filter} [id="f_color-dodge"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
+          LayoutSVGResourceFilter {filter} [id="f_color-dodge2"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
             [feBlend mode="color-dodge"]
               [feFlood flood-color="#3340CC80" flood-opacity="1.00"]
               [feFlood flood-color="#99C06680" flood-opacity="1.00"]
           LayoutSVGRect {rect} at (0,0) size 50x50 [fill={[type=SOLID] [color=#000000]}] [x=0.00] [y=0.00] [width=50.00] [height=50.00]
-            [filter="f_color-dodge"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
+            [filter="f_color-dodge2"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
         LayoutSVGRoot {svg} at (350,0) size 50x50
-          LayoutSVGResourceFilter {filter} [id="f_color-burn"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
+          LayoutSVGResourceFilter {filter} [id="f_color-burn2"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
             [feBlend mode="color-burn"]
               [feFlood flood-color="#3340CC80" flood-opacity="1.00"]
               [feFlood flood-color="#99C06680" flood-opacity="1.00"]
           LayoutSVGRect {rect} at (0,0) size 50x50 [fill={[type=SOLID] [color=#000000]}] [x=0.00] [y=0.00] [width=50.00] [height=50.00]
-            [filter="f_color-burn"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
+            [filter="f_color-burn2"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
         LayoutSVGRoot {svg} at (0,55) size 50x50
-          LayoutSVGResourceFilter {filter} [id="f_hard-light"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
+          LayoutSVGResourceFilter {filter} [id="f_hard-light2"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
             [feBlend mode="hard-light"]
               [feFlood flood-color="#3340CC80" flood-opacity="1.00"]
               [feFlood flood-color="#99C06680" flood-opacity="1.00"]
           LayoutSVGRect {rect} at (0,0) size 50x50 [fill={[type=SOLID] [color=#000000]}] [x=0.00] [y=0.00] [width=50.00] [height=50.00]
-            [filter="f_hard-light"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
+            [filter="f_hard-light2"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
         LayoutSVGRoot {svg} at (50,55) size 50x50
-          LayoutSVGResourceFilter {filter} [id="f_soft-light"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
+          LayoutSVGResourceFilter {filter} [id="f_soft-light2"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
             [feBlend mode="soft-light"]
               [feFlood flood-color="#3340CC80" flood-opacity="1.00"]
               [feFlood flood-color="#99C06680" flood-opacity="1.00"]
           LayoutSVGRect {rect} at (0,0) size 50x50 [fill={[type=SOLID] [color=#000000]}] [x=0.00] [y=0.00] [width=50.00] [height=50.00]
-            [filter="f_soft-light"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
+            [filter="f_soft-light2"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
         LayoutSVGRoot {svg} at (100,55) size 50x50
-          LayoutSVGResourceFilter {filter} [id="f_difference"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
+          LayoutSVGResourceFilter {filter} [id="f_difference2"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
             [feBlend mode="difference"]
               [feFlood flood-color="#3340CC80" flood-opacity="1.00"]
               [feFlood flood-color="#99C06680" flood-opacity="1.00"]
           LayoutSVGRect {rect} at (0,0) size 50x50 [fill={[type=SOLID] [color=#000000]}] [x=0.00] [y=0.00] [width=50.00] [height=50.00]
-            [filter="f_difference"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
+            [filter="f_difference2"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
         LayoutSVGRoot {svg} at (150,55) size 50x50
-          LayoutSVGResourceFilter {filter} [id="f_exclusion"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
+          LayoutSVGResourceFilter {filter} [id="f_exclusion2"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
             [feBlend mode="exclusion"]
               [feFlood flood-color="#3340CC80" flood-opacity="1.00"]
               [feFlood flood-color="#99C06680" flood-opacity="1.00"]
           LayoutSVGRect {rect} at (0,0) size 50x50 [fill={[type=SOLID] [color=#000000]}] [x=0.00] [y=0.00] [width=50.00] [height=50.00]
-            [filter="f_exclusion"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
+            [filter="f_exclusion2"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
         LayoutSVGRoot {svg} at (200,55) size 50x50
-          LayoutSVGResourceFilter {filter} [id="f_hue"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
+          LayoutSVGResourceFilter {filter} [id="f_hue2"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
             [feBlend mode="hue"]
               [feFlood flood-color="#3340CC80" flood-opacity="1.00"]
               [feFlood flood-color="#99C06680" flood-opacity="1.00"]
           LayoutSVGRect {rect} at (0,0) size 50x50 [fill={[type=SOLID] [color=#000000]}] [x=0.00] [y=0.00] [width=50.00] [height=50.00]
-            [filter="f_hue"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
+            [filter="f_hue2"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
         LayoutSVGRoot {svg} at (250,55) size 50x50
-          LayoutSVGResourceFilter {filter} [id="f_saturation"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
+          LayoutSVGResourceFilter {filter} [id="f_saturation2"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
             [feBlend mode="saturation"]
               [feFlood flood-color="#3340CC80" flood-opacity="1.00"]
               [feFlood flood-color="#99C06680" flood-opacity="1.00"]
           LayoutSVGRect {rect} at (0,0) size 50x50 [fill={[type=SOLID] [color=#000000]}] [x=0.00] [y=0.00] [width=50.00] [height=50.00]
-            [filter="f_saturation"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
+            [filter="f_saturation2"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
         LayoutSVGRoot {svg} at (300,55) size 50x50
-          LayoutSVGResourceFilter {filter} [id="f_color"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
+          LayoutSVGResourceFilter {filter} [id="f_color2"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
             [feBlend mode="color"]
               [feFlood flood-color="#3340CC80" flood-opacity="1.00"]
               [feFlood flood-color="#99C06680" flood-opacity="1.00"]
           LayoutSVGRect {rect} at (0,0) size 50x50 [fill={[type=SOLID] [color=#000000]}] [x=0.00] [y=0.00] [width=50.00] [height=50.00]
-            [filter="f_color"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
+            [filter="f_color2"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
         LayoutSVGRoot {svg} at (350,55) size 50x50
-          LayoutSVGResourceFilter {filter} [id="f_luminosity"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
+          LayoutSVGResourceFilter {filter} [id="f_luminosity2"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
             [feBlend mode="luminosity"]
               [feFlood flood-color="#3340CC80" flood-opacity="1.00"]
               [feFlood flood-color="#99C06680" flood-opacity="1.00"]
           LayoutSVGRect {rect} at (0,0) size 50x50 [fill={[type=SOLID] [color=#000000]}] [x=0.00] [y=0.00] [width=50.00] [height=50.00]
-            [filter="f_luminosity"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
+            [filter="f_luminosity2"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.10/fast/text/ellipsis-with-list-marker-in-ltr-flow-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.10/fast/text/ellipsis-with-list-marker-in-ltr-flow-expected.png
index 507963b..c4ef32c 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-mac10.10/fast/text/ellipsis-with-list-marker-in-ltr-flow-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.10/fast/text/ellipsis-with-list-marker-in-ltr-flow-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.10/fast/text/emphasis-ellipsis-complextext-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.10/fast/text/emphasis-ellipsis-complextext-expected.png
index 1d556f1..53fca53b 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-mac10.10/fast/text/emphasis-ellipsis-complextext-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.10/fast/text/emphasis-ellipsis-complextext-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.9/fast/text/ellipsis-with-list-marker-in-ltr-flow-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.9/fast/text/ellipsis-with-list-marker-in-ltr-flow-expected.png
index 9e567f3..a366eb91 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-mac10.9/fast/text/ellipsis-with-list-marker-in-ltr-flow-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.9/fast/text/ellipsis-with-list-marker-in-ltr-flow-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.9/fast/text/ellipsis-with-list-marker-in-rtl-flow-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.9/fast/text/ellipsis-with-list-marker-in-rtl-flow-expected.png
index 0fecc18..0b75d2c 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-mac10.9/fast/text/ellipsis-with-list-marker-in-rtl-flow-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.9/fast/text/ellipsis-with-list-marker-in-rtl-flow-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.9/fast/text/emphasis-ellipsis-complextext-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.9/fast/text/emphasis-ellipsis-complextext-expected.png
index 5e86d1d..0174d2fd 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-mac10.9/fast/text/emphasis-ellipsis-complextext-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.9/fast/text/emphasis-ellipsis-complextext-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/text/ellipsis-with-list-marker-in-rtl-flow-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/text/ellipsis-with-list-marker-in-rtl-flow-expected.png
index 6706f44..42a52a4 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/fast/text/ellipsis-with-list-marker-in-rtl-flow-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/fast/text/ellipsis-with-list-marker-in-rtl-flow-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/text/emphasis-ellipsis-complextext-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/text/emphasis-ellipsis-complextext-expected.png
index 2489a174..7eebb7c 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/fast/text/emphasis-ellipsis-complextext-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/fast/text/emphasis-ellipsis-complextext-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/text/ellipsis-with-list-marker-in-ltr-flow-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/text/ellipsis-with-list-marker-in-ltr-flow-expected.png
index 638e302..8c981f3 100644
--- a/third_party/WebKit/LayoutTests/platform/win/fast/text/ellipsis-with-list-marker-in-ltr-flow-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/fast/text/ellipsis-with-list-marker-in-ltr-flow-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/text/emphasis-ellipsis-complextext-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/text/emphasis-ellipsis-complextext-expected.png
index b7021b7..1b69f6f98 100644
--- a/third_party/WebKit/LayoutTests/platform/win/fast/text/emphasis-ellipsis-complextext-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/fast/text/emphasis-ellipsis-complextext-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win7/fast/text/emphasis-ellipsis-complextext-expected.png b/third_party/WebKit/LayoutTests/platform/win7/fast/text/emphasis-ellipsis-complextext-expected.png
index fa4b55e..27008c38 100644
--- a/third_party/WebKit/LayoutTests/platform/win7/fast/text/emphasis-ellipsis-complextext-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win7/fast/text/emphasis-ellipsis-complextext-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/filters/feBlend-all-modes-expected.txt b/third_party/WebKit/LayoutTests/svg/filters/feBlend-all-modes-expected.txt
index ce62c02d..9e928b6 100644
--- a/third_party/WebKit/LayoutTests/svg/filters/feBlend-all-modes-expected.txt
+++ b/third_party/WebKit/LayoutTests/svg/filters/feBlend-all-modes-expected.txt
@@ -5,340 +5,340 @@
     LayoutBlockFlow {BODY} at (8,8) size 784x324
       LayoutBlockFlow {DIV} at (0,0) size 400x108
         LayoutSVGRoot {svg} at (0,0) size 50x50
-          LayoutSVGResourceFilter {filter} [id="f_normal"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
+          LayoutSVGResourceFilter {filter} [id="f_normal0"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
             [feBlend mode="normal"]
               [feFlood flood-color="#FF0000" flood-opacity="1.00"]
               [feFlood flood-color="#00FF00" flood-opacity="1.00"]
           LayoutSVGRect {rect} at (0,0) size 50x50 [fill={[type=SOLID] [color=#000000]}] [x=0.00] [y=0.00] [width=50.00] [height=50.00]
-            [filter="f_normal"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
+            [filter="f_normal0"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
         LayoutSVGRoot {svg} at (50,0) size 50x50
-          LayoutSVGResourceFilter {filter} [id="f_multiply"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
+          LayoutSVGResourceFilter {filter} [id="f_multiply0"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
             [feBlend mode="multiply"]
               [feFlood flood-color="#FF0000" flood-opacity="1.00"]
               [feFlood flood-color="#00FF00" flood-opacity="1.00"]
           LayoutSVGRect {rect} at (0,0) size 50x50 [fill={[type=SOLID] [color=#000000]}] [x=0.00] [y=0.00] [width=50.00] [height=50.00]
-            [filter="f_multiply"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
+            [filter="f_multiply0"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
         LayoutSVGRoot {svg} at (100,0) size 50x50
-          LayoutSVGResourceFilter {filter} [id="f_screen"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
+          LayoutSVGResourceFilter {filter} [id="f_screen0"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
             [feBlend mode="screen"]
               [feFlood flood-color="#FF0000" flood-opacity="1.00"]
               [feFlood flood-color="#00FF00" flood-opacity="1.00"]
           LayoutSVGRect {rect} at (0,0) size 50x50 [fill={[type=SOLID] [color=#000000]}] [x=0.00] [y=0.00] [width=50.00] [height=50.00]
-            [filter="f_screen"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
+            [filter="f_screen0"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
         LayoutSVGRoot {svg} at (150,0) size 50x50
-          LayoutSVGResourceFilter {filter} [id="f_darken"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
+          LayoutSVGResourceFilter {filter} [id="f_darken0"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
             [feBlend mode="darken"]
               [feFlood flood-color="#FF0000" flood-opacity="1.00"]
               [feFlood flood-color="#00FF00" flood-opacity="1.00"]
           LayoutSVGRect {rect} at (0,0) size 50x50 [fill={[type=SOLID] [color=#000000]}] [x=0.00] [y=0.00] [width=50.00] [height=50.00]
-            [filter="f_darken"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
+            [filter="f_darken0"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
         LayoutSVGRoot {svg} at (200,0) size 50x50
-          LayoutSVGResourceFilter {filter} [id="f_lighten"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
+          LayoutSVGResourceFilter {filter} [id="f_lighten0"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
             [feBlend mode="lighten"]
               [feFlood flood-color="#FF0000" flood-opacity="1.00"]
               [feFlood flood-color="#00FF00" flood-opacity="1.00"]
           LayoutSVGRect {rect} at (0,0) size 50x50 [fill={[type=SOLID] [color=#000000]}] [x=0.00] [y=0.00] [width=50.00] [height=50.00]
-            [filter="f_lighten"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
+            [filter="f_lighten0"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
         LayoutSVGRoot {svg} at (250,0) size 50x50
-          LayoutSVGResourceFilter {filter} [id="f_overlay"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
+          LayoutSVGResourceFilter {filter} [id="f_overlay0"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
             [feBlend mode="overlay"]
               [feFlood flood-color="#FF0000" flood-opacity="1.00"]
               [feFlood flood-color="#00FF00" flood-opacity="1.00"]
           LayoutSVGRect {rect} at (0,0) size 50x50 [fill={[type=SOLID] [color=#000000]}] [x=0.00] [y=0.00] [width=50.00] [height=50.00]
-            [filter="f_overlay"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
+            [filter="f_overlay0"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
         LayoutSVGRoot {svg} at (300,0) size 50x50
-          LayoutSVGResourceFilter {filter} [id="f_color-dodge"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
+          LayoutSVGResourceFilter {filter} [id="f_color-dodge0"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
             [feBlend mode="color-dodge"]
               [feFlood flood-color="#FF0000" flood-opacity="1.00"]
               [feFlood flood-color="#00FF00" flood-opacity="1.00"]
           LayoutSVGRect {rect} at (0,0) size 50x50 [fill={[type=SOLID] [color=#000000]}] [x=0.00] [y=0.00] [width=50.00] [height=50.00]
-            [filter="f_color-dodge"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
+            [filter="f_color-dodge0"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
         LayoutSVGRoot {svg} at (350,0) size 50x50
-          LayoutSVGResourceFilter {filter} [id="f_color-burn"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
+          LayoutSVGResourceFilter {filter} [id="f_color-burn0"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
             [feBlend mode="color-burn"]
               [feFlood flood-color="#FF0000" flood-opacity="1.00"]
               [feFlood flood-color="#00FF00" flood-opacity="1.00"]
           LayoutSVGRect {rect} at (0,0) size 50x50 [fill={[type=SOLID] [color=#000000]}] [x=0.00] [y=0.00] [width=50.00] [height=50.00]
-            [filter="f_color-burn"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
+            [filter="f_color-burn0"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
         LayoutSVGRoot {svg} at (0,54) size 50x50
-          LayoutSVGResourceFilter {filter} [id="f_hard-light"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
+          LayoutSVGResourceFilter {filter} [id="f_hard-light0"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
             [feBlend mode="hard-light"]
               [feFlood flood-color="#FF0000" flood-opacity="1.00"]
               [feFlood flood-color="#00FF00" flood-opacity="1.00"]
           LayoutSVGRect {rect} at (0,0) size 50x50 [fill={[type=SOLID] [color=#000000]}] [x=0.00] [y=0.00] [width=50.00] [height=50.00]
-            [filter="f_hard-light"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
+            [filter="f_hard-light0"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
         LayoutSVGRoot {svg} at (50,54) size 50x50
-          LayoutSVGResourceFilter {filter} [id="f_soft-light"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
+          LayoutSVGResourceFilter {filter} [id="f_soft-light0"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
             [feBlend mode="soft-light"]
               [feFlood flood-color="#FF0000" flood-opacity="1.00"]
               [feFlood flood-color="#00FF00" flood-opacity="1.00"]
           LayoutSVGRect {rect} at (0,0) size 50x50 [fill={[type=SOLID] [color=#000000]}] [x=0.00] [y=0.00] [width=50.00] [height=50.00]
-            [filter="f_soft-light"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
+            [filter="f_soft-light0"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
         LayoutSVGRoot {svg} at (100,54) size 50x50
-          LayoutSVGResourceFilter {filter} [id="f_difference"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
+          LayoutSVGResourceFilter {filter} [id="f_difference0"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
             [feBlend mode="difference"]
               [feFlood flood-color="#FF0000" flood-opacity="1.00"]
               [feFlood flood-color="#00FF00" flood-opacity="1.00"]
           LayoutSVGRect {rect} at (0,0) size 50x50 [fill={[type=SOLID] [color=#000000]}] [x=0.00] [y=0.00] [width=50.00] [height=50.00]
-            [filter="f_difference"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
+            [filter="f_difference0"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
         LayoutSVGRoot {svg} at (150,54) size 50x50
-          LayoutSVGResourceFilter {filter} [id="f_exclusion"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
+          LayoutSVGResourceFilter {filter} [id="f_exclusion0"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
             [feBlend mode="exclusion"]
               [feFlood flood-color="#FF0000" flood-opacity="1.00"]
               [feFlood flood-color="#00FF00" flood-opacity="1.00"]
           LayoutSVGRect {rect} at (0,0) size 50x50 [fill={[type=SOLID] [color=#000000]}] [x=0.00] [y=0.00] [width=50.00] [height=50.00]
-            [filter="f_exclusion"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
+            [filter="f_exclusion0"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
         LayoutSVGRoot {svg} at (200,54) size 50x50
-          LayoutSVGResourceFilter {filter} [id="f_hue"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
+          LayoutSVGResourceFilter {filter} [id="f_hue0"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
             [feBlend mode="hue"]
               [feFlood flood-color="#FF0000" flood-opacity="1.00"]
               [feFlood flood-color="#00FF00" flood-opacity="1.00"]
           LayoutSVGRect {rect} at (0,0) size 50x50 [fill={[type=SOLID] [color=#000000]}] [x=0.00] [y=0.00] [width=50.00] [height=50.00]
-            [filter="f_hue"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
+            [filter="f_hue0"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
         LayoutSVGRoot {svg} at (250,54) size 50x50
-          LayoutSVGResourceFilter {filter} [id="f_saturation"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
+          LayoutSVGResourceFilter {filter} [id="f_saturation0"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
             [feBlend mode="saturation"]
               [feFlood flood-color="#FF0000" flood-opacity="1.00"]
               [feFlood flood-color="#00FF00" flood-opacity="1.00"]
           LayoutSVGRect {rect} at (0,0) size 50x50 [fill={[type=SOLID] [color=#000000]}] [x=0.00] [y=0.00] [width=50.00] [height=50.00]
-            [filter="f_saturation"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
+            [filter="f_saturation0"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
         LayoutSVGRoot {svg} at (300,54) size 50x50
-          LayoutSVGResourceFilter {filter} [id="f_color"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
+          LayoutSVGResourceFilter {filter} [id="f_color0"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
             [feBlend mode="color"]
               [feFlood flood-color="#FF0000" flood-opacity="1.00"]
               [feFlood flood-color="#00FF00" flood-opacity="1.00"]
           LayoutSVGRect {rect} at (0,0) size 50x50 [fill={[type=SOLID] [color=#000000]}] [x=0.00] [y=0.00] [width=50.00] [height=50.00]
-            [filter="f_color"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
+            [filter="f_color0"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
         LayoutSVGRoot {svg} at (350,54) size 50x50
-          LayoutSVGResourceFilter {filter} [id="f_luminosity"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
+          LayoutSVGResourceFilter {filter} [id="f_luminosity0"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
             [feBlend mode="luminosity"]
               [feFlood flood-color="#FF0000" flood-opacity="1.00"]
               [feFlood flood-color="#00FF00" flood-opacity="1.00"]
           LayoutSVGRect {rect} at (0,0) size 50x50 [fill={[type=SOLID] [color=#000000]}] [x=0.00] [y=0.00] [width=50.00] [height=50.00]
-            [filter="f_luminosity"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
+            [filter="f_luminosity0"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
       LayoutBlockFlow {DIV} at (0,108) size 400x108
         LayoutSVGRoot {svg} at (0,0) size 50x50
-          LayoutSVGResourceFilter {filter} [id="f_normal"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
+          LayoutSVGResourceFilter {filter} [id="f_normal1"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
             [feBlend mode="normal"]
               [feFlood flood-color="#3340CC" flood-opacity="1.00"]
               [feFlood flood-color="#99C066" flood-opacity="1.00"]
           LayoutSVGRect {rect} at (0,0) size 50x50 [fill={[type=SOLID] [color=#000000]}] [x=0.00] [y=0.00] [width=50.00] [height=50.00]
-            [filter="f_normal"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
+            [filter="f_normal1"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
         LayoutSVGRoot {svg} at (50,0) size 50x50
-          LayoutSVGResourceFilter {filter} [id="f_multiply"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
+          LayoutSVGResourceFilter {filter} [id="f_multiply1"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
             [feBlend mode="multiply"]
               [feFlood flood-color="#3340CC" flood-opacity="1.00"]
               [feFlood flood-color="#99C066" flood-opacity="1.00"]
           LayoutSVGRect {rect} at (0,0) size 50x50 [fill={[type=SOLID] [color=#000000]}] [x=0.00] [y=0.00] [width=50.00] [height=50.00]
-            [filter="f_multiply"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
+            [filter="f_multiply1"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
         LayoutSVGRoot {svg} at (100,0) size 50x50
-          LayoutSVGResourceFilter {filter} [id="f_screen"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
+          LayoutSVGResourceFilter {filter} [id="f_screen1"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
             [feBlend mode="screen"]
               [feFlood flood-color="#3340CC" flood-opacity="1.00"]
               [feFlood flood-color="#99C066" flood-opacity="1.00"]
           LayoutSVGRect {rect} at (0,0) size 50x50 [fill={[type=SOLID] [color=#000000]}] [x=0.00] [y=0.00] [width=50.00] [height=50.00]
-            [filter="f_screen"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
+            [filter="f_screen1"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
         LayoutSVGRoot {svg} at (150,0) size 50x50
-          LayoutSVGResourceFilter {filter} [id="f_darken"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
+          LayoutSVGResourceFilter {filter} [id="f_darken1"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
             [feBlend mode="darken"]
               [feFlood flood-color="#3340CC" flood-opacity="1.00"]
               [feFlood flood-color="#99C066" flood-opacity="1.00"]
           LayoutSVGRect {rect} at (0,0) size 50x50 [fill={[type=SOLID] [color=#000000]}] [x=0.00] [y=0.00] [width=50.00] [height=50.00]
-            [filter="f_darken"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
+            [filter="f_darken1"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
         LayoutSVGRoot {svg} at (200,0) size 50x50
-          LayoutSVGResourceFilter {filter} [id="f_lighten"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
+          LayoutSVGResourceFilter {filter} [id="f_lighten1"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
             [feBlend mode="lighten"]
               [feFlood flood-color="#3340CC" flood-opacity="1.00"]
               [feFlood flood-color="#99C066" flood-opacity="1.00"]
           LayoutSVGRect {rect} at (0,0) size 50x50 [fill={[type=SOLID] [color=#000000]}] [x=0.00] [y=0.00] [width=50.00] [height=50.00]
-            [filter="f_lighten"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
+            [filter="f_lighten1"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
         LayoutSVGRoot {svg} at (250,0) size 50x50
-          LayoutSVGResourceFilter {filter} [id="f_overlay"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
+          LayoutSVGResourceFilter {filter} [id="f_overlay1"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
             [feBlend mode="overlay"]
               [feFlood flood-color="#3340CC" flood-opacity="1.00"]
               [feFlood flood-color="#99C066" flood-opacity="1.00"]
           LayoutSVGRect {rect} at (0,0) size 50x50 [fill={[type=SOLID] [color=#000000]}] [x=0.00] [y=0.00] [width=50.00] [height=50.00]
-            [filter="f_overlay"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
+            [filter="f_overlay1"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
         LayoutSVGRoot {svg} at (300,0) size 50x50
-          LayoutSVGResourceFilter {filter} [id="f_color-dodge"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
+          LayoutSVGResourceFilter {filter} [id="f_color-dodge1"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
             [feBlend mode="color-dodge"]
               [feFlood flood-color="#3340CC" flood-opacity="1.00"]
               [feFlood flood-color="#99C066" flood-opacity="1.00"]
           LayoutSVGRect {rect} at (0,0) size 50x50 [fill={[type=SOLID] [color=#000000]}] [x=0.00] [y=0.00] [width=50.00] [height=50.00]
-            [filter="f_color-dodge"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
+            [filter="f_color-dodge1"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
         LayoutSVGRoot {svg} at (350,0) size 50x50
-          LayoutSVGResourceFilter {filter} [id="f_color-burn"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
+          LayoutSVGResourceFilter {filter} [id="f_color-burn1"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
             [feBlend mode="color-burn"]
               [feFlood flood-color="#3340CC" flood-opacity="1.00"]
               [feFlood flood-color="#99C066" flood-opacity="1.00"]
           LayoutSVGRect {rect} at (0,0) size 50x50 [fill={[type=SOLID] [color=#000000]}] [x=0.00] [y=0.00] [width=50.00] [height=50.00]
-            [filter="f_color-burn"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
+            [filter="f_color-burn1"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
         LayoutSVGRoot {svg} at (0,54) size 50x50
-          LayoutSVGResourceFilter {filter} [id="f_hard-light"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
+          LayoutSVGResourceFilter {filter} [id="f_hard-light1"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
             [feBlend mode="hard-light"]
               [feFlood flood-color="#3340CC" flood-opacity="1.00"]
               [feFlood flood-color="#99C066" flood-opacity="1.00"]
           LayoutSVGRect {rect} at (0,0) size 50x50 [fill={[type=SOLID] [color=#000000]}] [x=0.00] [y=0.00] [width=50.00] [height=50.00]
-            [filter="f_hard-light"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
+            [filter="f_hard-light1"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
         LayoutSVGRoot {svg} at (50,54) size 50x50
-          LayoutSVGResourceFilter {filter} [id="f_soft-light"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
+          LayoutSVGResourceFilter {filter} [id="f_soft-light1"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
             [feBlend mode="soft-light"]
               [feFlood flood-color="#3340CC" flood-opacity="1.00"]
               [feFlood flood-color="#99C066" flood-opacity="1.00"]
           LayoutSVGRect {rect} at (0,0) size 50x50 [fill={[type=SOLID] [color=#000000]}] [x=0.00] [y=0.00] [width=50.00] [height=50.00]
-            [filter="f_soft-light"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
+            [filter="f_soft-light1"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
         LayoutSVGRoot {svg} at (100,54) size 50x50
-          LayoutSVGResourceFilter {filter} [id="f_difference"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
+          LayoutSVGResourceFilter {filter} [id="f_difference1"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
             [feBlend mode="difference"]
               [feFlood flood-color="#3340CC" flood-opacity="1.00"]
               [feFlood flood-color="#99C066" flood-opacity="1.00"]
           LayoutSVGRect {rect} at (0,0) size 50x50 [fill={[type=SOLID] [color=#000000]}] [x=0.00] [y=0.00] [width=50.00] [height=50.00]
-            [filter="f_difference"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
+            [filter="f_difference1"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
         LayoutSVGRoot {svg} at (150,54) size 50x50
-          LayoutSVGResourceFilter {filter} [id="f_exclusion"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
+          LayoutSVGResourceFilter {filter} [id="f_exclusion1"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
             [feBlend mode="exclusion"]
               [feFlood flood-color="#3340CC" flood-opacity="1.00"]
               [feFlood flood-color="#99C066" flood-opacity="1.00"]
           LayoutSVGRect {rect} at (0,0) size 50x50 [fill={[type=SOLID] [color=#000000]}] [x=0.00] [y=0.00] [width=50.00] [height=50.00]
-            [filter="f_exclusion"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
+            [filter="f_exclusion1"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
         LayoutSVGRoot {svg} at (200,54) size 50x50
-          LayoutSVGResourceFilter {filter} [id="f_hue"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
+          LayoutSVGResourceFilter {filter} [id="f_hue1"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
             [feBlend mode="hue"]
               [feFlood flood-color="#3340CC" flood-opacity="1.00"]
               [feFlood flood-color="#99C066" flood-opacity="1.00"]
           LayoutSVGRect {rect} at (0,0) size 50x50 [fill={[type=SOLID] [color=#000000]}] [x=0.00] [y=0.00] [width=50.00] [height=50.00]
-            [filter="f_hue"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
+            [filter="f_hue1"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
         LayoutSVGRoot {svg} at (250,54) size 50x50
-          LayoutSVGResourceFilter {filter} [id="f_saturation"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
+          LayoutSVGResourceFilter {filter} [id="f_saturation1"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
             [feBlend mode="saturation"]
               [feFlood flood-color="#3340CC" flood-opacity="1.00"]
               [feFlood flood-color="#99C066" flood-opacity="1.00"]
           LayoutSVGRect {rect} at (0,0) size 50x50 [fill={[type=SOLID] [color=#000000]}] [x=0.00] [y=0.00] [width=50.00] [height=50.00]
-            [filter="f_saturation"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
+            [filter="f_saturation1"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
         LayoutSVGRoot {svg} at (300,54) size 50x50
-          LayoutSVGResourceFilter {filter} [id="f_color"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
+          LayoutSVGResourceFilter {filter} [id="f_color1"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
             [feBlend mode="color"]
               [feFlood flood-color="#3340CC" flood-opacity="1.00"]
               [feFlood flood-color="#99C066" flood-opacity="1.00"]
           LayoutSVGRect {rect} at (0,0) size 50x50 [fill={[type=SOLID] [color=#000000]}] [x=0.00] [y=0.00] [width=50.00] [height=50.00]
-            [filter="f_color"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
+            [filter="f_color1"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
         LayoutSVGRoot {svg} at (350,54) size 50x50
-          LayoutSVGResourceFilter {filter} [id="f_luminosity"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
+          LayoutSVGResourceFilter {filter} [id="f_luminosity1"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
             [feBlend mode="luminosity"]
               [feFlood flood-color="#3340CC" flood-opacity="1.00"]
               [feFlood flood-color="#99C066" flood-opacity="1.00"]
           LayoutSVGRect {rect} at (0,0) size 50x50 [fill={[type=SOLID] [color=#000000]}] [x=0.00] [y=0.00] [width=50.00] [height=50.00]
-            [filter="f_luminosity"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
+            [filter="f_luminosity1"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
       LayoutBlockFlow {DIV} at (0,216) size 400x108
         LayoutSVGRoot {svg} at (0,0) size 50x50
-          LayoutSVGResourceFilter {filter} [id="f_normal"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
+          LayoutSVGResourceFilter {filter} [id="f_normal2"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
             [feBlend mode="normal"]
               [feFlood flood-color="#3340CC80" flood-opacity="1.00"]
               [feFlood flood-color="#99C06680" flood-opacity="1.00"]
           LayoutSVGRect {rect} at (0,0) size 50x50 [fill={[type=SOLID] [color=#000000]}] [x=0.00] [y=0.00] [width=50.00] [height=50.00]
-            [filter="f_normal"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
+            [filter="f_normal2"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
         LayoutSVGRoot {svg} at (50,0) size 50x50
-          LayoutSVGResourceFilter {filter} [id="f_multiply"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
+          LayoutSVGResourceFilter {filter} [id="f_multiply2"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
             [feBlend mode="multiply"]
               [feFlood flood-color="#3340CC80" flood-opacity="1.00"]
               [feFlood flood-color="#99C06680" flood-opacity="1.00"]
           LayoutSVGRect {rect} at (0,0) size 50x50 [fill={[type=SOLID] [color=#000000]}] [x=0.00] [y=0.00] [width=50.00] [height=50.00]
-            [filter="f_multiply"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
+            [filter="f_multiply2"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
         LayoutSVGRoot {svg} at (100,0) size 50x50
-          LayoutSVGResourceFilter {filter} [id="f_screen"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
+          LayoutSVGResourceFilter {filter} [id="f_screen2"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
             [feBlend mode="screen"]
               [feFlood flood-color="#3340CC80" flood-opacity="1.00"]
               [feFlood flood-color="#99C06680" flood-opacity="1.00"]
           LayoutSVGRect {rect} at (0,0) size 50x50 [fill={[type=SOLID] [color=#000000]}] [x=0.00] [y=0.00] [width=50.00] [height=50.00]
-            [filter="f_screen"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
+            [filter="f_screen2"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
         LayoutSVGRoot {svg} at (150,0) size 50x50
-          LayoutSVGResourceFilter {filter} [id="f_darken"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
+          LayoutSVGResourceFilter {filter} [id="f_darken2"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
             [feBlend mode="darken"]
               [feFlood flood-color="#3340CC80" flood-opacity="1.00"]
               [feFlood flood-color="#99C06680" flood-opacity="1.00"]
           LayoutSVGRect {rect} at (0,0) size 50x50 [fill={[type=SOLID] [color=#000000]}] [x=0.00] [y=0.00] [width=50.00] [height=50.00]
-            [filter="f_darken"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
+            [filter="f_darken2"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
         LayoutSVGRoot {svg} at (200,0) size 50x50
-          LayoutSVGResourceFilter {filter} [id="f_lighten"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
+          LayoutSVGResourceFilter {filter} [id="f_lighten2"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
             [feBlend mode="lighten"]
               [feFlood flood-color="#3340CC80" flood-opacity="1.00"]
               [feFlood flood-color="#99C06680" flood-opacity="1.00"]
           LayoutSVGRect {rect} at (0,0) size 50x50 [fill={[type=SOLID] [color=#000000]}] [x=0.00] [y=0.00] [width=50.00] [height=50.00]
-            [filter="f_lighten"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
+            [filter="f_lighten2"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
         LayoutSVGRoot {svg} at (250,0) size 50x50
-          LayoutSVGResourceFilter {filter} [id="f_overlay"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
+          LayoutSVGResourceFilter {filter} [id="f_overlay2"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
             [feBlend mode="overlay"]
               [feFlood flood-color="#3340CC80" flood-opacity="1.00"]
               [feFlood flood-color="#99C06680" flood-opacity="1.00"]
           LayoutSVGRect {rect} at (0,0) size 50x50 [fill={[type=SOLID] [color=#000000]}] [x=0.00] [y=0.00] [width=50.00] [height=50.00]
-            [filter="f_overlay"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
+            [filter="f_overlay2"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
         LayoutSVGRoot {svg} at (300,0) size 50x50
-          LayoutSVGResourceFilter {filter} [id="f_color-dodge"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
+          LayoutSVGResourceFilter {filter} [id="f_color-dodge2"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
             [feBlend mode="color-dodge"]
               [feFlood flood-color="#3340CC80" flood-opacity="1.00"]
               [feFlood flood-color="#99C06680" flood-opacity="1.00"]
           LayoutSVGRect {rect} at (0,0) size 50x50 [fill={[type=SOLID] [color=#000000]}] [x=0.00] [y=0.00] [width=50.00] [height=50.00]
-            [filter="f_color-dodge"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
+            [filter="f_color-dodge2"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
         LayoutSVGRoot {svg} at (350,0) size 50x50
-          LayoutSVGResourceFilter {filter} [id="f_color-burn"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
+          LayoutSVGResourceFilter {filter} [id="f_color-burn2"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
             [feBlend mode="color-burn"]
               [feFlood flood-color="#3340CC80" flood-opacity="1.00"]
               [feFlood flood-color="#99C06680" flood-opacity="1.00"]
           LayoutSVGRect {rect} at (0,0) size 50x50 [fill={[type=SOLID] [color=#000000]}] [x=0.00] [y=0.00] [width=50.00] [height=50.00]
-            [filter="f_color-burn"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
+            [filter="f_color-burn2"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
         LayoutSVGRoot {svg} at (0,54) size 50x50
-          LayoutSVGResourceFilter {filter} [id="f_hard-light"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
+          LayoutSVGResourceFilter {filter} [id="f_hard-light2"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
             [feBlend mode="hard-light"]
               [feFlood flood-color="#3340CC80" flood-opacity="1.00"]
               [feFlood flood-color="#99C06680" flood-opacity="1.00"]
           LayoutSVGRect {rect} at (0,0) size 50x50 [fill={[type=SOLID] [color=#000000]}] [x=0.00] [y=0.00] [width=50.00] [height=50.00]
-            [filter="f_hard-light"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
+            [filter="f_hard-light2"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
         LayoutSVGRoot {svg} at (50,54) size 50x50
-          LayoutSVGResourceFilter {filter} [id="f_soft-light"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
+          LayoutSVGResourceFilter {filter} [id="f_soft-light2"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
             [feBlend mode="soft-light"]
               [feFlood flood-color="#3340CC80" flood-opacity="1.00"]
               [feFlood flood-color="#99C06680" flood-opacity="1.00"]
           LayoutSVGRect {rect} at (0,0) size 50x50 [fill={[type=SOLID] [color=#000000]}] [x=0.00] [y=0.00] [width=50.00] [height=50.00]
-            [filter="f_soft-light"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
+            [filter="f_soft-light2"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
         LayoutSVGRoot {svg} at (100,54) size 50x50
-          LayoutSVGResourceFilter {filter} [id="f_difference"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
+          LayoutSVGResourceFilter {filter} [id="f_difference2"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
             [feBlend mode="difference"]
               [feFlood flood-color="#3340CC80" flood-opacity="1.00"]
               [feFlood flood-color="#99C06680" flood-opacity="1.00"]
           LayoutSVGRect {rect} at (0,0) size 50x50 [fill={[type=SOLID] [color=#000000]}] [x=0.00] [y=0.00] [width=50.00] [height=50.00]
-            [filter="f_difference"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
+            [filter="f_difference2"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
         LayoutSVGRoot {svg} at (150,54) size 50x50
-          LayoutSVGResourceFilter {filter} [id="f_exclusion"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
+          LayoutSVGResourceFilter {filter} [id="f_exclusion2"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
             [feBlend mode="exclusion"]
               [feFlood flood-color="#3340CC80" flood-opacity="1.00"]
               [feFlood flood-color="#99C06680" flood-opacity="1.00"]
           LayoutSVGRect {rect} at (0,0) size 50x50 [fill={[type=SOLID] [color=#000000]}] [x=0.00] [y=0.00] [width=50.00] [height=50.00]
-            [filter="f_exclusion"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
+            [filter="f_exclusion2"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
         LayoutSVGRoot {svg} at (200,54) size 50x50
-          LayoutSVGResourceFilter {filter} [id="f_hue"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
+          LayoutSVGResourceFilter {filter} [id="f_hue2"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
             [feBlend mode="hue"]
               [feFlood flood-color="#3340CC80" flood-opacity="1.00"]
               [feFlood flood-color="#99C06680" flood-opacity="1.00"]
           LayoutSVGRect {rect} at (0,0) size 50x50 [fill={[type=SOLID] [color=#000000]}] [x=0.00] [y=0.00] [width=50.00] [height=50.00]
-            [filter="f_hue"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
+            [filter="f_hue2"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
         LayoutSVGRoot {svg} at (250,54) size 50x50
-          LayoutSVGResourceFilter {filter} [id="f_saturation"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
+          LayoutSVGResourceFilter {filter} [id="f_saturation2"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
             [feBlend mode="saturation"]
               [feFlood flood-color="#3340CC80" flood-opacity="1.00"]
               [feFlood flood-color="#99C06680" flood-opacity="1.00"]
           LayoutSVGRect {rect} at (0,0) size 50x50 [fill={[type=SOLID] [color=#000000]}] [x=0.00] [y=0.00] [width=50.00] [height=50.00]
-            [filter="f_saturation"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
+            [filter="f_saturation2"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
         LayoutSVGRoot {svg} at (300,54) size 50x50
-          LayoutSVGResourceFilter {filter} [id="f_color"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
+          LayoutSVGResourceFilter {filter} [id="f_color2"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
             [feBlend mode="color"]
               [feFlood flood-color="#3340CC80" flood-opacity="1.00"]
               [feFlood flood-color="#99C06680" flood-opacity="1.00"]
           LayoutSVGRect {rect} at (0,0) size 50x50 [fill={[type=SOLID] [color=#000000]}] [x=0.00] [y=0.00] [width=50.00] [height=50.00]
-            [filter="f_color"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
+            [filter="f_color2"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
         LayoutSVGRoot {svg} at (350,54) size 50x50
-          LayoutSVGResourceFilter {filter} [id="f_luminosity"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
+          LayoutSVGResourceFilter {filter} [id="f_luminosity2"] [filterUnits=objectBoundingBox] [primitiveUnits=userSpaceOnUse]
             [feBlend mode="luminosity"]
               [feFlood flood-color="#3340CC80" flood-opacity="1.00"]
               [feFlood flood-color="#99C06680" flood-opacity="1.00"]
           LayoutSVGRect {rect} at (0,0) size 50x50 [fill={[type=SOLID] [color=#000000]}] [x=0.00] [y=0.00] [width=50.00] [height=50.00]
-            [filter="f_luminosity"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
+            [filter="f_luminosity2"] LayoutSVGResourceFilter {filter} at (0,0) size 50x50
diff --git a/third_party/WebKit/LayoutTests/svg/filters/feBlend-all-modes.html b/third_party/WebKit/LayoutTests/svg/filters/feBlend-all-modes.html
index 75b0317..85a39240 100644
--- a/third_party/WebKit/LayoutTests/svg/filters/feBlend-all-modes.html
+++ b/third_party/WebKit/LayoutTests/svg/filters/feBlend-all-modes.html
@@ -36,13 +36,13 @@
   {a: 'rgb(255,0,0)', b: 'rgb(0,255,0)' },
   {a: 'rgb(51,64,204)', b: 'rgb(153,192,102)' },
   {a: 'rgba(51,64,204,0.5)', b: 'rgba(153,192,102,0.5)' },
-].forEach(function(colors) {
+].forEach(function(colors, groupNr) {
   var group = document.createElement('div');
   group.className = 'group';
   document.body.appendChild(group);
 
-  blendModes.forEach(function(mode, i) {
-    var filterId = 'f_' + mode;
+  blendModes.forEach(function(mode) {
+    var filterId = 'f_' + mode + groupNr;
     var filter = createSvgElement('filter', { id: filterId, x: 0, y: 0, width: 1, height: 1 });
     filter.appendChild(createSvgElement('feFlood', { result: 'a', 'flood-color': colors.a }));
     filter.appendChild(createSvgElement('feFlood', { result: 'b', 'flood-color': colors.b }));
diff --git a/third_party/WebKit/Source/core/css/RuleFeature.cpp b/third_party/WebKit/Source/core/css/RuleFeature.cpp
index 080193259..ec4bba5 100644
--- a/third_party/WebKit/Source/core/css/RuleFeature.cpp
+++ b/third_party/WebKit/Source/core/css/RuleFeature.cpp
@@ -467,8 +467,7 @@
   const CSSSelector* nextCompound =
       lastInCompound ? lastInCompound->tagHistory() : &ruleData.selector();
   if (!nextCompound) {
-    if (!features.hasFeaturesForRuleSetInvalidation)
-      m_metadata.needsFullRecalcForRuleSetInvalidation = true;
+    updateRuleSetInvalidation(features);
     return;
   }
   if (lastInCompound)
@@ -476,9 +475,17 @@
                                  siblingFeatures, features);
 
   addFeaturesToInvalidationSets(*nextCompound, siblingFeatures, features);
+  updateRuleSetInvalidation(features);
+}
 
-  if (!features.hasFeaturesForRuleSetInvalidation)
-    m_metadata.needsFullRecalcForRuleSetInvalidation = true;
+void RuleFeatureSet::updateRuleSetInvalidation(
+    const InvalidationSetFeatures& features) {
+  if (!features.hasFeaturesForRuleSetInvalidation) {
+    if (features.forceSubtree || features.tagNames.isEmpty())
+      m_metadata.needsFullRecalcForRuleSetInvalidation = true;
+    else
+      addTagNamesToTypeRuleInvalidationSet(features.tagNames);
+  }
 }
 
 void RuleFeatureSet::updateInvalidationSetsForContentAttribute(
@@ -608,7 +615,7 @@
     if (!simpleSelector->tagHistory() ||
         simpleSelector->relation() != CSSSelector::SubSelector) {
       features.hasFeaturesForRuleSetInvalidation =
-          features.hasTagIdClassOrAttribute();
+          features.hasIdClassOrAttribute();
       return simpleSelector;
     }
   }
@@ -1160,6 +1167,14 @@
                                  descendantFeatures);
 }
 
+void RuleFeatureSet::addTagNamesToTypeRuleInvalidationSet(
+    const Vector<AtomicString>& tagNames) {
+  DCHECK(!tagNames.isEmpty());
+  ensureTypeRuleInvalidationSet();
+  for (auto tagName : tagNames)
+    m_typeRuleInvalidationSet->addTagName(tagName);
+}
+
 DEFINE_TRACE(RuleFeatureSet) {
   visitor->trace(m_siblingRules);
   visitor->trace(m_uncommonAttributeRules);
@@ -1190,9 +1205,8 @@
          !tagNames.isEmpty() || customPseudoElement;
 }
 
-bool RuleFeatureSet::InvalidationSetFeatures::hasTagIdClassOrAttribute() const {
-  return !classes.isEmpty() || !attributes.isEmpty() || !ids.isEmpty() ||
-         !tagNames.isEmpty();
+bool RuleFeatureSet::InvalidationSetFeatures::hasIdClassOrAttribute() const {
+  return !classes.isEmpty() || !attributes.isEmpty() || !ids.isEmpty();
 }
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/css/RuleFeature.h b/third_party/WebKit/Source/core/css/RuleFeature.h
index 4a894eb..40bd9bd 100644
--- a/third_party/WebKit/Source/core/css/RuleFeature.h
+++ b/third_party/WebKit/Source/core/css/RuleFeature.h
@@ -212,7 +212,7 @@
 
     void add(const InvalidationSetFeatures& other);
     bool hasFeatures() const;
-    bool hasTagIdClassOrAttribute() const;
+    bool hasIdClassOrAttribute() const;
 
     Vector<AtomicString> classes;
     Vector<AtomicString> attributes;
@@ -280,6 +280,9 @@
       const InvalidationSetFeatures& siblingFeatures,
       const InvalidationSetFeatures& descendantFeatures);
 
+  void updateRuleSetInvalidation(const InvalidationSetFeatures&);
+  void addTagNamesToTypeRuleInvalidationSet(const Vector<AtomicString>&);
+
   FeatureMetadata m_metadata;
   InvalidationSetMap m_classInvalidationSets;
   InvalidationSetMap m_attributeInvalidationSets;
diff --git a/third_party/WebKit/Source/core/dom/StyleEngine.cpp b/third_party/WebKit/Source/core/dom/StyleEngine.cpp
index 19826f4..75ef643 100644
--- a/third_party/WebKit/Source/core/dom/StyleEngine.cpp
+++ b/third_party/WebKit/Source/core/dom/StyleEngine.cpp
@@ -832,15 +832,21 @@
     for (const Attribute& attribute : element.attributes())
       ruleSet->features().collectInvalidationSetsForAttribute(
           invalidationLists, element, attribute.name());
-    if (ruleSet->tagRules(element.localNameForSelectorMatching()))
-      element.setNeedsStyleRecalc(LocalStyleChange,
-                                  StyleChangeReasonForTracing::create(
-                                      StyleChangeReason::StyleSheetChange));
   }
   m_styleInvalidator.scheduleInvalidationSetsForNode(invalidationLists,
                                                      element);
 }
 
+void StyleEngine::scheduleTypeRuleSetInvalidations(
+    ContainerNode& node,
+    const HeapHashSet<Member<RuleSet>>& ruleSets) {
+  InvalidationLists invalidationLists;
+  for (const auto& ruleSet : ruleSets)
+    ruleSet->features().collectTypeRuleInvalidationSet(invalidationLists, node);
+  DCHECK(invalidationLists.siblings.isEmpty());
+  m_styleInvalidator.scheduleInvalidationSetsForNode(invalidationLists, node);
+}
+
 void StyleEngine::invalidateSlottedElements(HTMLSlotElement& slot) {
   for (auto& node : slot.getDistributedNodes()) {
     if (node->isElementNode())
@@ -863,6 +869,8 @@
   TRACE_EVENT0("blink,blink_style",
                "StyleEngine::scheduleInvalidationsForRuleSets");
 
+  scheduleTypeRuleSetInvalidations(treeScope.rootNode(), ruleSets);
+
   bool invalidateSlotted = false;
   if (treeScope.rootNode().isShadowRoot()) {
     Element& host = toShadowRoot(treeScope.rootNode()).host();
diff --git a/third_party/WebKit/Source/core/dom/StyleEngine.h b/third_party/WebKit/Source/core/dom/StyleEngine.h
index 20e3d9a..0df63e6 100644
--- a/third_party/WebKit/Source/core/dom/StyleEngine.h
+++ b/third_party/WebKit/Source/core/dom/StyleEngine.h
@@ -315,6 +315,8 @@
   void scheduleRuleSetInvalidationsForElement(
       Element&,
       const HeapHashSet<Member<RuleSet>>&);
+  void scheduleTypeRuleSetInvalidations(ContainerNode&,
+                                        const HeapHashSet<Member<RuleSet>>&);
   void invalidateSlottedElements(HTMLSlotElement&);
 
   void updateViewport();
diff --git a/third_party/WebKit/Source/core/dom/StyleEngineTest.cpp b/third_party/WebKit/Source/core/dom/StyleEngineTest.cpp
index e62026e..7859ffbc 100644
--- a/third_party/WebKit/Source/core/dom/StyleEngineTest.cpp
+++ b/third_party/WebKit/Source/core/dom/StyleEngineTest.cpp
@@ -144,29 +144,44 @@
       "<div>"
       "  <span></span>"
       "  <div></div>"
-      "</div>");
+      "</div>"
+      "<b></b><b></b><b></b><b></b>"
+      "<i id=i>"
+      "  <i>"
+      "    <b></b>"
+      "  </i>"
+      "</i>");
 
   document().view()->updateAllLifecyclePhases();
 
   unsigned beforeCount = styleEngine().styleForElementCount();
   EXPECT_EQ(
-      scheduleInvalidationsForRules(document(), "span { background: green}"),
-      RuleSetInvalidationsScheduled);
+      RuleSetInvalidationsScheduled,
+      scheduleInvalidationsForRules(document(), "span { background: green}"));
   document().view()->updateAllLifecyclePhases();
   unsigned afterCount = styleEngine().styleForElementCount();
   EXPECT_EQ(1u, afterCount - beforeCount);
 
   beforeCount = afterCount;
-  EXPECT_EQ(scheduleInvalidationsForRules(document(),
-                                          "body div { background: green}"),
-            RuleSetInvalidationsScheduled);
+  EXPECT_EQ(RuleSetInvalidationsScheduled,
+            scheduleInvalidationsForRules(document(),
+                                          "body div { background: green}"));
   document().view()->updateAllLifecyclePhases();
   afterCount = styleEngine().styleForElementCount();
   EXPECT_EQ(2u, afterCount - beforeCount);
 
   EXPECT_EQ(
-      scheduleInvalidationsForRules(document(), "div * { background: green}"),
-      RuleSetInvalidationFullRecalc);
+      RuleSetInvalidationFullRecalc,
+      scheduleInvalidationsForRules(document(), "div * { background: green}"));
+  document().view()->updateAllLifecyclePhases();
+
+  beforeCount = styleEngine().styleForElementCount();
+  EXPECT_EQ(
+      RuleSetInvalidationsScheduled,
+      scheduleInvalidationsForRules(document(), "#i b { background: green}"));
+  document().view()->updateAllLifecyclePhases();
+  afterCount = styleEngine().styleForElementCount();
+  EXPECT_EQ(1u, afterCount - beforeCount);
 }
 
 TEST_F(StyleEngineTest, RuleSetInvalidationHost) {
diff --git a/third_party/WebKit/Source/core/frame/RootFrameViewport.h b/third_party/WebKit/Source/core/frame/RootFrameViewport.h
index f84a9511..5c9cb153 100644
--- a/third_party/WebKit/Source/core/frame/RootFrameViewport.h
+++ b/third_party/WebKit/Source/core/frame/RootFrameViewport.h
@@ -64,10 +64,6 @@
   IntRect visibleContentRect(
       IncludeScrollbarsInRect = ExcludeScrollbars) const override;
   bool shouldUseIntegerScrollOffset() const override;
-  LayoutRect visualRectForScrollbarParts() const override {
-    ASSERT_NOT_REACHED();
-    return LayoutRect();
-  }
   bool isActive() const override;
   int scrollSize(ScrollbarOrientation) const override;
   bool isScrollCornerVisible() const override;
diff --git a/third_party/WebKit/Source/core/frame/RootFrameViewportTest.cpp b/third_party/WebKit/Source/core/frame/RootFrameViewportTest.cpp
index 4249201b..6c0cb3c 100644
--- a/third_party/WebKit/Source/core/frame/RootFrameViewportTest.cpp
+++ b/third_party/WebKit/Source/core/frame/RootFrameViewportTest.cpp
@@ -88,10 +88,6 @@
     m_scrollOffset = offset;
   }
   bool shouldUseIntegerScrollOffset() const override { return true; }
-  LayoutRect visualRectForScrollbarParts() const override {
-    ASSERT_NOT_REACHED();
-    return LayoutRect();
-  }
   bool isActive() const override { return true; }
   bool isScrollCornerVisible() const override { return true; }
   IntRect scrollCornerRect() const override { return IntRect(); }
diff --git a/third_party/WebKit/Source/core/frame/VisualViewport.h b/third_party/WebKit/Source/core/frame/VisualViewport.h
index f094835..5168e769 100644
--- a/third_party/WebKit/Source/core/frame/VisualViewport.h
+++ b/third_party/WebKit/Source/core/frame/VisualViewport.h
@@ -168,10 +168,6 @@
   void setScrollOffset(const ScrollOffset&,
                        ScrollType,
                        ScrollBehavior = ScrollBehaviorInstant) override;
-  LayoutRect visualRectForScrollbarParts() const override {
-    ASSERT_NOT_REACHED();
-    return LayoutRect();
-  }
   bool isActive() const override { return false; }
   int scrollSize(ScrollbarOrientation) const override;
   bool isScrollCornerVisible() const override { return false; }
diff --git a/third_party/WebKit/Source/core/layout/LayoutObject.h b/third_party/WebKit/Source/core/layout/LayoutObject.h
index 5ec3340c..4cc4a99 100644
--- a/third_party/WebKit/Source/core/layout/LayoutObject.h
+++ b/third_party/WebKit/Source/core/layout/LayoutObject.h
@@ -213,7 +213,7 @@
   String decoratedName() const;
 
   // DisplayItemClient methods.
-  LayoutRect visualRect() const override;
+  LayoutRect visualRect() const final;
   String debugName() const final;
 
   LayoutObject* parent() const { return m_parent; }
diff --git a/third_party/WebKit/Source/core/layout/LayoutScrollbar.cpp b/third_party/WebKit/Source/core/layout/LayoutScrollbar.cpp
index 4e9fac1..e4e120b 100644
--- a/third_party/WebKit/Source/core/layout/LayoutScrollbar.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutScrollbar.cpp
@@ -381,10 +381,17 @@
 }
 
 void LayoutScrollbar::invalidateDisplayItemClientsOfScrollbarParts() {
-  for (auto& part : m_parts)
+  for (auto& part : m_parts) {
     ObjectPaintInvalidator(*part.value)
         .invalidateDisplayItemClientsIncludingNonCompositingDescendants(
             PaintInvalidationScroll);
+  }
+}
+
+void LayoutScrollbar::setVisualRect(const LayoutRect& rect) {
+  Scrollbar::setVisualRect(rect);
+  for (auto& part : m_parts)
+    part.value->setPreviousVisualRect(rect);
 }
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/layout/LayoutScrollbar.h b/third_party/WebKit/Source/core/layout/LayoutScrollbar.h
index bd8363b..005f0ad 100644
--- a/third_party/WebKit/Source/core/layout/LayoutScrollbar.h
+++ b/third_party/WebKit/Source/core/layout/LayoutScrollbar.h
@@ -67,6 +67,8 @@
 
   void invalidateDisplayItemClientsOfScrollbarParts();
 
+  void setVisualRect(const LayoutRect&) final;
+
   DECLARE_VIRTUAL_TRACE();
 
  protected:
diff --git a/third_party/WebKit/Source/core/layout/LayoutScrollbarPart.cpp b/third_party/WebKit/Source/core/layout/LayoutScrollbarPart.cpp
index 0193163e..765bf915 100644
--- a/third_party/WebKit/Source/core/layout/LayoutScrollbarPart.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutScrollbarPart.cpp
@@ -243,10 +243,4 @@
   m_scrollableArea->setScrollCornerNeedsPaintInvalidation();
 }
 
-LayoutRect LayoutScrollbarPart::visualRect() const {
-  // This returns the combined bounds of all scrollbar parts, which is
-  // sufficient for correctness but not as tight as it could be.
-  return m_scrollableArea->visualRectForScrollbarParts();
-}
-
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/layout/LayoutScrollbarPart.h b/third_party/WebKit/Source/core/layout/LayoutScrollbarPart.h
index 1266fcf..b71c454 100644
--- a/third_party/WebKit/Source/core/layout/LayoutScrollbarPart.h
+++ b/third_party/WebKit/Source/core/layout/LayoutScrollbarPart.h
@@ -79,7 +79,9 @@
   // Must call setStyleWithWritingModeOfParent() instead.
   void setStyle(PassRefPtr<ComputedStyle>) = delete;
 
-  LayoutRect visualRect() const override;
+  // Expose for LayoutScrollbar and PaintInvalidationCapableScrollableArea for
+  // paint invalidation.
+  using LayoutObject::setPreviousVisualRect;
 
  protected:
   void styleWillChange(StyleDifference, const ComputedStyle& newStyle) override;
diff --git a/third_party/WebKit/Source/core/layout/ng/ng_inline_node.cc b/third_party/WebKit/Source/core/layout/ng/ng_inline_node.cc
index 406a740..31cd036 100644
--- a/third_party/WebKit/Source/core/layout/ng/ng_inline_node.cc
+++ b/third_party/WebKit/Source/core/layout/ng/ng_inline_node.cc
@@ -21,6 +21,7 @@
 #include "platform/fonts/CharacterRange.h"
 #include "platform/fonts/shaping/CachingWordShapeIterator.h"
 #include "platform/fonts/shaping/CachingWordShaper.h"
+#include "platform/fonts/shaping/HarfBuzzShaper.h"
 #include "platform/fonts/shaping/ShapeResultBuffer.h"
 #include "wtf/text/CharacterNames.h"
 
@@ -199,44 +200,34 @@
   if (start == end)
     return LayoutUnit();
 
-  if (!style_) {
+  if (!style_ || !shape_result_) {
     // Bidi controls do not have widths.
     // TODO(kojii): Atomic inline not supported yet.
     return LayoutUnit();
   }
 
-  float total_width = 0;
-  for (const auto& result : shape_results_)
-    total_width += result->width();
-
   if (start == start_offset_ && end == end_offset_)
-    return LayoutUnit(total_width);
+    return LayoutUnit(shape_result_->width());
 
   return LayoutUnit(ShapeResultBuffer::getCharacterRange(
-                        shape_results_, Direction(), total_width,
+                        shape_result_, Direction(), shape_result_->width(),
                         start - StartOffset(), end - StartOffset())
                         .width());
 }
 
 void NGInlineNode::ShapeText() {
-  // TODO(layout-dev): Should pass the entire range to the shaper as context
-  // and then shape each item based on the relevant font.
+  // TODO(eae): Add support for shaping latin-1 text?
+  text_content_.ensure16Bit();
+
+  // Shape each item with the full context of the entire node.
+  HarfBuzzShaper shaper(text_content_.characters16(), text_content_.length());
   for (auto& item : items_) {
     // Skip object replacement characters and bidi control characters.
     if (!item.style_)
       continue;
-    StringView item_text(text_content_, item.start_offset_,
-                         item.end_offset_ - item.start_offset_);
-    const Font& item_font = item.style_->font();
-    ShapeCache* shape_cache = item_font.shapeCache();
 
-    TextRun item_run(item_text);
-    item_run.setDirection(item.Direction());
-    CachingWordShapeIterator iterator(shape_cache, item_run, &item_font);
-    RefPtr<const ShapeResult> word_result;
-    while (iterator.next(&word_result)) {
-      item.shape_results_.push_back(std::move(word_result));
-    }
+    item.shape_result_ = shaper.shape(&item.Style()->font(), item.Direction(),
+                                      item.StartOffset(), item.EndOffset());
   }
 }
 
diff --git a/third_party/WebKit/Source/core/layout/ng/ng_inline_node.h b/third_party/WebKit/Source/core/layout/ng/ng_inline_node.h
index 85914af..83f4c5bc 100644
--- a/third_party/WebKit/Source/core/layout/ng/ng_inline_node.h
+++ b/third_party/WebKit/Source/core/layout/ng/ng_inline_node.h
@@ -143,7 +143,7 @@
   FontFallbackPriority fallback_priority_;
   bool rotate_sideways_;
   const ComputedStyle* style_;
-  Vector<RefPtr<const ShapeResult>, 64> shape_results_;
+  RefPtr<const ShapeResult> shape_result_;
   LayoutObject* layout_object_;
 
   friend class NGInlineNode;
diff --git a/third_party/WebKit/Source/core/paint/NinePieceImageGrid.cpp b/third_party/WebKit/Source/core/paint/NinePieceImageGrid.cpp
index 087128f..f918106 100644
--- a/third_party/WebKit/Source/core/paint/NinePieceImageGrid.cpp
+++ b/third_party/WebKit/Source/core/paint/NinePieceImageGrid.cpp
@@ -63,8 +63,10 @@
   // as its height, and Wside as the border image width offset for the side, let
   // f = min(Lwidth/(Wleft+Wright), Lheight/(Wtop+Wbottom)). If f < 1, then all
   // W are reduced by multiplying them by f.
-  int borderSideWidth = std::max(1, m_left.width + m_right.width);
-  int borderSideHeight = std::max(1, m_top.width + m_bottom.width);
+  int borderSideWidth =
+      std::max(1, SaturatedAddition(m_left.width, m_right.width));
+  int borderSideHeight =
+      std::max(1, SaturatedAddition(m_top.width, m_bottom.width));
   float borderSideScaleFactor =
       std::min((float)borderImageArea.width() / borderSideWidth,
                (float)borderImageArea.height() / borderSideHeight);
diff --git a/third_party/WebKit/Source/core/paint/PaintInvalidationCapableScrollableArea.cpp b/third_party/WebKit/Source/core/paint/PaintInvalidationCapableScrollableArea.cpp
index 0fdbed2..aed9e07 100644
--- a/third_party/WebKit/Source/core/paint/PaintInvalidationCapableScrollableArea.cpp
+++ b/third_party/WebKit/Source/core/paint/PaintInvalidationCapableScrollableArea.cpp
@@ -40,6 +40,10 @@
   // transform node).
   if (!visualRect.isEmpty() &&
       !RuntimeEnabledFeatures::slimmingPaintV2Enabled()) {
+    // PaintInvalidatorContext::mapLocalRectToPaintInvalidationBacking() treats
+    // the rect as in flipped block direction, but scrollbar controls don't
+    // flip for block direction, so flip here to undo the flip in the function.
+    box.flipForWritingMode(visualRect);
     context.mapLocalRectToPaintInvalidationBacking(box, visualRect);
 
     IntSize adjustment = box.scrollAdjustmentForPaintInvalidation(
@@ -71,11 +75,11 @@
   return false;
 }
 
-static void invalidatePaintOfScrollbarIfNeeded(
+static LayoutRect invalidatePaintOfScrollbarIfNeeded(
     Scrollbar* scrollbar,
     GraphicsLayer* graphicsLayer,
     bool& previouslyWasOverlay,
-    LayoutRect& previousVisualRect,
+    const LayoutRect& previousVisualRect,
     bool needsPaintInvalidationArg,
     LayoutBox& box,
     const PaintInvalidatorContext& context) {
@@ -128,52 +132,55 @@
       newVisualRect, previousVisualRect, needsPaintInvalidation, box,
       paintInvalidationContainer);
 
-  previousVisualRect = newVisualRect;
   previouslyWasOverlay = isOverlay;
 
   if (!invalidated || !scrollbar || graphicsLayer)
-    return;
+    return newVisualRect;
 
   context.paintingLayer->setNeedsRepaint();
   ObjectPaintInvalidator(box).invalidateDisplayItemClient(
       *scrollbar, PaintInvalidationScroll);
-  if (scrollbar->isCustomScrollbar())
+  if (scrollbar->isCustomScrollbar()) {
     toLayoutScrollbar(scrollbar)
         ->invalidateDisplayItemClientsOfScrollbarParts();
+  }
+
+  return newVisualRect;
 }
 
 void PaintInvalidationCapableScrollableArea::
     invalidatePaintOfScrollControlsIfNeeded(
         const PaintInvalidatorContext& context) {
   LayoutBox& box = *layoutBox();
-  invalidatePaintOfScrollbarIfNeeded(
+  setHorizontalScrollbarVisualRect(invalidatePaintOfScrollbarIfNeeded(
       horizontalScrollbar(), layerForHorizontalScrollbar(),
       m_horizontalScrollbarPreviouslyWasOverlay,
-      m_horizontalScrollbarPreviousVisualRect,
-      horizontalScrollbarNeedsPaintInvalidation(), box, context);
-  invalidatePaintOfScrollbarIfNeeded(
+      m_horizontalScrollbarVisualRect,
+      horizontalScrollbarNeedsPaintInvalidation(), box, context));
+  setVerticalScrollbarVisualRect(invalidatePaintOfScrollbarIfNeeded(
       verticalScrollbar(), layerForVerticalScrollbar(),
-      m_verticalScrollbarPreviouslyWasOverlay,
-      m_verticalScrollbarPreviousVisualRect,
-      verticalScrollbarNeedsPaintInvalidation(), box, context);
+      m_verticalScrollbarPreviouslyWasOverlay, m_verticalScrollbarVisualRect,
+      verticalScrollbarNeedsPaintInvalidation(), box, context));
 
-  LayoutRect scrollCornerVisualRect =
+  LayoutRect scrollCornerAndResizerVisualRect =
       scrollControlVisualRect(scrollCornerAndResizerRect(), box, context);
   const LayoutBoxModelObject& paintInvalidationContainer =
       *context.paintInvalidationContainer;
   if (invalidatePaintOfScrollControlIfNeeded(
-          scrollCornerVisualRect, m_scrollCornerAndResizerPreviousVisualRect,
+          scrollCornerAndResizerVisualRect, m_scrollCornerAndResizerVisualRect,
           scrollCornerNeedsPaintInvalidation(), box,
           paintInvalidationContainer)) {
-    m_scrollCornerAndResizerPreviousVisualRect = scrollCornerVisualRect;
-    if (LayoutScrollbarPart* scrollCorner = this->scrollCorner())
+    setScrollCornerAndResizerVisualRect(scrollCornerAndResizerVisualRect);
+    if (LayoutScrollbarPart* scrollCorner = this->scrollCorner()) {
       ObjectPaintInvalidator(*scrollCorner)
           .invalidateDisplayItemClientsIncludingNonCompositingDescendants(
               PaintInvalidationScroll);
-    if (LayoutScrollbarPart* resizer = this->resizer())
+    }
+    if (LayoutScrollbarPart* resizer = this->resizer()) {
       ObjectPaintInvalidator(*resizer)
           .invalidateDisplayItemClientsIncludingNonCompositingDescendants(
               PaintInvalidationScroll);
+    }
   }
 
   clearNeedsPaintInvalidationForScrollControls();
@@ -187,17 +194,32 @@
 }
 
 void PaintInvalidationCapableScrollableArea::clearPreviousVisualRects() {
-  m_horizontalScrollbarPreviousVisualRect = LayoutRect();
-  m_verticalScrollbarPreviousVisualRect = LayoutRect();
-  m_scrollCornerAndResizerPreviousVisualRect = LayoutRect();
+  setHorizontalScrollbarVisualRect(LayoutRect());
+  setVerticalScrollbarVisualRect(LayoutRect());
+  setScrollCornerAndResizerVisualRect(LayoutRect());
 }
 
-LayoutRect PaintInvalidationCapableScrollableArea::visualRectForScrollbarParts()
-    const {
-  LayoutRect fullBounds(m_horizontalScrollbarPreviousVisualRect);
-  fullBounds.unite(m_verticalScrollbarPreviousVisualRect);
-  fullBounds.unite(m_scrollCornerAndResizerPreviousVisualRect);
-  return fullBounds;
+void PaintInvalidationCapableScrollableArea::setHorizontalScrollbarVisualRect(
+    const LayoutRect& rect) {
+  m_horizontalScrollbarVisualRect = rect;
+  if (Scrollbar* scrollbar = horizontalScrollbar())
+    scrollbar->setVisualRect(rect);
+}
+
+void PaintInvalidationCapableScrollableArea::setVerticalScrollbarVisualRect(
+    const LayoutRect& rect) {
+  m_verticalScrollbarVisualRect = rect;
+  if (Scrollbar* scrollbar = verticalScrollbar())
+    scrollbar->setVisualRect(rect);
+}
+
+void PaintInvalidationCapableScrollableArea::
+    setScrollCornerAndResizerVisualRect(const LayoutRect& rect) {
+  m_scrollCornerAndResizerVisualRect = rect;
+  if (LayoutScrollbarPart* scrollCorner = this->scrollCorner())
+    scrollCorner->setPreviousVisualRect(rect);
+  if (LayoutScrollbarPart* resizer = this->resizer())
+    resizer->setPreviousVisualRect(rect);
 }
 
 void PaintInvalidationCapableScrollableArea::
diff --git a/third_party/WebKit/Source/core/paint/PaintInvalidationCapableScrollableArea.h b/third_party/WebKit/Source/core/paint/PaintInvalidationCapableScrollableArea.h
index 77ce4c6..12a8ca58 100644
--- a/third_party/WebKit/Source/core/paint/PaintInvalidationCapableScrollableArea.h
+++ b/third_party/WebKit/Source/core/paint/PaintInvalidationCapableScrollableArea.h
@@ -38,8 +38,6 @@
     return scrollCornerRect();
   }
 
-  LayoutRect visualRectForScrollbarParts() const override;
-
   void didScrollWithScrollbar(ScrollbarPart, ScrollbarOrientation) override;
 
  private:
@@ -48,11 +46,15 @@
 
   void scrollControlWasSetNeedsPaintInvalidation() override;
 
+  void setHorizontalScrollbarVisualRect(const LayoutRect&);
+  void setVerticalScrollbarVisualRect(const LayoutRect&);
+  void setScrollCornerAndResizerVisualRect(const LayoutRect&);
+
   bool m_horizontalScrollbarPreviouslyWasOverlay;
   bool m_verticalScrollbarPreviouslyWasOverlay;
-  LayoutRect m_horizontalScrollbarPreviousVisualRect;
-  LayoutRect m_verticalScrollbarPreviousVisualRect;
-  LayoutRect m_scrollCornerAndResizerPreviousVisualRect;
+  LayoutRect m_horizontalScrollbarVisualRect;
+  LayoutRect m_verticalScrollbarVisualRect;
+  LayoutRect m_scrollCornerAndResizerVisualRect;
 };
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/paint/PaintPropertyTreeBuilder.cpp b/third_party/WebKit/Source/core/paint/PaintPropertyTreeBuilder.cpp
index a49b7bb..0b61beb5f 100644
--- a/third_party/WebKit/Source/core/paint/PaintPropertyTreeBuilder.cpp
+++ b/third_party/WebKit/Source/core/paint/PaintPropertyTreeBuilder.cpp
@@ -88,7 +88,8 @@
     const IntSize& bounds,
     bool userScrollableHorizontal,
     bool userScrollableVertical,
-    MainThreadScrollingReasons mainThreadScrollingReasons) {
+    MainThreadScrollingReasons mainThreadScrollingReasons,
+    WebLayerScrollClient* scrollClient) {
   DCHECK(!RuntimeEnabledFeatures::rootLayerScrollingEnabled());
   CompositorElementId compositorElementId =
       createDomNodeBasedCompositorElementId(*frameView.layoutView());
@@ -99,7 +100,7 @@
         std::move(parent), matrix, origin, false, 0, CompositingReasonNone,
         compositorElementId, std::move(scrollParent), clip, bounds,
         userScrollableHorizontal, userScrollableVertical,
-        mainThreadScrollingReasons);
+        mainThreadScrollingReasons, scrollClient);
     return existingReasons != mainThreadScrollingReasons;
   }
   frameView.setScrollTranslation(
@@ -107,7 +108,7 @@
           std::move(parent), matrix, origin, false, 0, CompositingReasonNone,
           compositorElementId, std::move(scrollParent), clip, bounds,
           userScrollableHorizontal, userScrollableVertical,
-          mainThreadScrollingReasons));
+          mainThreadScrollingReasons, scrollClient));
   return true;
 }
 
@@ -175,7 +176,8 @@
       context.forceSubtreeUpdate |= updateScrollTranslation(
           frameView, frameView.preTranslation(), frameScroll, FloatPoint3D(),
           context.current.scroll, scrollClip, scrollBounds,
-          userScrollableHorizontal, userScrollableVertical, reasons);
+          userScrollableHorizontal, userScrollableVertical, reasons,
+          frameView.getScrollableArea());
     } else {
       if (frameView.scrollTranslation()) {
         // Ensure pre-existing properties are cleared if there is no scrolling.
@@ -853,7 +855,7 @@
       bool scrollNodeNeededForMainThreadReasons = ancestorReasons != reasons;
 
       const LayoutBox& box = toLayoutBox(object);
-      const auto* scrollableArea = box.getScrollableArea();
+      auto* scrollableArea = box.getScrollableArea();
       IntSize scrollOffset = box.scrolledContentOffset();
       if (scrollNodeNeededForMainThreadReasons || !scrollOffset.isZero() ||
           scrollableArea->scrollsOverflow()) {
@@ -886,7 +888,7 @@
             context.current.renderingContextId, CompositingReasonNone,
             compositorElementId, context.current.scroll, scrollClip,
             scrollBounds, userScrollableHorizontal, userScrollableVertical,
-            reasons);
+            reasons, scrollableArea);
       }
     }
 
diff --git a/third_party/WebKit/Source/devtools/front_end/components/CPUThrottlingManager.js b/third_party/WebKit/Source/devtools/front_end/components/CPUThrottlingManager.js
index 4ce1d5b..8b5d156 100644
--- a/third_party/WebKit/Source/devtools/front_end/components/CPUThrottlingManager.js
+++ b/third_party/WebKit/Source/devtools/front_end/components/CPUThrottlingManager.js
@@ -23,6 +23,7 @@
     SDK.targetManager.targets().forEach(target => target.emulationAgent().setCPUThrottlingRate(this._throttlingRate));
     var icon = null;
     if (this._throttlingRate !== 1) {
+      Host.userMetrics.actionTaken(Host.UserMetrics.Action.CpuThrottlingEnabled);
       icon = UI.Icon.create('smallicon-warning');
       icon.title = Common.UIString('CPU throttling is enabled');
     }
diff --git a/third_party/WebKit/Source/devtools/front_end/host/UserMetrics.js b/third_party/WebKit/Source/devtools/front_end/host/UserMetrics.js
index e947a4dbd..1e3d888 100644
--- a/third_party/WebKit/Source/devtools/front_end/host/UserMetrics.js
+++ b/third_party/WebKit/Source/devtools/front_end/host/UserMetrics.js
@@ -83,6 +83,7 @@
   TimelinePageReloadStarted: 18,
   ConnectToNodeJSFromFrontend: 19,
   ConnectToNodeJSDirectly: 20,
+  CpuThrottlingEnabled: 21,
 };
 
 Host.UserMetrics._PanelCodes = {
diff --git a/third_party/WebKit/Source/devtools/front_end/sources/CallStackSidebarPane.js b/third_party/WebKit/Source/devtools/front_end/sources/CallStackSidebarPane.js
index 933f79f..66bd6c65 100644
--- a/third_party/WebKit/Source/devtools/front_end/sources/CallStackSidebarPane.js
+++ b/third_party/WebKit/Source/devtools/front_end/sources/CallStackSidebarPane.js
@@ -215,19 +215,8 @@
       fromElement.classList.remove('selected');
     if (toElement)
       toElement.classList.add('selected');
-
-    if (!to)
-      return;
-
-    var oldCallFrame = UI.context.flavor(SDK.DebuggerModel.CallFrame);
-    if (oldCallFrame === to.debuggerCallFrame) {
-      var uiLocation = Bindings.debuggerWorkspaceBinding.rawLocationToUILocation(oldCallFrame.location());
-      Common.Revealer.reveal(uiLocation);
-      return;
-    }
-
-    UI.context.setFlavor(SDK.DebuggerModel.CallFrame, to.debuggerCallFrame);
-    this._debuggerModel.setSelectedCallFrame(to.debuggerCallFrame);
+    if (to)
+      this._activateItem(to);
   }
 
   /**
@@ -297,12 +286,23 @@
    */
   _onClick(event) {
     var item = this._list.itemForNode(/** @type {?Node} */ (event.target));
-    if (!item || (!item.runtimeCallFrame && !item.promiseCreationFrame))
-      return;
+    if (item)
+      this._activateItem(item);
+  }
+
+  /**
+   * @param {!Sources.CallStackSidebarPane.Item} item
+   */
+  _activateItem(item) {
     var location = this._itemLocation(item);
     if (!location)
       return;
-    Common.Revealer.reveal(Bindings.debuggerWorkspaceBinding.rawLocationToUILocation(location));
+    if (item.debuggerCallFrame && UI.context.flavor(SDK.DebuggerModel.CallFrame) !== item.debuggerCallFrame) {
+      UI.context.setFlavor(SDK.DebuggerModel.CallFrame, item.debuggerCallFrame);
+      this._debuggerModel.setSelectedCallFrame(item.debuggerCallFrame);
+    } else {
+      Common.Revealer.reveal(Bindings.debuggerWorkspaceBinding.rawLocationToUILocation(location));
+    }
   }
 
   /**
diff --git a/third_party/WebKit/Source/modules/webgl/WebGLContextAttributeHelpers.cpp b/third_party/WebKit/Source/modules/webgl/WebGLContextAttributeHelpers.cpp
index bf24b48..8c07036e 100644
--- a/third_party/WebKit/Source/modules/webgl/WebGLContextAttributeHelpers.cpp
+++ b/third_party/WebKit/Source/modules/webgl/WebGLContextAttributeHelpers.cpp
@@ -23,10 +23,19 @@
 
 Platform::ContextAttributes toPlatformContextAttributes(
     const CanvasContextCreationAttributes& attrs,
-    unsigned webGLVersion) {
+    unsigned webGLVersion,
+    bool supportOwnOffscreenSurface) {
   Platform::ContextAttributes result;
   result.failIfMajorPerformanceCaveat = attrs.failIfMajorPerformanceCaveat();
   result.webGLVersion = webGLVersion;
+  if (supportOwnOffscreenSurface) {
+    // Only ask for alpha/depth/stencil/antialias if we may be using the default
+    // framebuffer. They are not needed for standard offscreen rendering.
+    result.supportAlpha = attrs.alpha();
+    result.supportDepth = attrs.depth();
+    result.supportStencil = attrs.stencil();
+    result.supportAntialias = attrs.antialias();
+  }
   return result;
 }
 
diff --git a/third_party/WebKit/Source/modules/webgl/WebGLContextAttributeHelpers.h b/third_party/WebKit/Source/modules/webgl/WebGLContextAttributeHelpers.h
index 8f40b86b..8aa2a335 100644
--- a/third_party/WebKit/Source/modules/webgl/WebGLContextAttributeHelpers.h
+++ b/third_party/WebKit/Source/modules/webgl/WebGLContextAttributeHelpers.h
@@ -18,7 +18,8 @@
 // Platform API.
 Platform::ContextAttributes toPlatformContextAttributes(
     const CanvasContextCreationAttributes&,
-    unsigned webGLVersion);
+    unsigned webGLVersion,
+    bool supportOwnOffscreenSurface);
 
 }  // namespace blink
 
diff --git a/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.cpp b/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.cpp
index be351bc..6158955 100644
--- a/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.cpp
+++ b/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.cpp
@@ -25,6 +25,7 @@
 
 #include "modules/webgl/WebGLRenderingContextBase.h"
 
+#include <memory>
 #include "bindings/core/v8/ExceptionMessages.h"
 #include "bindings/core/v8/ExceptionState.h"
 #include "bindings/core/v8/ScriptWrappableVisitor.h"
@@ -47,6 +48,7 @@
 #include "core/layout/LayoutBox.h"
 #include "core/loader/FrameLoader.h"
 #include "core/loader/FrameLoaderClient.h"
+#include "core/origin_trials/OriginTrials.h"
 #include "gpu/command_buffer/client/gles2_interface.h"
 #include "modules/webgl/ANGLEInstancedArrays.h"
 #include "modules/webgl/EXTBlendMinMax.h"
@@ -102,7 +104,6 @@
 #include "wtf/text/StringBuilder.h"
 #include "wtf/text/StringUTF8Adaptor.h"
 #include "wtf/typed_arrays/ArrayBufferContents.h"
-#include <memory>
 
 namespace blink {
 
@@ -611,6 +612,24 @@
   return std::move(creationInfo.createdContextProvider);
 }
 
+bool WebGLRenderingContextBase::supportOwnOffscreenSurface(
+    ExecutionContext* executionContext) {
+  // If there's a possibility this context may be used with WebVR make sure it
+  // is created with an offscreen surface that can be swapped out for a
+  // VR-specific surface if needed.
+  //
+  // At this time, treat this as an experimental rendering optimization
+  // that needs a separate opt-in. See crbug.com/691102 for details.
+  if (RuntimeEnabledFeatures::webVRExperimentalRenderingEnabled()) {
+    if (RuntimeEnabledFeatures::webVREnabled() ||
+        OriginTrials::webVREnabled(executionContext)) {
+      DVLOG(1) << "Requesting supportOwnOffscreenSurface";
+      return true;
+    }
+  }
+  return false;
+}
+
 std::unique_ptr<WebGraphicsContext3DProvider>
 WebGLRenderingContextBase::createContextProviderInternal(
     HTMLCanvasElement* canvas,
@@ -622,8 +641,11 @@
   // The canvas is only given on the main thread.
   DCHECK(!canvas || isMainThread());
 
-  Platform::ContextAttributes contextAttributes =
-      toPlatformContextAttributes(attributes, webGLVersion);
+  auto executionContext = canvas ? canvas->document().getExecutionContext()
+                                 : scriptState->getExecutionContext();
+  Platform::ContextAttributes contextAttributes = toPlatformContextAttributes(
+      attributes, webGLVersion, supportOwnOffscreenSurface(executionContext));
+
   Platform::GraphicsInfo glInfo;
   std::unique_ptr<WebGraphicsContext3DProvider> contextProvider;
   const auto& url = canvas ? canvas->document().topDocument().url()
@@ -7458,8 +7480,11 @@
     m_drawingBuffer.clear();
   }
 
+  auto executionContext = canvas() ? canvas()->document().getExecutionContext()
+                                   : offscreenCanvas()->getExecutionContext();
   Platform::ContextAttributes attributes =
-      toPlatformContextAttributes(creationAttributes(), version());
+      toPlatformContextAttributes(creationAttributes(), version(),
+                                  supportOwnOffscreenSurface(executionContext));
   Platform::GraphicsInfo glInfo;
   std::unique_ptr<WebGraphicsContext3DProvider> contextProvider;
   const auto& url = canvas() ? canvas()->document().topDocument().url()
diff --git a/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.h b/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.h
index 23c818a..119e746 100644
--- a/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.h
+++ b/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.h
@@ -1635,6 +1635,7 @@
                             std::unique_ptr<WebGraphicsContext3DProvider>,
                             const CanvasContextCreationAttributes&,
                             unsigned);
+  static bool supportOwnOffscreenSurface(ExecutionContext*);
   static std::unique_ptr<WebGraphicsContext3DProvider>
   createContextProviderInternal(HTMLCanvasElement*,
                                 ScriptState*,
diff --git a/third_party/WebKit/Source/platform/RuntimeEnabledFeatures.json5 b/third_party/WebKit/Source/platform/RuntimeEnabledFeatures.json5
index 0dcb871..69a12661 100644
--- a/third_party/WebKit/Source/platform/RuntimeEnabledFeatures.json5
+++ b/third_party/WebKit/Source/platform/RuntimeEnabledFeatures.json5
@@ -915,6 +915,12 @@
       status: "test",
     },
     {
+      name: "WebVRExperimentalRendering",
+      // Don't mark this as depends_on: ["WebVR"], we want to be able to turn
+      // it on for just origin trial sites where the dependency is unset.
+      status: "experimental",
+    },
+    {
       name: "WebVTTRegions",
       status: "experimental",
     },
diff --git a/third_party/WebKit/Source/platform/fonts/shaping/ShapeResultBuffer.cpp b/third_party/WebKit/Source/platform/fonts/shaping/ShapeResultBuffer.cpp
index 4514c13c..801017f 100644
--- a/third_party/WebKit/Source/platform/fonts/shaping/ShapeResultBuffer.cpp
+++ b/third_party/WebKit/Source/platform/fonts/shaping/ShapeResultBuffer.cpp
@@ -312,7 +312,22 @@
   return advance;
 }
 
+// TODO(eae): This is a bit of a hack to allow reuse of the implementation
+// for both ShapeResultBuffer and single ShapeResult use cases. Ideally the
+// logic should move into ShapeResult itself and then the ShapeResultBuffer
+// implementation may wrap that.
 CharacterRange ShapeResultBuffer::getCharacterRange(
+    RefPtr<const ShapeResult> result,
+    TextDirection direction,
+    float totalWidth,
+    unsigned from,
+    unsigned to) {
+  Vector<RefPtr<const ShapeResult>, 64> results;
+  results.push_back(result);
+  return getCharacterRangeInternal(results, direction, totalWidth, from, to);
+}
+
+CharacterRange ShapeResultBuffer::getCharacterRangeInternal(
     const Vector<RefPtr<const ShapeResult>, 64>& results,
     TextDirection direction,
     float totalWidth,
@@ -404,7 +419,7 @@
                                                     float totalWidth,
                                                     unsigned from,
                                                     unsigned to) const {
-  return getCharacterRange(m_results, direction, totalWidth, from, to);
+  return getCharacterRangeInternal(m_results, direction, totalWidth, from, to);
 }
 
 void ShapeResultBuffer::addRunInfoRanges(const ShapeResult::RunInfo& runInfo,
diff --git a/third_party/WebKit/Source/platform/fonts/shaping/ShapeResultBuffer.h b/third_party/WebKit/Source/platform/fonts/shaping/ShapeResultBuffer.h
index 6dcb22d..6079827 100644
--- a/third_party/WebKit/Source/platform/fonts/shaping/ShapeResultBuffer.h
+++ b/third_party/WebKit/Source/platform/fonts/shaping/ShapeResultBuffer.h
@@ -51,14 +51,20 @@
   Vector<CharacterRange> individualCharacterRanges(TextDirection,
                                                    float totalWidth) const;
 
-  static CharacterRange getCharacterRange(
+  static CharacterRange getCharacterRange(RefPtr<const ShapeResult>,
+                                          TextDirection,
+                                          float totalWidth,
+                                          unsigned from,
+                                          unsigned to);
+
+ private:
+  static CharacterRange getCharacterRangeInternal(
       const Vector<RefPtr<const ShapeResult>, 64>&,
       TextDirection,
       float totalWidth,
       unsigned from,
       unsigned to);
 
- private:
   float fillFastHorizontalGlyphBuffer(GlyphBuffer*, const TextRun&) const;
 
   template <TextDirection>
diff --git a/third_party/WebKit/Source/platform/graphics/GraphicsLayerTest.cpp b/third_party/WebKit/Source/platform/graphics/GraphicsLayerTest.cpp
index 7dd4b73..4b4fc0dd 100644
--- a/third_party/WebKit/Source/platform/graphics/GraphicsLayerTest.cpp
+++ b/third_party/WebKit/Source/platform/graphics/GraphicsLayerTest.cpp
@@ -165,9 +165,6 @@
  public:
   static FakeScrollableArea* create() { return new FakeScrollableArea; }
 
-  LayoutRect visualRectForScrollbarParts() const override {
-    return LayoutRect();
-  }
   bool isActive() const override { return false; }
   int scrollSize(ScrollbarOrientation) const override { return 100; }
   bool isScrollCornerVisible() const override { return false; }
diff --git a/third_party/WebKit/Source/platform/graphics/compositing/PaintArtifactCompositor.cpp b/third_party/WebKit/Source/platform/graphics/compositing/PaintArtifactCompositor.cpp
index e27e644c..a34b992 100644
--- a/third_party/WebKit/Source/platform/graphics/compositing/PaintArtifactCompositor.cpp
+++ b/third_party/WebKit/Source/platform/graphics/compositing/PaintArtifactCompositor.cpp
@@ -727,8 +727,7 @@
     layer->SetTransformTreeIndex(transformId);
     layer->SetClipTreeIndex(clipId);
     layer->SetEffectTreeIndex(effectId);
-    layer->SetScrollTreeIndex(propertyTreeManager.ensureCompositorScrollNode(
-        transform->findEnclosingScrollNode()));
+    propertyTreeManager.updateLayerScrollMapping(layer.get(), transform);
 
     layer->SetShouldCheckBackfaceVisibility(pendingLayer.backfaceHidden);
 
diff --git a/third_party/WebKit/Source/platform/graphics/compositing/PaintArtifactCompositorTest.cpp b/third_party/WebKit/Source/platform/graphics/compositing/PaintArtifactCompositorTest.cpp
index 8ca7790..9f2c4306 100644
--- a/third_party/WebKit/Source/platform/graphics/compositing/PaintArtifactCompositorTest.cpp
+++ b/third_party/WebKit/Source/platform/graphics/compositing/PaintArtifactCompositorTest.cpp
@@ -26,6 +26,7 @@
 #include "platform/testing/RuntimeEnabledFeaturesTestHelpers.h"
 #include "platform/testing/TestPaintArtifact.h"
 #include "platform/testing/WebLayerTreeViewImplForTesting.h"
+#include "public/platform/WebLayerScrollClient.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -666,7 +667,22 @@
   EXPECT_EQ(convertedEffect3.id, contentLayerAt(2)->effect_tree_index());
 }
 
+class FakeScrollClient : public WebLayerScrollClient {
+ public:
+  FakeScrollClient() : didScrollCount(0) {}
+
+  void didScroll(const gfx::ScrollOffset& scrollOffset) final {
+    didScrollCount++;
+    lastScrollOffset = scrollOffset;
+  };
+
+  gfx::ScrollOffset lastScrollOffset;
+  unsigned didScrollCount;
+};
+
 TEST_F(PaintArtifactCompositorTestWithPropertyTrees, OneScrollNode) {
+  FakeScrollClient scrollClient;
+
   CompositorElementId expectedCompositorElementId = CompositorElementId(2, 0);
   RefPtr<TransformPaintPropertyNode> scrollTranslation =
       TransformPaintPropertyNode::createScrollTranslation(
@@ -674,7 +690,7 @@
           TransformationMatrix().translate(7, 9), FloatPoint3D(), false, 0,
           CompositingReasonNone, expectedCompositorElementId,
           ScrollPaintPropertyNode::root(), IntSize(11, 13), IntSize(27, 31),
-          true, false, 0 /* mainThreadScrollingReasons */);
+          true, false, 0 /* mainThreadScrollingReasons */, &scrollClient);
 
   TestPaintArtifact artifact;
   artifact
@@ -705,6 +721,17 @@
 
   EXPECT_EQ(MainThreadScrollingReason::kNotScrollingOnMain,
             scrollNode.main_thread_scrolling_reasons);
+
+  auto* layer = contentLayerAt(0);
+  EXPECT_EQ(layer->id(), scrollNode.owning_layer_id);
+  auto scrollNodeIndexIt =
+      propertyTrees().layer_id_to_scroll_node_index.find(layer->id());
+  EXPECT_EQ(scrollNodeIndexIt->second, scrollNode.id);
+
+  EXPECT_EQ(0u, scrollClient.didScrollCount);
+  layer->SetScrollOffsetFromImplSide(gfx::ScrollOffset(1, 2));
+  EXPECT_EQ(1u, scrollClient.didScrollCount);
+  EXPECT_EQ(gfx::ScrollOffset(1, 2), scrollClient.lastScrollOffset);
 }
 
 TEST_F(PaintArtifactCompositorTestWithPropertyTrees, TransformUnderScrollNode) {
@@ -714,7 +741,7 @@
           TransformationMatrix().translate(7, 9), FloatPoint3D(), false, 0,
           CompositingReasonNone, CompositorElementId(),
           ScrollPaintPropertyNode::root(), IntSize(11, 13), IntSize(27, 31),
-          true, false, 0 /* mainThreadScrollingReasons */);
+          true, false, 0 /* mainThreadScrollingReasons */, nullptr);
 
   RefPtr<TransformPaintPropertyNode> transform =
       TransformPaintPropertyNode::create(
@@ -759,8 +786,8 @@
           TransformationMatrix().translate(11, 13), FloatPoint3D(), false, 0,
           CompositingReasonNone, expectedCompositorElementIdA,
           ScrollPaintPropertyNode::root(), IntSize(2, 3), IntSize(5, 7), false,
-          true,
-          MainThreadScrollingReason::kHasBackgroundAttachmentFixedObjects);
+          true, MainThreadScrollingReason::kHasBackgroundAttachmentFixedObjects,
+          nullptr);
 
   CompositorElementId expectedCompositorElementIdB = CompositorElementId(3, 0);
   RefPtr<TransformPaintPropertyNode> scrollTranslationB =
@@ -769,7 +796,7 @@
           FloatPoint3D(), false, 0, CompositingReasonNone,
           expectedCompositorElementIdB, scrollTranslationA->scrollNode(),
           IntSize(19, 23), IntSize(29, 31), true, false,
-          0 /* mainThreadScrollingReasons */);
+          0 /* mainThreadScrollingReasons */, nullptr);
   TestPaintArtifact artifact;
   artifact.chunk(scrollTranslationA, ClipPaintPropertyNode::root(), effect)
       .rectDrawing(FloatRect(7, 11, 13, 17), Color::white);
diff --git a/third_party/WebKit/Source/platform/graphics/compositing/PropertyTreeManager.cpp b/third_party/WebKit/Source/platform/graphics/compositing/PropertyTreeManager.cpp
index 088dab80..05d7a0d 100644
--- a/third_party/WebKit/Source/platform/graphics/compositing/PropertyTreeManager.cpp
+++ b/third_party/WebKit/Source/platform/graphics/compositing/PropertyTreeManager.cpp
@@ -16,6 +16,7 @@
 #include "platform/graphics/paint/GeometryMapper.h"
 #include "platform/graphics/paint/ScrollPaintPropertyNode.h"
 #include "platform/graphics/paint/TransformPaintPropertyNode.h"
+#include "public/platform/WebLayerScrollClient.h"
 
 namespace blink {
 
@@ -264,12 +265,6 @@
   int id = scrollTree().Insert(cc::ScrollNode(), parentId);
 
   cc::ScrollNode& compositorNode = *scrollTree().Node(id);
-  // TODO(wkorman): Fix owning layer id to reference a layer id rather than a
-  // scroll node index.
-  compositorNode.owning_layer_id = parentId;
-  m_propertyTrees
-      .layer_id_to_scroll_node_index[compositorNode.owning_layer_id] = id;
-
   compositorNode.scrollable = true;
 
   compositorNode.scroll_clip_layer_bounds.SetSize(scrollNode->clip().width(),
@@ -319,7 +314,41 @@
   compositorTransformNode.local.MakeIdentity();
   compositorTransformNode.scrolls = true;
   transformTree().set_needs_update(true);
-  // TODO(pdr): The scroll tree's scroll offset will need to be set here.
+  // TODO(pdr): Because of a layer dependancy, the scroll tree scroll offset is
+  // set in updateLayerScrollMapping but that should occur here.
+}
+
+void PropertyTreeManager::updateLayerScrollMapping(
+    cc::Layer* layer,
+    const TransformPaintPropertyNode* transform) {
+  auto* enclosingScrollNode = transform->findEnclosingScrollNode();
+  int scrollNodeId = ensureCompositorScrollNode(enclosingScrollNode);
+  layer->SetScrollTreeIndex(scrollNodeId);
+  int layerId = layer->id();
+  m_propertyTrees.layer_id_to_scroll_node_index[layerId] = scrollNodeId;
+
+  if (!transform->isScrollTranslation())
+    return;
+
+  auto& compositorScrollNode = *scrollTree().Node(scrollNodeId);
+
+  // TODO(pdr): Remove the scroll node's owning_layer_id. This approach of
+  // setting owning_layer_id only when it is not set lets us maintain a 1:1
+  // mapping from layer to scroll node.
+  if (compositorScrollNode.owning_layer_id == cc::Layer::INVALID_ID) {
+    compositorScrollNode.owning_layer_id = layerId;
+    auto& compositorTransformNode =
+        *transformTree().Node(compositorScrollNode.transform_id);
+    // TODO(pdr): Set this in updateScrollAndScrollTranslationNodes once the
+    // layer id is no longer needed.
+    scrollTree().SetScrollOffset(layerId,
+                                 compositorTransformNode.scroll_offset);
+    if (auto* scrollClient = enclosingScrollNode->scrollClient()) {
+      layer->set_did_scroll_callback(
+          base::Bind(&blink::WebLayerScrollClient::didScroll,
+                     base::Unretained(scrollClient)));
+    }
+  }
 }
 
 int PropertyTreeManager::switchToEffectNode(
diff --git a/third_party/WebKit/Source/platform/graphics/compositing/PropertyTreeManager.h b/third_party/WebKit/Source/platform/graphics/compositing/PropertyTreeManager.h
index 6704ded..f440bea 100644
--- a/third_party/WebKit/Source/platform/graphics/compositing/PropertyTreeManager.h
+++ b/third_party/WebKit/Source/platform/graphics/compositing/PropertyTreeManager.h
@@ -75,7 +75,9 @@
 
   int ensureCompositorTransformNode(const TransformPaintPropertyNode*);
   int ensureCompositorClipNode(const ClipPaintPropertyNode*);
-  int ensureCompositorScrollNode(const ScrollPaintPropertyNode*);
+  // Update the layer->scroll and scroll->layer mapping. The latter is temporary
+  // until |owning_layer_id| is removed from the scroll node.
+  void updateLayerScrollMapping(cc::Layer*, const TransformPaintPropertyNode*);
 
   int switchToEffectNode(const EffectPaintPropertyNode& nextEffect);
   int getCurrentCompositorEffectNodeIndex() const {
@@ -90,6 +92,8 @@
   cc::EffectTree& effectTree();
   cc::ScrollTree& scrollTree();
 
+  int ensureCompositorScrollNode(const ScrollPaintPropertyNode*);
+
   const EffectPaintPropertyNode* currentEffectNode() const;
 
   // Scroll translation has special treatment in the transform and scroll trees.
diff --git a/third_party/WebKit/Source/platform/graphics/paint/ScrollPaintPropertyNode.cpp b/third_party/WebKit/Source/platform/graphics/paint/ScrollPaintPropertyNode.cpp
index fe601869..a26f22a1 100644
--- a/third_party/WebKit/Source/platform/graphics/paint/ScrollPaintPropertyNode.cpp
+++ b/third_party/WebKit/Source/platform/graphics/paint/ScrollPaintPropertyNode.cpp
@@ -9,9 +9,10 @@
 namespace blink {
 
 ScrollPaintPropertyNode* ScrollPaintPropertyNode::root() {
-  DEFINE_STATIC_REF(ScrollPaintPropertyNode, root,
-                    (ScrollPaintPropertyNode::create(
-                        nullptr, IntSize(), IntSize(), false, false, 0)));
+  DEFINE_STATIC_REF(
+      ScrollPaintPropertyNode, root,
+      (ScrollPaintPropertyNode::create(nullptr, IntSize(), IntSize(), false,
+                                       false, 0, nullptr)));
   return root;
 }
 
@@ -40,6 +41,8 @@
   } else {
     text.append("none");
   }
+  if (m_scrollClient)
+    text.append(String::format(" scrollClient=%p", m_scrollClient));
   return text.toString();
 }
 
diff --git a/third_party/WebKit/Source/platform/graphics/paint/ScrollPaintPropertyNode.h b/third_party/WebKit/Source/platform/graphics/paint/ScrollPaintPropertyNode.h
index ea1bc43..60ec0322 100644
--- a/third_party/WebKit/Source/platform/graphics/paint/ScrollPaintPropertyNode.h
+++ b/third_party/WebKit/Source/platform/graphics/paint/ScrollPaintPropertyNode.h
@@ -18,6 +18,7 @@
 namespace blink {
 
 using MainThreadScrollingReasons = uint32_t;
+class WebLayerScrollClient;
 
 // A scroll node contains auxiliary scrolling information which includes how far
 // an area can be scrolled, main thread scrolling reasons, etc. Scroll nodes
@@ -43,10 +44,11 @@
       const IntSize& bounds,
       bool userScrollableHorizontal,
       bool userScrollableVertical,
-      MainThreadScrollingReasons mainThreadScrollingReasons) {
+      MainThreadScrollingReasons mainThreadScrollingReasons,
+      WebLayerScrollClient* scrollClient) {
     return adoptRef(new ScrollPaintPropertyNode(
         std::move(parent), clip, bounds, userScrollableHorizontal,
-        userScrollableVertical, mainThreadScrollingReasons));
+        userScrollableVertical, mainThreadScrollingReasons, scrollClient));
   }
 
   void update(PassRefPtr<const ScrollPaintPropertyNode> parent,
@@ -54,7 +56,8 @@
               const IntSize& bounds,
               bool userScrollableHorizontal,
               bool userScrollableVertical,
-              MainThreadScrollingReasons mainThreadScrollingReasons) {
+              MainThreadScrollingReasons mainThreadScrollingReasons,
+              WebLayerScrollClient* scrollClient) {
     DCHECK(!isRoot());
     DCHECK(parent != this);
     m_parent = parent;
@@ -63,6 +66,7 @@
     m_userScrollableHorizontal = userScrollableHorizontal;
     m_userScrollableVertical = userScrollableVertical;
     m_mainThreadScrollingReasons = mainThreadScrollingReasons;
+    m_scrollClient = scrollClient;
   }
 
   const ScrollPaintPropertyNode* parent() const { return m_parent.get(); }
@@ -94,6 +98,8 @@
            MainThreadScrollingReason::kHasBackgroundAttachmentFixedObjects;
   }
 
+  WebLayerScrollClient* scrollClient() const { return m_scrollClient; }
+
 #if DCHECK_IS_ON()
   // The clone function is used by FindPropertiesNeedingUpdate.h for recording
   // a scroll node before it has been updated, to later detect changes.
@@ -101,7 +107,8 @@
     RefPtr<ScrollPaintPropertyNode> cloned =
         adoptRef(new ScrollPaintPropertyNode(
             m_parent, m_clip, m_bounds, m_userScrollableHorizontal,
-            m_userScrollableVertical, m_mainThreadScrollingReasons));
+            m_userScrollableVertical, m_mainThreadScrollingReasons,
+            m_scrollClient));
     return cloned;
   }
 
@@ -112,7 +119,8 @@
            m_bounds == o.m_bounds &&
            m_userScrollableHorizontal == o.m_userScrollableHorizontal &&
            m_userScrollableVertical == o.m_userScrollableVertical &&
-           m_mainThreadScrollingReasons == o.m_mainThreadScrollingReasons;
+           m_mainThreadScrollingReasons == o.m_mainThreadScrollingReasons &&
+           m_scrollClient == o.m_scrollClient;
   }
 
   String toTreeString() const;
@@ -126,13 +134,15 @@
                           IntSize bounds,
                           bool userScrollableHorizontal,
                           bool userScrollableVertical,
-                          MainThreadScrollingReasons mainThreadScrollingReasons)
+                          MainThreadScrollingReasons mainThreadScrollingReasons,
+                          WebLayerScrollClient* scrollClient)
       : m_parent(parent),
         m_clip(clip),
         m_bounds(bounds),
         m_userScrollableHorizontal(userScrollableHorizontal),
         m_userScrollableVertical(userScrollableVertical),
-        m_mainThreadScrollingReasons(mainThreadScrollingReasons) {}
+        m_mainThreadScrollingReasons(mainThreadScrollingReasons),
+        m_scrollClient(scrollClient) {}
 
   RefPtr<const ScrollPaintPropertyNode> m_parent;
   IntSize m_clip;
@@ -140,6 +150,7 @@
   bool m_userScrollableHorizontal : 1;
   bool m_userScrollableVertical : 1;
   MainThreadScrollingReasons m_mainThreadScrollingReasons;
+  WebLayerScrollClient* m_scrollClient;
 };
 
 // Redeclared here to avoid ODR issues.
diff --git a/third_party/WebKit/Source/platform/graphics/paint/TransformPaintPropertyNode.h b/third_party/WebKit/Source/platform/graphics/paint/TransformPaintPropertyNode.h
index 186fe59..76844fb 100644
--- a/third_party/WebKit/Source/platform/graphics/paint/TransformPaintPropertyNode.h
+++ b/third_party/WebKit/Source/platform/graphics/paint/TransformPaintPropertyNode.h
@@ -61,7 +61,8 @@
       const IntSize& bounds,
       bool userScrollableHorizontal,
       bool userScrollableVertical,
-      MainThreadScrollingReasons mainThreadScrollingReasons) {
+      MainThreadScrollingReasons mainThreadScrollingReasons,
+      WebLayerScrollClient* scrollClient) {
     // If this transform is for scroll offset, it should be a 2d translation.
     DCHECK(matrix.isIdentityOr2DTranslation());
     return adoptRef(new TransformPaintPropertyNode(
@@ -69,7 +70,7 @@
         renderingContextId, directCompositingReasons, compositorElementId,
         ScrollPaintPropertyNode::create(
             std::move(parentScroll), clip, bounds, userScrollableHorizontal,
-            userScrollableVertical, mainThreadScrollingReasons)));
+            userScrollableVertical, mainThreadScrollingReasons, scrollClient)));
   }
 
   void update(
@@ -104,14 +105,15 @@
       const IntSize& bounds,
       bool userScrollableHorizontal,
       bool userScrollableVertical,
-      MainThreadScrollingReasons mainThreadScrollingReasons) {
+      MainThreadScrollingReasons mainThreadScrollingReasons,
+      WebLayerScrollClient* scrollClient) {
     update(std::move(parent), matrix, origin, flattensInheritedTransform,
            renderingContextId, directCompositingReasons, compositorElementId);
     DCHECK(m_scroll);
     DCHECK(matrix.isIdentityOr2DTranslation());
     m_scroll->update(std::move(parentScroll), clip, bounds,
                      userScrollableHorizontal, userScrollableVertical,
-                     mainThreadScrollingReasons);
+                     mainThreadScrollingReasons, scrollClient);
   }
 
   const TransformationMatrix& matrix() const { return m_matrix; }
diff --git a/third_party/WebKit/Source/platform/scroll/ScrollableArea.h b/third_party/WebKit/Source/platform/scroll/ScrollableArea.h
index d84ded4..266e804 100644
--- a/third_party/WebKit/Source/platform/scroll/ScrollableArea.h
+++ b/third_party/WebKit/Source/platform/scroll/ScrollableArea.h
@@ -104,10 +104,6 @@
                                     const ScrollAlignment& alignY,
                                     ScrollType = ProgrammaticScroll);
 
-  // Returns a rect, in the space of the area's backing graphics layer, that
-  // contains the visual region of all scrollbar parts.
-  virtual LayoutRect visualRectForScrollbarParts() const = 0;
-
   static bool scrollBehaviorFromString(const String&, ScrollBehavior&);
 
   void contentAreaWillPaint() const;
diff --git a/third_party/WebKit/Source/platform/scroll/Scrollbar.cpp b/third_party/WebKit/Source/platform/scroll/Scrollbar.cpp
index cd3b8ac..e4bf898e7 100644
--- a/third_party/WebKit/Source/platform/scroll/Scrollbar.cpp
+++ b/third_party/WebKit/Source/platform/scroll/Scrollbar.cpp
@@ -629,11 +629,6 @@
          m_scrollableArea->minimumScrollOffset().height();
 }
 
-LayoutRect Scrollbar::visualRect() const {
-  return m_scrollableArea ? m_scrollableArea->visualRectForScrollbarParts()
-                          : LayoutRect();
-}
-
 void Scrollbar::setNeedsPaintInvalidation(ScrollbarPart invalidParts) {
   if (m_theme.shouldRepaintAllPartsOnInvalidation())
     invalidParts = AllParts;
diff --git a/third_party/WebKit/Source/platform/scroll/Scrollbar.h b/third_party/WebKit/Source/platform/scroll/Scrollbar.h
index 914c9aa..6549ff2 100644
--- a/third_party/WebKit/Source/platform/scroll/Scrollbar.h
+++ b/third_party/WebKit/Source/platform/scroll/Scrollbar.h
@@ -181,7 +181,9 @@
     return m_orientation == HorizontalScrollbar ? "HorizontalScrollbar"
                                                 : "VerticalScrollbar";
   }
-  LayoutRect visualRect() const override;
+  LayoutRect visualRect() const final { return m_visualRect; }
+
+  virtual void setVisualRect(const LayoutRect& r) { m_visualRect = r; }
 
   // Marks the scrollbar as needing to be redrawn.
   //
@@ -255,6 +257,7 @@
   int m_themeScrollbarThickness;
   bool m_trackNeedsRepaint;
   bool m_thumbNeedsRepaint;
+  LayoutRect m_visualRect;
 };
 
 DEFINE_TYPE_CASTS(Scrollbar,
diff --git a/third_party/WebKit/Source/web/WebRuntimeFeatures.cpp b/third_party/WebKit/Source/web/WebRuntimeFeatures.cpp
index e110dce6..12986c06 100644
--- a/third_party/WebKit/Source/web/WebRuntimeFeatures.cpp
+++ b/third_party/WebKit/Source/web/WebRuntimeFeatures.cpp
@@ -314,6 +314,10 @@
   RuntimeEnabledFeatures::setWebVREnabled(enable);
 }
 
+void WebRuntimeFeatures::enableWebVRExperimentalRendering(bool enable) {
+  RuntimeEnabledFeatures::setWebVRExperimentalRenderingEnabled(enable);
+}
+
 void WebRuntimeFeatures::enablePresentationAPI(bool enable) {
   RuntimeEnabledFeatures::setPresentationEnabled(enable);
 }
diff --git a/third_party/WebKit/public/platform/Platform.h b/third_party/WebKit/public/platform/Platform.h
index d7d3e5c..2cd7334 100644
--- a/third_party/WebKit/public/platform/Platform.h
+++ b/third_party/WebKit/public/platform/Platform.h
@@ -460,6 +460,13 @@
   struct ContextAttributes {
     bool failIfMajorPerformanceCaveat = false;
     unsigned webGLVersion = 0;
+    // Offscreen contexts usually share a surface for the default frame buffer
+    // since they aren't rendering to it. Setting any of the following
+    // attributes causes creation of a custom surface owned by the context.
+    bool supportAlpha = false;
+    bool supportDepth = false;
+    bool supportAntialias = false;
+    bool supportStencil = false;
   };
   struct GraphicsInfo {
     unsigned vendorId = 0;
diff --git a/third_party/WebKit/public/web/WebRuntimeFeatures.h b/third_party/WebKit/public/web/WebRuntimeFeatures.h
index 1ef45cb..1428a480 100644
--- a/third_party/WebKit/public/web/WebRuntimeFeatures.h
+++ b/third_party/WebKit/public/web/WebRuntimeFeatures.h
@@ -133,6 +133,7 @@
   BLINK_EXPORT static void enableWebGLImageChromium(bool);
   BLINK_EXPORT static void enableWebUsb(bool);
   BLINK_EXPORT static void enableWebVR(bool);
+  BLINK_EXPORT static void enableWebVRExperimentalRendering(bool);
   BLINK_EXPORT static void enableXSLT(bool);
   BLINK_EXPORT static void forceOverlayFullscreenVideo(bool);
   BLINK_EXPORT static void enableAutoplayMutedVideos(bool);
diff --git a/third_party/re2/OWNERS b/third_party/re2/OWNERS
index d706bc6..bcd86b7d1 100644
--- a/third_party/re2/OWNERS
+++ b/third_party/re2/OWNERS
@@ -1,2 +1,3 @@
+mmoroz@chromium.org
 tfarina@chromium.org
 thakis@chromium.org
diff --git a/third_party/re2/README.chromium b/third_party/re2/README.chromium
index 1d7b9c33..a941175a 100644
--- a/third_party/re2/README.chromium
+++ b/third_party/re2/README.chromium
@@ -1,8 +1,8 @@
 Name: re2 - an efficient, principled regular expression library
 Short Name: re2
 URL: https://github.com/google/re2
-Version: aa627d9e7bb93778967e34cc015452ae453a4e78
-Date: 2017-02-13
+Version: 193486d7164a40ce28d8ec64552df129c0558bad
+Date: 2017-02-17
 License: BSD 3-Clause
 License File: LICENSE
 Security Critical: yes
diff --git a/tools/grit/grit/format/rc_header.py b/tools/grit/grit/format/rc_header.py
index 74e7127..7b02122 100755
--- a/tools/grit/grit/format/rc_header.py
+++ b/tools/grit/grit/format/rc_header.py
@@ -79,21 +79,44 @@
 _cached_ids = {}
 
 
+_predetermined_tids = {}
+
+
+def SetPredeterminedIdsFile(predetermined_ids_file):
+  global _predetermined_tids
+  if predetermined_ids_file:
+    _predetermined_tids = _ReadIdsFromFile(predetermined_ids_file)
+  else:
+    _predetermined_tids = {}
+
+
+def _ReadIdsFromFile(path):
+  with open(path, "r") as f:
+    content = f.readlines()
+  tids = {}  # Maps textual id to numeric id
+  for line in content:
+    tid, id = line.split()
+    tids[tid] = int(id)
+  return tids
+
+
 def GetIds(root):
   '''Return a dictionary mapping textual ids to numeric ids for the given tree.
 
   Args:
     root: A GritNode.
   '''
+  global _cached_ids
+  global _predetermined_tids
   # TODO(benrg): Since other formatters use this, it might make sense to move it
   # and _ComputeIds to GritNode and store the cached ids as an attribute. On the
   # other hand, GritNode has too much random stuff already.
   if root not in _cached_ids:
-    _cached_ids[root] = _ComputeIds(root)
+    _cached_ids[root] = _ComputeIds(root, _predetermined_tids)
   return _cached_ids[root]
 
 
-def _ComputeIds(root):
+def _ComputeIds(root, predetermined_tids):
   from grit.node import empty, include, message, misc, structure
 
   ids = {}  # Maps numeric id to textual id
@@ -101,6 +124,8 @@
   id_reasons = {}  # Maps numeric id to text id and a human-readable explanation
   group = None
   last_id = None
+  predetermined_ids = {value: key
+                       for key, value in predetermined_tids.iteritems()}
 
   for item in root:
     if isinstance(item, empty.GroupingNode):
@@ -129,9 +154,13 @@
       if tid in tids:
         continue
 
+      if predetermined_tids and tid in predetermined_tids:
+        id = predetermined_tids[tid]
+        reason = "from predetermined_tids map"
+
       # Some identifier nodes can provide their own id,
       # and we use that id in the generated header in that case.
-      if hasattr(item, 'GetId') and item.GetId():
+      elif hasattr(item, 'GetId') and item.GetId():
         id = long(item.GetId())
         reason = 'returned by GetId() method'
 
@@ -197,6 +226,10 @@
         print ('WARNING: Numeric resource IDs should be greater than 100 to\n'
                'avoid conflicts with system-defined resource IDs.')
 
+      if tid not in predetermined_tids and id in predetermined_ids:
+        raise exception.IdRangeOverlap('ID %d overlaps between %s and %s'
+                                       % (id, tid, predetermined_ids[tid]))
+
       ids[id] = tid
       tids[tid] = id
       id_reasons[id] = reason
diff --git a/tools/grit/grit/format/rc_header_unittest.py b/tools/grit/grit/format/rc_header_unittest.py
index 5d780e3..22c5f38 100755
--- a/tools/grit/grit/format/rc_header_unittest.py
+++ b/tools/grit/grit/format/rc_header_unittest.py
@@ -10,6 +10,7 @@
 
 import os
 import sys
+import tempfile
 if __name__ == '__main__':
   sys.path.append(os.path.join(os.path.dirname(__file__), '../..'))
 
@@ -27,6 +28,13 @@
     output = rc_header.FormatDefines(grd, grd.ShouldOutputAllResourceDefines())
     return ''.join(output).replace(' ', '')
 
+  def _MakeTempPredeterminedIdsFile(self, content):
+    tmp_dir = tempfile.gettempdir()
+    predetermined_ids_file = tmp_dir + "/predetermined_ids.txt"
+    with open(predetermined_ids_file, 'w') as f:
+      f.write(content)
+    return predetermined_ids_file
+
   def testFormatter(self):
     grd = grd_reader.Parse(StringIO.StringIO('''<?xml version="1.0" encoding="UTF-8"?>
       <grit latest_public_release="2" source_lang_id="en" current_release="3" base_dir=".">
@@ -189,5 +197,53 @@
                       '#define IDS_BONGO _Pragma("IDS_BONGO") 10001\n'),
                      ''.join(output))
 
+  def testPredeterminedIds(self):
+    predetermined_ids_file = self._MakeTempPredeterminedIdsFile(
+        'IDS_BONGO 101\nID_LOGO 102\n')
+    grd = grd_reader.Parse(StringIO.StringIO('''<?xml version="1.0" encoding="UTF-8"?>
+      <grit latest_public_release="2" source_lang_id="en" current_release="3" base_dir=".">
+        <release seq="3">
+          <includes first_id="300" comment="bingo">
+            <include type="gif" name="ID_LOGO" file="images/logo.gif" />
+          </includes>
+          <messages first_id="10000">
+            <message name="IDS_GREETING" desc="Printed to greet the currently logged in user">
+              Hello <ph name="USERNAME">%s<ex>Joi</ex></ph>, how are you doing today?
+            </message>
+            <message name="IDS_BONGO">
+              Bongo!
+            </message>
+          </messages>
+        </release>
+      </grit>'''), '.', predetermined_ids_file=predetermined_ids_file)
+    output = rc_header.FormatDefines(grd, grd.ShouldOutputAllResourceDefines(),
+                                     grd.GetRcHeaderFormat())
+    self.assertEqual(('#define ID_LOGO 102\n'
+                      '#define IDS_GREETING 10000\n'
+                      '#define IDS_BONGO 101\n'), ''.join(output))
+
+  def testPredeterminedIdsOverlap(self):
+    predetermined_ids_file = self._MakeTempPredeterminedIdsFile(
+        'ID_LOGO 10000\n')
+    grd = grd_reader.Parse(StringIO.StringIO('''<?xml version="1.0" encoding="UTF-8"?>
+      <grit latest_public_release="2" source_lang_id="en" current_release="3" base_dir=".">
+        <release seq="3">
+          <includes first_id="300" comment="bingo">
+            <include type="gif" name="ID_LOGO" file="images/logo.gif" />
+          </includes>
+          <messages first_id="10000">
+            <message name="IDS_GREETING" desc="Printed to greet the currently logged in user">
+              Hello <ph name="USERNAME">%s<ex>Joi</ex></ph>, how are you doing today?
+            </message>
+            <message name="IDS_BONGO">
+              Bongo!
+            </message>
+          </messages>
+        </release>
+      </grit>'''), '.', predetermined_ids_file=predetermined_ids_file)
+    output = rc_header.FormatDefines(grd, grd.ShouldOutputAllResourceDefines(),
+                                     grd.GetRcHeaderFormat())
+    self.assertRaises(exception.IdRangeOverlap, self.FormatAll, grd)
+
 if __name__ == '__main__':
   unittest.main()
diff --git a/tools/grit/grit/grd_reader.py b/tools/grit/grit/grd_reader.py
index 87eec5e..ba8ad49 100755
--- a/tools/grit/grit/grd_reader.py
+++ b/tools/grit/grit/grd_reader.py
@@ -13,6 +13,7 @@
 
 from grit import exception
 from grit import util
+from grit.format import rc_header
 from grit.node import base
 from grit.node import mapping
 from grit.node import misc
@@ -139,7 +140,8 @@
 
 
 def Parse(filename_or_stream, dir=None, stop_after=None, first_ids_file=None,
-          debug=False, defines=None, tags_to_ignore=None, target_platform=None):
+          debug=False, defines=None, tags_to_ignore=None, target_platform=None,
+          predetermined_ids_file=None):
   '''Parses a GRD file into a tree of nodes (from grit.node).
 
   If filename_or_stream is a stream, 'dir' should point to the directory
@@ -168,6 +170,9 @@
     defines: dictionary of defines, like {'chromeos': '1'}
     target_platform: None or the value that would be returned by sys.platform
         on your target platform.
+    predetermined_ids_file: File path to a file containing a pre-determined
+        mapping from resource names to resource ids which will be used to assign
+        resource ids to those resources.
 
   Return:
     Subclass of grit.node.base.Node
@@ -179,6 +184,7 @@
   if dir is None and isinstance(filename_or_stream, types.StringType):
     dir = util.dirname(filename_or_stream)
 
+  rc_header.SetPredeterminedIdsFile(predetermined_ids_file)
   handler = GrdContentHandler(stop_after=stop_after, debug=debug, dir=dir,
                               defines=defines, tags_to_ignore=tags_to_ignore,
                               target_platform=target_platform)
diff --git a/tools/grit/grit/tool/build.py b/tools/grit/grit/tool/build.py
index a5703b20..cab2b37 100755
--- a/tools/grit/grit/tool/build.py
+++ b/tools/grit/grit/tool/build.py
@@ -85,6 +85,17 @@
   -o OUTPUTDIR      Specify what directory output paths are relative to.
                     Defaults to the current directory.
 
+  -p FILE           Specify a file containing a pre-determined mapping from
+                    resource names to resource ids which will be used to assign
+                    resource ids to those resources. Resources not found in this
+                    file will be assigned ids normally. The motivation is to run
+                    your app's startup and have it dump the resources it loads,
+                    and then pass these via this flag. This will pack startup
+                    resources together, thus reducing paging while all other
+                    resources are unperturbed. The file should have the format:
+                      RESOURCE_ONE_NAME 123
+                      RESOURCE_TWO_NAME 124
+
   -D NAME[=VAL]     Specify a C-preprocessor-like define NAME with optional
                     value VAL (defaults to 1) which will be used to control
                     conditional inclusion of resources.
@@ -146,6 +157,7 @@
   def Run(self, opts, args):
     self.output_directory = '.'
     first_ids_file = None
+    predetermined_ids_file = None
     whitelist_filenames = []
     assert_output_files = []
     target_platform = None
@@ -157,7 +169,7 @@
     depend_on_stamp = False
     js_minifier = None
     replace_ellipsis = True
-    (own_opts, args) = getopt.getopt(args, 'a:o:D:E:f:w:t:h:',
+    (own_opts, args) = getopt.getopt(args, 'a:p:o:D:E:f:w:t:h:',
         ('depdir=','depfile=','assert-file-list=',
          'output-all-resource-defines',
          'no-output-all-resource-defines',
@@ -192,6 +204,8 @@
         output_all_resource_defines = False
       elif key == '--no-replace-ellipsis':
         replace_ellipsis = False
+      elif key == '-p':
+        predetermined_ids_file = val
       elif key == '-t':
         target_platform = val
       elif key == '-h':
@@ -233,6 +247,7 @@
     self.res = grd_reader.Parse(opts.input,
                                 debug=opts.extra_verbose,
                                 first_ids_file=first_ids_file,
+                                predetermined_ids_file=predetermined_ids_file,
                                 defines=self.defines,
                                 target_platform=target_platform)
 
diff --git a/tools/grit/grit_rule.gni b/tools/grit/grit_rule.gni
index 00dd9258..eab1956 100644
--- a/tools/grit/grit_rule.gni
+++ b/tools/grit/grit_rule.gni
@@ -249,6 +249,11 @@
 grit_resource_id_file = "//tools/gritsettings/resource_ids"
 grit_info_script = "//tools/grit/grit_info.py"
 
+grit_predetermined_resource_ids_file = ""
+
+# TODO(asvitkine): Add platform-specific resource id file paths here.
+#                  http://crbug.com/692670
+
 template("grit") {
   assert(defined(invoker.source),
          "\"source\" must be defined for the grit template $target_name")
@@ -301,6 +306,12 @@
       rebase_path(resource_ids, root_build_dir),
     ]
   }
+  if (grit_predetermined_resource_ids_file != "") {
+    grit_flags += [
+      "-p",
+      rebase_path(grit_predetermined_resource_ids_file, root_build_dir),
+    ]
+  }
 
   if (defined(invoker.source_is_generated)) {
     source_is_generated = invoker.source_is_generated
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index ac5d116..1965037 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -84993,6 +84993,7 @@
   <int value="18" label="Timeline started (page reload)"/>
   <int value="19" label="Connect to node.js from frontend"/>
   <int value="20" label="Connect to node.js directly (paste link from CLI)"/>
+  <int value="21" label="CPU throttling enabled"/>
 </enum>
 
 <enum name="DevToolsPanel" type="int">
@@ -97329,6 +97330,7 @@
   <int value="-290672626" label="enable-asm-wasm"/>
   <int value="-288316828" label="enable-delegated-renderer"/>
   <int value="-279920685" label="affiliation-based-matching:enabled"/>
+  <int value="-279493876" label="WebVRExperimentalRendering:enabled"/>
   <int value="-278347667" label="default-tile-height"/>
   <int value="-277144896" label="enable-viewport-meta"/>
   <int value="-268357961" label="enable-feature-policy"/>
@@ -97424,6 +97426,7 @@
   <int value="189728101" label="FasterLocationReload:disabled"/>
   <int value="194573877" label="MacViewsNativeDialogs:disabled"/>
   <int value="194895489" label="passive-listeners-default"/>
+  <int value="200347243" label="WebVRExperimentalRendering:disabled"/>
   <int value="201343576" label="enable-password-change-support:enabled"/>
   <int value="203776499" label="enable-virtual-keyboard-overscroll"/>
   <int value="223662457" label="BackgroundLoadingForDownloads:enabled"/>
diff --git a/ui/gl/gl_surface_egl.cc b/ui/gl/gl_surface_egl.cc
index 444ae10..9196ca0 100644
--- a/ui/gl/gl_surface_egl.cc
+++ b/ui/gl/gl_surface_egl.cc
@@ -274,6 +274,7 @@
 EGLConfig ChooseConfig(GLSurfaceFormat format) {
   // Choose an EGL configuration.
   // On X this is only used for PBuffer surfaces.
+
   std::vector<EGLint> renderable_types;
   if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
           switches::kDisableES3GLContext)) {
@@ -284,6 +285,9 @@
   EGLint buffer_size = format.GetBufferSize();
   EGLint alpha_size = 8;
   bool want_rgb565 = buffer_size == 16;
+  EGLint depth_size = format.GetDepthBits();
+  EGLint stencil_size = format.GetStencilBits();
+  EGLint samples = format.GetSamples();
 
 #if defined(USE_X11) && !defined(OS_CHROMEOS)
   // If we're using ANGLE_NULL, we may not have a display, in which case we
@@ -310,6 +314,12 @@
                                     8,
                                     EGL_RED_SIZE,
                                     8,
+                                    EGL_SAMPLES,
+                                    samples,
+                                    EGL_DEPTH_SIZE,
+                                    depth_size,
+                                    EGL_STENCIL_SIZE,
+                                    stencil_size,
                                     EGL_RENDERABLE_TYPE,
                                     renderable_type,
                                     EGL_SURFACE_TYPE,
@@ -324,6 +334,12 @@
                                    6,
                                    EGL_RED_SIZE,
                                    5,
+                                   EGL_SAMPLES,
+                                   samples,
+                                   EGL_DEPTH_SIZE,
+                                   depth_size,
+                                   EGL_STENCIL_SIZE,
+                                   stencil_size,
                                    EGL_RENDERABLE_TYPE,
                                    renderable_type,
                                    EGL_SURFACE_TYPE,
diff --git a/ui/views/widget/desktop_aura/desktop_native_widget_aura.cc b/ui/views/widget/desktop_aura/desktop_native_widget_aura.cc
index e816e40..2e903f9 100644
--- a/ui/views/widget/desktop_aura/desktop_native_widget_aura.cc
+++ b/ui/views/widget/desktop_aura/desktop_native_widget_aura.cc
@@ -389,6 +389,10 @@
   }
 }
 
+gfx::NativeWindow DesktopNativeWidgetAura::GetNativeWindow() const {
+  return content_window_;
+}
+
 ////////////////////////////////////////////////////////////////////////////////
 // DesktopNativeWidgetAura, internal::NativeWidgetPrivate implementation:
 
@@ -563,10 +567,6 @@
   return content_window_;
 }
 
-gfx::NativeWindow DesktopNativeWidgetAura::GetNativeWindow() const {
-  return content_window_;
-}
-
 Widget* DesktopNativeWidgetAura::GetTopLevelWidget() {
   return GetWidget();
 }
diff --git a/ui/views/widget/desktop_aura/desktop_native_widget_aura.h b/ui/views/widget/desktop_aura/desktop_native_widget_aura.h
index c28cea4435..194df82e 100644
--- a/ui/views/widget/desktop_aura/desktop_native_widget_aura.h
+++ b/ui/views/widget/desktop_aura/desktop_native_widget_aura.h
@@ -97,6 +97,9 @@
   // we are being activated/deactivated.
   void HandleActivationChanged(bool active);
 
+  // Overridden from internal::NativeWidgetPrivate:
+  gfx::NativeWindow GetNativeWindow() const override;
+
  protected:
   // Overridden from internal::NativeWidgetPrivate:
   void InitNativeWidget(const Widget::InitParams& params) override;
@@ -108,7 +111,6 @@
   Widget* GetWidget() override;
   const Widget* GetWidget() const override;
   gfx::NativeView GetNativeView() const override;
-  gfx::NativeWindow GetNativeWindow() const override;
   Widget* GetTopLevelWidget() override;
   const ui::Compositor* GetCompositor() const override;
   const ui::Layer* GetLayer() const override;