diff --git a/.gitignore b/.gitignore
index 1b00c64..7839be8c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -362,7 +362,6 @@
 /third_party/gvr-android-sdk/libgvr_shim_static_arm64.a
 /third_party/gvr-android-sdk/src
 /third_party/gperf
-/third_party/grpc
 /third_party/guava/lib/*.jar
 /third_party/hamcrest/lib/*.jar
 /third_party/httpcomponents-client
diff --git a/DEPS b/DEPS
index 886ccbc..2dbff98 100644
--- a/DEPS
+++ b/DEPS
@@ -64,7 +64,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling PDFium
   # and whatever else without interference from each other.
-  'pdfium_revision': 'e6cf01356e3336dc4f0717a391d9067693a418c1',
+  'pdfium_revision': '95bec8046a28928df627ce4d48eee8b209b3e36e',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling openmax_dl
   # and whatever else without interference from each other.
@@ -449,10 +449,6 @@
     'src/third_party/wds/src':
       Var('chromium_git') + '/external/github.com/01org/wds' + '@' + 'ac3d8210d95f3000bf5c8e16a79dbbbf22d554a5',
 
-    # gRPC, an RPC framework. For Blimp use only.
-    'src/third_party/grpc':
-      Var('chromium_git') + '/external/github.com/grpc/grpc' + '@' + '5945dfa700a0566be7ea6691cc8a86ecb4a53924',
-
     # DevTools node modules. Used on Linux buildbots only.
     'src/third_party/WebKit/Source/devtools/devtools-node-modules':
       Var('chromium_git') + '/external/github.com/ChromeDevTools/devtools-node-modules' + '@' + Var('devtools_node_modules_revision')
@@ -1038,18 +1034,6 @@
     ],
   },
   {
-    'name': 'blimp_fonts',
-    'pattern': '.',
-    'action': [ 'download_from_google_storage',
-                '--no_resume',
-                '--platform=linux*',
-                '--extract',
-                '--no_auth',
-                '--bucket', 'chromium-fonts',
-                '-s', 'src/third_party/blimp_fonts/font_bundle.tar.gz.sha1',
-    ],
-  },
-  {
     # Pull sanitizer-instrumented third-party libraries if requested via
     # GYP_DEFINES.
     'name': 'instrumented_libraries',
diff --git a/ash/common/shelf/wm_shelf.cc b/ash/common/shelf/wm_shelf.cc
index 6f07f30e..75bf105 100644
--- a/ash/common/shelf/wm_shelf.cc
+++ b/ash/common/shelf/wm_shelf.cc
@@ -127,7 +127,7 @@
   shelf_widget_.reset();
 }
 
-void WmShelf::InitializeShelf() {
+void WmShelf::CreateShelfView() {
   DCHECK(shelf_layout_manager_);
   DCHECK(shelf_widget_);
   DCHECK(!shelf_view_);
diff --git a/ash/common/shelf/wm_shelf.h b/ash/common/shelf/wm_shelf.h
index 819be307..64b00620a 100644
--- a/ash/common/shelf/wm_shelf.h
+++ b/ash/common/shelf/wm_shelf.h
@@ -59,7 +59,9 @@
   ShelfWidget* shelf_widget() { return shelf_widget_.get(); }
 
   // Creates the shelf view.
-  void InitializeShelf();
+  void CreateShelfView();
+
+  // TODO(jamescook): Eliminate this method.
   void ShutdownShelf();
 
   // True after the ShelfView has been created (e.g. after login).
diff --git a/ash/common/test/test_session_state_delegate.cc b/ash/common/test/test_session_state_delegate.cc
index 9132b8ce..928e6b3 100644
--- a/ash/common/test/test_session_state_delegate.cc
+++ b/ash/common/test/test_session_state_delegate.cc
@@ -171,7 +171,7 @@
   if (active_user_session_started) {
     user_manager_->SessionStarted();
     session_state_ = session_manager::SessionState::ACTIVE;
-    WmShell::Get()->CreateShelf();
+    WmShell::Get()->CreateShelfView();
     WmShell::Get()->UpdateAfterLoginStatusChange(LoginStatus::USER);
   } else {
     session_state_ = session_manager::SessionState::LOGIN_PRIMARY;
diff --git a/ash/common/wm/window_cycle_list.cc b/ash/common/wm/window_cycle_list.cc
index bc2f2d0..c486947c 100644
--- a/ash/common/wm/window_cycle_list.cc
+++ b/ash/common/wm/window_cycle_list.cc
@@ -14,7 +14,6 @@
 #include "ash/public/cpp/shell_window_ids.h"
 #include "ash/root_window_controller.h"
 #include "base/command_line.h"
-#include "base/memory/ptr_util.h"
 #include "ui/accessibility/ax_node_data.h"
 #include "ui/compositor/scoped_layer_animation_settings.h"
 #include "ui/display/display.h"
@@ -247,9 +246,9 @@
     // because the layer animates bounds changes but the View's bounds change
     // immediately.
     highlight_view_->set_background(new LayerFillBackgroundPainter(
-        base::WrapUnique(views::Painter::CreateRoundRectWith1PxBorderPainter(
+        views::Painter::CreateRoundRectWith1PxBorderPainter(
             SkColorSetA(SK_ColorWHITE, 0x4D), SkColorSetA(SK_ColorWHITE, 0x33),
-            kBackgroundCornerRadius))));
+            kBackgroundCornerRadius)));
     highlight_view_->SetPaintToLayer(true);
     highlight_view_->layer()->SetFillsBoundsOpaquely(false);
 
diff --git a/ash/common/wm/workspace/phantom_window_controller.cc b/ash/common/wm/workspace/phantom_window_controller.cc
index bd56e4d..2843d93 100644
--- a/ash/common/wm/workspace/phantom_window_controller.cc
+++ b/ash/common/wm/workspace/phantom_window_controller.cc
@@ -130,11 +130,9 @@
   }
 
   const int kImages[] = IMAGE_GRID(IDR_AURA_PHANTOM_WINDOW);
-  views::Painter* background_painter =
-      views::Painter::CreateImageGridPainter(kImages);
   views::View* content_view = new views::View;
-  content_view->set_background(
-      views::Background::CreateBackgroundPainter(true, background_painter));
+  content_view->set_background(views::Background::CreateBackgroundPainter(
+      views::Painter::CreateImageGridPainter(kImages)));
   phantom_widget->SetContentsView(content_view);
 
   // Show the widget after all the setups.
diff --git a/ash/common/wm_shell.cc b/ash/common/wm_shell.cc
index c2f91ab..075d6d2b 100644
--- a/ash/common/wm_shell.cc
+++ b/ash/common/wm_shell.cc
@@ -153,14 +153,14 @@
                                                    source_type);
 }
 
-void WmShell::CreateShelf() {
+void WmShell::CreateShelfView() {
   // Must occur after SessionStateDelegate creation and user login.
   DCHECK(GetSessionStateDelegate());
   DCHECK_GT(GetSessionStateDelegate()->NumberOfLoggedInUsers(), 0);
   CreateShelfDelegate();
 
   for (WmWindow* root_window : GetAllRootWindows())
-    root_window->GetRootWindowController()->CreateShelf();
+    root_window->GetRootWindowController()->CreateShelfView();
 }
 
 void WmShell::CreateShelfDelegate() {
@@ -438,7 +438,7 @@
   // Create the shelf when a session becomes active. It's safe to do this
   // multiple times (e.g. initial login vs. multiprofile add session).
   if (state == session_manager::SessionState::ACTIVE)
-    CreateShelf();
+    CreateShelfView();
 }
 
 void WmShell::OnWindowActivated(
diff --git a/ash/common/wm_shell.h b/ash/common/wm_shell.h
index ade3b37b..f13fb91 100644
--- a/ash/common/wm_shell.h
+++ b/ash/common/wm_shell.h
@@ -360,8 +360,8 @@
   virtual std::unique_ptr<KeyEventWatcher> CreateKeyEventWatcher() = 0;
 
   // Creates the ShelfView for each display and populates it with items.
-  // TODO(jamescook): Rename this. http://crbug.com/679925
-  void CreateShelf();
+  // Called after the user session is active and profile is available.
+  void CreateShelfView();
 
   void CreateShelfDelegate();
 
diff --git a/ash/mus/BUILD.gn b/ash/mus/BUILD.gn
index 339b273c..586bbc8 100644
--- a/ash/mus/BUILD.gn
+++ b/ash/mus/BUILD.gn
@@ -49,8 +49,6 @@
     "non_client_frame_controller.h",
     "property_util.cc",
     "property_util.h",
-    "root_window_controller.cc",
-    "root_window_controller.h",
     "screen_mus.cc",
     "screen_mus.h",
     "shadow.cc",
@@ -63,6 +61,8 @@
     "shell_delegate_mus.h",
     "system_tray_delegate_mus.cc",
     "system_tray_delegate_mus.h",
+    "top_level_window_factory.cc",
+    "top_level_window_factory.h",
     "wallpaper_delegate_mus.cc",
     "wallpaper_delegate_mus.h",
     "window_manager.cc",
@@ -206,13 +206,13 @@
     "accelerators/accelerator_controller_unittest.cc",
     "app_launch_unittest.cc",
     "bridge/wm_shell_mus_test_api.h",
-    "root_window_controller_unittest.cc",
     "test/ash_test_impl_mus.cc",
     "test/ash_test_impl_mus.h",
     "test/wm_test_base.cc",
     "test/wm_test_base.h",
     "test/wm_test_helper.cc",
     "test/wm_test_helper.h",
+    "top_level_window_factory_unittest.cc",
     "window_manager_unittest.cc",
   ]
 
diff --git a/ash/mus/bridge/wm_lookup_mus.cc b/ash/mus/bridge/wm_lookup_mus.cc
index d0bc4e58..b5cab151 100644
--- a/ash/mus/bridge/wm_lookup_mus.cc
+++ b/ash/mus/bridge/wm_lookup_mus.cc
@@ -6,7 +6,6 @@
 
 #include "ash/common/wm_window.h"
 #include "ash/mus/bridge/wm_shell_mus.h"
-#include "ash/mus/root_window_controller.h"
 #include "ui/views/widget/widget.h"
 
 namespace ash {
@@ -21,11 +20,9 @@
     WmLookup::Set(nullptr);
 }
 
-ash::RootWindowController* WmLookupMus::GetRootWindowControllerWithDisplayId(
+RootWindowController* WmLookupMus::GetRootWindowControllerWithDisplayId(
     int64_t id) {
-  return WmShellMus::Get()
-      ->GetRootWindowControllerWithDisplayId(id)
-      ->ash_root_window_controller();
+  return WmShellMus::Get()->GetRootWindowControllerWithDisplayId(id);
 }
 
 WmWindow* WmLookupMus::GetWindowForWidget(views::Widget* widget) {
diff --git a/ash/mus/bridge/wm_lookup_mus.h b/ash/mus/bridge/wm_lookup_mus.h
index 91ad320..154534ad3 100644
--- a/ash/mus/bridge/wm_lookup_mus.h
+++ b/ash/mus/bridge/wm_lookup_mus.h
@@ -20,7 +20,7 @@
   ~WmLookupMus() override;
 
   // WmLookup:
-  ash::RootWindowController* GetRootWindowControllerWithDisplayId(
+  RootWindowController* GetRootWindowControllerWithDisplayId(
       int64_t id) override;
   WmWindow* GetWindowForWidget(views::Widget* widget) override;
 
diff --git a/ash/mus/bridge/wm_shell_mus.cc b/ash/mus/bridge/wm_shell_mus.cc
index 75e6b78..ca58c142 100644
--- a/ash/mus/bridge/wm_shell_mus.cc
+++ b/ash/mus/bridge/wm_shell_mus.cc
@@ -25,8 +25,9 @@
 #include "ash/mus/bridge/workspace_event_handler_mus.h"
 #include "ash/mus/drag_window_resizer.h"
 #include "ash/mus/keyboard_ui_mus.h"
-#include "ash/mus/root_window_controller.h"
+#include "ash/mus/screen_mus.h"
 #include "ash/mus/window_manager.h"
+#include "ash/root_window_controller.h"
 #include "ash/root_window_settings.h"
 #include "ash/shared/immersive_fullscreen_controller.h"
 #include "ash/shell.h"
@@ -149,15 +150,13 @@
 
 RootWindowController* WmShellMus::GetRootWindowControllerWithDisplayId(
     int64_t id) {
-  for (ash::RootWindowController* root_window_controller :
-       ash::RootWindowController::root_window_controllers()) {
+  for (RootWindowController* root_window_controller :
+       RootWindowController::root_window_controllers()) {
     RootWindowSettings* settings =
         GetRootWindowSettings(root_window_controller->GetRootWindow());
     DCHECK(settings);
-    if (settings->display_id == id) {
-      return RootWindowController::ForWindow(
-          root_window_controller->GetRootWindow());
-    }
+    if (settings->display_id == id)
+      return root_window_controller;
   }
   NOTREACHED();
   return nullptr;
@@ -214,8 +213,10 @@
 }
 
 WmWindow* WmShellMus::GetRootWindowForDisplayId(int64_t display_id) {
-  return WmWindow::Get(
-      GetRootWindowControllerWithDisplayId(display_id)->root());
+  RootWindowController* root_window_controller =
+      GetRootWindowControllerWithDisplayId(display_id);
+  DCHECK(root_window_controller);
+  return WmWindow::Get(root_window_controller->GetRootWindow());
 }
 
 const display::ManagedDisplayInfo& WmShellMus::GetDisplayInfo(
@@ -257,9 +258,7 @@
 
 void WmShellMus::SetDisplayWorkAreaInsets(WmWindow* window,
                                           const gfx::Insets& insets) {
-  RootWindowController* root_window_controller =
-      RootWindowController::ForWindow(window->aura_window());
-  root_window_controller->SetWorkAreaInests(insets);
+  window_manager_->screen()->SetWorkAreaInsets(window->aura_window(), insets);
 }
 
 bool WmShellMus::IsPinned() {
@@ -289,8 +288,8 @@
 
 std::vector<WmWindow*> WmShellMus::GetAllRootWindows() {
   std::vector<WmWindow*> root_windows;
-  for (ash::RootWindowController* root_window_controller :
-       ash::RootWindowController::root_window_controllers()) {
+  for (RootWindowController* root_window_controller :
+       RootWindowController::root_window_controllers()) {
     root_windows.push_back(root_window_controller->GetWindow());
   }
   return root_windows;
diff --git a/ash/mus/bridge/wm_shell_mus.h b/ash/mus/bridge/wm_shell_mus.h
index f089ce74..6539bab 100644
--- a/ash/mus/bridge/wm_shell_mus.h
+++ b/ash/mus/bridge/wm_shell_mus.h
@@ -22,12 +22,14 @@
 }
 
 namespace ash {
+
+class RootWindowController;
+
 namespace mus {
 
 class AcceleratorControllerDelegateMus;
 class AcceleratorControllerRegistrar;
 class ImmersiveHandlerFactoryMus;
-class RootWindowController;
 class WindowManager;
 class WmShellMusTestApi;
 
@@ -42,7 +44,7 @@
 
   static WmShellMus* Get();
 
-  RootWindowController* GetRootWindowControllerWithDisplayId(int64_t id);
+  ash::RootWindowController* GetRootWindowControllerWithDisplayId(int64_t id);
 
   AcceleratorControllerDelegateMus* accelerator_controller_delegate() {
     return accelerator_controller_delegate_.get();
diff --git a/ash/mus/root_window_controller.cc b/ash/mus/root_window_controller.cc
deleted file mode 100644
index c679108..0000000
--- a/ash/mus/root_window_controller.cc
+++ /dev/null
@@ -1,245 +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 "ash/mus/root_window_controller.h"
-
-#include <stdint.h>
-
-#include <algorithm>
-#include <map>
-#include <sstream>
-#include <string>
-#include <utility>
-#include <vector>
-
-#include "ash/common/shelf/shelf_layout_manager.h"
-#include "ash/common/shelf/wm_shelf.h"
-#include "ash/common/wm/container_finder.h"
-#include "ash/common/wm/dock/docked_window_layout_manager.h"
-#include "ash/common/wm/panels/panel_layout_manager.h"
-#include "ash/common/wm/root_window_layout_manager.h"
-#include "ash/common/wm_window.h"
-#include "ash/mus/bridge/wm_shell_mus.h"
-#include "ash/mus/disconnected_app_handler.h"
-#include "ash/mus/non_client_frame_controller.h"
-#include "ash/mus/property_util.h"
-#include "ash/mus/screen_mus.h"
-#include "ash/mus/window_manager.h"
-#include "ash/public/cpp/shell_window_ids.h"
-#include "ash/root_window_settings.h"
-#include "base/bind.h"
-#include "base/command_line.h"
-#include "base/memory/ptr_util.h"
-#include "mojo/public/cpp/bindings/type_converter.h"
-#include "services/service_manager/public/cpp/connector.h"
-#include "services/ui/common/switches.h"
-#include "services/ui/common/util.h"
-#include "ui/aura/client/aura_constants.h"
-#include "ui/aura/mus/property_converter.h"
-#include "ui/aura/mus/property_utils.h"
-#include "ui/aura/mus/window_tree_client.h"
-#include "ui/aura/mus/window_tree_host_mus.h"
-#include "ui/aura/window.h"
-#include "ui/aura/window_property.h"
-#include "ui/base/ui_base_types.h"
-#include "ui/display/display_list.h"
-
-DECLARE_WINDOW_PROPERTY_TYPE(ash::mus::RootWindowController*);
-
-namespace ash {
-namespace mus {
-namespace {
-
-DEFINE_LOCAL_WINDOW_PROPERTY_KEY(ash::mus::RootWindowController*,
-                                 kRootWindowControllerKey,
-                                 nullptr);
-
-bool IsFullscreen(aura::PropertyConverter* property_converter,
-                  const std::vector<uint8_t>& transport_data) {
-  using ui::mojom::WindowManager;
-  aura::PropertyConverter::PrimitiveType show_state = 0;
-  return property_converter->GetPropertyValueFromTransportValue(
-             WindowManager::kShowState_Property, transport_data, &show_state) &&
-         (static_cast<ui::WindowShowState>(show_state) ==
-          ui::SHOW_STATE_FULLSCREEN);
-}
-
-}  // namespace
-
-RootWindowController::RootWindowController(
-    WindowManager* window_manager,
-    std::unique_ptr<aura::WindowTreeHostMus> window_tree_host,
-    const display::Display& display,
-    ash::RootWindowController::RootWindowType root_window_type)
-    : window_manager_(window_manager),
-      window_tree_host_(window_tree_host.get()),
-      window_count_(0),
-      display_(display) {
-  RootWindowSettings* root_window_settings =
-      InitRootWindowSettings(window_tree_host->window());
-  root_window_settings->display_id = display.id();
-  window_tree_host->window()->SetProperty(kRootWindowControllerKey, this);
-  ash_root_window_controller_ = base::WrapUnique(
-      new ash::RootWindowController(nullptr, window_tree_host.release()));
-  ash_root_window_controller_->Init(root_window_type);
-
-  // TODO: To avoid lots of IPC AddActivationParent() should take an array.
-  // http://crbug.com/682048.
-  for (size_t i = 0; i < kNumActivatableShellWindowIds; ++i) {
-    window_manager_->window_manager_client()->AddActivationParent(
-        GetWindowByShellWindowId(kActivatableShellWindowIds[i])->aura_window());
-  }
-}
-
-RootWindowController::~RootWindowController() {
-  Shutdown();
-  ash_root_window_controller_.reset();
-}
-
-// static
-RootWindowController* RootWindowController::ForWindow(aura::Window* window) {
-  return window->GetRootWindow()->GetProperty(kRootWindowControllerKey);
-}
-
-void RootWindowController::Shutdown() {
-  // NOTE: Shutdown() may be called multiple times.
-  ash_root_window_controller_->Shutdown();
-}
-
-service_manager::Connector* RootWindowController::GetConnector() {
-  return window_manager_->connector();
-}
-
-aura::Window* RootWindowController::root() {
-  return window_tree_host_->window();
-}
-
-const aura::Window* RootWindowController::root() const {
-  return window_tree_host_->window();
-}
-
-aura::Window* RootWindowController::NewTopLevelWindow(
-    ui::mojom::WindowType window_type,
-    std::map<std::string, std::vector<uint8_t>>* properties) {
-  // TODO(sky): constrain and validate properties.
-
-  int32_t container_id = kShellWindowId_Invalid;
-  aura::Window* context = nullptr;
-  aura::Window* container_window = nullptr;
-  if (GetInitialContainerId(*properties, &container_id))
-    container_window = GetWindowByShellWindowId(container_id)->aura_window();
-  else
-    context = root();
-
-  gfx::Rect bounds = CalculateDefaultBounds(container_window, properties);
-  window_count_++;
-
-  const bool provide_non_client_frame =
-      window_type == ui::mojom::WindowType::WINDOW ||
-      window_type == ui::mojom::WindowType::PANEL;
-  if (provide_non_client_frame) {
-    // See NonClientFrameController for details on lifetime.
-    NonClientFrameController* non_client_frame_controller =
-        new NonClientFrameController(container_window, context, bounds,
-                                     window_type, properties, window_manager_);
-    DisconnectedAppHandler::Create(non_client_frame_controller->window());
-    return non_client_frame_controller->window();
-  }
-
-  aura::Window* window = new aura::Window(nullptr);
-  aura::SetWindowType(window, window_type);
-  // Apply properties before Init(), that way they are sent to the server at
-  // the time the window is created.
-  aura::PropertyConverter* property_converter =
-      window_manager_->property_converter();
-  for (auto& property_pair : *properties) {
-    property_converter->SetPropertyFromTransportValue(
-        window, property_pair.first, &property_pair.second);
-  }
-  window->Init(ui::LAYER_TEXTURED);
-  window->SetBounds(bounds);
-  DisconnectedAppHandler::Create(window);
-
-  if (container_window) {
-    container_window->AddChild(window);
-  } else {
-    WmWindow* root = WmWindow::Get(this->root());
-    gfx::Point origin =
-        root->ConvertPointToTarget(root->GetRootWindow(), gfx::Point());
-    origin += display_.bounds().OffsetFromOrigin();
-    gfx::Rect bounds_in_screen(origin, bounds.size());
-    ash::wm::GetDefaultParent(WmWindow::Get(context), WmWindow::Get(window),
-                              bounds_in_screen)
-        ->aura_window()
-        ->AddChild(window);
-  }
-  return window;
-}
-
-WmWindow* RootWindowController::GetWindowByShellWindowId(int id) {
-  return WmWindow::Get(root())->GetChildByShellWindowId(id);
-}
-
-void RootWindowController::SetWorkAreaInests(const gfx::Insets& insets) {
-  gfx::Rect old_work_area = display_.work_area();
-  display_.UpdateWorkAreaFromInsets(insets);
-
-  if (old_work_area == display_.work_area())
-    return;
-
-  window_manager_->screen()->display_list().UpdateDisplay(display_);
-
-  // Push new display insets to service:ui if we have a connection.
-  auto* display_controller = window_manager_->GetDisplayController();
-  if (display_controller) {
-    display_controller->SetDisplayWorkArea(display_.id(),
-                                           display_.bounds().size(), insets);
-  }
-}
-
-void RootWindowController::SetDisplay(const display::Display& display) {
-  DCHECK_EQ(display.id(), display_.id());
-  display_ = display;
-  window_manager_->screen()->display_list().UpdateDisplay(display_);
-}
-
-gfx::Rect RootWindowController::CalculateDefaultBounds(
-    aura::Window* container_window,
-    const std::map<std::string, std::vector<uint8_t>>* properties) const {
-  gfx::Rect requested_bounds;
-  if (GetInitialBounds(*properties, &requested_bounds))
-    return requested_bounds;
-
-  auto show_state_iter =
-      properties->find(ui::mojom::WindowManager::kShowState_Property);
-  if (show_state_iter != properties->end()) {
-    if (IsFullscreen(window_manager_->property_converter(),
-                     show_state_iter->second)) {
-      gfx::Rect bounds(0, 0, root()->bounds().width(),
-                       root()->bounds().height());
-      if (!container_window) {
-        bounds.Offset(display_.bounds().origin().x(),
-                      display_.bounds().origin().y());
-      }
-      return bounds;
-    }
-  }
-
-  int width, height;
-  gfx::Size pref;
-  if (GetWindowPreferredSize(*properties, &pref) && !pref.IsEmpty()) {
-    // TODO(sky): likely want to constrain more than root size.
-    const gfx::Size max_size = root()->bounds().size();
-    width = std::max(0, std::min(max_size.width(), pref.width()));
-    height = std::max(0, std::min(max_size.height(), pref.height()));
-  } else {
-    width = root()->bounds().width() - 240;
-    height = root()->bounds().height() - 240;
-  }
-  return gfx::Rect(40 + (window_count_ % 4) * 40, 40 + (window_count_ % 4) * 40,
-                   width, height);
-}
-
-}  // namespace mus
-}  // namespace ash
diff --git a/ash/mus/root_window_controller.h b/ash/mus/root_window_controller.h
deleted file mode 100644
index 14d29f6a..0000000
--- a/ash/mus/root_window_controller.h
+++ /dev/null
@@ -1,102 +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_MUS_ROOT_WINDOW_CONTROLLER_H_
-#define ASH_MUS_ROOT_WINDOW_CONTROLLER_H_
-
-#include <memory>
-
-#include "ash/root_window_controller.h"
-#include "services/ui/public/interfaces/window_manager_constants.mojom.h"
-#include "ui/display/display.h"
-
-namespace aura {
-class WindowTreeHostMus;
-}
-
-namespace gfx {
-class Insets;
-}
-
-namespace service_manager {
-class Connector;
-}
-
-namespace ash {
-
-class WmWindow;
-
-namespace mus {
-
-class WindowManager;
-class WmTestBase;
-class WmTestHelper;
-
-// RootWindowController manages the windows and state for a single display.
-// RootWindowController takes ownership of the WindowTreeHostMus that it passed
-// to it.
-// TODO(sky): rename this (or possibly just remove entirely).
-// http://crbug.com/671246
-class RootWindowController {
- public:
-  RootWindowController(
-      WindowManager* window_manager,
-      std::unique_ptr<aura::WindowTreeHostMus> window_tree_host,
-      const display::Display& display,
-      ash::RootWindowController::RootWindowType root_window_type);
-  ~RootWindowController();
-
-  // Returns the RootWindowController for |window|'s root.
-  static RootWindowController* ForWindow(aura::Window* window);
-
-  void Shutdown();
-
-  service_manager::Connector* GetConnector();
-
-  aura::Window* root();
-  const aura::Window* root() const;
-
-  aura::Window* NewTopLevelWindow(
-      ui::mojom::WindowType window_type,
-      std::map<std::string, std::vector<uint8_t>>* properties);
-
-  WmWindow* GetWindowByShellWindowId(int id);
-
-  void SetWorkAreaInests(const gfx::Insets& insets);
-  void SetDisplay(const display::Display& display);
-
-  WindowManager* window_manager() { return window_manager_; }
-
-  aura::WindowTreeHostMus* window_tree_host() { return window_tree_host_; }
-
-  const display::Display& display() const { return display_; }
-
-  ash::RootWindowController* ash_root_window_controller() {
-    return ash_root_window_controller_.get();
-  }
-
- private:
-  friend class WmTestBase;
-  friend class WmTestHelper;
-
-  gfx::Rect CalculateDefaultBounds(
-      aura::Window* container_window,
-      const std::map<std::string, std::vector<uint8_t>>* properties) const;
-  gfx::Rect GetMaximizedWindowBounds() const;
-
-  WindowManager* window_manager_;
-  std::unique_ptr<ash::RootWindowController> ash_root_window_controller_;
-  // Owned by |ash_root_window_controller_|.
-  aura::WindowTreeHostMus* window_tree_host_;
-  int window_count_ = 0;
-
-  display::Display display_;
-
-  DISALLOW_COPY_AND_ASSIGN(RootWindowController);
-};
-
-}  // namespace mus
-}  // namespace ash
-
-#endif  // ASH_MUS_ROOT_WINDOW_CONTROLLER_H_
diff --git a/ash/mus/screen_mus.cc b/ash/mus/screen_mus.cc
index f8c1586..260bd95 100644
--- a/ash/mus/screen_mus.cc
+++ b/ash/mus/screen_mus.cc
@@ -4,16 +4,37 @@
 
 #include "ash/mus/screen_mus.h"
 
+#include "services/ui/public/interfaces/display/display_controller.mojom.h"
 #include "ui/aura/env.h"
 #include "ui/aura/mus/window_tree_host_mus.h"
 #include "ui/aura/window.h"
 
 namespace ash {
 
-ScreenMus::ScreenMus() = default;
+ScreenMus::ScreenMus(display::mojom::DisplayController* display_controller)
+    : display_controller_(display_controller) {}
 
 ScreenMus::~ScreenMus() = default;
 
+void ScreenMus::SetWorkAreaInsets(aura::Window* window,
+                                  const gfx::Insets& insets) {
+  // If we are not the active instance assume we're in shutdown, and ignore.
+  if (display::Screen::GetScreen() != this)
+    return;
+
+  display::Display old_display = GetDisplayNearestWindow(window);
+  display::Display new_display = old_display;
+  new_display.UpdateWorkAreaFromInsets(insets);
+  if (old_display.work_area() == new_display.work_area())
+    return;
+
+  display_list().UpdateDisplay(new_display);
+  if (display_controller_) {
+    display_controller_->SetDisplayWorkArea(
+        new_display.id(), new_display.bounds().size(), insets);
+  }
+}
+
 display::Display ScreenMus::GetDisplayNearestWindow(
     aura::Window* window) const {
   const aura::WindowTreeHost* host = window->GetHost();
diff --git a/ash/mus/screen_mus.h b/ash/mus/screen_mus.h
index d75147f..752a77ff 100644
--- a/ash/mus/screen_mus.h
+++ b/ash/mus/screen_mus.h
@@ -8,6 +8,12 @@
 #include "base/macros.h"
 #include "ui/display/screen_base.h"
 
+namespace display {
+namespace mojom {
+class DisplayController;
+}
+}
+
 namespace ash {
 
 // Implementation of Screen for mus. The WindowManager/RootWindowController
@@ -18,14 +24,19 @@
 // http://crbug.com/671408.
 class ScreenMus : public display::ScreenBase {
  public:
-  ScreenMus();
+  explicit ScreenMus(display::mojom::DisplayController* display_controller);
   ~ScreenMus() override;
 
+  // Sets the work area of the display containing |window|.
+  void SetWorkAreaInsets(aura::Window* window, const gfx::Insets& insets);
+
  private:
   // display::ScreenBase:
   display::Display GetDisplayNearestWindow(aura::Window* window) const override;
   gfx::Point GetCursorScreenPoint() override;
 
+  display::mojom::DisplayController* display_controller_;
+
   DISALLOW_COPY_AND_ASSIGN(ScreenMus);
 };
 
diff --git a/ash/mus/test/wm_test_base.cc b/ash/mus/test/wm_test_base.cc
index 11786e9..251d90b 100644
--- a/ash/mus/test/wm_test_base.cc
+++ b/ash/mus/test/wm_test_base.cc
@@ -9,8 +9,8 @@
 
 #include "ash/common/session/session_controller.h"
 #include "ash/common/wm_shell.h"
-#include "ash/mus/root_window_controller.h"
 #include "ash/mus/test/wm_test_helper.h"
+#include "ash/mus/top_level_window_factory.h"
 #include "ash/mus/window_manager.h"
 #include "ash/mus/window_manager_application.h"
 #include "ash/public/cpp/session_types.h"
@@ -80,26 +80,27 @@
   std::vector<RootWindowController*> roots =
       test_helper_->GetRootsOrderedByDisplayId();
   DCHECK(!roots.empty());
-  return roots[0]->root();
+  return roots[0]->GetRootWindow();
 }
 
 aura::Window* WmTestBase::GetSecondaryRootWindow() {
   std::vector<RootWindowController*> roots =
       test_helper_->GetRootsOrderedByDisplayId();
-  return roots.size() < 2 ? nullptr : roots[1]->root();
+  return roots.size() < 2 ? nullptr : roots[1]->GetRootWindow();
 }
 
 display::Display WmTestBase::GetPrimaryDisplay() {
   std::vector<RootWindowController*> roots =
       test_helper_->GetRootsOrderedByDisplayId();
   DCHECK(!roots.empty());
-  return roots[0]->display();
+  return roots[0]->GetWindow()->GetDisplayNearestWindow();
 }
 
 display::Display WmTestBase::GetSecondaryDisplay() {
   std::vector<RootWindowController*> roots =
       test_helper_->GetRootsOrderedByDisplayId();
-  return roots.size() < 2 ? display::Display() : roots[1]->display();
+  return roots.size() < 2 ? display::Display()
+                          : roots[1]->GetWindow()->GetDisplayNearestWindow();
 }
 
 aura::Window* WmTestBase::CreateTestWindow(const gfx::Rect& bounds) {
@@ -123,9 +124,10 @@
 
   const ui::mojom::WindowType mus_window_type =
       MusWindowTypeFromWmWindowType(window_type);
-  aura::Window* window = test_helper_->GetRootsOrderedByDisplayId()[0]
-                             ->window_manager()
-                             ->NewTopLevelWindow(mus_window_type, &properties);
+  WindowManager* window_manager =
+      test_helper_->window_manager_app()->window_manager();
+  aura::Window* window = CreateAndParentTopLevelWindow(
+      window_manager, mus_window_type, &properties);
   window->Show();
   return window;
 }
@@ -140,10 +142,10 @@
     properties[ui::mojom::WindowManager::kDisplayId_InitProperty] =
         mojo::ConvertTo<std::vector<uint8_t>>(display_id);
   }
-  aura::Window* window =
-      test_helper_->GetRootsOrderedByDisplayId()[0]
-          ->window_manager()
-          ->NewTopLevelWindow(ui::mojom::WindowType::WINDOW, &properties);
+  WindowManager* window_manager =
+      test_helper_->window_manager_app()->window_manager();
+  aura::Window* window = CreateAndParentTopLevelWindow(
+      window_manager, ui::mojom::WindowType::WINDOW, &properties);
   window->Show();
   return window;
 }
diff --git a/ash/mus/test/wm_test_helper.cc b/ash/mus/test/wm_test_helper.cc
index 184bee1..8bfb0e4f 100644
--- a/ash/mus/test/wm_test_helper.cc
+++ b/ash/mus/test/wm_test_helper.cc
@@ -9,7 +9,7 @@
 #include "ash/common/test/test_system_tray_delegate.h"
 #include "ash/common/test/wm_shell_test_api.h"
 #include "ash/common/wm_shell.h"
-#include "ash/mus/root_window_controller.h"
+#include "ash/common/wm_window.h"
 #include "ash/mus/screen_mus.h"
 #include "ash/mus/window_manager.h"
 #include "ash/mus/window_manager_application.h"
@@ -34,9 +34,10 @@
 namespace mus {
 namespace {
 
-bool CompareByDisplayId(const RootWindowController* root1,
-                        const RootWindowController* root2) {
-  return root1->display().id() < root2->display().id();
+bool CompareByDisplayId(RootWindowController* root1,
+                        RootWindowController* root2) {
+  return root1->GetWindow()->GetDisplayNearestWindow().id() <
+         root2->GetWindow()->GetDisplayNearestWindow().id();
 }
 
 // TODO(sky): at some point this needs to support everything in DisplayInfo,
@@ -175,19 +176,19 @@
   gfx::Rect bounds = ParseDisplayBounds(display_spec);
   bounds.set_x(*next_x);
   *next_x += bounds.size().width();
-  gfx::Insets work_area_insets =
-      root_window_controller->display_.GetWorkAreaInsets();
-  root_window_controller->display_.set_bounds(bounds);
-  root_window_controller->display_.UpdateWorkAreaFromInsets(work_area_insets);
-  root_window_controller->root()->SetBounds(gfx::Rect(bounds.size()));
+  display::Display updated_display =
+      root_window_controller->GetWindow()->GetDisplayNearestWindow();
+  gfx::Insets work_area_insets = updated_display.GetWorkAreaInsets();
+  updated_display.set_bounds(bounds);
+  updated_display.UpdateWorkAreaFromInsets(work_area_insets);
+  root_window_controller->GetWindow()->SetBounds(gfx::Rect(bounds.size()));
   ScreenMus* screen = window_manager_app_->window_manager()->screen_.get();
-  const bool is_primary = screen->display_list().FindDisplayById(
-                              root_window_controller->display().id()) ==
-                          screen->display_list().GetPrimaryDisplayIterator();
+  const bool is_primary =
+      screen->display_list().FindDisplayById(updated_display.id()) ==
+      screen->display_list().GetPrimaryDisplayIterator();
   screen->display_list().UpdateDisplay(
-      root_window_controller->display(),
-      is_primary ? display::DisplayList::Type::PRIMARY
-                 : display::DisplayList::Type::NOT_PRIMARY);
+      updated_display, is_primary ? display::DisplayList::Type::PRIMARY
+                                  : display::DisplayList::Type::NOT_PRIMARY);
 }
 
 }  // namespace mus
diff --git a/ash/mus/test/wm_test_helper.h b/ash/mus/test/wm_test_helper.h
index 5900711..8ba7e04 100644
--- a/ash/mus/test/wm_test_helper.h
+++ b/ash/mus/test/wm_test_helper.h
@@ -29,10 +29,11 @@
 }
 
 namespace ash {
-namespace mus {
 
 class RootWindowController;
 
+namespace mus {
+
 // WMTestHelper is responsible for configuring a WindowTreeClient that
 // does not talk to mus.
 class WmTestHelper {
diff --git a/ash/mus/top_level_window_factory.cc b/ash/mus/top_level_window_factory.cc
new file mode 100644
index 0000000..f3260d0d
--- /dev/null
+++ b/ash/mus/top_level_window_factory.cc
@@ -0,0 +1,193 @@
+// 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 "ash/mus/top_level_window_factory.h"
+
+#include "ash/common/wm/container_finder.h"
+#include "ash/common/wm/window_state.h"
+#include "ash/common/wm_shell.h"
+#include "ash/common/wm_window.h"
+#include "ash/mus/disconnected_app_handler.h"
+#include "ash/mus/non_client_frame_controller.h"
+#include "ash/mus/property_util.h"
+#include "ash/mus/window_manager.h"
+#include "ash/public/cpp/shell_window_ids.h"
+#include "ash/root_window_controller.h"
+#include "ash/root_window_settings.h"
+#include "mojo/public/cpp/bindings/type_converter.h"
+#include "services/ui/public/cpp/property_type_converters.h"
+#include "services/ui/public/interfaces/window_manager.mojom.h"
+#include "services/ui/public/interfaces/window_manager_constants.mojom.h"
+#include "ui/aura/mus/property_converter.h"
+#include "ui/aura/mus/property_utils.h"
+#include "ui/aura/window.h"
+#include "ui/display/display.h"
+
+namespace ash {
+namespace mus {
+namespace {
+
+// Returns true if a fullscreen window was requested.
+bool IsFullscreen(aura::PropertyConverter* property_converter,
+                  const std::vector<uint8_t>& transport_data) {
+  using ui::mojom::WindowManager;
+  aura::PropertyConverter::PrimitiveType show_state = 0;
+  return property_converter->GetPropertyValueFromTransportValue(
+             WindowManager::kShowState_Property, transport_data, &show_state) &&
+         (static_cast<ui::WindowShowState>(show_state) ==
+          ui::SHOW_STATE_FULLSCREEN);
+}
+
+// Returns the RootWindowController where new top levels are created.
+// |properties| is the properties supplied during window creation.
+RootWindowController* GetRootWindowControllerForNewTopLevelWindow(
+    std::map<std::string, std::vector<uint8_t>>* properties) {
+  // If a specific display was requested, use it.
+  const int64_t display_id = GetInitialDisplayId(*properties);
+  if (display_id != display::kInvalidDisplayId) {
+    for (RootWindowController* root_window_controller :
+         RootWindowController::root_window_controllers()) {
+      if (GetRootWindowSettings(root_window_controller->GetRootWindow())
+              ->display_id == display_id) {
+        return root_window_controller;
+      }
+    }
+  }
+  return RootWindowController::ForWindow(
+      WmShell::Get()->GetRootWindowForNewWindows()->aura_window());
+}
+
+// Returns the bounds for the new window.
+gfx::Rect CalculateDefaultBounds(
+    WindowManager* window_manager,
+    RootWindowController* root_window_controller,
+    aura::Window* container_window,
+    const std::map<std::string, std::vector<uint8_t>>* properties) {
+  gfx::Rect requested_bounds;
+  if (GetInitialBounds(*properties, &requested_bounds))
+    return requested_bounds;
+
+  const gfx::Size root_size =
+      root_window_controller->GetRootWindow()->bounds().size();
+  auto show_state_iter =
+      properties->find(ui::mojom::WindowManager::kShowState_Property);
+  if (show_state_iter != properties->end()) {
+    if (IsFullscreen(window_manager->property_converter(),
+                     show_state_iter->second)) {
+      gfx::Rect bounds(root_size);
+      if (!container_window) {
+        const display::Display display =
+            root_window_controller->GetWindow()->GetDisplayNearestWindow();
+        bounds.Offset(display.bounds().OffsetFromOrigin());
+      }
+      return bounds;
+    }
+  }
+
+  gfx::Size window_size;
+  if (GetWindowPreferredSize(*properties, &window_size) &&
+      !window_size.IsEmpty()) {
+    // TODO(sky): likely want to constrain more than root size.
+    window_size.SetToMin(root_size);
+  } else {
+    static constexpr int kRootSizeDelta = 240;
+    window_size.SetSize(root_size.width() - kRootSizeDelta,
+                        root_size.height() - kRootSizeDelta);
+  }
+  // TODO(sky): this should use code in chrome/browser/ui/window_sizer.
+  static constexpr int kOriginOffset = 40;
+  return gfx::Rect(gfx::Point(kOriginOffset, kOriginOffset), window_size);
+}
+
+// Does the real work of CreateAndParentTopLevelWindow() once the appropriate
+// RootWindowController was found.
+aura::Window* CreateAndParentTopLevelWindowInRoot(
+    WindowManager* window_manager,
+    RootWindowController* root_window_controller,
+    ui::mojom::WindowType window_type,
+    std::map<std::string, std::vector<uint8_t>>* properties) {
+  // TODO(sky): constrain and validate properties.
+
+  int32_t container_id = kShellWindowId_Invalid;
+  aura::Window* context = nullptr;
+  aura::Window* container_window = nullptr;
+  if (GetInitialContainerId(*properties, &container_id)) {
+    container_window = root_window_controller->GetWindow()
+                           ->GetChildByShellWindowId(container_id)
+                           ->aura_window();
+  } else {
+    context = root_window_controller->GetRootWindow();
+  }
+
+  gfx::Rect bounds = CalculateDefaultBounds(
+      window_manager, root_window_controller, container_window, properties);
+
+  const bool provide_non_client_frame =
+      window_type == ui::mojom::WindowType::WINDOW ||
+      window_type == ui::mojom::WindowType::PANEL;
+  if (provide_non_client_frame) {
+    // See NonClientFrameController for details on lifetime.
+    NonClientFrameController* non_client_frame_controller =
+        new NonClientFrameController(container_window, context, bounds,
+                                     window_type, properties, window_manager);
+    return non_client_frame_controller->window();
+  }
+
+  aura::Window* window = new aura::Window(nullptr);
+  aura::SetWindowType(window, window_type);
+  // Apply properties before Init(), that way they are sent to the server at
+  // the time the window is created.
+  aura::PropertyConverter* property_converter =
+      window_manager->property_converter();
+  for (auto& property_pair : *properties) {
+    property_converter->SetPropertyFromTransportValue(
+        window, property_pair.first, &property_pair.second);
+  }
+  window->Init(ui::LAYER_TEXTURED);
+  window->SetBounds(bounds);
+
+  if (container_window) {
+    container_window->AddChild(window);
+  } else {
+    WmWindow* root = root_window_controller->GetWindow();
+    gfx::Point origin =
+        root->ConvertPointToTarget(root->GetRootWindow(), gfx::Point());
+    origin += root_window_controller->GetWindow()
+                  ->GetDisplayNearestWindow()
+                  .bounds()
+                  .OffsetFromOrigin();
+    gfx::Rect bounds_in_screen(origin, bounds.size());
+    ash::wm::GetDefaultParent(WmWindow::Get(context), WmWindow::Get(window),
+                              bounds_in_screen)
+        ->aura_window()
+        ->AddChild(window);
+  }
+  return window;
+}
+
+}  // namespace
+
+aura::Window* CreateAndParentTopLevelWindow(
+    WindowManager* window_manager,
+    ui::mojom::WindowType window_type,
+    std::map<std::string, std::vector<uint8_t>>* properties) {
+  RootWindowController* root_window_controller =
+      GetRootWindowControllerForNewTopLevelWindow(properties);
+  aura::Window* window = CreateAndParentTopLevelWindowInRoot(
+      window_manager, root_window_controller, window_type, properties);
+  DisconnectedAppHandler::Create(window);
+  if (properties->count(
+          ui::mojom::WindowManager::kWindowIgnoredByShelf_Property)) {
+    wm::WindowState* window_state = WmWindow::Get(window)->GetWindowState();
+    window_state->set_ignored_by_shelf(mojo::ConvertTo<bool>(
+        (*properties)
+            [ui::mojom::WindowManager::kWindowIgnoredByShelf_Property]));
+    // No need to persist this value.
+    properties->erase(ui::mojom::WindowManager::kWindowIgnoredByShelf_Property);
+  }
+  return window;
+}
+
+}  // namespace mus
+}  // namespace ash
diff --git a/ash/mus/top_level_window_factory.h b/ash/mus/top_level_window_factory.h
new file mode 100644
index 0000000..5f4a2b3f
--- /dev/null
+++ b/ash/mus/top_level_window_factory.h
@@ -0,0 +1,39 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef ASH_MUS_TOP_LEVEL_WINDOW_FACTORY_H_
+#define ASH_MUS_TOP_LEVEL_WINDOW_FACTORY_H_
+
+#include <stdint.h>
+
+#include <map>
+#include <string>
+#include <vector>
+
+namespace aura {
+class Window;
+}
+
+namespace ui {
+namespace mojom {
+enum class WindowType;
+}
+}
+
+namespace ash {
+namespace mus {
+
+class WindowManager;
+
+// Creates and parents a new top-level window and returns it. The returned
+// aura::Window is owned by its parent.
+aura::Window* CreateAndParentTopLevelWindow(
+    WindowManager* window_manager,
+    ui::mojom::WindowType window_type,
+    std::map<std::string, std::vector<uint8_t>>* properties);
+
+}  // namespace mus
+}  // namespace ash
+
+#endif  // ASH_MUS_TOP_LEVEL_WINDOW_FACTORY_H_
diff --git a/ash/mus/root_window_controller_unittest.cc b/ash/mus/top_level_window_factory_unittest.cc
similarity index 84%
rename from ash/mus/root_window_controller_unittest.cc
rename to ash/mus/top_level_window_factory_unittest.cc
index 2037cd2..65c44d4 100644
--- a/ash/mus/root_window_controller_unittest.cc
+++ b/ash/mus/top_level_window_factory_unittest.cc
@@ -2,8 +2,6 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "ash/mus/root_window_controller.h"
-
 #include "ash/common/test/ash_test.h"
 #include "ash/common/wm_shell.h"
 #include "ash/common/wm_window.h"
@@ -21,9 +19,9 @@
 
 }  // namespace
 
-using RootWindowControllerTest = AshTest;
+using TopLevelWindowFactoryTest = AshTest;
 
-TEST_F(RootWindowControllerTest, CreateFullscreenWindow) {
+TEST_F(TopLevelWindowFactoryTest, CreateFullscreenWindow) {
   std::unique_ptr<WindowOwner> window_owner = CreateToplevelTestWindow();
   WmWindow* window = window_owner->window();
   window->SetFullscreen();
@@ -31,9 +29,9 @@
   EXPECT_EQ(root_window->GetBounds(), window->GetBounds());
 }
 
-using RootWindowControllerWmTest = mus::WmTestBase;
+using TopLevelWindowFactoryWmTest = mus::WmTestBase;
 
-TEST_F(RootWindowControllerWmTest, IsWindowShownInCorrectDisplay) {
+TEST_F(TopLevelWindowFactoryWmTest, IsWindowShownInCorrectDisplay) {
   if (!SupportsMultipleDisplays())
     return;
 
diff --git a/ash/mus/window_manager.cc b/ash/mus/window_manager.cc
index fcdced56..8d7f21e 100644
--- a/ash/mus/window_manager.cc
+++ b/ash/mus/window_manager.cc
@@ -20,13 +20,14 @@
 #include "ash/mus/move_event_handler.h"
 #include "ash/mus/non_client_frame_controller.h"
 #include "ash/mus/property_util.h"
-#include "ash/mus/root_window_controller.h"
 #include "ash/mus/screen_mus.h"
 #include "ash/mus/shadow_controller.h"
 #include "ash/mus/shell_delegate_mus.h"
+#include "ash/mus/top_level_window_factory.h"
 #include "ash/mus/window_properties.h"
 #include "ash/public/cpp/shell_window_ids.h"
 #include "ash/root_window_controller.h"
+#include "ash/root_window_settings.h"
 #include "ash/shell.h"
 #include "ash/shell_init_params.h"
 #include "ash/wm/ash_focus_rules.h"
@@ -92,7 +93,7 @@
   if (connector_)
     connector_->BindInterface(ui::mojom::kServiceName, &display_controller_);
 
-  screen_ = base::MakeUnique<ScreenMus>();
+  screen_ = base::MakeUnique<ScreenMus>(display_controller_.get());
   display::Screen::SetScreenInstance(screen_.get());
 
   pointer_watcher_event_router_ =
@@ -136,25 +137,6 @@
   DCHECK(root_window_controllers_.empty());
 }
 
-aura::Window* WindowManager::NewTopLevelWindow(
-    ui::mojom::WindowType window_type,
-    std::map<std::string, std::vector<uint8_t>>* properties) {
-  RootWindowController* root_window_controller =
-      GetRootWindowControllerForNewTopLevelWindow(properties);
-  aura::Window* window =
-      root_window_controller->NewTopLevelWindow(window_type, properties);
-  if (properties->count(
-          ui::mojom::WindowManager::kWindowIgnoredByShelf_Property)) {
-    wm::WindowState* window_state = WmWindow::Get(window)->GetWindowState();
-    window_state->set_ignored_by_shelf(mojo::ConvertTo<bool>(
-        (*properties)
-            [ui::mojom::WindowManager::kWindowIgnoredByShelf_Property]));
-    // No need to persist this value.
-    properties->erase(ui::mojom::WindowManager::kWindowIgnoredByShelf_Property);
-  }
-  return window;
-}
-
 std::set<RootWindowController*> WindowManager::GetRootWindowControllers() {
   std::set<RootWindowController*> result;
   for (auto& root_window_controller : root_window_controllers_)
@@ -190,11 +172,9 @@
     std::unique_ptr<aura::WindowTreeHostMus> window_tree_host) {
   // See comment in CreateRootWindowController().
   DCHECK(created_shell_);
-  std::unique_ptr<RootWindowController> root_window_controller_ptr(
-      new RootWindowController(
-          this, std::move(window_tree_host), screen_->GetAllDisplays()[0],
-          ash::RootWindowController::RootWindowType::PRIMARY));
-  root_window_controllers_.insert(std::move(root_window_controller_ptr));
+  CreateAndRegisterRootWindowController(
+      std::move(window_tree_host), screen_->GetAllDisplays()[0],
+      RootWindowController::RootWindowType::PRIMARY);
 }
 
 void WindowManager::CreateShell(
@@ -213,31 +193,25 @@
   Shell::CreateInstance(init_params);
 }
 
-void WindowManager::CreateRootWindowController(
+void WindowManager::CreateAndRegisterRootWindowController(
     std::unique_ptr<aura::WindowTreeHostMus> window_tree_host,
     const display::Display& display,
-    ash::RootWindowController::RootWindowType root_window_type) {
-  // The ash startup sequence creates the Shell, which creates
-  // WindowTreeHostManager, which creates the WindowTreeHosts and
-  // RootWindowControllers. For mash we are supplied the WindowTreeHost when
-  // a display is added (and WindowTreeHostManager is not used in mash). Mash
-  // waits for the first WindowTreeHost, then creates the shell. As there are
-  // order dependencies we have to create the RootWindowController at a similar
-  // time as cash, to do that we inject the WindowTreeHost into ShellInitParams.
-  // Shell calls to WmShell::InitHosts(), which calls back to
-  // CreatePrimaryRootWindowController().
-  if (!created_shell_) {
-    CreateShell(std::move(window_tree_host));
-    return;
+    RootWindowController::RootWindowType root_window_type) {
+  RootWindowSettings* root_window_settings =
+      InitRootWindowSettings(window_tree_host->window());
+  root_window_settings->display_id = display.id();
+  std::unique_ptr<RootWindowController> root_window_controller(
+      new RootWindowController(nullptr, window_tree_host.release()));
+  root_window_controller->Init(root_window_type);
+  // TODO: To avoid lots of IPC AddActivationParent() should take an array.
+  // http://crbug.com/682048.
+  WmWindow* root_window = root_window_controller->GetWindow();
+  for (size_t i = 0; i < kNumActivatableShellWindowIds; ++i) {
+    window_manager_client_->AddActivationParent(
+        root_window->GetChildByShellWindowId(kActivatableShellWindowIds[i])
+            ->aura_window());
   }
-  std::unique_ptr<RootWindowController> root_window_controller_ptr(
-      new RootWindowController(
-          this, std::move(window_tree_host), display,
-          ash::RootWindowController::RootWindowType::SECONDARY));
-  root_window_controllers_.insert(std::move(root_window_controller_ptr));
-
-  for (auto& observer : *screen_->display_list().observers())
-    observer.OnDisplayAdded(display);
+  root_window_controllers_.insert(std::move(root_window_controller));
 }
 
 void WindowManager::DestroyRootWindowController(
@@ -245,8 +219,8 @@
     bool in_shutdown) {
   if (!in_shutdown && root_window_controllers_.size() > 1) {
     DCHECK_NE(root_window_controller, GetPrimaryRootWindowController());
-    root_window_controller->ash_root_window_controller()->MoveWindowsTo(
-        GetPrimaryRootWindowController()->root());
+    root_window_controller->MoveWindowsTo(
+        GetPrimaryRootWindowController()->GetRootWindow());
   }
 
   root_window_controller->Shutdown();
@@ -282,20 +256,6 @@
                                              ->aura_window());
 }
 
-RootWindowController*
-WindowManager::GetRootWindowControllerForNewTopLevelWindow(
-    std::map<std::string, std::vector<uint8_t>>* properties) {
-  // If a specific display was requested, use it.
-  const int64_t display_id = GetInitialDisplayId(*properties);
-  for (auto& root_window_controller_ptr : root_window_controllers_) {
-    if (root_window_controller_ptr->display().id() == display_id)
-      return root_window_controller_ptr.get();
-  }
-
-  return RootWindowController::ForWindow(
-      WmShellMus::Get()->GetRootWindowForNewWindows()->aura_window());
-}
-
 void WindowManager::OnEmbed(
     std::unique_ptr<aura::WindowTreeHostMus> window_tree_host) {
   // WindowManager should never see this, instead OnWmNewDisplay() is called.
@@ -369,7 +329,7 @@
     return nullptr;
   }
 
-  return NewTopLevelWindow(window_type, properties);
+  return CreateAndParentTopLevelWindow(this, window_type, properties);
 }
 
 void WindowManager::OnWmClientJankinessChanged(
@@ -398,18 +358,34 @@
 void WindowManager::OnWmNewDisplay(
     std::unique_ptr<aura::WindowTreeHostMus> window_tree_host,
     const display::Display& display) {
-  ash::RootWindowController::RootWindowType root_window_type =
+  RootWindowController::RootWindowType root_window_type =
       screen_->display_list().displays().size() == 1
-          ? ash::RootWindowController::RootWindowType::PRIMARY
-          : ash::RootWindowController::RootWindowType::SECONDARY;
-  CreateRootWindowController(std::move(window_tree_host), display,
-                             root_window_type);
+          ? RootWindowController::RootWindowType::PRIMARY
+          : RootWindowController::RootWindowType::SECONDARY;
+  // The ash startup sequence creates the Shell, which creates
+  // WindowTreeHostManager, which creates the WindowTreeHosts and
+  // RootWindowControllers. For mash we are supplied the WindowTreeHost when
+  // a display is added (and WindowTreeHostManager is not used in mash). Mash
+  // waits for the first WindowTreeHost, then creates the shell. As there are
+  // order dependencies we have to create the RootWindowController at a similar
+  // time as cash, to do that we inject the WindowTreeHost into ShellInitParams.
+  // Shell calls to WmShell::InitHosts(), which calls back to
+  // CreatePrimaryRootWindowController().
+  if (!created_shell_) {
+    CreateShell(std::move(window_tree_host));
+    return;
+  }
+  CreateAndRegisterRootWindowController(std::move(window_tree_host), display,
+                                        root_window_type);
+
+  for (auto& observer : *screen_->display_list().observers())
+    observer.OnDisplayAdded(display);
 }
 
 void WindowManager::OnWmDisplayRemoved(
     aura::WindowTreeHostMus* window_tree_host) {
   for (auto& root_window_controller_ptr : root_window_controllers_) {
-    if (root_window_controller_ptr->window_tree_host() == window_tree_host) {
+    if (root_window_controller_ptr->GetHost() == window_tree_host) {
       const bool in_shutdown = false;
       DestroyRootWindowController(root_window_controller_ptr.get(),
                                   in_shutdown);
@@ -419,15 +395,7 @@
 }
 
 void WindowManager::OnWmDisplayModified(const display::Display& display) {
-  for (auto& controller : root_window_controllers_) {
-    if (controller->display().id() == display.id()) {
-      controller->SetDisplay(display);
-      // The root window will be resized by the window server.
-      return;
-    }
-  }
-
-  NOTREACHED();
+  screen_->display_list().UpdateDisplay(display);
 }
 
 void WindowManager::OnWmPerformMoveLoop(
diff --git a/ash/mus/window_manager.h b/ash/mus/window_manager.h
index ec6dfc89..6936f926 100644
--- a/ash/mus/window_manager.h
+++ b/ash/mus/window_manager.h
@@ -41,13 +41,13 @@
 
 namespace ash {
 
+class RootWindowController;
 class ScreenMus;
 class SystemTrayDelegate;
 
 namespace mus {
 
 class AcceleratorHandler;
-class RootWindowController;
 class ShadowController;
 class WmLookupMus;
 class WmTestHelper;
@@ -84,11 +84,6 @@
     return property_converter_.get();
   }
 
-  // Creates a new top level window.
-  aura::Window* NewTopLevelWindow(
-      ui::mojom::WindowType window_type,
-      std::map<std::string, std::vector<uint8_t>>* properties);
-
   std::set<RootWindowController*> GetRootWindowControllers();
 
   // Returns the next accelerator namespace id by value in |id|. Returns true
@@ -116,7 +111,7 @@
   void CreateShell(
       std::unique_ptr<aura::WindowTreeHostMus> primary_window_tree_host);
 
-  void CreateRootWindowController(
+  void CreateAndRegisterRootWindowController(
       std::unique_ptr<aura::WindowTreeHostMus> window_tree_host,
       const display::Display& display,
       ash::RootWindowController::RootWindowType root_window_type);
@@ -130,11 +125,6 @@
 
   RootWindowController* GetPrimaryRootWindowController();
 
-  // Returns the RootWindowController where new top levels are created.
-  // |properties| is the properties supplied during window creation.
-  RootWindowController* GetRootWindowControllerForNewTopLevelWindow(
-      std::map<std::string, std::vector<uint8_t>>* properties);
-
   // WindowTreeClientDelegate:
   void OnEmbed(
       std::unique_ptr<aura::WindowTreeHostMus> window_tree_host) override;
diff --git a/ash/root_window_controller.cc b/ash/root_window_controller.cc
index ed93360..7585098 100644
--- a/ash/root_window_controller.cc
+++ b/ash/root_window_controller.cc
@@ -355,11 +355,13 @@
   return wm_shelf_.get();
 }
 
-void RootWindowController::CreateShelf() {
+void RootWindowController::CreateShelfView() {
   if (wm_shelf_->IsShelfInitialized())
     return;
-  wm_shelf_->InitializeShelf();
+  wm_shelf_->CreateShelfView();
 
+  // TODO(jamescook): Pass |wm_shelf_| into the constructors for these layout
+  // managers.
   if (panel_layout_manager_)
     panel_layout_manager_->SetShelf(wm_shelf_.get());
   if (docked_window_layout_manager_) {
@@ -800,7 +802,7 @@
 
     // Create a shelf if a user is already logged in.
     if (wm_shell->GetSessionStateDelegate()->NumberOfLoggedInUsers())
-      CreateShelf();
+      CreateShelfView();
 
     // Notify shell observers about new root window.
     shell->OnRootWindowAdded(WmWindow::Get(root_window));
diff --git a/ash/root_window_controller.h b/ash/root_window_controller.h
index 56610f5..660b2cf8 100644
--- a/ash/root_window_controller.h
+++ b/ash/root_window_controller.h
@@ -67,7 +67,7 @@
 class WorkspaceController;
 
 namespace mus {
-class RootWindowController;
+class WindowManager;
 }
 
 namespace wm {
@@ -144,8 +144,8 @@
 
   WmShelf* GetShelf();
 
-  // Creates the shelf for this root window and notifies observers.
-  void CreateShelf();
+  // Creates the shelf view for this root window and notifies observers.
+  void CreateShelfView();
 
   // Get touch HUDs associated with this root window controller.
   TouchHudDebug* touch_hud_debug() const { return touch_hud_debug_; }
@@ -291,7 +291,7 @@
  private:
   // TODO(sky): remove this. Temporary during ash-mus unification.
   // http://crbug.com/671246.
-  friend class mus::RootWindowController;
+  friend class mus::WindowManager;
 
   // Creates a new RootWindowController with the specified host. Only one of
   // |ash_host| or |window_tree_host| should be specified. This takes ownership
diff --git a/ash/shell/content/client/shell_browser_main_parts.cc b/ash/shell/content/client/shell_browser_main_parts.cc
index 81e5c18..0259296 100644
--- a/ash/shell/content/client/shell_browser_main_parts.cc
+++ b/ash/shell/content/client/shell_browser_main_parts.cc
@@ -133,7 +133,7 @@
   init_params.context_factory_private = content::GetContextFactoryPrivate();
   init_params.blocking_pool = content::BrowserThread::GetBlockingPool();
   ash::Shell::CreateInstance(init_params);
-  ash::WmShell::Get()->CreateShelf();
+  ash::WmShell::Get()->CreateShelfView();
   ash::WmShell::Get()->UpdateAfterLoginStatusChange(LoginStatus::USER);
 
   window_watcher_.reset(new ash::shell::WindowWatcher);
diff --git a/ash/system/chromeos/power/tablet_power_button_controller.cc b/ash/system/chromeos/power/tablet_power_button_controller.cc
index 7017674..cb0a7f1 100644
--- a/ash/system/chromeos/power/tablet_power_button_controller.cc
+++ b/ash/system/chromeos/power/tablet_power_button_controller.cc
@@ -25,9 +25,6 @@
 // animation when in tablet mode.
 constexpr int kShutdownTimeoutMs = 500;
 
-// Amount of time to delay locking screen after display is forced off.
-constexpr int kLockScreenTimeoutMs = 1000;
-
 // Amount of time since last SuspendDone() that power button event needs to be
 // ignored.
 constexpr int kIgnorePowerButtonAfterResumeMs = 2000;
@@ -67,16 +64,6 @@
   controller_->shutdown_timer_.Stop();
 }
 
-bool TabletPowerButtonController::TestApi::LockScreenTimerIsRunning() const {
-  return controller_->lock_screen_timer_.IsRunning();
-}
-
-void TabletPowerButtonController::TestApi::TriggerLockScreenTimeout() {
-  DCHECK(LockScreenTimerIsRunning());
-  controller_->OnLockScreenTimeout();
-  controller_->lock_screen_timer_.Stop();
-}
-
 TabletPowerButtonController::TabletPowerButtonController(
     LockStateController* controller)
     : tick_clock_(new base::DefaultTickClock()),
@@ -125,7 +112,6 @@
     }
     screen_off_when_power_button_down_ = brightness_level_is_zero_;
     SetDisplayForcedOff(false);
-    lock_screen_timer_.Stop();
     StartShutdownTimer();
   } else {
     if (shutdown_timer_.IsRunning()) {
@@ -177,27 +163,22 @@
   if (event->key_code() == ui::VKEY_POWER)
     return;
 
-  if (!IsTabletModeActive() && backlights_forced_off_) {
+  if (!IsTabletModeActive() && backlights_forced_off_)
     SetDisplayForcedOff(false);
-    lock_screen_timer_.Stop();
-  }
 }
 
 void TabletPowerButtonController::OnMouseEvent(ui::MouseEvent* event) {
   if (event->flags() & ui::EF_IS_SYNTHESIZED)
     return;
 
-  if (!IsTabletModeActive() && backlights_forced_off_) {
+  if (!IsTabletModeActive() && backlights_forced_off_)
     SetDisplayForcedOff(false);
-    lock_screen_timer_.Stop();
-  }
 }
 
 void TabletPowerButtonController::OnStylusStateChanged(ui::StylusState state) {
   if (IsTabletModeSupported() && state == ui::StylusState::REMOVED &&
       backlights_forced_off_) {
     SetDisplayForcedOff(false);
-    lock_screen_timer_.Stop();
   }
 }
 
@@ -257,14 +238,8 @@
       session_state_delegate->CanLockScreen() &&
       !session_state_delegate->IsUserSessionBlocked() &&
       !controller_->LockRequested()) {
-    lock_screen_timer_.Start(
-        FROM_HERE, base::TimeDelta::FromMilliseconds(kLockScreenTimeoutMs),
-        this, &TabletPowerButtonController::OnLockScreenTimeout);
+    session_state_delegate->LockScreen();
   }
 }
 
-void TabletPowerButtonController::OnLockScreenTimeout() {
-  WmShell::Get()->GetSessionStateDelegate()->LockScreen();
-}
-
 }  // namespace ash
diff --git a/ash/system/chromeos/power/tablet_power_button_controller.h b/ash/system/chromeos/power/tablet_power_button_controller.h
index 78cecebc..b99148e 100644
--- a/ash/system/chromeos/power/tablet_power_button_controller.h
+++ b/ash/system/chromeos/power/tablet_power_button_controller.h
@@ -42,12 +42,6 @@
     // Emulates |shutdown_timer_| timeout.
     void TriggerShutdownTimeout();
 
-    // Returns true when |lock_screen_timer_| is running.
-    bool LockScreenTimerIsRunning() const;
-
-    // Emulates |lock_screen_timer_| timeout.
-    void TriggerLockScreenTimeout();
-
    private:
     TabletPowerButtonController* controller_;  // Not owned.
 
@@ -107,9 +101,6 @@
   // and locking is possible.
   void LockScreenIfRequired();
 
-  // Called by |lock_screen_timer_| to start locking screen.
-  void OnLockScreenTimeout();
-
   // True if the brightness level is currently set to off.
   bool brightness_level_is_zero_ = false;
 
@@ -133,10 +124,6 @@
   // released. Runs OnShutdownTimeout() to start shutdown.
   base::OneShotTimer shutdown_timer_;
 
-  // Used to provide a grace period between forcing the display off and locking
-  // the screen. Runs OnLockScreenTimeout().
-  base::OneShotTimer lock_screen_timer_;
-
   LockStateController* controller_;  // Not owned.
 
   base::WeakPtrFactory<TabletPowerButtonController> weak_ptr_factory_;
diff --git a/ash/system/chromeos/power/tablet_power_button_controller_unittest.cc b/ash/system/chromeos/power/tablet_power_button_controller_unittest.cc
index ae61441..a115f49 100644
--- a/ash/system/chromeos/power/tablet_power_button_controller_unittest.cc
+++ b/ash/system/chromeos/power/tablet_power_button_controller_unittest.cc
@@ -139,15 +139,11 @@
   // automatic screen-locking was requested.
   PressPowerButton();
   ReleasePowerButton();
-  EXPECT_TRUE(test_api_->LockScreenTimerIsRunning());
-  EXPECT_FALSE(GetLockedState());
-  test_api_->TriggerLockScreenTimeout();
   EXPECT_TRUE(GetLockedState());
 
   // On locked state, power-button-press-release should do nothing.
   PressPowerButton();
   ReleasePowerButton();
-  EXPECT_FALSE(test_api_->LockScreenTimerIsRunning());
   EXPECT_TRUE(GetLockedState());
 
   // Unlock the sceen.
@@ -159,26 +155,6 @@
   SetShouldLockScreenAutomatically(false);
   PressPowerButton();
   ReleasePowerButton();
-  EXPECT_FALSE(test_api_->LockScreenTimerIsRunning());
-  EXPECT_FALSE(GetLockedState());
-}
-
-// Tests when display is on, quickly tapping power button two times, screen is
-// not locked.
-TEST_F(TabletPowerButtonControllerTest, LockScreenGracePeriodTest) {
-  Initialize(LoginStatus::USER);
-  SetShouldLockScreenAutomatically(true);
-  EXPECT_FALSE(GetLockedState());
-
-  PressPowerButton();
-  ReleasePowerButton();
-  power_manager_client_->SendBrightnessChanged(0, false);
-  EXPECT_TRUE(test_api_->LockScreenTimerIsRunning());
-  PressPowerButton();
-  power_manager_client_->SendBrightnessChanged(kNonZeroBrightness, false);
-  EXPECT_FALSE(test_api_->LockScreenTimerIsRunning());
-  ReleasePowerButton();
-  EXPECT_FALSE(test_api_->LockScreenTimerIsRunning());
   EXPECT_FALSE(GetLockedState());
 }
 
diff --git a/build/android/gradle/android.jinja b/build/android/gradle/android.jinja
index 5dba39da..b4b9340 100644
--- a/build/android/gradle/android.jinja
+++ b/build/android/gradle/android.jinja
@@ -1,6 +1,23 @@
 {# 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. #}
+{% macro expand_sourceset(variables, prefix) %}
+{% if variables is defined %}
+        {{ prefix }} {
+            manifest.srcFile "{{ variables.android_manifest }}"
+            java.srcDirs = [
+{% for path in variables.java_dirs %}
+                "{{ path }}",
+{% endfor %}
+            ]
+            jniLibs.srcDirs = [
+{% for path in variables.jni_libs %}
+                "{{ path }}",
+{% endfor %}
+            ]
+        }
+{% endif %}
+{% endmacro %}
 // Generated by //build/android/generate_gradle.py
 
 {% if template_type in ('android_library', 'android_junit') %}
@@ -32,20 +49,9 @@
         }
 {% endfor %}
 
-        main.manifest.srcFile "{{ android_manifest }}"
-
-        {{ sourceSetName }} {
-            java.srcDirs = [
-{% for path in java_dirs %}
-                "{{ path }}",
-{% endfor %}
-            ]
-            jniLibs.srcDirs = [
-{% for path in jni_libs %}
-                "{{ path }}",
-{% endfor %}
-            ]
-        }
+{{ expand_sourceset(main, 'main') }}
+{{ expand_sourceset(test, 'test') }}
+{{ expand_sourceset(android_test, 'androidTest') }}
     }
 }
 
diff --git a/build/android/gradle/dependencies.jinja b/build/android/gradle/dependencies.jinja
index 7cc91eb..c7e884a8b 100644
--- a/build/android/gradle/dependencies.jinja
+++ b/build/android/gradle/dependencies.jinja
@@ -1,14 +1,22 @@
 {# 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. #}
+{% macro expand_deps(variables, prefix) %}
+{% if variables is defined %}
+{% for path in variables.prebuilts %}
+    {{ prefix }} files("{{ path }}")
+{% endfor %}
+{% for proj in variables.java_project_deps %}
+    {{ prefix }} project(":{{ proj }}")
+{% endfor %}
+{% for proj in variables.android_project_deps %}
+    {{ prefix }} project(path: ":{{ proj }}", configuration: "debug")
+{% endfor %}
+{% endif %}
+{% endmacro %}
+
 dependencies {
-{% for path in prebuilts %}
-    {{ depCompileName }} files("{{ path }}")
-{% endfor %}
-{% for proj in java_project_deps %}
-    {{ depCompileName }} project(":{{ proj }}")
-{% endfor %}
-{% for proj in android_project_deps %}
-    {{ depCompileName }} project(path: ":{{ proj }}", configuration: "debug")
-{% endfor %}
+{{ expand_deps(main, 'compile') }}
+{{ expand_deps(test, 'testCompile') }}
+{{ expand_deps(android_test, 'androidTestCompile') }}
 }
diff --git a/build/android/gradle/generate_gradle.py b/build/android/gradle/generate_gradle.py
index 3c08114..2686500 100755
--- a/build/android/gradle/generate_gradle.py
+++ b/build/android/gradle/generate_gradle.py
@@ -115,13 +115,15 @@
 
 
 class _ProjectEntry(object):
-  """Helper class for various path transformations."""
+  """Helper class for project entries."""
   def __init__(self, gn_target):
     assert gn_target.startswith('//'), gn_target
     if ':' not in gn_target:
       gn_target = '%s:%s' % (gn_target, os.path.basename(gn_target))
     self._gn_target = gn_target
     self._build_config = None
+    self._java_files = None
+    self.android_test_entry = None
 
   @classmethod
   def FromBuildConfigPath(cls, path):
@@ -164,9 +166,91 @@
       self._build_config = build_utils.ReadJson(_RebasePath(path))
     return self._build_config
 
+  def DepsInfo(self):
+    return self.BuildConfig()['deps_info']
+
+  def Gradle(self):
+    return self.BuildConfig()['gradle']
+
   def GetType(self):
     """Returns the target type from its .build_config."""
-    return self.BuildConfig()['deps_info']['type']
+    return self.DepsInfo()['type']
+
+  def JavaFiles(self):
+    if self._java_files is None:
+      java_sources_file = self.Gradle().get('java_sources_file')
+      java_files = []
+      if java_sources_file:
+        java_sources_file = _RebasePath(java_sources_file)
+        java_files = build_utils.ReadSourcesList(java_sources_file)
+      self._java_files = java_files
+    return self._java_files
+
+
+class _ProjectContextGenerator(object):
+  """Helper class to generate gradle build files"""
+  def __init__(self, project_dir, use_gradle_process_resources):
+    self.project_dir = project_dir
+    self.use_gradle_process_resources = use_gradle_process_resources
+
+  def _GenJniLibs(self, entry):
+    native_section = entry.BuildConfig().get('native')
+    if native_section:
+      jni_libs = _CreateJniLibsDir(
+          constants.GetOutDirectory(), self.EntryOutputDir(entry),
+          native_section.get('libraries'))
+    else:
+      jni_libs = []
+    return jni_libs
+
+  def _GenJavaDirs(self, entry):
+    java_dirs = _CreateJavaSourceDir(
+        constants.GetOutDirectory(), self.EntryOutputDir(entry),
+        entry.JavaFiles())
+    if self.Srcjars(entry):
+      java_dirs.append(
+          os.path.join(self.EntryOutputDir(entry), _SRCJARS_SUBDIR))
+    return java_dirs
+
+  def _Relativize(self, entry, paths):
+    return _RebasePath(paths, self.EntryOutputDir(entry))
+
+  def EntryOutputDir(self, entry):
+    return os.path.join(self.project_dir, entry.GradleSubdir())
+
+  def Srcjars(self, entry):
+    srcjars = _RebasePath(entry.Gradle().get('bundled_srcjars', []))
+    if not self.use_gradle_process_resources:
+      srcjars += _RebasePath(entry.BuildConfig()['javac']['srcjars'])
+    return srcjars
+
+  def GeneratedInputs(self, entry):
+    generated_inputs = []
+    generated_inputs.extend(self.Srcjars(entry))
+    generated_inputs.extend(
+        p for p in entry.JavaFiles() if not p.startswith('..'))
+    generated_inputs.extend(entry.Gradle()['dependent_prebuilt_jars'])
+    return generated_inputs
+
+  def Generate(self, entry):
+    variables = {}
+    android_test_manifest = entry.Gradle().get(
+        'android_manifest', _DEFAULT_ANDROID_MANIFEST_PATH)
+    variables['android_manifest'] = self._Relativize(
+        entry, android_test_manifest)
+    variables['java_dirs'] = self._Relativize(entry, self._GenJavaDirs(entry))
+    variables['jni_libs'] = self._Relativize(entry, self._GenJniLibs(entry))
+    deps = [_ProjectEntry.FromBuildConfigPath(p)
+            for p in entry.Gradle()['dependent_android_projects']]
+    variables['android_project_deps'] = [d.ProjectName() for d in deps]
+    # TODO(agrieve): Add an option to use interface jars and see if that speeds
+    # things up at all.
+    variables['prebuilts'] = self._Relativize(
+        entry, entry.Gradle()['dependent_prebuilt_jars'])
+    deps = [_ProjectEntry.FromBuildConfigPath(p)
+            for p in entry.Gradle()['dependent_java_projects']]
+    variables['java_project_deps'] = [d.ProjectName() for d in deps]
+    return variables
 
 
 def _ComputeJavaSourceDirs(java_files):
@@ -278,12 +362,10 @@
       ''])
 
 
-def _GenerateGradleFile(build_config, build_vars, java_dirs, jni_libs,
-                        relativize, use_gradle_process_resources,
-                        jinja_processor):
+def _GenerateGradleFile(entry, generator, build_vars, jinja_processor):
   """Returns the data for a project's build.gradle."""
-  deps_info = build_config['deps_info']
-  gradle = build_config['gradle']
+  deps_info = entry.DepsInfo()
+  gradle = entry.Gradle()
 
   variables = {
       'sourceSetName': 'main',
@@ -294,8 +376,7 @@
   elif deps_info['type'] == 'java_library':
     if deps_info['is_prebuilt'] or deps_info['gradle_treat_as_prebuilt']:
       return None
-
-    if deps_info['requires_android']:
+    elif deps_info['requires_android']:
       target_type = 'android_library'
     else:
       target_type = 'java_library'
@@ -312,25 +393,15 @@
 
   variables['target_name'] = os.path.splitext(deps_info['name'])[0]
   variables['template_type'] = target_type
-  variables['use_gradle_process_resources'] = use_gradle_process_resources
+  variables['use_gradle_process_resources'] = (
+      generator.use_gradle_process_resources)
   variables['build_tools_version'] = (
       build_vars['android_sdk_build_tools_version'])
   variables['compile_sdk_version'] = build_vars['android_sdk_version']
-  android_manifest = gradle.get('android_manifest',
-                                _DEFAULT_ANDROID_MANIFEST_PATH)
-  variables['android_manifest'] = relativize(android_manifest)
-  variables['java_dirs'] = relativize(java_dirs)
-  variables['jni_libs'] = relativize(jni_libs)
-  # TODO(agrieve): Add an option to use interface jars and see if that speeds
-  # things up at all.
-  variables['prebuilts'] = relativize(gradle['dependent_prebuilt_jars'])
-  deps = [_ProjectEntry.FromBuildConfigPath(p)
-          for p in gradle['dependent_android_projects']]
-
-  variables['android_project_deps'] = [d.ProjectName() for d in deps]
-  deps = [_ProjectEntry.FromBuildConfigPath(p)
-          for p in gradle['dependent_java_projects']]
-  variables['java_project_deps'] = [d.ProjectName() for d in deps]
+  variables['main'] = generator.Generate(entry)
+  if entry.android_test_entry:
+    variables['android_test'] = generator.Generate(
+        entry.android_test_entry)
 
   return jinja_processor.Render(
       _TemplatePath(target_type.split('_')[0]), variables)
@@ -380,16 +451,44 @@
     if cur_entry in found:
       continue
     found.add(cur_entry)
-    build_config = cur_entry.BuildConfig()
-    sub_config_paths = build_config['deps_info']['deps_configs']
+    sub_config_paths = cur_entry.DepsInfo()['deps_configs']
     to_scan.extend(
         _ProjectEntry.FromBuildConfigPath(p) for p in sub_config_paths)
   return list(found)
 
 
+def _CombineTestEntries(entries):
+  """Combines test apks into the androidTest source set of their target.
+
+  - Speeds up android studio
+  - Adds proper dependency between test and apk_under_test
+  - Doesn't work for junit yet due to resulting circular dependencies
+    - e.g. base_junit_tests > base_junit_test_support > base_java
+  """
+  combined_entries = []
+  android_test_entries = {}
+  for entry in entries:
+    target_name = entry.GnTarget()
+    if (target_name.endswith('_test_apk__apk') and
+        'apk_under_test' in entry.Gradle()):
+      apk_name = entry.Gradle()['apk_under_test']
+      android_test_entries[apk_name] = entry
+    else:
+      combined_entries.append(entry)
+  for entry in combined_entries:
+    target_name = entry.DepsInfo()['name']
+    if target_name in android_test_entries:
+      entry.android_test_entry = android_test_entries[target_name]
+      del android_test_entries[target_name]
+  # Add unmatched test entries as individual targets.
+  combined_entries.extend(android_test_entries.values())
+  return combined_entries
+
+
 def main():
   parser = argparse.ArgumentParser()
   parser.add_argument('--output-directory',
+                      default='out/Debug',
                       help='Path to the root build directory.')
   parser.add_argument('-v',
                       '--verbose',
@@ -419,20 +518,21 @@
   devil_chromium.Initialize(output_directory=output_dir)
   run_tests_helper.SetLogLevel(args.verbose_count)
 
-  gradle_output_dir = os.path.abspath(
+  _gradle_output_dir = os.path.abspath(
       args.project_dir.replace('$CHROMIUM_OUTPUT_DIR', output_dir))
-  logging.warning('Creating project at: %s', gradle_output_dir)
+  generator = _ProjectContextGenerator(
+      _gradle_output_dir, args.use_gradle_process_resources)
+  logging.warning('Creating project at: %s', generator.project_dir)
 
   if args.all:
     # Run GN gen if necessary (faster than running "gn gen" in the no-op case).
-    _RunNinja(output_dir, ['build.ninja'])
+    _RunNinja(constants.GetOutDirectory(), ['build.ninja'])
     # Query ninja for all __build_config targets.
     targets = _QueryForAllGnTargets(output_dir)
   else:
     targets = args.targets or _DEFAULT_TARGETS
-    # TODO(agrieve): See if it makes sense to utilize Gradle's test constructs
-    # for our instrumentation tests.
     targets = [re.sub(r'_test_apk$', '_test_apk__apk', t) for t in targets]
+    # TODO(wnwen): Utilize Gradle's test constructs for our junit tests?
     targets = [re.sub(r'_junit_tests$', '_junit_tests__java_binary', t)
                for t in targets]
 
@@ -448,6 +548,8 @@
 
   all_entries = _FindAllProjectEntries(main_entries)
   logging.info('Found %d dependent build_config targets.', len(all_entries))
+  entries = _CombineTestEntries(all_entries)
+  logging.info('Creating %d projects for targets.', len(entries))
 
   logging.warning('Writing .gradle files...')
   jinja_processor = jinja_template.JinjaProcessor(_FILE_DIR)
@@ -455,57 +557,29 @@
   project_entries = []
   srcjar_tuples = []
   generated_inputs = []
-  for entry in all_entries:
+  for entry in entries:
     if entry.GetType() not in ('android_apk', 'java_library', 'java_binary'):
       continue
 
-    entry_output_dir = os.path.join(gradle_output_dir, entry.GradleSubdir())
-    relativize = lambda x, d=entry_output_dir: _RebasePath(x, d)
-    build_config = entry.BuildConfig()
-
-    srcjars = _RebasePath(build_config['gradle'].get('bundled_srcjars', []))
-    if not args.use_gradle_process_resources:
-      srcjars += _RebasePath(build_config['javac']['srcjars'])
-
-    java_sources_file = build_config['gradle'].get('java_sources_file')
-    java_files = []
-    if java_sources_file:
-      java_sources_file = _RebasePath(java_sources_file)
-      java_files = build_utils.ReadSourcesList(java_sources_file)
-
-    java_dirs = _CreateJavaSourceDir(output_dir, entry_output_dir, java_files)
-    if srcjars:
-      java_dirs.append(os.path.join(entry_output_dir, _SRCJARS_SUBDIR))
-
-    native_section = build_config.get('native')
-    if native_section:
-      jni_libs = _CreateJniLibsDir(
-          output_dir, entry_output_dir, native_section.get('libraries'))
-    else:
-      jni_libs = []
-
-    data = _GenerateGradleFile(build_config, build_vars, java_dirs, jni_libs,
-                               relativize, args.use_gradle_process_resources,
-                               jinja_processor)
+    data = _GenerateGradleFile(entry, generator, build_vars, jinja_processor)
     if data:
       project_entries.append(entry)
       # Build all paths references by .gradle that exist within output_dir.
-      generated_inputs.extend(srcjars)
-      generated_inputs.extend(p for p in java_files if not p.startswith('..'))
-      generated_inputs.extend(build_config['gradle']['dependent_prebuilt_jars'])
-
+      generated_inputs.extend(generator.GeneratedInputs(entry))
       srcjar_tuples.extend(
-          (s, os.path.join(entry_output_dir, _SRCJARS_SUBDIR)) for s in srcjars)
-      _WriteFile(os.path.join(entry_output_dir, 'build.gradle'), data)
+          (s, os.path.join(generator.EntryOutputDir(entry), _SRCJARS_SUBDIR))
+          for s in generator.Srcjars(entry))
+      _WriteFile(
+          os.path.join(generator.EntryOutputDir(entry), 'build.gradle'), data)
 
-  _WriteFile(os.path.join(gradle_output_dir, 'build.gradle'),
+  _WriteFile(os.path.join(generator.project_dir, 'build.gradle'),
              _GenerateRootGradle(jinja_processor))
 
-  _WriteFile(os.path.join(gradle_output_dir, 'settings.gradle'),
+  _WriteFile(os.path.join(generator.project_dir, 'settings.gradle'),
              _GenerateSettingsGradle(project_entries))
 
   sdk_path = _RebasePath(build_vars['android_sdk_root'])
-  _WriteFile(os.path.join(gradle_output_dir, 'local.properties'),
+  _WriteFile(os.path.join(generator.project_dir, 'local.properties'),
              _GenerateLocalProperties(sdk_path))
 
   if generated_inputs:
@@ -514,7 +588,7 @@
     _RunNinja(output_dir, targets)
 
   if srcjar_tuples:
-    _ExtractSrcjars(gradle_output_dir, srcjar_tuples)
+    _ExtractSrcjars(generator.project_dir, srcjar_tuples)
 
   logging.warning('Project created! (%d subprojects)', len(project_entries))
   logging.warning('Generated projects work best with Android Studio 2.2')
diff --git a/build/android/gradle/java.jinja b/build/android/gradle/java.jinja
index ef3591c7..848b45e 100644
--- a/build/android/gradle/java.jinja
+++ b/build/android/gradle/java.jinja
@@ -11,7 +11,7 @@
 sourceSets {
     main {
         java.srcDirs = [
-{% for path in java_dirs %}
+{% for path in main.java_dirs %}
             "{{ path }}",
 {% endfor %}
         ]
diff --git a/build/android/gyp/write_build_config.py b/build/android/gyp/write_build_config.py
index 98d1d7d..d636f31d 100755
--- a/build/android/gyp/write_build_config.py
+++ b/build/android/gyp/write_build_config.py
@@ -380,12 +380,6 @@
   # overrides are done correctly.
   all_resources_deps.reverse()
 
-  if options.type == 'android_apk' and options.tested_apk_config:
-    tested_apk_deps = Deps([options.tested_apk_config])
-    tested_apk_resources_deps = tested_apk_deps.All('android_resources')
-    all_resources_deps = [
-        d for d in all_resources_deps if not d in tested_apk_resources_deps]
-
   # Initialize some common config.
   # Any value that needs to be queryable by dependents must go within deps_info.
   config = {
@@ -401,6 +395,14 @@
   deps_info = config['deps_info']
   gradle = config['gradle']
 
+  if options.type == 'android_apk' and options.tested_apk_config:
+    tested_apk_deps = Deps([options.tested_apk_config])
+    tested_apk_name = tested_apk_deps.Direct()[0]['name']
+    tested_apk_resources_deps = tested_apk_deps.All('android_resources')
+    gradle['apk_under_test'] = tested_apk_name
+    all_resources_deps = [
+        d for d in all_resources_deps if not d in tested_apk_resources_deps]
+
   # Required for generating gradle files.
   if options.type == 'java_library':
     deps_info['is_prebuilt'] = is_java_prebuilt
diff --git a/build/clobber.py b/build/clobber.py
index 1229f7b..b6c69982 100755
--- a/build/clobber.py
+++ b/build/clobber.py
@@ -37,6 +37,8 @@
 
 
 def delete_dir(build_dir):
+  if os.path.islink(build_dir):
+    return
   # For unknown reasons (anti-virus?) rmtree of Chromium build directories
   # often fails on Windows.
   if sys.platform.startswith('win'):
diff --git a/build/sanitizers/sanitizer_options.cc b/build/sanitizers/sanitizer_options.cc
index 39fa140..81958f2 100644
--- a/build/sanitizers/sanitizer_options.cc
+++ b/build/sanitizers/sanitizer_options.cc
@@ -101,7 +101,7 @@
   return kAsanDefaultOptions;
 }
 
-extern "C" char kASanDefaultSuppressions[];
+extern char kASanDefaultSuppressions[];
 
 SANITIZER_HOOK_ATTRIBUTE const char *__asan_default_suppressions() {
   return kASanDefaultSuppressions;
@@ -131,7 +131,7 @@
   return kTsanDefaultOptions;
 }
 
-extern "C" char kTSanDefaultSuppressions[];
+extern char kTSanDefaultSuppressions[];
 
 SANITIZER_HOOK_ATTRIBUTE const char *__tsan_default_suppressions() {
   return kTSanDefaultSuppressions;
@@ -166,7 +166,7 @@
   return kLsanDefaultOptions;
 }
 
-extern "C" char kLSanDefaultSuppressions[];
+extern char kLSanDefaultSuppressions[];
 
 SANITIZER_HOOK_ATTRIBUTE const char *__lsan_default_suppressions() {
   return kLSanDefaultSuppressions;
diff --git a/cc/BUILD.gn b/cc/BUILD.gn
index d16ec63..e2988e1 100644
--- a/cc/BUILD.gn
+++ b/cc/BUILD.gn
@@ -939,7 +939,7 @@
     "surfaces/direct_compositor_frame_sink_unittest.cc",
     "surfaces/display_scheduler_unittest.cc",
     "surfaces/display_unittest.cc",
-    "surfaces/embedded_surface_tracker_unittest.cc",
+    "surfaces/referenced_surface_tracker_unittest.cc",
     "surfaces/surface_aggregator_unittest.cc",
     "surfaces/surface_factory_unittest.cc",
     "surfaces/surface_hittest_unittest.cc",
diff --git a/cc/ipc/display_compositor.mojom b/cc/ipc/display_compositor.mojom
index 1b405f8..0cc76bf 100644
--- a/cc/ipc/display_compositor.mojom
+++ b/cc/ipc/display_compositor.mojom
@@ -61,11 +61,6 @@
 // compositor. The display compositor host is either the browser process in
 // Chrome or the window server process.
 interface DisplayCompositorClient {
-  // Called by the display compostor when it is created. Provides the top level
-  // root surface id that should reference display roots. This will always be
-  // the first message sent.
-  OnDisplayCompositorCreated(cc.mojom.SurfaceId root_surface_id);
-
   // Called by the display compositor immediately upon receiving a
   // CompositorFrame with a new SurfaceId for the first time.
   OnSurfaceCreated(SurfaceInfo surface_info);
diff --git a/cc/ipc/mojo_compositor_frame_sink.mojom b/cc/ipc/mojo_compositor_frame_sink.mojom
index 87ddd3a..6bbb9732 100644
--- a/cc/ipc/mojo_compositor_frame_sink.mojom
+++ b/cc/ipc/mojo_compositor_frame_sink.mojom
@@ -33,12 +33,6 @@
   SubmitCompositorFrame(cc.mojom.LocalFrameId local_frame_id,
                         cc.mojom.CompositorFrame frame);
 
-  // Adds surface references.
-  AddSurfaceReferences(array<SurfaceReference> references);
-
-  // Removes surface references.
-  RemoveSurfaceReferences(array<SurfaceReference> references);
-
   // Notify that the surface is no longer in use (and is okay to be evicted) so
   // that its resources gets returned in time.
   EvictFrame();
diff --git a/cc/surfaces/BUILD.gn b/cc/surfaces/BUILD.gn
index 63b5414..e83d5817 100644
--- a/cc/surfaces/BUILD.gn
+++ b/cc/surfaces/BUILD.gn
@@ -44,8 +44,8 @@
     "display_client.h",
     "display_scheduler.cc",
     "display_scheduler.h",
-    "embedded_surface_tracker.cc",
-    "embedded_surface_tracker.h",
+    "referenced_surface_tracker.cc",
+    "referenced_surface_tracker.h",
     "sequence_surface_reference_factory.cc",
     "sequence_surface_reference_factory.h",
     "surface.cc",
diff --git a/cc/surfaces/embedded_surface_tracker.cc b/cc/surfaces/embedded_surface_tracker.cc
deleted file mode 100644
index 4541382..0000000
--- a/cc/surfaces/embedded_surface_tracker.cc
+++ /dev/null
@@ -1,95 +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 "cc/surfaces/embedded_surface_tracker.h"
-
-#include <utility>
-
-#include "base/logging.h"
-
-namespace cc {
-
-EmbeddedSurfaceTracker::EmbeddedSurfaceTracker() {}
-
-EmbeddedSurfaceTracker::~EmbeddedSurfaceTracker() {}
-
-void EmbeddedSurfaceTracker::SetCurrentSurfaceId(const SurfaceId& surface_id) {
-  DCHECK(surface_id.is_valid());
-  DCHECK_NE(current_surface_id_, surface_id);
-
-  // The last submitted CompositorFrame for |current_surface_id_| still embeds
-  // the surfaces in |references_to_remove_| and hasn't embedded the surfaces in
-  // |references_to_add_| yet.
-  references_to_remove_.clear();
-  references_to_add_.clear();
-
-  current_surface_id_ = surface_id;
-
-  // Add references from updated |current_surface_id_| to all embedded surfaces.
-  for (auto& map_entry : embedded_surfaces_)
-    AddReference(current_surface_id_, map_entry.second);
-}
-
-bool EmbeddedSurfaceTracker::EmbedSurface(const SurfaceId& embedded_id) {
-  auto iter = embedded_surfaces_.find(embedded_id.frame_sink_id());
-
-  // This is the first surface for the FrameSinkId.
-  if (iter == embedded_surfaces_.end()) {
-    if (HasValidSurfaceId())
-      AddReference(current_surface_id_, embedded_id);
-
-    // Add record that surface is embedded.
-    embedded_surfaces_[embedded_id.frame_sink_id()] = embedded_id;
-    return true;
-  }
-
-  // This is not the first surface for the FrameSinkId, we are unembedding the
-  // old surface and embedding the new surface.
-  SurfaceId& stored_surface_id = iter->second;
-  DCHECK_NE(stored_surface_id, embedded_id);
-
-  if (HasValidSurfaceId()) {
-    RemoveReference(current_surface_id_, stored_surface_id);
-    AddReference(current_surface_id_, embedded_id);
-  }
-
-  stored_surface_id = embedded_id;
-  return false;
-}
-
-void EmbeddedSurfaceTracker::UnembedSurface(const FrameSinkId& frame_sink_id) {
-  auto iter = embedded_surfaces_.find(frame_sink_id);
-  if (iter == embedded_surfaces_.end())
-    return;
-
-  if (HasValidSurfaceId())
-    RemoveReference(current_surface_id_, iter->second);
-
-  // Remove record that surface is embedded.
-  embedded_surfaces_.erase(iter);
-}
-
-std::vector<SurfaceReference> EmbeddedSurfaceTracker::GetReferencesToAdd() {
-  std::vector<SurfaceReference> references;
-  std::swap(references, references_to_add_);
-  return references;
-}
-
-std::vector<SurfaceReference> EmbeddedSurfaceTracker::GetReferencesToRemove() {
-  std::vector<SurfaceReference> references;
-  std::swap(references, references_to_remove_);
-  return references;
-}
-
-void EmbeddedSurfaceTracker::AddReference(const SurfaceId& parent_id,
-                                          const SurfaceId& child_id) {
-  references_to_add_.push_back(SurfaceReference(parent_id, child_id));
-}
-
-void EmbeddedSurfaceTracker::RemoveReference(const SurfaceId& parent_id,
-                                             const SurfaceId& child_id) {
-  references_to_remove_.push_back(SurfaceReference(parent_id, child_id));
-}
-
-}  // namespace cc
diff --git a/cc/surfaces/embedded_surface_tracker.h b/cc/surfaces/embedded_surface_tracker.h
deleted file mode 100644
index 858d04c..0000000
--- a/cc/surfaces/embedded_surface_tracker.h
+++ /dev/null
@@ -1,97 +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 CC_SURFACES_EMBEDDED_SURFACE_TRACKER_H_
-#define CC_SURFACES_EMBEDDED_SURFACE_TRACKER_H_
-
-#include <unordered_map>
-#include <vector>
-
-#include "base/macros.h"
-#include "cc/surfaces/frame_sink_id.h"
-#include "cc/surfaces/surface_id.h"
-#include "cc/surfaces/surface_reference.h"
-#include "cc/surfaces/surfaces_export.h"
-
-namespace cc {
-
-namespace test {
-class EmbeddedSurfaceTrackerTest;
-}
-
-// Tracks surface references from a client surface to embedded surfaces. Handles
-// updating the references when the client surface resizes.
-class CC_SURFACES_EXPORT EmbeddedSurfaceTracker {
- public:
-  EmbeddedSurfaceTracker();
-  ~EmbeddedSurfaceTracker();
-
-  const SurfaceId& current_surface_id() const { return current_surface_id_; }
-
-  // Checks if the client has a valid SurfaceId. This will become true after
-  // SetCurrentSurfaceId() is called for the first time. No references will be
-  // added or removed until this is true.
-  bool HasValidSurfaceId() const { return current_surface_id_.is_valid(); }
-
-  // Sets |current_surface_id_| when the client switches surfaces. Clears all
-  // references waiting to be added or removed, since no CompositorFrame will be
-  // submitted for the previous surface now. Generates new references from the
-  // new surface to all embedded surfaces. Does not send IPC.
-  void SetCurrentSurfaceId(const SurfaceId& surface_id);
-
-  // Adds a reference from |current_surface_id_| to |embedded_id| and records
-  // |embedded_id|. If an existing surface with the same FrameSinkId is embedded
-  // removes the reference to it. Does not send IPC. Returns true for the first
-  // surface from a FrameSinkId and false for all subsequent surfaces.
-  bool EmbedSurface(const SurfaceId& embedded_id);
-
-  // Removes reference from |current_surface_id_| to latest embedded surface for
-  // |frame_sink_id|. Does not send IPC.
-  void UnembedSurface(const FrameSinkId& frame_sink_id);
-
-  // Returns |references_to_add_| and clears contents. It's expected this will
-  // be called immediately before submitting a CompositorFrame and caller will
-  // add references via IPC.
-  std::vector<SurfaceReference> GetReferencesToAdd();
-  bool HasReferencesToAdd() const { return !references_to_add_.empty(); }
-
-  // Returns |references_to_remove_| and clears contents. It's expected this
-  // will be called immediately after submitting a CompositorFrame and caller
-  // will remove references via IPC.
-  std::vector<SurfaceReference> GetReferencesToRemove();
-  bool HasReferencesToRemove() const { return !references_to_remove_.empty(); }
-
- private:
-  friend class test::EmbeddedSurfaceTrackerTest;
-
-  // Records adding a reference from |parent_id| to |child_id|. References are
-  // not actually added until SendAddSurfaceReferences() is called.
-  void AddReference(const SurfaceId& parent_id, const SurfaceId& child_id);
-
-  // Records removing a reference from |parent_id| to |child_id|. References
-  // are not actually removed until SendRemoveSurfaceReferences() is called.
-  void RemoveReference(const SurfaceId& parent_id, const SurfaceId& child_id);
-
-  // The id of the client surface that is embedding other surfaces.
-  SurfaceId current_surface_id_;
-
-  // Surfaces that are embedded by the client surface. A reference from
-  // |current_surface_id_| will be added if it's valid.
-  std::unordered_map<FrameSinkId, SurfaceId, FrameSinkIdHash>
-      embedded_surfaces_;
-
-  // References to surfaces that should be removed after the next
-  // CompositorFrame has been submitted and the surfaces are no longer embedded.
-  std::vector<SurfaceReference> references_to_remove_;
-
-  // References that should be added before the next CompositorFrame is
-  // submitted.
-  std::vector<SurfaceReference> references_to_add_;
-
-  DISALLOW_COPY_AND_ASSIGN(EmbeddedSurfaceTracker);
-};
-
-}  // namespace cc
-
-#endif  // CC_SURFACES_EMBEDDED_SURFACE_TRACKER_H_
diff --git a/cc/surfaces/embedded_surface_tracker_unittest.cc b/cc/surfaces/embedded_surface_tracker_unittest.cc
deleted file mode 100644
index a1566cc..0000000
--- a/cc/surfaces/embedded_surface_tracker_unittest.cc
+++ /dev/null
@@ -1,192 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "cc/surfaces/embedded_surface_tracker.h"
-
-#include <memory>
-
-#include "base/logging.h"
-#include "base/macros.h"
-#include "base/memory/ptr_util.h"
-#include "cc/surfaces/frame_sink_id.h"
-#include "cc/surfaces/surface_id.h"
-#include "cc/surfaces/surface_reference.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-using testing::ElementsAre;
-using testing::IsEmpty;
-using testing::SizeIs;
-
-namespace cc {
-namespace test {
-namespace {
-
-constexpr FrameSinkId kParentFrameSink(2, 1);
-constexpr FrameSinkId kEmbeddedFrameSink(65563, 1);
-
-SurfaceId MakeSurfaceId(const FrameSinkId& frame_sink_id, uint32_t local_id) {
-  return SurfaceId(
-      frame_sink_id,
-      LocalFrameId(local_id, base::UnguessableToken::Deserialize(0, 1u)));
-}
-
-}  // namespace
-
-class EmbeddedSurfaceTrackerTest : public testing::Test {
- public:
-  EmbeddedSurfaceTrackerTest() {}
-  ~EmbeddedSurfaceTrackerTest() override {}
-
-  EmbeddedSurfaceTracker& tracker() { return *tracker_; }
-
-  // Returns references to add without clearing them.
-  const std::vector<SurfaceReference>& peek_to_add() {
-    return tracker_->references_to_add_;
-  }
-
-  // Returns references to remove without clearing them.
-  const std::vector<SurfaceReference>& peek_to_remove() {
-    return tracker_->references_to_remove_;
-  }
-
-  // testing::Test:
-  void SetUp() override {
-    testing::Test::SetUp();
-    tracker_ = base::MakeUnique<EmbeddedSurfaceTracker>();
-  }
-
-  void TearDown() override { tracker_.reset(); }
-
- private:
-  std::unique_ptr<EmbeddedSurfaceTracker> tracker_;
-
-  DISALLOW_COPY_AND_ASSIGN(EmbeddedSurfaceTrackerTest);
-};
-
-TEST_F(EmbeddedSurfaceTrackerTest, SetCurrentSurfaceId) {
-  const SurfaceId parent_id = MakeSurfaceId(kParentFrameSink, 1);
-
-  // Initially HasValidSurfaceId() should be false.
-  EXPECT_FALSE(tracker().HasValidSurfaceId());
-
-  // After setting current SurfaceId then HasValidSurfaceId() should be true.
-  tracker().SetCurrentSurfaceId(parent_id);
-  EXPECT_TRUE(tracker().HasValidSurfaceId());
-  EXPECT_EQ(parent_id, tracker().current_surface_id());
-}
-
-TEST_F(EmbeddedSurfaceTrackerTest, EmbedSurface) {
-  const SurfaceId parent_id = MakeSurfaceId(kParentFrameSink, 1);
-  const SurfaceId embedded_id = MakeSurfaceId(kEmbeddedFrameSink, 1);
-  const SurfaceReference reference(parent_id, embedded_id);
-
-  // Set parent surface id then embed another surface. The tracker should have a
-  // reference to add from parent surface to embedded surface.
-  tracker().SetCurrentSurfaceId(parent_id);
-  EXPECT_TRUE(tracker().EmbedSurface(embedded_id));
-  EXPECT_THAT(peek_to_add(), ElementsAre(reference));
-
-  // Getting the references to add should return the correct reference and empty
-  // the reference the add.
-  EXPECT_THAT(tracker().GetReferencesToAdd(), ElementsAre(reference));
-  EXPECT_THAT(peek_to_add(), IsEmpty());
-}
-
-TEST_F(EmbeddedSurfaceTrackerTest, EmbedNewSurfaceForFrameSink) {
-  const SurfaceId parent_id = MakeSurfaceId(kParentFrameSink, 1);
-  const SurfaceId embedded_id_first = MakeSurfaceId(kEmbeddedFrameSink, 1);
-  const SurfaceId embedded_id_second = MakeSurfaceId(kEmbeddedFrameSink, 2);
-  const SurfaceReference reference_first(parent_id, embedded_id_first);
-  const SurfaceReference reference_second(parent_id, embedded_id_second);
-
-  // Embed a surface and add references.
-  tracker().SetCurrentSurfaceId(parent_id);
-  EXPECT_TRUE(tracker().EmbedSurface(embedded_id_first));
-  EXPECT_THAT(tracker().GetReferencesToAdd(), ElementsAre(reference_first));
-
-  // Embed a newer surface with the same FrameSinkId as the first embedded
-  // surface. The first reference should be in the list to remove and the new
-  // reference in the last to add.
-  EXPECT_FALSE(tracker().EmbedSurface(embedded_id_second));
-  EXPECT_THAT(peek_to_remove(), ElementsAre(reference_first));
-  EXPECT_THAT(peek_to_add(), ElementsAre(reference_second));
-}
-
-TEST_F(EmbeddedSurfaceTrackerTest, UnembedSurface) {
-  const SurfaceId parent_id = MakeSurfaceId(kParentFrameSink, 1);
-  const SurfaceId embedded_id = MakeSurfaceId(kEmbeddedFrameSink, 1);
-  const SurfaceReference reference(parent_id, embedded_id);
-
-  tracker().SetCurrentSurfaceId(parent_id);
-  tracker().EmbedSurface(embedded_id);
-  EXPECT_THAT(tracker().GetReferencesToAdd(), ElementsAre(reference));
-  EXPECT_THAT(peek_to_remove(), IsEmpty());
-
-  // Unembed the surface. The reference should be in the list to remove.
-  tracker().UnembedSurface(embedded_id.frame_sink_id());
-  EXPECT_THAT(peek_to_remove(), ElementsAre(reference));
-
-  // Getting the references to remove should return the correct reference and
-  // empty the reference the remove.
-  EXPECT_THAT(tracker().GetReferencesToRemove(), ElementsAre(reference));
-  EXPECT_THAT(peek_to_remove(), IsEmpty());
-}
-
-TEST_F(EmbeddedSurfaceTrackerTest, EmbedSurfaceBeforeSetCurrentSurfaceId) {
-  const SurfaceId parent_id = MakeSurfaceId(kParentFrameSink, 1);
-  const SurfaceId embedded_id = MakeSurfaceId(kEmbeddedFrameSink, 1);
-  const SurfaceReference reference(parent_id, embedded_id);
-
-  // Embed a surface before the parent id is set. There should be no references
-  // to add because we don't know the parent id yet.
-  tracker().EmbedSurface(embedded_id);
-  EXPECT_THAT(peek_to_add(), IsEmpty());
-
-  // Set the parent id, this should add a reference to add to the embedded
-  // surface.
-  tracker().SetCurrentSurfaceId(parent_id);
-  EXPECT_THAT(peek_to_add(), ElementsAre(reference));
-}
-
-TEST_F(EmbeddedSurfaceTrackerTest, UpdateCurrentSurfaceId) {
-  const SurfaceId parent_id_first = MakeSurfaceId(kParentFrameSink, 1);
-  const SurfaceId parent_id_second = MakeSurfaceId(kParentFrameSink, 2);
-  const SurfaceId embedded_id = MakeSurfaceId(kEmbeddedFrameSink, 1);
-  const SurfaceReference reference(parent_id_second, embedded_id);
-
-  // Set parent id and embed a surface.
-  tracker().SetCurrentSurfaceId(parent_id_first);
-  tracker().EmbedSurface(embedded_id);
-  EXPECT_THAT(tracker().GetReferencesToAdd(), SizeIs(1));
-
-  // Update the current parent id. There should be a reference to add from the
-  // new parent id to the embedded surface.
-  tracker().SetCurrentSurfaceId(parent_id_second);
-  EXPECT_THAT(peek_to_add(), ElementsAre(reference));
-}
-
-TEST_F(EmbeddedSurfaceTrackerTest, UpdateCurrentSurfaceIdBeforeAdding) {
-  const SurfaceId parent_id_first = MakeSurfaceId(kParentFrameSink, 1);
-  const SurfaceId parent_id_second = MakeSurfaceId(kParentFrameSink, 2);
-  const SurfaceId embedded_id = MakeSurfaceId(kEmbeddedFrameSink, 1);
-  const SurfaceReference reference_first(parent_id_first, embedded_id);
-  const SurfaceReference reference_second(parent_id_second, embedded_id);
-
-  // Set parent id and embed a surface. There should be a reference to add from
-  // the parent to embedded surface.
-  tracker().SetCurrentSurfaceId(parent_id_first);
-  tracker().EmbedSurface(embedded_id);
-  EXPECT_THAT(peek_to_add(), ElementsAre(reference_first));
-
-  // Update the parent id before sending IPC to add references. There should be
-  // a reference to add from the new parent id to the embedded surface and the
-  // previous reference to add was deleted.
-  tracker().SetCurrentSurfaceId(parent_id_second);
-  EXPECT_THAT(peek_to_add(), ElementsAre(reference_second));
-  EXPECT_THAT(tracker().GetReferencesToAdd(), ElementsAre(reference_second));
-}
-
-}  // namespace test
-}  // namespace cc
diff --git a/cc/surfaces/referenced_surface_tracker.cc b/cc/surfaces/referenced_surface_tracker.cc
new file mode 100644
index 0000000..b2ffd54
--- /dev/null
+++ b/cc/surfaces/referenced_surface_tracker.cc
@@ -0,0 +1,80 @@
+// 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 "cc/surfaces/referenced_surface_tracker.h"
+
+#include <utility>
+
+#include "base/logging.h"
+
+namespace cc {
+
+ReferencedSurfaceTracker::ReferencedSurfaceTracker(
+    const FrameSinkId& frame_sink_id)
+    : current_surface_id_(frame_sink_id, LocalFrameId()) {
+  DCHECK(current_surface_id_.frame_sink_id().is_valid());
+}
+
+ReferencedSurfaceTracker::~ReferencedSurfaceTracker() {}
+
+void ReferencedSurfaceTracker::UpdateReferences(
+    const LocalFrameId& local_frame_id,
+    const std::vector<SurfaceId>& referenced_surfaces) {
+  DCHECK(local_frame_id.is_valid());
+
+  // Clear references to add/remove from the last frame.
+  references_to_remove_.clear();
+  references_to_add_.clear();
+
+  // If |current_surface_id_| is changing then update |current_surface_id_|.
+  // Also clear |referenced_surfaces_| because we haven't added any references
+  // from the new SurfaceId yet.
+  if (current_surface_id_.local_frame_id() != local_frame_id) {
+    current_surface_id_ =
+        SurfaceId(current_surface_id_.frame_sink_id(), local_frame_id);
+    referenced_surfaces_.clear();
+  }
+
+  std::unordered_set<SurfaceId, SurfaceIdHash> referenced_surface_set(
+      referenced_surfaces.begin(), referenced_surfaces.end());
+  ProcessNewReferences(referenced_surface_set);
+}
+
+void ReferencedSurfaceTracker::ProcessNewReferences(
+    const std::unordered_set<SurfaceId, SurfaceIdHash>&
+        new_referenced_surfaces) {
+  // Removed references for each SurfaceId in |referenced_surfaces_| if they
+  // aren't referenced anymore. Removing from a set invalidates iterators, so
+  // create a new vector then remove everything in it.
+  std::vector<SurfaceId> not_referenced;
+  for (const SurfaceId& surface_id : referenced_surfaces_) {
+    if (new_referenced_surfaces.count(surface_id) == 0)
+      not_referenced.push_back(surface_id);
+  }
+  for (const SurfaceId& surface_id : not_referenced)
+    RemoveSurfaceReference(surface_id);
+
+  // Add references for each SurfaceId in |new_referenced_surfaces| if they
+  // aren't already referenced.
+  for (const SurfaceId& surface_id : new_referenced_surfaces) {
+    if (referenced_surfaces_.count(surface_id) == 0)
+      AddSurfaceReference(surface_id);
+  }
+}
+
+void ReferencedSurfaceTracker::AddSurfaceReference(
+    const SurfaceId& surface_id) {
+  references_to_add_.push_back(
+      SurfaceReference(current_surface_id_, surface_id));
+  referenced_surfaces_.insert(surface_id);
+}
+
+void ReferencedSurfaceTracker::RemoveSurfaceReference(
+    const SurfaceId& surface_id) {
+  references_to_remove_.push_back(
+      SurfaceReference(current_surface_id_, surface_id));
+  referenced_surfaces_.erase(surface_id);
+}
+
+}  // namespace cc
diff --git a/cc/surfaces/referenced_surface_tracker.h b/cc/surfaces/referenced_surface_tracker.h
new file mode 100644
index 0000000..19e17f3
--- /dev/null
+++ b/cc/surfaces/referenced_surface_tracker.h
@@ -0,0 +1,78 @@
+// 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 CC_SURFACES_REFERENCED_SURFACE_TRACKER_H_
+#define CC_SURFACES_REFERENCED_SURFACE_TRACKER_H_
+
+#include <unordered_set>
+#include <vector>
+
+#include "base/macros.h"
+#include "cc/surfaces/frame_sink_id.h"
+#include "cc/surfaces/surface_id.h"
+#include "cc/surfaces/surface_reference.h"
+#include "cc/surfaces/surfaces_export.h"
+
+namespace cc {
+
+// Tracks surface references for a client surface. UpdateReferences() should be
+// called once per CompositorFrame to populate |references_to_add_| and
+// |references_to_remove_|.
+class CC_SURFACES_EXPORT ReferencedSurfaceTracker {
+ public:
+  explicit ReferencedSurfaceTracker(const FrameSinkId& frame_sink_id);
+  ~ReferencedSurfaceTracker();
+
+  const SurfaceId& current_surface_id() const { return current_surface_id_; }
+
+  std::vector<SurfaceReference>& references_to_add() {
+    return references_to_add_;
+  }
+
+  std::vector<SurfaceReference>& references_to_remove() {
+    return references_to_remove_;
+  }
+
+  // Update the references for a CompositorFrame. If |local_frame_id| has
+  // changed then new references will be generated for everything in
+  // |referenced_surfaces|. Otherwise a diff from the referenced surfaces in the
+  // last frame will be computed. This should be called once per
+  // CompositorFrame.
+  void UpdateReferences(const LocalFrameId& local_frame_id,
+                        const std::vector<SurfaceId>& referenced_surfaces);
+
+ private:
+  // Updates |referenced_surfaces_| based on a |new_referenced_surfaces| from a
+  // CompositorFrame. Populates |references_to_add_| and |references_to_remove_|
+  // based on the difference between the sets.
+  void ProcessNewReferences(const std::unordered_set<SurfaceId, SurfaceIdHash>&
+                                new_referenced_surfaces);
+
+  // Adds reference from |current_surface_id_| to |surface_id|.
+  void AddSurfaceReference(const SurfaceId& surface_id);
+
+  // Removes reference from |current_surface_id_| to |surface_id|.
+  void RemoveSurfaceReference(const SurfaceId& surface_id);
+
+  // The id of the client surface that is embedding other surfaces.
+  SurfaceId current_surface_id_;
+
+  // TODO(samans): Use the same SurfaceId set that SurfaceManager holds.
+  // Set of surfaces referenced by the last submitted CompositorFrame.
+  std::unordered_set<SurfaceId, SurfaceIdHash> referenced_surfaces_;
+
+  // References to surfaces that should be added for the next CompositorFrame.
+  std::vector<SurfaceReference> references_to_add_;
+
+  // References to surfaces that should be removed after the next
+  // CompositorFrame has been submitted and the surfaces are no longer needed by
+  // |current_surface_id_|.
+  std::vector<SurfaceReference> references_to_remove_;
+
+  DISALLOW_COPY_AND_ASSIGN(ReferencedSurfaceTracker);
+};
+
+}  // namespace cc
+
+#endif  // CC_SURFACES_REFERENCED_SURFACE_TRACKER_H_
diff --git a/cc/surfaces/referenced_surface_tracker_unittest.cc b/cc/surfaces/referenced_surface_tracker_unittest.cc
new file mode 100644
index 0000000..119b4a5
--- /dev/null
+++ b/cc/surfaces/referenced_surface_tracker_unittest.cc
@@ -0,0 +1,179 @@
+// 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/surfaces/referenced_surface_tracker.h"
+
+#include <memory>
+
+#include "base/logging.h"
+#include "base/macros.h"
+#include "base/memory/ptr_util.h"
+#include "cc/surfaces/frame_sink_id.h"
+#include "cc/surfaces/surface_id.h"
+#include "cc/surfaces/surface_reference.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using testing::UnorderedElementsAre;
+using testing::IsEmpty;
+using testing::SizeIs;
+
+namespace cc {
+namespace test {
+namespace {
+
+constexpr FrameSinkId kParentFrameSink(2, 1);
+constexpr FrameSinkId kChildFrameSink1(65563, 1);
+constexpr FrameSinkId kChildFrameSink2(65564, 1);
+
+std::vector<SurfaceId> empty_surface_ids() {
+  return std::vector<SurfaceId>();
+}
+
+SurfaceId MakeSurfaceId(const FrameSinkId& frame_sink_id, uint32_t local_id) {
+  return SurfaceId(
+      frame_sink_id,
+      LocalFrameId(local_id, base::UnguessableToken::Deserialize(0, 1u)));
+}
+
+}  // namespace
+
+class ReferencedSurfaceTrackerTest : public testing::Test {
+ public:
+  ReferencedSurfaceTrackerTest() {}
+  ~ReferencedSurfaceTrackerTest() override {}
+
+  ReferencedSurfaceTracker& tracker() { return *tracker_; }
+
+  // testing::Test:
+  void SetUp() override {
+    testing::Test::SetUp();
+    tracker_ = base::MakeUnique<ReferencedSurfaceTracker>(kParentFrameSink);
+  }
+
+  void TearDown() override { tracker_.reset(); }
+
+ private:
+  std::unique_ptr<ReferencedSurfaceTracker> tracker_;
+
+  DISALLOW_COPY_AND_ASSIGN(ReferencedSurfaceTrackerTest);
+};
+
+TEST_F(ReferencedSurfaceTrackerTest, SetCurrentSurfaceId) {
+  const SurfaceId parent_id = MakeSurfaceId(kParentFrameSink, 1);
+
+  // Initially current_surface_id() should be invalid.
+  EXPECT_FALSE(tracker().current_surface_id().is_valid());
+
+  // After setting current SurfaceId then current_surface_id() should be valid.
+  tracker().UpdateReferences(parent_id.local_frame_id(), empty_surface_ids());
+  EXPECT_EQ(parent_id, tracker().current_surface_id());
+}
+
+TEST_F(ReferencedSurfaceTrackerTest, RefSurface) {
+  const SurfaceId parent_id = MakeSurfaceId(kParentFrameSink, 1);
+  const SurfaceId child_id1 = MakeSurfaceId(kChildFrameSink1, 1);
+  const SurfaceReference reference(parent_id, child_id1);
+
+  // First frame has a reference to |child_id1|, check that reference is added.
+  tracker().UpdateReferences(parent_id.local_frame_id(), {child_id1});
+  EXPECT_THAT(tracker().references_to_add(), UnorderedElementsAre(reference));
+  EXPECT_THAT(tracker().references_to_remove(), IsEmpty());
+}
+
+TEST_F(ReferencedSurfaceTrackerTest, NoChangeToReferences) {
+  const SurfaceId parent_id = MakeSurfaceId(kParentFrameSink, 1);
+  const SurfaceId child_id1 = MakeSurfaceId(kChildFrameSink1, 1);
+  const SurfaceReference reference(parent_id, child_id1);
+
+  // First frame has a reference to |child_id1|, check that reference is added.
+  tracker().UpdateReferences(parent_id.local_frame_id(), {child_id1});
+  EXPECT_THAT(tracker().references_to_remove(), IsEmpty());
+  EXPECT_THAT(tracker().references_to_add(), UnorderedElementsAre(reference));
+
+  // Second frame has same reference, check that no references are added or
+  // removed.
+  tracker().UpdateReferences(parent_id.local_frame_id(), {child_id1});
+  EXPECT_THAT(tracker().references_to_remove(), IsEmpty());
+  EXPECT_THAT(tracker().references_to_add(), IsEmpty());
+}
+
+TEST_F(ReferencedSurfaceTrackerTest, UnrefSurface) {
+  const SurfaceId parent_id = MakeSurfaceId(kParentFrameSink, 1);
+  const SurfaceId child_id1 = MakeSurfaceId(kChildFrameSink1, 1);
+  const SurfaceReference reference(parent_id, child_id1);
+
+  tracker().UpdateReferences(parent_id.local_frame_id(), {child_id1});
+
+  // Second frame no longer references |child_id1|, check that reference to is
+  // removed.
+  tracker().UpdateReferences(parent_id.local_frame_id(), empty_surface_ids());
+  EXPECT_THAT(tracker().references_to_add(), IsEmpty());
+  EXPECT_THAT(tracker().references_to_remove(),
+              UnorderedElementsAre(reference));
+}
+
+TEST_F(ReferencedSurfaceTrackerTest, RefNewSurfaceForFrameSink) {
+  const SurfaceId parent_id = MakeSurfaceId(kParentFrameSink, 1);
+  const SurfaceId child_id1_first = MakeSurfaceId(kChildFrameSink1, 1);
+  const SurfaceId child_id1_second = MakeSurfaceId(kChildFrameSink1, 2);
+  const SurfaceReference reference_first(parent_id, child_id1_first);
+  const SurfaceReference reference_second(parent_id, child_id1_second);
+
+  // First frame has reference to |child_id1_first|.
+  tracker().UpdateReferences(parent_id.local_frame_id(), {child_id1_first});
+  EXPECT_THAT(tracker().references_to_add(),
+              UnorderedElementsAre(reference_first));
+
+  // Second frame has reference to |child_id1_second| which has the same
+  // FrameSinkId but different LocalFrameId. Check that first reference is
+  // removed and second reference is added.
+  tracker().UpdateReferences(parent_id.local_frame_id(), {child_id1_second});
+  EXPECT_THAT(tracker().references_to_remove(),
+              UnorderedElementsAre(reference_first));
+  EXPECT_THAT(tracker().references_to_add(),
+              UnorderedElementsAre(reference_second));
+}
+
+TEST_F(ReferencedSurfaceTrackerTest, UpdateParentSurfaceId) {
+  const SurfaceId parent_id_first = MakeSurfaceId(kParentFrameSink, 1);
+  const SurfaceId parent_id_second = MakeSurfaceId(kParentFrameSink, 2);
+  const SurfaceId child_id1 = MakeSurfaceId(kChildFrameSink1, 1);
+  const SurfaceReference reference(parent_id_second, child_id1);
+
+  // First frame references |child_id1|.
+  tracker().UpdateReferences(parent_id_first.local_frame_id(), {child_id1});
+  EXPECT_THAT(tracker().references_to_add(), SizeIs(1));
+
+  // Second frame still reference |child_id1| but the parent SurfaceId has
+  // changed. The new parent SurfaceId should have a reference added to
+  // |child_id1|.
+  tracker().UpdateReferences(parent_id_second.local_frame_id(), {child_id1});
+  EXPECT_THAT(tracker().references_to_add(), UnorderedElementsAre(reference));
+  EXPECT_THAT(tracker().references_to_remove(), IsEmpty());
+}
+
+TEST_F(ReferencedSurfaceTrackerTest, RefTwoThenUnrefOneSurface) {
+  const SurfaceId parent_id = MakeSurfaceId(kParentFrameSink, 1);
+  const SurfaceId child_id1 = MakeSurfaceId(kChildFrameSink1, 1);
+  const SurfaceId child_id2 = MakeSurfaceId(kChildFrameSink2, 2);
+  const SurfaceReference reference1(parent_id, child_id1);
+  const SurfaceReference reference2(parent_id, child_id2);
+
+  // First frame references both surfaces.
+  tracker().UpdateReferences(parent_id.local_frame_id(),
+                             {child_id1, child_id2});
+  EXPECT_THAT(tracker().references_to_add(),
+              UnorderedElementsAre(reference1, reference2));
+
+  // Second frame references only |child_id2|, check that reference to
+  // |child_id1| is removed.
+  tracker().UpdateReferences(parent_id.local_frame_id(), {child_id2});
+  EXPECT_THAT(tracker().references_to_remove(),
+              UnorderedElementsAre(reference1));
+  EXPECT_THAT(tracker().references_to_add(), IsEmpty());
+}
+
+}  // namespace test
+}  // namespace cc
diff --git a/cc/trees/layer_tree_impl.cc b/cc/trees/layer_tree_impl.cc
index fa637e2..e6484ec 100644
--- a/cc/trees/layer_tree_impl.cc
+++ b/cc/trees/layer_tree_impl.cc
@@ -544,18 +544,25 @@
 }
 
 void LayerTreeImpl::AddToElementMap(LayerImpl* layer) {
-  if (!layer->element_id())
+  ElementId element_id = layer->element_id();
+  if (!element_id)
     return;
 
   TRACE_EVENT2(TRACE_DISABLED_BY_DEFAULT("compositor-worker"),
                "LayerTreeImpl::AddToElementMap", "element",
-               layer->element_id().AsValue().release(), "layer_id",
-               layer->id());
+               element_id.AsValue().release(), "layer_id", layer->id());
 
-  element_layers_map_[layer->element_id()] = layer->id();
+#if DCHECK_IS_ON()
+  LayerImpl* existing_layer = LayerByElementId(element_id);
+  bool element_id_collision_detected =
+      existing_layer && existing_layer != layer;
+  DCHECK(!element_id_collision_detected);
+#endif
+
+  element_layers_map_[element_id] = layer->id();
 
   layer_tree_host_impl_->mutator_host()->RegisterElement(
-      layer->element_id(),
+      element_id,
       IsActiveTree() ? ElementListType::ACTIVE : ElementListType::PENDING);
 }
 
diff --git a/chrome/android/java/res/drawable-hdpi/card_bottom.9.png b/chrome/android/java/res/drawable-hdpi/card_bottom.9.png
new file mode 100644
index 0000000..18e44f9
--- /dev/null
+++ b/chrome/android/java/res/drawable-hdpi/card_bottom.9.png
Binary files differ
diff --git a/chrome/android/java/res/drawable-hdpi/card_middle.9.png b/chrome/android/java/res/drawable-hdpi/card_middle.9.png
new file mode 100644
index 0000000..b037501
--- /dev/null
+++ b/chrome/android/java/res/drawable-hdpi/card_middle.9.png
Binary files differ
diff --git a/chrome/android/java/res/drawable-hdpi/card_single.9.png b/chrome/android/java/res/drawable-hdpi/card_single.9.png
new file mode 100644
index 0000000..339191c
--- /dev/null
+++ b/chrome/android/java/res/drawable-hdpi/card_single.9.png
Binary files differ
diff --git a/chrome/android/java/res/drawable-hdpi/card_top.9.png b/chrome/android/java/res/drawable-hdpi/card_top.9.png
new file mode 100644
index 0000000..a0d1dd24
--- /dev/null
+++ b/chrome/android/java/res/drawable-hdpi/card_top.9.png
Binary files differ
diff --git a/chrome/android/java/res/drawable-hdpi/textbox.9.png b/chrome/android/java/res/drawable-hdpi/textbox.9.png
deleted file mode 100644
index 994e5a5..0000000
--- a/chrome/android/java/res/drawable-hdpi/textbox.9.png
+++ /dev/null
Binary files differ
diff --git a/chrome/android/java/res/drawable-mdpi/card_bottom.9.png b/chrome/android/java/res/drawable-mdpi/card_bottom.9.png
new file mode 100644
index 0000000..9289c5d
--- /dev/null
+++ b/chrome/android/java/res/drawable-mdpi/card_bottom.9.png
Binary files differ
diff --git a/chrome/android/java/res/drawable-mdpi/card_middle.9.png b/chrome/android/java/res/drawable-mdpi/card_middle.9.png
new file mode 100644
index 0000000..cc958e0
--- /dev/null
+++ b/chrome/android/java/res/drawable-mdpi/card_middle.9.png
Binary files differ
diff --git a/chrome/android/java/res/drawable-mdpi/card_single.9.png b/chrome/android/java/res/drawable-mdpi/card_single.9.png
new file mode 100644
index 0000000..adcff308
--- /dev/null
+++ b/chrome/android/java/res/drawable-mdpi/card_single.9.png
Binary files differ
diff --git a/chrome/android/java/res/drawable-mdpi/card_top.9.png b/chrome/android/java/res/drawable-mdpi/card_top.9.png
new file mode 100644
index 0000000..f8d1df9
--- /dev/null
+++ b/chrome/android/java/res/drawable-mdpi/card_top.9.png
Binary files differ
diff --git a/chrome/android/java/res/drawable-mdpi/textbox.9.png b/chrome/android/java/res/drawable-mdpi/textbox.9.png
deleted file mode 100644
index a015e50..0000000
--- a/chrome/android/java/res/drawable-mdpi/textbox.9.png
+++ /dev/null
Binary files differ
diff --git a/chrome/android/java/res/drawable-xhdpi/card_bottom.9.png b/chrome/android/java/res/drawable-xhdpi/card_bottom.9.png
new file mode 100644
index 0000000..c2a9655
--- /dev/null
+++ b/chrome/android/java/res/drawable-xhdpi/card_bottom.9.png
Binary files differ
diff --git a/chrome/android/java/res/drawable-xhdpi/card_middle.9.png b/chrome/android/java/res/drawable-xhdpi/card_middle.9.png
new file mode 100644
index 0000000..e973985
--- /dev/null
+++ b/chrome/android/java/res/drawable-xhdpi/card_middle.9.png
Binary files differ
diff --git a/chrome/android/java/res/drawable-xhdpi/card_single.9.png b/chrome/android/java/res/drawable-xhdpi/card_single.9.png
new file mode 100644
index 0000000..e95008f
--- /dev/null
+++ b/chrome/android/java/res/drawable-xhdpi/card_single.9.png
Binary files differ
diff --git a/chrome/android/java/res/drawable-xhdpi/card_top.9.png b/chrome/android/java/res/drawable-xhdpi/card_top.9.png
new file mode 100644
index 0000000..ad04f2bd
--- /dev/null
+++ b/chrome/android/java/res/drawable-xhdpi/card_top.9.png
Binary files differ
diff --git a/chrome/android/java/res/drawable-xhdpi/textbox.9.png b/chrome/android/java/res/drawable-xhdpi/textbox.9.png
deleted file mode 100644
index 016d897..0000000
--- a/chrome/android/java/res/drawable-xhdpi/textbox.9.png
+++ /dev/null
Binary files differ
diff --git a/chrome/android/java/res/drawable-xxhdpi/card_bottom.9.png b/chrome/android/java/res/drawable-xxhdpi/card_bottom.9.png
new file mode 100644
index 0000000..c3cc895a
--- /dev/null
+++ b/chrome/android/java/res/drawable-xxhdpi/card_bottom.9.png
Binary files differ
diff --git a/chrome/android/java/res/drawable-xxhdpi/card_middle.9.png b/chrome/android/java/res/drawable-xxhdpi/card_middle.9.png
new file mode 100644
index 0000000..3d7d221
--- /dev/null
+++ b/chrome/android/java/res/drawable-xxhdpi/card_middle.9.png
Binary files differ
diff --git a/chrome/android/java/res/drawable-xxhdpi/card_single.9.png b/chrome/android/java/res/drawable-xxhdpi/card_single.9.png
new file mode 100644
index 0000000..400c45c
--- /dev/null
+++ b/chrome/android/java/res/drawable-xxhdpi/card_single.9.png
Binary files differ
diff --git a/chrome/android/java/res/drawable-xxhdpi/card_top.9.png b/chrome/android/java/res/drawable-xxhdpi/card_top.9.png
new file mode 100644
index 0000000..f8ed40165
--- /dev/null
+++ b/chrome/android/java/res/drawable-xxhdpi/card_top.9.png
Binary files differ
diff --git a/chrome/android/java/res/drawable-xxhdpi/textbox.9.png b/chrome/android/java/res/drawable-xxhdpi/textbox.9.png
deleted file mode 100644
index c2cbd05..0000000
--- a/chrome/android/java/res/drawable-xxhdpi/textbox.9.png
+++ /dev/null
Binary files differ
diff --git a/chrome/android/java/res/drawable-xxxhdpi/card_bottom.9.png b/chrome/android/java/res/drawable-xxxhdpi/card_bottom.9.png
new file mode 100644
index 0000000..867c917
--- /dev/null
+++ b/chrome/android/java/res/drawable-xxxhdpi/card_bottom.9.png
Binary files differ
diff --git a/chrome/android/java/res/drawable-xxxhdpi/card_middle.9.png b/chrome/android/java/res/drawable-xxxhdpi/card_middle.9.png
new file mode 100644
index 0000000..7f0a30b
--- /dev/null
+++ b/chrome/android/java/res/drawable-xxxhdpi/card_middle.9.png
Binary files differ
diff --git a/chrome/android/java/res/drawable-xxxhdpi/card_single.9.png b/chrome/android/java/res/drawable-xxxhdpi/card_single.9.png
new file mode 100644
index 0000000..b5a82394
--- /dev/null
+++ b/chrome/android/java/res/drawable-xxxhdpi/card_single.9.png
Binary files differ
diff --git a/chrome/android/java/res/drawable-xxxhdpi/card_top.9.png b/chrome/android/java/res/drawable-xxxhdpi/card_top.9.png
new file mode 100644
index 0000000..ad85ed7e
--- /dev/null
+++ b/chrome/android/java/res/drawable-xxxhdpi/card_top.9.png
Binary files differ
diff --git a/chrome/android/java/res/drawable-xxxhdpi/textbox.9.png b/chrome/android/java/res/drawable-xxxhdpi/textbox.9.png
deleted file mode 100644
index 02d5fb8e..0000000
--- a/chrome/android/java/res/drawable-xxxhdpi/textbox.9.png
+++ /dev/null
Binary files differ
diff --git a/chrome/android/java/res/layout/new_tab_page_action_card.xml b/chrome/android/java/res/layout/new_tab_page_action_card.xml
index f9e5c1a5..db474dd 100644
--- a/chrome/android/java/res/layout/new_tab_page_action_card.xml
+++ b/chrome/android/java/res/layout/new_tab_page_action_card.xml
@@ -14,7 +14,7 @@
     android:layout_height="wrap_content"
     android:orientation="vertical"
     android:padding="8dp"
-    android:background="@drawable/ntp_card_single">
+    android:background="@drawable/card_single">
 
 
     <!-- Using some standard metrics (minWidth, paddings) to override the
diff --git a/chrome/android/java/res/layout/new_tab_page_layout.xml b/chrome/android/java/res/layout/new_tab_page_layout.xml
index 4dc623c..d68172e 100644
--- a/chrome/android/java/res/layout/new_tab_page_layout.xml
+++ b/chrome/android/java/res/layout/new_tab_page_layout.xml
@@ -64,7 +64,7 @@
         android:layout_marginTop="0dp"
         android:layout_marginBottom="1dp"
         android:gravity="center_vertical"
-        android:background="@drawable/textbox"
+        android:background="@drawable/card_single"
         android:orientation="horizontal"
         android:paddingStart="2dp"
         android:paddingEnd="2dp"
diff --git a/chrome/android/java/res/layout/new_tab_page_snippets_card.xml b/chrome/android/java/res/layout/new_tab_page_snippets_card.xml
index 58eb79b..650429e 100644
--- a/chrome/android/java/res/layout/new_tab_page_snippets_card.xml
+++ b/chrome/android/java/res/layout/new_tab_page_snippets_card.xml
@@ -12,7 +12,7 @@
     android:layout_height="wrap_content"
     android:foreground="@drawable/button_borderless_compat"
     android:padding="@dimen/snippets_padding"
-    android:background="@drawable/ntp_card_single">
+    android:background="@drawable/card_single">
 
     <org.chromium.ui.widget.TextViewWithLeading
         android:id="@+id/article_headline"
@@ -42,16 +42,23 @@
     <LinearLayout
         tools:ignore="UseCompoundDrawables"
         android:id="@+id/publisher_bar"
-        android:layout_width="match_parent"
+        android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:layout_marginTop="@dimen/snippets_publisher_margin_top_with_article_snippet"
         android:layout_alignParentStart="true"
         android:layout_below="@+id/article_snippet"
         android:orientation="horizontal">
 
+        <!-- The following attributes:
+        - LinearLayout's android:layout_width="wrap_content"
+        - TextView's android:layout_width="0dp"
+        - TextView's android:layout_weight="1"
+        All ensure that when the TextView is long and the ImageView is showing, the TextView starts
+        to ellipsize before pushing the ImageView off the screen. See: https://crbug.com/678568 -->
         <TextView
             android:id="@+id/article_publisher"
-            android:layout_width="wrap_content"
+            android:layout_width="0dp"
+            android:layout_weight="1"
             android:layout_height="wrap_content"
             android:drawablePadding="8dp"
             android:paddingStart="4dp"
diff --git a/chrome/android/java/res/layout/new_tab_page_status_card.xml b/chrome/android/java/res/layout/new_tab_page_status_card.xml
index 27dbfcd..e6f60340 100644
--- a/chrome/android/java/res/layout/new_tab_page_status_card.xml
+++ b/chrome/android/java/res/layout/new_tab_page_status_card.xml
@@ -12,7 +12,7 @@
     android:gravity="end"
     android:orientation="vertical"
     android:padding="@dimen/snippets_padding"
-    android:background="@drawable/ntp_card_single">
+    android:background="@drawable/card_single">
 
     <org.chromium.ui.widget.TextViewWithLeading
         android:id="@+id/status_title"
diff --git a/chrome/android/java/res/layout/toolbar_tablet.xml b/chrome/android/java/res/layout/toolbar_tablet.xml
index 9699ff3..458c337 100644
--- a/chrome/android/java/res/layout/toolbar_tablet.xml
+++ b/chrome/android/java/res/layout/toolbar_tablet.xml
@@ -53,7 +53,7 @@
             android:layout_marginTop="5dp"
             android:layout_weight="1"
             android:layout_gravity="top|center"
-            android:background="@drawable/textbox"
+            android:background="@drawable/card_single"
             android:paddingEnd="1dp"
             android:paddingStart="2dp" />
 
diff --git a/chrome/android/java/res/values/dimens.xml b/chrome/android/java/res/values/dimens.xml
index 746b84b..35b1f96 100644
--- a/chrome/android/java/res/values/dimens.xml
+++ b/chrome/android/java/res/values/dimens.xml
@@ -290,7 +290,8 @@
          (https://crbug.com/660837). -->
     <dimen name="snippets_peeking_card_peek_amount">32dp</dimen>
     <dimen name="snippets_peeking_card_bounce_distance">10dp</dimen>
-    <dimen name="snippets_card_9_patch_adjustment">2dp</dimen>
+    <dimen name="snippets_card_corner_radius">2dp</dimen>
+    <dimen name="snippets_card_gap">0.5dp</dimen>
     <dimen name="snippets_article_header_height">40dp</dimen>
     <dimen name="snippets_publisher_margin_top_with_article_snippet">16dp</dimen>
     <dimen name="snippets_publisher_margin_top_without_article_snippet">8dp</dimen>
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ServiceTabLauncher.java b/chrome/android/java/src/org/chromium/chrome/browser/ServiceTabLauncher.java
index 5a2b92b..b8d68088 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ServiceTabLauncher.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ServiceTabLauncher.java
@@ -76,9 +76,14 @@
         final WebappDataStorage storage =
                 WebappRegistry.getInstance().getWebappDataStorageForUrl(url);
 
-        // If we do not find a WebappDataStorage corresponding to this URL, or if it hasn't
-        // been opened recently enough, open the URL in a tab.
-        if (storage == null || !storage.wasLaunchedRecently()) {
+        // Open a new tab if:
+        // - We did not find a WebappDataStorage corresponding to this URL.
+        // OR
+        // - The WebappDataStorage hasn't been opened recently enough.
+        // OR
+        // - The WebappDataStorage corresponds to a WebAPK (and WebAPKs are disabled).
+        if (storage == null || !storage.wasLaunchedRecently()
+                || storage.getWebApkPackageName() != null) {
             LoadUrlParams loadUrlParams = new LoadUrlParams(url, PageTransition.LINK);
             loadUrlParams.setPostData(postData);
             loadUrlParams.setVerbatimHeaders(extraHeaders);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/scene_layer/TabListSceneLayer.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/scene_layer/TabListSceneLayer.java
index e31a495..8d51961 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/scene_layer/TabListSceneLayer.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/scene_layer/TabListSceneLayer.java
@@ -97,7 +97,7 @@
                     LayoutTab.CLOSE_BUTTON_WIDTH_DP * dpToPx, t.getStaticToViewBlend(),
                     t.getBorderScale(), t.getSaturation(), t.getBrightness(), t.showToolbar(),
                     defaultThemeColor, t.getToolbarBackgroundColor(), closeButtonColor,
-                    t.anonymizeToolbar(), t.isTitleNeeded(), R.drawable.textbox,
+                    t.anonymizeToolbar(), t.isTitleNeeded(), R.drawable.card_single,
                     t.getTextBoxBackgroundColor(), t.getTextBoxAlpha(), t.getToolbarAlpha(),
                     t.getToolbarYOffset() * dpToPx, t.getSideBorderScale(),
                     t.insetBorderVertical());
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/scene_layer/ToolbarSceneLayer.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/scene_layer/ToolbarSceneLayer.java
index 4e65c0f6..50542ab 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/scene_layer/ToolbarSceneLayer.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/scene_layer/ToolbarSceneLayer.java
@@ -96,8 +96,8 @@
                 : fullscreenManager.getTopControlOffset();
 
         nativeUpdateToolbarLayer(mNativePtr, resourceManager, R.id.control_container,
-                browserControlsBackgroundColor, R.drawable.textbox, browserControlsUrlBarAlpha,
-                controlsOffset, windowHeight, useTexture, showShadow,
+                browserControlsBackgroundColor, R.drawable.card_single,
+                browserControlsUrlBarAlpha, controlsOffset, windowHeight, useTexture, showShadow,
                 fullscreenManager.areBrowserControlsAtBottom());
 
         if (mProgressBarDrawingInfo == null) return;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchFieldTrial.java b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchFieldTrial.java
index 7555c804..18c4f93 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchFieldTrial.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchFieldTrial.java
@@ -83,6 +83,9 @@
 
     private static final String ENABLE_AMP_AS_SEPARATE_TAB = "enable_amp_as_separate_tab";
 
+    // Privacy-related flags
+    private static final String ENABLE_SEND_HOME_COUNTRY = "enable_send_home_country";
+
     // Cached values to avoid repeated and redundant JNI operations.
     private static Boolean sEnabled;
     private static Boolean sDisableSearchTermResolution;
@@ -108,6 +111,7 @@
     private static Boolean sIsOnlineDetectionDisabled;
     private static Boolean sIsAmpAsSeparateTabEnabled;
     private static Boolean sContextualSearchSingleActionsEnabled;
+    private static Boolean sCanSendHomeCountry;
 
     /**
      * Don't instantiate.
@@ -398,6 +402,16 @@
         return sIsOnlineDetectionDisabled;
     }
 
+    /**
+     * @return Whether sending the "home country" to Google is enabled.
+     */
+    static boolean isSendHomeCountryEnabled() {
+        if (sCanSendHomeCountry == null) {
+            sCanSendHomeCountry = getBooleanParam(ENABLE_SEND_HOME_COUNTRY);
+        }
+        return sCanSendHomeCountry.booleanValue();
+    }
+
     // ---------------
     // Features.
     // ---------------
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManager.java b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManager.java
index edbf1afa..3dd635b 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManager.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManager.java
@@ -67,9 +67,6 @@
         ContextualSearchTranslateInterface, ContextualSearchNetworkCommunicator,
         ContextualSearchSelectionHandler, ContextualSearchClient {
 
-    private static final boolean ALWAYS_USE_RESOLVED_SEARCH_TERM = true;
-    private static final boolean NEVER_USE_RESOLVED_SEARCH_TERM = false;
-
     private static final String INTENT_URL_PREFIX = "intent:";
 
     // The animation duration of a URL being promoted to a tab when triggered by an
@@ -82,6 +79,9 @@
 
     private static final Pattern CONTAINS_WHITESPACE_PATTERN = Pattern.compile("\\s");
 
+    // When we don't need to send any "home country" code we can just pass the empty string.
+    private static final String NO_HOME_COUNTRY = "";
+
     private final ObserverList<ContextualSearchObserver> mObservers =
             new ObserverList<ContextualSearchObserver>();
 
@@ -421,7 +421,6 @@
 
         boolean isTap = mSelectionController.getSelectionType() == SelectionType.TAP;
         boolean didRequestSurroundings = false;
-
         if (isTap) {
             // If the user action was not a long-press, immediately start loading content.
             mShouldLoadDelayedSearch = false;
@@ -461,7 +460,7 @@
             // part of search term resolution, just sent to Icing which keeps them local until
             // the user activates a Voice Search.
             nativeGatherSurroundingText(mNativeContextualSearchManagerPtr,
-                    mSelectionController.getSelectedText(), NEVER_USE_RESOLVED_SEARCH_TERM,
+                    mSelectionController.getSelectedText(), NO_HOME_COUNTRY,
                     getBaseContentView().getWebContents(), mPolicy.maySendBasePageUrl());
         }
 
@@ -508,7 +507,7 @@
         ContentViewCore baseContentView = getBaseContentView();
         if (baseContentView != null) {
             nativeStartSearchTermResolutionRequest(mNativeContextualSearchManagerPtr, selection,
-                    ALWAYS_USE_RESOLVED_SEARCH_TERM, getBaseContentView().getWebContents(),
+                    mPolicy.getHomeCountry(mActivity), getBaseContentView().getWebContents(),
                     mPolicy.maySendBasePageUrl());
         }
     }
@@ -1445,10 +1444,10 @@
     private native long nativeInit();
     private native void nativeDestroy(long nativeContextualSearchManager);
     private native void nativeStartSearchTermResolutionRequest(long nativeContextualSearchManager,
-            String selection, boolean useResolvedSearchTerm, WebContents baseWebContents,
+            String selection, String homeCountry, WebContents baseWebContents,
             boolean maySendBasePageUrl);
     protected native void nativeGatherSurroundingText(long nativeContextualSearchManager,
-            String selection, boolean useResolvedSearchTerm, WebContents baseWebContents,
+            String selection, String homeCountry, WebContents baseWebContents,
             boolean maySendBasePageUrl);
     private native void nativeEnableContextualSearchJsApiForOverlay(
             long nativeContextualSearchManager, WebContents overlayWebContents);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchPolicy.java b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchPolicy.java
index a953667..3233561 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchPolicy.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchPolicy.java
@@ -6,6 +6,7 @@
 
 import android.content.Context;
 import android.net.Uri;
+import android.telephony.TelephonyManager;
 import android.text.TextUtils;
 
 import org.chromium.base.VisibleForTesting;
@@ -509,6 +510,23 @@
     }
 
     /**
+     * @return The ISO country code for the user's home country, or an empty string if not
+     *         available or privacy-enabled.
+     */
+    String getHomeCountry(Context context) {
+        if (!ContextualSearchFieldTrial.isSendHomeCountryEnabled()) return "";
+
+        TelephonyManager telephonyManager =
+                (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
+        if (telephonyManager == null) return "";
+
+        String simCountryIso = telephonyManager.getSimCountryIso();
+        if (TextUtils.isEmpty(simCountryIso)) return "";
+
+        return simCountryIso;
+    }
+
+    /**
      * Sets the limit for the tap triggered promo.
      */
     @VisibleForTesting
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/ContentSuggestionsNotificationHelper.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/ContentSuggestionsNotificationHelper.java
index a149fca..a5cfba4 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/ContentSuggestionsNotificationHelper.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/ContentSuggestionsNotificationHelper.java
@@ -123,6 +123,8 @@
                         .setContentTitle(title)
                         .setContentText(text)
                         .setGroup(NOTIFICATION_TAG)
+                        .setDefaults(NotificationCompat.DEFAULT_LIGHTS)
+                        .setPriority(-1)
                         .setLargeIcon(image)
                         .setSmallIcon(R.drawable.ic_chrome);
         manager.notify(NOTIFICATION_TAG, nextId, builder.build());
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/CardViewHolder.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/CardViewHolder.java
index 05a102f..4eff2c88 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/CardViewHolder.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/CardViewHolder.java
@@ -4,6 +4,7 @@
 
 package org.chromium.chrome.browser.ntp.cards;
 
+import android.graphics.Rect;
 import android.support.annotation.CallSuper;
 import android.support.annotation.DrawableRes;
 import android.support.annotation.Nullable;
@@ -18,6 +19,7 @@
 import android.view.ViewGroup;
 import android.view.animation.Interpolator;
 
+import org.chromium.base.ApiCompatibilityUtils;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.ntp.ContextMenuManager;
 import org.chromium.chrome.browser.ntp.UiConfig;
@@ -48,11 +50,16 @@
     private final int mMaxPeekPadding;
 
     /**
-     * Due to the card background being a 9 patch file - the card border shadow will be part of
-     * the card width and height. This value will be used to adjust values to account for the
-     * borders.
+     * The card shadow is part of the drawable nine-patch and not drawn via setElevation(),
+     * so it is included in the height and width of the drawable. This member contains the
+     * dimensions of the shadow (from the drawable's padding), so it can be used to offset the
+     * position in calculations.
      */
-    private final int mCards9PatchAdjustment;
+    private final Rect mCardShadow = new Rect();
+
+    private final int mCardGap;
+
+    private final int mDefaultLateralMargin;
 
     protected final NewTabPageRecyclerView mRecyclerView;
 
@@ -78,8 +85,10 @@
             UiConfig uiConfig, final ContextMenuManager contextMenuManager) {
         super(inflateView(layoutId, recyclerView));
 
-        mCards9PatchAdjustment = recyclerView.getResources().getDimensionPixelSize(
-                R.dimen.snippets_card_9_patch_adjustment);
+        ApiCompatibilityUtils.getDrawable(recyclerView.getResources(), R.drawable.card_single)
+                .getPadding(mCardShadow);
+
+        mCardGap = recyclerView.getResources().getDimensionPixelSize(R.dimen.snippets_card_gap);
 
         mMaxPeekPadding = recyclerView.getResources().getDimensionPixelSize(
                 R.dimen.snippets_padding);
@@ -115,7 +124,11 @@
 
         // Configure the resizer to use negative margins on regular display to balance out the
         // lateral shadow of the card 9-patch and avoid a rounded corner effect.
-        mMarginResizer.setMargins(-mCards9PatchAdjustment);
+        int cardCornerRadius = recyclerView.getResources().getDimensionPixelSize(
+                R.dimen.snippets_card_corner_radius);
+        assert mCardShadow.left == mCardShadow.right;
+        mDefaultLateralMargin = -(mCardShadow.left + cardCornerRadius);
+        mMarginResizer.setMargins(mDefaultLateralMargin);
     }
 
     /**
@@ -176,7 +189,11 @@
             hasCardBelow = isCard(belowViewType) && belowViewType != ItemViewType.PROMO;
         }
 
-        getParams().bottomMargin = hasCardBelow ? -mCards9PatchAdjustment : 0;
+        // By default the apparent distance between two cards is the sum of the bottom and top
+        // height of their shadows. We want |mCardGap| instead, so we set the bottom margin to
+        // the difference.
+        getParams().bottomMargin =
+                hasCardBelow ? (mCardGap - (mCardShadow.top + mCardShadow.bottom)) : 0;
 
         @DrawableRes
         int selectedBackground = selectBackground(hasCardAbove, hasCardBelow);
@@ -247,9 +264,8 @@
         }
         itemView.setPadding(lateralPadding, mMaxPeekPadding, lateralPadding, mMaxPeekPadding);
 
-        // Adjust the margins by |mCards9PatchAdjustment| so the card width
-        // is the actual width not including the elevation shadow, so we can have full bleed.
-        mMarginResizer.setMargins(mMaxPeekPadding - (peekPadding + mCards9PatchAdjustment));
+        // Adjust the margins. The shadow width is offset via the default lateral margin.
+        mMarginResizer.setMargins(mDefaultLateralMargin + mMaxPeekPadding - peekPadding);
 
         // Set the opacity of the card content to be 0 when peeking and 1 when full width.
         int itemViewChildCount = ((ViewGroup) itemView).getChildCount();
@@ -285,10 +301,10 @@
 
     @DrawableRes
     protected int selectBackground(boolean hasCardAbove, boolean hasCardBelow) {
-        if (hasCardAbove && hasCardBelow) return R.drawable.ntp_card_middle;
-        if (!hasCardAbove && hasCardBelow) return R.drawable.ntp_card_top;
-        if (hasCardAbove && !hasCardBelow) return R.drawable.ntp_card_bottom;
-        return R.drawable.ntp_card_single;
+        if (hasCardAbove && hasCardBelow) return R.drawable.card_middle;
+        if (!hasCardAbove && hasCardBelow) return R.drawable.card_top;
+        if (hasCardAbove && !hasCardBelow) return R.drawable.card_bottom;
+        return R.drawable.card_single;
     }
 
     protected NewTabPageRecyclerView getRecyclerView() {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarPhone.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarPhone.java
index 4d7259ec..f921606 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarPhone.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarPhone.java
@@ -334,7 +334,7 @@
                 new ColorDrawable(getToolbarColorForVisualState(VisualState.NORMAL));
 
         mLocationBarBackground =
-                ApiCompatibilityUtils.getDrawable(getResources(), R.drawable.textbox);
+                ApiCompatibilityUtils.getDrawable(getResources(), R.drawable.card_single);
         mLocationBarBackground.getPadding(mLocationBarBackgroundPadding);
         mLocationBar.setPadding(
                 mLocationBarBackgroundPadding.left, mLocationBarBackgroundPadding.top,
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrShellDelegate.java b/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrShellDelegate.java
index 67990ac3..550ed7c 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrShellDelegate.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrShellDelegate.java
@@ -9,6 +9,7 @@
 import android.content.ComponentName;
 import android.content.Intent;
 import android.content.pm.ActivityInfo;
+import android.os.Handler;
 import android.os.StrictMode;
 import android.os.SystemClock;
 import android.support.annotation.IntDef;
@@ -47,13 +48,15 @@
     public static final int ENTER_VR_CANCELLED = 1;
     public static final int ENTER_VR_REQUESTED = 2;
     public static final int ENTER_VR_SUCCEEDED = 3;
+
     @Retention(RetentionPolicy.SOURCE)
-    @IntDef({ENTER_VR_NOT_NECESSARY, ENTER_VR_CANCELLED, ENTER_VR_REQUESTED, ENTER_VR_SUCCEEDED })
+    @IntDef({ENTER_VR_NOT_NECESSARY, ENTER_VR_CANCELLED, ENTER_VR_REQUESTED, ENTER_VR_SUCCEEDED})
     public @interface EnterVRResult {}
 
     public static final int VR_NOT_AVAILABLE = 0;
     public static final int VR_CARDBOARD = 1;
     public static final int VR_DAYDREAM = 2; // Supports both Cardboard and Daydream viewer.
+
     @Retention(RetentionPolicy.SOURCE)
     @IntDef({VR_NOT_AVAILABLE, VR_CARDBOARD, VR_DAYDREAM})
     public @interface VrSupportLevel {}
@@ -139,7 +142,7 @@
                 @Override
                 public void onLoadProgressChanged(Tab tab, int progress) {
                     if (!mInVr) return;
-                    mVrShell.onLoadProgressChanged((double) progress / 100.0);
+                    mVrShell.onLoadProgressChanged(progress / 100.0);
                 }
             };
         }
@@ -148,8 +151,8 @@
     }
 
     /**
-     * Should be called once the native library is loaded so that the native portion of this
-     * class can be initialized.
+     * Should be called once the native library is loaded so that the native portion of this class
+     * can be initialized.
      */
     public void onNativeLibraryReady() {
         if (mVrSupportLevel == VR_NOT_AVAILABLE) return;
@@ -193,37 +196,48 @@
             mVrDaydreamApi.launchVrHomescreen();
             return;
         }
-        if (enterVR()) {
-            if (mRequestedWebVR) nativeSetPresentResult(mNativeVrShellDelegate, true);
-        } else {
-            if (mRequestedWebVR) nativeSetPresentResult(mNativeVrShellDelegate, false);
-            if (!mVrDaydreamApi.exitFromVr(EXIT_VR_RESULT, new Intent())) {
-                mVrClassesWrapper.setVrModeEnabled(false);
-            }
-        }
-
-        mRequestedWebVR = false;
+        enterVR();
     }
 
-    private boolean enterVR() {
-        if (mInVr) return true;
+    private void enterVR() {
+        if (mInVr) {
+            setEnterVRResult(true, mRequestedWebVR);
+            return;
+        }
 
-        Tab tab = mActivity.getActivityTab();
-        if (!canEnterVR(tab)) return false;
+        if (!canEnterVR(mActivity.getActivityTab())) {
+            setEnterVRResult(false, mRequestedWebVR);
+            return;
+        }
 
         mRestoreOrientation = mActivity.getRequestedOrientation();
         mActivity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
+        setupVrModeWindowFlags();
+        final boolean requestedWebVR = mRequestedWebVR;
+        mRequestedWebVR = false;
+        // We need to post this to the end of the message queue so that the display properties can
+        // update in response to our request to enter landscape and hide the system UI.
+        new Handler().post(new Runnable() {
+            @Override
+            public void run() {
+                enterVRWithOrientationSet(requestedWebVR);
+            }
+        });
+    }
+
+    private void enterVRWithOrientationSet(boolean requestedWebVR) {
         if (!createVrShell()) {
             mActivity.setRequestedOrientation(mRestoreOrientation);
-            return false;
+            clearVrModeWindowFlags();
+            setEnterVRResult(false, requestedWebVR);
+            return;
         }
         mVrClassesWrapper.setVrModeEnabled(true);
         mInVr = true;
-        mTab = tab;
+        mTab = mActivity.getActivityTab();
         mTab.addObserver(mTabObserver);
         addVrViews();
-        setupVrModeWindowFlags();
-        mVrShell.initializeNative(mTab, this, mRequestedWebVR);
+        mVrShell.initializeNative(mTab, this, requestedWebVR);
         mVrShell.setCloseButtonListener(new Runnable() {
             @Override
             public void run() {
@@ -234,7 +248,15 @@
         // properly.
         mVrShell.resume();
         mTab.updateFullscreenEnabledState();
-        return true;
+        setEnterVRResult(true, requestedWebVR);
+    }
+
+    private void setEnterVRResult(boolean success, boolean requestedWebVR) {
+        if (requestedWebVR) nativeSetPresentResult(mNativeVrShellDelegate, success);
+        if (!success && !mVrDaydreamApi.exitFromVr(EXIT_VR_RESULT, new Intent())) {
+            mVrClassesWrapper.setVrModeEnabled(false);
+        }
+        mRequestedWebVR = false;
     }
 
     private boolean canEnterVR(Tab tab) {
@@ -302,7 +324,8 @@
         if (mVrSupportLevel == VR_CARDBOARD || !mVrDaydreamApi.isDaydreamCurrentViewer()) {
             // Avoid using launchInVr which would trigger DON flow regardless current viewer type
             // due to the lack of support for unexported activities.
-            return enterVR() ? ENTER_VR_SUCCEEDED : ENTER_VR_CANCELLED;
+            enterVR();
+            return ENTER_VR_REQUESTED;
         } else {
             if (!mVrDaydreamApi.launchInVr(getPendingEnterVRIntent())) return ENTER_VR_CANCELLED;
         }
@@ -579,9 +602,7 @@
     private boolean isVrShellEnabled() {
         // Only enable ChromeVR (VrShell) on Daydream devices as it currently needs a Daydream
         // controller.
-        if (mVrSupportLevel != VR_DAYDREAM) {
-            return false;
-        }
+        if (mVrSupportLevel != VR_DAYDREAM) return false;
         return ChromeFeatureList.isEnabled(ChromeFeatureList.VR_SHELL);
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebappDataStorage.java b/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebappDataStorage.java
index 075918f..d6057db3 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebappDataStorage.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebappDataStorage.java
@@ -345,7 +345,7 @@
     /**
      * Returns the package name if the data is for a WebAPK, null otherwise.
      */
-    String getWebApkPackageName() {
+    public String getWebApkPackageName() {
         return mPreferences.getString(KEY_WEBAPK_PACKAGE_NAME, null);
     }
 
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchTapEventTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchTapEventTest.java
index fa0e1136..918985df 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchTapEventTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchTapEventTest.java
@@ -114,8 +114,8 @@
 
         @Override
         protected void nativeGatherSurroundingText(long nativeContextualSearchManager,
-                String selection, boolean useResolvedSearchTerm,
-                WebContents webContents, boolean maySendBasePageUrl) {}
+                String selection, String homeCountry, WebContents webContents,
+                boolean maySendBasePageUrl) {}
 
         /**
          * @return A stubbed ContentViewCore for mocking text selection.
diff --git a/chrome/app/chromeos_strings.grdp b/chrome/app/chromeos_strings.grdp
index 75d0325..aa5376c 100644
--- a/chrome/app/chromeos_strings.grdp
+++ b/chrome/app/chromeos_strings.grdp
@@ -2314,6 +2314,23 @@
     Certificates not loaded
   </message>
 
+  <!-- Strings used in <cr-network-list>, used in Settings and OOBE -->
+  <message name="IDS_NETWORK_LIST_DISABLED" desc="Text in the network list element when the network type is disabled.">
+    Disabled
+  </message>
+  <message name="IDS_NETWORK_LIST_NOT_CONNECTED" desc="Text in the network list element when there is no network for the type.">
+    No network
+  </message>
+  <message name="IDS_NETWORK_LIST_CONNECTED" desc="Text in a network list item when the network is connected.">
+    connected
+  </message>
+  <message name="IDS_NETWORK_LIST_CONNECTING" desc="Text in the network element when a network is connecting.">
+    Connecting to <ph name="NAME">$1<ex>GoogleGuest</ex></ph>
+  </message>
+  <message name="IDS_NETWORK_LIST_THIRD_PARTY_VPN_NAME_TEMPLATE" desc="Template for constructing the name of a VPN network that is handled by a third-party VPN provider from the provider name and the network name.">
+    <ph name="PROVIDER_NAME">$1<ex>OpenVPN</ex></ph>: <ph name="NETWORK_NAME">$2<ex>Work Network</ex></ph>
+  </message>
+
   <!-- Other Network UI strings -->
   <message name="IDS_NETWORK_CONNECTION_ERROR_TITLE" desc="Title for network connection error notification">
     Network Connection Error
diff --git a/chrome/app/settings_strings.grdp b/chrome/app/settings_strings.grdp
index cf4edcee..ef3f217 100644
--- a/chrome/app/settings_strings.grdp
+++ b/chrome/app/settings_strings.grdp
@@ -1227,21 +1227,6 @@
     <message name="IDS_SETTINGS_INTERNET_CONNECT_NOT_ALLOWED" desc="Settings > Internet > Message when connecting to a non policy network is not allowed.">
       Connecting to this network is disabled by your administrator.
     </message>
-    <message name="IDS_SETTINGS_NETWORK_TYPE_ETHERNET" desc="The ethernet network type.">
-      Ethernet
-    </message>
-    <message name="IDS_SETTINGS_NETWORK_TYPE_WIFI" desc="The wifi network type.">
-      Wi-Fi
-    </message>
-    <message name="IDS_SETTINGS_NETWORK_TYPE_WIMAX" desc="The wimax network type.">
-      WiMAX
-    </message>
-    <message name="IDS_SETTINGS_NETWORK_TYPE_CELLULAR" desc="The cellular network type.">
-      Cellular
-    </message>
-    <message name="IDS_SETTINGS_NETWORK_TYPE_VPN" desc="The vpn network type.">
-      VPN
-    </message>
     <message name="IDS_SETTINGS_INTERNET_KNOWN_NETWORKS_BUTTON" desc="Text for button that opens the known networks subpage.">
       Known networks
     </message>
@@ -1258,23 +1243,6 @@
       All networks
     </message>
 
-    <!-- Strings used in <cr-network-list>, used in Settings and OOBE -->
-    <message name="IDS_NETWORK_LIST_DISABLED" desc="Settings > Internet, text in network summary when the network type is connected">
-      Disabled
-    </message>
-    <message name="IDS_NETWORK_LIST_NOT_CONNECTED" desc="Settings > Internet, text in network summary when there is no network for the type.">
-      No network
-    </message>
-    <message name="IDS_NETWORK_LIST_CONNECTED" desc="Settings > Internet, text to show in a network list item that is connected.">
-      connected
-    </message>
-    <message name="IDS_NETWORK_LIST_CONNECTING" desc="Settings > Internet, text in network summary when the primary network is connecting.">
-      Connecting to <ph name="NAME">$1<ex>GoogleGuest</ex></ph>
-    </message>
-    <message name="IDS_NETWORK_LIST_THIRD_PARTY_VPN_NAME_TEMPLATE" desc="Template for constructing the name of a VPN network that is handled by a third-party VPN provider from the provider name and the network name.">
-      <ph name="PROVIDER_NAME">$1<ex>OpenVPN</ex></ph>: <ph name="NETWORK_NAME">$2<ex>Work Network</ex></ph>
-    </message>
-
      <!-- Strings translating ONC (Open Network Configuration) properties -->
      <!-- and translatable values. See onc_spec.html for more information. -->
     <message name="IDS_ONC_IPV4_ADDRESS" desc="ONC Property label for ipv4-IPAddress">
diff --git a/chrome/browser/android/contextualsearch/contextual_search_context.cc b/chrome/browser/android/contextualsearch/contextual_search_context.cc
index 36216ae..e0db7cc 100644
--- a/chrome/browser/android/contextualsearch/contextual_search_context.cc
+++ b/chrome/browser/android/contextualsearch/contextual_search_context.cc
@@ -6,14 +6,13 @@
 
 ContextualSearchContext::ContextualSearchContext(
     const std::string& selected_text,
-    const bool use_resolved_search_term,
+    const std::string& home_country,
     const GURL& page_url,
     const std::string& encoding)
     : selected_text(selected_text),
-      use_resolved_search_term(use_resolved_search_term),
+      home_country(home_country),
       page_url(page_url),
-      encoding(encoding) {
-}
+      encoding(encoding) {}
 
 ContextualSearchContext::~ContextualSearchContext() {
 }
diff --git a/chrome/browser/android/contextualsearch/contextual_search_context.h b/chrome/browser/android/contextualsearch/contextual_search_context.h
index 325ec6d..436a114 100644
--- a/chrome/browser/android/contextualsearch/contextual_search_context.h
+++ b/chrome/browser/android/contextualsearch/contextual_search_context.h
@@ -15,13 +15,13 @@
 struct ContextualSearchContext {
  public:
   ContextualSearchContext(const std::string& selected_text,
-                          const bool use_resolved_search_term,
+                          const std::string& home_country,
                           const GURL& page_url,
                           const std::string& encoding);
   ~ContextualSearchContext();
 
   const std::string selected_text;
-  const bool use_resolved_search_term;
+  const std::string home_country;
   const GURL page_url;
   const std::string encoding;
 
diff --git a/chrome/browser/android/contextualsearch/contextual_search_delegate.cc b/chrome/browser/android/contextualsearch/contextual_search_delegate.cc
index 4e920ef..765b1651 100644
--- a/chrome/browser/android/contextualsearch/contextual_search_delegate.cc
+++ b/chrome/browser/android/contextualsearch/contextual_search_delegate.cc
@@ -101,22 +101,22 @@
 
 void ContextualSearchDelegate::StartSearchTermResolutionRequest(
     const std::string& selection,
-    bool use_resolved_search_term,
+    const std::string& home_country,
     content::WebContents* web_contents,
     bool may_send_base_page_url) {
   GatherSurroundingTextWithCallback(
-      selection, use_resolved_search_term, web_contents, may_send_base_page_url,
+      selection, home_country, web_contents, may_send_base_page_url,
       base::Bind(&ContextualSearchDelegate::StartSearchTermRequestFromSelection,
                  AsWeakPtr()));
 }
 
 void ContextualSearchDelegate::GatherAndSaveSurroundingText(
     const std::string& selection,
-    bool use_resolved_search_term,
+    const std::string& home_country,
     content::WebContents* web_contents,
     bool may_send_base_page_url) {
   GatherSurroundingTextWithCallback(
-      selection, use_resolved_search_term, web_contents, may_send_base_page_url,
+      selection, home_country, web_contents, may_send_base_page_url,
       base::Bind(&ContextualSearchDelegate::SaveSurroundingText, AsWeakPtr()));
   // TODO(donnd): clear the context here, since we're done with it (but risky).
 }
@@ -125,7 +125,7 @@
   DCHECK(context_.get());
   if (!context_.get())
     return;
-  GURL request_url(BuildRequestUrl(context_->selected_text));
+  GURL request_url(BuildRequestUrl(context_->home_country));
   DCHECK(request_url.is_valid());
 
   // Reset will delete any previous fetcher, and we won't get any callback.
@@ -219,14 +219,14 @@
       quick_action_category));
 }
 
-std::string ContextualSearchDelegate::BuildRequestUrl(std::string selection) {
+std::string ContextualSearchDelegate::BuildRequestUrl(
+    std::string home_country) {
   // TODO(donnd): Confirm this is the right way to handle TemplateURL fails.
   if (!template_url_service_ ||
       !template_url_service_->GetDefaultSearchProvider()) {
     return std::string();
   }
 
-  std::string selected_text(net::EscapeQueryParamValue(selection, true));
   TemplateURL* template_url = template_url_service_->GetDefaultSearchProvider();
 
   TemplateURLRef::SearchTermsArgs search_terms_args =
@@ -248,7 +248,7 @@
   }
 
   TemplateURLRef::SearchTermsArgs::ContextualSearchParams params(
-      kContextualSearchRequestVersion, contextual_cards_version, std::string());
+      kContextualSearchRequestVersion, contextual_cards_version, home_country);
 
   search_terms_args.contextual_search_params = params;
 
@@ -274,15 +274,14 @@
 
 void ContextualSearchDelegate::GatherSurroundingTextWithCallback(
     const std::string& selection,
-    bool use_resolved_search_term,
+    const std::string& home_country,
     content::WebContents* web_contents,
     bool may_send_base_page_url,
     HandleSurroundingsCallback callback) {
   // Immediately cancel any request that's in flight, since we're building a new
   // context (and the response disposes of any existing context).
   search_term_fetcher_.reset();
-  BuildContext(selection, use_resolved_search_term, web_contents,
-               may_send_base_page_url);
+  BuildContext(selection, home_country, web_contents, may_send_base_page_url);
   DCHECK(web_contents);
   RenderFrameHost* focused_frame = web_contents->GetFocusedFrame();
   if (focused_frame) {
@@ -293,11 +292,10 @@
   }
 }
 
-void ContextualSearchDelegate::BuildContext(
-    const std::string& selection,
-    bool use_resolved_search_term,
-    content::WebContents* web_contents,
-    bool may_send_base_page_url) {
+void ContextualSearchDelegate::BuildContext(const std::string& selection,
+                                            const std::string& home_country,
+                                            content::WebContents* web_contents,
+                                            bool may_send_base_page_url) {
   // Decide if the URL should be sent with the context.
   GURL page_url(web_contents->GetURL());
   GURL url_to_send;
@@ -307,8 +305,8 @@
     url_to_send = page_url;
   }
   std::string encoding(web_contents->GetEncoding());
-  context_.reset(new ContextualSearchContext(
-      selection, use_resolved_search_term, url_to_send, encoding));
+  context_.reset(new ContextualSearchContext(selection, home_country,
+                                             url_to_send, encoding));
 }
 
 void ContextualSearchDelegate::StartSearchTermRequestFromSelection(
diff --git a/chrome/browser/android/contextualsearch/contextual_search_delegate.h b/chrome/browser/android/contextualsearch/contextual_search_delegate.h
index 779f177..dde551b3 100644
--- a/chrome/browser/android/contextualsearch/contextual_search_delegate.h
+++ b/chrome/browser/android/contextualsearch/contextual_search_delegate.h
@@ -70,15 +70,14 @@
   // request. The "search term" is the best query to issue for a section of text
   // in the context of a web page. When the response is available the callback
   // specified in the constructor is run.
-  void StartSearchTermResolutionRequest(
-      const std::string& selection,
-      bool use_resolved_search_term,
-      content::WebContents* web_contents,
-      bool may_send_base_page_url);
+  void StartSearchTermResolutionRequest(const std::string& selection,
+                                        const std::string& home_country,
+                                        content::WebContents* web_contents,
+                                        bool may_send_base_page_url);
 
   // Gathers surrounding text and saves it locally for a future query.
   void GatherAndSaveSurroundingText(const std::string& selection,
-                                    bool use_resolved_search_term,
+                                    const std::string& home_country,
                                     content::WebContents* web_contents,
                                     bool may_send_base_page_url);
 
@@ -122,7 +121,7 @@
   // Builds the ContextualSearchContext in the current context from
   // the given parameters.
   void BuildContext(const std::string& selection,
-                    bool use_resolved_search_term,
+                    const std::string& home_country,
                     content::WebContents* web_contents,
                     bool may_send_base_page_url);
 
@@ -139,12 +138,11 @@
 
   // Will gather the surrounding text from the |content_view_core| and call the
   // |callback|.
-  void GatherSurroundingTextWithCallback(
-      const std::string& selection,
-      bool use_resolved_search_term,
-      content::WebContents* web_contents,
-      bool may_send_base_page_url,
-      HandleSurroundingsCallback callback);
+  void GatherSurroundingTextWithCallback(const std::string& selection,
+                                         const std::string& home_country,
+                                         content::WebContents* web_contents,
+                                         bool may_send_base_page_url,
+                                         HandleSurroundingsCallback callback);
 
   // Callback for GatherSurroundingTextWithCallback(). Will start the search
   // term resolution request.
diff --git a/chrome/browser/android/contextualsearch/contextual_search_delegate_unittest.cc b/chrome/browser/android/contextualsearch/contextual_search_delegate_unittest.cc
index f0f32f6..f373452 100644
--- a/chrome/browser/android/contextualsearch/contextual_search_delegate_unittest.cc
+++ b/chrome/browser/android/contextualsearch/contextual_search_delegate_unittest.cc
@@ -93,7 +93,7 @@
       int start_offset,
       int end_offset) {
     test_context_ = new ContextualSearchContext(
-        selected_text, true, GURL(kSomeSpecificBasePage), "utf-8");
+        selected_text, std::string(), GURL(kSomeSpecificBasePage), "utf-8");
     // ContextualSearchDelegate class takes ownership of the context.
     delegate_->set_context_for_testing(test_context_);
 
@@ -148,7 +148,7 @@
                              int start_offset,
                              int end_offset) {
     test_context_ = new ContextualSearchContext(
-        "Bogus", true, GURL(kSomeSpecificBasePage), "utf-8");
+        "Bogus", std::string(), GURL(kSomeSpecificBasePage), "utf-8");
     test_context_->surrounding_text = surrounding_text;
     test_context_->start_offset = start_offset;
     test_context_->end_offset = end_offset;
diff --git a/chrome/browser/android/contextualsearch/contextual_search_manager.cc b/chrome/browser/android/contextualsearch/contextual_search_manager.cc
index c9aab60f..9c96f5ec 100644
--- a/chrome/browser/android/contextualsearch/contextual_search_manager.cc
+++ b/chrome/browser/android/contextualsearch/contextual_search_manager.cc
@@ -66,7 +66,7 @@
     JNIEnv* env,
     const JavaParamRef<jobject>& obj,
     const JavaParamRef<jstring>& j_selection,
-    jboolean j_use_resolved_search_term,
+    const JavaParamRef<jstring>& j_home_country,
     const JavaParamRef<jobject>& j_base_web_contents,
     jboolean j_may_send_base_page_url) {
   WebContents* base_web_contents =
@@ -74,19 +74,19 @@
   DCHECK(base_web_contents);
   std::string selection(
       base::android::ConvertJavaStringToUTF8(env, j_selection));
-  bool use_resolved_search_term = j_use_resolved_search_term;
+  std::string home_country(
+      base::android::ConvertJavaStringToUTF8(env, j_home_country));
   bool may_send_base_page_url = j_may_send_base_page_url;
   // Calls back to OnSearchTermResolutionResponse.
   delegate_->StartSearchTermResolutionRequest(
-      selection, use_resolved_search_term, base_web_contents,
-      may_send_base_page_url);
+      selection, home_country, base_web_contents, may_send_base_page_url);
 }
 
 void ContextualSearchManager::GatherSurroundingText(
     JNIEnv* env,
     const JavaParamRef<jobject>& obj,
     const JavaParamRef<jstring>& j_selection,
-    jboolean j_use_resolved_search_term,
+    const JavaParamRef<jstring>& j_home_country,
     const JavaParamRef<jobject>& j_base_web_contents,
     jboolean j_may_send_base_page_url) {
   WebContents* base_web_contents =
@@ -94,11 +94,11 @@
   DCHECK(base_web_contents);
   std::string selection(
       base::android::ConvertJavaStringToUTF8(env, j_selection));
-  bool use_resolved_search_term = j_use_resolved_search_term;
+  std::string home_country(
+      base::android::ConvertJavaStringToUTF8(env, j_home_country));
   bool may_send_base_page_url = j_may_send_base_page_url;
-  delegate_->GatherAndSaveSurroundingText(selection, use_resolved_search_term,
-                                          base_web_contents,
-                                          may_send_base_page_url);
+  delegate_->GatherAndSaveSurroundingText(
+      selection, home_country, base_web_contents, may_send_base_page_url);
 }
 
 base::android::ScopedJavaLocalRef<jstring>
diff --git a/chrome/browser/android/contextualsearch/contextual_search_manager.h b/chrome/browser/android/contextualsearch/contextual_search_manager.h
index f0aa73b..f173376 100644
--- a/chrome/browser/android/contextualsearch/contextual_search_manager.h
+++ b/chrome/browser/android/contextualsearch/contextual_search_manager.h
@@ -39,7 +39,7 @@
       JNIEnv* env,
       const base::android::JavaParamRef<jobject>& obj,
       const base::android::JavaParamRef<jstring>& j_selection,
-      jboolean j_use_resolved_search_term,
+      const base::android::JavaParamRef<jstring>& j_home_country,
       const base::android::JavaParamRef<jobject>& j_base_web_contents,
       jboolean j_may_send_base_page_url);
 
@@ -49,7 +49,7 @@
       JNIEnv* env,
       const base::android::JavaParamRef<jobject>& obj,
       const base::android::JavaParamRef<jstring>& j_selection,
-      jboolean j_use_resolved_search_term,
+      const base::android::JavaParamRef<jstring>& j_home_country,
       const base::android::JavaParamRef<jobject>& j_base_web_contents,
       jboolean j_may_send_base_page_url);
 
diff --git a/chrome/browser/apps/guest_view/web_view_interactive_browsertest.cc b/chrome/browser/apps/guest_view/web_view_interactive_browsertest.cc
index 7a43d338..0cf066b 100644
--- a/chrome/browser/apps/guest_view/web_view_interactive_browsertest.cc
+++ b/chrome/browser/apps/guest_view/web_view_interactive_browsertest.cc
@@ -513,6 +513,7 @@
   }
 };
 
+class WebViewDragDropInteractiveTest : public WebViewInteractiveTest {};
 class WebViewNewWindowInteractiveTest : public WebViewInteractiveTest {};
 class WebViewPointerLockInteractiveTest : public WebViewInteractiveTest {};
 
@@ -524,13 +525,16 @@
 // with WebViewInteractiveTest (see crbug.com/582562).
 class WebViewFocusInteractiveTest : public WebViewInteractiveTestBase {};
 class WebViewPopupInteractiveTest : public WebViewInteractiveTestBase {};
-class WebViewDragDropInteractiveTest : public WebViewInteractiveTestBase {};
 
 INSTANTIATE_TEST_CASE_P(WebViewInteractiveTests,
                         WebViewInteractiveTest,
                         testing::Bool());
 
 INSTANTIATE_TEST_CASE_P(WebViewInteractiveTests,
+                        WebViewDragDropInteractiveTest,
+                        testing::Bool());
+
+INSTANTIATE_TEST_CASE_P(WebViewInteractiveTests,
                         WebViewNewWindowInteractiveTest,
                         testing::Bool());
 
@@ -1037,7 +1041,7 @@
 // but the tests don't work on anything except chromeos for now. This is because
 // of simulating mouse drag code's dependency on platforms.
 #if defined(OS_CHROMEOS) && !defined(USE_OZONE)
-IN_PROC_BROWSER_TEST_F(WebViewDragDropInteractiveTest, DragDropWithinWebView) {
+IN_PROC_BROWSER_TEST_P(WebViewDragDropInteractiveTest, DragDropWithinWebView) {
   LoadAndLaunchPlatformApp("web_view/dnd_within_webview", "connected");
   ASSERT_TRUE(ui_test_utils::ShowAndFocusNativeWindow(GetPlatformAppWindow()));
 
diff --git a/chrome/browser/chromeos/login/users/wallpaper/wallpaper_manager_browsertest.cc b/chrome/browser/chromeos/login/users/wallpaper/wallpaper_manager_browsertest.cc
index 7b81089..5aebe9eb 100644
--- a/chrome/browser/chromeos/login/users/wallpaper/wallpaper_manager_browsertest.cc
+++ b/chrome/browser/chromeos/login/users/wallpaper/wallpaper_manager_browsertest.cc
@@ -119,7 +119,7 @@
     SessionManager::Get()->CreateSession(account_id, user_id_hash);
     // Adding a secondary display creates a shelf on that display, which
     // assumes a shelf on the primary display if the user was logged in.
-    ash::WmShell::Get()->CreateShelf();
+    ash::WmShell::Get()->CreateShelfView();
     WaitAsyncWallpaperLoadStarted();
   }
 
diff --git a/chrome/browser/manifest/manifest_icon_selector.h b/chrome/browser/manifest/manifest_icon_selector.h
index 13fc4de..ae1f7e2 100644
--- a/chrome/browser/manifest/manifest_icon_selector.h
+++ b/chrome/browser/manifest/manifest_icon_selector.h
@@ -16,10 +16,7 @@
   // Runs the algorithm to find the best matching icon in the icons listed in
   // the Manifest.
   //
-  // Size is defined in Android's density-independent pixels (dp):
-  // http://developer.android.com/guide/practices/screens_support.html
-  // If/when this class is generalized, it may be a good idea to switch this to
-  // taking in pixels, instead.
+  // Size is defined in pixels.
   //
   // Any icon returned will be close as possible to |ideal_icon_size_in_px|
   // with a size not less than |minimum_icon_size_in_px|.
diff --git a/chrome/browser/resources/chromeos/login/oobe_welcome.js b/chrome/browser/resources/chromeos/login/oobe_welcome.js
index 6384059..e3c9d0cb 100644
--- a/chrome/browser/resources/chromeos/login/oobe_welcome.js
+++ b/chrome/browser/resources/chromeos/login/oobe_welcome.js
@@ -109,6 +109,31 @@
     },
   },
 
+  /** @override */
+  ready: function() {
+    CrOncStrings = {
+      OncTypeCellular: loadTimeData.getString('OncTypeCellular'),
+      OncTypeEthernet: loadTimeData.getString('OncTypeEthernet'),
+      OncTypeVPN: loadTimeData.getString('OncTypeVPN'),
+      OncTypeWiFi: loadTimeData.getString('OncTypeWiFi'),
+      OncTypeWiMAX: loadTimeData.getString('OncTypeWiMAX'),
+      networkDisabled: loadTimeData.getString('networkDisabled'),
+      networkListItemConnected:
+          loadTimeData.getString('networkListItemConnected'),
+      networkListItemConnecting:
+          loadTimeData.getString('networkListItemConnecting'),
+      networkListItemNotConnected:
+          loadTimeData.getString('networkListItemNotConnected'),
+      vpnNameTemplate: loadTimeData.getString('vpnNameTemplate'),
+
+      // Additional strings for custom items.
+      addMobileNetworkMenuName:
+          loadTimeData.getString('addMobileNetworkMenuName'),
+      addWiFiNetworkMenuName: loadTimeData.getString('addWiFiNetworkMenuName'),
+      proxySettingsMenuName: loadTimeData.getString('proxySettingsMenuName'),
+    };
+  },
+
   /**
    * Hides all screens to help switching from one screen to another.
    */
diff --git a/chrome/browser/resources/chromeos/network_ui/network_ui.js b/chrome/browser/resources/chromeos/network_ui/network_ui.js
index 347b7be..c51daec 100644
--- a/chrome/browser/resources/chromeos/network_ui/network_ui.js
+++ b/chrome/browser/resources/chromeos/network_ui/network_ui.js
@@ -5,6 +5,22 @@
 var NetworkUI = (function() {
   'use strict';
 
+  CrOncStrings = {
+    OncTypeCellular: loadTimeData.getString('OncTypeCellular'),
+    OncTypeEthernet: loadTimeData.getString('OncTypeEthernet'),
+    OncTypeVPN: loadTimeData.getString('OncTypeVPN'),
+    OncTypeWiFi: loadTimeData.getString('OncTypeWiFi'),
+    OncTypeWiMAX: loadTimeData.getString('OncTypeWiMAX'),
+    networkDisabled: loadTimeData.getString('networkDisabled'),
+    networkListItemConnected:
+        loadTimeData.getString('networkListItemConnected'),
+    networkListItemConnecting:
+        loadTimeData.getString('networkListItemConnecting'),
+    networkListItemNotConnected:
+        loadTimeData.getString('networkListItemNotConnected'),
+    vpnNameTemplate: loadTimeData.getString('vpnNameTemplate'),
+  };
+
   // Properties to display in the network state table. Each entry can be either
   // a single state field or an array of state fields. If more than one is
   // specified then the first non empty value is used.
diff --git a/chrome/browser/resources/settings/internet_page/internet_detail_page.js b/chrome/browser/resources/settings/internet_page/internet_detail_page.js
index 98c02b3..6fcc9697 100644
--- a/chrome/browser/resources/settings/internet_page/internet_detail_page.js
+++ b/chrome/browser/resources/settings/internet_page/internet_detail_page.js
@@ -198,8 +198,7 @@
     this.IPAddress_ = (ipv4 && ipv4.IPAddress) || '';
 
     // Update the detail page title.
-    this.parentNode.pageTitle =
-        CrOnc.getNetworkName(this.networkProperties, this);
+    this.parentNode.pageTitle = CrOnc.getNetworkName(this.networkProperties);
   },
 
   /** @private */
diff --git a/chrome/browser/resources/settings/settings_resources.grd b/chrome/browser/resources/settings/settings_resources.grd
index a3c554a..c4b54707 100644
--- a/chrome/browser/resources/settings/settings_resources.grd
+++ b/chrome/browser/resources/settings/settings_resources.grd
@@ -252,7 +252,9 @@
                  flattenhtml="true" />
       <structure name="IDR_SETTINGS_CR_SETTINGS_UI_HTML"
                  file="settings_ui/settings_ui.html"
-                 type="chrome_html" />
+                 type="chrome_html"
+                 flattenhtml="true"
+                 allowexternalscript="true" />
       <structure name="IDR_SETTINGS_CR_SETTINGS_UI_JS"
                  file="settings_ui/settings_ui.js"
                  type="chrome_html"
diff --git a/chrome/browser/resources/settings/settings_ui/compiled_resources2.gyp b/chrome/browser/resources/settings/settings_ui/compiled_resources2.gyp
index 4e2268e..3b836f0 100644
--- a/chrome/browser/resources/settings/settings_ui/compiled_resources2.gyp
+++ b/chrome/browser/resources/settings/settings_ui/compiled_resources2.gyp
@@ -9,6 +9,7 @@
         '<(DEPTH)/ui/webui/resources/cr_elements/cr_drawer/compiled_resources2.gyp:cr_drawer',
         '<(DEPTH)/ui/webui/resources/cr_elements/cr_toolbar/compiled_resources2.gyp:cr_toolbar',
         '<(DEPTH)/ui/webui/resources/cr_elements/cr_toolbar/compiled_resources2.gyp:cr_toolbar_search_field',
+        '<(DEPTH)/ui/webui/resources/cr_elements/network/compiled_resources2.gyp:cr_onc_types',
         '<(DEPTH)/ui/webui/resources/cr_elements/policy/compiled_resources2.gyp:cr_policy_indicator_behavior',
         '../compiled_resources2.gyp:direction_delegate',
         '../compiled_resources2.gyp:global_scroll_target_behavior',
diff --git a/chrome/browser/resources/settings/settings_ui/settings_ui.html b/chrome/browser/resources/settings/settings_ui/settings_ui.html
index 55c43e79..011015a 100644
--- a/chrome/browser/resources/settings/settings_ui/settings_ui.html
+++ b/chrome/browser/resources/settings/settings_ui/settings_ui.html
@@ -15,6 +15,10 @@
 <link rel="import" href="/route.html">
 <link rel="import" href="/settings_vars_css.html">
 
+<if expr="chromeos">
+<link rel="import" href="chrome://resources/cr_elements/network/cr_onc_types.html">
+</if>
+
 <dom-module id="settings-ui">
   <template>
     <style include="settings-shared">
diff --git a/chrome/browser/resources/settings/settings_ui/settings_ui.js b/chrome/browser/resources/settings/settings_ui/settings_ui.js
index 22fe0457..cb932754 100644
--- a/chrome/browser/resources/settings/settings_ui/settings_ui.js
+++ b/chrome/browser/resources/settings/settings_ui/settings_ui.js
@@ -101,6 +101,24 @@
 // </if>
     };
 
+// <if expr="chromeos">
+    CrOncStrings = {
+      OncTypeCellular: loadTimeData.getString('OncTypeCellular'),
+      OncTypeEthernet: loadTimeData.getString('OncTypeEthernet'),
+      OncTypeVPN: loadTimeData.getString('OncTypeVPN'),
+      OncTypeWiFi: loadTimeData.getString('OncTypeWiFi'),
+      OncTypeWiMAX: loadTimeData.getString('OncTypeWiMAX'),
+      networkDisabled: loadTimeData.getString('networkDisabled'),
+      networkListItemConnected:
+          loadTimeData.getString('networkListItemConnected'),
+      networkListItemConnecting:
+          loadTimeData.getString('networkListItemConnecting'),
+      networkListItemNotConnected:
+          loadTimeData.getString('networkListItemNotConnected'),
+      vpnNameTemplate: loadTimeData.getString('vpnNameTemplate'),
+    };
+// </if>
+
     if (loadTimeData.getBoolean('isGuest')) {
       this.pageVisibility_ = {
         people: false,
diff --git a/chrome/browser/sync/test/integration/two_client_uss_sync_test.cc b/chrome/browser/sync/test/integration/two_client_uss_sync_test.cc
index dbba60da..5ef52f81 100644
--- a/chrome/browser/sync/test/integration/two_client_uss_sync_test.cc
+++ b/chrome/browser/sync/test/integration/two_client_uss_sync_test.cc
@@ -65,7 +65,7 @@
 
   TestModelTypeSyncBridge()
       : FakeModelTypeSyncBridge(base::Bind(&ModelTypeChangeProcessor::Create)) {
-    change_processor()->OnMetadataLoaded(db().CreateMetadataBatch());
+    change_processor()->ModelReadyToSync(db().CreateMetadataBatch());
   }
 
   base::Optional<syncer::ModelError> ApplySyncChanges(
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn
index 8ebd7124..154b5cff 100644
--- a/chrome/browser/ui/BUILD.gn
+++ b/chrome/browser/ui/BUILD.gn
@@ -307,6 +307,8 @@
     "webui/chromeos/mobile_setup_dialog.h",
     "webui/chromeos/mobile_setup_ui.cc",
     "webui/chromeos/mobile_setup_ui.h",
+    "webui/chromeos/network_element_localized_strings_provider.cc",
+    "webui/chromeos/network_element_localized_strings_provider.h",
     "webui/chromeos/network_ui.cc",
     "webui/chromeos/network_ui.h",
     "webui/chromeos/power_ui.cc",
diff --git a/chrome/browser/ui/android/autofill/autofill_popup_view_android.cc b/chrome/browser/ui/android/autofill/autofill_popup_view_android.cc
index 6795ac7..c6d77bc 100644
--- a/chrome/browser/ui/android/autofill/autofill_popup_view_android.cc
+++ b/chrome/browser/ui/android/autofill/autofill_popup_view_android.cc
@@ -15,6 +15,7 @@
 #include "components/autofill/core/browser/popup_item_ids.h"
 #include "components/autofill/core/browser/suggestion.h"
 #include "components/autofill/core/common/autofill_util.h"
+#include "components/security_state/core/security_state.h"
 #include "content/public/browser/android/content_view_core.h"
 #include "jni/AutofillPopupBridge_jni.h"
 #include "ui/android/view_android.h"
@@ -96,9 +97,15 @@
 
     bool is_deletable =
         controller_->GetRemovalConfirmationText(i, nullptr, nullptr);
+    // In the Form-Not-Secure experiment, the payment disabled message
+    // is a short message that should be displayed the same as the other
+    // autofill suggestions. If this experiment is not enabled, then the
+    // payment disabled message should be allowed to span multiple
+    // lines.
     bool is_label_multiline =
-        suggestion.frontend_id ==
-            POPUP_ITEM_ID_INSECURE_CONTEXT_PAYMENT_DISABLED_MESSAGE ||
+        (!security_state::IsHttpWarningInFormEnabled() &&
+         suggestion.frontend_id ==
+             POPUP_ITEM_ID_INSECURE_CONTEXT_PAYMENT_DISABLED_MESSAGE) ||
         suggestion.frontend_id == POPUP_ITEM_ID_CREDIT_CARD_SIGNIN_PROMO;
     Java_AutofillPopupBridge_addToAutofillSuggestionArray(
         env, data_array, i, value, label, android_icon_id,
diff --git a/chrome/browser/ui/libgtkui/gtk_ui.cc b/chrome/browser/ui/libgtkui/gtk_ui.cc
index 9c25e84..9d9bd89 100644
--- a/chrome/browser/ui/libgtkui/gtk_ui.cc
+++ b/chrome/browser/ui/libgtkui/gtk_ui.cc
@@ -687,17 +687,14 @@
       owning_button->GetClassName() == views::BlueButton::kViewClassName;
 
   for (unsigned i = 0; i < arraysize(paintstate); i++) {
-    views::Painter* painter = nullptr;
-
     if (border->PaintsButtonState(paintstate[i].focus, paintstate[i].state)) {
       std::string idr = is_blue ? paintstate[i].idr_blue : paintstate[i].idr;
-      painter = new GtkButtonPainter(idr);
+      gtk_border->SetPainter(paintstate[i].focus, paintstate[i].state,
+                             base::MakeUnique<GtkButtonPainter>(idr));
     }
-
-    gtk_border->SetPainter(paintstate[i].focus, paintstate[i].state, painter);
   }
 
-  return std::move(gtk_border);
+  return gtk_border;
 }
 
 void GtkUi::AddWindowButtonOrderObserver(
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 6192515..662fe9f0 100644
--- a/chrome/browser/ui/views/payments/payment_request_views_util.cc
+++ b/chrome/browser/ui/views/payments/payment_request_views_util.cc
@@ -4,18 +4,46 @@
 
 #include "chrome/browser/ui/views/payments/payment_request_views_util.h"
 
+#include <vector>
+
 #include "base/memory/ptr_util.h"
+#include "base/strings/utf_string_conversions.h"
 #include "chrome/app/vector_icons/vector_icons.h"
 #include "chrome/browser/ui/views/payments/payment_request_sheet_controller.h"
+#include "components/autofill/core/browser/autofill_profile.h"
+#include "components/autofill/core/browser/autofill_type.h"
+#include "components/autofill/core/browser/field_types.h"
 #include "third_party/skia/include/core/SkColor.h"
 #include "ui/views/background.h"
 #include "ui/views/bubble/bubble_frame_view.h"
 #include "ui/views/controls/button/button.h"
 #include "ui/views/controls/button/vector_icon_button.h"
 #include "ui/views/controls/label.h"
+#include "ui/views/controls/styled_label.h"
 #include "ui/views/layout/grid_layout.h"
 #include "ui/views/view.h"
 
+namespace {
+
+// TODO(tmartino): Consider combining this with the Android equivalent in
+// PersonalDataManager.java
+base::string16 GetAddressFromProfile(const autofill::AutofillProfile& profile,
+                                     const std::string& locale) {
+  std::vector<autofill::ServerFieldType> fields;
+  fields.push_back(autofill::COMPANY_NAME);
+  fields.push_back(autofill::ADDRESS_HOME_LINE1);
+  fields.push_back(autofill::ADDRESS_HOME_LINE2);
+  fields.push_back(autofill::ADDRESS_HOME_DEPENDENT_LOCALITY);
+  fields.push_back(autofill::ADDRESS_HOME_CITY);
+  fields.push_back(autofill::ADDRESS_HOME_STATE);
+  fields.push_back(autofill::ADDRESS_HOME_ZIP);
+  fields.push_back(autofill::ADDRESS_HOME_SORTING_CODE);
+
+  return profile.ConstructInferredLabel(fields, fields.size(), locale);
+}
+
+}  // namespace
+
 namespace payments {
 
 std::unique_ptr<views::View> CreateSheetHeaderView(
@@ -87,4 +115,70 @@
   return view;
 }
 
+std::unique_ptr<views::View> GetShippingAddressLabel(
+    AddressStyleType type,
+    const std::string& locale,
+    const autofill::AutofillProfile& profile) {
+  base::string16 name_value =
+      profile.GetInfo(autofill::AutofillType(autofill::NAME_FULL), locale);
+
+  // TODO(tmartino): Add bold styling for name in DETAILED style.
+
+  base::string16 address_value = GetAddressFromProfile(profile, locale);
+
+  base::string16 phone_value = profile.GetInfo(
+      autofill::AutofillType(autofill::PHONE_HOME_WHOLE_NUMBER), locale);
+
+  std::vector<base::string16> values;
+  if (!name_value.empty())
+    values.push_back(name_value);
+  if (!address_value.empty())
+    values.push_back(address_value);
+  if (!phone_value.empty())
+    values.push_back(phone_value);
+
+  return base::MakeUnique<views::StyledLabel>(
+      base::JoinString(values, base::ASCIIToUTF16("\n")), nullptr);
+}
+
+std::unique_ptr<views::View> GetContactInfoLabel(
+    AddressStyleType type,
+    const std::string& locale,
+    const autofill::AutofillProfile& profile,
+    bool show_payer_name,
+    bool show_payer_email,
+    bool show_payer_phone) {
+  base::string16 name_value;
+  base::string16 phone_value;
+  base::string16 email_value;
+
+  if (show_payer_name) {
+    name_value =
+        profile.GetInfo(autofill::AutofillType(autofill::NAME_FULL), locale);
+
+    // TODO(tmartino): Add bold styling for name in DETAILED style.
+  }
+
+  if (show_payer_phone) {
+    phone_value = profile.GetInfo(
+        autofill::AutofillType(autofill::PHONE_HOME_WHOLE_NUMBER), locale);
+  }
+
+  if (show_payer_email) {
+    email_value = profile.GetInfo(
+        autofill::AutofillType(autofill::EMAIL_ADDRESS), locale);
+  }
+
+  std::vector<base::string16> values;
+  if (!name_value.empty())
+    values.push_back(name_value);
+  if (!phone_value.empty())
+    values.push_back(phone_value);
+  if (!email_value.empty())
+    values.push_back(email_value);
+
+  return base::MakeUnique<views::StyledLabel>(
+      base::JoinString(values, base::ASCIIToUTF16("\n")), nullptr);
+}
+
 }  // namespace payments
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 d72f6ead..9176241 100644
--- a/chrome/browser/ui/views/payments/payment_request_views_util.h
+++ b/chrome/browser/ui/views/payments/payment_request_views_util.h
@@ -6,9 +6,14 @@
 #define CHROME_BROWSER_UI_VIEWS_PAYMENTS_PAYMENT_REQUEST_VIEWS_UTIL_H_
 
 #include <memory>
+#include <string>
 
 #include "base/strings/string16.h"
 
+namespace autofill {
+class AutofillProfile;
+}
+
 namespace views {
 class VectorIconButtonDelegate;
 class View;
@@ -54,6 +59,28 @@
     std::unique_ptr<views::View> header_view,
     std::unique_ptr<views::View> content_view);
 
+// Represents formatting options for each of the different contexts in which an
+// Address label may be displayed.
+enum class AddressStyleType { SUMMARY, DETAILED };
+
+// Extracts and formats descriptive text from the given |profile| to represent
+// the address in the context specified by |type|.
+std::unique_ptr<views::View> GetShippingAddressLabel(
+    AddressStyleType type,
+    const std::string& locale,
+    const autofill::AutofillProfile& profile);
+
+// Extracts and formats descriptive text from the given |profile| to represent
+// the contact info in the context specified by |type|. Includes/excludes name,
+// email, and phone fields according to the respective boolean fields.
+std::unique_ptr<views::View> GetContactInfoLabel(
+    AddressStyleType type,
+    const std::string& locale,
+    const autofill::AutofillProfile& profile,
+    bool show_payer_name,
+    bool show_payer_email,
+    bool show_payer_phone);
+
 }  // namespace payments
 
 #endif  // CHROME_BROWSER_UI_VIEWS_PAYMENTS_PAYMENT_REQUEST_VIEWS_UTIL_H_
diff --git a/chrome/browser/ui/views/payments/payment_sheet_view_controller.cc b/chrome/browser/ui/views/payments/payment_sheet_view_controller.cc
index 0484ef69..1fbb4bcf 100644
--- a/chrome/browser/ui/views/payments/payment_sheet_view_controller.cc
+++ b/chrome/browser/ui/views/payments/payment_sheet_view_controller.cc
@@ -7,8 +7,10 @@
 #include <algorithm>
 #include <memory>
 #include <utility>
+#include <vector>
 
 #include "base/memory/ptr_util.h"
+#include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/ui/views/payments/payment_request_dialog.h"
@@ -46,11 +48,15 @@
 namespace payments {
 namespace {
 
+constexpr int kFirstTagValue = static_cast<int>(
+    payments::PaymentRequestCommonTags::PAYMENT_REQUEST_COMMON_TAG_MAX);
+
 enum class PaymentSheetViewControllerTags {
   // The tag for the button that navigates to the Order Summary sheet.
-  SHOW_ORDER_SUMMARY_BUTTON = static_cast<int>(
-      payments::PaymentRequestCommonTags::PAYMENT_REQUEST_COMMON_TAG_MAX),
+  SHOW_ORDER_SUMMARY_BUTTON = kFirstTagValue,
+  SHOW_SHIPPING_BUTTON,
   SHOW_PAYMENT_METHOD_BUTTON,
+  SHOW_CONTACT_INFO_BUTTON,
 };
 
 // Creates a clickable row to be displayed in the Payment Sheet. It contains
@@ -129,6 +135,7 @@
     layout->AddView(chevron);
   }
 
+ private:
   DISALLOW_COPY_AND_ASSIGN(PaymentSheetRow);
 };
 
@@ -139,10 +146,10 @@
   // correct size. To measure the required size, layout a label with each
   // section name, measure its width, then initialize |widest_column_width|
   // with the largest value.
-  std::vector<int> section_names {
-    IDS_PAYMENT_REQUEST_ORDER_SUMMARY_SECTION_NAME,
-    IDS_PAYMENT_REQUEST_PAYMENT_METHOD_SECTION_NAME,
-  };
+  std::vector<int> section_names{
+      IDS_PAYMENT_REQUEST_ORDER_SUMMARY_SECTION_NAME,
+      IDS_PAYMENT_REQUEST_PAYMENT_METHOD_SECTION_NAME,
+      IDS_PAYMENT_REQUEST_SHIPPING_SECTION_NAME};
 
   int widest_column_width = 0;
 
@@ -178,8 +185,12 @@
 
   layout->StartRow(0, 0);
   layout->AddView(CreatePaymentSheetSummaryRow().release());
+  layout->StartRow(1, 0);
+  layout->AddView(CreateShippingRow().release());
   layout->StartRow(0, 0);
   layout->AddView(CreatePaymentMethodRow().release());
+  layout->StartRow(1, 0);
+  layout->AddView(CreateContactInfoRow().release());
 
   return CreatePaymentView(
       CreateSheetHeaderView(
@@ -195,14 +206,26 @@
     case static_cast<int>(PaymentRequestCommonTags::CLOSE_BUTTON_TAG):
       dialog()->CloseDialog();
       break;
+
     case static_cast<int>(
         PaymentSheetViewControllerTags::SHOW_ORDER_SUMMARY_BUTTON):
       dialog()->ShowOrderSummary();
       break;
+
+    case static_cast<int>(PaymentSheetViewControllerTags::SHOW_SHIPPING_BUTTON):
+      // TODO(tmartino): Transition to shipping page once it exists.
+      break;
+
     case static_cast<int>(
         PaymentSheetViewControllerTags::SHOW_PAYMENT_METHOD_BUTTON):
       dialog()->ShowPaymentMethodSheet();
       break;
+
+    case static_cast<int>(
+        PaymentSheetViewControllerTags::SHOW_CONTACT_INFO_BUTTON):
+      // TODO(tmartino): Transition to contact info page once it exists.
+      break;
+
     default:
       NOTREACHED();
   }
@@ -241,6 +264,35 @@
   return section;
 }
 
+std::unique_ptr<views::View>
+PaymentSheetViewController::CreateShippingSectionContent() {
+  auto profile = request()->GetCurrentlySelectedProfile();
+
+  // TODO(tmartino): Empty string param is app locale; this should be passed
+  // at construct-time and stored as a member in a future CL.
+  return profile ? payments::GetShippingAddressLabel(AddressStyleType::SUMMARY,
+                                                     std::string(), *profile)
+                 : base::MakeUnique<views::Label>(base::string16());
+}
+
+// Creates the Shipping row, which contains a "Shipping address" label, the
+// user's selected shipping address, and a chevron.
+// +----------------------------------------------+
+// | Shipping Address   Barack Obama              |
+// |                    1600 Pennsylvania Ave.  > |
+// |                    1800MYPOTUS               |
+// +----------------------------------------------+
+std::unique_ptr<views::Button> PaymentSheetViewController::CreateShippingRow() {
+  std::unique_ptr<views::Button> section = base::MakeUnique<PaymentSheetRow>(
+      this,
+      l10n_util::GetStringUTF16(IDS_PAYMENT_REQUEST_SHIPPING_SECTION_NAME),
+      CreateShippingSectionContent(), std::unique_ptr<views::View>(nullptr),
+      widest_name_column_view_width_);
+  section->set_tag(
+      static_cast<int>(PaymentSheetViewControllerTags::SHOW_SHIPPING_BUTTON));
+  return section;
+}
+
 // Creates the Payment Method row, which contains a "Payment" label, the user's
 // masked Credit Card details, the icon for the selected card, and a chevron.
 // +----------------------------------------------+
@@ -297,4 +349,33 @@
   return section;
 }
 
+std::unique_ptr<views::View>
+PaymentSheetViewController::CreateContactInfoSectionContent() {
+  auto profile = request()->GetCurrentlySelectedProfile();
+  // TODO(tmartino): Replace empty string with app locale.
+  return profile ? payments::GetContactInfoLabel(AddressStyleType::SUMMARY,
+                                                 std::string(), *profile, true,
+                                                 true, true)
+                 : base::MakeUnique<views::Label>(base::string16());
+}
+
+// Creates the Contact Info row, which contains a "Contact info" label; the
+// name, email address, and/or phone number; and a chevron.
+// +----------------------------------------------+
+// | Contact info       Barack Obama              |
+// |                    1800MYPOTUS             > |
+// |                    potus@whitehouse.gov      |
+// +----------------------------------------------+
+std::unique_ptr<views::Button>
+PaymentSheetViewController::CreateContactInfoRow() {
+  std::unique_ptr<views::Button> section = base::MakeUnique<PaymentSheetRow>(
+      this,
+      l10n_util::GetStringUTF16(IDS_PAYMENT_REQUEST_CONTACT_INFO_SECTION_NAME),
+      CreateContactInfoSectionContent(), std::unique_ptr<views::View>(nullptr),
+      widest_name_column_view_width_);
+  section->set_tag(static_cast<int>(
+      PaymentSheetViewControllerTags::SHOW_CONTACT_INFO_BUTTON));
+  return section;
+}
+
 }  // namespace payments
diff --git a/chrome/browser/ui/views/payments/payment_sheet_view_controller.h b/chrome/browser/ui/views/payments/payment_sheet_view_controller.h
index c6b12961..8e0a08c9 100644
--- a/chrome/browser/ui/views/payments/payment_sheet_view_controller.h
+++ b/chrome/browser/ui/views/payments/payment_sheet_view_controller.h
@@ -5,6 +5,8 @@
 #ifndef CHROME_BROWSER_UI_VIEWS_PAYMENTS_PAYMENT_SHEET_VIEW_CONTROLLER_H_
 #define CHROME_BROWSER_UI_VIEWS_PAYMENTS_PAYMENT_SHEET_VIEW_CONTROLLER_H_
 
+#include <memory>
+
 #include "base/macros.h"
 #include "chrome/browser/ui/views/payments/payment_request_sheet_controller.h"
 #include "ui/views/controls/button/vector_icon_button_delegate.h"
@@ -32,8 +34,12 @@
   void ButtonPressed(views::Button* sender, const ui::Event& event) override;
 
   std::unique_ptr<views::View> CreateOrderSummarySectionContent();
+  std::unique_ptr<views::View> CreateShippingSectionContent();
+  std::unique_ptr<views::Button> CreateShippingRow();
   std::unique_ptr<views::Button> CreatePaymentSheetSummaryRow();
   std::unique_ptr<views::Button> CreatePaymentMethodRow();
+  std::unique_ptr<views::View> CreateContactInfoSectionContent();
+  std::unique_ptr<views::Button> CreateContactInfoRow();
 
   const int widest_name_column_view_width_;
 
diff --git a/chrome/browser/ui/views/toolbar/browser_actions_container.cc b/chrome/browser/ui/views/toolbar/browser_actions_container.cc
index 87fc688..ba8992f 100644
--- a/chrome/browser/ui/views/toolbar/browser_actions_container.cc
+++ b/chrome/browser/ui/views/toolbar/browser_actions_container.cc
@@ -95,8 +95,8 @@
     AddChildView(resize_area_);
 
     const int kWarningImages[] = IMAGE_GRID(IDR_DEVELOPER_MODE_HIGHLIGHT);
-    warning_highlight_painter_.reset(
-        views::Painter::CreateImageGridPainter(kWarningImages));
+    warning_highlight_painter_ =
+        views::Painter::CreateImageGridPainter(kWarningImages);
   }
 }
 
diff --git a/chrome/browser/ui/webui/chromeos/login/oobe_ui.cc b/chrome/browser/ui/webui/chromeos/login/oobe_ui.cc
index 587d761..7dc1f89 100644
--- a/chrome/browser/ui/webui/chromeos/login/oobe_ui.cc
+++ b/chrome/browser/ui/webui/chromeos/login/oobe_ui.cc
@@ -57,8 +57,8 @@
 #include "chrome/browser/ui/webui/chromeos/login/user_board_screen_handler.h"
 #include "chrome/browser/ui/webui/chromeos/login/user_image_screen_handler.h"
 #include "chrome/browser/ui/webui/chromeos/login/wrong_hwid_screen_handler.h"
+#include "chrome/browser/ui/webui/chromeos/network_element_localized_strings_provider.h"
 #include "chrome/browser/ui/webui/options/chromeos/user_image_source.h"
-#include "chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.h"
 #include "chrome/browser/ui/webui/test_files_request_filter.h"
 #include "chrome/browser/ui/webui/theme_source.h"
 #include "chrome/common/chrome_constants.h"
@@ -361,7 +361,7 @@
   content::WebUIDataSource* html_source =
       CreateOobeUIDataSource(localized_strings, display_type_);
   content::WebUIDataSource::Add(profile, html_source);
-  settings::AddCrNetworkStrings(html_source);
+  network_element::AddLocalizedStrings(html_source);
 
   // Set up the chrome://userimage/ source.
   options::UserImageSource* user_image_source =
diff --git a/chrome/browser/ui/webui/chromeos/network_element_localized_strings_provider.cc b/chrome/browser/ui/webui/chromeos/network_element_localized_strings_provider.cc
new file mode 100644
index 0000000..e61fb85
--- /dev/null
+++ b/chrome/browser/ui/webui/chromeos/network_element_localized_strings_provider.cc
@@ -0,0 +1,35 @@
+// 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/webui/chromeos/network_element_localized_strings_provider.h"
+
+#include "build/build_config.h"
+#include "chrome/grit/generated_resources.h"
+#include "content/public/browser/web_ui_data_source.h"
+
+namespace chromeos {
+namespace network_element {
+
+void AddLocalizedStrings(content::WebUIDataSource* html_source) {
+  struct {
+    const char* name;
+    int id;
+  } localized_strings[] = {
+      {"OncTypeCellular", IDS_NETWORK_TYPE_CELLULAR},
+      {"OncTypeEthernet", IDS_NETWORK_TYPE_ETHERNET},
+      {"OncTypeVPN", IDS_NETWORK_TYPE_VPN},
+      {"OncTypeWiFi", IDS_NETWORK_TYPE_WIFI},
+      {"OncTypeWiMAX", IDS_NETWORK_TYPE_WIMAX},
+      {"networkDisabled", IDS_NETWORK_LIST_DISABLED},
+      {"networkListItemConnected", IDS_NETWORK_LIST_CONNECTED},
+      {"networkListItemConnecting", IDS_NETWORK_LIST_CONNECTING},
+      {"networkListItemNotConnected", IDS_NETWORK_LIST_NOT_CONNECTED},
+      {"vpnNameTemplate", IDS_NETWORK_LIST_THIRD_PARTY_VPN_NAME_TEMPLATE},
+  };
+  for (const auto& entry : localized_strings)
+    html_source->AddLocalizedString(entry.name, entry.id);
+}
+
+}  // namespace network_element
+}  // namespace chromeos
diff --git a/chrome/browser/ui/webui/chromeos/network_element_localized_strings_provider.h b/chrome/browser/ui/webui/chromeos/network_element_localized_strings_provider.h
new file mode 100644
index 0000000..cbf0652
--- /dev/null
+++ b/chrome/browser/ui/webui/chromeos/network_element_localized_strings_provider.h
@@ -0,0 +1,22 @@
+// 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_WEBUI_CHROMEOS_NETWORK_ELEMENT_LOCALIZED_STRINGS_PROVIDER_H_
+#define CHROME_BROWSER_UI_WEBUI_CHROMEOS_NETWORK_ELEMENT_LOCALIZED_STRINGS_PROVIDER_H_
+
+namespace content {
+class WebUIDataSource;
+}
+
+namespace chromeos {
+namespace network_element {
+
+// Adds the strings needed for network elements to |html_source|. String ids
+// correspond to matching ids in ui/webui/resources/cr_elements/network/.
+void AddLocalizedStrings(content::WebUIDataSource* html_source);
+
+}  // namespace network_element
+}  // namespace chromeos
+
+#endif  // CHROME_BROWSER_UI_WEBUI_CHROMEOS_NETWORK_ELEMENT_LOCALIZED_STRINGS_PROVIDER_H_
diff --git a/chrome/browser/ui/webui/chromeos/network_ui.cc b/chrome/browser/ui/webui/chromeos/network_ui.cc
index 59d49bec..f8ca248 100644
--- a/chrome/browser/ui/webui/chromeos/network_ui.cc
+++ b/chrome/browser/ui/webui/chromeos/network_ui.cc
@@ -13,7 +13,7 @@
 #include "base/values.h"
 #include "chrome/browser/chromeos/options/network_config_view.h"
 #include "chrome/browser/extensions/tab_helper.h"
-#include "chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.h"
+#include "chrome/browser/ui/webui/chromeos/network_element_localized_strings_provider.h"
 #include "chrome/common/url_constants.h"
 #include "chrome/grit/browser_resources.h"
 #include "chrome/grit/generated_resources.h"
@@ -214,7 +214,7 @@
       content::WebUIDataSource::Create(chrome::kChromeUINetworkHost);
   html->AddLocalizedStrings(localized_strings);
 
-  settings::AddCrNetworkStrings(html);
+  network_element::AddLocalizedStrings(html);
 
   html->SetJsonPath("strings.js");
   html->AddResourcePath("network_ui.css", IDR_NETWORK_UI_CSS);
diff --git a/chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.cc b/chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.cc
index b921e911..11fd724 100644
--- a/chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.cc
+++ b/chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.cc
@@ -35,6 +35,7 @@
 #if defined(OS_CHROMEOS)
 #include "ash/common/system/chromeos/devicetype_utils.h"
 #include "chrome/browser/chromeos/profiles/profile_helper.h"
+#include "chrome/browser/ui/webui/chromeos/network_element_localized_strings_provider.h"
 #include "chrome/browser/ui/webui/chromeos/ui_account_tweaks.h"
 #include "chromeos/chromeos_switches.h"
 #include "components/user_manager/user.h"
@@ -1752,19 +1753,8 @@
                           arraysize(localized_strings));
 }
 
-}  // namespace
-
 #if defined(OS_CHROMEOS)
-void AddCrNetworkStrings(content::WebUIDataSource* html_source) {
-  LocalizedString localized_strings[] = {
-      {"networkDisabled", IDS_NETWORK_LIST_DISABLED},
-      {"networkListItemConnected", IDS_NETWORK_LIST_CONNECTED},
-      {"networkListItemConnecting", IDS_NETWORK_LIST_CONNECTING},
-      {"networkListItemNotConnected", IDS_NETWORK_LIST_NOT_CONNECTED},
-      {"vpnNameTemplate", IDS_NETWORK_LIST_THIRD_PARTY_VPN_NAME_TEMPLATE},
-  };
-  AddLocalizedStringsBulk(html_source, localized_strings,
-                          arraysize(localized_strings));
+void AddOncStrings(content::WebUIDataSource* html_source) {
   LocalizedString onc_property_strings[] = {
       // Thes strings are generated by prepending 'Onc' to the ONC property
       // name. Any '.' in the property name is replaced with '-'. Properties
@@ -1809,11 +1799,6 @@
       {"OncMacAddress", IDS_ONC_MAC_ADDRESS},
       {"OncNotConnected", IDS_ONC_NOT_CONNECTED},
       {"OncRestrictedConnectivity", IDS_ONC_RESTRICTED_CONNECTIVITY},
-      {"OncTypeCellular", IDS_SETTINGS_NETWORK_TYPE_CELLULAR},
-      {"OncTypeEthernet", IDS_SETTINGS_NETWORK_TYPE_ETHERNET},
-      {"OncTypeVPN", IDS_SETTINGS_NETWORK_TYPE_VPN},
-      {"OncTypeWiFi", IDS_SETTINGS_NETWORK_TYPE_WIFI},
-      {"OncTypeWiMAX", IDS_SETTINGS_NETWORK_TYPE_WIMAX},
       {"OncVPN-Host", IDS_ONC_VPN_HOST},
       {"OncVPN-L2TP-Username", IDS_ONC_VPN_L2TP_USERNAME},
       {"OncVPN-OpenVPN-Username", IDS_ONC_VPN_OPEN_VPN_USERNAME},
@@ -1834,6 +1819,8 @@
 }
 #endif  // OS_CHROMEOS
 
+}  // namespace
+
 void AddLocalizedStrings(content::WebUIDataSource* html_source,
                          Profile* profile) {
   AddA11yStrings(html_source);
@@ -1860,12 +1847,12 @@
   AddAccountUITweaksStrings(html_source, profile);
   AddAndroidAppStrings(html_source);
   AddBluetoothStrings(html_source);
-  AddCrNetworkStrings(html_source);
   AddDateTimeStrings(html_source);
   AddDeviceStrings(html_source);
   AddEasyUnlockStrings(html_source);
   AddInternetStrings(html_source);
   AddMultiProfilesStrings(html_source, profile);
+  AddOncStrings(html_source);
 #else
   AddDefaultBrowserStrings(html_source);
   AddImportDataStrings(html_source);
@@ -1876,6 +1863,9 @@
   AddCertificateManagerStrings(html_source);
 #endif
 
+#if defined(OS_CHROMEOS)
+  chromeos::network_element::AddLocalizedStrings(html_source);
+#endif
   policy_indicator::AddLocalizedStrings(html_source);
 
   html_source->SetJsonPath(kLocalizedStringsFile);
diff --git a/chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.h b/chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.h
index c97bf10..cfa3786 100644
--- a/chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.h
+++ b/chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.h
@@ -13,11 +13,6 @@
 
 namespace settings {
 
-#if defined(OS_CHROMEOS)
-// Strings specific to cr-network elements. Also used by NetworkUI and OobeUI.
-void AddCrNetworkStrings(content::WebUIDataSource* html_source);
-#endif  // OS_CHROMEOS
-
 // Adds the strings needed by the settings page to |html_source|. This function
 // causes |html_source| to expose a strings.js file from its source which
 // contains a mapping from string's name to its translated value.
diff --git a/chromeos/dbus/auth_policy_client.cc b/chromeos/dbus/auth_policy_client.cc
index 43578e3..52d7cc9a 100644
--- a/chromeos/dbus/auth_policy_client.cc
+++ b/chromeos/dbus/auth_policy_client.cc
@@ -14,6 +14,10 @@
 
 namespace {
 
+// The first device policy fetch after joining Active Directory can be very slow
+// because machine credentials need to propagate through the AD deployment.
+const int kRefreshDevicePolicyTimeoutMilliseconds = 90000;
+
 authpolicy::ErrorType GetErrorFromReader(dbus::MessageReader* reader) {
   int32_t int_error;
   if (!reader->PopInt32(&int_error)) {
@@ -64,7 +68,7 @@
     dbus::MethodCall method_call(authpolicy::kAuthPolicyInterface,
                                  authpolicy::kAuthPolicyRefreshDevicePolicy);
     proxy_->CallMethod(
-        &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
+        &method_call, kRefreshDevicePolicyTimeoutMilliseconds,
         base::Bind(&AuthPolicyClientImpl::HandleRefreshPolicyCallback,
                    weak_ptr_factory_.GetWeakPtr(), callback));
   }
@@ -98,7 +102,8 @@
       callback.Run(false);
       return;
     }
-    callback.Run(true);
+    dbus::MessageReader reader(response);
+    callback.Run(GetErrorFromReader(&reader) == authpolicy::ERROR_NONE);
   }
 
   void HandleJoinCallback(const JoinCallback& callback,
diff --git a/components/arc/arc_features.cc b/components/arc/arc_features.cc
index 7b656d4..5e3f68ff 100644
--- a/components/arc/arc_features.cc
+++ b/components/arc/arc_features.cc
@@ -8,7 +8,7 @@
 
 // Controls if Arc should use silent auth code request API.
 const base::Feature kArcUseAuthEndpointFeature {
-    "ArcUseAuthEndpoint", base::FEATURE_DISABLED_BY_DEFAULT
+    "ArcUseAuthEndpoint", base::FEATURE_ENABLED_BY_DEFAULT
 };
 
 // Controls ACTION_BOOT_COMPLETED broadcast for third party applications on ARC.
diff --git a/components/autofill/android/java/res/values/colors.xml b/components/autofill/android/java/res/values/colors.xml
index 6f68255e..8b10dd3a 100644
--- a/components/autofill/android/java/res/values/colors.xml
+++ b/components/autofill/android/java/res/values/colors.xml
@@ -6,6 +6,6 @@
 -->
 <resources>
 	<!-- Text colors of warning messages for credit card and password forms. -->
-	<color name="http_bad_warning_message_text">#C53929</color>
-
-</resources>
\ No newline at end of file
+    <color name="http_bad_warning_message_text">#C53929</color>
+    <color name="insecure_context_payment_disabled_message_text">#646464</color>
+</resources>
diff --git a/components/autofill/android/java/res/values/dimens.xml b/components/autofill/android/java/res/values/dimens.xml
index 9e38726..82d8c5e07 100644
--- a/components/autofill/android/java/res/values/dimens.xml
+++ b/components/autofill/android/java/res/values/dimens.xml
@@ -16,9 +16,12 @@
     <dimen name="keyboard_accessory_padding">8dp</dimen>
     <dimen name="keyboard_accessory_text_size">14sp</dimen>
 
-    <!-- 
-         Smaller label font size for http not secure warning messages of credit 
-         card and password forms, when users are on http sites. 
+    <!--
+         Larger label and icon sizes for Form-Not-Secure experiment
+         (warning messages on credit card and password forms when users
+         are on HTTP sites).
     -->
-    <dimen name="dropdown_item_smaller_label_font_size">14sp</dimen>
+    <dimen name="dropdown_item_larger_sublabel_font_size">18sp</dimen>
+    <dimen name="dropdown_large_icon_size">24dp</dimen>
+    <dimen name="dropdown_large_icon_margin">10dp</dimen>
 </resources>
diff --git a/components/autofill/android/java/src/org/chromium/components/autofill/AutofillSuggestion.java b/components/autofill/android/java/src/org/chromium/components/autofill/AutofillSuggestion.java
index ec5efc7e..21d4b89 100644
--- a/components/autofill/android/java/src/org/chromium/components/autofill/AutofillSuggestion.java
+++ b/components/autofill/android/java/src/org/chromium/components/autofill/AutofillSuggestion.java
@@ -11,10 +11,11 @@
  */
 public class AutofillSuggestion extends DropdownItemBase {
     /**
-     * The constant used to specify a http warning message in a list of Autofill suggestions.
+     * The constant used to specify warning messages in a list of Autofill suggestions.
      * Has to be kept in sync with {@code POPUP_ITEM_ID_SEPARATOR} enum in
      * components/autofill/core/browser/popup_item_ids.h
      */
+    private static final int ITEM_ID_INSECURE_CONTEXT_PAYMENT_DISABLED_MESSAGE = -1;
     private static final int ITEM_ID_HTTP_NOT_SECURE_WARNING_MESSAGE = -10;
 
     private final String mLabel;
@@ -80,16 +81,18 @@
     public int getLabelFontColorResId() {
         if (mSuggestionId == ITEM_ID_HTTP_NOT_SECURE_WARNING_MESSAGE) {
             return R.color.http_bad_warning_message_text;
+        } else if (mSuggestionId == ITEM_ID_INSECURE_CONTEXT_PAYMENT_DISABLED_MESSAGE) {
+            return R.color.insecure_context_payment_disabled_message_text;
         }
         return super.getLabelFontColorResId();
     }
 
     @Override
-    public int getLabelFontSizeResId() {
+    public int getSublabelFontSizeResId() {
         if (mSuggestionId == ITEM_ID_HTTP_NOT_SECURE_WARNING_MESSAGE) {
-            return R.dimen.dropdown_item_smaller_label_font_size;
+            return R.dimen.dropdown_item_larger_sublabel_font_size;
         }
-        return super.getLabelFontSizeResId();
+        return super.getSublabelFontSizeResId();
     }
 
     @Override
@@ -108,6 +111,22 @@
         return super.isIconAtStart();
     }
 
+    @Override
+    public int getIconSizeResId() {
+        if (mSuggestionId == ITEM_ID_HTTP_NOT_SECURE_WARNING_MESSAGE) {
+            return R.dimen.dropdown_large_icon_size;
+        }
+        return super.getIconSizeResId();
+    }
+
+    @Override
+    public int getIconMarginResId() {
+        if (mSuggestionId == ITEM_ID_HTTP_NOT_SECURE_WARNING_MESSAGE) {
+            return R.dimen.dropdown_large_icon_margin;
+        }
+        return super.getIconMarginResId();
+    }
+
     public int getSuggestionId() {
         return mSuggestionId;
     }
diff --git a/components/autofill_strings.grdp b/components/autofill_strings.grdp
index 03a916d..e2a1b8e 100644
--- a/components/autofill_strings.grdp
+++ b/components/autofill_strings.grdp
@@ -360,4 +360,10 @@
   <message name="IDS_PAYMENT_REQUEST_ORDER_SUMMARY_SHEET_TOTAL_FORMAT" desc="The format specifier of the Total label in the Order Summary Sheet of the Payment Request dialog.">
     <ph name="CURRENCY_CODE">$1<ex>USD</ex></ph> <ph name="FORMATTED_TOTAL_AMOUNT">$2<ex>$ 12.34</ex></ph>
   </message>
+  <message name="IDS_PAYMENT_REQUEST_SHIPPING_SECTION_NAME" desc="The name of the Shipping Address section in the Payment Sheet of the Payment Request dialog.">
+    Shipping address
+  </message>
+  <message name="IDS_PAYMENT_REQUEST_CONTACT_INFO_SECTION_NAME" desc="The name of the Contact Info section in the Payment Sheet of the Payment Request dialog.">
+    Contact info
+  </message>
 </grit-part>
diff --git a/components/exo/compositor_frame_sink.cc b/components/exo/compositor_frame_sink.cc
index 3418413e..c49758a4 100644
--- a/components/exo/compositor_frame_sink.cc
+++ b/components/exo/compositor_frame_sink.cc
@@ -36,18 +36,6 @@
   support_.SubmitCompositorFrame(local_frame_id, std::move(frame));
 }
 
-void CompositorFrameSink::AddSurfaceReferences(
-    const std::vector<cc::SurfaceReference>& references) {
-  // TODO(fsamuel, staraz): Implement this.
-  NOTIMPLEMENTED();
-}
-
-void CompositorFrameSink::RemoveSurfaceReferences(
-    const std::vector<cc::SurfaceReference>& references) {
-  // TODO(fsamuel, staraz): Implement this.
-  NOTIMPLEMENTED();
-}
-
 void CompositorFrameSink::EvictFrame() {
   support_.EvictFrame();
 }
diff --git a/components/exo/compositor_frame_sink.h b/components/exo/compositor_frame_sink.h
index f80832ca..549899ff 100644
--- a/components/exo/compositor_frame_sink.h
+++ b/components/exo/compositor_frame_sink.h
@@ -29,10 +29,6 @@
   void SetNeedsBeginFrame(bool needs_begin_frame) override;
   void SubmitCompositorFrame(const cc::LocalFrameId& local_frame_id,
                              cc::CompositorFrame frame) override;
-  void AddSurfaceReferences(
-      const std::vector<cc::SurfaceReference>& references) override;
-  void RemoveSurfaceReferences(
-      const std::vector<cc::SurfaceReference>& references) override;
   void EvictFrame() override;
   void Require(const cc::LocalFrameId& local_frame_id,
                const cc::SurfaceSequence& sequence) override;
diff --git a/components/ntp_snippets/category.cc b/components/ntp_snippets/category.cc
index 4409ac1b..7274a01 100644
--- a/components/ntp_snippets/category.cc
+++ b/components/ntp_snippets/category.cc
@@ -22,12 +22,17 @@
 
 // static
 Category Category::FromIDValue(int id) {
-  DCHECK_GE(id, 0);
-  DCHECK(id < static_cast<int>(KnownCategories::LOCAL_CATEGORIES_COUNT) ||
-         id > static_cast<int>(KnownCategories::REMOTE_CATEGORIES_OFFSET));
+  DCHECK(IsValidIDValue(id)) << "Not a valid ID: " << id;
   return Category(id);
 }
 
+// static
+bool Category::IsValidIDValue(int id) {
+  return (id >= 0) &&
+         ((id < static_cast<int>(KnownCategories::LOCAL_CATEGORIES_COUNT) ||
+           id > static_cast<int>(KnownCategories::REMOTE_CATEGORIES_OFFSET)));
+}
+
 Category::Category(int id) : id_(id) {}
 
 bool Category::IsKnownCategory(KnownCategories known_category) const {
diff --git a/components/ntp_snippets/category.h b/components/ntp_snippets/category.h
index c13c11531..6e36a3a 100644
--- a/components/ntp_snippets/category.h
+++ b/components/ntp_snippets/category.h
@@ -67,9 +67,15 @@
   static Category FromRemoteCategory(int remote_category);
 
   // Creates a category from an ID as returned by |id()|. |id| must be a
-  // non-negative value.
+  // non-negative value. Callers should make sure this is a valid id (if in
+  // doubt, call IsValidIDValue()).
   static Category FromIDValue(int id);
 
+  // Verifies if |id| is a valid ID value. Only checks that the value is within
+  // a valid range -- not that the system actually knows about the corresponding
+  // category.
+  static bool IsValidIDValue(int id);
+
   // Returns a non-negative identifier that is unique for the category and can
   // be converted back to a Category instance using
   // |CategoryFactory::FromIDValue(id)|.
diff --git a/components/ntp_snippets/category_rankers/click_based_category_ranker.cc b/components/ntp_snippets/category_rankers/click_based_category_ranker.cc
index 8b78279..9965ab7 100644
--- a/components/ntp_snippets/category_rankers/click_based_category_ranker.cc
+++ b/components/ntp_snippets/category_rankers/click_based_category_ranker.cc
@@ -5,8 +5,11 @@
 #include "components/ntp_snippets/category_rankers/click_based_category_ranker.h"
 
 #include <algorithm>
+#include <string>
+#include <utility>
 
 #include "base/memory/ptr_util.h"
+#include "base/strings/string_number_conversions.h"
 #include "base/values.h"
 #include "components/ntp_snippets/category_rankers/constant_category_ranker.h"
 #include "components/ntp_snippets/features.h"
@@ -64,6 +67,9 @@
 
 const char kCategoryIdKey[] = "category";
 const char kClicksKey[] = "clicks";
+const char kLastDismissedKey[] = "last_dismissed";
+const char kContentSuggestionsPromotedCategory[] =
+    "click_based_category_ranker-promoted_category";
 
 int GetDismissedCategoryPenaltyVariationValue() {
   return variations::GetVariationParamByFeatureAsInt(
@@ -71,6 +77,20 @@
       kDefaultDismissedCategoryPenalty);
 }
 
+base::Optional<Category> GetPromotedCategoryFromVariations() {
+  int category_id = variations::GetVariationParamByFeatureAsInt(
+      kCategoryRanker, kContentSuggestionsPromotedCategory, -1);
+  if (category_id < 0) {
+    return base::nullopt;
+  }
+  if (!Category::IsValidIDValue(category_id)) {
+    LOG(WARNING) << "Received invalid category ID for promotion: "
+                 << category_id << ". Ignoring promotion.";
+    return base::nullopt;
+  }
+  return Category::FromIDValue(category_id);
+}
+
 }  // namespace
 
 ClickBasedCategoryRanker::ClickBasedCategoryRanker(
@@ -87,6 +107,25 @@
   if (ReadLastDecayTimeFromPrefs() == base::Time::FromInternalValue(0)) {
     StoreLastDecayTimeToPrefs(clock_->Now());
   }
+  promoted_category_ = DeterminePromotedCategory();
+}
+
+// |ordered_categories_| needs to be properly initialized before calling
+// this method.
+base::Optional<Category> ClickBasedCategoryRanker::DeterminePromotedCategory() {
+  base::Optional<Category> promoted = GetPromotedCategoryFromVariations();
+  if (!promoted.has_value()) {
+    return base::nullopt;
+  }
+  auto promoted_it = FindCategory(promoted.value());
+  if (promoted_it != ordered_categories_.end() &&
+      promoted_it->last_dismissed >
+          clock_->Now() - base::TimeDelta::FromDays(14)) {
+    // Only promote categories to the top if they weren't dismissed within the
+    // last 2 weeks.
+    return base::nullopt;
+  }
+  return promoted;
 }
 
 ClickBasedCategoryRanker::~ClickBasedCategoryRanker() = default;
@@ -103,6 +142,12 @@
   if (left == right) {
     return false;
   }
+  if (promoted_category_.has_value() && left == *promoted_category_) {
+    return true;
+  }
+  if (promoted_category_.has_value() && right == *promoted_category_) {
+    return false;
+  }
   for (const RankedCategory& ranked_category : ordered_categories_) {
     if (ranked_category.category == left) {
       return true;
@@ -150,7 +195,8 @@
             Category::CompareByID());
 
   for (Category added_category : added_categories) {
-    ordered_categories_.push_back(RankedCategory(added_category, /*clicks=*/0));
+    ordered_categories_.push_back(RankedCategory(
+        added_category, /*clicks=*/0, /*last_dismissed=*/base::Time()));
   }
 
   StoreOrderToPrefs(ordered_categories_);
@@ -158,7 +204,8 @@
 
 void ClickBasedCategoryRanker::AppendCategoryIfNecessary(Category category) {
   if (!ContainsCategory(category)) {
-    ordered_categories_.push_back(RankedCategory(category, /*clicks=*/0));
+    ordered_categories_.push_back(RankedCategory(
+        category, /*clicks=*/0, /*last_dismissed=*/base::Time()));
   }
 }
 
@@ -199,28 +246,29 @@
   }
 
   const int penalty = GetDismissedCategoryPenaltyVariationValue();
-  if (penalty == 0) {
-    // The dismissed category penalty is turned off, the call is ignored.
-    return;
-  }
-
-  std::vector<RankedCategory>::iterator current = FindCategory(category);
-  for (int downgrade = 0; downgrade < penalty; ++downgrade) {
-    std::vector<RankedCategory>::iterator next = current + 1;
-    if (next == ordered_categories_.end()) {
-      break;
+  if (penalty != 0) {  // Dismissed category penalty is turned on?
+    std::vector<RankedCategory>::iterator current = FindCategory(category);
+    for (int downgrade = 0; downgrade < penalty; ++downgrade) {
+      std::vector<RankedCategory>::iterator next = current + 1;
+      if (next == ordered_categories_.end()) {
+        break;
+      }
+      std::swap(*current, *next);
+      current = next;
     }
-    std::swap(*current, *next);
-    current = next;
-  }
 
-  DCHECK(current != ordered_categories_.begin());
-  std::vector<RankedCategory>::iterator previous = current - 1;
-  int new_clicks = std::max(previous->clicks - kPassingMargin, 0);
-  // The previous category may have more clicks (but not enough to pass the
-  // margin, this is possible when penalty >= 2), therefore, we ensure that for
-  // this category we don't increase clicks.
-  current->clicks = std::min(current->clicks, new_clicks);
+    DCHECK(current != ordered_categories_.begin());
+    std::vector<RankedCategory>::iterator previous = current - 1;
+    int new_clicks = std::max(previous->clicks - kPassingMargin, 0);
+    // The previous category may have more clicks (but not enough to pass the
+    // margin, this is possible when penalty >= 2), therefore, we ensure that
+    // for this category we don't increase clicks.
+    current->clicks = std::min(current->clicks, new_clicks);
+  }
+  FindCategory(category)->last_dismissed = clock_->Now();
+  if (promoted_category_.has_value() && category == *promoted_category_) {
+    promoted_category_.reset();
+  }
   StoreOrderToPrefs(ordered_categories_);
 }
 
@@ -251,9 +299,11 @@
   return GetDismissedCategoryPenaltyVariationValue();
 }
 
-ClickBasedCategoryRanker::RankedCategory::RankedCategory(Category category,
-                                                         int clicks)
-    : category(category), clicks(clicks) {}
+ClickBasedCategoryRanker::RankedCategory::RankedCategory(
+    Category category,
+    int clicks,
+    const base::Time& last_dismissed)
+    : category(category), clicks(clicks), last_dismissed(last_dismissed) {}
 
 // Returns passing margin for a given position taking into account whether it is
 // a top category.
@@ -285,9 +335,26 @@
     KnownCategories known_category) {
   Category category = Category::FromKnownCategory(known_category);
   DCHECK(!ContainsCategory(category));
-  ordered_categories_.push_back(RankedCategory(category, /*clicks=*/0));
+  ordered_categories_.push_back(RankedCategory(
+      category, /*clicks=*/0, /*last_dismissed=*/base::Time()));
 }
 
+namespace {
+
+base::Time ParseLastDismissedDate(const base::DictionaryValue& value) {
+  // We don't expect the last-dismissed value to be present in all cases (we
+  // added this after the fact).
+  std::string serialized_value;
+  int64_t parsed_value;
+  if (value.GetString(kLastDismissedKey, &serialized_value) &&
+      base::StringToInt64(serialized_value, &parsed_value)) {
+    return base::Time::FromInternalValue(parsed_value);
+  }
+  return base::Time();
+}
+
+}  // namespace
+
 bool ClickBasedCategoryRanker::ReadOrderFromPrefs(
     std::vector<RankedCategory>* result_categories) const {
   result_categories->clear();
@@ -314,8 +381,10 @@
       LOG(DFATAL) << "Dictionary does not have '" << kClicksKey << "' key.";
       return false;
     }
+    base::Time last_dismissed = ParseLastDismissedDate(*dictionary);
     Category category = Category::FromIDValue(category_id);
-    result_categories->push_back(RankedCategory(category, clicks));
+    result_categories->push_back(
+        RankedCategory(category, clicks, last_dismissed));
   }
   return true;
 }
@@ -327,6 +396,9 @@
     auto dictionary = base::MakeUnique<base::DictionaryValue>();
     dictionary->SetInteger(kCategoryIdKey, category.category.id());
     dictionary->SetInteger(kClicksKey, category.clicks);
+    dictionary->SetString(
+        kLastDismissedKey,
+        base::Int64ToString(category.last_dismissed.ToInternalValue()));
     list.Append(std::move(dictionary));
   }
   pref_service_->Set(prefs::kClickBasedCategoryRankerOrderWithClicks, list);
diff --git a/components/ntp_snippets/category_rankers/click_based_category_ranker.h b/components/ntp_snippets/category_rankers/click_based_category_ranker.h
index 8466158..0042ffe 100644
--- a/components/ntp_snippets/category_rankers/click_based_category_ranker.h
+++ b/components/ntp_snippets/category_rankers/click_based_category_ranker.h
@@ -2,12 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef COMPONENTS_NTP_SNIPPETS_SECTION_RANKERS_CLICK_BASED_SECTION_RANKER_H_
-#define COMPONENTS_NTP_SNIPPETS_SECTION_RANKERS_CLICK_BASED_SECTION_RANKER_H_
+#ifndef COMPONENTS_NTP_SNIPPETS_CATEGORY_RANKERS_CLICK_BASED_CATEGORY_RANKER_H_
+#define COMPONENTS_NTP_SNIPPETS_CATEGORY_RANKERS_CLICK_BASED_CATEGORY_RANKER_H_
 
 #include <memory>
 #include <vector>
 
+#include "base/optional.h"
 #include "base/time/clock.h"
 #include "base/time/time.h"
 #include "components/ntp_snippets/category.h"
@@ -59,10 +60,14 @@
   struct RankedCategory {
     Category category;
     int clicks;
+    base::Time last_dismissed;
 
-    RankedCategory(Category category, int clicks);
+    RankedCategory(Category category,
+                   int clicks,
+                   const base::Time& last_dismissed);
   };
 
+  base::Optional<Category> DeterminePromotedCategory();
   int GetPositionPassingMargin(
       std::vector<RankedCategory>::const_iterator category_position) const;
   void RestoreDefaultOrder();
@@ -79,12 +84,12 @@
 
   std::vector<RankedCategory> ordered_categories_;
   PrefService* pref_service_;
-  // Allow for an injectable clock for testing.
   std::unique_ptr<base::Clock> clock_;
+  base::Optional<Category> promoted_category_;
 
   DISALLOW_COPY_AND_ASSIGN(ClickBasedCategoryRanker);
 };
 
 }  // namespace ntp_snippets
 
-#endif  // COMPONENTS_NTP_SNIPPETS_SECTION_RANKERS_CLICK_BASED_SECTION_RANKER_H_
+#endif  // COMPONENTS_NTP_SNIPPETS_CATEGORY_RANKERS_CLICK_BASED_CATEGORY_RANKER_H_
diff --git a/components/ntp_snippets/category_rankers/click_based_category_ranker_unittest.cc b/components/ntp_snippets/category_rankers/click_based_category_ranker_unittest.cc
index 7c19013..dbc017bc 100644
--- a/components/ntp_snippets/category_rankers/click_based_category_ranker_unittest.cc
+++ b/components/ntp_snippets/category_rankers/click_based_category_ranker_unittest.cc
@@ -4,6 +4,8 @@
 
 #include "components/ntp_snippets/category_rankers/click_based_category_ranker.h"
 
+#include <utility>
+
 #include "base/memory/ptr_util.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/test/simple_test_clock.h"
@@ -77,6 +79,14 @@
         {kCategoryRanker.name});
   }
 
+  void SetPromotedCategoryVariationParam(int value) {
+    variation_params_manager_.SetVariationParamsWithFeatureAssociations(
+        ntp_snippets::kStudyName,
+        {{"click_based_category_ranker-promoted_category",
+          base::IntToString(value)}},
+        {kCategoryRanker.name});
+  }
+
   ClickBasedCategoryRanker* ranker() { return ranker_.get(); }
 
  private:
@@ -559,4 +569,84 @@
   EXPECT_FALSE(CompareCategories(first, second));
 }
 
+TEST_F(ClickBasedCategoryRankerTest, ShouldPromoteCategory) {
+  const Category downloads =
+      Category::FromKnownCategory(KnownCategories::DOWNLOADS);
+  const Category bookmarks =
+      Category::FromKnownCategory(KnownCategories::BOOKMARKS);
+  const Category articles =
+      Category::FromKnownCategory(KnownCategories::ARTICLES);
+  ASSERT_TRUE(CompareCategories(downloads, bookmarks));
+  ASSERT_TRUE(CompareCategories(bookmarks, articles));
+  SetPromotedCategoryVariationParam(articles.id());
+  ResetRanker(base::MakeUnique<base::DefaultClock>());
+  EXPECT_TRUE(CompareCategories(articles, downloads));
+  EXPECT_TRUE(CompareCategories(articles, bookmarks));
+  EXPECT_FALSE(CompareCategories(downloads, articles));
+  EXPECT_FALSE(CompareCategories(bookmarks, articles));
+  EXPECT_FALSE(CompareCategories(articles, articles));
+}
+
+TEST_F(ClickBasedCategoryRankerTest,
+       ShouldHandleInvalidCategoryIDForPromotion) {
+  SetPromotedCategoryVariationParam(
+      static_cast<int>(KnownCategories::LOCAL_CATEGORIES_COUNT));
+  ResetRanker(base::MakeUnique<base::DefaultClock>());
+  // Make sure we have the default order.
+  EXPECT_TRUE(CompareCategories(
+      Category::FromKnownCategory(KnownCategories::PHYSICAL_WEB_PAGES),
+      Category::FromKnownCategory(KnownCategories::DOWNLOADS)));
+  EXPECT_TRUE(CompareCategories(
+      Category::FromKnownCategory(KnownCategories::DOWNLOADS),
+      Category::FromKnownCategory(KnownCategories::RECENT_TABS)));
+  EXPECT_TRUE(CompareCategories(
+      Category::FromKnownCategory(KnownCategories::RECENT_TABS),
+      Category::FromKnownCategory(KnownCategories::FOREIGN_TABS)));
+  EXPECT_TRUE(CompareCategories(
+      Category::FromKnownCategory(KnownCategories::FOREIGN_TABS),
+      Category::FromKnownCategory(KnownCategories::BOOKMARKS)));
+  EXPECT_TRUE(CompareCategories(
+      Category::FromKnownCategory(KnownCategories::BOOKMARKS),
+      Category::FromKnownCategory(KnownCategories::ARTICLES)));
+}
+
+TEST_F(ClickBasedCategoryRankerTest, ShouldEndPromotionOnSectionDismissal) {
+  const Category physical_web =
+      Category::FromKnownCategory(KnownCategories::PHYSICAL_WEB_PAGES);
+  const Category articles =
+      Category::FromKnownCategory(KnownCategories::ARTICLES);
+  ASSERT_TRUE(CompareCategories(physical_web, articles));
+
+  SetPromotedCategoryVariationParam(articles.id());
+  ResetRanker(base::MakeUnique<base::DefaultClock>());
+
+  ASSERT_TRUE(CompareCategories(articles, physical_web));
+
+  ranker()->OnCategoryDismissed(articles);
+  EXPECT_FALSE(CompareCategories(articles, physical_web));
+  EXPECT_TRUE(CompareCategories(physical_web, articles));
+}
+
+TEST_F(ClickBasedCategoryRankerTest,
+       ShouldResumePromotionAfter2WeeksSinceDismissal) {
+  const Category downloads =
+      Category::FromKnownCategory(KnownCategories::DOWNLOADS);
+  const Category recent_tabs =
+      Category::FromKnownCategory(KnownCategories::RECENT_TABS);
+  ASSERT_TRUE(CompareCategories(downloads, recent_tabs));
+
+  SetPromotedCategoryVariationParam(recent_tabs.id());
+  ResetRanker(base::MakeUnique<base::DefaultClock>());
+  ASSERT_TRUE(CompareCategories(recent_tabs, downloads));
+
+  ranker()->OnCategoryDismissed(recent_tabs);
+  ASSERT_FALSE(CompareCategories(recent_tabs, downloads));
+
+  // Simulate a little over 2 weeks of time passing.
+  auto test_clock = base::MakeUnique<base::SimpleTestClock>();
+  test_clock->SetNow(base::Time::Now() + base::TimeDelta::FromDays(15));
+  ResetRanker(std::move(test_clock));
+  EXPECT_TRUE(CompareCategories(recent_tabs, downloads));
+}
+
 }  // namespace ntp_snippets
diff --git a/components/ntp_snippets/category_unittest.cc b/components/ntp_snippets/category_unittest.cc
index 8ae1c5f..0129231 100644
--- a/components/ntp_snippets/category_unittest.cc
+++ b/components/ntp_snippets/category_unittest.cc
@@ -16,6 +16,19 @@
   EXPECT_EQ(first, second);
 }
 
+TEST(CategoryTest, ShouldIdentifyValidIDValues) {
+  EXPECT_TRUE(
+      Category::IsValidIDValue(static_cast<int>(KnownCategories::ARTICLES)));
+  EXPECT_FALSE(Category::IsValidIDValue(-1));
+  EXPECT_TRUE(Category::IsValidIDValue(0));
+  EXPECT_FALSE(Category::IsValidIDValue(
+      static_cast<int>(KnownCategories::REMOTE_CATEGORIES_OFFSET)));
+  EXPECT_TRUE(Category::IsValidIDValue(
+      static_cast<int>(KnownCategories::REMOTE_CATEGORIES_OFFSET) + 5));
+  EXPECT_FALSE(Category::IsValidIDValue(
+      static_cast<int>(KnownCategories::LOCAL_CATEGORIES_COUNT)));
+}
+
 TEST(CategoryFactoryTest,
      FromRemoteCategoryShouldReturnSameCategoryForSameInput) {
   const int remote_category_id = 123;
diff --git a/components/payments/payment_request.cc b/components/payments/payment_request.cc
index 06ec2b4..282b3fa 100644
--- a/components/payments/payment_request.cc
+++ b/components/payments/payment_request.cc
@@ -4,6 +4,7 @@
 
 #include "components/payments/payment_request.h"
 
+#include "base/memory/ptr_util.h"
 #include "components/autofill/core/browser/personal_data_manager.h"
 #include "components/payments/payment_details_validation.h"
 #include "components/payments/payment_request_delegate.h"
@@ -74,6 +75,19 @@
   return currency_formatter_.get();
 }
 
+autofill::AutofillProfile* PaymentRequest::GetCurrentlySelectedProfile() {
+  // TODO(tmartino): Implement more sophisticated algorithm for populating
+  // this when it starts empty.
+  if (!profile_) {
+    autofill::PersonalDataManager* data_manager =
+        delegate_->GetPersonalDataManager();
+    auto profiles = data_manager->GetProfiles();
+    if (!profiles.empty())
+      profile_ = base::MakeUnique<autofill::AutofillProfile>(*profiles[0]);
+  }
+  return profile_ ? profile_.get() : nullptr;
+}
+
 autofill::CreditCard* PaymentRequest::GetCurrentlySelectedCreditCard() {
   // TODO(anthonyvd): Change this code to prioritize server cards and implement
   // a way to modify this function's return value.
diff --git a/components/payments/payment_request.h b/components/payments/payment_request.h
index beb1120..6c55cca 100644
--- a/components/payments/payment_request.h
+++ b/components/payments/payment_request.h
@@ -6,13 +6,15 @@
 #define COMPONENTS_PAYMENTS_PAYMENT_REQUEST_H_
 
 #include <memory>
+#include <string>
+#include <vector>
 
-#include "base/optional.h"
 #include "components/payments/currency_formatter.h"
 #include "components/payments/payment_request.mojom.h"
 #include "mojo/public/cpp/bindings/binding.h"
 
 namespace autofill {
+class AutofillProfile;
 class CreditCard;
 }
 
@@ -57,6 +59,13 @@
       const base::Optional<std::string> currency_system,
       const std::string& locale_name);
 
+  // Returns the Autofill Profile, representing the shipping address and contact
+  // information, currently selected for this PaymentRequest flow. If
+  // unpopulated, populates with and returns the 0th profile on record for this
+  // user, if it exists; or nullptr otherwise. Profile is owned by the request
+  // object, not the caller.
+  autofill::AutofillProfile* GetCurrentlySelectedProfile();
+
   // Returns the currently selected credit card for this PaymentRequest flow.
   // It's not guaranteed to be complete. Returns nullptr if there is no selected
   // card.
@@ -74,6 +83,7 @@
   payments::mojom::PaymentRequestClientPtr client_;
   payments::mojom::PaymentDetailsPtr details_;
   std::unique_ptr<CurrencyFormatter> currency_formatter_;
+  std::unique_ptr<autofill::AutofillProfile> profile_;
 
   DISALLOW_COPY_AND_ASSIGN(PaymentRequest);
 };
diff --git a/components/reading_list/ios/reading_list_store.cc b/components/reading_list/ios/reading_list_store.cc
index 528bcab..087ad62 100644
--- a/components/reading_list/ios/reading_list_store.cc
+++ b/components/reading_list/ios/reading_list_store.cc
@@ -4,6 +4,9 @@
 
 #include "components/reading_list/ios/reading_list_store.h"
 
+#include <set>
+#include <utility>
+
 #include "base/bind.h"
 #include "base/logging.h"
 #include "base/memory/ptr_util.h"
@@ -25,7 +28,7 @@
       pending_transaction_count_(0) {}
 
 ReadingListStore::~ReadingListStore() {
-  DCHECK(pending_transaction_count_ == 0);
+  DCHECK_EQ(0, pending_transaction_count_);
 }
 
 void ReadingListStore::SetReadingListModel(ReadingListModel* model,
@@ -156,7 +159,7 @@
   if (error) {
     change_processor()->ReportError(FROM_HERE, "Failed to read metadata.");
   } else {
-    change_processor()->OnMetadataLoaded(std::move(metadata_batch));
+    change_processor()->ModelReadyToSync(std::move(metadata_batch));
   }
 }
 
@@ -252,7 +255,6 @@
       // ping-pong.
       change_processor()->Put(entry_sync_pb->entry_id(), std::move(entity_data),
                               metadata_change_list.get());
-
     }
   }
 
@@ -341,7 +343,6 @@
         change_processor()->Put(entry_sync_pb->entry_id(),
                                 std::move(entity_data),
                                 metadata_change_list.get());
-
       }
     }
   }
diff --git a/components/reading_list/ios/reading_list_store.h b/components/reading_list/ios/reading_list_store.h
index 7d454a2..2b78007 100644
--- a/components/reading_list/ios/reading_list_store.h
+++ b/components/reading_list/ios/reading_list_store.h
@@ -5,6 +5,9 @@
 #ifndef COMPONENTS_READING_LIST_IOS_READING_LIST_STORE_H_
 #define COMPONENTS_READING_LIST_IOS_READING_LIST_STORE_H_
 
+#include <memory>
+#include <string>
+
 #include "base/threading/non_thread_safe.h"
 #include "components/reading_list/ios/reading_list_model_storage.h"
 #include "components/reading_list/ios/reading_list_store_delegate.h"
diff --git a/components/sync/device_info/device_info_sync_bridge.cc b/components/sync/device_info/device_info_sync_bridge.cc
index 86d09f7..0ba09e3 100644
--- a/components/sync/device_info/device_info_sync_bridge.cc
+++ b/components/sync/device_info/device_info_sync_bridge.cc
@@ -387,7 +387,7 @@
     return;
   }
 
-  change_processor()->OnMetadataLoaded(std::move(metadata_batch));
+  change_processor()->ModelReadyToSync(std::move(metadata_batch));
   ReconcileLocalAndStored();
 }
 
diff --git a/components/sync/device_info/device_info_sync_bridge_unittest.cc b/components/sync/device_info/device_info_sync_bridge_unittest.cc
index e0f484d..6f996f4 100644
--- a/components/sync/device_info/device_info_sync_bridge_unittest.cc
+++ b/components/sync/device_info/device_info_sync_bridge_unittest.cc
@@ -190,7 +190,7 @@
     delete_set_.insert(storage_key);
   }
 
-  void OnMetadataLoaded(std::unique_ptr<MetadataBatch> batch) override {
+  void ModelReadyToSync(std::unique_ptr<MetadataBatch> batch) override {
     std::swap(metadata_, batch);
   }
 
diff --git a/components/sync/model/fake_model_type_change_processor.cc b/components/sync/model/fake_model_type_change_processor.cc
index a71df0f..9f41879 100644
--- a/components/sync/model/fake_model_type_change_processor.cc
+++ b/components/sync/model/fake_model_type_change_processor.cc
@@ -35,7 +35,7 @@
     const std::string& client_tag,
     MetadataChangeList* metadata_change_list) {}
 
-void FakeModelTypeChangeProcessor::OnMetadataLoaded(
+void FakeModelTypeChangeProcessor::ModelReadyToSync(
     std::unique_ptr<MetadataBatch> batch) {}
 
 void FakeModelTypeChangeProcessor::OnSyncStarting(
diff --git a/components/sync/model/fake_model_type_change_processor.h b/components/sync/model/fake_model_type_change_processor.h
index 8d732f0..732f9e6 100644
--- a/components/sync/model/fake_model_type_change_processor.h
+++ b/components/sync/model/fake_model_type_change_processor.h
@@ -33,7 +33,7 @@
            MetadataChangeList* metadata_change_list) override;
   void Delete(const std::string& client_tag,
               MetadataChangeList* metadata_change_list) override;
-  void OnMetadataLoaded(std::unique_ptr<MetadataBatch> batch) override;
+  void ModelReadyToSync(std::unique_ptr<MetadataBatch> batch) override;
   void OnSyncStarting(const ModelErrorHandler& error_handler,
                       const StartCallback& callback) override;
   void DisableSync() override;
diff --git a/components/sync/model/model_type_change_processor.h b/components/sync/model/model_type_change_processor.h
index 1f2885b..f26ab61 100644
--- a/components/sync/model/model_type_change_processor.h
+++ b/components/sync/model/model_type_change_processor.h
@@ -21,8 +21,7 @@
 class MetadataChangeList;
 class ModelTypeSyncBridge;
 
-// Interface used by the ModelTypeSyncBridge to inform sync of local
-// changes.
+// Interface used by the ModelTypeSyncBridge to inform sync of local changes.
 class ModelTypeChangeProcessor {
  public:
   typedef base::Callback<void(std::unique_ptr<ActivationContext>)>
@@ -48,10 +47,13 @@
   virtual void Delete(const std::string& storage_key,
                       MetadataChangeList* metadata_change_list) = 0;
 
-  // Accept the initial sync metadata loaded by the bridge. This must be called
-  // by the bridge for syncing to begin for this model type. If an error occurs,
-  // call ReportError instead of this.
-  virtual void OnMetadataLoaded(std::unique_ptr<MetadataBatch> batch) = 0;
+  // The bridge is expected to call this exactly once unless it encounters an
+  // error. Ideally ModelReadyToSync() is called as soon as possible during
+  // initialization, and must be called before invoking either Put() or
+  // Delete(). The bridge needs to be able to synchronously handle
+  // MergeSyncData() and ApplySyncChanges() after calling ModelReadyToSync(). If
+  // an error is encountered, calling ReportError() instead is sufficient.
+  virtual void ModelReadyToSync(std::unique_ptr<MetadataBatch> batch) = 0;
 
   // Indicates that sync wants to connect a sync worker to this processor. Once
   // the processor has metadata from the bridge, it will pass the info needed
@@ -68,7 +70,8 @@
 
   // Returns a boolean representing whether the processor's metadata is
   // currently up to date and accurately tracking the model type's data. If
-  // false, calls to Put and Delete will no-op and can be omitted by bridge.
+  // false, and ModelReadyToSync() has already been called, then Put and Delete
+  // will no-op and can be omitted by bridge.
   virtual bool IsTrackingMetadata() = 0;
 
   // Report an error in the model to sync. Should be called for any persistence
diff --git a/components/sync/model/model_type_sync_bridge.cc b/components/sync/model/model_type_sync_bridge.cc
index c6954286..0e5a1dd 100644
--- a/components/sync/model/model_type_sync_bridge.cc
+++ b/components/sync/model/model_type_sync_bridge.cc
@@ -44,7 +44,7 @@
   // processor that there is no metadata. DisableSync() should never be called
   // while the models are loading, aka before the service has finished loading
   // the initial metadata.
-  change_processor_->OnMetadataLoaded(base::MakeUnique<MetadataBatch>());
+  change_processor_->ModelReadyToSync(base::MakeUnique<MetadataBatch>());
 }
 
 ModelTypeChangeProcessor* ModelTypeSyncBridge::change_processor() const {
diff --git a/components/sync/model/model_type_sync_bridge.h b/components/sync/model/model_type_sync_bridge.h
index 74e7df45..6dde843 100644
--- a/components/sync/model/model_type_sync_bridge.h
+++ b/components/sync/model/model_type_sync_bridge.h
@@ -28,10 +28,10 @@
 // ModelTypeChangeProcessor. Provides a way for sync to update the data and
 // metadata for entities, as well as the model type state. Sync bridge
 // implementations must provide their change_processor() with metadata through
-// OnMetadataLoaded() as soon as possible. Once this is called, sync will
+// ModelReadyToSync() as soon as possible. Once this is called, sync will
 // immediately begin locally tracking changes and can start syncing with the
 // server soon afterward. If an error occurs during startup, the processor's
-// ReportError() method should be called instead of OnMetadataLoaded().
+// ReportError() method should be called instead of ModelReadyToSync().
 class ModelTypeSyncBridge : public base::SupportsWeakPtr<ModelTypeSyncBridge> {
  public:
   typedef base::Callback<void(std::unique_ptr<DataBatch>)> DataCallback;
@@ -121,6 +121,9 @@
   // metadata, and then destroys the change processor.
   virtual void DisableSync();
 
+  // Needs to be informed about any model change occurring via Delete() and
+  // Put(). The changing metadata should be stored to persistent storage before
+  // or atomically with the model changes.
   ModelTypeChangeProcessor* change_processor() const;
 
  private:
diff --git a/components/sync/model/model_type_sync_bridge_unittest.cc b/components/sync/model/model_type_sync_bridge_unittest.cc
index 51dd4c0..7b30935a 100644
--- a/components/sync/model/model_type_sync_bridge_unittest.cc
+++ b/components/sync/model/model_type_sync_bridge_unittest.cc
@@ -16,7 +16,7 @@
 
 namespace syncer {
 
-// A mock MTCP that lets verify DisableSync and OnMetadataLoaded were called in
+// A mock MTCP that lets verify DisableSync and ModelReadyToSync were called in
 // the ways that we expect.
 class MockModelTypeChangeProcessor : public FakeModelTypeChangeProcessor {
  public:
@@ -26,13 +26,11 @@
 
   void DisableSync() override { disabled_callback_.Run(); }
 
-  void OnMetadataLoaded(std::unique_ptr<MetadataBatch> batch) override {
-    on_metadata_loaded_batch_ = std::move(batch);
+  void ModelReadyToSync(std::unique_ptr<MetadataBatch> batch) override {
+    metadata_batch_ = std::move(batch);
   }
 
-  MetadataBatch* on_metadata_loaded_batch() {
-    return on_metadata_loaded_batch_.get();
-  }
+  MetadataBatch* metadata_batch() { return metadata_batch_.get(); }
 
  private:
   // This callback is invoked when DisableSync() is called, instead of
@@ -42,7 +40,7 @@
   // allows this information to reach somewhere safe instead.
   base::Closure disabled_callback_;
 
-  std::unique_ptr<MetadataBatch> on_metadata_loaded_batch_;
+  std::unique_ptr<MetadataBatch> metadata_batch_;
 };
 
 class MockModelTypeSyncBridge : public StubModelTypeSyncBridge {
@@ -120,8 +118,7 @@
   // processor about this.
   EXPECT_TRUE(bridge()->processor_disable_sync_called());
 
-  MetadataBatch* batch =
-      bridge()->change_processor()->on_metadata_loaded_batch();
+  MetadataBatch* batch = bridge()->change_processor()->metadata_batch();
   EXPECT_NE(nullptr, batch);
   EXPECT_EQ(sync_pb::ModelTypeState().SerializeAsString(),
             batch->GetModelTypeState().SerializeAsString());
diff --git a/components/sync/model_impl/shared_model_type_processor.cc b/components/sync/model_impl/shared_model_type_processor.cc
index ef29ab96..ff50859 100644
--- a/components/sync/model_impl/shared_model_type_processor.cc
+++ b/components/sync/model_impl/shared_model_type_processor.cc
@@ -44,7 +44,7 @@
   ConnectIfReady();
 }
 
-void SharedModelTypeProcessor::OnMetadataLoaded(
+void SharedModelTypeProcessor::ModelReadyToSync(
     std::unique_ptr<MetadataBatch> batch) {
   DCHECK(CalledOnValidThread());
   DCHECK(waiting_for_metadata_);
diff --git a/components/sync/model_impl/shared_model_type_processor.h b/components/sync/model_impl/shared_model_type_processor.h
index 68c8bcd..266d7a9e 100644
--- a/components/sync/model_impl/shared_model_type_processor.h
+++ b/components/sync/model_impl/shared_model_type_processor.h
@@ -53,7 +53,7 @@
            MetadataChangeList* metadata_change_list) override;
   void Delete(const std::string& storage_key,
               MetadataChangeList* metadata_change_list) override;
-  void OnMetadataLoaded(std::unique_ptr<MetadataBatch> batch) override;
+  void ModelReadyToSync(std::unique_ptr<MetadataBatch> batch) override;
   void OnSyncStarting(const ModelErrorHandler& error_handler,
                       const StartCallback& callback) override;
   void DisableSync() override;
diff --git a/components/sync/model_impl/shared_model_type_processor_unittest.cc b/components/sync/model_impl/shared_model_type_processor_unittest.cc
index 118c4d4..a624904 100644
--- a/components/sync/model_impl/shared_model_type_processor_unittest.cc
+++ b/components/sync/model_impl/shared_model_type_processor_unittest.cc
@@ -163,7 +163,7 @@
 
   void InitializeToMetadataLoaded() {
     bridge()->SetInitialSyncDone(true);
-    OnMetadataLoaded();
+    ModelReadyToSync();
   }
 
   // Initialize to a "ready-to-commit" state.
@@ -173,8 +173,8 @@
     OnSyncStarting();
   }
 
-  void OnMetadataLoaded() {
-    type_processor()->OnMetadataLoaded(db().CreateMetadataBatch());
+  void ModelReadyToSync() {
+    type_processor()->ModelReadyToSync(db().CreateMetadataBatch());
   }
 
   void OnPendingCommitDataLoaded() { bridge()->OnPendingCommitDataLoaded(); }
@@ -291,7 +291,7 @@
 
 // Test that an initial sync handles local and remote items properly.
 TEST_F(SharedModelTypeProcessorTest, InitialSync) {
-  OnMetadataLoaded();
+  ModelReadyToSync();
   OnSyncStarting();
 
   // Local write before initial sync.
@@ -320,7 +320,7 @@
 
 // Test that an initial sync filters out tombstones in the processor.
 TEST_F(SharedModelTypeProcessorTest, InitialSyncWithTombstone) {
-  OnMetadataLoaded();
+  ModelReadyToSync();
   OnSyncStarting();
 
   EXPECT_EQ(0, bridge()->merge_call_count());
@@ -356,7 +356,7 @@
 
 // Test that an error during the merge is propagated to the error handler.
 TEST_F(SharedModelTypeProcessorTest, MergeError) {
-  OnMetadataLoaded();
+  ModelReadyToSync();
   OnSyncStarting();
 
   bridge()->ErrorOnNextCall();
@@ -388,7 +388,7 @@
   type_processor()->ReportError(FROM_HERE, "boom");
   ExpectError();
   OnSyncStarting();
-  OnMetadataLoaded();
+  ModelReadyToSync();
 
   // Test an error prior to pending data load.
   ResetStateWriteItem(kKey1, kValue1);
diff --git a/components/task_scheduler_util/common/variations_util.cc b/components/task_scheduler_util/common/variations_util.cc
index 385b83bc..f703e11 100644
--- a/components/task_scheduler_util/common/variations_util.cc
+++ b/components/task_scheduler_util/common/variations_util.cc
@@ -99,7 +99,8 @@
     const char* const worker_pool_name = constant_worker_pool_params.name();
     auto it = variation_params.find(worker_pool_name);
     if (it == variation_params.end()) {
-      DLOG(ERROR) << "Missing Worker Pool Configuration: " << worker_pool_name;
+      // Non-branded builds don't have access to external worker pool
+      // configurations.
       return std::vector<base::SchedulerWorkerPoolParams>();
     }
     const auto variable_worker_pool_params =
diff --git a/content/browser/loader/navigation_resource_handler.cc b/content/browser/loader/navigation_resource_handler.cc
index 37d8031..20ee17d 100644
--- a/content/browser/loader/navigation_resource_handler.cc
+++ b/content/browser/loader/navigation_resource_handler.cc
@@ -100,6 +100,7 @@
                            request()->url().GetOrigin());
 
   NetLogObserver::PopulateResponseInfo(request(), response);
+  response->head.encoded_data_length = request()->raw_header_size();
 
   std::unique_ptr<NavigationData> cloned_data;
   if (resource_dispatcher_host_delegate_) {
diff --git a/content/browser/renderer_host/input/web_input_event_builders_mac.mm b/content/browser/renderer_host/input/web_input_event_builders_mac.mm
index 14754e2..11f434f 100644
--- a/content/browser/renderer_host/input/web_input_event_builders_mac.mm
+++ b/content/browser/renderer_host/input/web_input_event_builders_mac.mm
@@ -344,6 +344,14 @@
     NSPoint tilt = [event tilt];
     result.tiltX = lround(tilt.x * 90);
     result.tiltY = lround(tilt.y * 90);
+    result.tangentialPressure = [event tangentialPressure];
+    // NSEvent spec doesn't specify the range of rotation, we make sure that
+    // this value is in the range of [0,359].
+    int twist = (int)[event rotation];
+    twist = twist % 360;
+    if (twist < 0)
+      twist += 360;
+    result.twist = twist;
   }
   return result;
 }
diff --git a/content/browser/renderer_host/media/OWNERS b/content/browser/renderer_host/media/OWNERS
index a8e56056..092aed5 100644
--- a/content/browser/renderer_host/media/OWNERS
+++ b/content/browser/renderer_host/media/OWNERS
@@ -1,10 +1,8 @@
 file://media/OWNERS
 
 # WebRTC OWNERS.
-perkj@chromium.org
+emircan@chromium.org
 tommi@chromium.org
 
-per-file gpu_memory*=mcasas@chromium.org
-per-file shared_memory*=mcasas@chromium.org
 per-file video_*=mcasas@chromium.org
 per-file video_*=chfremer@chromium.org
diff --git a/content/browser/renderer_host/offscreen_canvas_compositor_frame_sink.cc b/content/browser/renderer_host/offscreen_canvas_compositor_frame_sink.cc
index 5717d03..c040991 100644
--- a/content/browser/renderer_host/offscreen_canvas_compositor_frame_sink.cc
+++ b/content/browser/renderer_host/offscreen_canvas_compositor_frame_sink.cc
@@ -40,21 +40,11 @@
 void OffscreenCanvasCompositorFrameSink::SubmitCompositorFrame(
     const cc::LocalFrameId& local_frame_id,
     cc::CompositorFrame frame) {
+  // TODO(samans): This will need to do something similar to
+  // GpuCompositorFrameSink.
   support_.SubmitCompositorFrame(local_frame_id, std::move(frame));
 }
 
-void OffscreenCanvasCompositorFrameSink::AddSurfaceReferences(
-    const std::vector<cc::SurfaceReference>& references) {
-  // TODO(fsamuel, staraz): Implement this.
-  NOTIMPLEMENTED();
-}
-
-void OffscreenCanvasCompositorFrameSink::RemoveSurfaceReferences(
-    const std::vector<cc::SurfaceReference>& references) {
-  // TODO(fsamuel, staraz): Implement this.
-  NOTIMPLEMENTED();
-}
-
 void OffscreenCanvasCompositorFrameSink::EvictFrame() {
   support_.EvictFrame();
 }
diff --git a/content/browser/renderer_host/offscreen_canvas_compositor_frame_sink.h b/content/browser/renderer_host/offscreen_canvas_compositor_frame_sink.h
index db19679..91d0276 100644
--- a/content/browser/renderer_host/offscreen_canvas_compositor_frame_sink.h
+++ b/content/browser/renderer_host/offscreen_canvas_compositor_frame_sink.h
@@ -32,10 +32,6 @@
   void SetNeedsBeginFrame(bool needs_begin_frame) override;
   void SubmitCompositorFrame(const cc::LocalFrameId& local_frame_id,
                              cc::CompositorFrame frame) override;
-  void AddSurfaceReferences(
-      const std::vector<cc::SurfaceReference>& references) override;
-  void RemoveSurfaceReferences(
-      const std::vector<cc::SurfaceReference>& references) override;
   void EvictFrame() override;
   void Require(const cc::LocalFrameId& local_frame_id,
                const cc::SurfaceSequence& sequence) override;
diff --git a/content/browser/web_contents/web_contents_view_child_frame.cc b/content/browser/web_contents/web_contents_view_child_frame.cc
index 9b17012..17d39e9 100644
--- a/content/browser/web_contents/web_contents_view_child_frame.cc
+++ b/content/browser/web_contents/web_contents_view_child_frame.cc
@@ -35,6 +35,13 @@
   return web_contents_->GetOuterWebContents()->GetView();
 }
 
+RenderViewHostDelegateView* WebContentsViewChildFrame::GetOuterDelegateView() {
+  RenderViewHostImpl* outer_rvh = static_cast<RenderViewHostImpl*>(
+      web_contents_->GetOuterWebContents()->GetRenderViewHost());
+  CHECK(outer_rvh);
+  return outer_rvh->GetDelegate()->GetDelegateView();
+}
+
 gfx::NativeView WebContentsViewChildFrame::GetNativeView() const {
   return GetOuterView()->GetNativeView();
 }
@@ -144,7 +151,8 @@
 }
 
 void WebContentsViewChildFrame::UpdateDragCursor(WebDragOperation operation) {
-  NOTREACHED();
+  if (auto view = GetOuterDelegateView())
+    view->UpdateDragCursor(operation);
 }
 
 void WebContentsViewChildFrame::GotFocus() {
@@ -169,7 +177,12 @@
     const gfx::Vector2d& image_offset,
     const DragEventSourceInfo& event_info,
     RenderWidgetHostImpl* source_rwh) {
-  NOTREACHED();
+  if (auto view = GetOuterDelegateView()) {
+    view->StartDragging(
+        drop_data, ops, image, image_offset, event_info, source_rwh);
+  } else {
+    web_contents_->GetOuterWebContents()->SystemDragEnded(source_rwh);
+  }
 }
 
 }  // namespace content
diff --git a/content/browser/web_contents/web_contents_view_child_frame.h b/content/browser/web_contents/web_contents_view_child_frame.h
index ce85c33..86ce68b 100644
--- a/content/browser/web_contents/web_contents_view_child_frame.h
+++ b/content/browser/web_contents/web_contents_view_child_frame.h
@@ -70,6 +70,8 @@
   WebContentsView* GetOuterView();
   const WebContentsView* GetOuterView() const;
 
+  RenderViewHostDelegateView* GetOuterDelegateView();
+
   // The WebContentsImpl whose contents we display.
   WebContentsImpl* web_contents_;
 
diff --git a/content/browser/webrtc/OWNERS b/content/browser/webrtc/OWNERS
index 4f58c911..d5b7a8a 100644
--- a/content/browser/webrtc/OWNERS
+++ b/content/browser/webrtc/OWNERS
@@ -1,6 +1,5 @@
 emircan@chromium.org
 mcasas@chromium.org
-perkj@chromium.org
 tommi@chromium.org
 
 per-file *test*=phoglund@chromium.org
diff --git a/content/child/web_url_loader_impl.cc b/content/child/web_url_loader_impl.cc
index 44625b72..06ac3eb 100644
--- a/content/child/web_url_loader_impl.cc
+++ b/content/child/web_url_loader_impl.cc
@@ -709,6 +709,11 @@
   // received on the browser side, and has been passed down to the renderer.
   if (stream_override_.get()) {
     CHECK(IsBrowserSideNavigationEnabled());
+    // Compute the delta between the response sizes so that the accurate
+    // transfer size can be reported at the end of the request.
+    stream_override_->total_transfer_size_delta =
+        stream_override_->response.encoded_data_length -
+        initial_info.encoded_data_length;
     info = stream_override_->response;
   }
 
@@ -868,6 +873,12 @@
                                          error_code, was_ignored_by_handler),
                        total_transfer_size, encoded_body_size);
     } else {
+      // PlzNavigate: compute the accurate transfer size for navigations.
+      if (stream_override_.get()) {
+        DCHECK(IsBrowserSideNavigationEnabled());
+        total_transfer_size += stream_override_->total_transfer_size_delta;
+      }
+
       client_->didFinishLoading((completion_time - TimeTicks()).InSecondsF(),
                                 total_transfer_size, encoded_body_size);
     }
diff --git a/content/child/web_url_loader_impl.h b/content/child/web_url_loader_impl.h
index 7c55189..7320f5ed 100644
--- a/content/child/web_url_loader_impl.h
+++ b/content/child/web_url_loader_impl.h
@@ -34,6 +34,10 @@
   ResourceResponseHead response;
   std::vector<GURL> redirects;
   std::vector<ResourceResponseInfo> redirect_responses;
+
+  // The delta between the actual transfer size and the one reported by the
+  // AsyncResourceLoader due to not having the ResourceResponse.
+  int total_transfer_size_delta;
 };
 
 class CONTENT_EXPORT WebURLLoaderImpl
diff --git a/content/public/android/java/src/org/chromium/content/browser/OWNERS b/content/public/android/java/src/org/chromium/content/browser/OWNERS
index fb4de38..5e1b79f 100644
--- a/content/public/android/java/src/org/chromium/content/browser/OWNERS
+++ b/content/public/android/java/src/org/chromium/content/browser/OWNERS
@@ -1,11 +1,6 @@
 # Device Motion / Orientation API related
-per-file DeviceSensors.java=mvanouwerkerk@chromium.org
 per-file DeviceSensors.java=timvolodine@chromium.org
 
-# Geolocation API related
-per-file LocationProvider*.java=mvanouwerkerk@chromium.org
-per-file LocationProvider*.java=timvolodine@chromium.org
-
 # Screen Orientation API related
 per-file ScreenOrientation*.java=mlamouri@chromium.org
 
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/OWNERS b/content/public/android/javatests/src/org/chromium/content/browser/OWNERS
index d569bc71..e791694 100644
--- a/content/public/android/javatests/src/org/chromium/content/browser/OWNERS
+++ b/content/public/android/javatests/src/org/chromium/content/browser/OWNERS
@@ -1,5 +1,4 @@
 # Device Motion / Orientation API related
-per-file DeviceSensorsTest.java=mvanouwerkerk@chromium.org
 per-file DeviceSensorsTest.java=timvolodine@chromium.org
 
 # Geolocation API related
diff --git a/content/renderer/media/OWNERS b/content/renderer/media/OWNERS
index e1c3bcf3..47e2073 100644
--- a/content/renderer/media/OWNERS
+++ b/content/renderer/media/OWNERS
@@ -3,8 +3,8 @@
 miu@chromium.org
 
 # WebRTC OWNERS.
+emircan@chromium.org
 hbos@chromium.org
-perkj@chromium.org
 tommi@chromium.org
 
 per-file *midi*=toyoshim@chromium.org
diff --git a/device/bluetooth/bluetooth_remote_gatt_characteristic.cc b/device/bluetooth/bluetooth_remote_gatt_characteristic.cc
index 8c94e7a5..77cd0a3a 100644
--- a/device/bluetooth/bluetooth_remote_gatt_characteristic.cc
+++ b/device/bluetooth/bluetooth_remote_gatt_characteristic.cc
@@ -235,7 +235,8 @@
   NotifySessionCommand* command = new NotifySessionCommand(
       base::Bind(&BluetoothRemoteGattCharacteristic::ExecuteStopNotifySession,
                  GetWeakPtr(), session, callback),
-      callback /* cancel_callback */);
+      base::Bind(&BluetoothRemoteGattCharacteristic::CancelStopNotifySession,
+                 GetWeakPtr(), callback));
 
   pending_notify_commands_.push(std::unique_ptr<NotifySessionCommand>(command));
   if (pending_notify_commands_.size() == 1) {
diff --git a/docs/windows_build_instructions.md b/docs/windows_build_instructions.md
index 70ab1302..beadbba 100644
--- a/docs/windows_build_instructions.md
+++ b/docs/windows_build_instructions.md
@@ -14,7 +14,8 @@
 
 * A 64-bit Intel machine with at least 8GB of RAM. More than 16GB is highly
   recommended.
-* At least 100GB of free disk space.
+* At least 100GB of free disk space on an NTFS-formatted hard drive. FAT32
+  will not work, as some of the Git packfiles are larger than 4GB.
 * Visual Studio 2015 Update 3, see below (no other version is supported).
 * Windows 7 or newer.
 
@@ -52,20 +53,17 @@
 ***
 
 Add depot_tools to the start of your PATH (must be ahead of any installs of 
-Python). Assuming you unzipped the bundle to C:\src\depot_tools:
-
-With Administrator access:
+Python). Assuming you unzipped the bundle to C:\src\depot_tools, open:
 
 Control Panel → System and Security → System → Advanced system settings
 
-Modify the PATH system variable to include C:\src\depot_tools.
+If you have Administrator access, Modify the PATH system variable and
+put `C:\src\depot_tools` at the front (or at least in front of any directory
+that might already have a copy of Python or Git).
 
-Without Administrator access:
-
-Control Panel → User Accounts → User Accounts → Change my environment variables
-
-Add a PATH user variable (or modify the existing one to include):
-`C:\src\depot_tools`.
+If you don't have Administrator access, you can add a user-level PATH
+environment variable and put `C:\src\depot_tools` at the front, but
+if your system PATH has a Python in it, you will be out of luck.
 
 Also, add a DEPOT_TOOLS_WIN_TOOLCHAIN system variable in the same way, and set
 it to 0. This tells depot_tools to use your locally installed version of Visual
diff --git a/ios/chrome/app/multitasking_test_application_delegate.mm b/ios/chrome/app/multitasking_test_application_delegate.mm
index d9030a03..f5a3a8eb 100644
--- a/ios/chrome/app/multitasking_test_application_delegate.mm
+++ b/ios/chrome/app/multitasking_test_application_delegate.mm
@@ -86,7 +86,9 @@
       size.height = kRegularIPadPortraitSize.width;
     }
   } else {
-    LOG(ERROR) << "Unsupported multitasking test mode.";
+    NOTREACHED() << "Unsupported multitasking test mode. Only "
+                    "--enable-slide-over-test-mode and "
+                    "--enable-split-view-test-mode are supported.";
   }
   return size;
 }
diff --git a/ios/chrome/browser/tabs/tab.mm b/ios/chrome/browser/tabs/tab.mm
index 0cd014850..06dab25a 100644
--- a/ios/chrome/browser/tabs/tab.mm
+++ b/ios/chrome/browser/tabs/tab.mm
@@ -1768,7 +1768,8 @@
   // |disableFullScreen| is called only from one place.
   [fullScreenController_ disableFullScreen];
   [findInPageController_ disableFindInPageWithCompletionHandler:nil];
-  [autoReloadBridge_ loadStartedForURL:webState->GetLastCommittedURL()];
+  GURL lastCommittedURL = webState->GetLastCommittedURL();
+  [autoReloadBridge_ loadStartedForURL:lastCommittedURL];
 
   if (isUserNavigationEvent_) {
     [[NSNotificationCenter defaultCenter]
@@ -1784,7 +1785,7 @@
   favicon::FaviconDriver* faviconDriver =
       favicon::WebFaviconDriver::FromWebState(webState);
   if (faviconDriver) {
-    faviconDriver->FetchFavicon(webState->GetLastCommittedURL());
+    faviconDriver->FetchFavicon(lastCommittedURL);
   }
   [parentTabModel_ notifyTabChanged:self];
   if (parentTabModel_) {
@@ -1794,6 +1795,17 @@
                     userInfo:@{kTabModelTabKey : self}];
   }
   [parentTabModel_ navigationCommittedInTab:self];
+
+  // Sending a notification about the url change for crash reporting.
+  // TODO(crbug.com/661675): Consider using the navigation entry committed
+  // notification now that it's in the right place.
+  NSString* URLSpec = base::SysUTF8ToNSString(lastCommittedURL.spec());
+  if (URLSpec.length) {
+    [[NSNotificationCenter defaultCenter]
+        postNotificationName:kTabUrlStartedLoadingNotificationForCrashReporting
+                      object:self
+                    userInfo:@{kTabUrlKey : URLSpec}];
+  }
 }
 
 // Called when the page URL has changed.
@@ -1803,18 +1815,6 @@
     [self addCurrentEntryToHistoryDB];
     [self countMainFrameLoad];
   }
-
-  // Sending a notification about the url change for crash reporting.
-  // TODO(crbug.com/661675): Consider using the navigation entry committed
-  // notification now that it's in the right place.
-  NSString* urlString = base::SysUTF8ToNSString(currentUrl.spec());
-  if ([urlString length]) {
-    [[NSNotificationCenter defaultCenter]
-        postNotificationName:kTabUrlStartedLoadingNotificationForCrashReporting
-                      object:self
-                    userInfo:[NSDictionary dictionaryWithObject:urlString
-                                                         forKey:kTabUrlKey]];
-  }
 }
 
 - (void)webState:(web::WebState*)webState
@@ -2110,7 +2110,7 @@
   [self updateFullscreenWithToolbarVisible:YES];
 }
 
-- (void)webControllerWebProcessDidCrash:(CRWWebController*)webController {
+- (void)renderProcessGoneForWebState:(web::WebState*)webState {
   if (browserState_ && !browserState_->IsOffTheRecord()) {
     // Report the crash.
     GetApplicationContext()
@@ -2169,21 +2169,6 @@
 
 #pragma mark - WebUserInterfaceDelegate methods.
 
-- (void)webController:(CRWWebController*)webController
-    runAuthDialogForProtectionSpace:(NSURLProtectionSpace*)protectionSpace
-                 proposedCredential:(NSURLCredential*)credential
-                  completionHandler:
-                      (void (^)(NSString* user, NSString* password))handler {
-  if (self.dialogDelegate) {
-    [self.dialogDelegate tab:self
-        runAuthDialogForProtectionSpace:protectionSpace
-                     proposedCredential:credential
-                      completionHandler:handler];
-  } else if (handler) {
-    handler(nil, nil);
-  }
-}
-
 - (void)cancelDialogsForWebController:(CRWWebController*)webController {
   [self.dialogDelegate cancelDialogForTab:self];
 }
diff --git a/ios/chrome/browser/tabs/tab_dialog_delegate.h b/ios/chrome/browser/tabs/tab_dialog_delegate.h
index a57afa2..82d66783 100644
--- a/ios/chrome/browser/tabs/tab_dialog_delegate.h
+++ b/ios/chrome/browser/tabs/tab_dialog_delegate.h
@@ -10,15 +10,6 @@
 // A protocol delegating the display of dialogs for a Tab.
 @protocol TabDialogDelegate
 
-// Displays an HTTP authentication dialog. |completionHandler| should be called
-// with non nil |username| and |password| in order to proceed with
-// authentication.
-- (void)tab:(Tab*)tab
-    runAuthDialogForProtectionSpace:(NSURLProtectionSpace*)protectionSpace
-                 proposedCredential:(NSURLCredential*)credential
-                  completionHandler:
-                      (void (^)(NSString* user, NSString* password))handler;
-
 // Called by Tabs to cancel a previously-requested dialog.
 - (void)cancelDialogForTab:(Tab*)tab;
 
diff --git a/ios/chrome/browser/ui/browser_view_controller.mm b/ios/chrome/browser/ui/browser_view_controller.mm
index af75824e2..2cc3d7b1 100644
--- a/ios/chrome/browser/ui/browser_view_controller.mm
+++ b/ios/chrome/browser/ui/browser_view_controller.mm
@@ -2574,6 +2574,17 @@
   return _javaScriptDialogPresenter.get();
 }
 
+- (void)webState:(web::WebState*)webState
+    didRequestHTTPAuthForProtectionSpace:(NSURLProtectionSpace*)protectionSpace
+                      proposedCredential:(NSURLCredential*)proposedCredential
+                       completionHandler:(void (^)(NSString* username,
+                                                   NSString* password))handler {
+  [self.dialogPresenter runAuthDialogForProtectionSpace:protectionSpace
+                                     proposedCredential:proposedCredential
+                                               webState:webState
+                                      completionHandler:handler];
+}
+
 #pragma mark - FullScreenControllerDelegate methods
 
 - (CGFloat)headerOffset {
@@ -5081,17 +5092,6 @@
 
 #pragma mark - TabDialogDelegate methods
 
-- (void)tab:(Tab*)tab
-    runAuthDialogForProtectionSpace:(NSURLProtectionSpace*)protectionSpace
-                 proposedCredential:(NSURLCredential*)credential
-                  completionHandler:
-                      (void (^)(NSString* user, NSString* password))handler {
-  [self.dialogPresenter runAuthDialogForProtectionSpace:protectionSpace
-                                     proposedCredential:credential
-                                               webState:tab.webState
-                                      completionHandler:handler];
-}
-
 - (void)cancelDialogForTab:(Tab*)tab {
   [self.dialogPresenter cancelDialogForWebState:tab.webState];
 }
diff --git a/ios/chrome/widget_extension/widget_view.mm b/ios/chrome/widget_extension/widget_view.mm
index 843adccd3..d2c5a77e 100644
--- a/ios/chrome/widget_extension/widget_view.mm
+++ b/ios/chrome/widget_extension/widget_view.mm
@@ -8,13 +8,59 @@
 #error "This file requires ARC support."
 #endif
 
+namespace {
+
+const CGFloat kCursorHeight = 40;
+const CGFloat kCursorWidth = 2;
+const CGFloat kCursorHorizontalPadding = 40;
+
+}  // namespace
+
+@interface WidgetView ()
+
+@property(nonatomic, weak) UIView* cursor;
+
+// Creates a cursor, adds it to the view and sets the class cursor property.
+- (void)addCursor;
+
+@end
+
 @implementation WidgetView
 
-#pragma mark - Lifecycle
+@synthesize cursor = _cursor;
 
 - (instancetype)init {
   self = [super initWithFrame:CGRectZero];
+  if (self) {
+    [self addCursor];
+  }
   return self;
 }
 
+- (void)addCursor {
+  UIView* cursor = [[UIView alloc] initWithFrame:CGRectZero];
+  self.cursor = cursor;
+  self.cursor.backgroundColor = [UIColor blueColor];
+  [self addSubview:self.cursor];
+
+  [self.cursor setTranslatesAutoresizingMaskIntoConstraints:NO];
+  [NSLayoutConstraint activateConstraints:@[
+    [[self.cursor widthAnchor] constraintEqualToConstant:kCursorWidth],
+    [[self.cursor leadingAnchor]
+        constraintEqualToAnchor:self.leadingAnchor
+                       constant:kCursorHorizontalPadding],
+    [[self.cursor heightAnchor] constraintEqualToConstant:kCursorHeight],
+    [[self.cursor centerYAnchor] constraintEqualToAnchor:self.centerYAnchor]
+  ]];
+
+  [UIView animateWithDuration:0.3
+                        delay:0.0
+                      options:UIViewAnimationOptionRepeat |
+                              UIViewAnimationOptionAutoreverse
+                   animations:^{
+                     self.cursor.alpha = 0.0f;
+                   }
+                   completion:nil];
+}
+
 @end
diff --git a/ios/chrome/widget_extension/widget_view_controller.mm b/ios/chrome/widget_extension/widget_view_controller.mm
index dfe050a..735d49e 100644
--- a/ios/chrome/widget_extension/widget_view_controller.mm
+++ b/ios/chrome/widget_extension/widget_view_controller.mm
@@ -30,6 +30,18 @@
   WidgetView* widgetView = [[WidgetView alloc] init];
   self.widgetView = widgetView;
   [self.view addSubview:self.widgetView];
+
+  [self.widgetView setTranslatesAutoresizingMaskIntoConstraints:NO];
+  [NSLayoutConstraint activateConstraints:@[
+    [self.widgetView.leadingAnchor
+        constraintEqualToAnchor:[self.view leadingAnchor]],
+    [self.widgetView.trailingAnchor
+        constraintEqualToAnchor:[self.view trailingAnchor]],
+    [self.widgetView.heightAnchor
+        constraintEqualToAnchor:[self.view heightAnchor]],
+    [self.widgetView.widthAnchor
+        constraintEqualToAnchor:[self.view widthAnchor]]
+  ]];
 }
 
 @end
diff --git a/ios/web/public/test/fakes/test_web_state_delegate.h b/ios/web/public/test/fakes/test_web_state_delegate.h
index 6cb8363..e1eb13e 100644
--- a/ios/web/public/test/fakes/test_web_state_delegate.h
+++ b/ios/web/public/test/fakes/test_web_state_delegate.h
@@ -5,14 +5,33 @@
 #ifndef IOS_WEB_PUBLIC_TEST_FAKES_TEST_WEB_STATE_DELEGATE_H_
 #define IOS_WEB_PUBLIC_TEST_FAKES_TEST_WEB_STATE_DELEGATE_H_
 
+#import <Foundation/Foundation.h>
+
+#include <memory>
+
+#include "base/mac/scoped_nsobject.h"
 #include "ios/web/public/web_state/web_state_delegate.h"
 #import "ios/web/public/test/fakes/test_java_script_dialog_presenter.h"
 
 namespace web {
 
+// Encapsulates parameters passed to OnAuthRequired.
+struct TestAuthenticationRequest {
+  TestAuthenticationRequest();
+  TestAuthenticationRequest(const TestAuthenticationRequest&);
+  ~TestAuthenticationRequest();
+  WebState* web_state = nullptr;
+  base::scoped_nsobject<NSURLProtectionSpace> protection_space;
+  base::scoped_nsobject<NSURLCredential> credential;
+  WebStateDelegate::AuthCallback auth_callback;
+};
+
 // Fake WebStateDelegate used for testing purposes.
 class TestWebStateDelegate : public WebStateDelegate {
  public:
+  TestWebStateDelegate();
+  ~TestWebStateDelegate() override;
+
   // WebStateDelegate overrides:
   JavaScriptDialogPresenter* GetJavaScriptDialogPresenter(WebState*) override;
   void LoadProgressChanged(WebState* source, double progress) override;
@@ -20,6 +39,10 @@
                          const ContextMenuParams& params) override;
 
   TestJavaScriptDialogPresenter* GetTestJavaScriptDialogPresenter();
+  void OnAuthRequired(WebState* source,
+                      NSURLProtectionSpace* protection_space,
+                      NSURLCredential* proposed_credential,
+                      const AuthCallback& callback) override;
 
   // True if the WebStateDelegate LoadProgressChanged method has been called.
   bool load_progress_changed_called() const {
@@ -37,11 +60,17 @@
     return get_java_script_dialog_presenter_called_;
   }
 
+  // Returns the last HTTP Authentication request passed to |OnAuthRequired|.
+  TestAuthenticationRequest* last_authentication_request() const {
+    return last_authentication_request_.get();
+  }
+
  private:
   bool load_progress_changed_called_ = false;
   bool handle_context_menu_called_ = false;
   bool get_java_script_dialog_presenter_called_ = false;
   TestJavaScriptDialogPresenter java_script_dialog_presenter_;
+  std::unique_ptr<TestAuthenticationRequest> last_authentication_request_;
 };
 
 }  // namespace web
diff --git a/ios/web/public/test/fakes/test_web_state_delegate.mm b/ios/web/public/test/fakes/test_web_state_delegate.mm
index 3792e05..26683ef 100644
--- a/ios/web/public/test/fakes/test_web_state_delegate.mm
+++ b/ios/web/public/test/fakes/test_web_state_delegate.mm
@@ -4,8 +4,18 @@
 
 #import "ios/web/public/test/fakes/test_web_state_delegate.h"
 
+#include "base/memory/ptr_util.h"
+
 namespace web {
 
+TestAuthenticationRequest::TestAuthenticationRequest() {}
+
+TestAuthenticationRequest::~TestAuthenticationRequest() = default;
+
+TestWebStateDelegate::TestWebStateDelegate() {}
+
+TestWebStateDelegate::~TestWebStateDelegate() = default;
+
 JavaScriptDialogPresenter* TestWebStateDelegate::GetJavaScriptDialogPresenter(
     WebState*) {
   get_java_script_dialog_presenter_called_ = true;
@@ -27,4 +37,17 @@
   return &java_script_dialog_presenter_;
 }
 
+void TestWebStateDelegate::OnAuthRequired(
+    WebState* source,
+    NSURLProtectionSpace* protection_space,
+    NSURLCredential* credential,
+    const AuthCallback& callback) {
+  last_authentication_request_ = base::MakeUnique<TestAuthenticationRequest>();
+  last_authentication_request_->web_state = source;
+  last_authentication_request_->protection_space.reset(
+      [protection_space retain]);
+  last_authentication_request_->credential.reset([credential retain]);
+  last_authentication_request_->auth_callback = callback;
+}
+
 }  // namespace web
diff --git a/ios/web/public/test/test_web_thread_bundle.h b/ios/web/public/test/test_web_thread_bundle.h
index 2723a8a..dc3497c 100644
--- a/ios/web/public/test/test_web_thread_bundle.h
+++ b/ios/web/public/test/test_web_thread_bundle.h
@@ -6,25 +6,22 @@
 #define IOS_WEB_PUBLIC_TEST_TEST_WEB_THREAD_BUNDLE_H_
 
 // TestWebThreadBundle is a convenience class for creating a set of
-// TestWebThreads in unit tests.  For most tests, it is sufficient to
-// just instantiate the TestWebThreadBundle as a member variable.
+// TestWebThreads, a blocking pool, and a task scheduler in unit tests. For
+// most tests, it is sufficient to just instantiate the TestWebThreadBundle as a
+// member variable. It is a good idea to put the TestWebThreadBundle as the
+// first member variable in test classes, so it is destroyed last, and the test
+// threads always exist from the perspective of other classes.
 //
-// By default, all of the created TestWebThreads will be backed by a single
-// shared MessageLoop. If a test truly needs separate threads, it can do
-// so by passing the appropriate combination of RealThreadsMask values during
-// the TestWebThreadBundle construction.
+// By default, all of the created TestWebThreads and the task scheduler will
+// be backed by a single shared MessageLoop. If a test truly needs separate
+// threads, it can do so by passing the appropriate combination of option values
+// during the TestWebThreadBundle construction.
 //
-// The TestWebThreadBundle will attempt to drain the MessageLoop on
-// destruction. Sometimes a test needs to drain currently enqueued tasks
-// mid-test.
-//
-// The TestWebThreadBundle will also flush the blocking pool on destruction.
-// We do this to avoid memory leaks, particularly in the case of threads posting
-// tasks to the blocking pool via PostTaskAndReply. By ensuring that the tasks
-// are run while the originating TestBroswserThreads still exist, we prevent
-// leakage of PostTaskAndReplyRelay objects. We also flush the blocking pool
-// again at the point where it would normally be shut down, to better simulate
-// the normal thread shutdown process.
+// To synchronously run tasks posted to task scheduler or to TestWebThreads
+// that use the shared MessageLoop, call RunLoop::Run/RunUntilIdle() on the
+// thread where the TestWebThreadBundle lives. The destructor of
+// TestWebThreadBundle runs remaining TestWebThreads tasks, remaining
+// blocking pool tasks, and remaining BLOCK_SHUTDOWN task scheduler tasks.
 //
 // Some tests using the IO thread expect a MessageLoopForIO. Passing
 // IO_MAINLOOP will use a MessageLoopForIO for the main MessageLoop.
@@ -36,7 +33,11 @@
 
 namespace base {
 class MessageLoop;
-}
+namespace test {
+class ScopedAsyncTaskScheduler;
+class ScopedTaskScheduler;
+}  // namespace test
+}  // namespace base
 
 namespace web {
 
@@ -48,11 +49,12 @@
   // which of the named WebThreads should be backed by a real
   // threads. The UI thread is always the main thread in a unit test.
   enum Options {
-    DEFAULT = 0x00,
-    IO_MAINLOOP = 0x01,
-    REAL_DB_THREAD = 0x02,
-    REAL_FILE_THREAD = 0x04,
-    REAL_IO_THREAD = 0x08,
+    DEFAULT = 0,
+    IO_MAINLOOP = 1 << 0,
+    REAL_DB_THREAD = 1 << 1,
+    REAL_FILE_THREAD = 1 << 2,
+    REAL_IO_THREAD = 1 << 3,
+    REAL_TASK_SCHEDULER = 1 << 4,
   };
 
   TestWebThreadBundle();
@@ -64,6 +66,9 @@
   void Init(int options);
 
   std::unique_ptr<base::MessageLoop> message_loop_;
+  std::unique_ptr<base::test::ScopedAsyncTaskScheduler>
+      scoped_async_task_scheduler_;
+  std::unique_ptr<base::test::ScopedTaskScheduler> scoped_task_scheduler_;
   std::unique_ptr<TestWebThread> ui_thread_;
   std::unique_ptr<TestWebThread> db_thread_;
   std::unique_ptr<TestWebThread> file_thread_;
diff --git a/ios/web/public/web_state/crw_web_user_interface_delegate.h b/ios/web/public/web_state/crw_web_user_interface_delegate.h
index 39cc3bb..3db4f57 100644
--- a/ios/web/public/web_state/crw_web_user_interface_delegate.h
+++ b/ios/web/public/web_state/crw_web_user_interface_delegate.h
@@ -16,18 +16,6 @@
 
  @optional
 
-// Displays an HTTP authentication dialog.  |completionHandler| should be called
-// with non-nil |username| and |password| if embedder wants to proceed with
-// authentication.  If this selector isn't implemented or completion is called
-// with nil |username| and nil |password|, authentication will be cancelled.
-// If this method is implemented, but |handler| is not called then
-// NSInternalInconsistencyException will be thrown.
-- (void)webController:(CRWWebController*)webController
-    runAuthDialogForProtectionSpace:(NSURLProtectionSpace*)protectionSpace
-                 proposedCredential:(NSURLCredential*)credential
-                  completionHandler:
-                      (void (^)(NSString* user, NSString* password))handler;
-
 // Cancels any outstanding dialogs requested by the methods above.
 - (void)cancelDialogsForWebController:(CRWWebController*)webController;
 
diff --git a/ios/web/public/web_state/ui/crw_web_delegate.h b/ios/web/public/web_state/ui/crw_web_delegate.h
index 1adc7ed..b8dd184 100644
--- a/ios/web/public/web_state/ui/crw_web_delegate.h
+++ b/ios/web/public/web_state/ui/crw_web_delegate.h
@@ -180,9 +180,6 @@
 - (void)webControllerDidUpdateSSLStatusForCurrentNavigationItem:
     (CRWWebController*)webController;
 
-// Called when web view process has been terminated.
-- (void)webControllerWebProcessDidCrash:(CRWWebController*)webController;
-
 // Called when a PassKit file is downloaded. |data| should be the data from a
 // PassKit file, but this is not guaranteed, and the delegate is responsible for
 // error handling non PassKit data using -[PKPass initWithData:error:]. If the
diff --git a/ios/web/public/web_state/web_state_delegate.h b/ios/web/public/web_state/web_state_delegate.h
index 2392d11..d5f1590 100644
--- a/ios/web/public/web_state/web_state_delegate.h
+++ b/ios/web/public/web_state/web_state_delegate.h
@@ -7,6 +7,8 @@
 
 #include <set>
 
+#import <Foundation/Foundation.h>
+
 #include "base/callback.h"
 #import "ios/web/public/web_state/web_state.h"
 
@@ -43,6 +45,17 @@
   virtual JavaScriptDialogPresenter* GetJavaScriptDialogPresenter(
       WebState* source);
 
+  // Called when a request receives an authentication challenge specified by
+  // |protection_space|, and is unable to respond using cached credentials.
+  // Clients must call |callback| even if they want to cancel authentication
+  // (in which case |username| or |password| should be nil).
+  typedef base::Callback<void(NSString* username, NSString* password)>
+      AuthCallback;
+  virtual void OnAuthRequired(WebState* source,
+                              NSURLProtectionSpace* protection_space,
+                              NSURLCredential* proposed_credential,
+                              const AuthCallback& callback) = 0;
+
  protected:
   virtual ~WebStateDelegate();
 
diff --git a/ios/web/public/web_state/web_state_delegate_bridge.h b/ios/web/public/web_state/web_state_delegate_bridge.h
index 8378da6..11eef9f 100644
--- a/ios/web/public/web_state/web_state_delegate_bridge.h
+++ b/ios/web/public/web_state/web_state_delegate_bridge.h
@@ -35,6 +35,15 @@
 - (web::JavaScriptDialogPresenter*)javaScriptDialogPresenterForWebState:
     (web::WebState*)webState;
 
+// Called when a request receives an authentication challenge specified by
+// |protectionSpace|, and is unable to respond using cached credentials.
+// Clients must call |handler| even if they want to cancel authentication
+// (in which case |username| or |password| should be nil).
+- (void)webState:(web::WebState*)webState
+    didRequestHTTPAuthForProtectionSpace:(NSURLProtectionSpace*)protectionSpace
+                      proposedCredential:(NSURLCredential*)proposedCredential
+                       completionHandler:(void (^)(NSString* username,
+                                                   NSString* password))handler;
 @end
 
 namespace web {
@@ -53,6 +62,10 @@
                          const ContextMenuParams& params) override;
   JavaScriptDialogPresenter* GetJavaScriptDialogPresenter(
       WebState* source) override;
+  void OnAuthRequired(WebState* source,
+                      NSURLProtectionSpace* protection_space,
+                      NSURLCredential* proposed_credential,
+                      const AuthCallback& callback) override;
 
  private:
   // CRWWebStateDelegate which receives forwarded calls.
diff --git a/ios/web/public/web_state/web_state_observer.h b/ios/web/public/web_state/web_state_observer.h
index ca05867..53698a5 100644
--- a/ios/web/public/web_state/web_state_observer.h
+++ b/ios/web/public/web_state/web_state_observer.h
@@ -82,6 +82,10 @@
   // Invoked when new favicon URL candidates are received.
   virtual void FaviconUrlUpdated(const std::vector<FaviconURL>& candidates) {}
 
+  // Called when the web process is terminated (usually by crashing, though
+  // possibly by other means).
+  virtual void RenderProcessGone() {}
+
   // Notifies the observer that the credential manager API was invoked from
   // |source_url| to request a credential from the browser. If |unmediated|
   // is true, the browser MUST NOT show any UI to the user. If this means that
diff --git a/ios/web/public/web_state/web_state_observer_bridge.h b/ios/web/public/web_state/web_state_observer_bridge.h
index 895f96a..1b88355d3 100644
--- a/ios/web/public/web_state/web_state_observer_bridge.h
+++ b/ios/web/public/web_state/web_state_observer_bridge.h
@@ -60,6 +60,9 @@
     didUpdateFaviconURLCandidates:
         (const std::vector<web::FaviconURL>&)candidates;
 
+// Invoked by WebStateObserverBridge::RenderProcessGone.
+- (void)renderProcessGoneForWebState:(web::WebState*)webState;
+
 // Note: after |webStateDestroyed:| is invoked, the WebState being observed
 // is no longer valid.
 - (void)webStateDestroyed:(web::WebState*)webState;
@@ -103,6 +106,7 @@
                               const std::string& value,
                               bool input_missing) override;
   void FaviconUrlUpdated(const std::vector<FaviconURL>& candidates) override;
+  void RenderProcessGone() override;
   void WebStateDestroyed() override;
   void DidStartLoading() override;
   void DidStopLoading() override;
diff --git a/ios/web/test/test_web_thread_bundle.cc b/ios/web/test/test_web_thread_bundle.cc
index 42ead5cb..14eb656 100644
--- a/ios/web/test/test_web_thread_bundle.cc
+++ b/ios/web/test/test_web_thread_bundle.cc
@@ -4,8 +4,11 @@
 
 #include "ios/web/public/test/test_web_thread_bundle.h"
 
+#include "base/memory/ptr_util.h"
 #include "base/message_loop/message_loop.h"
 #include "base/run_loop.h"
+#include "base/test/scoped_async_task_scheduler.h"
+#include "base/test/scoped_task_scheduler.h"
 #include "ios/web/public/test/test_web_thread.h"
 #include "ios/web/web_thread_impl.h"
 
@@ -48,6 +51,9 @@
   base::RunLoop().RunUntilIdle();
   ui_thread_.reset();
   base::RunLoop().RunUntilIdle();
+
+  scoped_async_task_scheduler_.reset();
+  scoped_task_scheduler_.reset();
 }
 
 void TestWebThreadBundle::Init(int options) {
@@ -59,6 +65,14 @@
 
   ui_thread_.reset(new TestWebThread(WebThread::UI, message_loop_.get()));
 
+  if (options & REAL_TASK_SCHEDULER) {
+    scoped_async_task_scheduler_ =
+        base::MakeUnique<base::test::ScopedAsyncTaskScheduler>();
+  } else {
+    scoped_task_scheduler_ =
+        base::MakeUnique<base::test::ScopedTaskScheduler>(message_loop_.get());
+  }
+
   if (options & TestWebThreadBundle::REAL_DB_THREAD) {
     db_thread_.reset(new TestWebThread(WebThread::DB));
     db_thread_->Start();
diff --git a/ios/web/web_state/ui/crw_web_controller.mm b/ios/web/web_state/ui/crw_web_controller.mm
index 88e3349..ea28c26 100644
--- a/ios/web/web_state/ui/crw_web_controller.mm
+++ b/ios/web/web_state/ui/crw_web_controller.mm
@@ -3666,25 +3666,13 @@
     return;
   }
 
-  SEL selector = @selector(webController:
-         runAuthDialogForProtectionSpace:
-                      proposedCredential:
-                       completionHandler:);
-  if (![self.UIDelegate respondsToSelector:selector]) {
-    // Embedder does not support HTTP Authentication.
-    completionHandler(NSURLSessionAuthChallengeRejectProtectionSpace, nil);
-    return;
-  }
-
-  [self.UIDelegate webController:self
-      runAuthDialogForProtectionSpace:space
-                   proposedCredential:challenge.proposedCredential
-                    completionHandler:^(NSString* user, NSString* password) {
-                      [CRWWebController
-                          processHTTPAuthForUser:user
+  _webStateImpl->OnAuthRequired(
+      space, challenge.proposedCredential,
+      base::BindBlock(^(NSString* user, NSString* password) {
+        [CRWWebController processHTTPAuthForUser:user
                                         password:password
                                completionHandler:completionHandler];
-                    }];
+      }));
 }
 
 + (void)processHTTPAuthForUser:(NSString*)user
@@ -4544,9 +4532,7 @@
     [self.UIDelegate cancelDialogsForWebController:self];
   _webStateImpl->CancelDialogs();
 
-  SEL rendererCrashSelector = @selector(webControllerWebProcessDidCrash:);
-  if ([self.delegate respondsToSelector:rendererCrashSelector])
-    [self.delegate webControllerWebProcessDidCrash:self];
+  _webStateImpl->OnRenderProcessGone();
 }
 
 - (web::WKWebViewConfigurationProvider&)webViewConfigurationProvider {
diff --git a/ios/web/web_state/ui/crw_web_controller_unittest.mm b/ios/web/web_state/ui/crw_web_controller_unittest.mm
index 836bd30..364580c 100644
--- a/ios/web/web_state/ui/crw_web_controller_unittest.mm
+++ b/ios/web/web_state/ui/crw_web_controller_unittest.mm
@@ -1022,18 +1022,31 @@
   base::scoped_nsobject<WKWebView> webView_;
 };
 
-// Tests that -[CRWWebDelegate webControllerWebProcessDidCrash:] is called
-// when WKWebView web process has crashed.
+// Tests that WebStateDelegate::RenderProcessGone is called when WKWebView web
+// process has crashed.
 TEST_F(CRWWebControllerWebProcessTest, Crash) {
-  id delegate = [OCMockObject niceMockForProtocol:@protocol(CRWWebDelegate)];
-  [[delegate expect] webControllerWebProcessDidCrash:web_controller()];
+  // Observes and waits for RenderProcessGone call.
+  class RenderProcessGoneObserver : public web::WebStateObserver {
+   public:
+    explicit RenderProcessGoneObserver(web::WebState* web_state)
+        : web::WebStateObserver(web_state) {}
+    void WaitForRenderProcessGone() const {
+      base::test::ios::WaitUntilCondition(^{
+        return render_process_gone_;
+      });
+    }
+    // WebStateObserver overrides:
+    void RenderProcessGone() override { render_process_gone_ = true; }
 
-  [web_controller() setDelegate:delegate];
+   private:
+    bool render_process_gone_ = false;
+  };
+
+  RenderProcessGoneObserver observer(web_state());
   web::SimulateWKWebViewCrash(webView_);
+  observer.WaitForRenderProcessGone();
 
-  EXPECT_OCMOCK_VERIFY(delegate);
   EXPECT_FALSE([web_controller() isViewAlive]);
-  [web_controller() setDelegate:nil];
 };
 
 }  // namespace
diff --git a/ios/web/web_state/web_state_delegate.mm b/ios/web/web_state/web_state_delegate.mm
index 68e6fcd9..a6b1698 100644
--- a/ios/web/web_state/web_state_delegate.mm
+++ b/ios/web/web_state/web_state_delegate.mm
@@ -35,6 +35,13 @@
   return nullptr;
 }
 
+void WebStateDelegate::OnAuthRequired(WebState* source,
+                                      NSURLProtectionSpace* protection_space,
+                                      NSURLCredential* proposed_credential,
+                                      const AuthCallback& callback) {
+  callback.Run(nil, nil);
+}
+
 void WebStateDelegate::Attach(WebState* source) {
   DCHECK(attached_states_.find(source) == attached_states_.end());
   attached_states_.insert(source);
diff --git a/ios/web/web_state/web_state_delegate_bridge.mm b/ios/web/web_state/web_state_delegate_bridge.mm
index bd1dfca4..695410a 100644
--- a/ios/web/web_state/web_state_delegate_bridge.mm
+++ b/ios/web/web_state/web_state_delegate_bridge.mm
@@ -46,4 +46,27 @@
   return nullptr;
 }
 
+void WebStateDelegateBridge::OnAuthRequired(
+    WebState* source,
+    NSURLProtectionSpace* protection_space,
+    NSURLCredential* proposed_credential,
+    const AuthCallback& callback) {
+  AuthCallback local_callback(callback);
+  if ([delegate_
+          respondsToSelector:@selector(webState:
+                                 didRequestHTTPAuthForProtectionSpace:
+                                                   proposedCredential:
+                                                    completionHandler:)]) {
+    [delegate_ webState:source
+        didRequestHTTPAuthForProtectionSpace:protection_space
+                          proposedCredential:proposed_credential
+                           completionHandler:^(NSString* username,
+                                               NSString* password) {
+                             local_callback.Run(username, password);
+                           }];
+  } else {
+    local_callback.Run(nil, nil);
+  }
+}
+
 }  // web
diff --git a/ios/web/web_state/web_state_delegate_bridge_unittest.mm b/ios/web/web_state/web_state_delegate_bridge_unittest.mm
index 9d882e20e..422b0ec 100644
--- a/ios/web/web_state/web_state_delegate_bridge_unittest.mm
+++ b/ios/web/web_state/web_state_delegate_bridge_unittest.mm
@@ -4,6 +4,8 @@
 
 #import "ios/web/public/web_state/web_state_delegate_bridge.h"
 
+#import <Foundation/Foundation.h>
+
 #include <memory>
 
 #import "base/mac/scoped_nsobject.h"
@@ -102,4 +104,19 @@
   EXPECT_TRUE([delegate_ javaScriptDialogPresenterRequested]);
 }
 
+// Tests |OnAuthRequired| forwarding.
+TEST_F(WebStateDelegateBridgeTest, OnAuthRequired) {
+  EXPECT_FALSE([delegate_ authenticationRequested]);
+  EXPECT_FALSE([delegate_ webState]);
+  base::scoped_nsobject<NSURLProtectionSpace> protection_space(
+      [[NSURLProtectionSpace alloc] init]);
+  base::scoped_nsobject<NSURLCredential> credential(
+      [[NSURLCredential alloc] init]);
+  WebStateDelegate::AuthCallback callback;
+  bridge_->OnAuthRequired(&test_web_state_, protection_space.get(),
+                          credential.get(), callback);
+  EXPECT_TRUE([delegate_ authenticationRequested]);
+  EXPECT_EQ(&test_web_state_, [delegate_ webState]);
+}
+
 }  // namespace web
diff --git a/ios/web/web_state/web_state_delegate_stub.h b/ios/web/web_state/web_state_delegate_stub.h
index 262ccc0..282fc8b 100644
--- a/ios/web/web_state/web_state_delegate_stub.h
+++ b/ios/web/web_state/web_state_delegate_stub.h
@@ -23,6 +23,9 @@
 @property(nonatomic, readonly) web::ContextMenuParams* contextMenuParams;
 // Whether |javaScriptDialogPresenterForWebState:| has been called or not.
 @property(nonatomic, readonly) BOOL javaScriptDialogPresenterRequested;
+// Whether |authenticationRequested| has been called or not.
+@property(nonatomic, readonly) BOOL authenticationRequested;
+
 @end
 
 #endif  // IOS_WEB_WEB_STATE_WEB_STATE_DELEGATE_STUB_H_
diff --git a/ios/web/web_state/web_state_delegate_stub.mm b/ios/web/web_state/web_state_delegate_stub.mm
index 740ad03..b86a9eba 100644
--- a/ios/web/web_state/web_state_delegate_stub.mm
+++ b/ios/web/web_state/web_state_delegate_stub.mm
@@ -18,6 +18,7 @@
 
 @synthesize webState = _webState;
 @synthesize changedProgress = _changedProgress;
+@synthesize authenticationRequested = _authenticationRequested;
 
 - (web::WebState*)webState:(web::WebState*)webState
          openURLWithParams:(const web::WebState::OpenURLParams&)params {
@@ -45,6 +46,15 @@
   return nil;
 }
 
+- (void)webState:(web::WebState*)webState
+    didRequestHTTPAuthForProtectionSpace:(NSURLProtectionSpace*)protectionSpace
+                      proposedCredential:(NSURLCredential*)proposedCredential
+                       completionHandler:(void (^)(NSString* username,
+                                                   NSString* password))handler {
+  _webState = webState;
+  _authenticationRequested = YES;
+}
+
 - (const web::WebState::OpenURLParams*)openURLParams {
   return _openURLParams.get();
 }
diff --git a/ios/web/web_state/web_state_impl.h b/ios/web/web_state/web_state_impl.h
index ed7214f..2ea1d5c 100644
--- a/ios/web/web_state/web_state_impl.h
+++ b/ios/web/web_state/web_state_impl.h
@@ -23,6 +23,7 @@
 #import "ios/web/public/java_script_dialog_callback.h"
 #include "ios/web/public/java_script_dialog_type.h"
 #import "ios/web/public/web_state/web_state.h"
+#import "ios/web/public/web_state/web_state_delegate.h"
 #include "url/gurl.h"
 
 @protocol CRWRequestTrackerDelegate;
@@ -45,7 +46,6 @@
 class NavigationManager;
 class ImageDataFetcher;
 class WebInterstitialImpl;
-class WebStateDelegate;
 class WebStateFacadeDelegate;
 class WebStatePolicyDecider;
 class WebUIIOS;
@@ -94,6 +94,9 @@
   // Notifies the observers that the history state of the current page changed.
   void OnHistoryStateChanged();
 
+  // Notifies the observers that the render process was terminated.
+  void OnRenderProcessGone();
+
   // Called when a script command is received.
   // Returns true if the command was handled.
   bool OnScriptCommandReceived(const std::string& command,
@@ -274,6 +277,12 @@
                            NSString* default_prompt_text,
                            const DialogClosedCallback& callback);
 
+  // Notifies the delegate that request receives an authentication challenge
+  // and is unable to respond using cached credentials.
+  void OnAuthRequired(NSURLProtectionSpace* protection_space,
+                      NSURLCredential* proposed_credential,
+                      const WebStateDelegate::AuthCallback& callback);
+
   // Cancels all dialogs associated with this web_state.
   void CancelDialogs();
 
diff --git a/ios/web/web_state/web_state_impl.mm b/ios/web/web_state/web_state_impl.mm
index 4ab5963c..0f0bd47 100644
--- a/ios/web/web_state/web_state_impl.mm
+++ b/ios/web/web_state/web_state_impl.mm
@@ -179,6 +179,11 @@
     observer.HistoryStateChanged();
 }
 
+void WebStateImpl::OnRenderProcessGone() {
+  for (auto& observer : observers_)
+    observer.RenderProcessGone();
+}
+
 bool WebStateImpl::OnScriptCommandReceived(const std::string& command,
                                            const base::DictionaryValue& value,
                                            const GURL& url,
@@ -463,6 +468,18 @@
                                  message_text, default_prompt_text, callback);
 }
 
+void WebStateImpl::OnAuthRequired(
+    NSURLProtectionSpace* protection_space,
+    NSURLCredential* proposed_credential,
+    const WebStateDelegate::AuthCallback& callback) {
+  if (delegate_) {
+    delegate_->OnAuthRequired(this, protection_space, proposed_credential,
+                              callback);
+  } else {
+    callback.Run(nil, nil);
+  }
+}
+
 void WebStateImpl::CancelDialogs() {
   if (delegate_) {
     JavaScriptDialogPresenter* presenter =
diff --git a/ios/web/web_state/web_state_impl_unittest.mm b/ios/web/web_state/web_state_impl_unittest.mm
index 13dd7915..b4628d1 100644
--- a/ios/web/web_state/web_state_impl_unittest.mm
+++ b/ios/web/web_state/web_state_impl_unittest.mm
@@ -437,6 +437,23 @@
   EXPECT_FALSE(presenter->cancel_dialogs_called());
   web_state_->CancelDialogs();
   EXPECT_TRUE(presenter->cancel_dialogs_called());
+
+  // Test that OnAuthRequired() is called.
+  EXPECT_FALSE(delegate.last_authentication_request());
+  base::scoped_nsobject<NSURLProtectionSpace> protection_space(
+      [[NSURLProtectionSpace alloc] init]);
+  base::scoped_nsobject<NSURLCredential> credential(
+      [[NSURLCredential alloc] init]);
+  WebStateDelegate::AuthCallback callback;
+  web_state_->OnAuthRequired(protection_space.get(), credential.get(),
+                             callback);
+  ASSERT_TRUE(delegate.last_authentication_request());
+  EXPECT_EQ(delegate.last_authentication_request()->web_state,
+            web_state_.get());
+  EXPECT_EQ(delegate.last_authentication_request()->protection_space,
+            protection_space.get());
+  EXPECT_EQ(delegate.last_authentication_request()->credential,
+            credential.get());
 }
 
 // Verifies that GlobalWebStateObservers are called when expected.
diff --git a/ios/web/web_state/web_state_observer_bridge.mm b/ios/web/web_state/web_state_observer_bridge.mm
index b00fb2b..d8621e8 100644
--- a/ios/web/web_state/web_state_observer_bridge.mm
+++ b/ios/web/web_state/web_state_observer_bridge.mm
@@ -119,6 +119,11 @@
     [observer_ webState:web_state() didUpdateFaviconURLCandidates:candidates];
 }
 
+void WebStateObserverBridge::RenderProcessGone() {
+  if ([observer_ respondsToSelector:@selector(renderProcessGoneForWebState:)])
+    [observer_ renderProcessGoneForWebState:web_state()];
+}
+
 void WebStateObserverBridge::WebStateDestroyed() {
   SEL selector = @selector(webStateDestroyed:);
   if ([observer_ respondsToSelector:selector]) {
diff --git a/media/capture/video/OWNERS b/media/capture/video/OWNERS
index 3165f0b..f385a14 100644
--- a/media/capture/video/OWNERS
+++ b/media/capture/video/OWNERS
@@ -1,3 +1,3 @@
+emircan@chromium.org
 mcasas@chromium.org
-perkj@chromium.org
 tommi@chromium.org
diff --git a/net/base/net_error_list.h b/net/base/net_error_list.h
index 8bb47cb..617a56d 100644
--- a/net/base/net_error_list.h
+++ b/net/base/net_error_list.h
@@ -382,9 +382,9 @@
 // fallback will be removed.
 NET_ERROR(SSL_OBSOLETE_CIPHER, -172)
 
-// When a WebSocket handshake is done successfully, the URLRequest is cancelled
-// with this error code.
-NET_ERROR(WEBSOCKET_HANDSHAKE_SUCCESS, -173)
+// When a WebSocket handshake is done successfully and the connection has been
+// upgraded, the URLRequest is cancelled with this error code.
+NET_ERROR(WS_UPGRADE, -173)
 
 // Certificate error codes
 //
diff --git a/net/socket/ssl_client_socket_impl.cc b/net/socket/ssl_client_socket_impl.cc
index 6fd3c363..a50b190 100644
--- a/net/socket/ssl_client_socket_impl.cc
+++ b/net/socket/ssl_client_socket_impl.cc
@@ -241,7 +241,8 @@
 class SSLClientSocketImpl::SSLContext {
  public:
   static SSLContext* GetInstance() {
-    return base::Singleton<SSLContext>::get();
+    return base::Singleton<SSLContext,
+                           base::LeakySingletonTraits<SSLContext>>::get();
   }
   SSL_CTX* ssl_ctx() { return ssl_ctx_.get(); }
   SSLClientSessionCache* session_cache() { return &session_cache_; }
diff --git a/net/websockets/websocket_stream.cc b/net/websockets/websocket_stream.cc
index ca73a53..b700519a 100644
--- a/net/websockets/websocket_stream.cc
+++ b/net/websockets/websocket_stream.cc
@@ -154,7 +154,7 @@
     connect_delegate_->OnSuccess(handshake_stream->Upgrade());
 
     // This is safe even if |this| has already been deleted.
-    url_request->CancelWithError(ERR_WEBSOCKET_HANDSHAKE_SUCCESS);
+    url_request->CancelWithError(ERR_WS_UPGRADE);
   }
 
   std::string FailureMessageFromNetError(int net_error) {
diff --git a/net/websockets/websocket_stream_test.cc b/net/websockets/websocket_stream_test.cc
index 78bda66..5945e24 100644
--- a/net/websockets/websocket_stream_test.cc
+++ b/net/websockets/websocket_stream_test.cc
@@ -337,7 +337,7 @@
   EXPECT_TRUE(stream_);
   EXPECT_TRUE(request_info_);
   EXPECT_TRUE(response_info_);
-  EXPECT_EQ(ERR_WEBSOCKET_HANDSHAKE_SUCCESS,
+  EXPECT_EQ(ERR_WS_UPGRADE,
             url_request_context_host_.network_delegate().last_error());
 }
 
diff --git a/remoting/client/ios/BUILD.gn b/remoting/client/ios/BUILD.gn
index 2e9ee82..b2644f1 100644
--- a/remoting/client/ios/BUILD.gn
+++ b/remoting/client/ios/BUILD.gn
@@ -2,6 +2,8 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
+import("//remoting/build/config/remoting_build.gni")
+
 group("all") {
   testonly = true
 
@@ -34,6 +36,7 @@
     "//base",
     "//remoting/base",
     "//remoting/client",
+    "//remoting/client/ios/bridge",
     "//remoting/protocol",
     "//third_party/google_toolbox_for_mac",
     "//ui/base",
@@ -46,8 +49,15 @@
 
 source_set("ios_core") {
   sources = [
+    "app_runtime.cc",
+    "app_runtime.h",
+    "client_gestures.h",
+    "client_gestures.mm",
     "host.h",
     "host.mm",
+    "host_preferences.h",
+    "host_preferences.mm",
+    "host_preferences_persistence.h",
     "key_input.h",
     "key_input.mm",
     "key_map_us.h",
@@ -55,6 +65,10 @@
     "utility.mm",
   ]
 
+  if (!is_chrome_branded) {
+    sources += [ "host_preferences_persistence_chromium.mm" ]
+  }
+
   public_deps = [
     "//third_party/webrtc/base:rtc_base",
     "//third_party/webrtc/modules/desktop_capture:primitives",
@@ -62,6 +76,7 @@
 
   deps = [
     "//base",
+    "//remoting/protocol",
   ]
 
   libs = [
diff --git a/remoting/client/ios/app_runtime.cc b/remoting/client/ios/app_runtime.cc
new file mode 100644
index 0000000..f03b9067
--- /dev/null
+++ b/remoting/client/ios/app_runtime.cc
@@ -0,0 +1,45 @@
+// 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 "remoting/client/ios/app_runtime.h"
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/logging.h"
+#include "base/memory/ptr_util.h"
+#include "base/synchronization/waitable_event.h"
+#include "jingle/glue/thread_wrapper.h"
+#include "net/socket/client_socket_factory.h"
+#include "remoting/base/chromium_url_request.h"
+#include "remoting/base/url_request_context_getter.h"
+#include "remoting/client/audio_player.h"
+#include "remoting/client/client_status_logger.h"
+#include "remoting/client/ios/bridge/client_proxy.h"
+#include "remoting/proto/event.pb.h"
+#include "remoting/protocol/chromium_port_allocator_factory.h"
+#include "remoting/protocol/client_authentication_config.h"
+#include "remoting/protocol/host_stub.h"
+#include "remoting/protocol/negotiating_client_authenticator.h"
+#include "remoting/protocol/transport_context.h"
+#include "remoting/signaling/delegating_signal_strategy.h"
+
+namespace remoting {
+namespace ios {
+
+AppRuntime::AppRuntime() {
+  if (!base::MessageLoop::current()) {
+    ui_loop_.reset(new base::MessageLoopForUI());
+    base::MessageLoopForUI::current()->Attach();
+  } else {
+    ui_loop_.reset(base::MessageLoopForUI::current());
+  }
+  runtime_ = ChromotingClientRuntime::Create(ui_loop_.get());
+}
+
+AppRuntime::~AppRuntime() {
+  // TODO(nicholss): Shutdown the app.
+}
+
+}  // namespace ios
+}  // namespace remoting
diff --git a/remoting/client/ios/app_runtime.h b/remoting/client/ios/app_runtime.h
new file mode 100644
index 0000000..5441e476
--- /dev/null
+++ b/remoting/client/ios/app_runtime.h
@@ -0,0 +1,67 @@
+// 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 REMOTING_CLIENT_IOS_APP_RUNTIME_H_
+#define REMOTING_CLIENT_IOS_APP_RUNTIME_H_
+
+#include <memory>
+#include <string>
+
+#include "base/bind.h"
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/weak_ptr.h"
+#include "base/message_loop/message_loop.h"
+#include "remoting/base/auto_thread.h"
+#include "remoting/client/chromoting_client_runtime.h"
+
+// TODO(nicholss): Saving this for a pending CL that introduces audio.
+//#include "remoting/client/ios/audio_player_ios.h"
+
+namespace remoting {
+namespace ios {
+
+class AppRuntime {
+ public:
+  AppRuntime();
+
+  scoped_refptr<AutoThreadTaskRunner> display_task_runner() {
+    return runtime_->ui_task_runner();
+  }
+
+  scoped_refptr<AutoThreadTaskRunner> network_task_runner() {
+    return runtime_->network_task_runner();
+  }
+
+  scoped_refptr<AutoThreadTaskRunner> file_task_runner() {
+    return runtime_->file_task_runner();
+  }
+
+  // TODO(nicholss): Saving this for a pending CL that introduces audio.
+  //  scoped_refptr<AutoThreadTaskRunner> audio_task_runner() {
+  //    return _runtime->audio_task_runner();
+  //  }
+
+ private:
+  // This object is ref-counted, so it cleans itself up.
+  ~AppRuntime();
+
+  // TODO(nicholss): Saving this for a pending CL that introduces GL rendering.
+  //  void SetupOpenGl();
+
+  // Chromium code's connection to the OBJ_C message loop.  Once created the
+  // MessageLoop will live for the life of the program.  An attempt was made to
+  // create the primary message loop earlier in the programs life, but a
+  // MessageLoop requires ARC to be disabled.
+  std::unique_ptr<base::MessageLoopForUI> ui_loop_;
+
+  std::unique_ptr<remoting::ChromotingClientRuntime> runtime_;
+
+  DISALLOW_COPY_AND_ASSIGN(AppRuntime);
+};
+
+}  // namespace ios
+}  // namespace remoting
+
+#endif  // REMOTING_CLIENT_IOS_APP_RUNTIME_H_
diff --git a/remoting/client/ios/bridge/client_instance_unittest.mm b/remoting/client/ios/bridge/client_instance_unittest.mm
index f093978..d0e6a175 100644
--- a/remoting/client/ios/bridge/client_instance_unittest.mm
+++ b/remoting/client/ios/bridge/client_instance_unittest.mm
@@ -187,7 +187,7 @@
   HostPreferences* newHost = [HostPreferences hostForId:hostId];
   newHost.pairId = pairingId;
   newHost.pairSecret = pairingSecret;
-  [newHost saveToSSOKeychain];
+  [newHost saveToKeychain];
 
   // Suggesting that our pairing Id is known, but since it is not the correct
   // credentials expect the stored value to be discarded before requesting the
diff --git a/remoting/client/ios/bridge/client_proxy.mm b/remoting/client/ios/bridge/client_proxy.mm
index ad99a27f..6dae2c6e 100644
--- a/remoting/client/ios/bridge/client_proxy.mm
+++ b/remoting/client/ios/bridge/client_proxy.mm
@@ -122,7 +122,7 @@
   host.pairId = nsPairId;
   host.pairSecret = nsPairSecret;
 
-  [host saveToSSOKeychain];
+  [host saveToKeychain];
 }
 
 void ClientProxy::RedrawCanvas(webrtc::DesktopFrame* buffer) {
diff --git a/remoting/client/ios/bridge/client_proxy_unittest.mm b/remoting/client/ios/bridge/client_proxy_unittest.mm
index 3e0e8b4..66faf21 100644
--- a/remoting/client/ios/bridge/client_proxy_unittest.mm
+++ b/remoting/client/ios/bridge/client_proxy_unittest.mm
@@ -198,7 +198,7 @@
     if (existingHost != nil) {
       existingHost.pairId = @"";
       existingHost.pairSecret = @"";
-      [existingHost saveToSSOKeychain];
+      [existingHost saveToKeychain];
     }
 
     clientProxy_->CommitPairingCredentials(hostName, pairingId, pairingSecret);
@@ -230,7 +230,7 @@
   ClientProxyDelegateWrapper* delegateWrapper_;
 };
 
-// TODO(nicholss): Removing these tests for now until we settle on a
+// TODO(nicholss): Commenting these tests out for now until we settle on
 // what the final strings will be.
 // TEST_F(ClientProxyTest, ReportConnectionStatusINITIALIZING) {
 //   TestConnnectionStatus(protocol::ConnectionToHost::State::INITIALIZING,
@@ -284,7 +284,8 @@
                base::SysNSStringToUTF8(kPairingSecret));
 }
 
-// TODO(nicholss): Re-enable these tests.
+// TODO(nicholss): Re-enable these tests. Activly changing how rendering
+// is done for the app at the moment.
 // TEST_F(ClientProxyTest, RedrawCanvasBasic) {
 //   webrtc::BasicDesktopFrame frame(webrtc::DesktopSize(1, 1));
 //   webrtc::DesktopRegion regions;
diff --git a/remoting/client/ios/client_gestures.h b/remoting/client/ios/client_gestures.h
new file mode 100644
index 0000000..aea0d3c
--- /dev/null
+++ b/remoting/client/ios/client_gestures.h
@@ -0,0 +1,67 @@
+// 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 REMOTING_CLIENT_IOS_CLIENT_GESTURES_H_
+#define REMOTING_CLIENT_IOS_CLIENT_GESTURES_H_
+
+#import <Foundation/Foundation.h>
+#import <UIKit/UIKit.h>
+#include "base/logging.h"
+#import "remoting/client/ios/key_input.h"
+
+typedef NS_ENUM(NSInteger, HostInputScheme) {
+  // Mouse cursor is shown
+  // Dragging or Panning, moves the mouse cursor
+  // Tapping causes mouse input at the cursor location
+  HostInputSchemeTrackpad = 0,  // Default
+  // Mouse cursor is not shown
+  // Dragging or Panning is similar to a map
+  // Tapping causes mouse input at the tap location
+  HostInputSchemeTouch = 1
+};
+
+typedef NS_ENUM(NSInteger, MouseButton) {
+
+  NO_BUTTON = 0,
+  LEFT_BUTTON = 1,
+  MIDDLE_BUTTON = 2,
+  RIGHT_BUTTON = 3,
+
+};
+
+@interface ClientGestures : NSObject<UIGestureRecognizerDelegate> {
+ @private
+  UILongPressGestureRecognizer* _longPressRecognizer;
+  UIPanGestureRecognizer* _panRecognizer;
+  UIPanGestureRecognizer* _threeFingerPanRecognizer;
+  UIPinchGestureRecognizer* _pinchRecognizer;
+  UITapGestureRecognizer* _singleTapRecognizer;
+  UITapGestureRecognizer* _twoFingerTapRecognizer;
+  UITapGestureRecognizer* _threeFingerTapRecognizer;
+  UIScreenEdgePanGestureRecognizer* _edgeGesture;
+  UISwipeGestureRecognizer* _swipeGesture;
+
+  HostInputScheme _inputScheme;
+}
+
+- (instancetype)initWithView:(UIView*)view;
+
+// Zoom in/out
+- (IBAction)pinchGestureTriggered:(UIPinchGestureRecognizer*)sender;
+// Left mouse click, moves cursor
+- (IBAction)tapGestureTriggered:(UITapGestureRecognizer*)sender;
+// Scroll the view in 2d
+- (IBAction)panGestureTriggered:(UIPanGestureRecognizer*)sender;
+// Right mouse click and drag, moves cursor
+- (IBAction)longPressGestureTriggered:(UILongPressGestureRecognizer*)sender;
+// Right mouse click
+- (IBAction)twoFingerTapGestureTriggered:(UITapGestureRecognizer*)sender;
+// Middle mouse click
+- (IBAction)threeFingerTapGestureTriggered:(UITapGestureRecognizer*)sender;
+// Show hidden menus.  Swipe up for keyboard, swipe down for navigation menu
+- (IBAction)threeFingerPanGestureTriggered:(UIPanGestureRecognizer*)sender;
+
+@end
+
+#endif  //  REMOTING_CLIENT_IOS_CLIENT_GESTURES_H_
diff --git a/remoting/client/ios/client_gestures.mm b/remoting/client/ios/client_gestures.mm
new file mode 100644
index 0000000..047e8ea8a
--- /dev/null
+++ b/remoting/client/ios/client_gestures.mm
@@ -0,0 +1,339 @@
+// 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.
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+#import "remoting/client/ios/client_gestures.h"
+
+@implementation ClientGestures
+
+- (id)initWithView:(UIView*)view {
+  _inputScheme = HostInputSchemeTouch;
+
+  _longPressRecognizer = [[UILongPressGestureRecognizer alloc]
+      initWithTarget:self
+              action:@selector(longPressGestureTriggered:)];
+  _longPressRecognizer.delegate = self;
+  [view addGestureRecognizer:_longPressRecognizer];
+
+  _panRecognizer = [[UIPanGestureRecognizer alloc]
+      initWithTarget:self
+              action:@selector(panGestureTriggered:)];
+  _panRecognizer.minimumNumberOfTouches = 1;
+  _panRecognizer.maximumNumberOfTouches = 2;
+  _panRecognizer.delegate = self;
+  [view addGestureRecognizer:_panRecognizer];
+
+  _threeFingerPanRecognizer = [[UIPanGestureRecognizer alloc]
+      initWithTarget:self
+              action:@selector(threeFingerPanGestureTriggered:)];
+  _threeFingerPanRecognizer.minimumNumberOfTouches = 3;
+  _threeFingerPanRecognizer.maximumNumberOfTouches = 3;
+  _threeFingerPanRecognizer.delegate = self;
+  [view addGestureRecognizer:_threeFingerPanRecognizer];
+
+  _pinchRecognizer = [[UIPinchGestureRecognizer alloc]
+      initWithTarget:self
+              action:@selector(pinchGestureTriggered:)];
+  _pinchRecognizer.delegate = self;
+  [view addGestureRecognizer:_pinchRecognizer];
+
+  _singleTapRecognizer = [[UITapGestureRecognizer alloc]
+      initWithTarget:self
+              action:@selector(tapGestureTriggered:)];
+  _singleTapRecognizer.delegate = self;
+  [view addGestureRecognizer:_singleTapRecognizer];
+
+  _twoFingerTapRecognizer = [[UITapGestureRecognizer alloc]
+      initWithTarget:self
+              action:@selector(twoFingerTapGestureTriggered:)];
+  _twoFingerTapRecognizer.numberOfTouchesRequired = 2;
+  _twoFingerTapRecognizer.delegate = self;
+  [view addGestureRecognizer:_twoFingerTapRecognizer];
+
+  _threeFingerTapRecognizer = [[UITapGestureRecognizer alloc]
+      initWithTarget:self
+              action:@selector(threeFingerTapGestureTriggered:)];
+  _threeFingerTapRecognizer.numberOfTouchesRequired = 3;
+  _threeFingerPanRecognizer.delegate = self;
+  [view addGestureRecognizer:_threeFingerTapRecognizer];
+
+  _inputScheme = HostInputSchemeTouch;
+
+  [_singleTapRecognizer requireGestureRecognizerToFail:_twoFingerTapRecognizer];
+  [_twoFingerTapRecognizer
+      requireGestureRecognizerToFail:_threeFingerTapRecognizer];
+  [_pinchRecognizer requireGestureRecognizerToFail:_singleTapRecognizer];
+  [_panRecognizer requireGestureRecognizerToFail:_singleTapRecognizer];
+  [_threeFingerPanRecognizer
+      requireGestureRecognizerToFail:_threeFingerTapRecognizer];
+
+  _edgeGesture = [[UIScreenEdgePanGestureRecognizer alloc]
+      initWithTarget:self
+              action:@selector(edgeGestureTriggered:)];
+  //_edgeGesture.edges = UIRectEdgeLeft;
+  _edgeGesture.delegate = self;
+  [view addGestureRecognizer:_edgeGesture];
+
+  _swipeGesture = [[UISwipeGestureRecognizer alloc]
+      initWithTarget:self
+              action:@selector(swipeGestureTriggered:)];
+  _swipeGesture.numberOfTouchesRequired = 2;
+  _swipeGesture.delegate = self;
+  [view addGestureRecognizer:_swipeGesture];
+
+  return self;
+}
+
+// TODO(nicholss): The following several methods have been commented out.
+// Integreation with the original implementation will be done with the app
+// is able to run to the point of interaction and debugging can happen.
+// I would prefer to leave this here rather than deleting because it is close
+// to the implementation that will be used client gestures integration.
+// This is a new class that was derived from the original source which had
+// the implementation mixed in with the host controller and was a huge mess.
+
+// Resize the view of the desktop - Zoom in/out.  This can occur during a Pan.
+- (IBAction)pinchGestureTriggered:(UIPinchGestureRecognizer*)sender {
+  // LOG_TRACE(INFO) << "pinchGestureTriggered";
+  // if ([sender state] == UIGestureRecognizerStateChanged) {
+  //   [self applySceneChange:CGPointMake(0.0, 0.0) scaleBy:sender.scale];
+  //
+  //   sender.scale = 1.0;  // reset scale so next iteration is a relative ratio
+  // }
+}
+
+- (IBAction)tapGestureTriggered:(UITapGestureRecognizer*)sender {
+  // LOG_TRACE(INFO) << "tapGestureTriggered";
+  // CGPoint touchPoint = [sender locationInView:self.view];
+  // if ([_scene containsTouchPoint:touchPoint]) {
+  //   if (_inputScheme == HostInputSchemeTouch) {
+  //     [_scene setMouseLocationFromLocationInView:touchPoint];
+  //     _circle.expandedRadius = 11.0f;
+  //     [_circle doExpandingAnimationAtLocation:[_scene mouseLocationInView]];
+  //   }
+  //   [Utility leftClickOn:_clientToHostProxy at:_scene.mousePosition];
+  // }
+}
+
+// Change position of scene.  This can occur during a pinch or long press.
+// Or perform a Mouse Wheel Scroll.
+- (IBAction)panGestureTriggered:(UIPanGestureRecognizer*)sender {
+  // LOG_TRACE(INFO) << "panGestureTriggered";
+  //   CGPoint translation = [sender translationInView:self.view];
+  //   // If we start with 2 touches, and the pinch gesture is not in progress
+  //   yet,
+  //   // then disable it, so mouse scrolling and zoom do not occur at the same
+  //   // time.
+  //   if ([sender numberOfTouches] == 2 &&
+  //       [sender state] == UIGestureRecognizerStateBegan &&
+  //       !(_pinchRecognizer.state == UIGestureRecognizerStateBegan ||
+  //         _pinchRecognizer.state == UIGestureRecognizerStateChanged)) {
+  //     _pinchRecognizer.enabled = NO;
+  //   }
+  //
+  //   if (!_pinchRecognizer.enabled) {
+  //     // Began with 2 touches, so this is a scroll event.
+  //     translation.x *= kMouseWheelSensitivity;
+  //     translation.y *= kMouseWheelSensitivity;
+  //     // [Utility mouseScroll:_clientToHostProxy
+  //     //                   at:_scene.mousePosition
+  //     //                delta:webrtc::DesktopVector(translation.x,
+  //     translation.y)];
+  //   } else {
+  //     // Did not begin with 2 touches, doing a pan event.
+  //     if ([sender state] == UIGestureRecognizerStateChanged) {
+  //       CGPoint translation = [sender translationInView:self.view];
+  //       BOOL shouldApplyPanAndTapBounding =
+  //           _inputScheme == HostInputSchemeTouch &&
+  //           [_longPressRecognizer state] != UIGestureRecognizerStateChanged;
+  //
+  //       if (shouldApplyPanAndTapBounding) {
+  //         // Reverse the orientation on both axes.
+  //         translation = CGPointMake(-translation.x, -translation.y);
+  //       }
+  //
+  //       // if (shouldApplyPanAndTapBounding) {
+  //       //   // Stop the translation as soon as the view becomes anchored.
+  //       //   if ([SceneView
+  //       //           couldMouseMoveTowardAnchorWithTranslation:translation.x
+  //       // isAnchoredLow:_scene.anchored.left
+  //       // isAnchoredHigh:_scene.anchored
+  //       //                                                         .right]) {
+  //       //     translation = CGPointMake(0, translation.y);
+  //       //   }
+  //       //
+  //       //   if ([SceneView
+  //       //           couldMouseMoveTowardAnchorWithTranslation:translation.y
+  //       // isAnchoredLow:_scene.anchored.top
+  //       // isAnchoredHigh:_scene.anchored
+  //       //                                                         .bottom])
+  //       {
+  //       //     translation = CGPointMake(translation.x, 0);
+  //       //   }
+  //       // }
+  //
+  //       [self applySceneChange:translation scaleBy:1.0];
+  //
+  //       if (_inputScheme == HostInputSchemeTouch &&
+  //           [_longPressRecognizer state] == UIGestureRecognizerStateChanged
+  //           &&
+  //           [sender numberOfTouches] == 1) {
+  //         // [_scene
+  //         //     setMouseLocationFromLocationInView:[sender
+  //         // locationInView:self.view]];
+  //
+  // //        [Utility moveMouse:_clientToHostProxy at:_scene.mousePosition];
+  //       }
+  //
+  //     } else if ([sender state] == UIGestureRecognizerStateEnded) {
+  //       // After user removes their fingers from the screen
+  //       // apply an acceleration effect.
+  //       CGPoint velocity = [sender velocityInView:self.view];
+  //
+  //       if (_inputScheme == HostInputSchemeTouch) {
+  //         // Reverse the orientation on both axes.
+  //         velocity = CGPointMake(-velocity.x, -velocity.y);
+  //       }
+  // //      [_scene setPanVelocity:velocity];
+  //     }
+  //   }
+  //
+  //   // Finished the event chain.
+  //   if (!([sender state] == UIGestureRecognizerStateBegan ||
+  //         [sender state] == UIGestureRecognizerStateChanged)) {
+  //     _pinchRecognizer.enabled = YES;
+  //   }
+  //
+  //   // Reset translation so next iteration is relative.  Wait until a changed
+  //   // event in order to also capture the portion of the translation that
+  //   occurred
+  //   // between the Began and Changed States.
+  //   if ([sender state] == UIGestureRecognizerStateChanged) {
+  //     [sender setTranslation:CGPointZero inView:self.view];
+  //   }
+}
+
+// Click-Drag mouse operation.  This can occur during a Pan.
+- (IBAction)longPressGestureTriggered:(UILongPressGestureRecognizer*)sender {
+  // LOG_TRACE(INFO) << "longPressGestureTriggered";
+  // if ([sender state] == UIGestureRecognizerStateBegan) {
+  //   if (_inputScheme == HostInputSchemeTouch) {
+  //     CGPoint touchPoint = [sender locationInView:self.view];
+  //     [_scene setMouseLocationFromLocationInView:touchPoint];
+  //   }
+  //   [_clientToHostProxy mouseAction:_scene.mousePosition
+  //                        wheelDelta:webrtc::DesktopVector(0, 0)
+  //                       whichButton:1
+  //                        buttonDown:YES];
+  //   if (_inputScheme == HostInputSchemeTouch) {
+  //     // location is going to be under the user's finger
+  //     // create a bigger bubble.
+  //     _circle.expandedRadius = 110.0f;
+  //   } else {
+  //     _circle.expandedRadius = 11.0f;
+  //   }
+  //
+  //   [_circle doExpandingAnimationAtLocation:[_scene mouseLocationInView]];
+  // } else if (!([sender state] == UIGestureRecognizerStateBegan ||
+  //              [sender state] == UIGestureRecognizerStateChanged)) {
+  //   [_clientToHostProxy mouseAction:_scene.mousePosition
+  //                        wheelDelta:webrtc::DesktopVector(0, 0)
+  //                       whichButton:1
+  //                        buttonDown:NO];
+  //   if (_inputScheme == HostInputSchemeTouch) {
+  //     // Return to the center.
+  //     [_scene centerMouseInView];
+  //   }
+  // }
+}
+
+- (IBAction)twoFingerTapGestureTriggered:(UITapGestureRecognizer*)sender {
+  // LOG_TRACE(INFO) << "twoFingerTapGestureTriggered";
+  if (_inputScheme == HostInputSchemeTouch) {
+    // disabled
+    return;
+  }
+  // if ([_scene containsTouchPoint:[sender locationInView:self.view]]) {
+  //   [Utility rightClickOn:_clientToHostProxy at:_scene.mousePosition];
+  // }
+}
+
+- (IBAction)threeFingerTapGestureTriggered:(UITapGestureRecognizer*)sender {
+  // LOG_TRACE(INFO) << "threeFingerTapGestureTriggered";
+  if (_inputScheme == HostInputSchemeTouch) {
+    // disabled
+    return;
+  }
+
+  // if ([_scene containsTouchPoint:[sender locationInView:self.view]]) {
+  //   [Utility middleClickOn:_clientToHostProxy at:_scene.mousePosition];
+  // }
+}
+
+- (IBAction)threeFingerPanGestureTriggered:(UIPanGestureRecognizer*)sender {
+  // LOG_TRACE(INFO) << "threeFingerPanGestureTriggered";
+  // if ([sender state] == UIGestureRecognizerStateChanged) {
+  //   CGPoint translation = [sender translationInView:self.view];
+  //   if (translation.y > 0) {
+  //     // Swiped down - do nothing
+  //   } else if (translation.y < 0) {
+  //     // Swiped up
+  //     [_keyEntryView becomeFirstResponder];
+  //   }
+  //   [sender setTranslation:CGPointZero inView:self.view];
+  // }
+}
+
+- (IBAction)edgeGestureTriggered:(UIScreenEdgePanGestureRecognizer*)sender {
+  // LOG_TRACE(INFO) << "edgeGestureTriggered";
+}
+
+- (IBAction)swipeGestureTriggered:(UISwipeGestureRecognizer*)sender {
+  // LOG_TRACE(INFO) << "swipeGestureTriggered";
+}
+
+#pragma mark - UIGestureRecognizerDelegate
+
+// Allow panning and zooming to occur simultaneously.
+// Allow panning and long press to occur simultaneously.
+// Pinch requires 2 touches, and long press requires a single touch, so they are
+// mutually exclusive regardless of if panning is the initiating gesture.
+- (BOOL)gestureRecognizer:(UIGestureRecognizer*)gestureRecognizer
+    shouldRecognizeSimultaneouslyWithGestureRecognizer:
+        (UIGestureRecognizer*)otherGestureRecognizer {
+  if (gestureRecognizer == _pinchRecognizer ||
+      (gestureRecognizer == _panRecognizer)) {
+    if (otherGestureRecognizer == _pinchRecognizer ||
+        otherGestureRecognizer == _panRecognizer) {
+      return YES;
+    }
+  }
+
+  if (gestureRecognizer == _longPressRecognizer ||
+      gestureRecognizer == _panRecognizer) {
+    if (otherGestureRecognizer == _longPressRecognizer ||
+        otherGestureRecognizer == _panRecognizer) {
+      return YES;
+    }
+  }
+
+  if (gestureRecognizer == _twoFingerTapRecognizer &&
+      otherGestureRecognizer == _longPressRecognizer) {
+    return YES;
+  }
+
+  if (gestureRecognizer == _panRecognizer &&
+      otherGestureRecognizer == _edgeGesture) {
+    return YES;
+  }
+  // TODO(nicholss): If we return NO here, it dismisses the other reconizers.
+  // As we add more types of reconizers, they need to be accounted for in the
+  // above logic.
+  return NO;
+}
+
+@end
diff --git a/remoting/client/ios/host_preferences.h b/remoting/client/ios/host_preferences.h
index 6fb19a0..553167b 100644
--- a/remoting/client/ios/host_preferences.h
+++ b/remoting/client/ios/host_preferences.h
@@ -1,4 +1,4 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
+// 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.
 
@@ -9,7 +9,6 @@
 
 // A HostPreferences contains details to negotiate and maintain a connection
 // to a remote Chromoting host.  This is an entity in a backing store.
-
 @interface HostPreferences : NSObject<NSCoding>
 
 // Properties supplied by the host server.
@@ -17,12 +16,10 @@
 @property(nonatomic, copy) NSString* pairId;
 @property(nonatomic, copy) NSString* pairSecret;
 
-// Commit this record using the SSOKeychain
-// for SSOSigninManager's current identity.
-- (void)saveToSSOKeychain;
+// Commit this record using the Keychain for current identity.
+- (void)saveToKeychain;
 
-// Load a record from the SSOKeychain
-// for SSOSigninManager's current identity.
+// Load a record from the Keychain for current identity.
 // If a record does not exist, return a new record with a blank secret.
 + (HostPreferences*)hostForId:(NSString*)hostId;
 
diff --git a/remoting/client/ios/host_preferences.mm b/remoting/client/ios/host_preferences.mm
new file mode 100644
index 0000000..f229ce25
--- /dev/null
+++ b/remoting/client/ios/host_preferences.mm
@@ -0,0 +1,92 @@
+// 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.
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+#import "remoting/client/ios/host_preferences.h"
+
+#import "base/logging.h"
+#import "remoting/client/ios/host_preferences_persistence.h"
+
+namespace {
+static NSString* const kHostPreferencesDataKeyHostDictionary =
+    @"kHostPreferencesDataKeyHostDictionary";
+static NSString* const kHostPreferencesHostIdKey = @"HostId";
+static NSString* const kHostPreferencesPairIdKey = @"PairId";
+static NSString* const kHostPreferencesPairSecretKey = @"PairSecret";
+}  // namespace
+
+@interface HostPreferences ()
+
+// Load the known hosts from the Keychain.
+// If no data exists, return an empty dictionary
++ (NSMutableDictionary*)loadHosts;
+
+@end
+
+@implementation HostPreferences
+
+@synthesize hostId = _hostId;
+@synthesize pairId = _pairId;
+@synthesize pairSecret = _pairSecret;
+
+#pragma mark - Public
+
+- (void)saveToKeychain {
+  NSMutableDictionary* hosts = [HostPreferences loadHosts];
+  [hosts setObject:self forKey:_hostId];
+
+  NSData* writeData = [NSKeyedArchiver archivedDataWithRootObject:hosts];
+
+  NSError* keychainError =
+      remoting::ios::WriteHostPreferencesToKeychain(writeData);
+
+  DLOG_IF(ERROR, !keychainError) << "Could not write to keychain.";
+}
+
++ (HostPreferences*)hostForId:(NSString*)hostId {
+  NSMutableDictionary* hosts = [HostPreferences loadHosts];
+  HostPreferences* host = hosts[hostId];
+  if (!host) {
+    host = [[HostPreferences alloc] init];
+    host.hostId = hostId;
+    host.pairId = @"";
+    host.pairSecret = @"";
+  }
+  return host;
+}
+
+#pragma mark - Private
+
++ (NSMutableDictionary*)loadHosts {
+  NSData* readData = remoting::ios::ReadHostPreferencesFromKeychain();
+  if (readData) {
+    return [NSKeyedUnarchiver unarchiveObjectWithData:readData];
+  } else {
+    return [[NSMutableDictionary alloc] init];
+  }
+}
+
+#pragma mark - NSCoding
+
+- (instancetype)initWithCoder:(NSCoder*)coder {
+  self = [super init];
+  if (self) {
+    [self setHostId:[coder decodeObjectForKey:kHostPreferencesHostIdKey]];
+    [self setPairId:[coder decodeObjectForKey:kHostPreferencesPairIdKey]];
+    [self
+        setPairSecret:[coder decodeObjectForKey:kHostPreferencesPairSecretKey]];
+  }
+  return self;
+}
+
+- (void)encodeWithCoder:(NSCoder*)coder {
+  [coder encodeObject:_hostId forKey:kHostPreferencesHostIdKey];
+  [coder encodeObject:_pairId forKey:kHostPreferencesPairIdKey];
+  [coder encodeObject:_pairSecret forKey:kHostPreferencesPairSecretKey];
+}
+
+@end
diff --git a/remoting/client/ios/host_preferences_persistence.h b/remoting/client/ios/host_preferences_persistence.h
new file mode 100644
index 0000000..b5484eb
--- /dev/null
+++ b/remoting/client/ios/host_preferences_persistence.h
@@ -0,0 +1,21 @@
+// 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 REMOTING_CLIENT_IOS_HOST_PREFERENCES_PERSISTENCE_H_
+#define REMOTING_CLIENT_IOS_HOST_PREFERENCES_PERSISTENCE_H_
+
+#import <CoreData/CoreData.h>
+
+// Methods used to store and recall Host Prefrences on the keychain.
+// Used to cache data for quicker connection to previously fetched host data.
+namespace remoting {
+namespace ios {
+
+NSError* WriteHostPreferencesToKeychain(NSData* data);
+NSData* ReadHostPreferencesFromKeychain();
+
+}  // namespace ios
+}  // namespace remoting
+
+#endif  // REMOTING_CLIENT_IOS_HOST_PREFERENCES_PERSISTENCE_H_
diff --git a/remoting/client/ios/host_preferences_persistence_chromium.mm b/remoting/client/ios/host_preferences_persistence_chromium.mm
new file mode 100644
index 0000000..fee5609
--- /dev/null
+++ b/remoting/client/ios/host_preferences_persistence_chromium.mm
@@ -0,0 +1,28 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "remoting/client/ios/host_preferences_persistence.h"
+
+#import "base/logging.h"
+
+namespace remoting {
+namespace ios {
+
+// TODO(nicholss): It might be useful to save |data| in a static variable,
+// which is then returned from ReadHostPreferencesFromKeychain(). This would
+// allow to test pairing, even though the pairing info is not persisted when
+// the app is restarted.
+
+NSError* WriteHostPreferencesToKeychain(NSData* data) {
+  NOTIMPLEMENTED();
+  return nil;
+}
+
+NSData* ReadHostPreferencesFromKeychain() {
+  NOTIMPLEMENTED();
+  return nil;
+}
+
+}  // namespace ios
+}  // namespace remoting
diff --git a/remoting/host/heartbeat_sender_unittest.cc b/remoting/host/heartbeat_sender_unittest.cc
index e537288..06fab1c3 100644
--- a/remoting/host/heartbeat_sender_unittest.cc
+++ b/remoting/host/heartbeat_sender_unittest.cc
@@ -10,6 +10,7 @@
 #include "base/message_loop/message_loop.h"
 #include "base/run_loop.h"
 #include "base/strings/string_number_conversions.h"
+#include "base/test/mock_callback.h"
 #include "remoting/base/constants.h"
 #include "remoting/base/rsa_key_pair.h"
 #include "remoting/base/test_rsa_key_pair.h"
@@ -53,16 +54,6 @@
   list->erase(arg0);
 }
 
-class MockClosure {
- public:
-  MOCK_CONST_METHOD0(Run, void());
-};
-
-class MockAckCallback {
- public:
-  MOCK_CONST_METHOD1(Run, void(bool success));
-};
-
 class HeartbeatSenderTest
     : public testing::Test {
  protected:
@@ -80,12 +71,10 @@
     EXPECT_CALL(mock_unknown_host_id_error_callback_, Run())
         .Times(0);
 
-    heartbeat_sender_.reset(new HeartbeatSender(
-        base::Bind(&MockClosure::Run,
-                   base::Unretained(&mock_heartbeat_successful_callback_)),
-        base::Bind(&MockClosure::Run,
-                   base::Unretained(&mock_unknown_host_id_error_callback_)),
-        kHostId, &signal_strategy_, key_pair_, kTestBotJid));
+    heartbeat_sender_.reset(
+        new HeartbeatSender(mock_heartbeat_successful_callback_.Get(),
+                            mock_unknown_host_id_error_callback_.Get(), kHostId,
+                            &signal_strategy_, key_pair_, kTestBotJid));
   }
 
   void TearDown() override {
@@ -103,8 +92,8 @@
 
   base::MessageLoop message_loop_;
   MockSignalStrategy signal_strategy_;
-  MockClosure mock_heartbeat_successful_callback_;
-  MockClosure mock_unknown_host_id_error_callback_;
+  base::MockCallback<base::Closure> mock_heartbeat_successful_callback_;
+  base::MockCallback<base::Closure> mock_unknown_host_id_error_callback_;
   std::set<SignalStrategy::Listener*> signal_strategy_listeners_;
   scoped_refptr<RsaKeyPair> key_pair_;
   std::unique_ptr<HeartbeatSender> heartbeat_sender_;
@@ -257,7 +246,7 @@
 // Make sure SetHostOfflineReason sends a correct stanza.
 TEST_F(HeartbeatSenderTest, DoSetHostOfflineReason) {
   XmlElement* sent_iq = nullptr;
-  MockAckCallback mock_ack_callback;
+  base::MockCallback<base::Callback<void(bool success)>> mock_ack_callback;
 
   EXPECT_CALL(signal_strategy_, GetLocalJid())
       .WillRepeatedly(Return(kTestJid));
@@ -270,9 +259,8 @@
       .WillRepeatedly(Return(SignalStrategy::CONNECTED));
   EXPECT_CALL(mock_ack_callback, Run(_)).Times(0);
 
-  heartbeat_sender_->SetHostOfflineReason(
-      "test_error", kTestTimeout,
-      base::Bind(&MockAckCallback::Run, base::Unretained(&mock_ack_callback)));
+  heartbeat_sender_->SetHostOfflineReason("test_error", kTestTimeout,
+                                          mock_ack_callback.Get());
   heartbeat_sender_->OnSignalStrategyStateChange(SignalStrategy::CONNECTED);
   base::RunLoop().RunUntilIdle();
 
@@ -286,7 +274,7 @@
 
 // Make sure SetHostOfflineReason triggers a callback when bot responds.
 TEST_F(HeartbeatSenderTest, ProcessHostOfflineResponses) {
-  MockAckCallback mock_ack_callback;
+  base::MockCallback<base::Callback<void(bool success)>> mock_ack_callback;
 
   EXPECT_CALL(signal_strategy_, GetLocalJid())
       .WillRepeatedly(Return(kTestJid));
@@ -303,9 +291,8 @@
   // Callback should not run, until response to offline-reason.
   EXPECT_CALL(mock_ack_callback, Run(_)).Times(0);
 
-  heartbeat_sender_->SetHostOfflineReason(
-      "test_error", kTestTimeout,
-      base::Bind(&MockAckCallback::Run, base::Unretained(&mock_ack_callback)));
+  heartbeat_sender_->SetHostOfflineReason("test_error", kTestTimeout,
+                                          mock_ack_callback.Get());
   heartbeat_sender_->OnSignalStrategyStateChange(SignalStrategy::CONNECTED);
   base::RunLoop().RunUntilIdle();
 
diff --git a/remoting/host/register_support_host_request_unittest.cc b/remoting/host/register_support_host_request_unittest.cc
index aed7da0..a23a59e 100644
--- a/remoting/host/register_support_host_request_unittest.cc
+++ b/remoting/host/register_support_host_request_unittest.cc
@@ -12,6 +12,7 @@
 #include "base/observer_list.h"
 #include "base/run_loop.h"
 #include "base/strings/string_number_conversions.h"
+#include "base/test/mock_callback.h"
 #include "remoting/base/constants.h"
 #include "remoting/base/rsa_key_pair.h"
 #include "remoting/base/test_rsa_key_pair.h"
@@ -48,13 +49,6 @@
   list->RemoveObserver(arg0);
 }
 
-class MockCallback {
- public:
-  MOCK_METHOD3(OnResponse, void(const std::string& support_id,
-                                const base::TimeDelta& lifetime,
-                                const std::string& error_message));
-};
-
 }  // namespace
 
 class RegisterSupportHostRequestTest : public testing::Test {
@@ -76,7 +70,7 @@
   MockSignalStrategy signal_strategy_;
   base::ObserverList<SignalStrategy::Listener, true> signal_strategy_listeners_;
   scoped_refptr<RsaKeyPair> key_pair_;
-  MockCallback callback_;
+  base::MockCallback<RegisterSupportHostRequest::RegisterCallback> callback_;
 };
 
 TEST_F(RegisterSupportHostRequestTest, Send) {
@@ -84,9 +78,8 @@
   int64_t start_time = static_cast<int64_t>(base::Time::Now().ToDoubleT());
 
   std::unique_ptr<RegisterSupportHostRequest> request(
-      new RegisterSupportHostRequest(
-          &signal_strategy_, key_pair_, kTestBotJid,
-          base::Bind(&MockCallback::OnResponse, base::Unretained(&callback_))));
+      new RegisterSupportHostRequest(&signal_strategy_, key_pair_, kTestBotJid,
+                                     callback_.Get()));
 
   XmlElement* sent_iq = nullptr;
   EXPECT_CALL(signal_strategy_, GetNextId())
@@ -129,9 +122,8 @@
   EXPECT_EQ(expected_signature, signature->BodyText());
 
   // Generate response and verify that callback is called.
-  EXPECT_CALL(callback_, OnResponse(kSupportId,
-                                    base::TimeDelta::FromSeconds(300),
-                                    ""));
+  EXPECT_CALL(callback_,
+              Run(kSupportId, base::TimeDelta::FromSeconds(300), ""));
 
   std::unique_ptr<XmlElement> response(new XmlElement(buzz::QN_IQ));
   response->AddAttr(QName(std::string(), "from"), kTestBotJid);
diff --git a/remoting/protocol/channel_multiplexer_unittest.cc b/remoting/protocol/channel_multiplexer_unittest.cc
index 30e5be9..6ff2a84 100644
--- a/remoting/protocol/channel_multiplexer_unittest.cc
+++ b/remoting/protocol/channel_multiplexer_unittest.cc
@@ -11,6 +11,7 @@
 #include "base/message_loop/message_loop.h"
 #include "base/run_loop.h"
 #include "base/single_thread_task_runner.h"
+#include "base/test/mock_callback.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "net/base/net_errors.h"
 #include "net/socket/socket.h"
@@ -43,11 +44,6 @@
       FROM_HERE, base::MessageLoop::QuitWhenIdleClosure());
 }
 
-class MockSocketCallback {
- public:
-  MOCK_METHOD1(OnDone, void(int result));
-};
-
 class MockConnectCallback {
  public:
   MOCK_METHOD1(OnConnectedPtr, void(P2PStreamSocket* socket));
@@ -241,21 +237,14 @@
 
   scoped_refptr<net::IOBufferWithSize> buf = CreateTestBuffer(100);
 
-  MockSocketCallback cb1;
-  MockSocketCallback cb2;
-  EXPECT_CALL(cb1, OnDone(net::ERR_FAILED));
-  EXPECT_CALL(cb2, OnDone(net::ERR_FAILED));
+  base::MockCallback<net::CompletionCallback> cb1, cb2;
+  EXPECT_CALL(cb1, Run(net::ERR_FAILED));
+  EXPECT_CALL(cb2, Run(net::ERR_FAILED));
 
   EXPECT_EQ(net::ERR_IO_PENDING,
-            host_socket1_->Write(buf.get(),
-                                 buf->size(),
-                                 base::Bind(&MockSocketCallback::OnDone,
-                                            base::Unretained(&cb1))));
+            host_socket1_->Write(buf.get(), buf->size(), cb1.Get()));
   EXPECT_EQ(net::ERR_IO_PENDING,
-            host_socket2_->Write(buf.get(),
-                                 buf->size(),
-                                 base::Bind(&MockSocketCallback::OnDone,
-                                            base::Unretained(&cb2))));
+            host_socket2_->Write(buf.get(), buf->size(), cb2.Get()));
 
   base::RunLoop().RunUntilIdle();
 }
@@ -274,21 +263,14 @@
 
   scoped_refptr<net::IOBufferWithSize> buf = CreateTestBuffer(100);
 
-  MockSocketCallback cb1;
-  MockSocketCallback cb2;
-  EXPECT_CALL(cb1, OnDone(net::ERR_FAILED));
-  EXPECT_CALL(cb2, OnDone(net::ERR_FAILED));
+  base::MockCallback<net::CompletionCallback> cb1, cb2;
+  EXPECT_CALL(cb1, Run(net::ERR_FAILED));
+  EXPECT_CALL(cb2, Run(net::ERR_FAILED));
 
   EXPECT_EQ(net::ERR_IO_PENDING,
-            host_socket1_->Write(buf.get(),
-                                 buf->size(),
-                                 base::Bind(&MockSocketCallback::OnDone,
-                                            base::Unretained(&cb1))));
+            host_socket1_->Write(buf.get(), buf->size(), cb1.Get()));
   EXPECT_EQ(net::ERR_IO_PENDING,
-            host_socket2_->Write(buf.get(),
-                                 buf->size(),
-                                 base::Bind(&MockSocketCallback::OnDone,
-                                            base::Unretained(&cb2))));
+            host_socket2_->Write(buf.get(), buf->size(), cb2.Get()));
 
   base::RunLoop().RunUntilIdle();
 }
@@ -306,26 +288,18 @@
 
   scoped_refptr<net::IOBufferWithSize> buf = CreateTestBuffer(100);
 
-  MockSocketCallback cb1;
-  MockSocketCallback cb2;
-
-  EXPECT_CALL(cb1, OnDone(net::ERR_FAILED))
+  base::MockCallback<net::CompletionCallback> cb1, cb2;
+  EXPECT_CALL(cb1, Run(net::ERR_FAILED))
       .Times(AtMost(1))
       .WillOnce(InvokeWithoutArgs(this, &ChannelMultiplexerTest::DeleteAll));
-  EXPECT_CALL(cb2, OnDone(net::ERR_FAILED))
+  EXPECT_CALL(cb2, Run(net::ERR_FAILED))
       .Times(AtMost(1))
       .WillOnce(InvokeWithoutArgs(this, &ChannelMultiplexerTest::DeleteAll));
 
   EXPECT_EQ(net::ERR_IO_PENDING,
-            host_socket1_->Write(buf.get(),
-                                 buf->size(),
-                                 base::Bind(&MockSocketCallback::OnDone,
-                                            base::Unretained(&cb1))));
+            host_socket1_->Write(buf.get(), buf->size(), cb1.Get()));
   EXPECT_EQ(net::ERR_IO_PENDING,
-            host_socket2_->Write(buf.get(),
-                                 buf->size(),
-                                 base::Bind(&MockSocketCallback::OnDone,
-                                            base::Unretained(&cb2))));
+            host_socket2_->Write(buf.get(), buf->size(), cb2.Get()));
 
   base::RunLoop().RunUntilIdle();
 
diff --git a/remoting/signaling/iq_sender_unittest.cc b/remoting/signaling/iq_sender_unittest.cc
index c03abd6..8ef1041 100644
--- a/remoting/signaling/iq_sender_unittest.cc
+++ b/remoting/signaling/iq_sender_unittest.cc
@@ -11,6 +11,7 @@
 #include "base/message_loop/message_loop.h"
 #include "base/run_loop.h"
 #include "base/strings/stringprintf.h"
+#include "base/test/mock_callback.h"
 #include "remoting/signaling/mock_signal_strategy.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -38,11 +39,6 @@
 const char kType[] = "get";
 const char kTo[] = "user@domain.com";
 
-class MockCallback {
- public:
-  MOCK_METHOD2(OnReply, void(IqRequest* request, const XmlElement* reply));
-};
-
 MATCHER_P(XmlEq, expected, "") {
   return arg->Str() == expected->Str();
 }
@@ -67,8 +63,7 @@
         .WillOnce(Return(kStanzaId));
     EXPECT_CALL(signal_strategy_, SendStanzaPtr(_))
         .WillOnce(DoAll(SaveArg<0>(&sent_stanza), Return(true)));
-    request_ = sender_->SendIq(kType, kTo, std::move(iq_body), base::Bind(
-        &MockCallback::OnReply, base::Unretained(&callback_)));
+    request_ = sender_->SendIq(kType, kTo, std::move(iq_body), callback_.Get());
 
     std::string expected_xml_string =
         base::StringPrintf(
@@ -104,7 +99,7 @@
   base::MessageLoop message_loop_;
   MockSignalStrategy signal_strategy_;
   std::unique_ptr<IqSender> sender_;
-  MockCallback callback_;
+  base::MockCallback<IqSender::ReplyCallback> callback_;
   std::unique_ptr<IqRequest> request_;
 };
 
@@ -116,7 +111,7 @@
   std::unique_ptr<XmlElement> response;
   EXPECT_TRUE(FormatAndDeliverResponse(kTo, &response));
 
-  EXPECT_CALL(callback_, OnReply(request_.get(), XmlEq(response.get())));
+  EXPECT_CALL(callback_, Run(request_.get(), XmlEq(response.get())));
   base::RunLoop().RunUntilIdle();
 }
 
@@ -127,7 +122,7 @@
 
   request_->SetTimeout(base::TimeDelta::FromMilliseconds(2));
 
-  EXPECT_CALL(callback_, OnReply(request_.get(), nullptr))
+  EXPECT_CALL(callback_, Run(request_.get(), nullptr))
       .WillOnce(
           InvokeWithoutArgs(&message_loop_, &base::MessageLoop::QuitWhenIdle));
   base::RunLoop().Run();
@@ -143,7 +138,7 @@
   std::unique_ptr<XmlElement> response;
   EXPECT_TRUE(FormatAndDeliverResponse("USER@domain.com", &response));
 
-  EXPECT_CALL(callback_, OnReply(request_.get(), XmlEq(response.get())));
+  EXPECT_CALL(callback_, Run(request_.get(), XmlEq(response.get())));
   base::RunLoop().RunUntilIdle();
 }
 
@@ -154,7 +149,7 @@
 
   EXPECT_FALSE(FormatAndDeliverResponse("different_user@domain.com", nullptr));
 
-  EXPECT_CALL(callback_, OnReply(_, _)).Times(0);
+  EXPECT_CALL(callback_, Run(_, _)).Times(0);
   base::RunLoop().RunUntilIdle();
 }
 
diff --git a/services/ui/surfaces/display_compositor.cc b/services/ui/surfaces/display_compositor.cc
index 8f30e7f..33df6b6 100644
--- a/services/ui/surfaces/display_compositor.cc
+++ b/services/ui/surfaces/display_compositor.cc
@@ -41,8 +41,6 @@
       client_(std::move(client)),
       binding_(this, std::move(request)) {
   manager_.AddObserver(this);
-  if (client_)
-    client_->OnDisplayCompositorCreated(GetRootSurfaceId());
 }
 
 void DisplayCompositor::AddSurfaceReferences(
diff --git a/services/ui/surfaces/gpu_compositor_frame_sink.cc b/services/ui/surfaces/gpu_compositor_frame_sink.cc
index 34ef009..0e1584f 100644
--- a/services/ui/surfaces/gpu_compositor_frame_sink.cc
+++ b/services/ui/surfaces/gpu_compositor_frame_sink.cc
@@ -4,6 +4,7 @@
 
 #include "services/ui/surfaces/gpu_compositor_frame_sink.h"
 
+#include "cc/surfaces/surface_reference.h"
 #include "services/ui/surfaces/display_compositor.h"
 
 namespace ui {
@@ -24,6 +25,7 @@
                frame_sink_id,
                std::move(display),
                std::move(begin_frame_source)),
+      surface_tracker_(frame_sink_id),
       client_(std::move(client)),
       binding_(this, std::move(request)),
       compositor_frame_sink_private_binding_(
@@ -38,7 +40,17 @@
                  base::Unretained(this)));
 }
 
-GpuCompositorFrameSink::~GpuCompositorFrameSink() {}
+GpuCompositorFrameSink::~GpuCompositorFrameSink() {
+  // For display root surfaces, remove the reference from top level root to
+  // indicate the display root surface is no longer visible.
+  if (support_.display() && surface_tracker_.current_surface_id().is_valid()) {
+    const cc::SurfaceId top_level_root_surface_id =
+        display_compositor_->manager()->GetRootSurfaceId();
+    std::vector<cc::SurfaceReference> references_to_remove{cc::SurfaceReference(
+        top_level_root_surface_id, surface_tracker_.current_surface_id())};
+    display_compositor_->RemoveSurfaceReferences(references_to_remove);
+  }
+}
 
 void GpuCompositorFrameSink::EvictFrame() {
   support_.EvictFrame();
@@ -51,17 +63,41 @@
 void GpuCompositorFrameSink::SubmitCompositorFrame(
     const cc::LocalFrameId& local_frame_id,
     cc::CompositorFrame frame) {
+  cc::SurfaceId start_surface_id = surface_tracker_.current_surface_id();
+  surface_tracker_.UpdateReferences(local_frame_id,
+                                    frame.metadata.referenced_surfaces);
+
   support_.SubmitCompositorFrame(local_frame_id, std::move(frame));
-}
 
-void GpuCompositorFrameSink::AddSurfaceReferences(
-    const std::vector<cc::SurfaceReference>& references) {
-  display_compositor_->AddSurfaceReferences(references);
-}
+  // Get the list of surfaces to add/remove from |surface_tracker_| so we can
+  // append to them before adding/removing.
+  std::vector<cc::SurfaceReference>& references_to_add =
+      surface_tracker_.references_to_add();
+  std::vector<cc::SurfaceReference>& references_to_remove =
+      surface_tracker_.references_to_remove();
 
-void GpuCompositorFrameSink::RemoveSurfaceReferences(
-    const std::vector<cc::SurfaceReference>& references) {
-  display_compositor_->RemoveSurfaceReferences(references);
+  // Append TLR references for the display root surfaces when display root
+  // surface changes.
+  if (support_.display() &&
+      start_surface_id != surface_tracker_.current_surface_id()) {
+    const cc::SurfaceId top_level_root_surface_id =
+        display_compositor_->manager()->GetRootSurfaceId();
+
+    // The first frame will not have a valid |start_surface_id| and there will
+    // be no surface to remove.
+    if (start_surface_id.local_frame_id().is_valid()) {
+      references_to_remove.push_back(
+          cc::SurfaceReference(top_level_root_surface_id, start_surface_id));
+    }
+
+    references_to_add.push_back(cc::SurfaceReference(
+        top_level_root_surface_id, surface_tracker_.current_surface_id()));
+  }
+
+  if (!references_to_add.empty())
+    display_compositor_->AddSurfaceReferences(references_to_add);
+  if (!references_to_remove.empty())
+    display_compositor_->RemoveSurfaceReferences(references_to_remove);
 }
 
 void GpuCompositorFrameSink::Require(const cc::LocalFrameId& local_frame_id,
diff --git a/services/ui/surfaces/gpu_compositor_frame_sink.h b/services/ui/surfaces/gpu_compositor_frame_sink.h
index 89e3618..c2a80bc 100644
--- a/services/ui/surfaces/gpu_compositor_frame_sink.h
+++ b/services/ui/surfaces/gpu_compositor_frame_sink.h
@@ -14,6 +14,7 @@
 #include "cc/ipc/mojo_compositor_frame_sink.mojom.h"
 #include "cc/surfaces/compositor_frame_sink_support.h"
 #include "cc/surfaces/compositor_frame_sink_support_client.h"
+#include "cc/surfaces/referenced_surface_tracker.h"
 #include "mojo/public/cpp/bindings/binding.h"
 
 namespace cc {
@@ -52,10 +53,6 @@
   void SetNeedsBeginFrame(bool needs_begin_frame) override;
   void SubmitCompositorFrame(const cc::LocalFrameId& local_frame_id,
                              cc::CompositorFrame frame) override;
-  void AddSurfaceReferences(
-      const std::vector<cc::SurfaceReference>& references) override;
-  void RemoveSurfaceReferences(
-      const std::vector<cc::SurfaceReference>& references) override;
   void Require(const cc::LocalFrameId& local_frame_id,
                const cc::SurfaceSequence& sequence) override;
   void Satisfy(const cc::SurfaceSequence& sequence) override;
@@ -85,6 +82,10 @@
 
   cc::CompositorFrameSinkSupport support_;
 
+  // Track the surface references for the surface corresponding to this
+  // compositor frame sink.
+  cc::ReferencedSurfaceTracker surface_tracker_;
+
   bool client_connection_lost_ = false;
   bool private_connection_lost_ = false;
 
diff --git a/services/ui/ws/frame_generator.cc b/services/ui/ws/frame_generator.cc
index 793a42cb..114af932 100644
--- a/services/ui/ws/frame_generator.cc
+++ b/services/ui/ws/frame_generator.cc
@@ -32,16 +32,6 @@
 }
 
 FrameGenerator::~FrameGenerator() {
-  // Remove reference from top level root to the display root surface, if one
-  // exists. This will make everything referenced by the display surface
-  // unreachable so it can be garbage collected.
-  if (surface_tracker_.HasValidSurfaceId()) {
-    compositor_frame_sink_->RemoveSurfaceReferences(
-        std::vector<cc::SurfaceReference>{
-            cc::SurfaceReference(root_window_->delegate()->GetRootSurfaceId(),
-                                 surface_tracker_.current_surface_id())});
-  }
-
   // Invalidate WeakPtrs now to avoid callbacks back into the
   // FrameGenerator during destruction of |compositor_frame_sink_|.
   weak_factory_.InvalidateWeakPtrs();
@@ -67,16 +57,12 @@
                                       ServerWindow* window) {
   DCHECK(surface_id.is_valid());
 
-  // TODO(samans): Clients are actually embedded in the WM and only the WM is
-  // embedded here. This needs to be fixed.
-
   // Only handle embedded surfaces changing here. The display root surface
   // changing is handled immediately after the CompositorFrame is submitted.
-  if (window != root_window_) {
-    // Add observer for window the first time it's seen.
-    if (surface_tracker_.EmbedSurface(surface_id))
-      Add(window);
-  }
+  // TODO(samans): Only tell FrameGenerator about WM surface instead of all
+  // all surfaces.
+  if (window == delegate_->GetActiveRootWindow())
+    window_manager_surface_id_ = surface_id;
 }
 
 void FrameGenerator::DidReceiveCompositorFrameAck() {}
@@ -93,36 +79,12 @@
     if (!frame.render_pass_list.empty())
       frame_size = frame.render_pass_list[0]->output_rect.size();
 
-    bool display_surface_changed = false;
-    if (!local_frame_id_.is_valid() ||
-        frame_size != last_submitted_frame_size_) {
+    if (!local_frame_id_.is_valid() || frame_size != last_submitted_frame_size_)
       local_frame_id_ = id_allocator_.GenerateId();
-      display_surface_changed = true;
-    } else {
-      // If the display surface is changing then we shouldn't add references
-      // from the old display surface. We want to add references from the new
-      // display surface, this happens after we submit the first CompositorFrame
-      // so the new display surface exists.
-      if (surface_tracker_.HasReferencesToAdd()) {
-        compositor_frame_sink_->AddSurfaceReferences(
-            surface_tracker_.GetReferencesToAdd());
-      }
-    }
 
     compositor_frame_sink_->SubmitCompositorFrame(local_frame_id_,
                                                   std::move(frame));
     last_submitted_frame_size_ = frame_size;
-
-    if (display_surface_changed)
-      UpdateDisplaySurfaceId();
-
-    // Remove references to surfaces that are no longer embedded. This has to
-    // happen after the frame is submitted otherwise we could end up deleting
-    // a surface that is still embedded in the last submitted frame.
-    if (surface_tracker_.HasReferencesToRemove()) {
-      compositor_frame_sink_->RemoveSurfaceReferences(
-          surface_tracker_.GetReferencesToRemove());
-    }
   }
 }
 
@@ -136,43 +98,6 @@
   // TODO(fsamuel, staraz): Implement this.
 }
 
-void FrameGenerator::UpdateDisplaySurfaceId() {
-  // FrameGenerator owns the display root surface and is a bit of a special
-  // case. There is no surface that embeds the display surface, so nothing
-  // would reference it. Instead, a reference from the top level root is added
-  // to mark the display surface as visible. As a result, FrameGenerator is
-  // responsible for maintaining a reference from the top level root to the
-  // display surface, in addition to references from the display surface to
-  // embedded surfaces.
-  const cc::SurfaceId old_surface_id = surface_tracker_.current_surface_id();
-  const cc::SurfaceId new_surface_id(
-      cc::FrameSinkId(WindowIdToTransportId(root_window_->id()), 0),
-      local_frame_id_);
-
-  DCHECK_NE(old_surface_id, new_surface_id);
-
-  // Set new SurfaceId for the display surface. This will add references from
-  // the new display surface to all embedded surfaces.
-  surface_tracker_.SetCurrentSurfaceId(new_surface_id);
-  std::vector<cc::SurfaceReference> references_to_add =
-      surface_tracker_.GetReferencesToAdd();
-
-  // Adds a reference from the top level root to the new display surface.
-  references_to_add.push_back(cc::SurfaceReference(
-      root_window_->delegate()->GetRootSurfaceId(), new_surface_id));
-
-  compositor_frame_sink_->AddSurfaceReferences(references_to_add);
-
-  // Remove the reference from the top level root to the old display surface
-  // after we have added references from the new display surface. Not applicable
-  // for the first display surface.
-  if (old_surface_id.is_valid()) {
-    compositor_frame_sink_->RemoveSurfaceReferences(
-        std::vector<cc::SurfaceReference>{cc::SurfaceReference(
-            root_window_->delegate()->GetRootSurfaceId(), old_surface_id)});
-  }
-}
-
 cc::CompositorFrame FrameGenerator::GenerateCompositorFrame(
     const gfx::Rect& output_rect) {
   const int render_pass_id = 1;
@@ -202,6 +127,9 @@
   }
   frame.metadata.device_scale_factor = device_scale_factor_;
 
+  if (window_manager_surface_id_.is_valid())
+    frame.metadata.referenced_surfaces.push_back(window_manager_surface_id_);
+
   return frame;
 }
 
@@ -241,17 +169,6 @@
 
 void FrameGenerator::OnWindowDestroying(ServerWindow* window) {
   Remove(window);
-  ServerWindowCompositorFrameSinkManager* compositor_frame_sink_manager =
-      window->compositor_frame_sink_manager();
-  // If FrameGenerator was observing |window|, then that means it had a
-  // CompositorFrame at some point in time and should have a
-  // ServerWindowCompositorFrameSinkManager.
-  DCHECK(compositor_frame_sink_manager);
-
-  cc::SurfaceId surface_id =
-      window->compositor_frame_sink_manager()->GetLatestSurfaceId();
-  if (surface_id.is_valid())
-    surface_tracker_.UnembedSurface(surface_id.frame_sink_id());
 }
 
 }  // namespace ws
diff --git a/services/ui/ws/frame_generator.h b/services/ui/ws/frame_generator.h
index db05f1f..9b7e742 100644
--- a/services/ui/ws/frame_generator.h
+++ b/services/ui/ws/frame_generator.h
@@ -10,7 +10,6 @@
 #include "base/macros.h"
 #include "base/timer/timer.h"
 #include "cc/ipc/display_compositor.mojom.h"
-#include "cc/surfaces/embedded_surface_tracker.h"
 #include "cc/surfaces/frame_sink_id.h"
 #include "cc/surfaces/surface_id.h"
 #include "cc/surfaces/surface_id_allocator.h"
@@ -52,19 +51,8 @@
   // Schedules a redraw for the provided region.
   void OnAcceleratedWidgetAvailable(gfx::AcceleratedWidget widget);
 
-  // Adds a reference to new surface with |surface_id| for |window|. This
-  // reference is to ensure the surface is not deleted while it's still being
-  // displayed. The display root surface has a reference from the top level
-  // root. All child surfaces are embedded by the display root and receive a
-  // reference from it.
-  //
-  // If a new display root Surface is created, then all child surfaces will
-  // receive a reference from the new display root so they are not deleted with
-  // the old display root.
-  //
-  // If there is an existing reference to an old surface with the same
-  // FrameSinkId then that reference will be removed after the next
-  // CompositorFrame is submitted.
+  // If |window| corresponds to the active WM for the display then update
+  // |window_manager_surface_id_|.
   void OnSurfaceCreated(const cc::SurfaceId& surface_id, ServerWindow* window);
 
  private:
@@ -76,9 +64,6 @@
   void ReclaimResources(const cc::ReturnedResourceArray& resources) override;
   void WillDrawSurface() override;
 
-  // Updates the display surface SurfaceId using new value in |local_frame_id_|.
-  void UpdateDisplaySurfaceId();
-
   // Generates the CompositorFrame.
   cc::CompositorFrame GenerateCompositorFrame(const gfx::Rect& output_rect);
 
@@ -99,8 +84,7 @@
   cc::mojom::MojoCompositorFrameSinkPtr compositor_frame_sink_;
   cc::mojom::DisplayPrivatePtr display_private_;
 
-  // Tracks surface references for embedded surfaces.
-  cc::EmbeddedSurfaceTracker surface_tracker_;
+  cc::SurfaceId window_manager_surface_id_;
 
   mojo::Binding<cc::mojom::MojoCompositorFrameSinkClient> binding_;
 
diff --git a/services/ui/ws/server_window_delegate.h b/services/ui/ws/server_window_delegate.h
index 035bc1e..26784fa 100644
--- a/services/ui/ws/server_window_delegate.h
+++ b/services/ui/ws/server_window_delegate.h
@@ -29,9 +29,6 @@
   // DisplayCompositor running in the system.
   virtual cc::mojom::DisplayCompositor* GetDisplayCompositor() = 0;
 
-  // Returns the root surface id that was received from DisplayCompositor.
-  virtual const cc::SurfaceId& GetRootSurfaceId() const = 0;
-
   // Returns the root of the window tree to which this |window| is attached.
   // Returns null if this window is not attached up through to a root window.
   virtual ServerWindow* GetRootWindow(const ServerWindow* window) = 0;
diff --git a/services/ui/ws/test_server_window_delegate.cc b/services/ui/ws/test_server_window_delegate.cc
index 6465ac4..32cd203 100644
--- a/services/ui/ws/test_server_window_delegate.cc
+++ b/services/ui/ws/test_server_window_delegate.cc
@@ -17,10 +17,6 @@
   return nullptr;
 }
 
-const cc::SurfaceId& TestServerWindowDelegate::GetRootSurfaceId() const {
-  return root_surface_id_;
-}
-
 ServerWindow* TestServerWindowDelegate::GetRootWindow(
     const ServerWindow* window) {
   return root_window_;
diff --git a/services/ui/ws/test_server_window_delegate.h b/services/ui/ws/test_server_window_delegate.h
index 8c7a8911..8ef89a7a 100644
--- a/services/ui/ws/test_server_window_delegate.h
+++ b/services/ui/ws/test_server_window_delegate.h
@@ -6,7 +6,6 @@
 #define SERVICES_UI_WS_TEST_SERVER_WINDOW_DELEGATE_H_
 
 #include "base/macros.h"
-#include "cc/surfaces/surface_id.h"
 #include "services/ui/ws/server_window_delegate.h"
 
 namespace cc {
@@ -28,10 +27,8 @@
  private:
   // ServerWindowDelegate:
   cc::mojom::DisplayCompositor* GetDisplayCompositor() override;
-  const cc::SurfaceId& GetRootSurfaceId() const override;
   ServerWindow* GetRootWindow(const ServerWindow* window) override;
 
-  cc::SurfaceId root_surface_id_;
   ServerWindow* root_window_ = nullptr;
 
   DISALLOW_COPY_AND_ASSIGN(TestServerWindowDelegate);
diff --git a/services/ui/ws/window_server.cc b/services/ui/ws/window_server.cc
index aaafe89..0bf97ea2 100644
--- a/services/ui/ws/window_server.cc
+++ b/services/ui/ws/window_server.cc
@@ -532,11 +532,6 @@
   return display_compositor_.get();
 }
 
-const cc::SurfaceId& WindowServer::GetRootSurfaceId() const {
-  DCHECK(root_surface_id_.local_frame_id().is_valid());
-  return root_surface_id_;
-}
-
 bool WindowServer::GetFrameDecorationsForUser(
     const UserId& user_id,
     mojom::FrameDecorationValuesPtr* values) {
@@ -806,11 +801,6 @@
     window_tree->ProcessWindowSurfaceChanged(window, surface_info);
 }
 
-void WindowServer::OnDisplayCompositorCreated(
-    const cc::SurfaceId& root_surface_id) {
-  root_surface_id_ = root_surface_id;
-}
-
 void WindowServer::OnActiveUserIdChanged(const UserId& previously_active_id,
                                          const UserId& active_id) {
 }
diff --git a/services/ui/ws/window_server.h b/services/ui/ws/window_server.h
index 5808c1d..8b08fd5c 100644
--- a/services/ui/ws/window_server.h
+++ b/services/ui/ws/window_server.h
@@ -228,7 +228,6 @@
 
   // ServerWindowDelegate:
   cc::mojom::DisplayCompositor* GetDisplayCompositor() override;
-  const cc::SurfaceId& GetRootSurfaceId() const override;
 
   // UserDisplayManagerDelegate:
   bool GetFrameDecorationsForUser(
@@ -329,8 +328,6 @@
 
   // cc::mojom::DisplayCompositorClient:
   void OnSurfaceCreated(const cc::SurfaceInfo& surface_info) override;
-  void OnDisplayCompositorCreated(
-      const cc::SurfaceId& root_surface_id) override;
 
   // UserIdTrackerObserver:
   void OnActiveUserIdChanged(const UserId& previously_active_id,
diff --git a/third_party/WebKit/LayoutTests/FlagExpectations/enable-browser-side-navigation b/third_party/WebKit/LayoutTests/FlagExpectations/enable-browser-side-navigation
index 034a4d1..6e58f35 100644
--- a/third_party/WebKit/LayoutTests/FlagExpectations/enable-browser-side-navigation
+++ b/third_party/WebKit/LayoutTests/FlagExpectations/enable-browser-side-navigation
@@ -26,9 +26,6 @@
 crbug.com/551000 virtual/mojo-loading/http/tests/inspector/extensions-ignore-cache.html [ Failure ]
 crbug.com/551000 virtual/mojo-loading/http/tests/inspector/extensions-network-redirect.html [ Timeout ]
 crbug.com/551000 virtual/mojo-loading/http/tests/inspector/network/x-frame-options-deny.html [ Failure ]
-#  Encoded bytes received & encoded data length mismatch.
-crbug.com/551000 http/tests/inspector/network/network-datareceived.html [ Failure ]
-crbug.com/551000 virtual/mojo-loading/http/tests/inspector/network/network-datareceived.html [ Failure ]
 #  Console error messages are wrongly ordered.
 crbug.com/551000 http/tests/inspector/console-resource-errors.html [ Failure ]
 crbug.com/551000 virtual/mojo-loading/http/tests/inspector/console-resource-errors.html [ Failure ]
diff --git a/third_party/WebKit/LayoutTests/cssom/serialize-attribute-selectors.html b/third_party/WebKit/LayoutTests/cssom/serialize-attribute-selectors.html
new file mode 100644
index 0000000..34aaba20
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/cssom/serialize-attribute-selectors.html
@@ -0,0 +1,34 @@
+<!DOCTYPE html>
+<title>Attribute selector serialization</title>
+<script src="../resources/testharness.js"></script>
+<script src="../resources/testharnessreport.js"></script>
+<style id="teststyles">
+</style>
+<script>
+    var escaped_ns_rule = "@namespace ns\\:odd url(ns);";
+
+    function assert_selector_serializes_to(source, expected_result) {
+        var style_element = document.getElementById("teststyles");
+        style_element.firstChild.data = source + "{ font-size: 1em; }";
+        var sheet = style_element.sheet;
+        assert_equals(sheet.cssRules[sheet.cssRules.length - 1].selectorText, expected_result);
+    }
+    test(function() {
+        assert_selector_serializes_to("[ns\\:foo]", "[ns\\:foo]");
+    }, document.title+", escaped character in attribute name");
+    test(function() {
+        assert_selector_serializes_to("[\\30zonk]", "[\\30 zonk]");
+    }, document.title+", escaped character as code point in attribute name");
+    test(function() {
+        assert_selector_serializes_to("[\\*]", "[\\*]");
+    }, document.title+", escaped character (*) in attribute");
+    test(function() {
+        assert_selector_serializes_to("[*|ns\\:foo]", "[*|ns\\:foo]");
+    }, document.title+", escaped character in attribute name with any namespace");
+    test(function() {
+        assert_selector_serializes_to(escaped_ns_rule + "[ns\\:odd|foo]", "[ns\\:odd|foo]");
+    }, document.title+", escaped character in attribute prefix");
+    test(function() {
+        assert_selector_serializes_to(escaped_ns_rule + "[ns\\:odd|odd\\:name]", "[ns\\:odd|odd\\:name]");
+    }, document.title+", escaped character in both attribute prefix and name");
+</script>
diff --git a/third_party/WebKit/LayoutTests/cssom/serialize-namespaced-type-selectors.html b/third_party/WebKit/LayoutTests/cssom/serialize-namespaced-type-selectors.html
index 84e82828..eb509d6 100644
--- a/third_party/WebKit/LayoutTests/cssom/serialize-namespaced-type-selectors.html
+++ b/third_party/WebKit/LayoutTests/cssom/serialize-namespaced-type-selectors.html
@@ -6,6 +6,7 @@
 <script>
     var ns_rule = "@namespace ns url(ns);";
     var default_ns_rules = "@namespace url(default_ns); @namespace nsdefault url(default_ns);" + ns_rule;
+    var escaped_ns_rule = "@namespace ns\\:odd url(ns);";
 
     function assert_selector_serializes_to(source, expected_result) {
         var style_element = document.getElementById("teststyles");
@@ -89,4 +90,10 @@
     test(function() {
         assert_selector_serializes_to(default_ns_rules + "nsdefault|*.c", ".c");
     }, "Universal selector with namespace equal to default namespace followed by class");
+    test(function() {
+        assert_selector_serializes_to(escaped_ns_rule + "ns\\:odd|e", "ns\\:odd|e");
+    }, "Type selector with namespace with escaped character");
+    test(function() {
+        assert_selector_serializes_to(escaped_ns_rule + "ns\\:odd|odd\\:e", "ns\\:odd|odd\\:e");
+    }, "Type selector with escaped character and namespace with escaped character");
 </script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/pointerevents/idlharness-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/pointerevents/idlharness-expected.txt
index 948b11d..107597a1 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/pointerevents/idlharness-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/pointerevents/idlharness-expected.txt
@@ -58,10 +58,10 @@
 PASS PointerEvent interface: attribute width 
 PASS PointerEvent interface: attribute height 
 PASS PointerEvent interface: attribute pressure 
-FAIL PointerEvent interface: attribute tangentialPressure assert_true: The prototype object must have a property "tangentialPressure" expected true got false
+PASS PointerEvent interface: attribute tangentialPressure 
 PASS PointerEvent interface: attribute tiltX 
 PASS PointerEvent interface: attribute tiltY 
-FAIL PointerEvent interface: attribute twist assert_true: The prototype object must have a property "twist" expected true got false
+PASS PointerEvent interface: attribute twist 
 PASS PointerEvent interface: attribute pointerType 
 PASS PointerEvent interface: attribute isPrimary 
 Harness: the test ran to completion.
diff --git a/third_party/WebKit/LayoutTests/external/wpt/pointerevents/pointerevent_constructor.html b/third_party/WebKit/LayoutTests/external/wpt/pointerevents/pointerevent_constructor.html
index b2a779d..b8a97d1 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/pointerevents/pointerevent_constructor.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/pointerevents/pointerevent_constructor.html
@@ -33,6 +33,8 @@
             var testButton = 0;
             var testButtons = 1;
             var testPressure = 0.4;
+            var testTangentialPressure = 0.5;
+            var testTwist = 286;
             var testIsPrimary = true;
 
             on_event(target0, "pointerover", this.step_func(function(event) {
@@ -50,10 +52,12 @@
                     ["custom clientY", event.clientY, testClientY],
                     ["custom tiltX", event.tiltX, testTiltX],
                     ["custom tiltY", event.tiltY, testTiltY],
+                    ["custom twist", event.twist, testTwist],
                     ["custom isPrimary", event.isPrimary, testIsPrimary]
                 ]);
                 test(function() {
                     assert_approx_equals(event.pressure, testPressure, 0.00000001, "custom pressure: ");
+                    assert_approx_equals(event.tangentialPressure, testTangentialPressure, 0.00000001, "custom tangential pressure: ");
                 }, "custom pressure: ");
             }));
 
@@ -66,6 +70,8 @@
                     ["default tiltX", event.tiltX, 0],
                     ["default tiltY", event.tiltY, 0],
                     ["default pressure", event.pressure, 0],
+                    ["default tangentialPressure", event.tangentialPressure, 0],
+                    ["default twist", event.twist, 0],
                     ["default isPrimary", event.isPrimary, false]
                 ]);
             }));
@@ -87,6 +93,8 @@
                 button: testButton,
                 buttons: testButtons,
                 pressure: testPressure,
+                tangentialPressure: testTangentialPressure,
+                twist: testTwist,
                 isPrimary: testIsPrimary
                 });
                 // A PointerEvent created with a PointerEvent constructor must have all its attributes set to the corresponding values provided to the constructor.
diff --git a/third_party/WebKit/LayoutTests/fast/block/float/rubybase-children-moved-crash-expected.txt b/third_party/WebKit/LayoutTests/fast/block/float/rubybase-children-moved-crash-expected.txt
new file mode 100644
index 0000000..5913014
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/block/float/rubybase-children-moved-crash-expected.txt
@@ -0,0 +1,3 @@
+crbug.com/681423: Don't clear floats when moving just some of the children of a ruby run. This test passes if it does not crash.
+
+ 
diff --git a/third_party/WebKit/LayoutTests/fast/block/float/rubybase-children-moved-crash.html b/third_party/WebKit/LayoutTests/fast/block/float/rubybase-children-moved-crash.html
new file mode 100644
index 0000000..9836932
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/block/float/rubybase-children-moved-crash.html
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<style>
+.CLASS1{display:list-item;}
+.CLASS13{float:right;}
+</style>
+<p>crbug.com/681423: Don't clear floats when moving just some of the children of a ruby run. This test passes if it does not crash.</p>
+<script>
+	if (window.testRunner)
+		testRunner.dumpAsText();
+	function fuzz() {
+	document.designMode = 'on';
+		document.execCommand("selectAll");
+		document.execCommand("Strikethrough");
+		document.execCommand("Strikethrough");
+	}
+	setTimeout(fuzz); 
+</script>
+<ruby>
+<rt>
+<rtc class="CLASS1">
+<input class="CLASS13">
\ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/fast/events/constructors/pointer-event-constructor-expected.txt b/third_party/WebKit/LayoutTests/fast/events/constructors/pointer-event-constructor-expected.txt
index 2b35ba3..07b0a94 100644
--- a/third_party/WebKit/LayoutTests/fast/events/constructors/pointer-event-constructor-expected.txt
+++ b/third_party/WebKit/LayoutTests/fast/events/constructors/pointer-event-constructor-expected.txt
@@ -74,6 +74,29 @@
 PASS new PointerEvent('eventType', { tiltY: {} }).tiltY is 0
 PASS new PointerEvent('eventType', { tiltY: {valueOf: function () { return 123; }} }).tiltY is 123
 -- no init --
+PASS new PointerEvent('eventType').twist is 0
+-- init with valid long values --
+PASS new PointerEvent('eventType', { twist: 0 }).twist is 0
+PASS new PointerEvent('eventType', { twist: 123 }).twist is 123
+PASS new PointerEvent('eventType', { twist: -123 }).twist is -123
+PASS new PointerEvent('eventType', { twist: 2147483647 }).twist is 2147483647
+PASS new PointerEvent('eventType', { twist: -2147483648 }).twist is -2147483648
+-- init with non-long values --
+PASS new PointerEvent('eventType', { twist: 18446744073709551615 }).twist is 0
+PASS new PointerEvent('eventType', {twist: 123.45 }).twist is 123
+PASS new PointerEvent('eventType', { twist: '123abc' }).twist is 0
+PASS new PointerEvent('eventType', { twist: 'dummy' }).twist is 0
+PASS new PointerEvent('eventType', { twist: NaN }).twist is 0
+PASS new PointerEvent('eventType', { twist: null }).twist is 0
+PASS new PointerEvent('eventType', { twist: undefined }).twist is 0
+PASS new PointerEvent('eventType', { twist: [] }).twist is 0
+PASS new PointerEvent('eventType', { twist: [12] }).twist is 12
+PASS new PointerEvent('eventType', { twist: [12, 34] }).twist is 0
+PASS new PointerEvent('eventType', { twist: {} }).twist is 0
+PASS new PointerEvent('eventType', { twist: {abc:1} }).twist is 0
+PASS new PointerEvent('eventType', { twist: {} }).twist is 0
+PASS new PointerEvent('eventType', { twist: {valueOf: function () { return 123; }} }).twist is 123
+-- no init --
 PASS new PointerEvent('eventType').width is 1
 -- init with valid float/double values --
 PASS new PointerEvent('eventType', { width: 0 }).width is 0
@@ -149,6 +172,31 @@
 PASS new PointerEvent('eventType', { pressure: {} }).pressure threw exception TypeError: Failed to construct 'PointerEvent': The provided float value is non-finite..
 PASS new PointerEvent('eventType', { pressure: {valueOf: function () { return 123; }} }).pressure is 123
 -- no init --
+PASS new PointerEvent('eventType').tangentialPressure is 0
+-- init with valid float/double values --
+PASS new PointerEvent('eventType', { tangentialPressure: 0 }).tangentialPressure is 0
+PASS new PointerEvent('eventType', { tangentialPressure: 123 }).tangentialPressure is 123
+PASS new PointerEvent('eventType', { tangentialPressure: -123 }).tangentialPressure is -123
+PASS new PointerEvent('eventType', { tangentialPressure: 123.45 }).tangentialPressure is within 0.00001 of 123.45
+PASS new PointerEvent('eventType', { tangentialPressure: -123.45 }).tangentialPressure is within 0.00001 of -123.45
+PASS new PointerEvent('eventType', { tangentialPressure: 1.23e5 }).tangentialPressure is within 0.00001 of 123000
+PASS new PointerEvent('eventType', { tangentialPressure: -1.2e-3 }).tangentialPressure is within 0.00001 of -0.0012
+PASS new PointerEvent('eventType', { tangentialPressure: 16777215 }).tangentialPressure is 16777215
+PASS new PointerEvent('eventType', { tangentialPressure: -16777216 }).tangentialPressure is -16777216
+-- init with non-float/double values --
+PASS new PointerEvent('eventType', { tangentialPressure: '123abc' }).tangentialPressure threw exception TypeError: Failed to construct 'PointerEvent': The provided float value is non-finite..
+PASS new PointerEvent('eventType', { tangentialPressure: 'dummy' }).tangentialPressure threw exception TypeError: Failed to construct 'PointerEvent': The provided float value is non-finite..
+PASS new PointerEvent('eventType', { tangentialPressure: NaN }).tangentialPressure threw exception TypeError: Failed to construct 'PointerEvent': The provided float value is non-finite..
+PASS new PointerEvent('eventType', { tangentialPressure: null }).tangentialPressure is 0
+PASS new PointerEvent('eventType', { tangentialPressure: undefined }).tangentialPressure is 0
+PASS new PointerEvent('eventType', { tangentialPressure: [] }).tangentialPressure is 0
+PASS new PointerEvent('eventType', { tangentialPressure: [12] }).tangentialPressure is 12
+PASS new PointerEvent('eventType', { tangentialPressure: [12, 34] }).tangentialPressure threw exception TypeError: Failed to construct 'PointerEvent': The provided float value is non-finite..
+PASS new PointerEvent('eventType', { tangentialPressure: {} }).tangentialPressure threw exception TypeError: Failed to construct 'PointerEvent': The provided float value is non-finite..
+PASS new PointerEvent('eventType', { tangentialPressure: {abc:1} }).tangentialPressure threw exception TypeError: Failed to construct 'PointerEvent': The provided float value is non-finite..
+PASS new PointerEvent('eventType', { tangentialPressure: {} }).tangentialPressure threw exception TypeError: Failed to construct 'PointerEvent': The provided float value is non-finite..
+PASS new PointerEvent('eventType', { tangentialPressure: {valueOf: function () { return 123; }} }).tangentialPressure is 123
+-- no init --
 PASS new PointerEvent('eventType').screenX is 0
 -- init with valid float/double values --
 PASS new PointerEvent('eventType', { screenX: 0 }).screenX is 0
diff --git a/third_party/WebKit/LayoutTests/fast/events/constructors/pointer-event-constructor.html b/third_party/WebKit/LayoutTests/fast/events/constructors/pointer-event-constructor.html
index 134bb2f..32dfdbd3 100644
--- a/third_party/WebKit/LayoutTests/fast/events/constructors/pointer-event-constructor.html
+++ b/third_party/WebKit/LayoutTests/fast/events/constructors/pointer-event-constructor.html
@@ -7,7 +7,7 @@
 
 debug("--- tests for intrinsic attributes plus screen & client coordinates ---");
 
-["pointerId", "tiltX", "tiltY"].forEach(function (attr) {
+["pointerId", "tiltX", "tiltY", "twist"].forEach(function (attr) {
   debug("-- no init --");
   shouldBeZero("new PointerEvent('eventType')." + attr);
 
@@ -35,7 +35,7 @@
   shouldBeEqualToNumber("new PointerEvent('eventType', { " + attr + ": {valueOf: function () { return 123; }} })." + attr, 123);
 });
 
-["width", "height", "pressure", "screenX", "screenY", "clientX", "clientY"].forEach(function (attr) {
+["width", "height", "pressure", "tangentialPressure", "screenX", "screenY", "clientX", "clientY"].forEach(function (attr) {
   debug("-- no init --");
   var defaultValue = (attr == "width" || attr == "height") ? 1 : 0;
   shouldBeEqualToNumber("new PointerEvent('eventType')." + attr, defaultValue);
diff --git a/third_party/WebKit/LayoutTests/http/tests/feature-policy/payment-disabled-expected.txt b/third_party/WebKit/LayoutTests/http/tests/feature-policy/payment-disabled-expected.txt
new file mode 100644
index 0000000..674a76bf
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/feature-policy/payment-disabled-expected.txt
@@ -0,0 +1,33 @@
+   
+
+--------
+Frame: '<!--framePath //<!--frame0-->-->'
+--------
+This is a testharness.js-based test.
+PASS No iframe may construct PaymentRequest when disabled. 
+Harness: the test ran to completion.
+
+
+--------
+Frame: '<!--framePath //<!--frame1-->-->'
+--------
+This is a testharness.js-based test.
+PASS No iframe may construct PaymentRequest when disabled. 
+Harness: the test ran to completion.
+
+
+--------
+Frame: '<!--framePath //<!--frame2-->-->'
+--------
+This is a testharness.js-based test.
+FAIL No iframe may construct PaymentRequest when disabled. assert_unreached: PaymentRequest should be disabled by FeaturePolicy Reached unreachable code
+Harness: the test ran to completion.
+
+
+--------
+Frame: '<!--framePath //<!--frame3-->-->'
+--------
+This is a testharness.js-based test.
+FAIL No iframe may construct PaymentRequest when disabled. assert_unreached: PaymentRequest should be disabled by FeaturePolicy Reached unreachable code
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/http/tests/feature-policy/payment-disabled.php b/third_party/WebKit/LayoutTests/http/tests/feature-policy/payment-disabled.php
new file mode 100644
index 0000000..5e134e9
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/feature-policy/payment-disabled.php
@@ -0,0 +1,24 @@
+<?php
+// 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.
+
+// This test ensures that payment feature when disabled may not be called by
+// any iframe even when allowpaymentrequest is set.
+
+Header("Feature-Policy: {\"payment\": []}");
+?>
+
+<!DOCTYPE html>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script>
+  if (window.testRunner) {
+    testRunner.dumpAsText();
+    testRunner.dumpChildFramesAsText();
+  }
+</script>
+<iframe id="f1" src="resources/feature-policy-payment-disabled.html"></iframe>
+<iframe id="f2" src="http://localhost:8000/feature-policy/resources/feature-policy-payment-disabled.html"></iframe>
+<iframe id="f3" src="resources/feature-policy-payment-disabled.html" allowpaymentrequest></iframe>
+<iframe id="f4" src="http://localhost:8000/feature-policy/resources/feature-policy-payment-disabled.html" allowpaymentrequest></iframe>
diff --git a/third_party/WebKit/LayoutTests/http/tests/feature-policy/payment-enabledforall-expected.txt b/third_party/WebKit/LayoutTests/http/tests/feature-policy/payment-enabledforall-expected.txt
new file mode 100644
index 0000000..e8fb2be
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/feature-policy/payment-enabledforall-expected.txt
@@ -0,0 +1,33 @@
+   
+
+--------
+Frame: '<!--framePath //<!--frame0-->-->'
+--------
+This is a testharness.js-based test.
+FAIL Any iframes may construct PaymentRequest when enabled. assert_unreached: PaymentRequest should be enabled by FeaturePolicy Reached unreachable code
+Harness: the test ran to completion.
+
+
+--------
+Frame: '<!--framePath //<!--frame1-->-->'
+--------
+This is a testharness.js-based test.
+FAIL Any iframes may construct PaymentRequest when enabled. assert_unreached: PaymentRequest should be enabled by FeaturePolicy Reached unreachable code
+Harness: the test ran to completion.
+
+
+--------
+Frame: '<!--framePath //<!--frame2-->-->'
+--------
+This is a testharness.js-based test.
+PASS Any iframes may construct PaymentRequest when enabled. 
+Harness: the test ran to completion.
+
+
+--------
+Frame: '<!--framePath //<!--frame3-->-->'
+--------
+This is a testharness.js-based test.
+PASS Any iframes may construct PaymentRequest when enabled. 
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/http/tests/feature-policy/payment-enabledforall.php b/third_party/WebKit/LayoutTests/http/tests/feature-policy/payment-enabledforall.php
new file mode 100644
index 0000000..4c6d529
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/feature-policy/payment-enabledforall.php
@@ -0,0 +1,25 @@
+<?php
+// 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.
+
+// This test ensures that payment feature when enabled for all works across
+// all origins regardless whether allowpaymentrequest is set. (Feature policy
+// header takes precedence over the absence of allowpaymentrequest.)
+
+Header("Feature-Policy: {\"payment\": [\"*\"]}");
+?>
+
+<!DOCTYPE html>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script>
+  if (window.testRunner) {
+    testRunner.dumpAsText();
+    testRunner.dumpChildFramesAsText();
+  }
+</script>
+<iframe id="f1" src="resources/feature-policy-payment-enabled.html"></iframe>
+<iframe id="f2" src="http://localhost:8000/feature-policy/resources/feature-policy-payment-enabled.html"></iframe>
+<iframe id="f3" src="resources/feature-policy-payment-enabled.html" allowpaymentrequest></iframe>
+<iframe id="f4" src="http://localhost:8000/feature-policy/resources/feature-policy-payment-enabled.html" allowpaymentrequest></iframe>
diff --git a/third_party/WebKit/LayoutTests/http/tests/feature-policy/payment-enabledforself-expected.txt b/third_party/WebKit/LayoutTests/http/tests/feature-policy/payment-enabledforself-expected.txt
new file mode 100644
index 0000000..3ae1f16
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/feature-policy/payment-enabledforself-expected.txt
@@ -0,0 +1,33 @@
+   
+
+--------
+Frame: '<!--framePath //<!--frame0-->-->'
+--------
+This is a testharness.js-based test.
+FAIL Any iframes may construct PaymentRequest when enabled. assert_unreached: PaymentRequest should be enabled by FeaturePolicy Reached unreachable code
+Harness: the test ran to completion.
+
+
+--------
+Frame: '<!--framePath //<!--frame1-->-->'
+--------
+This is a testharness.js-based test.
+PASS No iframe may construct PaymentRequest when disabled. 
+Harness: the test ran to completion.
+
+
+--------
+Frame: '<!--framePath //<!--frame2-->-->'
+--------
+This is a testharness.js-based test.
+PASS Any iframes may construct PaymentRequest when enabled. 
+Harness: the test ran to completion.
+
+
+--------
+Frame: '<!--framePath //<!--frame3-->-->'
+--------
+This is a testharness.js-based test.
+PASS Any iframes may construct PaymentRequest when enabled. 
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/http/tests/feature-policy/payment-enabledforself.php b/third_party/WebKit/LayoutTests/http/tests/feature-policy/payment-enabledforself.php
new file mode 100644
index 0000000..bc92d47
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/feature-policy/payment-enabledforself.php
@@ -0,0 +1,25 @@
+<?php
+// 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.
+
+// This test ensures that payment feature when enabled for self works in
+// the same origin or when allowpaymentrequest is set. No cross-origin iframe
+// may call it when allowpaymentrequest is not set.
+
+Header("Feature-Policy: {\"payment\": [\"self\"]}");
+?>
+
+<!DOCTYPE html>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script>
+  if (window.testRunner) {
+    testRunner.dumpAsText();
+    testRunner.dumpChildFramesAsText();
+  }
+</script>
+<iframe id="f1" src="resources/feature-policy-payment-enabled.html"></iframe>
+<iframe id="f2" src="http://localhost:8000/feature-policy/resources/feature-policy-payment-disabled.html"></iframe>
+<iframe id="f3" src="resources/feature-policy-payment-enabled.html" allowpaymentrequest></iframe>
+<iframe id="f4" src="http://localhost:8000/feature-policy/resources/feature-policy-payment-enabled.html" allowpaymentrequest></iframe>
diff --git a/third_party/WebKit/LayoutTests/http/tests/feature-policy/resources/feature-policy-payment-disabled.html b/third_party/WebKit/LayoutTests/http/tests/feature-policy/resources/feature-policy-payment-disabled.html
new file mode 100644
index 0000000..cfe76f1d
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/feature-policy/resources/feature-policy-payment-disabled.html
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<head>
+  <title>Feature-Policy PaymentRequest Disabled</title>
+  <script src="/resources/testharness.js"></script>
+  <script src="/resources/testharnessreport.js"></script>
+</head>
+<script>
+  test(function() {
+    var supportedInstruments = [ { supportedMethods: [ 'visa' ] } ];
+    var details = {
+      total: { label: 'Test', amount: { currency: 'USD', value: '5.00' } }
+    };
+    try {
+      new PaymentRequest(supportedInstruments, details);
+      assert_unreached('PaymentRequest should be disabled by FeaturePolicy');
+    } catch (e) {
+      if ( e.message.includes("assert_unreached") ) { throw e; }
+      assert_equals(e.name, "SecurityError");
+      assert_equals(e.message, "Failed to construct 'PaymentRequest': Must be in a top-level browsing context or an iframe needs to specify 'allowpaymentrequest' explicitly");
+    }
+  }, 'No iframe may construct PaymentRequest when disabled.');
+</script>
diff --git a/third_party/WebKit/LayoutTests/http/tests/feature-policy/resources/feature-policy-payment-enabled.html b/third_party/WebKit/LayoutTests/http/tests/feature-policy/resources/feature-policy-payment-enabled.html
new file mode 100644
index 0000000..ee07de1
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/feature-policy/resources/feature-policy-payment-enabled.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<head>
+  <title>Feature-Policy PaymentRequest Enabled</title>
+  <script src="/resources/testharness.js"></script>
+  <script src="/resources/testharnessreport.js"></script>
+</head>
+<script>
+  test(function() {
+    var supportedInstruments = [ { supportedMethods: [ 'visa' ] } ];
+    var details = {
+      total: { label: 'Test', amount: { currency: 'USD', value: '5.00' } }
+    };
+    try {
+      new PaymentRequest(supportedInstruments, details);
+    } catch (e) {
+      assert_unreached('PaymentRequest should be enabled by FeaturePolicy');
+    }
+  }, 'Any iframes may construct PaymentRequest when enabled.');
+</script>
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/stable/webexposed/global-interface-listing-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/virtual/stable/webexposed/global-interface-listing-expected.txt
index 4c553a34..051e01431 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/virtual/stable/webexposed/global-interface-listing-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/stable/webexposed/global-interface-listing-expected.txt
@@ -3829,8 +3829,10 @@
     getter pointerId
     getter pointerType
     getter pressure
+    getter tangentialPressure
     getter tiltX
     getter tiltY
+    getter twist
     getter width
     method constructor
 interface PopStateEvent : Event
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/stable/webexposed/global-interface-listing-expected.txt b/third_party/WebKit/LayoutTests/platform/win/virtual/stable/webexposed/global-interface-listing-expected.txt
index 4c553a34..051e01431 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/stable/webexposed/global-interface-listing-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/stable/webexposed/global-interface-listing-expected.txt
@@ -3829,8 +3829,10 @@
     getter pointerId
     getter pointerType
     getter pressure
+    getter tangentialPressure
     getter tiltX
     getter tiltY
+    getter twist
     getter width
     method constructor
 interface PopStateEvent : Event
diff --git a/third_party/WebKit/LayoutTests/virtual/feature-policy/http/tests/feature-policy/payment-disabled-expected.txt b/third_party/WebKit/LayoutTests/virtual/feature-policy/http/tests/feature-policy/payment-disabled-expected.txt
new file mode 100644
index 0000000..8d0c5ed5
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/virtual/feature-policy/http/tests/feature-policy/payment-disabled-expected.txt
@@ -0,0 +1,33 @@
+   
+
+--------
+Frame: '<!--framePath //<!--frame0-->-->'
+--------
+This is a testharness.js-based test.
+PASS No iframe may construct PaymentRequest when disabled. 
+Harness: the test ran to completion.
+
+
+--------
+Frame: '<!--framePath //<!--frame1-->-->'
+--------
+This is a testharness.js-based test.
+PASS No iframe may construct PaymentRequest when disabled. 
+Harness: the test ran to completion.
+
+
+--------
+Frame: '<!--framePath //<!--frame2-->-->'
+--------
+This is a testharness.js-based test.
+PASS No iframe may construct PaymentRequest when disabled. 
+Harness: the test ran to completion.
+
+
+--------
+Frame: '<!--framePath //<!--frame3-->-->'
+--------
+This is a testharness.js-based test.
+PASS No iframe may construct PaymentRequest when disabled. 
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/virtual/feature-policy/http/tests/feature-policy/payment-enabledforall-expected.txt b/third_party/WebKit/LayoutTests/virtual/feature-policy/http/tests/feature-policy/payment-enabledforall-expected.txt
new file mode 100644
index 0000000..ee0cd67
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/virtual/feature-policy/http/tests/feature-policy/payment-enabledforall-expected.txt
@@ -0,0 +1,33 @@
+   
+
+--------
+Frame: '<!--framePath //<!--frame0-->-->'
+--------
+This is a testharness.js-based test.
+PASS Any iframes may construct PaymentRequest when enabled. 
+Harness: the test ran to completion.
+
+
+--------
+Frame: '<!--framePath //<!--frame1-->-->'
+--------
+This is a testharness.js-based test.
+PASS Any iframes may construct PaymentRequest when enabled. 
+Harness: the test ran to completion.
+
+
+--------
+Frame: '<!--framePath //<!--frame2-->-->'
+--------
+This is a testharness.js-based test.
+PASS Any iframes may construct PaymentRequest when enabled. 
+Harness: the test ran to completion.
+
+
+--------
+Frame: '<!--framePath //<!--frame3-->-->'
+--------
+This is a testharness.js-based test.
+PASS Any iframes may construct PaymentRequest when enabled. 
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/virtual/feature-policy/http/tests/feature-policy/payment-enabledforself-expected.txt b/third_party/WebKit/LayoutTests/virtual/feature-policy/http/tests/feature-policy/payment-enabledforself-expected.txt
new file mode 100644
index 0000000..073d901
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/virtual/feature-policy/http/tests/feature-policy/payment-enabledforself-expected.txt
@@ -0,0 +1,33 @@
+   
+
+--------
+Frame: '<!--framePath //<!--frame0-->-->'
+--------
+This is a testharness.js-based test.
+PASS Any iframes may construct PaymentRequest when enabled. 
+Harness: the test ran to completion.
+
+
+--------
+Frame: '<!--framePath //<!--frame1-->-->'
+--------
+This is a testharness.js-based test.
+PASS No iframe may construct PaymentRequest when disabled. 
+Harness: the test ran to completion.
+
+
+--------
+Frame: '<!--framePath //<!--frame2-->-->'
+--------
+This is a testharness.js-based test.
+PASS Any iframes may construct PaymentRequest when enabled. 
+Harness: the test ran to completion.
+
+
+--------
+Frame: '<!--framePath //<!--frame3-->-->'
+--------
+This is a testharness.js-based test.
+PASS Any iframes may construct PaymentRequest when enabled. 
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/virtual/stable/webexposed/global-interface-listing-expected.txt b/third_party/WebKit/LayoutTests/virtual/stable/webexposed/global-interface-listing-expected.txt
index 93501d7c..35608e8 100644
--- a/third_party/WebKit/LayoutTests/virtual/stable/webexposed/global-interface-listing-expected.txt
+++ b/third_party/WebKit/LayoutTests/virtual/stable/webexposed/global-interface-listing-expected.txt
@@ -3901,8 +3901,10 @@
     getter pointerId
     getter pointerType
     getter pressure
+    getter tangentialPressure
     getter tiltX
     getter tiltY
+    getter twist
     getter width
     method constructor
 interface PopStateEvent : Event
diff --git a/third_party/WebKit/LayoutTests/webaudio/AudioListener/audiolistener-automation-basic-expected.txt b/third_party/WebKit/LayoutTests/webaudio/AudioListener/audiolistener-automation-basic-expected.txt
deleted file mode 100644
index 9a2e023..0000000
--- a/third_party/WebKit/LayoutTests/webaudio/AudioListener/audiolistener-automation-basic-expected.txt
+++ /dev/null
@@ -1,6 +0,0 @@
-CONSOLE ERROR: line 9: Uncaught ReferenceError: description is not defined
-layer at (0,0) size 800x600
-  LayoutView at (0,0) size 800x600
-layer at (0,0) size 800x8
-  LayoutBlockFlow {HTML} at (0,0) size 800x8
-    LayoutBlockFlow {BODY} at (8,8) size 784x0
diff --git a/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt b/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt
index b3a7f5f..8f8479af 100644
--- a/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt
+++ b/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt
@@ -4748,8 +4748,10 @@
     getter pointerId
     getter pointerType
     getter pressure
+    getter tangentialPressure
     getter tiltX
     getter tiltY
+    getter twist
     getter width
     method constructor
     method getCoalescedEvents
diff --git a/third_party/WebKit/Source/core/css/CSSSelector.cpp b/third_party/WebKit/Source/core/css/CSSSelector.cpp
index 308d664..8cb455f 100644
--- a/third_party/WebKit/Source/core/css/CSSSelector.cpp
+++ b/third_party/WebKit/Source/core/css/CSSSelector.cpp
@@ -630,17 +630,28 @@
   return true;
 }
 
+static void serializeIdentifierOrAny(const AtomicString& identifier,
+                                     StringBuilder& builder) {
+  if (identifier != starAtom)
+    serializeIdentifier(identifier, builder);
+  else
+    builder.append(identifier);
+}
+
+static void serializeNamespacePrefixIfNeeded(const AtomicString& prefix,
+                                             StringBuilder& builder) {
+  if (prefix.isNull())
+    return;
+  serializeIdentifierOrAny(prefix, builder);
+  builder.append('|');
+}
+
 String CSSSelector::selectorText(const String& rightSide) const {
   StringBuilder str;
 
   if (m_match == Tag && !m_tagIsImplicit) {
-    if (tagQName().prefix().isNull()) {
-      str.append(tagQName().localName());
-    } else {
-      str.append(tagQName().prefix().getString());
-      str.append('|');
-      str.append(tagQName().localName());
-    }
+    serializeNamespacePrefixIfNeeded(tagQName().prefix(), str);
+    serializeIdentifierOrAny(tagQName().localName(), str);
   }
 
   const CSSSelector* cs = this;
@@ -699,12 +710,8 @@
       str.append(cs->serializingValue());
     } else if (cs->isAttributeSelector()) {
       str.append('[');
-      const AtomicString& prefix = cs->attribute().prefix();
-      if (!prefix.isNull()) {
-        str.append(prefix);
-        str.append('|');
-      }
-      str.append(cs->attribute().localName());
+      serializeNamespacePrefixIfNeeded(cs->attribute().prefix(), str);
+      serializeIdentifier(cs->attribute().localName(), str);
       switch (cs->m_match) {
         case AttributeExact:
           str.append('=');
diff --git a/third_party/WebKit/Source/core/events/PointerEvent.cpp b/third_party/WebKit/Source/core/events/PointerEvent.cpp
index a609321e1..8b416ad 100644
--- a/third_party/WebKit/Source/core/events/PointerEvent.cpp
+++ b/third_party/WebKit/Source/core/events/PointerEvent.cpp
@@ -18,6 +18,8 @@
       m_pressure(0),
       m_tiltX(0),
       m_tiltY(0),
+      m_tangentialPressure(0),
+      m_twist(0),
       m_isPrimary(false) {
   if (initializer.hasPointerId())
     m_pointerId = initializer.pointerId();
@@ -31,6 +33,10 @@
     m_tiltX = initializer.tiltX();
   if (initializer.hasTiltY())
     m_tiltY = initializer.tiltY();
+  if (initializer.hasTangentialPressure())
+    m_tangentialPressure = initializer.tangentialPressure();
+  if (initializer.hasTwist())
+    m_twist = initializer.twist();
   if (initializer.hasPointerType())
     m_pointerType = initializer.pointerType();
   if (initializer.hasIsPrimary())
diff --git a/third_party/WebKit/Source/core/events/PointerEvent.h b/third_party/WebKit/Source/core/events/PointerEvent.h
index e647948..38e82a5 100644
--- a/third_party/WebKit/Source/core/events/PointerEvent.h
+++ b/third_party/WebKit/Source/core/events/PointerEvent.h
@@ -26,6 +26,8 @@
   float pressure() const { return m_pressure; }
   long tiltX() const { return m_tiltX; }
   long tiltY() const { return m_tiltY; }
+  float tangentialPressure() const { return m_tangentialPressure; }
+  long twist() const { return m_twist; }
   const String& pointerType() const { return m_pointerType; }
   bool isPrimary() const { return m_isPrimary; }
 
@@ -48,6 +50,8 @@
   float m_pressure;
   long m_tiltX;
   long m_tiltY;
+  float m_tangentialPressure;
+  long m_twist;
   String m_pointerType;
   bool m_isPrimary;
 
diff --git a/third_party/WebKit/Source/core/events/PointerEvent.idl b/third_party/WebKit/Source/core/events/PointerEvent.idl
index 7370d376..1a6fef3 100644
--- a/third_party/WebKit/Source/core/events/PointerEvent.idl
+++ b/third_party/WebKit/Source/core/events/PointerEvent.idl
@@ -14,6 +14,8 @@
     [MeasureAs=PointerEventAttributeCount]   readonly    attribute float     pressure;
     [MeasureAs=PointerEventAttributeCount]   readonly    attribute long      tiltX;
     [MeasureAs=PointerEventAttributeCount]   readonly    attribute long      tiltY;
+    [MeasureAs=PointerEventAttributeCount]   readonly    attribute float     tangentialPressure;
+    [MeasureAs=PointerEventAttributeCount]   readonly    attribute long      twist;
     [MeasureAs=PointerEventAttributeCount]   readonly    attribute DOMString pointerType;
     [MeasureAs=PointerEventAttributeCount]   readonly    attribute boolean   isPrimary;
 
diff --git a/third_party/WebKit/Source/core/events/PointerEventFactory.cpp b/third_party/WebKit/Source/core/events/PointerEventFactory.cpp
index 8271c17..c7ea4712 100644
--- a/third_party/WebKit/Source/core/events/PointerEventFactory.cpp
+++ b/third_party/WebKit/Source/core/events/PointerEventFactory.cpp
@@ -129,6 +129,9 @@
       getPointerEventPressure(touchPoint.force(), pointerEventInit->buttons()));
   pointerEventInit->setTiltX(touchPoint.pointerProperties().tiltX);
   pointerEventInit->setTiltY(touchPoint.pointerProperties().tiltY);
+  pointerEventInit->setTangentialPressure(
+      touchPoint.pointerProperties().tangentialPressure);
+  pointerEventInit->setTwist(touchPoint.pointerProperties().twist);
 }
 
 void updateMousePointerEventInit(const PlatformMouseEvent& mouseEvent,
@@ -159,6 +162,9 @@
       mouseEvent.pointerProperties().force, pointerEventInit->buttons()));
   pointerEventInit->setTiltX(mouseEvent.pointerProperties().tiltX);
   pointerEventInit->setTiltY(mouseEvent.pointerProperties().tiltY);
+  pointerEventInit->setTangentialPressure(
+      mouseEvent.pointerProperties().tangentialPressure);
+  pointerEventInit->setTwist(mouseEvent.pointerProperties().twist);
 }
 
 }  // namespace
@@ -369,6 +375,8 @@
   pointerEventInit.setPressure(pointerEvent->pressure());
   pointerEventInit.setTiltX(pointerEvent->tiltX());
   pointerEventInit.setTiltY(pointerEvent->tiltY());
+  pointerEventInit.setTangentialPressure(pointerEvent->tangentialPressure());
+  pointerEventInit.setTwist(pointerEvent->twist());
   pointerEventInit.setView(pointerEvent->view());
 
   setEventSpecificFields(pointerEventInit, type);
diff --git a/third_party/WebKit/Source/core/events/PointerEventInit.idl b/third_party/WebKit/Source/core/events/PointerEventInit.idl
index 18e2bdc..049adc7 100644
--- a/third_party/WebKit/Source/core/events/PointerEventInit.idl
+++ b/third_party/WebKit/Source/core/events/PointerEventInit.idl
@@ -11,6 +11,8 @@
     float     pressure = 0;
     long      tiltX = 0;
     long      tiltY = 0;
+    float     tangentialPressure = 0;
+    long      twist = 0;
     DOMString pointerType = "";
     boolean   isPrimary = false;
 
diff --git a/third_party/WebKit/Source/core/fetch/MemoryCacheCorrectnessTest.cpp b/third_party/WebKit/Source/core/fetch/MemoryCacheCorrectnessTest.cpp
index 46b3f6c..baefbba4 100644
--- a/third_party/WebKit/Source/core/fetch/MemoryCacheCorrectnessTest.cpp
+++ b/third_party/WebKit/Source/core/fetch/MemoryCacheCorrectnessTest.cpp
@@ -38,6 +38,7 @@
 #include "core/fetch/Resource.h"
 #include "core/fetch/ResourceFetcher.h"
 #include "platform/network/ResourceRequest.h"
+#include "platform/testing/TestingPlatformSupport.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace blink {
@@ -49,21 +50,9 @@
 
 // The origin time of our first request.
 constexpr char kOriginalRequestDateAsString[] = "Thu, 25 May 1977 18:30:00 GMT";
-constexpr double kOriginalRequestDateAsDouble = 233433000.;
-
 constexpr char kOneDayBeforeOriginalRequest[] = "Wed, 24 May 1977 18:30:00 GMT";
 constexpr char kOneDayAfterOriginalRequest[] = "Fri, 26 May 1977 18:30:00 GMT";
 
-double timeElapsed = 0.0;
-
-void advanceClock(double seconds) {
-  timeElapsed += seconds;
-}
-
-double returnMockTime() {
-  return kOriginalRequestDateAsDouble + timeElapsed;
-}
-
 }  // namespace
 
 class MemoryCacheCorrectnessTest : public ::testing::Test {
@@ -105,6 +94,9 @@
     return MockResource::fetch(fetchRequest, fetcher());
   }
   ResourceFetcher* fetcher() const { return m_fetcher.get(); }
+  void advanceClock(double seconds) {
+    m_platform->advanceClockSeconds(seconds);
+  }
 
  private:
   // Overrides ::testing::Test.
@@ -114,22 +106,18 @@
 
     m_fetcher = ResourceFetcher::create(
         MockFetchContext::create(MockFetchContext::kShouldNotLoadNewResource));
-
-    timeElapsed = 0.0;
-    m_originalTimeFunction = setTimeFunctionsForTesting(returnMockTime);
   }
   void TearDown() override {
     memoryCache()->evictResources();
 
     // Yield the ownership of the global memory cache back.
     replaceMemoryCacheForTesting(m_globalMemoryCache.release());
-
-    setTimeFunctionsForTesting(m_originalTimeFunction);
   }
 
   Persistent<MemoryCache> m_globalMemoryCache;
   Persistent<ResourceFetcher> m_fetcher;
-  TimeFunction m_originalTimeFunction;
+  ScopedTestingPlatformSupport<TestingPlatformSupportWithMockScheduler>
+      m_platform;
 };
 
 TEST_F(MemoryCacheCorrectnessTest, FreshFromLastModified) {
diff --git a/third_party/WebKit/Source/core/layout/LayoutRubyBase.cpp b/third_party/WebKit/Source/core/layout/LayoutRubyBase.cpp
index a60916d..18d3e2f 100644
--- a/third_party/WebKit/Source/core/layout/LayoutRubyBase.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutRubyBase.cpp
@@ -129,7 +129,7 @@
   if (!beforeChild)
     moveAllChildrenIncludingFloatsTo(toBase, toBase->hasLayer() || hasLayer());
   else
-    moveChildrenTo(toBase, firstChild(), beforeChild, toBase->children());
+    moveChildrenTo(toBase, firstChild(), beforeChild);
 }
 
 ETextAlign LayoutRubyBase::textAlignmentForLine(
diff --git a/third_party/WebKit/Source/core/loader/ThreadableLoaderTest.cpp b/third_party/WebKit/Source/core/loader/ThreadableLoaderTest.cpp
index 41ebcca..5a28dcdc 100644
--- a/third_party/WebKit/Source/core/loader/ThreadableLoaderTest.cpp
+++ b/third_party/WebKit/Source/core/loader/ThreadableLoaderTest.cpp
@@ -30,6 +30,7 @@
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "wtf/Assertions.h"
+#include "wtf/Functional.h"
 #include "wtf/PtrUtil.h"
 #include "wtf/RefPtr.h"
 #include <memory>
@@ -178,11 +179,11 @@
         WTF::makeUnique<WaitableEvent>();
     postTaskToWorkerGlobalScope(
         BLINK_FROM_HERE,
-        createCrossThreadTask(
-            &WorkerThreadableLoaderTestHelper::workerCreateLoader,
-            crossThreadUnretained(this), crossThreadUnretained(client),
-            crossThreadUnretained(completionEvent.get()),
-            crossOriginRequestPolicy));
+        crossThreadBind(&WorkerThreadableLoaderTestHelper::workerCreateLoader,
+                        crossThreadUnretained(this),
+                        crossThreadUnretained(client),
+                        crossThreadUnretained(completionEvent.get()),
+                        crossOriginRequestPolicy));
     completionEvent->wait();
   }
 
@@ -191,10 +192,9 @@
         WTF::makeUnique<WaitableEvent>();
     postTaskToWorkerGlobalScope(
         BLINK_FROM_HERE,
-        createCrossThreadTask(
-            &WorkerThreadableLoaderTestHelper::workerStartLoader,
-            crossThreadUnretained(this),
-            crossThreadUnretained(completionEvent.get()), request));
+        crossThreadBind(&WorkerThreadableLoaderTestHelper::workerStartLoader,
+                        crossThreadUnretained(this),
+                        crossThreadUnretained(completionEvent.get()), request));
     completionEvent->wait();
   }
 
@@ -228,10 +228,9 @@
         WTF::makeUnique<WaitableEvent>();
     postTaskToWorkerGlobalScope(
         BLINK_FROM_HERE,
-        createCrossThreadTask(
-            &WorkerThreadableLoaderTestHelper::workerCallCheckpoint,
-            crossThreadUnretained(this),
-            crossThreadUnretained(completionEvent.get()), n));
+        crossThreadBind(&WorkerThreadableLoaderTestHelper::workerCallCheckpoint,
+                        crossThreadUnretained(this),
+                        crossThreadUnretained(completionEvent.get()), n));
     completionEvent->wait();
   }
 
@@ -254,12 +253,12 @@
   void onTearDown() override {
     postTaskToWorkerGlobalScope(
         BLINK_FROM_HERE,
-        createCrossThreadTask(&WorkerThreadableLoaderTestHelper::clearLoader,
-                              crossThreadUnretained(this)));
+        crossThreadBind(&WorkerThreadableLoaderTestHelper::clearLoader,
+                        crossThreadUnretained(this)));
     WaitableEvent event;
     postTaskToWorkerGlobalScope(
-        BLINK_FROM_HERE, createCrossThreadTask(&WaitableEvent::signal,
-                                               crossThreadUnretained(&event)));
+        BLINK_FROM_HERE,
+        crossThreadBind(&WaitableEvent::signal, crossThreadUnretained(&event)));
     event.wait();
     m_workerThread->terminateAndWait();
 
@@ -340,7 +339,7 @@
 
   void postTaskToWorkerGlobalScope(
       const WebTraceLocation& location,
-      std::unique_ptr<ExecutionContextTask> task) override {
+      std::unique_ptr<WTF::CrossThreadClosure> task) override {
     DCHECK(m_workerThread);
     m_workerThread->postTask(location, std::move(task));
   }
diff --git a/third_party/WebKit/Source/core/loader/WorkerThreadableLoader.cpp b/third_party/WebKit/Source/core/loader/WorkerThreadableLoader.cpp
index f0e49d8..3f9d1e8 100644
--- a/third_party/WebKit/Source/core/loader/WorkerThreadableLoader.cpp
+++ b/third_party/WebKit/Source/core/loader/WorkerThreadableLoader.cpp
@@ -44,6 +44,7 @@
 #include "platform/network/ResourceTimingInfo.h"
 #include "platform/weborigin/KURL.h"
 #include "platform/weborigin/SecurityPolicy.h"
+#include "wtf/Functional.h"
 #include "wtf/debug/Alias.h"
 #include <memory>
 
@@ -72,13 +73,13 @@
   ~AsyncTaskForwarder() override { DCHECK(isMainThread()); }
 
   void forwardTask(const WebTraceLocation& location,
-                   std::unique_ptr<ExecutionContextTask> task) override {
+                   std::unique_ptr<CrossThreadClosure> task) override {
     DCHECK(isMainThread());
     m_loaderProxy->postTaskToWorkerGlobalScope(location, std::move(task));
   }
   void forwardTaskWithDoneSignal(
       const WebTraceLocation& location,
-      std::unique_ptr<ExecutionContextTask> task) override {
+      std::unique_ptr<CrossThreadClosure> task) override {
     DCHECK(isMainThread());
     m_loaderProxy->postTaskToWorkerGlobalScope(location, std::move(task));
   }
@@ -90,14 +91,14 @@
 
 struct WorkerThreadableLoader::TaskWithLocation final {
   TaskWithLocation(const WebTraceLocation& location,
-                   std::unique_ptr<ExecutionContextTask> task)
+                   std::unique_ptr<CrossThreadClosure> task)
       : m_location(location), m_task(std::move(task)) {}
   TaskWithLocation(TaskWithLocation&& task)
       : TaskWithLocation(task.m_location, std::move(task.m_task)) {}
   ~TaskWithLocation() = default;
 
   WebTraceLocation m_location;
-  std::unique_ptr<ExecutionContextTask> m_task;
+  std::unique_ptr<CrossThreadClosure> m_task;
 };
 
 // Observing functions and wait() need to be called on the worker thread.
@@ -168,13 +169,13 @@
   ~SyncTaskForwarder() override { DCHECK(isMainThread()); }
 
   void forwardTask(const WebTraceLocation& location,
-                   std::unique_ptr<ExecutionContextTask> task) override {
+                   std::unique_ptr<CrossThreadClosure> task) override {
     DCHECK(isMainThread());
     m_eventWithTasks->append(TaskWithLocation(location, std::move(task)));
   }
   void forwardTaskWithDoneSignal(
       const WebTraceLocation& location,
-      std::unique_ptr<ExecutionContextTask> task) override {
+      std::unique_ptr<CrossThreadClosure> task) override {
     DCHECK(isMainThread());
     m_eventWithTasks->append(TaskWithLocation(location, std::move(task)));
     m_eventWithTasks->signal();
@@ -260,9 +261,7 @@
     const void* programCounter = task.m_location.program_counter();
     WTF::debug::alias(&programCounter);
 
-    // m_clientTask contains only CallClosureTasks. So, it's ok to pass
-    // the nullptr.
-    task.m_task->performTask(nullptr);
+    (*task.m_task)();
   }
 }
 
@@ -454,9 +453,9 @@
   mainThreadLoaderHolder->m_workerLoader = workerLoader;
   forwarder->forwardTask(
       BLINK_FROM_HERE,
-      createCrossThreadTask(&WorkerThreadableLoader::didStart,
-                            wrapCrossThreadPersistent(workerLoader),
-                            wrapCrossThreadPersistent(mainThreadLoaderHolder)));
+      crossThreadBind(&WorkerThreadableLoader::didStart,
+                      wrapCrossThreadPersistent(workerLoader),
+                      wrapCrossThreadPersistent(mainThreadLoaderHolder)));
   mainThreadLoaderHolder->start(*toDocument(executionContext),
                                 std::move(request), options,
                                 resourceLoaderOptions);
@@ -494,8 +493,8 @@
     return;
   m_forwarder->forwardTask(
       BLINK_FROM_HERE,
-      createCrossThreadTask(&WorkerThreadableLoader::didSendData, workerLoader,
-                            bytesSent, totalBytesToBeSent));
+      crossThreadBind(&WorkerThreadableLoader::didSendData, workerLoader,
+                      bytesSent, totalBytesToBeSent));
 }
 
 void WorkerThreadableLoader::MainThreadLoaderHolder::didReceiveRedirectTo(
@@ -507,8 +506,8 @@
     return;
   m_forwarder->forwardTask(
       BLINK_FROM_HERE,
-      createCrossThreadTask(&WorkerThreadableLoader::didReceiveRedirectTo,
-                            workerLoader, url));
+      crossThreadBind(&WorkerThreadableLoader::didReceiveRedirectTo,
+                      workerLoader, url));
 }
 
 void WorkerThreadableLoader::MainThreadLoaderHolder::didReceiveResponse(
@@ -522,9 +521,8 @@
     return;
   m_forwarder->forwardTask(
       BLINK_FROM_HERE,
-      createCrossThreadTask(&WorkerThreadableLoader::didReceiveResponse,
-                            workerLoader, identifier, response,
-                            WTF::passed(std::move(handle))));
+      crossThreadBind(&WorkerThreadableLoader::didReceiveResponse, workerLoader,
+                      identifier, response, WTF::passed(std::move(handle))));
 }
 
 void WorkerThreadableLoader::MainThreadLoaderHolder::didReceiveData(
@@ -537,7 +535,7 @@
     return;
   m_forwarder->forwardTask(
       BLINK_FROM_HERE,
-      createCrossThreadTask(
+      crossThreadBind(
           &WorkerThreadableLoader::didReceiveData, workerLoader,
           WTF::passed(createVectorFromMemoryRegion(data, dataLength))));
 }
@@ -550,9 +548,8 @@
   if (!workerLoader || !m_forwarder)
     return;
   m_forwarder->forwardTask(
-      BLINK_FROM_HERE,
-      createCrossThreadTask(&WorkerThreadableLoader::didDownloadData,
-                            workerLoader, dataLength));
+      BLINK_FROM_HERE, crossThreadBind(&WorkerThreadableLoader::didDownloadData,
+                                       workerLoader, dataLength));
 }
 
 void WorkerThreadableLoader::MainThreadLoaderHolder::didReceiveCachedMetadata(
@@ -565,7 +562,7 @@
     return;
   m_forwarder->forwardTask(
       BLINK_FROM_HERE,
-      createCrossThreadTask(
+      crossThreadBind(
           &WorkerThreadableLoader::didReceiveCachedMetadata, workerLoader,
           WTF::passed(createVectorFromMemoryRegion(data, dataLength))));
 }
@@ -580,8 +577,8 @@
     return;
   m_forwarder->forwardTaskWithDoneSignal(
       BLINK_FROM_HERE,
-      createCrossThreadTask(&WorkerThreadableLoader::didFinishLoading,
-                            workerLoader, identifier, finishTime));
+      crossThreadBind(&WorkerThreadableLoader::didFinishLoading, workerLoader,
+                      identifier, finishTime));
   m_forwarder = nullptr;
 }
 
@@ -593,8 +590,8 @@
   if (!workerLoader || !m_forwarder)
     return;
   m_forwarder->forwardTaskWithDoneSignal(
-      BLINK_FROM_HERE, createCrossThreadTask(&WorkerThreadableLoader::didFail,
-                                             workerLoader, error));
+      BLINK_FROM_HERE,
+      crossThreadBind(&WorkerThreadableLoader::didFail, workerLoader, error));
   m_forwarder = nullptr;
 }
 
@@ -607,8 +604,8 @@
     return;
   m_forwarder->forwardTaskWithDoneSignal(
       BLINK_FROM_HERE,
-      createCrossThreadTask(&WorkerThreadableLoader::didFailAccessControlCheck,
-                            workerLoader, error));
+      crossThreadBind(&WorkerThreadableLoader::didFailAccessControlCheck,
+                      workerLoader, error));
   m_forwarder = nullptr;
 }
 
@@ -620,8 +617,8 @@
     return;
   m_forwarder->forwardTaskWithDoneSignal(
       BLINK_FROM_HERE,
-      createCrossThreadTask(&WorkerThreadableLoader::didFailRedirectCheck,
-                            workerLoader));
+      crossThreadBind(&WorkerThreadableLoader::didFailRedirectCheck,
+                      workerLoader));
   m_forwarder = nullptr;
 }
 
@@ -634,8 +631,8 @@
     return;
   m_forwarder->forwardTask(
       BLINK_FROM_HERE,
-      createCrossThreadTask(&WorkerThreadableLoader::didReceiveResourceTiming,
-                            workerLoader, info));
+      crossThreadBind(&WorkerThreadableLoader::didReceiveResourceTiming,
+                      workerLoader, info));
 }
 
 void WorkerThreadableLoader::MainThreadLoaderHolder::contextDestroyed(
diff --git a/third_party/WebKit/Source/core/loader/WorkerThreadableLoader.h b/third_party/WebKit/Source/core/loader/WorkerThreadableLoader.h
index 3cffacf..5f3d2b0e 100644
--- a/third_party/WebKit/Source/core/loader/WorkerThreadableLoader.h
+++ b/third_party/WebKit/Source/core/loader/WorkerThreadableLoader.h
@@ -31,7 +31,6 @@
 #ifndef WorkerThreadableLoader_h
 #define WorkerThreadableLoader_h
 
-#include "core/dom/ExecutionContextTask.h"
 #include "core/loader/ThreadableLoader.h"
 #include "core/loader/ThreadableLoaderClient.h"
 #include "core/workers/WorkerThread.h"
@@ -110,15 +109,15 @@
  private:
   enum BlockingBehavior { LoadSynchronously, LoadAsynchronously };
 
-  // A TaskForwarder forwards an ExecutionContextTask to the worker thread.
+  // A TaskForwarder forwards a task to the worker thread.
   class TaskForwarder : public GarbageCollectedFinalized<TaskForwarder> {
    public:
     virtual ~TaskForwarder() {}
     virtual void forwardTask(const WebTraceLocation&,
-                             std::unique_ptr<ExecutionContextTask>) = 0;
+                             std::unique_ptr<CrossThreadClosure>) = 0;
     virtual void forwardTaskWithDoneSignal(
         const WebTraceLocation&,
-        std::unique_ptr<ExecutionContextTask>) = 0;
+        std::unique_ptr<CrossThreadClosure>) = 0;
     virtual void abort() = 0;
 
     DEFINE_INLINE_VIRTUAL_TRACE() {}
diff --git a/third_party/WebKit/Source/core/workers/InProcessWorkerMessagingProxy.cpp b/third_party/WebKit/Source/core/workers/InProcessWorkerMessagingProxy.cpp
index 9c8b717b6..563e9fb 100644
--- a/third_party/WebKit/Source/core/workers/InProcessWorkerMessagingProxy.cpp
+++ b/third_party/WebKit/Source/core/workers/InProcessWorkerMessagingProxy.cpp
@@ -174,10 +174,9 @@
 
   postTaskToWorkerGlobalScope(
       BLINK_FROM_HERE,
-      createCrossThreadTask(
-          &InProcessWorkerObjectProxy::processUnhandledException,
-          crossThreadUnretained(m_workerObjectProxy.get()), exceptionId,
-          crossThreadUnretained(workerThread())));
+      crossThreadBind(&InProcessWorkerObjectProxy::processUnhandledException,
+                      crossThreadUnretained(m_workerObjectProxy.get()),
+                      exceptionId, crossThreadUnretained(workerThread())));
 }
 
 void InProcessWorkerMessagingProxy::workerThreadCreated() {
diff --git a/third_party/WebKit/Source/core/workers/ThreadedMessagingProxyBase.cpp b/third_party/WebKit/Source/core/workers/ThreadedMessagingProxyBase.cpp
index f3c7be8..f9df56d 100644
--- a/third_party/WebKit/Source/core/workers/ThreadedMessagingProxyBase.cpp
+++ b/third_party/WebKit/Source/core/workers/ThreadedMessagingProxyBase.cpp
@@ -62,7 +62,7 @@
 
 void ThreadedMessagingProxyBase::postTaskToWorkerGlobalScope(
     const WebTraceLocation& location,
-    std::unique_ptr<ExecutionContextTask> task) {
+    std::unique_ptr<WTF::CrossThreadClosure> task) {
   if (m_askedToTerminate)
     return;
 
diff --git a/third_party/WebKit/Source/core/workers/ThreadedMessagingProxyBase.h b/third_party/WebKit/Source/core/workers/ThreadedMessagingProxyBase.h
index 0ea4a216..09a841d 100644
--- a/third_party/WebKit/Source/core/workers/ThreadedMessagingProxyBase.h
+++ b/third_party/WebKit/Source/core/workers/ThreadedMessagingProxyBase.h
@@ -82,7 +82,7 @@
                         std::unique_ptr<ExecutionContextTask>) override;
   void postTaskToWorkerGlobalScope(
       const WebTraceLocation&,
-      std::unique_ptr<ExecutionContextTask>) override;
+      std::unique_ptr<WTF::CrossThreadClosure>) override;
 
  private:
   friend class InProcessWorkerMessagingProxyForTest;
diff --git a/third_party/WebKit/Source/core/workers/ThreadedWorkletMessagingProxy.cpp b/third_party/WebKit/Source/core/workers/ThreadedWorkletMessagingProxy.cpp
index e70ec8f2..c0be1a3 100644
--- a/third_party/WebKit/Source/core/workers/ThreadedWorkletMessagingProxy.cpp
+++ b/third_party/WebKit/Source/core/workers/ThreadedWorkletMessagingProxy.cpp
@@ -60,10 +60,10 @@
     const ScriptSourceCode& scriptSourceCode) {
   postTaskToWorkerGlobalScope(
       BLINK_FROM_HERE,
-      createCrossThreadTask(&ThreadedWorkletObjectProxy::evaluateScript,
-                            crossThreadUnretained(m_workletObjectProxy.get()),
-                            scriptSourceCode.source(), scriptSourceCode.url(),
-                            crossThreadUnretained(workerThread())));
+      crossThreadBind(&ThreadedWorkletObjectProxy::evaluateScript,
+                      crossThreadUnretained(m_workletObjectProxy.get()),
+                      scriptSourceCode.source(), scriptSourceCode.url(),
+                      crossThreadUnretained(workerThread())));
 }
 
 void ThreadedWorkletMessagingProxy::terminateWorkletGlobalScope() {
diff --git a/third_party/WebKit/Source/core/workers/WorkerLoaderProxy.cpp b/third_party/WebKit/Source/core/workers/WorkerLoaderProxy.cpp
index 922d5bc6..7c21c93 100644
--- a/third_party/WebKit/Source/core/workers/WorkerLoaderProxy.cpp
+++ b/third_party/WebKit/Source/core/workers/WorkerLoaderProxy.cpp
@@ -34,7 +34,7 @@
 
 void WorkerLoaderProxy::postTaskToWorkerGlobalScope(
     const WebTraceLocation& location,
-    std::unique_ptr<ExecutionContextTask> task) {
+    std::unique_ptr<WTF::CrossThreadClosure> task) {
   MutexLocker locker(m_lock);
   if (!m_loaderProxyProvider)
     return;
diff --git a/third_party/WebKit/Source/core/workers/WorkerLoaderProxy.h b/third_party/WebKit/Source/core/workers/WorkerLoaderProxy.h
index e31d7bc..5951d8b 100644
--- a/third_party/WebKit/Source/core/workers/WorkerLoaderProxy.h
+++ b/third_party/WebKit/Source/core/workers/WorkerLoaderProxy.h
@@ -69,7 +69,7 @@
   // Posts callbacks from loading code to the WorkerGlobalScope.
   virtual void postTaskToWorkerGlobalScope(
       const WebTraceLocation&,
-      std::unique_ptr<ExecutionContextTask>) = 0;
+      std::unique_ptr<WTF::CrossThreadClosure>) = 0;
 };
 
 class CORE_EXPORT WorkerLoaderProxy final
@@ -85,7 +85,7 @@
   void postTaskToLoader(const WebTraceLocation&,
                         std::unique_ptr<ExecutionContextTask>);
   void postTaskToWorkerGlobalScope(const WebTraceLocation&,
-                                   std::unique_ptr<ExecutionContextTask>);
+                                   std::unique_ptr<WTF::CrossThreadClosure>);
 
   // Notification from the provider that it can no longer be accessed. An
   // implementation of WorkerLoaderProxyProvider is required to call
diff --git a/third_party/WebKit/Source/core/workers/WorkerThread.cpp b/third_party/WebKit/Source/core/workers/WorkerThread.cpp
index 56fd9be0..e7fc1966 100644
--- a/third_party/WebKit/Source/core/workers/WorkerThread.cpp
+++ b/third_party/WebKit/Source/core/workers/WorkerThread.cpp
@@ -199,6 +199,13 @@
                                 WTF::passed(std::move(task))));
 }
 
+void WorkerThread::postTask(const WebTraceLocation& location,
+                            std::unique_ptr<WTF::CrossThreadClosure> task) {
+  std::unique_ptr<ExecutionContextTask> wrappedTask = createCrossThreadTask(
+      &WTF::CrossThreadClosure::operator(), WTF::passed(std::move(task)));
+  postTask(location, std::move(wrappedTask));
+}
+
 void WorkerThread::appendDebuggerTask(
     std::unique_ptr<CrossThreadClosure> task) {
   DCHECK(isMainThread());
diff --git a/third_party/WebKit/Source/core/workers/WorkerThread.h b/third_party/WebKit/Source/core/workers/WorkerThread.h
index 89702de..d3af4f3 100644
--- a/third_party/WebKit/Source/core/workers/WorkerThread.h
+++ b/third_party/WebKit/Source/core/workers/WorkerThread.h
@@ -136,7 +136,12 @@
     return m_workerReportingProxy;
   }
 
+  // DEPRECATED: Use postTask() for WTF::CrossThreadClosure instead.
+  // TODO(nhiroki): Remove this after https://crbug.com/625927 is completed.
   void postTask(const WebTraceLocation&, std::unique_ptr<ExecutionContextTask>);
+
+  void postTask(const WebTraceLocation&,
+                std::unique_ptr<WTF::CrossThreadClosure>);
   void appendDebuggerTask(std::unique_ptr<CrossThreadClosure>);
 
   // Runs only debugger tasks while paused in debugger.
diff --git a/third_party/WebKit/Source/core/workers/WorkerThreadTestHelper.h b/third_party/WebKit/Source/core/workers/WorkerThreadTestHelper.h
index 7c7e06f..9cd4e0d7 100644
--- a/third_party/WebKit/Source/core/workers/WorkerThreadTestHelper.h
+++ b/third_party/WebKit/Source/core/workers/WorkerThreadTestHelper.h
@@ -46,7 +46,7 @@
 
   void postTaskToWorkerGlobalScope(
       const WebTraceLocation&,
-      std::unique_ptr<ExecutionContextTask>) override {
+      std::unique_ptr<WTF::CrossThreadClosure>) override {
     NOTIMPLEMENTED();
   }
 };
diff --git a/third_party/WebKit/Source/devtools/front_end/Images/src/optimize_png.hashes b/third_party/WebKit/Source/devtools/front_end/Images/src/optimize_png.hashes
index 152a9c3b..ea846dc 100644
--- a/third_party/WebKit/Source/devtools/front_end/Images/src/optimize_png.hashes
+++ b/third_party/WebKit/Source/devtools/front_end/Images/src/optimize_png.hashes
@@ -5,7 +5,7 @@
     "errorWave.svg": "e183fa242a22ed4784a92f6becbc2c45",
     "smallIcons.svg": "e42007c7e8da94ecab276fd254f0623e",
     "settingsListRemove.svg": "ce9e7c5c5cdaef28e6ee51d9478d5485",
-    "toolbarButtonGlyphs.svg": "ae43d11a5ce96de41357cca39f90e37c",
+    "toolbarButtonGlyphs.svg": "a2f97ba793fb31f61930f934c0837e34",
     "breakpoint.svg": "69cd92d807259c022791112809b97799",
     "search.svg": "fc990dd3836aec510d7ca1f36c2a3142"
 }
\ No newline at end of file
diff --git a/third_party/WebKit/Source/devtools/front_end/Images/src/svg2png.hashes b/third_party/WebKit/Source/devtools/front_end/Images/src/svg2png.hashes
index 152a9c3b..ea846dc 100644
--- a/third_party/WebKit/Source/devtools/front_end/Images/src/svg2png.hashes
+++ b/third_party/WebKit/Source/devtools/front_end/Images/src/svg2png.hashes
@@ -5,7 +5,7 @@
     "errorWave.svg": "e183fa242a22ed4784a92f6becbc2c45",
     "smallIcons.svg": "e42007c7e8da94ecab276fd254f0623e",
     "settingsListRemove.svg": "ce9e7c5c5cdaef28e6ee51d9478d5485",
-    "toolbarButtonGlyphs.svg": "ae43d11a5ce96de41357cca39f90e37c",
+    "toolbarButtonGlyphs.svg": "a2f97ba793fb31f61930f934c0837e34",
     "breakpoint.svg": "69cd92d807259c022791112809b97799",
     "search.svg": "fc990dd3836aec510d7ca1f36c2a3142"
 }
\ No newline at end of file
diff --git a/third_party/WebKit/Source/devtools/front_end/Images/src/toolbarButtonGlyphs.svg b/third_party/WebKit/Source/devtools/front_end/Images/src/toolbarButtonGlyphs.svg
index 37ac2fa..ff8ce6de 100644
--- a/third_party/WebKit/Source/devtools/front_end/Images/src/toolbarButtonGlyphs.svg
+++ b/third_party/WebKit/Source/devtools/front_end/Images/src/toolbarButtonGlyphs.svg
@@ -1147,18 +1147,12 @@
      inkscape:connector-curvature="0"
      d="m 288,72 h 24 v 24 h -24 z"
      id="path3763" /><g
-     style="fill:none;fill-rule:evenodd;stroke:none;stroke-width:1"
-     id="Page-1-6"
-     transform="translate(296,76)"><g
-       id="gear2"><g
-         id="Group-3-Copy-2"><rect
-           style="fill:#212121;fill-opacity:0"
-           id="Rectangle-2-Copy"
-           x="0"
-           y="0"
-           width="16"
-           height="16" /><path
-           style="fill:#000000"
-           inkscape:connector-curvature="0"
-           d="M 6,3.4160437 6,1 l 4,0 0,2.4160437 c 0.345025,0.1507477 0.669748,0.3393074 0.968932,0.5604413 l 2.093246,-1.2085358 2,3.4641016 -2.093129,1.2084688 C 12.989499,7.6241929 13,7.8108702 13,8 13,8.1891298 12.9895,8.3758071 12.96905,8.5594805 l 2.093129,1.2084687 -2,3.4641018 -2.093246,-1.208536 C 10.669748,12.244649 10.345025,12.433209 10,12.583956 L 10,15 6,15 6,12.583956 C 5.6549754,12.433209 5.3302519,12.244649 5.0310676,12.023515 L 2.9378222,13.232051 0.93782217,9.7679492 3.0309514,8.5594805 C 3.0105009,8.3758071 3,8.1891298 3,8 3,7.8108702 3.0105009,7.6241929 3.0309514,7.4405196 L 0.93782217,6.2320508 2.9378222,2.7679492 5.0310676,3.976485 C 5.3302519,3.7553511 5.6549754,3.5667914 6,3.4160437 Z M 8,10.5 C 9.3807119,10.5 10.5,9.3807119 10.5,8 10.5,6.6192881 9.3807119,5.5 8,5.5 6.6192881,5.5 5.5,6.6192881 5.5,8 c 0,1.3807119 1.1192881,2.5 2.5,2.5 z"
-           id="Combined-Shape" /></g></g></g></svg>
\ No newline at end of file
+     id="g3844"
+     transform="matrix(-1,0,0,-1,607.00004,168)"><path
+       sodipodi:nodetypes="ssccccccccsssssss"
+       inkscape:connector-curvature="0"
+       id="path3654"
+       d="m 304.5,76 c -0.73331,0 -1.5,0.7 -1.5,1.5 l 0,1.5 1.5,0 0,-1 7,0 0.0781,12 -7.07819,0 1.3e-4,-1 -1.5,0 0,1.5 c 0,0.8 0.76669,1.5 1.5,1.5 l 7,0 c 0.7333,0 1.5,-0.7 1.5,-1.5 l 0,-13 c 0,-0.8 -0.61045,-1.5 -1.34375,-1.5 z" /><path
+       id="path3765"
+       d="m 304.58443,84.588 c 0.0247,-0.192 0.0432,-0.384 0.0432,-0.588 0,-0.204 -0.0185,-0.396 -0.0432,-0.588 l 1.30152,-0.99 c 0.1172,-0.09 0.14804,-0.252 0.074,-0.384 l -1.23366,-2.076 c -0.0741,-0.132 -0.24056,-0.18 -0.37627,-0.132 l -1.53591,0.6 c -0.32075,-0.24 -0.66617,-0.438 -1.04244,-0.588 l -0.2344,-1.59 C 301.51877,78.108 301.38923,78 301.23502,78 h -2.46732 c -0.15421,0 -0.28374,0.108 -0.30225,0.252 l -0.23439,1.59 c -0.37627,0.15 -0.7217,0.354 -1.04245,0.588 l -1.5359,-0.6 c -0.14187,-0.054 -0.30225,0 -0.37627,0.132 l -1.23366,2.076 c -0.0802,0.132 -0.0432,0.294 0.074,0.384 l 1.30151,0.99 c -0.0247,0.192 -0.0432,0.39 -0.0432,0.588 0,0.198 0.0185,0.396 0.0432,0.588 l -1.30151,0.99 c -0.11719,0.09 -0.14803,0.252 -0.074,0.384 l 1.23366,2.076 c 0.0741,0.132 0.24057,0.18 0.37627,0.132 l 1.5359,-0.6 c 0.32075,0.24 0.66618,0.438 1.04245,0.588 l 0.23439,1.59 c 0.0185,0.144 0.14804,0.252 0.30225,0.252 h 2.46732 c 0.15421,0 0.28375,-0.108 0.30225,-0.252 l 0.2344,-1.59 c 0.37627,-0.15 0.72169,-0.354 1.04244,-0.588 l 1.53591,0.6 c 0.14188,0.054 0.30225,0 0.37627,-0.132 l 1.23366,-2.076 c 0.0741,-0.132 0.0432,-0.294 -0.074,-0.384 l -1.30152,-0.99 z m -4.58305,1.512 c -1.19048,0 -2.15891,-0.942 -2.15891,-2.1 0,-1.158 0.96843,-2.1 2.15891,-2.1 1.19048,0 2.15891,0.942 2.15891,2.1 0,1.158 -0.96843,2.1 -2.15891,2.1 z"
+       inkscape:connector-curvature="0" /></g></svg>
\ No newline at end of file
diff --git a/third_party/WebKit/Source/devtools/front_end/Images/toolbarButtonGlyphs.png b/third_party/WebKit/Source/devtools/front_end/Images/toolbarButtonGlyphs.png
index c9c5971..6e16294 100644
--- a/third_party/WebKit/Source/devtools/front_end/Images/toolbarButtonGlyphs.png
+++ b/third_party/WebKit/Source/devtools/front_end/Images/toolbarButtonGlyphs.png
Binary files differ
diff --git a/third_party/WebKit/Source/devtools/front_end/Images/toolbarButtonGlyphs_2x.png b/third_party/WebKit/Source/devtools/front_end/Images/toolbarButtonGlyphs_2x.png
index 736ef9c..4f809ef 100644
--- a/third_party/WebKit/Source/devtools/front_end/Images/toolbarButtonGlyphs_2x.png
+++ b/third_party/WebKit/Source/devtools/front_end/Images/toolbarButtonGlyphs_2x.png
Binary files differ
diff --git a/third_party/WebKit/Source/modules/geolocation/GeoNotifier.cpp b/third_party/WebKit/Source/modules/geolocation/GeoNotifier.cpp
index 0d78f5b..9d1027e 100644
--- a/third_party/WebKit/Source/modules/geolocation/GeoNotifier.cpp
+++ b/third_party/WebKit/Source/modules/geolocation/GeoNotifier.cpp
@@ -4,6 +4,7 @@
 
 #include "modules/geolocation/GeoNotifier.h"
 
+#include "core/dom/TaskRunnerHelper.h"
 #include "modules/geolocation/Geolocation.h"
 #include "modules/geolocation/PositionError.h"
 #include "modules/geolocation/PositionOptions.h"
@@ -20,7 +21,10 @@
       m_successCallback(successCallback),
       m_errorCallback(errorCallback),
       m_options(options),
-      m_timer(this, &GeoNotifier::timerFired),
+      m_timer(TaskRunnerHelper::get(TaskType::MiscPlatformAPI,
+                                    geolocation->frame()),
+              this,
+              &GeoNotifier::timerFired),
       m_useCachedPosition(false) {
   DCHECK(m_geolocation);
   DCHECK(m_successCallback);
diff --git a/third_party/WebKit/Source/modules/geolocation/GeoNotifier.h b/third_party/WebKit/Source/modules/geolocation/GeoNotifier.h
index e254fe1e..ee91c10 100644
--- a/third_party/WebKit/Source/modules/geolocation/GeoNotifier.h
+++ b/third_party/WebKit/Source/modules/geolocation/GeoNotifier.h
@@ -61,7 +61,7 @@
   Member<PositionCallback> m_successCallback;
   Member<PositionErrorCallback> m_errorCallback;
   const PositionOptions m_options;
-  Timer<GeoNotifier> m_timer;
+  TaskRunnerTimer<GeoNotifier> m_timer;
   Member<PositionError> m_fatalError;
   bool m_useCachedPosition;
 };
diff --git a/third_party/WebKit/Source/modules/payments/PaymentRequest.cpp b/third_party/WebKit/Source/modules/payments/PaymentRequest.cpp
index b4fa7ef5..ee4f321f 100644
--- a/third_party/WebKit/Source/modules/payments/PaymentRequest.cpp
+++ b/third_party/WebKit/Source/modules/payments/PaymentRequest.cpp
@@ -4,6 +4,7 @@
 
 #include "modules/payments/PaymentRequest.h"
 
+#include "bindings/core/v8/ConditionalFeatures.h"
 #include "bindings/core/v8/ExceptionState.h"
 #include "bindings/core/v8/ScriptPromiseResolver.h"
 #include "bindings/core/v8/ScriptState.h"
@@ -559,19 +560,54 @@
   if (!frame)
     return false;
 
-  // 2. If |document|'s browsing context is a top-level browsing context, then
-  // return true.
-  if (frame->isMainFrame())
+  if (!RuntimeEnabledFeatures::featurePolicyEnabled()) {
+    // 2. If |document|'s browsing context is a top-level browsing context, then
+    // return true.
+    if (frame->isMainFrame())
+      return true;
+
+    // 3. If |document|'s browsing context has a browsing context container that
+    // is an iframe element with an |allowpaymentrequest| attribute specified,
+    // and whose node document is allowed to use the feature indicated by
+    // |allowpaymentrequest|, then return true.
+    if (frame->owner() && frame->owner()->allowPaymentRequest())
+      return allowedToUsePaymentRequest(frame->tree().parent());
+
+    // 4. Return false.
+    return false;
+  }
+
+  // If Feature Policy is enabled. then we need this hack to support it, until
+  // we have proper support for <iframe allowfullscreen> in FP:
+  // TODO(lunalu): clean up the code once FP iframe is supported
+  // crbug.com/682280
+
+  // 1. If FP, by itself, enables paymentrequest in this document, then
+  // paymentrequest is allowed.
+  if (frame->securityContext()->getFeaturePolicy()->isFeatureEnabled(
+          kPaymentFeature)) {
     return true;
+  }
 
-  // 3. If |document|'s browsing context has a browsing context container that
-  // is an iframe element with an |allowpaymentrequest| attribute specified, and
-  // whose node document is allowed to use the feature indicated by
-  // |allowpaymentrequest|, then return true.
-  if (frame->owner() && frame->owner()->allowPaymentRequest())
-    return allowedToUsePaymentRequest(frame->tree().parent());
+  // 2. Otherwise, if the embedding frame's document is allowed to use
+  // paymentrequest (either through FP or otherwise), and either:
+  //   a) this is a same-origin embedded document, or
+  //   b) this document's iframe has the allowpayment attribute set,
+  // then paymentrequest is allowed.
+  if (!frame->isMainFrame()) {
+    if (allowedToUsePaymentRequest(frame->tree().parent())) {
+      return (frame->owner() && frame->owner()->allowPaymentRequest()) ||
+             frame->tree()
+                 .parent()
+                 ->securityContext()
+                 ->getSecurityOrigin()
+                 ->isSameSchemeHostPortAndSuborigin(
+                     frame->securityContext()->getSecurityOrigin());
+    }
+  }
 
-  // 4. Return false.
+  // Otherwise, paymentrequest is not allowed. (If we reach here and this is
+  // the main frame, then paymentrequest must have been disabled by FP.)
   return false;
 }
 
diff --git a/third_party/WebKit/Source/modules/websockets/WorkerWebSocketChannel.cpp b/third_party/WebKit/Source/modules/websockets/WorkerWebSocketChannel.cpp
index f7b53f92..ecddcb2 100644
--- a/third_party/WebKit/Source/modules/websockets/WorkerWebSocketChannel.cpp
+++ b/third_party/WebKit/Source/modules/websockets/WorkerWebSocketChannel.cpp
@@ -236,9 +236,7 @@
 
 static void workerGlobalScopeDidConnect(Bridge* bridge,
                                         const String& subprotocol,
-                                        const String& extensions,
-                                        ExecutionContext* context) {
-  DCHECK(context->isWorkerGlobalScope());
+                                        const String& extensions) {
   if (bridge && bridge->client())
     bridge->client()->didConnect(subprotocol, extensions);
 }
@@ -246,15 +244,12 @@
 void Peer::didConnect(const String& subprotocol, const String& extensions) {
   DCHECK(isMainThread());
   m_loaderProxy->postTaskToWorkerGlobalScope(
-      BLINK_FROM_HERE,
-      createCrossThreadTask(&workerGlobalScopeDidConnect, m_bridge, subprotocol,
-                            extensions));
+      BLINK_FROM_HERE, crossThreadBind(&workerGlobalScopeDidConnect, m_bridge,
+                                       subprotocol, extensions));
 }
 
 static void workerGlobalScopeDidReceiveTextMessage(Bridge* bridge,
-                                                   const String& payload,
-                                                   ExecutionContext* context) {
-  DCHECK(context->isWorkerGlobalScope());
+                                                   const String& payload) {
   if (bridge && bridge->client())
     bridge->client()->didReceiveTextMessage(payload);
 }
@@ -262,16 +257,13 @@
 void Peer::didReceiveTextMessage(const String& payload) {
   DCHECK(isMainThread());
   m_loaderProxy->postTaskToWorkerGlobalScope(
-      BLINK_FROM_HERE,
-      createCrossThreadTask(&workerGlobalScopeDidReceiveTextMessage, m_bridge,
-                            payload));
+      BLINK_FROM_HERE, crossThreadBind(&workerGlobalScopeDidReceiveTextMessage,
+                                       m_bridge, payload));
 }
 
 static void workerGlobalScopeDidReceiveBinaryMessage(
     Bridge* bridge,
-    std::unique_ptr<Vector<char>> payload,
-    ExecutionContext* context) {
-  DCHECK(context->isWorkerGlobalScope());
+    std::unique_ptr<Vector<char>> payload) {
   if (bridge && bridge->client())
     bridge->client()->didReceiveBinaryMessage(std::move(payload));
 }
@@ -280,15 +272,12 @@
   DCHECK(isMainThread());
   m_loaderProxy->postTaskToWorkerGlobalScope(
       BLINK_FROM_HERE,
-      createCrossThreadTask(&workerGlobalScopeDidReceiveBinaryMessage, m_bridge,
-                            WTF::passed(std::move(payload))));
+      crossThreadBind(&workerGlobalScopeDidReceiveBinaryMessage, m_bridge,
+                      WTF::passed(std::move(payload))));
 }
 
-static void workerGlobalScopeDidConsumeBufferedAmount(
-    Bridge* bridge,
-    uint64_t consumed,
-    ExecutionContext* context) {
-  DCHECK(context->isWorkerGlobalScope());
+static void workerGlobalScopeDidConsumeBufferedAmount(Bridge* bridge,
+                                                      uint64_t consumed) {
   if (bridge && bridge->client())
     bridge->client()->didConsumeBufferedAmount(consumed);
 }
@@ -297,14 +286,11 @@
   DCHECK(isMainThread());
   m_loaderProxy->postTaskToWorkerGlobalScope(
       BLINK_FROM_HERE,
-      createCrossThreadTask(&workerGlobalScopeDidConsumeBufferedAmount,
-                            m_bridge, consumed));
+      crossThreadBind(&workerGlobalScopeDidConsumeBufferedAmount, m_bridge,
+                      consumed));
 }
 
-static void workerGlobalScopeDidStartClosingHandshake(
-    Bridge* bridge,
-    ExecutionContext* context) {
-  DCHECK(context->isWorkerGlobalScope());
+static void workerGlobalScopeDidStartClosingHandshake(Bridge* bridge) {
   if (bridge && bridge->client())
     bridge->client()->didStartClosingHandshake();
 }
@@ -313,8 +299,7 @@
   DCHECK(isMainThread());
   m_loaderProxy->postTaskToWorkerGlobalScope(
       BLINK_FROM_HERE,
-      createCrossThreadTask(&workerGlobalScopeDidStartClosingHandshake,
-                            m_bridge));
+      crossThreadBind(&workerGlobalScopeDidStartClosingHandshake, m_bridge));
 }
 
 static void workerGlobalScopeDidClose(
@@ -322,9 +307,7 @@
     WebSocketChannelClient::ClosingHandshakeCompletionStatus
         closingHandshakeCompletion,
     unsigned short code,
-    const String& reason,
-    ExecutionContext* context) {
-  DCHECK(context->isWorkerGlobalScope());
+    const String& reason) {
   if (bridge && bridge->client())
     bridge->client()->didClose(closingHandshakeCompletion, code, reason);
 }
@@ -339,13 +322,11 @@
   }
   m_loaderProxy->postTaskToWorkerGlobalScope(
       BLINK_FROM_HERE,
-      createCrossThreadTask(&workerGlobalScopeDidClose, m_bridge,
-                            closingHandshakeCompletion, code, reason));
+      crossThreadBind(&workerGlobalScopeDidClose, m_bridge,
+                      closingHandshakeCompletion, code, reason));
 }
 
-static void workerGlobalScopeDidError(Bridge* bridge,
-                                      ExecutionContext* context) {
-  DCHECK(context->isWorkerGlobalScope());
+static void workerGlobalScopeDidError(Bridge* bridge) {
   if (bridge && bridge->client())
     bridge->client()->didError();
 }
@@ -353,8 +334,7 @@
 void Peer::didError() {
   DCHECK(isMainThread());
   m_loaderProxy->postTaskToWorkerGlobalScope(
-      BLINK_FROM_HERE,
-      createCrossThreadTask(&workerGlobalScopeDidError, m_bridge));
+      BLINK_FROM_HERE, crossThreadBind(&workerGlobalScopeDidError, m_bridge));
 }
 
 void Peer::contextDestroyed(WorkerThreadLifecycleContext*) {
diff --git a/third_party/WebKit/Source/platform/RuntimeEnabledFeatures.in b/third_party/WebKit/Source/platform/RuntimeEnabledFeatures.in
index fbdd9688..5b82500 100644
--- a/third_party/WebKit/Source/platform/RuntimeEnabledFeatures.in
+++ b/third_party/WebKit/Source/platform/RuntimeEnabledFeatures.in
@@ -144,7 +144,8 @@
 MediaConstraints status=stable
 MediaDocumentDownloadButton
 MediaGetSettings status=test
-MediaSession status=experimental
+// MediaSession is enabled by default on Android only.
+MediaSession status=test
 MediaSourceExperimental status=experimental
 MediaSourceNewAbortAndDuration status=experimental
 MediaStreamSpeech status=experimental
diff --git a/third_party/WebKit/Source/platform/heap/MarkingVisitorImpl.h b/third_party/WebKit/Source/platform/heap/MarkingVisitorImpl.h
index bd58304..390b3239 100644
--- a/third_party/WebKit/Source/platform/heap/MarkingVisitorImpl.h
+++ b/third_party/WebKit/Source/platform/heap/MarkingVisitorImpl.h
@@ -87,18 +87,16 @@
 #endif
 
   inline void registerMovingObjectReference(MovableReference* slot) {
-    if (toDerived()->getMarkingMode() !=
-        VisitorMarkingMode::GlobalMarkingWithCompaction)
-      return;
+    DCHECK(toDerived()->getMarkingMode() ==
+           VisitorMarkingMode::GlobalMarkingWithCompaction);
     toDerived()->heap().registerMovingObjectReference(slot);
   }
 
   inline void registerMovingObjectCallback(MovableReference reference,
                                            MovingObjectCallback callback,
                                            void* callbackData) {
-    if (toDerived()->getMarkingMode() !=
-        VisitorMarkingMode::GlobalMarkingWithCompaction)
-      return;
+    DCHECK(toDerived()->getMarkingMode() ==
+           VisitorMarkingMode::GlobalMarkingWithCompaction);
     toDerived()->heap().registerMovingObjectCallback(reference, callback,
                                                      callbackData);
   }
diff --git a/third_party/WebKit/Source/platform/heap/Visitor.h b/third_party/WebKit/Source/platform/heap/Visitor.h
index 3e4b441..0b6129b24 100644
--- a/third_party/WebKit/Source/platform/heap/Visitor.h
+++ b/third_party/WebKit/Source/platform/heap/Visitor.h
@@ -280,16 +280,18 @@
     Derived::fromHelper(this)->registerWeakMembers(object, object, callback);
   }
 
-  template <typename T>
-  void registerBackingStoreReference(T** slot) {
+  void registerBackingStoreReference(void* slot) {
+    if (getMarkingMode() != VisitorMarkingMode::GlobalMarkingWithCompaction)
+      return;
     Derived::fromHelper(this)->registerMovingObjectReference(
         reinterpret_cast<MovableReference*>(slot));
   }
 
-  template <typename T>
-  void registerBackingStoreCallback(T* backingStore,
+  void registerBackingStoreCallback(void* backingStore,
                                     MovingObjectCallback callback,
                                     void* callbackData) {
+    if (getMarkingMode() != VisitorMarkingMode::GlobalMarkingWithCompaction)
+      return;
     Derived::fromHelper(this)->registerMovingObjectCallback(
         reinterpret_cast<MovableReference>(backingStore), callback,
         callbackData);
diff --git a/third_party/WebKit/Source/platform/scheduler/base/real_time_domain.cc b/third_party/WebKit/Source/platform/scheduler/base/real_time_domain.cc
index 80f18b99..789afd3 100644
--- a/third_party/WebKit/Source/platform/scheduler/base/real_time_domain.cc
+++ b/third_party/WebKit/Source/platform/scheduler/base/real_time_domain.cc
@@ -46,23 +46,23 @@
   task_queue_manager_->MaybeScheduleDelayedWork(FROM_HERE, now, delay);
 }
 
-bool RealTimeDomain::MaybeAdvanceTime() {
+base::Optional<base::TimeDelta> RealTimeDomain::DelayTillNextTask(
+    LazyNow* lazy_now) {
   base::TimeTicks next_run_time;
   if (!NextScheduledRunTime(&next_run_time))
-    return false;
+    return base::Optional<base::TimeDelta>();
 
-  base::TimeTicks now = Now();
+  base::TimeTicks now = lazy_now->Now();
   if (now >= next_run_time)
-    return true;  // Causes DoWork to post a continuation.
+    return base::TimeDelta();  // Makes DoWork post an immediate continuation.
 
   base::TimeDelta delay = next_run_time - now;
-  TRACE_EVENT1(tracing_category_, "RealTimeDomain::MaybeAdvanceTime",
+  TRACE_EVENT1(tracing_category_, "RealTimeDomain::DelayTillNextTask",
                "delay_ms", delay.InMillisecondsF());
 
-  // The next task is sometime in the future, make sure we schedule a DoWork to
-  // run it.
-  task_queue_manager_->MaybeScheduleDelayedWork(FROM_HERE, now, delay);
-  return false;
+  // The next task is sometime in the future. DoWork will make sure it gets
+  // run at the right time.
+  return delay;
 }
 
 void RealTimeDomain::AsValueIntoInternal(
diff --git a/third_party/WebKit/Source/platform/scheduler/base/real_time_domain.h b/third_party/WebKit/Source/platform/scheduler/base/real_time_domain.h
index 94d8a59..6883599 100644
--- a/third_party/WebKit/Source/platform/scheduler/base/real_time_domain.h
+++ b/third_party/WebKit/Source/platform/scheduler/base/real_time_domain.h
@@ -23,7 +23,7 @@
   // TimeDomain implementation:
   LazyNow CreateLazyNow() const override;
   base::TimeTicks Now() const override;
-  bool MaybeAdvanceTime() override;
+  base::Optional<base::TimeDelta> DelayTillNextTask(LazyNow* lazy_now) override;
   const char* GetName() const override;
 
  protected:
diff --git a/third_party/WebKit/Source/platform/scheduler/base/task_queue_manager.cc b/third_party/WebKit/Source/platform/scheduler/base/task_queue_manager.cc
index cbfc90c..b2572ae4 100644
--- a/third_party/WebKit/Source/platform/scheduler/base/task_queue_manager.cc
+++ b/third_party/WebKit/Source/platform/scheduler/base/task_queue_manager.cc
@@ -147,15 +147,17 @@
   selector_.RemoveQueue(task_queue.get());
 }
 
-void TaskQueueManager::UpdateWorkQueues(LazyNow lazy_now) {
+void TaskQueueManager::UpdateWorkQueues(LazyNow* lazy_now) {
   TRACE_EVENT0(disabled_by_default_tracing_category_,
                "TaskQueueManager::UpdateWorkQueues");
 
   for (TimeDomain* time_domain : time_domains_) {
-    LazyNow lazy_now_in_domain = time_domain == real_time_domain_.get()
-                                     ? lazy_now
-                                     : time_domain->CreateLazyNow();
-    time_domain->UpdateWorkQueues(lazy_now_in_domain);
+    if (time_domain == real_time_domain_.get()) {
+      time_domain->UpdateWorkQueues(lazy_now);
+    } else {
+      LazyNow time_domain_lazy_now = time_domain->CreateLazyNow();
+      time_domain->UpdateWorkQueues(&time_domain_lazy_now);
+    }
   }
 }
 
@@ -232,14 +234,15 @@
     queues_to_delete_.clear();
 
   LazyNow lazy_now(real_time_domain()->CreateLazyNow());
-  UpdateWorkQueues(lazy_now);
+  UpdateWorkQueues(&lazy_now);
 
   for (int i = 0; i < work_batch_size_; i++) {
     internal::WorkQueue* work_queue;
     if (!SelectWorkQueueToService(&work_queue))
       break;
 
-    switch (ProcessTaskFromWorkQueue(work_queue, &lazy_now)) {
+    base::TimeTicks time_after_task;
+    switch (ProcessTaskFromWorkQueue(work_queue, lazy_now, &time_after_task)) {
       case ProcessTaskResult::DEFERRED:
         // If a task was deferred, try again with another task.
         continue;
@@ -251,7 +254,9 @@
 
     work_queue = nullptr;  // The queue may have been unregistered.
 
-    UpdateWorkQueues(lazy_now);
+    lazy_now = time_after_task.is_null() ? real_time_domain()->CreateLazyNow()
+                                         : LazyNow(time_after_task);
+    UpdateWorkQueues(&lazy_now);
 
     // Only run a single task per batch in nested run loops so that we can
     // properly exit the nested loop when someone calls RunLoop::Quit().
@@ -264,16 +269,38 @@
   // TODO(alexclarke): Consider refactoring the above loop to terminate only
   // when there's no more work left to be done, rather than posting a
   // continuation task.
-  if (!selector_.EnabledWorkQueuesEmpty() || TryAdvanceTimeDomains())
+  base::Optional<base::TimeDelta> next_delay =
+      ComputeDelayTillNextTask(&lazy_now);
+
+  if (!next_delay)
+    return;
+
+  base::TimeDelta delay = next_delay.value();
+  if (delay.is_zero()) {
     MaybeScheduleImmediateWork(FROM_HERE);
+  } else {
+    MaybeScheduleDelayedWork(FROM_HERE, lazy_now.Now(), delay);
+  }
 }
 
-bool TaskQueueManager::TryAdvanceTimeDomains() {
-  bool can_advance = false;
+base::Optional<base::TimeDelta> TaskQueueManager::ComputeDelayTillNextTask(
+    LazyNow* lazy_now) {
+  // If the selector has non-empty queues we trivially know there is immediate
+  // work to be done.
+  if (!selector_.EnabledWorkQueuesEmpty())
+    return base::TimeDelta();
+
+  // Otherwise we need to find the shortest delay, if any.
+  base::Optional<base::TimeDelta> next_continuation;
   for (TimeDomain* time_domain : time_domains_) {
-    can_advance |= time_domain->MaybeAdvanceTime();
+    base::Optional<base::TimeDelta> continuation =
+        time_domain->DelayTillNextTask(lazy_now);
+    if (!continuation)
+      continue;
+    if (!next_continuation || next_continuation.value() > continuation.value())
+      next_continuation = continuation;
   }
-  return can_advance;
+  return next_continuation;
 }
 
 bool TaskQueueManager::SelectWorkQueueToService(
@@ -292,7 +319,8 @@
 
 TaskQueueManager::ProcessTaskResult TaskQueueManager::ProcessTaskFromWorkQueue(
     internal::WorkQueue* work_queue,
-    LazyNow* lazy_now) {
+    LazyNow time_before_task,
+    base::TimeTicks* time_after_task) {
   DCHECK(main_thread_checker_.CalledOnValidThread());
   scoped_refptr<DeletionSentinel> protect(deletion_sentinel_);
   internal::TaskQueueImpl::Task pending_task =
@@ -332,7 +360,7 @@
     bool notify_time_observers =
         !delegate_->IsNested() && task_time_observers_.might_have_observers();
     if (notify_time_observers) {
-      task_start_time = MonotonicTimeInSeconds(lazy_now->Now());
+      task_start_time = MonotonicTimeInSeconds(time_before_task.Now());
       for (auto& observer : task_time_observers_)
         observer.willProcessTask(queue, task_start_time);
     }
@@ -354,11 +382,11 @@
 
   currently_executing_task_queue_ = prev_executing_task_queue;
 
-  *lazy_now = real_time_domain()->CreateLazyNow();
 
   if (queue->GetShouldNotifyObservers()) {
     if (task_start_time) {
-      double task_end_time = MonotonicTimeInSeconds(lazy_now->Now());
+      *time_after_task = real_time_domain()->Now();
+      double task_end_time = MonotonicTimeInSeconds(*time_after_task);
       for (auto& observer : task_time_observers_)
         observer.didProcessTask(queue, task_start_time, task_end_time);
     }
@@ -409,7 +437,8 @@
   task_observers_.RemoveObserver(task_observer);
 }
 
-void TaskQueueManager::AddTaskTimeObserver(TaskTimeObserver* task_time_observer) {
+void TaskQueueManager::AddTaskTimeObserver(
+    TaskTimeObserver* task_time_observer) {
   DCHECK(main_thread_checker_.CalledOnValidThread());
   task_time_observers_.AddObserver(task_time_observer);
 }
diff --git a/third_party/WebKit/Source/platform/scheduler/base/task_queue_manager.h b/third_party/WebKit/Source/platform/scheduler/base/task_queue_manager.h
index 53b9560..37c331f 100644
--- a/third_party/WebKit/Source/platform/scheduler/base/task_queue_manager.h
+++ b/third_party/WebKit/Source/platform/scheduler/base/task_queue_manager.h
@@ -176,23 +176,27 @@
 
   // Delayed Tasks with run_times <= Now() are enqueued onto the work queue and
   // reloads any empty work queues.
-  void UpdateWorkQueues(LazyNow lazy_now);
+  void UpdateWorkQueues(LazyNow* lazy_now);
 
   // Chooses the next work queue to service. Returns true if |out_queue|
   // indicates the queue from which the next task should be run, false to
   // avoid running any tasks.
   bool SelectWorkQueueToService(internal::WorkQueue** out_work_queue);
 
-  // Runs a single nestable task from the |queue|. On exit, |out_task| will
-  // contain the task which was executed. Non-nestable task are reposted on the
-  // run loop. The queue must not be empty.
   enum class ProcessTaskResult {
     DEFERRED,
     EXECUTED,
     TASK_QUEUE_MANAGER_DELETED
   };
+
+  // Runs a single nestable task from the |queue|. On exit, |out_task| will
+  // contain the task which was executed. Non-nestable task are reposted on the
+  // run loop. The queue must not be empty.  On exit |time_after_task| may get
+  // set (not guaranteed), sampling |real_time_domain()->Now()| immediately
+  // after running the task.
   ProcessTaskResult ProcessTaskFromWorkQueue(internal::WorkQueue* work_queue,
-                                             LazyNow*);
+                                             LazyNow time_before_task,
+                                             base::TimeTicks* time_after_task);
 
   bool RunsTasksOnCurrentThread() const;
   bool PostNonNestableDelayedTask(const tracked_objects::Location& from_here,
@@ -201,9 +205,9 @@
 
   internal::EnqueueOrder GetNextSequenceNumber();
 
-  // Calls MaybeAdvanceTime on all time domains and returns true if one of them
-  // was able to advance.
-  bool TryAdvanceTimeDomains();
+  // Calls DelayTillNextTask on all time domains and returns the smallest delay
+  // requested if any.
+  base::Optional<base::TimeDelta> ComputeDelayTillNextTask(LazyNow* lazy_now);
 
   void MaybeRecordTaskDelayHistograms(
       const internal::TaskQueueImpl::Task& pending_task,
diff --git a/third_party/WebKit/Source/platform/scheduler/base/task_queue_manager_perftest.cc b/third_party/WebKit/Source/platform/scheduler/base/task_queue_manager_perftest.cc
index b0f03a6..a7f7454 100644
--- a/third_party/WebKit/Source/platform/scheduler/base/task_queue_manager_perftest.cc
+++ b/third_party/WebKit/Source/platform/scheduler/base/task_queue_manager_perftest.cc
@@ -32,13 +32,14 @@
   PerfTestTimeDomain() : VirtualTimeDomain(nullptr, base::TimeTicks::Now()) {}
   ~PerfTestTimeDomain() override {}
 
-  bool MaybeAdvanceTime() override {
+  base::Optional<base::TimeDelta> DelayTillNextTask(
+      LazyNow* lazy_now) override {
     base::TimeTicks run_time;
     if (!NextScheduledRunTime(&run_time))
-      return false;
+      return base::Optional<base::TimeDelta>();
 
     AdvanceTo(run_time);
-    return true;
+    return base::TimeDelta();  // Makes DoWork post an immediate continuation.
   }
 
   void RequestWakeup(base::TimeTicks now, base::TimeDelta delay) override {
diff --git a/third_party/WebKit/Source/platform/scheduler/base/task_queue_manager_unittest.cc b/third_party/WebKit/Source/platform/scheduler/base/task_queue_manager_unittest.cc
index e16b5c6..bbfd517 100644
--- a/third_party/WebKit/Source/platform/scheduler/base/task_queue_manager_unittest.cc
+++ b/third_party/WebKit/Source/platform/scheduler/base/task_queue_manager_unittest.cc
@@ -117,7 +117,13 @@
   }
 
   void UpdateWorkQueues(LazyNow lazy_now) {
+    manager_->UpdateWorkQueues(&lazy_now);
+  }
+
+  base::Optional<base::TimeDelta> ComputeDelayTillNextTask(LazyNow* lazy_now) {
+    // TODO(alexclarke): Remove this once the DoWork refactor lands.
     manager_->UpdateWorkQueues(lazy_now);
+    return manager_->ComputeDelayTillNextTask(lazy_now);
   }
 
   // Runs all immediate tasks until there is no more work to do and advances
@@ -2200,5 +2206,52 @@
   EXPECT_EQ(2u, runners_[0]->GetNumberOfPendingTasks());
 }
 
+TEST_F(TaskQueueManagerTest, ComputeDelayTillNextTask) {
+  Initialize(2u);
+
+  std::unique_ptr<RealTimeDomain> domain2(new RealTimeDomain("test"));
+  manager_->RegisterTimeDomain(domain2.get());
+  runners_[1]->SetTimeDomain(domain2.get());
+
+  LazyNow lazy_now(now_src_.get());
+  EXPECT_FALSE(static_cast<bool>(ComputeDelayTillNextTask(&lazy_now)));
+
+  runners_[0]->PostDelayedTask(FROM_HERE, base::Bind(&NopTask),
+                               base::TimeDelta::FromSeconds(10));
+
+  EXPECT_EQ(base::TimeDelta::FromSeconds(10),
+            ComputeDelayTillNextTask(&lazy_now).value());
+
+  runners_[1]->PostDelayedTask(FROM_HERE, base::Bind(&NopTask),
+                               base::TimeDelta::FromSeconds(15));
+
+  EXPECT_EQ(base::TimeDelta::FromSeconds(10),
+            ComputeDelayTillNextTask(&lazy_now).value());
+
+  runners_[1]->PostDelayedTask(FROM_HERE, base::Bind(&NopTask),
+                               base::TimeDelta::FromSeconds(5));
+
+  EXPECT_EQ(base::TimeDelta::FromSeconds(5),
+            ComputeDelayTillNextTask(&lazy_now).value());
+
+  runners_[0]->PostTask(FROM_HERE, base::Bind(&NopTask));
+
+  EXPECT_EQ(base::TimeDelta(), ComputeDelayTillNextTask(&lazy_now).value());
+
+  // Tidy up.
+  runners_[1]->UnregisterTaskQueue();
+  manager_->UnregisterTimeDomain(domain2.get());
+}
+
+TEST_F(TaskQueueManagerTest, ComputeDelayTillNextTask_TaskBlocked) {
+  Initialize(1u);
+
+  runners_[0]->InsertFence(TaskQueue::InsertFencePosition::NOW);
+  runners_[0]->PostTask(FROM_HERE, base::Bind(&NopTask));
+
+  LazyNow lazy_now(now_src_.get());
+  EXPECT_FALSE(ComputeDelayTillNextTask(&lazy_now));
+}
+
 }  // namespace scheduler
 }  // namespace blink
diff --git a/third_party/WebKit/Source/platform/scheduler/base/time_domain.cc b/third_party/WebKit/Source/platform/scheduler/base/time_domain.cc
index 25d0caf..e55d7fe 100644
--- a/third_party/WebKit/Source/platform/scheduler/base/time_domain.cc
+++ b/third_party/WebKit/Source/platform/scheduler/base/time_domain.cc
@@ -117,11 +117,11 @@
     observer_->OnTimeDomainHasImmediateWork(queue);
 }
 
-void TimeDomain::UpdateWorkQueues(LazyNow lazy_now) {
+void TimeDomain::UpdateWorkQueues(LazyNow* lazy_now) {
   DCHECK(main_thread_checker_.CalledOnValidThread());
 
   // Move any ready delayed tasks into the Incoming queues.
-  WakeupReadyDelayedQueues(&lazy_now);
+  WakeupReadyDelayedQueues(lazy_now);
 
   std::set<internal::TaskQueueImpl*> queues_to_reload_if_empty;
 
diff --git a/third_party/WebKit/Source/platform/scheduler/base/time_domain.h b/third_party/WebKit/Source/platform/scheduler/base/time_domain.h
index f7f31b0..13914bd 100644
--- a/third_party/WebKit/Source/platform/scheduler/base/time_domain.h
+++ b/third_party/WebKit/Source/platform/scheduler/base/time_domain.h
@@ -62,9 +62,12 @@
   // Evaluate this TimeDomain's Now. Can be called from any thread.
   virtual base::TimeTicks Now() const = 0;
 
-  // Some TimeDomains support virtual time, this method tells us to advance time
-  // if possible and return true if time was advanced.
-  virtual bool MaybeAdvanceTime() = 0;
+  // Computes the delay until the next task the TimeDomain is aware of, if any.
+  // Note virtual time domains may return base::TimeDelta() if they have any
+  // delayed tasks they deem eligible to run.  Virtual time domains are allowed
+  // to advance their internal clock when this method is called.
+  virtual base::Optional<base::TimeDelta> DelayTillNextTask(
+      LazyNow* lazy_now) = 0;
 
   // Returns the name of this time domain for tracing.
   virtual const char* GetName() const = 0;
@@ -108,7 +111,7 @@
   void UnregisterQueue(internal::TaskQueueImpl* queue);
 
   // Updates active queues associated with this TimeDomain.
-  void UpdateWorkQueues(LazyNow lazy_now);
+  void UpdateWorkQueues(LazyNow* lazy_now);
 
   // Called by the TaskQueueManager when the TimeDomain is registered.
   virtual void OnRegisterWithTaskQueueManager(
diff --git a/third_party/WebKit/Source/platform/scheduler/base/time_domain_unittest.cc b/third_party/WebKit/Source/platform/scheduler/base/time_domain_unittest.cc
index 7a5e35e..413c64a 100644
--- a/third_party/WebKit/Source/platform/scheduler/base/time_domain_unittest.cc
+++ b/third_party/WebKit/Source/platform/scheduler/base/time_domain_unittest.cc
@@ -44,7 +44,10 @@
   void AsValueIntoInternal(
       base::trace_event::TracedValue* state) const override {}
 
-  bool MaybeAdvanceTime() override { return false; }
+  base::Optional<base::TimeDelta> DelayTillNextTask(
+      LazyNow* lazy_now) override {
+    return base::Optional<base::TimeDelta>();
+  }
   const char* GetName() const override { return "Test"; }
   void OnRegisterWithTaskQueueManager(
       TaskQueueManager* task_queue_manager) override {}
@@ -203,13 +206,13 @@
   EXPECT_EQ(delayed_runtime, next_run_time);
 
   LazyNow lazy_now = time_domain_->CreateLazyNow();
-  time_domain_->UpdateWorkQueues(lazy_now);
+  time_domain_->UpdateWorkQueues(&lazy_now);
   ASSERT_TRUE(time_domain_->NextScheduledRunTime(&next_run_time));
   EXPECT_EQ(delayed_runtime, next_run_time);
 
   time_domain_->SetNow(delayed_runtime);
   lazy_now = time_domain_->CreateLazyNow();
-  time_domain_->UpdateWorkQueues(lazy_now);
+  time_domain_->UpdateWorkQueues(&lazy_now);
   ASSERT_FALSE(time_domain_->NextScheduledRunTime(&next_run_time));
 }
 
diff --git a/third_party/WebKit/Source/platform/scheduler/base/virtual_time_domain.cc b/third_party/WebKit/Source/platform/scheduler/base/virtual_time_domain.cc
index a22796c5d..f40c6307 100644
--- a/third_party/WebKit/Source/platform/scheduler/base/virtual_time_domain.cc
+++ b/third_party/WebKit/Source/platform/scheduler/base/virtual_time_domain.cc
@@ -41,8 +41,9 @@
   // needed.
 }
 
-bool VirtualTimeDomain::MaybeAdvanceTime() {
-  return false;
+base::Optional<base::TimeDelta> VirtualTimeDomain::DelayTillNextTask(
+    LazyNow* lazy_now) {
+  return base::Optional<base::TimeDelta>();
 }
 
 void VirtualTimeDomain::AsValueIntoInternal(
diff --git a/third_party/WebKit/Source/platform/scheduler/base/virtual_time_domain.h b/third_party/WebKit/Source/platform/scheduler/base/virtual_time_domain.h
index 715948d..a841226 100644
--- a/third_party/WebKit/Source/platform/scheduler/base/virtual_time_domain.h
+++ b/third_party/WebKit/Source/platform/scheduler/base/virtual_time_domain.h
@@ -21,7 +21,7 @@
   // TimeDomain implementation:
   LazyNow CreateLazyNow() const override;
   base::TimeTicks Now() const override;
-  bool MaybeAdvanceTime() override;
+  base::Optional<base::TimeDelta> DelayTillNextTask(LazyNow* lazy_now) override;
   const char* GetName() const override;
 
   // Advances this time domain to |now|. NOTE |now| is supposed to be
diff --git a/third_party/WebKit/Source/platform/scheduler/renderer/auto_advancing_virtual_time_domain.cc b/third_party/WebKit/Source/platform/scheduler/renderer/auto_advancing_virtual_time_domain.cc
index a34edb215..455a0c2d 100644
--- a/third_party/WebKit/Source/platform/scheduler/renderer/auto_advancing_virtual_time_domain.cc
+++ b/third_party/WebKit/Source/platform/scheduler/renderer/auto_advancing_virtual_time_domain.cc
@@ -14,13 +14,14 @@
 
 AutoAdvancingVirtualTimeDomain::~AutoAdvancingVirtualTimeDomain() {}
 
-bool AutoAdvancingVirtualTimeDomain::MaybeAdvanceTime() {
+base::Optional<base::TimeDelta>
+AutoAdvancingVirtualTimeDomain::DelayTillNextTask(LazyNow* lazy_now) {
   base::TimeTicks run_time;
-  if (!can_advance_virtual_time_ || !NextScheduledRunTime(&run_time)) {
-    return false;
-  }
+  if (!can_advance_virtual_time_ || !NextScheduledRunTime(&run_time))
+    return base::Optional<base::TimeDelta>();
+
   AdvanceTo(run_time);
-  return true;
+  return base::TimeDelta();  // Makes DoWork post an immediate continuation.
 }
 
 void AutoAdvancingVirtualTimeDomain::RequestWakeup(base::TimeTicks now,
diff --git a/third_party/WebKit/Source/platform/scheduler/renderer/auto_advancing_virtual_time_domain.h b/third_party/WebKit/Source/platform/scheduler/renderer/auto_advancing_virtual_time_domain.h
index ffd880e..0ca186d 100644
--- a/third_party/WebKit/Source/platform/scheduler/renderer/auto_advancing_virtual_time_domain.h
+++ b/third_party/WebKit/Source/platform/scheduler/renderer/auto_advancing_virtual_time_domain.h
@@ -27,7 +27,7 @@
   ~AutoAdvancingVirtualTimeDomain() override;
 
   // TimeDomain implementation:
-  bool MaybeAdvanceTime() override;
+  base::Optional<base::TimeDelta> DelayTillNextTask(LazyNow* lazy_now) override;
   void RequestWakeup(base::TimeTicks now, base::TimeDelta delay) override;
   const char* GetName() const override;
 
diff --git a/third_party/WebKit/Source/platform/scheduler/renderer/throttled_time_domain.cc b/third_party/WebKit/Source/platform/scheduler/renderer/throttled_time_domain.cc
index 8f6887c..f81ad15 100644
--- a/third_party/WebKit/Source/platform/scheduler/renderer/throttled_time_domain.cc
+++ b/third_party/WebKit/Source/platform/scheduler/renderer/throttled_time_domain.cc
@@ -23,19 +23,19 @@
   // behalf.
 }
 
-bool ThrottledTimeDomain::MaybeAdvanceTime() {
+base::Optional<base::TimeDelta> ThrottledTimeDomain::DelayTillNextTask(
+    LazyNow* lazy_now) {
   base::TimeTicks next_run_time;
   if (!NextScheduledRunTime(&next_run_time))
-    return false;
+    return base::Optional<base::TimeDelta>();
 
-  base::TimeTicks now = Now();
+  base::TimeTicks now = lazy_now->Now();
   if (now >= next_run_time)
-    return true;  // Causes DoWork to post a continuation.
+    return base::TimeDelta();  // Makes DoWork post an immediate continuation.
 
-  // Unlike RealTimeDomain::MaybeAdvanceTime we don't request a wake up here, we
-  // assume the owner (i.e. TaskQueueThrottler) will manage wakeups on our
+  // We assume the owner (i.e. TaskQueueThrottler) will manage wakeups on our
   // behalf.
-  return false;
+  return base::Optional<base::TimeDelta>();
 }
 
 }  // namespace scheduler
diff --git a/third_party/WebKit/Source/platform/scheduler/renderer/throttled_time_domain.h b/third_party/WebKit/Source/platform/scheduler/renderer/throttled_time_domain.h
index ba59a6c2..c9d73fa 100644
--- a/third_party/WebKit/Source/platform/scheduler/renderer/throttled_time_domain.h
+++ b/third_party/WebKit/Source/platform/scheduler/renderer/throttled_time_domain.h
@@ -22,7 +22,7 @@
   // TimeDomain implementation:
   const char* GetName() const override;
   void RequestWakeup(base::TimeTicks now, base::TimeDelta delay) override;
-  bool MaybeAdvanceTime() override;
+  base::Optional<base::TimeDelta> DelayTillNextTask(LazyNow* lazy_now) override;
 
   using TimeDomain::WakeupReadyDelayedQueues;
 
diff --git a/third_party/WebKit/Source/web/WebEmbeddedWorkerImpl.cpp b/third_party/WebKit/Source/web/WebEmbeddedWorkerImpl.cpp
index 8a51606..dbc9cc1 100644
--- a/third_party/WebKit/Source/web/WebEmbeddedWorkerImpl.cpp
+++ b/third_party/WebKit/Source/web/WebEmbeddedWorkerImpl.cpp
@@ -274,7 +274,7 @@
 
 void WebEmbeddedWorkerImpl::postTaskToWorkerGlobalScope(
     const WebTraceLocation& location,
-    std::unique_ptr<ExecutionContextTask> task) {
+    std::unique_ptr<WTF::CrossThreadClosure> task) {
   if (m_askedToTerminate || !m_workerThread)
     return;
   m_workerThread->postTask(location, std::move(task));
diff --git a/third_party/WebKit/Source/web/WebEmbeddedWorkerImpl.h b/third_party/WebKit/Source/web/WebEmbeddedWorkerImpl.h
index 0d7db6f..7129571 100644
--- a/third_party/WebKit/Source/web/WebEmbeddedWorkerImpl.h
+++ b/third_party/WebKit/Source/web/WebEmbeddedWorkerImpl.h
@@ -105,7 +105,7 @@
                         std::unique_ptr<ExecutionContextTask>) override;
   void postTaskToWorkerGlobalScope(
       const WebTraceLocation&,
-      std::unique_ptr<ExecutionContextTask>) override;
+      std::unique_ptr<WTF::CrossThreadClosure>) override;
 
   WebEmbeddedWorkerStartData m_workerStartData;
 
diff --git a/third_party/WebKit/Source/web/WebInputEvent.cpp b/third_party/WebKit/Source/web/WebInputEvent.cpp
index ac01696..ddcba63 100644
--- a/third_party/WebKit/Source/web/WebInputEvent.cpp
+++ b/third_party/WebKit/Source/web/WebInputEvent.cpp
@@ -49,7 +49,7 @@
 };
 
 struct SameSizeAsWebMouseEvent : public SameSizeAsWebInputEvent {
-  int mouseData[15];
+  int mouseData[17];
 };
 
 struct SameSizeAsWebMouseWheelEvent : public SameSizeAsWebMouseEvent {
diff --git a/third_party/WebKit/Source/web/WebSharedWorkerImpl.cpp b/third_party/WebKit/Source/web/WebSharedWorkerImpl.cpp
index 7686ed7..3dc90bd 100644
--- a/third_party/WebKit/Source/web/WebSharedWorkerImpl.cpp
+++ b/third_party/WebKit/Source/web/WebSharedWorkerImpl.cpp
@@ -317,7 +317,7 @@
 
 void WebSharedWorkerImpl::postTaskToWorkerGlobalScope(
     const WebTraceLocation& location,
-    std::unique_ptr<ExecutionContextTask> task) {
+    std::unique_ptr<WTF::CrossThreadClosure> task) {
   m_workerThread->postTask(location, std::move(task));
 }
 
diff --git a/third_party/WebKit/Source/web/WebSharedWorkerImpl.h b/third_party/WebKit/Source/web/WebSharedWorkerImpl.h
index e7c13ae7..7ae7fe5 100644
--- a/third_party/WebKit/Source/web/WebSharedWorkerImpl.h
+++ b/third_party/WebKit/Source/web/WebSharedWorkerImpl.h
@@ -156,7 +156,7 @@
                         std::unique_ptr<ExecutionContextTask>) override;
   void postTaskToWorkerGlobalScope(
       const WebTraceLocation&,
-      std::unique_ptr<ExecutionContextTask>) override;
+      std::unique_ptr<WTF::CrossThreadClosure>) override;
 
   // 'shadow page' - created to proxy loading requests from the worker.
   Persistent<ExecutionContext> m_loadingDocument;
diff --git a/third_party/WebKit/public/platform/WebPointerProperties.h b/third_party/WebKit/public/platform/WebPointerProperties.h
index 0373dac..86f29600 100644
--- a/third_party/WebKit/public/platform/WebPointerProperties.h
+++ b/third_party/WebKit/public/platform/WebPointerProperties.h
@@ -22,6 +22,8 @@
         force(std::numeric_limits<float>::quiet_NaN()),
         tiltX(0),
         tiltY(0),
+        tangentialPressure(0.0f),
+        twist(0),
         button(Button::NoButton),
         pointerType(PointerType::Unknown) {}
 
@@ -58,6 +60,16 @@
   int tiltX;
   int tiltY;
 
+  // The normalized tangential pressure (or barrel pressure), typically set by
+  // an additional control of the stylus, which has a range of [-1,1], where 0
+  // is the neutral position of the control. Always 0 if the device does not
+  // support it.
+  float tangentialPressure;
+
+  // The clockwise rotation of a pen stylus around its own major axis, in
+  // degrees in the range [0,359]. Always 0 if the device does not support it.
+  int twist;
+
   Button button;
   PointerType pointerType;
 };
diff --git a/third_party/blimp_fonts/.gitignore b/third_party/blimp_fonts/.gitignore
deleted file mode 100644
index dfa02a1..0000000
--- a/third_party/blimp_fonts/.gitignore
+++ /dev/null
@@ -1,2 +0,0 @@
-font_bundle/
-font_bundle.tar.gz
diff --git a/third_party/blimp_fonts/BUILD.gn b/third_party/blimp_fonts/BUILD.gn
deleted file mode 100644
index 9ca01a85..0000000
--- a/third_party/blimp_fonts/BUILD.gn
+++ /dev/null
@@ -1,304 +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.
-
-copy("blimp_fonts") {
-  sources = [
-    "LICENSE",
-    "LICENSE.Apache",
-    "LICENSE.OFL",
-    "font_bundle/kitkat/AndroidClock.ttf",
-    "font_bundle/kitkat/AndroidClock_Highlight.ttf",
-    "font_bundle/kitkat/AndroidClock_Solid.ttf",
-    "font_bundle/kitkat/AndroidEmoji.ttf",
-    "font_bundle/kitkat/Clockopia.ttf",
-    "font_bundle/kitkat/DroidKufi-Bold.ttf",
-    "font_bundle/kitkat/DroidKufi-Regular.ttf",
-    "font_bundle/kitkat/DroidNaskh-Bold.ttf",
-    "font_bundle/kitkat/DroidNaskh-Regular.ttf",
-    "font_bundle/kitkat/DroidNaskhUI-Regular.ttf",
-    "font_bundle/kitkat/DroidSans-Bold.ttf",
-    "font_bundle/kitkat/DroidSans.ttf",
-    "font_bundle/kitkat/DroidSansArabic.ttf",
-    "font_bundle/kitkat/DroidSansArmenian.ttf",
-    "font_bundle/kitkat/DroidSansEthiopic-Bold.ttf",
-    "font_bundle/kitkat/DroidSansEthiopic-Regular.ttf",
-    "font_bundle/kitkat/DroidSansFallback.ttf",
-    "font_bundle/kitkat/DroidSansFallbackFull.ttf",
-    "font_bundle/kitkat/DroidSansFallbackLegacy.ttf",
-    "font_bundle/kitkat/DroidSansGeorgian.ttf",
-    "font_bundle/kitkat/DroidSansHebrew-Bold.ttf",
-    "font_bundle/kitkat/DroidSansHebrew-Regular.ttf",
-    "font_bundle/kitkat/DroidSansJapanese.ttf",
-    "font_bundle/kitkat/DroidSansMono.ttf",
-    "font_bundle/kitkat/DroidSerif-Bold.ttf",
-    "font_bundle/kitkat/DroidSerif-BoldItalic.ttf",
-    "font_bundle/kitkat/DroidSerif-Italic.ttf",
-    "font_bundle/kitkat/DroidSerif-Regular.ttf",
-    "font_bundle/kitkat/MTLc3m.ttf",
-    "font_bundle/kitkat/MTLmr3m.ttf",
-    "font_bundle/kitkat/NanumGothic.ttf",
-    "font_bundle/kitkat/NanumGothicBold.ttf",
-    "font_bundle/kitkat/NotoColorEmoji.ttf",
-    "font_bundle/kitkat/NotoSansBengali-Bold.ttf",
-    "font_bundle/kitkat/NotoSansBengali-Regular.ttf",
-    "font_bundle/kitkat/NotoSansBengaliUI-Bold.ttf",
-    "font_bundle/kitkat/NotoSansBengaliUI-Regular.ttf",
-    "font_bundle/kitkat/NotoSansDevanagari-Bold.ttf",
-    "font_bundle/kitkat/NotoSansDevanagari-Regular.ttf",
-    "font_bundle/kitkat/NotoSansDevanagariUI-Bold.ttf",
-    "font_bundle/kitkat/NotoSansDevanagariUI-Regular.ttf",
-    "font_bundle/kitkat/NotoSansKannada-Bold.ttf",
-    "font_bundle/kitkat/NotoSansKannada-Regular.ttf",
-    "font_bundle/kitkat/NotoSansKannadaUI-Bold.ttf",
-    "font_bundle/kitkat/NotoSansKannadaUI-Regular.ttf",
-    "font_bundle/kitkat/NotoSansKhmer-Bold.ttf",
-    "font_bundle/kitkat/NotoSansKhmer-Regular.ttf",
-    "font_bundle/kitkat/NotoSansKhmerUI-Bold.ttf",
-    "font_bundle/kitkat/NotoSansKhmerUI-Regular.ttf",
-    "font_bundle/kitkat/NotoSansLao-Bold.ttf",
-    "font_bundle/kitkat/NotoSansLao-Regular.ttf",
-    "font_bundle/kitkat/NotoSansLaoUI-Bold.ttf",
-    "font_bundle/kitkat/NotoSansLaoUI-Regular.ttf",
-    "font_bundle/kitkat/NotoSansMalayalam-Bold.ttf",
-    "font_bundle/kitkat/NotoSansMalayalam-Regular.ttf",
-    "font_bundle/kitkat/NotoSansMalayalamUI-Bold.ttf",
-    "font_bundle/kitkat/NotoSansMalayalamUI-Regular.ttf",
-    "font_bundle/kitkat/NotoSansSymbols-Regular.ttf",
-    "font_bundle/kitkat/NotoSansTamil-Bold.ttf",
-    "font_bundle/kitkat/NotoSansTamil-Regular.ttf",
-    "font_bundle/kitkat/NotoSansTamilUI-Bold.ttf",
-    "font_bundle/kitkat/NotoSansTamilUI-Regular.ttf",
-    "font_bundle/kitkat/NotoSansTelugu-Bold.ttf",
-    "font_bundle/kitkat/NotoSansTelugu-Regular.ttf",
-    "font_bundle/kitkat/NotoSansTeluguUI-Bold.ttf",
-    "font_bundle/kitkat/NotoSansTeluguUI-Regular.ttf",
-    "font_bundle/kitkat/NotoSansThai-Bold.ttf",
-    "font_bundle/kitkat/NotoSansThai-Regular.ttf",
-    "font_bundle/kitkat/NotoSansThaiUI-Bold.ttf",
-    "font_bundle/kitkat/NotoSansThaiUI-Regular.ttf",
-    "font_bundle/kitkat/Padauk-book.ttf",
-    "font_bundle/kitkat/Padauk-bookbold.ttf",
-    "font_bundle/kitkat/Roboto-Bold.ttf",
-    "font_bundle/kitkat/Roboto-BoldItalic.ttf",
-    "font_bundle/kitkat/Roboto-Italic.ttf",
-    "font_bundle/kitkat/Roboto-Light.ttf",
-    "font_bundle/kitkat/Roboto-LightItalic.ttf",
-    "font_bundle/kitkat/Roboto-Regular.ttf",
-    "font_bundle/kitkat/Roboto-Thin.ttf",
-    "font_bundle/kitkat/Roboto-ThinItalic.ttf",
-    "font_bundle/kitkat/RobotoCondensed-Bold.ttf",
-    "font_bundle/kitkat/RobotoCondensed-BoldItalic.ttf",
-    "font_bundle/kitkat/RobotoCondensed-Italic.ttf",
-    "font_bundle/kitkat/RobotoCondensed-Regular.ttf",
-    "font_bundle/kitkat/fallback_fonts.xml",
-    "font_bundle/kitkat/system_fonts.xml",
-    "font_bundle/kitkat/vendor_fonts.xml",
-    "font_bundle/marshmallow/AndroidClock.ttf",
-    "font_bundle/marshmallow/AndroidClock_Highlight.ttf",
-    "font_bundle/marshmallow/AndroidClock_Solid.ttf",
-    "font_bundle/marshmallow/CarroisGothicSC-Regular.ttf",
-    "font_bundle/marshmallow/Clockopia.ttf",
-    "font_bundle/marshmallow/ComingSoon.ttf",
-    "font_bundle/marshmallow/CutiveMono.ttf",
-    "font_bundle/marshmallow/DancingScript-Bold.ttf",
-    "font_bundle/marshmallow/DancingScript-Regular.ttf",
-    "font_bundle/marshmallow/DroidSansFallback.ttf",
-    "font_bundle/marshmallow/DroidSansFallbackFull.ttf",
-    "font_bundle/marshmallow/DroidSansMono.ttf",
-    "font_bundle/marshmallow/MTLc3m.ttf",
-    "font_bundle/marshmallow/MTLmr3m.ttf",
-    "font_bundle/marshmallow/NanumGothic.ttf",
-    "font_bundle/marshmallow/NanumGothicBold.ttf",
-    "font_bundle/marshmallow/NotoColorEmoji.ttf",
-    "font_bundle/marshmallow/NotoKufiArabic-Bold.ttf",
-    "font_bundle/marshmallow/NotoKufiArabic-Regular.ttf",
-    "font_bundle/marshmallow/NotoNaskhArabic-Bold.ttf",
-    "font_bundle/marshmallow/NotoNaskhArabic-Regular.ttf",
-    "font_bundle/marshmallow/NotoNaskhArabicUI-Bold.ttf",
-    "font_bundle/marshmallow/NotoNaskhArabicUI-Regular.ttf",
-    "font_bundle/marshmallow/NotoSans-Bold.ttf",
-    "font_bundle/marshmallow/NotoSans-BoldItalic.ttf",
-    "font_bundle/marshmallow/NotoSans-Italic.ttf",
-    "font_bundle/marshmallow/NotoSans-Regular.ttf",
-    "font_bundle/marshmallow/NotoSansArmenian-Bold.ttf",
-    "font_bundle/marshmallow/NotoSansArmenian-Regular.ttf",
-    "font_bundle/marshmallow/NotoSansAvestan-Regular.ttf",
-    "font_bundle/marshmallow/NotoSansBalinese-Regular.ttf",
-    "font_bundle/marshmallow/NotoSansBamum-Regular.ttf",
-    "font_bundle/marshmallow/NotoSansBatak-Regular.ttf",
-    "font_bundle/marshmallow/NotoSansBengali-Bold.ttf",
-    "font_bundle/marshmallow/NotoSansBengali-Regular.ttf",
-    "font_bundle/marshmallow/NotoSansBengaliUI-Bold.ttf",
-    "font_bundle/marshmallow/NotoSansBengaliUI-Regular.ttf",
-    "font_bundle/marshmallow/NotoSansBrahmi-Regular.ttf",
-    "font_bundle/marshmallow/NotoSansBuginese-Regular.ttf",
-    "font_bundle/marshmallow/NotoSansBuhid-Regular.ttf",
-    "font_bundle/marshmallow/NotoSansCanadianAboriginal-Regular.ttf",
-    "font_bundle/marshmallow/NotoSansCarian-Regular.ttf",
-    "font_bundle/marshmallow/NotoSansCham-Bold.ttf",
-    "font_bundle/marshmallow/NotoSansCham-Regular.ttf",
-    "font_bundle/marshmallow/NotoSansCherokee-Regular.ttf",
-    "font_bundle/marshmallow/NotoSansCoptic-Regular.ttf",
-    "font_bundle/marshmallow/NotoSansCuneiform-Regular.ttf",
-    "font_bundle/marshmallow/NotoSansCypriot-Regular.ttf",
-    "font_bundle/marshmallow/NotoSansDeseret-Regular.ttf",
-    "font_bundle/marshmallow/NotoSansDevanagari-Bold.ttf",
-    "font_bundle/marshmallow/NotoSansDevanagari-Regular.ttf",
-    "font_bundle/marshmallow/NotoSansDevanagariUI-Bold.ttf",
-    "font_bundle/marshmallow/NotoSansDevanagariUI-Regular.ttf",
-    "font_bundle/marshmallow/NotoSansEgyptianHieroglyphs-Regular.ttf",
-    "font_bundle/marshmallow/NotoSansEthiopic-Bold.ttf",
-    "font_bundle/marshmallow/NotoSansEthiopic-Regular.ttf",
-    "font_bundle/marshmallow/NotoSansGeorgian-Bold.ttf",
-    "font_bundle/marshmallow/NotoSansGeorgian-Regular.ttf",
-    "font_bundle/marshmallow/NotoSansGlagolitic-Regular.ttf",
-    "font_bundle/marshmallow/NotoSansGothic-Regular.ttf",
-    "font_bundle/marshmallow/NotoSansGujarati-Bold.ttf",
-    "font_bundle/marshmallow/NotoSansGujarati-Regular.ttf",
-    "font_bundle/marshmallow/NotoSansGujaratiUI-Bold.ttf",
-    "font_bundle/marshmallow/NotoSansGujaratiUI-Regular.ttf",
-    "font_bundle/marshmallow/NotoSansGurmukhi-Bold.ttf",
-    "font_bundle/marshmallow/NotoSansGurmukhi-Regular.ttf",
-    "font_bundle/marshmallow/NotoSansGurmukhiUI-Bold.ttf",
-    "font_bundle/marshmallow/NotoSansGurmukhiUI-Regular.ttf",
-    "font_bundle/marshmallow/NotoSansHanunoo-Regular.ttf",
-    "font_bundle/marshmallow/NotoSansHebrew-Bold.ttf",
-    "font_bundle/marshmallow/NotoSansHebrew-Regular.ttf",
-    "font_bundle/marshmallow/NotoSansImperialAramaic-Regular.ttf",
-    "font_bundle/marshmallow/NotoSansInscriptionalPahlavi-Regular.ttf",
-    "font_bundle/marshmallow/NotoSansInscriptionalParthian-Regular.ttf",
-    "font_bundle/marshmallow/NotoSansJP-Regular-Subsetted.otf",
-    "font_bundle/marshmallow/NotoSansJP-Regular.otf",
-    "font_bundle/marshmallow/NotoSansJavanese-Regular.ttf",
-    "font_bundle/marshmallow/NotoSansKR-Regular.otf",
-    "font_bundle/marshmallow/NotoSansKaithi-Regular.ttf",
-    "font_bundle/marshmallow/NotoSansKannada-Bold.ttf",
-    "font_bundle/marshmallow/NotoSansKannada-Regular.ttf",
-    "font_bundle/marshmallow/NotoSansKannadaUI-Bold.ttf",
-    "font_bundle/marshmallow/NotoSansKannadaUI-Regular.ttf",
-    "font_bundle/marshmallow/NotoSansKayahLi-Regular.ttf",
-    "font_bundle/marshmallow/NotoSansKharoshthi-Regular.ttf",
-    "font_bundle/marshmallow/NotoSansKhmer-Bold.ttf",
-    "font_bundle/marshmallow/NotoSansKhmer-Regular.ttf",
-    "font_bundle/marshmallow/NotoSansKhmerUI-Bold.ttf",
-    "font_bundle/marshmallow/NotoSansKhmerUI-Regular.ttf",
-    "font_bundle/marshmallow/NotoSansLao-Bold.ttf",
-    "font_bundle/marshmallow/NotoSansLao-Regular.ttf",
-    "font_bundle/marshmallow/NotoSansLaoUI-Bold.ttf",
-    "font_bundle/marshmallow/NotoSansLaoUI-Regular.ttf",
-    "font_bundle/marshmallow/NotoSansLepcha-Regular.ttf",
-    "font_bundle/marshmallow/NotoSansLimbu-Regular.ttf",
-    "font_bundle/marshmallow/NotoSansLinearB-Regular.ttf",
-    "font_bundle/marshmallow/NotoSansLisu-Regular.ttf",
-    "font_bundle/marshmallow/NotoSansLycian-Regular.ttf",
-    "font_bundle/marshmallow/NotoSansLydian-Regular.ttf",
-    "font_bundle/marshmallow/NotoSansMalayalam-Bold.ttf",
-    "font_bundle/marshmallow/NotoSansMalayalam-Regular.ttf",
-    "font_bundle/marshmallow/NotoSansMalayalamUI-Bold.ttf",
-    "font_bundle/marshmallow/NotoSansMalayalamUI-Regular.ttf",
-    "font_bundle/marshmallow/NotoSansMandaic-Regular.ttf",
-    "font_bundle/marshmallow/NotoSansMeeteiMayek-Regular.ttf",
-    "font_bundle/marshmallow/NotoSansMongolian-Regular.ttf",
-    "font_bundle/marshmallow/NotoSansMyanmar-Bold.ttf",
-    "font_bundle/marshmallow/NotoSansMyanmar-Regular.ttf",
-    "font_bundle/marshmallow/NotoSansMyanmarUI-Bold.ttf",
-    "font_bundle/marshmallow/NotoSansMyanmarUI-Regular.ttf",
-    "font_bundle/marshmallow/NotoSansNKo-Regular.ttf",
-    "font_bundle/marshmallow/NotoSansNewTaiLue-Regular.ttf",
-    "font_bundle/marshmallow/NotoSansOgham-Regular.ttf",
-    "font_bundle/marshmallow/NotoSansOlChiki-Regular.ttf",
-    "font_bundle/marshmallow/NotoSansOldItalic-Regular.ttf",
-    "font_bundle/marshmallow/NotoSansOldPersian-Regular.ttf",
-    "font_bundle/marshmallow/NotoSansOldSouthArabian-Regular.ttf",
-    "font_bundle/marshmallow/NotoSansOldTurkic-Regular.ttf",
-    "font_bundle/marshmallow/NotoSansOriya-Bold.ttf",
-    "font_bundle/marshmallow/NotoSansOriya-Regular.ttf",
-    "font_bundle/marshmallow/NotoSansOriyaUI-Bold.ttf",
-    "font_bundle/marshmallow/NotoSansOriyaUI-Regular.ttf",
-    "font_bundle/marshmallow/NotoSansOsmanya-Regular.ttf",
-    "font_bundle/marshmallow/NotoSansPhagsPa-Regular.ttf",
-    "font_bundle/marshmallow/NotoSansPhoenician-Regular.ttf",
-    "font_bundle/marshmallow/NotoSansRejang-Regular.ttf",
-    "font_bundle/marshmallow/NotoSansRunic-Regular.ttf",
-    "font_bundle/marshmallow/NotoSansSC-Regular.otf",
-    "font_bundle/marshmallow/NotoSansSamaritan-Regular.ttf",
-    "font_bundle/marshmallow/NotoSansSaurashtra-Regular.ttf",
-    "font_bundle/marshmallow/NotoSansShavian-Regular.ttf",
-    "font_bundle/marshmallow/NotoSansSinhala-Bold.ttf",
-    "font_bundle/marshmallow/NotoSansSinhala-Regular.ttf",
-    "font_bundle/marshmallow/NotoSansSundanese-Regular.ttf",
-    "font_bundle/marshmallow/NotoSansSylotiNagri-Regular.ttf",
-    "font_bundle/marshmallow/NotoSansSymbols-Regular-Subsetted.ttf",
-    "font_bundle/marshmallow/NotoSansSymbols-Regular.ttf",
-    "font_bundle/marshmallow/NotoSansSyriacEastern-Regular.ttf",
-    "font_bundle/marshmallow/NotoSansSyriacEstrangela-Regular.ttf",
-    "font_bundle/marshmallow/NotoSansSyriacWestern-Regular.ttf",
-    "font_bundle/marshmallow/NotoSansTC-Regular.otf",
-    "font_bundle/marshmallow/NotoSansTagalog-Regular.ttf",
-    "font_bundle/marshmallow/NotoSansTagbanwa-Regular.ttf",
-    "font_bundle/marshmallow/NotoSansTaiLe-Regular.ttf",
-    "font_bundle/marshmallow/NotoSansTaiTham-Regular.ttf",
-    "font_bundle/marshmallow/NotoSansTaiViet-Regular.ttf",
-    "font_bundle/marshmallow/NotoSansTamil-Bold.ttf",
-    "font_bundle/marshmallow/NotoSansTamil-Regular.ttf",
-    "font_bundle/marshmallow/NotoSansTamilUI-Bold.ttf",
-    "font_bundle/marshmallow/NotoSansTamilUI-Regular.ttf",
-    "font_bundle/marshmallow/NotoSansTelugu-Bold.ttf",
-    "font_bundle/marshmallow/NotoSansTelugu-Regular.ttf",
-    "font_bundle/marshmallow/NotoSansTeluguUI-Bold.ttf",
-    "font_bundle/marshmallow/NotoSansTeluguUI-Regular.ttf",
-    "font_bundle/marshmallow/NotoSansThaana-Bold.ttf",
-    "font_bundle/marshmallow/NotoSansThaana-Regular.ttf",
-    "font_bundle/marshmallow/NotoSansThai-Bold.ttf",
-    "font_bundle/marshmallow/NotoSansThai-Regular.ttf",
-    "font_bundle/marshmallow/NotoSansThaiUI-Bold.ttf",
-    "font_bundle/marshmallow/NotoSansThaiUI-Regular.ttf",
-    "font_bundle/marshmallow/NotoSansTibetan-Regular.ttf",
-    "font_bundle/marshmallow/NotoSansTifinagh-Regular.ttf",
-    "font_bundle/marshmallow/NotoSansUI-Bold.ttf",
-    "font_bundle/marshmallow/NotoSansUI-BoldItalic.ttf",
-    "font_bundle/marshmallow/NotoSansUI-Italic.ttf",
-    "font_bundle/marshmallow/NotoSansUI-Regular.ttf",
-    "font_bundle/marshmallow/NotoSansUgaritic-Regular.ttf",
-    "font_bundle/marshmallow/NotoSansVai-Regular.ttf",
-    "font_bundle/marshmallow/NotoSansYi-Regular.ttf",
-    "font_bundle/marshmallow/NotoSerif-Bold.ttf",
-    "font_bundle/marshmallow/NotoSerif-BoldItalic.ttf",
-    "font_bundle/marshmallow/NotoSerif-Italic.ttf",
-    "font_bundle/marshmallow/NotoSerif-Regular.ttf",
-    "font_bundle/marshmallow/NotoSerifArmenian-Bold.ttf",
-    "font_bundle/marshmallow/NotoSerifArmenian-Regular.ttf",
-    "font_bundle/marshmallow/NotoSerifGeorgian-Bold.ttf",
-    "font_bundle/marshmallow/NotoSerifGeorgian-Regular.ttf",
-    "font_bundle/marshmallow/NotoSerifKhmer-Bold.ttf",
-    "font_bundle/marshmallow/NotoSerifKhmer-Regular.ttf",
-    "font_bundle/marshmallow/NotoSerifLao-Bold.ttf",
-    "font_bundle/marshmallow/NotoSerifLao-Regular.ttf",
-    "font_bundle/marshmallow/NotoSerifThai-Bold.ttf",
-    "font_bundle/marshmallow/NotoSerifThai-Regular.ttf",
-    "font_bundle/marshmallow/Roboto-Black.ttf",
-    "font_bundle/marshmallow/Roboto-BlackItalic.ttf",
-    "font_bundle/marshmallow/Roboto-Bold.ttf",
-    "font_bundle/marshmallow/Roboto-BoldItalic.ttf",
-    "font_bundle/marshmallow/Roboto-Italic.ttf",
-    "font_bundle/marshmallow/Roboto-Light.ttf",
-    "font_bundle/marshmallow/Roboto-LightItalic.ttf",
-    "font_bundle/marshmallow/Roboto-Medium.ttf",
-    "font_bundle/marshmallow/Roboto-MediumItalic.ttf",
-    "font_bundle/marshmallow/Roboto-Regular.ttf",
-    "font_bundle/marshmallow/Roboto-Thin.ttf",
-    "font_bundle/marshmallow/Roboto-ThinItalic.ttf",
-    "font_bundle/marshmallow/RobotoCondensed-Bold.ttf",
-    "font_bundle/marshmallow/RobotoCondensed-BoldItalic.ttf",
-    "font_bundle/marshmallow/RobotoCondensed-Italic.ttf",
-    "font_bundle/marshmallow/RobotoCondensed-Light.ttf",
-    "font_bundle/marshmallow/RobotoCondensed-LightItalic.ttf",
-    "font_bundle/marshmallow/RobotoCondensed-Regular.ttf",
-    "font_bundle/marshmallow/fonts.xml",
-  ]
-
-  outputs = [
-    "$root_gen_dir/{{source}}",
-  ]
-}
diff --git a/third_party/blimp_fonts/LICENSE b/third_party/blimp_fonts/LICENSE
deleted file mode 100644
index 81b3c95..0000000
--- a/third_party/blimp_fonts/LICENSE
+++ /dev/null
@@ -1,345 +0,0 @@
-Fonts under Apache License Version 2.0 license:
-
-The font files below are in the font_bundle/marshmallow subdirectory.
-
-AndroidClock.ttf
-AndroidClock_Highlight.ttf
-AndroidClock_Solid.ttf
-Clockopia.ttf
-ComingSoon.ttf
-DroidSansFallback.ttf
-DroidSansFallbackFull.ttf
-DroidSansMono.ttf
-MTLc3m.ttf
-MTLmr3m.ttf
-NotoColorEmoji.ttf
-NotoKufiArabic-Bold.ttf
-NotoKufiArabic-Regular.ttf
-NotoNaskhArabic-Bold.ttf
-NotoNaskhArabic-Regular.ttf
-NotoNaskhArabicUI-Bold.ttf
-NotoNaskhArabicUI-Regular.ttf
-NotoSansArmenian-Bold.ttf
-NotoSansArmenian-Regular.ttf
-NotoSansAvestan-Regular.ttf
-NotoSansBalinese-Regular.ttf
-NotoSansBamum-Regular.ttf
-NotoSansBatak-Regular.ttf
-NotoSansBengali-Bold.ttf
-NotoSansBengali-Regular.ttf
-NotoSansBengaliUI-Bold.ttf
-NotoSansBengaliUI-Regular.ttf
-NotoSans-BoldItalic.ttf
-NotoSans-Bold.ttf
-NotoSansBrahmi-Regular.ttf
-NotoSansBuginese-Regular.ttf
-NotoSansBuhid-Regular.ttf
-NotoSansCanadianAboriginal-Regular.ttf
-NotoSansCarian-Regular.ttf
-NotoSansCham-Bold.ttf
-NotoSansCham-Regular.ttf
-NotoSansCherokee-Regular.ttf
-NotoSansCoptic-Regular.ttf
-NotoSansCuneiform-Regular.ttf
-NotoSansCypriot-Regular.ttf
-NotoSansDeseret-Regular.ttf
-NotoSansDevanagari-Bold.ttf
-NotoSansDevanagari-Regular.ttf
-NotoSansDevanagariUI-Bold.ttf
-NotoSansDevanagariUI-Regular.ttf
-NotoSansEgyptianHieroglyphs-Regular.ttf
-NotoSansEthiopic-Bold.ttf
-NotoSansEthiopic-Regular.ttf
-NotoSansGeorgian-Bold.ttf
-NotoSansGeorgian-Regular.ttf
-NotoSansGlagolitic-Regular.ttf
-NotoSansGothic-Regular.ttf
-NotoSansGujarati-Bold.ttf
-NotoSansGujarati-Regular.ttf
-NotoSansGujaratiUI-Bold.ttf
-NotoSansGujaratiUI-Regular.ttf
-NotoSansGurmukhi-Bold.ttf
-NotoSansGurmukhi-Regular.ttf
-NotoSansGurmukhiUI-Bold.ttf
-NotoSansGurmukhiUI-Regular.ttf
-NotoSansHanunoo-Regular.ttf
-NotoSansHebrew-Bold.ttf
-NotoSansHebrew-Regular.ttf
-NotoSansImperialAramaic-Regular.ttf
-NotoSansInscriptionalPahlavi-Regular.ttf
-NotoSansInscriptionalParthian-Regular.ttf
-NotoSans-Italic.ttf
-NotoSansJavanese-Regular.ttf
-NotoSansKaithi-Regular.ttf
-NotoSansKannada-Bold.ttf
-NotoSansKannada-Regular.ttf
-NotoSansKannadaUI-Bold.ttf
-NotoSansKannadaUI-Regular.ttf
-NotoSansKayahLi-Regular.ttf
-NotoSansKharoshthi-Regular.ttf
-NotoSansKhmer-Bold.ttf
-NotoSansKhmer-Regular.ttf
-NotoSansKhmerUI-Bold.ttf
-NotoSansKhmerUI-Regular.ttf
-NotoSansLao-Bold.ttf
-NotoSansLao-Regular.ttf
-NotoSansLaoUI-Bold.ttf
-NotoSansLaoUI-Regular.ttf
-NotoSansLepcha-Regular.ttf
-NotoSansLimbu-Regular.ttf
-NotoSansLinearB-Regular.ttf
-NotoSansLisu-Regular.ttf
-NotoSansLycian-Regular.ttf
-NotoSansLydian-Regular.ttf
-NotoSansMalayalam-Bold.ttf
-NotoSansMalayalam-Regular.ttf
-NotoSansMalayalamUI-Bold.ttf
-NotoSansMalayalamUI-Regular.ttf
-NotoSansMandaic-Regular.ttf
-NotoSansMeeteiMayek-Regular.ttf
-NotoSansMongolian-Regular.ttf
-NotoSansMyanmar-Bold.ttf
-NotoSansMyanmar-Regular.ttf
-NotoSansMyanmarUI-Bold.ttf
-NotoSansMyanmarUI-Regular.ttf
-NotoSansNewTaiLue-Regular.ttf
-NotoSansNKo-Regular.ttf
-NotoSansOgham-Regular.ttf
-NotoSansOlChiki-Regular.ttf
-NotoSansOldItalic-Regular.ttf
-NotoSansOldPersian-Regular.ttf
-NotoSansOldSouthArabian-Regular.ttf
-NotoSansOldTurkic-Regular.ttf
-NotoSansOriya-Bold.ttf
-NotoSansOriya-Regular.ttf
-NotoSansOriyaUI-Bold.ttf
-NotoSansOriyaUI-Regular.ttf
-NotoSansOsmanya-Regular.ttf
-NotoSansPhagsPa-Regular.ttf
-NotoSansPhoenician-Regular.ttf
-NotoSans-Regular.ttf
-NotoSansRejang-Regular.ttf
-NotoSansRunic-Regular.ttf
-NotoSansSamaritan-Regular.ttf
-NotoSansSaurashtra-Regular.ttf
-NotoSansShavian-Regular.ttf
-NotoSansSinhala-Bold.ttf
-NotoSansSinhala-Regular.ttf
-NotoSansSundanese-Regular.ttf
-NotoSansSylotiNagri-Regular.ttf
-NotoSansSymbols-Regular-Subsetted.ttf
-NotoSansSymbols-Regular.ttf
-NotoSansSyriacEastern-Regular.ttf
-NotoSansSyriacEstrangela-Regular.ttf
-NotoSansSyriacWestern-Regular.ttf
-NotoSansTagalog-Regular.ttf
-NotoSansTagbanwa-Regular.ttf
-NotoSansTaiLe-Regular.ttf
-NotoSansTaiTham-Regular.ttf
-NotoSansTaiViet-Regular.ttf
-NotoSansTamil-Bold.ttf
-NotoSansTamil-Regular.ttf
-NotoSansTamilUI-Bold.ttf
-NotoSansTamilUI-Regular.ttf
-NotoSansTelugu-Bold.ttf
-NotoSansTelugu-Regular.ttf
-NotoSansTeluguUI-Bold.ttf
-NotoSansTeluguUI-Regular.ttf
-NotoSansThaana-Bold.ttf
-NotoSansThaana-Regular.ttf
-NotoSansThai-Bold.ttf
-NotoSansThai-Regular.ttf
-NotoSansThaiUI-Bold.ttf
-NotoSansThaiUI-Regular.ttf
-NotoSansTibetan-Regular.ttf
-NotoSansTifinagh-Regular.ttf
-NotoSansUgaritic-Regular.ttf
-NotoSansUI-BoldItalic.ttf
-NotoSansUI-Bold.ttf
-NotoSansUI-Italic.ttf
-NotoSansUI-Regular.ttf
-NotoSansVai-Regular.ttf
-NotoSansYi-Regular.ttf
-NotoSerifArmenian-Bold.ttf
-NotoSerifArmenian-Regular.ttf
-NotoSerif-BoldItalic.ttf
-NotoSerif-Bold.ttf
-NotoSerifGeorgian-Bold.ttf
-NotoSerifGeorgian-Regular.ttf
-NotoSerif-Italic.ttf
-NotoSerifKhmer-Bold.ttf
-NotoSerifKhmer-Regular.ttf
-NotoSerifLao-Bold.ttf
-NotoSerifLao-Regular.ttf
-NotoSerif-Regular.ttf
-NotoSerifThai-Bold.ttf
-NotoSerifThai-Regular.ttf
-Roboto-BlackItalic.ttf
-Roboto-Black.ttf
-Roboto-BoldItalic.ttf
-Roboto-Bold.ttf
-RobotoCondensed-BoldItalic.ttf
-RobotoCondensed-Bold.ttf
-RobotoCondensed-Italic.ttf
-RobotoCondensed-LightItalic.ttf
-RobotoCondensed-Light.ttf
-RobotoCondensed-Regular.ttf
-Roboto-Italic.ttf
-Roboto-LightItalic.ttf
-Roboto-Light.ttf
-Roboto-MediumItalic.ttf
-Roboto-Medium.ttf
-Roboto-Regular.ttf
-Roboto-ThinItalic.ttf
-Roboto-Thin.ttf
-
-The font files below are in the font_bundle/kitkat subdirectory.
-
-AndroidClock_Highlight.ttf
-AndroidClock_Solid.ttf
-AndroidClock.ttf
-AndroidEmoji.ttf
-Clockopia.ttf
-DroidKufi-Bold.ttf
-DroidKufi-Regular.ttf
-DroidNaskh-Bold.ttf
-DroidNaskh-Regular.ttf
-DroidNaskhUI-Regular.ttf
-DroidSansArabic.ttf
-DroidSansArmenian.ttf
-DroidSans-Bold.ttf
-DroidSansEthiopic-Bold.ttf
-DroidSansEthiopic-Regular.ttf
-DroidSansFallbackFull.ttf
-DroidSansFallbackLegacy.ttf
-DroidSansFallback.ttf
-DroidSansGeorgian.ttf
-DroidSansHebrew-Bold.ttf
-DroidSansHebrew-Regular.ttf
-DroidSansJapanese.ttf
-DroidSansMono.ttf
-DroidSans.ttf
-DroidSerif-BoldItalic.ttf
-DroidSerif-Bold.ttf
-DroidSerif-Italic.ttf
-DroidSerif-Regular.ttf
-fallback_fonts.xml
-MTLc3m.ttf
-MTLmr3m.ttf
-NotoColorEmoji.ttf
-NotoSansBengali-Bold.ttf
-NotoSansBengali-Regular.ttf
-NotoSansBengaliUI-Bold.ttf
-NotoSansBengaliUI-Regular.ttf
-NotoSansDevanagari-Bold.ttf
-NotoSansDevanagari-Regular.ttf
-NotoSansDevanagariUI-Bold.ttf
-NotoSansDevanagariUI-Regular.ttf
-NotoSansKannada-Bold.ttf
-NotoSansKannada-Regular.ttf
-NotoSansKannadaUI-Bold.ttf
-NotoSansKannadaUI-Regular.ttf
-NotoSansKhmer-Bold.ttf
-NotoSansKhmer-Regular.ttf
-NotoSansKhmerUI-Bold.ttf
-NotoSansKhmerUI-Regular.ttf
-NotoSansLao-Bold.ttf
-NotoSansLao-Regular.ttf
-NotoSansLaoUI-Bold.ttf
-NotoSansLaoUI-Regular.ttf
-NotoSansMalayalam-Bold.ttf
-NotoSansMalayalam-Regular.ttf
-NotoSansMalayalamUI-Bold.ttf
-NotoSansMalayalamUI-Regular.ttf
-NotoSansSymbols-Regular.ttf
-NotoSansTamil-Bold.ttf
-NotoSansTamil-Regular.ttf
-NotoSansTamilUI-Bold.ttf
-NotoSansTamilUI-Regular.ttf
-NotoSansTelugu-Bold.ttf
-NotoSansTelugu-Regular.ttf
-NotoSansTeluguUI-Bold.ttf
-NotoSansTeluguUI-Regular.ttf
-NotoSansThai-Bold.ttf
-NotoSansThai-Regular.ttf
-NotoSansThaiUI-Bold.ttf
-NotoSansThaiUI-Regular.ttf
-Roboto-BoldItalic.ttf
-Roboto-Bold.ttf
-RobotoCondensed-BoldItalic.ttf
-RobotoCondensed-Bold.ttf
-RobotoCondensed-Italic.ttf
-RobotoCondensed-Regular.ttf
-Roboto-Italic.ttf
-Roboto-LightItalic.ttf
-Roboto-Light.ttf
-Roboto-Regular.ttf
-Roboto-ThinItalic.ttf
-Roboto-Thin.ttf
-
-
-Fonts under SIL Open Font License, Version 1.1:
-(Full license in LICENSE.OFL)
-
-The font files below are in the font_bundle/marshmallow subdirectory.
-NotoSansJP-Regular.otf
-NotoSansJP-Regular-Subsetted.otf
-NotoSansKR-Regular.otf
-NotoSansSC-Regular.otf
-NotoSansTC-Regular.otf
-
-
-Copyright (c) 2011 by Ralph du Carrois, with Reserved Font Name 'Carrois'
-This Font Software is licensed under the SIL Open Font License, Version 1.1
-(Full license in LICENSE.OFL)
-The font files below are in the font_bundle/marshmallow subdirectory.
-CarroisGothicSC-Regular.ttf
-
-
-Copyright (c) 2010, Pablo Impallari (www.impallari.com|impallari@gmail.com),
-Copyright (c) 2010, Igino Marini. (www.ikern.com|mail@iginomarini.com),
-with Reserved Font Name Dancing Script.
-This Font Software is licensed under the SIL Open Font License, Version 1.1.
-(Full license in LICENSE.OFL)
-
-The font files below are in the font_bundle/marshmallow subdirectory.
-DancingScript-Bold.ttf
-DancingScript-Regular.ttf
-CutiveMono.ttf
-
-
-Copyright (c) 2010, NHN Corporation (http://www.nhncorp.com),
-  (http://hangeul.naver.com/font)
-with Reserved Font Name Nanum, Naver Nanum, NanumGothic, Naver NanumGothic, NanumMyeongjo, Naver NanumMyeongjo, NanumBrush, Naver NanumBrush, NanumPen, Naver NanumPen, Naver NanumGothicEco, NanumGothicEco, Naver NanumMyeongjoEco, NanumMyeongjoEco, Naver NanumGothicLight, NanumGothicLight
-
-This Font Software is licensed under the SIL Open Font License, Version 1.1.
-(Full license in LICENSE.OFL)
-
-The files below are in the font_bundle/marshmallow subdirectory.
-NanumGothicBold.ttf
-NanumGothic.ttf
-
-
-Copyright (c) 2010, NHN Corporation (http://www.nhncorp.com),
-  (http://hangeul.naver.com/font)
-with Reserved Font Name Nanum, Naver Nanum, NanumGothic, Naver NanumGothic, NanumMyeongjo, Naver NanumMyeongjo, NanumBrush, Naver NanumBrush, NanumPen, Naver NanumPen, Naver NanumGothicEco, NanumGothicEco, Naver NanumMyeongjoEco, NanumMyeongjoEco, Naver NanumGothicLight, NanumGothicLight
-
-This Font Software is licensed under the SIL Open Font License, Version 1.1.
-This license is copied below, and is also available with a FAQ at:
-http://scripts.sil.org/OFL
-
-The files below are in the font_bundle/kitkat subdirectory.
-NanumGothicBold.ttf
-NanumGothic.ttf
-
-
-Copyright SIL International, all rights reserved
-Reserved names: "Padauk"
-
-This Font Software is licensed under the SIL Open Font License, Version 1.1.
-This license is copied below, and is also available with a FAQ at:
-http://scripts.sil.org/OFL
-
-The files below are in the font_bundle/kitkat subdirectory.
-Padauk-bookbold.ttf
-Padauk-book.ttf
diff --git a/third_party/blimp_fonts/LICENSE.Apache b/third_party/blimp_fonts/LICENSE.Apache
deleted file mode 100644
index a3711ba6..0000000
--- a/third_party/blimp_fonts/LICENSE.Apache
+++ /dev/null
@@ -1,201 +0,0 @@
-                             Apache License
-                       Version 2.0, January 2004
-                    http://www.apache.org/licenses/
-
-TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
-
-1. Definitions.
-
-  "License" shall mean the terms and conditions for use, reproduction,
-  and distribution as defined by Sections 1 through 9 of this document.
-
-  "Licensor" shall mean the copyright owner or entity authorized by
-  the copyright owner that is granting the License.
-
-  "Legal Entity" shall mean the union of the acting entity and all
-  other entities that control, are controlled by, or are under common
-  control with that entity. For the purposes of this definition,
-  "control" means (i) the power, direct or indirect, to cause the
-  direction or management of such entity, whether by contract or
-  otherwise, or (ii) ownership of fifty percent (50%) or more of the
-  outstanding shares, or (iii) beneficial ownership of such entity.
-
-  "You" (or "Your") shall mean an individual or Legal Entity
-  exercising permissions granted by this License.
-
-  "Source" form shall mean the preferred form for making modifications,
-  including but not limited to software source code, documentation
-  source, and configuration files.
-
-  "Object" form shall mean any form resulting from mechanical
-  transformation or translation of a Source form, including but
-  not limited to compiled object code, generated documentation,
-  and conversions to other media types.
-
-  "Work" shall mean the work of authorship, whether in Source or
-  Object form, made available under the License, as indicated by a
-  copyright notice that is included in or attached to the work
-  (an example is provided in the Appendix below).
-
-  "Derivative Works" shall mean any work, whether in Source or Object
-  form, that is based on (or derived from) the Work and for which the
-  editorial revisions, annotations, elaborations, or other modifications
-  represent, as a whole, an original work of authorship. For the purposes
-  of this License, Derivative Works shall not include works that remain
-  separable from, or merely link (or bind by name) to the interfaces of,
-  the Work and Derivative Works thereof.
-
-  "Contribution" shall mean any work of authorship, including
-  the original version of the Work and any modifications or additions
-  to that Work or Derivative Works thereof, that is intentionally
-  submitted to Licensor for inclusion in the Work by the copyright owner
-  or by an individual or Legal Entity authorized to submit on behalf of
-  the copyright owner. For the purposes of this definition, "submitted"
-  means any form of electronic, verbal, or written communication sent
-  to the Licensor or its representatives, including but not limited to
-  communication on electronic mailing lists, source code control systems,
-  and issue tracking systems that are managed by, or on behalf of, the
-  Licensor for the purpose of discussing and improving the Work, but
-  excluding communication that is conspicuously marked or otherwise
-  designated in writing by the copyright owner as "Not a Contribution."
-
-  "Contributor" shall mean Licensor and any individual or Legal Entity
-  on behalf of whom a Contribution has been received by Licensor and
-  subsequently incorporated within the Work.
-
-2. Grant of Copyright License. Subject to the terms and conditions of
-  this License, each Contributor hereby grants to You a perpetual,
-  worldwide, non-exclusive, no-charge, royalty-free, irrevocable
-  copyright license to reproduce, prepare Derivative Works of,
-  publicly display, publicly perform, sublicense, and distribute the
-  Work and such Derivative Works in Source or Object form.
-
-3. Grant of Patent License. Subject to the terms and conditions of
-  this License, each Contributor hereby grants to You a perpetual,
-  worldwide, non-exclusive, no-charge, royalty-free, irrevocable
-  (except as stated in this section) patent license to make, have made,
-  use, offer to sell, sell, import, and otherwise transfer the Work,
-  where such license applies only to those patent claims licensable
-  by such Contributor that are necessarily infringed by their
-  Contribution(s) alone or by combination of their Contribution(s)
-  with the Work to which such Contribution(s) was submitted. If You
-  institute patent litigation against any entity (including a
-  cross-claim or counterclaim in a lawsuit) alleging that the Work
-  or a Contribution incorporated within the Work constitutes direct
-  or contributory patent infringement, then any patent licenses
-  granted to You under this License for that Work shall terminate
-  as of the date such litigation is filed.
-
-4. Redistribution. You may reproduce and distribute copies of the
-  Work or Derivative Works thereof in any medium, with or without
-  modifications, and in Source or Object form, provided that You
-  meet the following conditions:
-
-  (a) You must give any other recipients of the Work or
-      Derivative Works a copy of this License; and
-
-  (b) You must cause any modified files to carry prominent notices
-      stating that You changed the files; and
-
-  (c) You must retain, in the Source form of any Derivative Works
-      that You distribute, all copyright, patent, trademark, and
-      attribution notices from the Source form of the Work,
-      excluding those notices that do not pertain to any part of
-      the Derivative Works; and
-
-  (d) If the Work includes a "NOTICE" text file as part of its
-      distribution, then any Derivative Works that You distribute must
-      include a readable copy of the attribution notices contained
-      within such NOTICE file, excluding those notices that do not
-      pertain to any part of the Derivative Works, in at least one
-      of the following places: within a NOTICE text file distributed
-      as part of the Derivative Works; within the Source form or
-      documentation, if provided along with the Derivative Works; or,
-      within a display generated by the Derivative Works, if and
-      wherever such third-party notices normally appear. The contents
-      of the NOTICE file are for informational purposes only and
-      do not modify the License. You may add Your own attribution
-      notices within Derivative Works that You distribute, alongside
-      or as an addendum to the NOTICE text from the Work, provided
-      that such additional attribution notices cannot be construed
-      as modifying the License.
-
-  You may add Your own copyright statement to Your modifications and
-  may provide additional or different license terms and conditions
-  for use, reproduction, or distribution of Your modifications, or
-  for any such Derivative Works as a whole, provided Your use,
-  reproduction, and distribution of the Work otherwise complies with
-  the conditions stated in this License.
-
-5. Submission of Contributions. Unless You explicitly state otherwise,
-  any Contribution intentionally submitted for inclusion in the Work
-  by You to the Licensor shall be under the terms and conditions of
-  this License, without any additional terms or conditions.
-  Notwithstanding the above, nothing herein shall supersede or modify
-  the terms of any separate license agreement you may have executed
-  with Licensor regarding such Contributions.
-
-6. Trademarks. This License does not grant permission to use the trade
-  names, trademarks, service marks, or product names of the Licensor,
-  except as required for reasonable and customary use in describing the
-  origin of the Work and reproducing the content of the NOTICE file.
-
-7. Disclaimer of Warranty. Unless required by applicable law or
-  agreed to in writing, Licensor provides the Work (and each
-  Contributor provides its Contributions) on an "AS IS" BASIS,
-  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
-  implied, including, without limitation, any warranties or conditions
-  of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
-  PARTICULAR PURPOSE. You are solely responsible for determining the
-  appropriateness of using or redistributing the Work and assume any
-  risks associated with Your exercise of permissions under this License.
-
-8. Limitation of Liability. In no event and under no legal theory,
-  whether in tort (including negligence), contract, or otherwise,
-  unless required by applicable law (such as deliberate and grossly
-  negligent acts) or agreed to in writing, shall any Contributor be
-  liable to You for damages, including any direct, indirect, special,
-  incidental, or consequential damages of any character arising as a
-  result of this License or out of the use or inability to use the
-  Work (including but not limited to damages for loss of goodwill,
-  work stoppage, computer failure or malfunction, or any and all
-  other commercial damages or losses), even if such Contributor
-  has been advised of the possibility of such damages.
-
-9. Accepting Warranty or Additional Liability. While redistributing
-  the Work or Derivative Works thereof, You may choose to offer,
-  and charge a fee for, acceptance of support, warranty, indemnity,
-  or other liability obligations and/or rights consistent with this
-  License. However, in accepting such obligations, You may act only
-  on Your own behalf and on Your sole responsibility, not on behalf
-  of any other Contributor, and only if You agree to indemnify,
-  defend, and hold each Contributor harmless for any liability
-  incurred by, or claims asserted against, such Contributor by reason
-  of your accepting any such warranty or additional liability.
-
-END OF TERMS AND CONDITIONS
-
-APPENDIX: How to apply the Apache License to your work.
-
-  To apply the Apache License to your work, attach the following
-  boilerplate notice, with the fields enclosed by brackets "[]"
-  replaced with your own identifying information. (Don't include
-  the brackets!)  The text should be enclosed in the appropriate
-  comment syntax for the file format. We also recommend that a
-  file or class name and description of purpose be included on the
-  same "printed page" as the copyright notice for easier
-  identification within third-party archives.
-
-Copyright [yyyy] [name of copyright owner]
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
-   http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
diff --git a/third_party/blimp_fonts/LICENSE.OFL b/third_party/blimp_fonts/LICENSE.OFL
deleted file mode 100644
index d952d62..0000000
--- a/third_party/blimp_fonts/LICENSE.OFL
+++ /dev/null
@@ -1,92 +0,0 @@
-This Font Software is licensed under the SIL Open Font License,
-Version 1.1.
-
-This license is copied below, and is also available with a FAQ at:
-http://scripts.sil.org/OFL
-
------------------------------------------------------------
-SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
------------------------------------------------------------
-
-PREAMBLE
-The goals of the Open Font License (OFL) are to stimulate worldwide
-development of collaborative font projects, to support the font
-creation efforts of academic and linguistic communities, and to
-provide a free and open framework in which fonts may be shared and
-improved in partnership with others.
-
-The OFL allows the licensed fonts to be used, studied, modified and
-redistributed freely as long as they are not sold by themselves. The
-fonts, including any derivative works, can be bundled, embedded,
-redistributed and/or sold with any software provided that any reserved
-names are not used by derivative works. The fonts and derivatives,
-however, cannot be released under any other type of license. The
-requirement for fonts to remain under this license does not apply to
-any document created using the fonts or their derivatives.
-
-DEFINITIONS
-"Font Software" refers to the set of files released by the Copyright
-Holder(s) under this license and clearly marked as such. This may
-include source files, build scripts and documentation.
-
-"Reserved Font Name" refers to any names specified as such after the
-copyright statement(s).
-
-"Original Version" refers to the collection of Font Software
-components as distributed by the Copyright Holder(s).
-
-"Modified Version" refers to any derivative made by adding to,
-deleting, or substituting -- in part or in whole -- any of the
-components of the Original Version, by changing formats or by porting
-the Font Software to a new environment.
-
-"Author" refers to any designer, engineer, programmer, technical
-writer or other person who contributed to the Font Software.
-
-PERMISSION & CONDITIONS
-Permission is hereby granted, free of charge, to any person obtaining
-a copy of the Font Software, to use, study, copy, merge, embed,
-modify, redistribute, and sell modified and unmodified copies of the
-Font Software, subject to the following conditions:
-
-1) Neither the Font Software nor any of its individual components, in
-Original or Modified Versions, may be sold by itself.
-
-2) Original or Modified Versions of the Font Software may be bundled,
-redistributed and/or sold with any software, provided that each copy
-contains the above copyright notice and this license. These can be
-included either as stand-alone text files, human-readable headers or
-in the appropriate machine-readable metadata fields within text or
-binary files as long as those fields can be easily viewed by the user.
-
-3) No Modified Version of the Font Software may use the Reserved Font
-Name(s) unless explicit written permission is granted by the
-corresponding Copyright Holder. This restriction only applies to the
-primary font name as presented to the users.
-
-4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
-Software shall not be used to promote, endorse or advertise any
-Modified Version, except to acknowledge the contribution(s) of the
-Copyright Holder(s) and the Author(s) or with their explicit written
-permission.
-
-5) The Font Software, modified or unmodified, in part or in whole,
-must be distributed entirely under this license, and must not be
-distributed under any other license. The requirement for fonts to
-remain under this license does not apply to any document created using
-the Font Software.
-
-TERMINATION
-This license becomes null and void if any of the above conditions are
-not met.
-
-DISCLAIMER
-THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
-MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
-OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
-COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
-INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
-DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
-OTHER DEALINGS IN THE FONT SOFTWARE.
diff --git a/third_party/blimp_fonts/OWNERS b/third_party/blimp_fonts/OWNERS
deleted file mode 100644
index d7dfb92..0000000
--- a/third_party/blimp_fonts/OWNERS
+++ /dev/null
@@ -1,5 +0,0 @@
-dtrainor@chromium.org
-haibinlu@chromium.org
-kmarshall@chromium.org
-nyquist@chromium.org
-wez@chromium.org
diff --git a/third_party/blimp_fonts/README.chromium b/third_party/blimp_fonts/README.chromium
deleted file mode 100644
index 14b75a9..0000000
--- a/third_party/blimp_fonts/README.chromium
+++ /dev/null
@@ -1,55 +0,0 @@
-Name: blimp_fonts
-URL: See below
-Version: unknown
-License: Apache Version 2.0 and SIL Open Font License, Version 1.1
-Security Critical: yes
-
-Description:
-A collection of fonts that are necessary to bundle with the blimp engine to be
-able to render the correct fonts for different clients.
-
-How to update:
-See //blimp/docs/fonts.md.
-
-Local Modifications:
-Not all files from the external repositories are used.
-- *.otf, *.ttf: From the various repositories.
-- .gitignore:   Added.
-- BUILD.gn:     Added.
-- LICENSE:      Added.
-- LICENSE.*:    Extracted from license files in the various repositories.
-- README.md:    Added.
-- fonts.xml:    From this repository:
-                https://android.googlesource.com/platform/frameworks/base.git
-
-Fonts are pulled from the following repositories:
-- Git repo: https://android.googlesource.com/platform/frameworks/base.git
-  Commit: 6a278db4c4a144829353e81420f28dcf2105f767 (marshmallow)
-          e89d3c9cebf59a6062974e9d2993adbddeaa4fef (KTU84Z)
-  Directory: data/fonts/
-- Git repo: https://android.googlesource.com/platform/external/noto-fonts.git
-  Commit: eb0883544dd538edbfb52cce9a2481509ca5ee9f (marshmallow)
-          90372d894b5d9c9f2a111315d2eb3b8de1979ee4 (KTU84Z)
-  Directory: cjk/, other/
-- Git repo: https://android.googlesource.com/platform/external/roboto-fonts.git
-  Commit: f5cf79102af594c746627b392b4f98eedd254571
-  Directory: .
-- Git repo: https://android.googlesource.com/platform/external/google-fonts/dancing-script.git
-  Commit: 7b6623bd54cee3e48ae8a4f477f616366643cc78
-  Directory: .
-- Git repo: https://android.googlesource.com/platform/external/google-fonts/cutive-mono.git
-  Commit: bce2136662854076023066602526ba299e6556b2
-  Directory: .
-- Git repo: https://android.googlesource.com/platform/external/google-fonts/coming-soon.git
-  Commit: 2c5cb418c690815545bbb0316eae5fd33b9fc859
-  Directory: .
-- Git repo: https://android.googlesource.com/platform/external/google-fonts/carrois-gothic-sc.git
-  Commit: 0062a10458d4c357f3082d66bcb129d11913aaae
-  Directory: .
-- Git repo: https://android.googlesource.com/platform/external/naver-fonts.git
-  Commit: 91e6e9f94d1d769a8f742649674149ba98ce7d45 (marshmallow)
-          9238a39d60763f81b98d96f02b087d52b9d4fd52 (KTU84Z)
-  Directory: .
-- Git repo: https://android.googlesource.com/platform/external/sil-fonts.git
-  Commit: 795a2f4339f8a82d6cff187e2a77bb01d5911aac (KTU84Z)
-  Directory: .
diff --git a/third_party/blimp_fonts/font_bundle.tar.gz.sha1 b/third_party/blimp_fonts/font_bundle.tar.gz.sha1
deleted file mode 100644
index 409daa6..0000000
--- a/third_party/blimp_fonts/font_bundle.tar.gz.sha1
+++ /dev/null
@@ -1 +0,0 @@
-953cc0e3f7c2c58284e41bbc3b11a771fe9bb1fe
\ No newline at end of file
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index eb1845a..fddeff3a 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -80866,6 +80866,8 @@
   <int value="-402" label="CACHE_WRITE_FAILURE"/>
   <int value="-401" label="CACHE_READ_FAILURE"/>
   <int value="-400" label="CACHE_MISS"/>
+  <int value="-372" label="SPDY_RST_STREAM_NO_ERROR_RECEIVED"/>
+  <int value="-371" label="CONTENT_DECODING_INIT_FAILED"/>
   <int value="-370" label="INVALID_HTTP_RESPONSE"/>
   <int value="-369" label="TEMPORARY_BACKOFF"/>
   <int value="-368" label="ALTERNATIVE_CERT_NOT_VALID_FOR_ORIGIN"/>
@@ -80937,6 +80939,7 @@
   <int value="-202" label="CERT_AUTHORITY_INVALID"/>
   <int value="-201" label="CERT_DATE_INVALID"/>
   <int value="-200" label="CERT_COMMON_NAME_INVALID"/>
+  <int value="-173" label="WS_UPGRADE"/>
   <int value="-172" label="SSL_OBSOLETE_CIPHER"/>
   <int value="-171" label="CT_CONSISTENCY_PROOF_PARSING_FAILED"/>
   <int value="-170" label="UNABLE_TO_REUSE_CONNECTION_FOR_PROXY_AUTH"/>
@@ -81006,6 +81009,8 @@
   <int value="-102" label="CONNECTION_REFUSED"/>
   <int value="-101" label="CONNECTION_RESET"/>
   <int value="-100" label="CONNECTION_CLOSED"/>
+  <int value="-29" label="CLEARTEXT_NOT_PERMITTED"/>
+  <int value="-28" label="BLOCKED_BY_XSS_AUDITOR"/>
   <int value="-27" label="BLOCKED_BY_RESPONSE"/>
   <int value="-26" label="CONTEXT_SHUT_DOWN"/>
   <int value="-25" label="UPLOAD_STREAM_REWIND_NOT_SUPPORTED"/>
@@ -97721,6 +97726,8 @@
   <int value="25" label="UPLOAD_STREAM_REWIND_NOT_SUPPORTED"/>
   <int value="26" label="CONTEXT_SHUT_DOWN"/>
   <int value="27" label="BLOCKED_BY_RESPONSE"/>
+  <int value="28" label="BLOCKED_BY_XSS_AUDITOR"/>
+  <int value="29" label="CLEARTEXT_NOT_PERMITTED"/>
   <int value="100" label="CONNECTION_CLOSED"/>
   <int value="101" label="CONNECTION_RESET"/>
   <int value="102" label="CONNECTION_REFUSED"/>
@@ -97794,6 +97801,7 @@
   <int value="170" label="UNABLE_TO_REUSE_CONNECTION_FOR_PROXY_AUTH"/>
   <int value="171" label="CT_CONSISTENCY_PROOF_PARSING_FAILED"/>
   <int value="172" label="SSL_OBSOLETE_CIPHER"/>
+  <int value="173" label="WS_UPGRADE"/>
   <int value="200" label="CERT_COMMON_NAME_INVALID"/>
   <int value="201" label="CERT_DATE_INVALID"/>
   <int value="202" label="CERT_AUTHORITY_INVALID"/>
@@ -97867,6 +97875,8 @@
   <int value="368" label="ALTERNATIVE_CERT_NOT_VALID_FOR_ORIGIN"/>
   <int value="369" label="TEMPORARY_BACKOFF"/>
   <int value="370" label="INVALID_HTTP_RESPONSE"/>
+  <int value="371" label="CONTENT_DECODING_INIT_FAILED"/>
+  <int value="372" label="SPDY_RST_STREAM_NO_ERROR_RECEIVED"/>
   <int value="400" label="CACHE_MISS"/>
   <int value="401" label="CACHE_READ_FAILURE"/>
   <int value="402" label="CACHE_WRITE_FAILURE"/>
diff --git a/tools/perf/docs/OWNERS b/tools/perf/docs/OWNERS
new file mode 100644
index 0000000..a85fa5e6
--- /dev/null
+++ b/tools/perf/docs/OWNERS
@@ -0,0 +1 @@
+per-file apk_size_regressions.md=agrieve@chromium.org
diff --git a/tools/perf/docs/apk_size_regressions.md b/tools/perf/docs/apk_size_regressions.md
index 33aa3fae..3ce3a94f 100644
--- a/tools/perf/docs/apk_size_regressions.md
+++ b/tools/perf/docs/apk_size_regressions.md
@@ -1,4 +1,6 @@
-# How to Deal with Apk Size Alerts
+# How to Deal with Android Size Alerts
+
+*Most alerts should not have a bug created for them. Please read on...*
 
 ### If the alert is for "other lib size" or "Unknown files size":
  * File a bug against agrieve@ to fix
@@ -9,7 +11,7 @@
 ### If the alert is a downstream size alert (aka, for Monochrome.apk):
  * The regression most likely already occurred in the upstream
    MonochromePublic.apk target. Look at the
-   [upstream graphs](https://chromeperf.appspot.com/report?sid=5cfed2a07b55702fc64255a316cdb78531e916da4e933677645bbf1fe78cf2e0&num_points=1500)
+   [upstream graphs](https://chromeperf.appspot.com/report?sid=cfc29eed1238fd38fb5e6cf83bdba6c619be621b606e03e5dfc2e99db14c418b&num_points=1500)
    to find the culprit & de-dupe with upstream alerts.
  * If no upstream regression was found, look through the downstream commits
    within the given date range to find the culprit.
@@ -18,6 +20,7 @@
 
 ### If the alert is for a roll:
  * Use a bisect to try and determine a more precise commit.
+    * Except don't. Bisects for these alerts [are currently broken](https://bugs.chromium.org/p/chromium/issues/detail?id=678338).
 
 ### What to do once the commit is identified:
  * If the code seems to justify the size increase:
@@ -26,41 +29,63 @@
        > (unless you can think of an obvious way to reduce the overhead).
        >
        > Link to size graph:
-[https://chromeperf.appspot.com/report?sid=6468aba6ff8d28723690042144ee893d2dd3ded7fb414a916520b90659b8410f&rev=**440074**](https://chromeperf.appspot.com/report?sid=6468aba6ff8d28723690042144ee893d2dd3ded7fb414a916520b90659b8410f&rev=440074)
+[https://chromeperf.appspot.com/report?sid=cfc29eed1238fd38fb5e6cf83bdba6c619be621b606e03e5dfc2e99db14c418b&rev=**440074**](https://chromeperf.appspot.com/report?sid=cfc29eed1238fd38fb5e6cf83bdba6c619be621b606e03e5dfc2e99db14c418b&rev=440074)
     2. Add an entry to
       [this spreadsheet](https://docs.google.com/spreadsheets/d/1GrRkszV7Oy5pVsaMb5Eb6s8izW9t4dElBxIH3iGq93o/edit#gid=1894856744)
       to document the increase (also Update the "Themes / Thoughts" tab if
       applicable).
  * If the code might not justify the size increase:
-    1. File a bug and assign to the author to follow-up (and link them to this
-       doc).
+    1. File a bug and assign to the author to follow-up (and link them to
+       [Debugging Apk Size Increase](https://chromium.googlesource.com/chromium/src/+/master/tools/perf/docs/apk_size_regressions.md#Debugging-Apk-Size-Increase)).
     2. Add an entry to
       [this spreadsheet](https://docs.google.com/spreadsheets/d/1GrRkszV7Oy5pVsaMb5Eb6s8izW9t4dElBxIH3iGq93o/edit#gid=1894856744)
       to document the increase.
 
 # Debugging Apk Size Increase
 
-### How to debug apk size increase
+## Step 1: Identify where the extra bytes came from
 
-1. Figure out which file within the .apk increased by looking at the size
-   graphs showing the breakdowns.
-    * Refer to the chromeperf link that should have been posted to your code review
-      (see above).
-    * Alternatively, refer to "Apk Size" section here:
-      [https://goto.google.com/clank/dashboards](https://goto.google.com/clank/dashboards) (*googler only*).
-1. If it's libchrome.so, build before & after and use
-   [tools/binary_size/](https://cs.chromium.org/chromium/src/tools/binary_size/).
-    * This is somewhat hand-wavy. Some notes on how this tool works at
-      [crbug/482401](https://bugs.chromium.org/p/chromium/issues/detail?id=482401).
-1. If it's classes.dex, build before & after and use:
-   [tools/android/dexdiffer/dexdiffer.py](https://cs.chromium.org/chromium/src/tools/android/dexdiffer/dexdiffer.py).
-    * This currently just shows a list of symbols added / removed rather than
-      taking into account method body sizes.
-    * Enhancements to this tool tracked at
-      [crbug/678044](https://bugs.chromium.org/p/chromium/issues/detail?id=678044).
-1. If it's images, ensure they are optimized:
+Figure out which file within the .apk increased by looking at the size graphs
+showing the breakdowns.
+
+ * Refer to the chromeperf link that should have been posted to your code
+   review (see above).
+ * Alternatively, refer to "Apk Size" section here:
+   [https://goto.google.com/clank/dashboards](https://goto.google.com/clank/dashboards) (*googler only*).
+
+## Step 2: Reproduce build results locally
+
+### Option 1: Build Locally
+ 1. Follow the normal [Android build instructions](https://chromium.googlesource.com/chromium/src/+/master/docs/android_build_instructions.md).
+ 1. Ensure you're using the same GN args as the bots by looking at the `generate_build_files` step of the build:
+    * https://luci-logdog.appspot.com/v/?s=chrome%2Fbb%2Fchromium.perf%2FAndroid_Builder%2F**134505**%2F%2B%2Frecipes%2Fsteps%2Fgenerate_build_files%2F0%2Fstdout
+ 3. Save artifacts you'll need for diffing:
+
+```shell
+    mv out/Release/lib.unstripped out/Release/lib.unstripped.withchange
+    mv out/Release/apks out/Release/apks.withchange
+```
+
+### Option 2: Download artifacts from perf jobs (Googlers only)**
+ 1. Find the archive hash by looking at the `zip_build_product`. Replace the bolded part of the following URL with your build number:
+    * https://luci-logdog.appspot.com/v/?s=chrome%2Fbb%2Fchromium.perf%2FAndroid_Builder%2F**134505**%2F%2B%2Frecipes%2Fsteps%2Fgsutil_upload_build_product%2F0%2Fstdout
+ 2. Download using the following:
+    * https://storage.cloud.google.com/chrome-perf/Android%20Builder/full-build-linux_**ARCHIVE_HASH**.zip
+
+## Step 3: Analyze
+
+ * If the growth is from native code:
+    * Refer to techniques used in [crbug.com/681991](https://bugs.chromium.org/p/chromium/issues/detail?id=681991)
+      and [crbug.com/680973](https://bugs.chromium.org/p/chromium/issues/detail?id=680973).
+ * If the growth is from java code:
+    * Use [tools/android/dexdiffer/dexdiffer.py](https://cs.chromium.org/chromium/src/tools/android/dexdiffer/dexdiffer.py).
+        * This currently just shows a list of symbols added / removed rather than
+          taking into account method body sizes.
+        * Enhancements to this tool tracked at
+          [crbug/678044](https://bugs.chromium.org/p/chromium/issues/detail?id=678044).
+ * If the growth is from images, ensure they are optimized:
     * Would it be smaller as a VectorDrawable?
     * If it's lossy, consider using webp.
     * Ensure you've optimized with
       [tools/resources/optimize-png-files.sh](https://cs.chromium.org/chromium/src/tools/resources/optimize-png-files.sh).
-
+    * There is some [Googler-specific guidance](https://goto.google.com/clank/engineering/best-practices/adding-image-assets) as well.
diff --git a/ui/android/java/res/layout/dropdown_item.xml b/ui/android/java/res/layout/dropdown_item.xml
index 5159c83..49469d4 100644
--- a/ui/android/java/res/layout/dropdown_item.xml
+++ b/ui/android/java/res/layout/dropdown_item.xml
@@ -16,7 +16,7 @@
         android:id="@+id/start_dropdown_icon"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
-        android:layout_margin="8dp"
+        android:layout_margin="@dimen/dropdown_icon_margin"
         android:contentDescription="@null" />
 
     <LinearLayout
@@ -51,7 +51,7 @@
             android:singleLine="true"
             android:textAlignment="viewStart"
             android:textColor="#646464"
-            android:textSize="14sp" />
+            android:textSize="@dimen/dropdown_item_sublabel_font_size" />
     </LinearLayout>
 
     <ImageView
diff --git a/ui/android/java/res/values/dimens.xml b/ui/android/java/res/values/dimens.xml
index b061feb..dc368807 100644
--- a/ui/android/java/res/values/dimens.xml
+++ b/ui/android/java/res/values/dimens.xml
@@ -9,6 +9,8 @@
     <dimen name="dropdown_item_divider_height">1px</dimen>
     <dimen name="dropdown_item_label_font_size">18sp</dimen>
     <dimen name="dropdown_item_label_margin">10dp</dimen>
+    <dimen name="dropdown_item_sublabel_font_size">14sp</dimen>
+    <dimen name="dropdown_icon_margin">8dp</dimen>
 
     <!--
          Fallback values if the corresponding com.android.internal.R dimensions
diff --git a/ui/android/java/src/org/chromium/ui/DropdownAdapter.java b/ui/android/java/src/org/chromium/ui/DropdownAdapter.java
index 3f502c6c..d08a159 100644
--- a/ui/android/java/src/org/chromium/ui/DropdownAdapter.java
+++ b/ui/android/java/src/org/chromium/ui/DropdownAdapter.java
@@ -169,6 +169,8 @@
             sublabelView.setVisibility(View.GONE);
         } else {
             sublabelView.setText(sublabel);
+            sublabelView.setTextSize(TypedValue.COMPLEX_UNIT_PX,
+                    mContext.getResources().getDimension(item.getSublabelFontSizeResId()));
             sublabelView.setVisibility(View.VISIBLE);
         }
 
@@ -184,6 +186,19 @@
         if (item.getIconId() == DropdownItem.NO_ICON) {
             iconView.setVisibility(View.GONE);
         } else {
+            int iconSizeResId = item.getIconSizeResId();
+            int iconSize = iconSizeResId == 0
+                    ? LayoutParams.WRAP_CONTENT
+                    : mContext.getResources().getDimensionPixelSize(iconSizeResId);
+            ViewGroup.MarginLayoutParams layoutParams =
+                    (ViewGroup.MarginLayoutParams) iconView.getLayoutParams();
+            layoutParams.width = iconSize;
+            layoutParams.height = iconSize;
+            int iconMargin =
+                    mContext.getResources().getDimensionPixelSize(item.getIconMarginResId());
+            ApiCompatibilityUtils.setMarginStart(layoutParams, iconMargin);
+            ApiCompatibilityUtils.setMarginEnd(layoutParams, iconMargin);
+            iconView.setLayoutParams(layoutParams);
             iconView.setImageDrawable(AppCompatResources.getDrawable(mContext, item.getIconId()));
             iconView.setVisibility(View.VISIBLE);
         }
diff --git a/ui/android/java/src/org/chromium/ui/DropdownItem.java b/ui/android/java/src/org/chromium/ui/DropdownItem.java
index d28db1d..bd0d79c 100644
--- a/ui/android/java/src/org/chromium/ui/DropdownItem.java
+++ b/ui/android/java/src/org/chromium/ui/DropdownItem.java
@@ -48,6 +48,10 @@
      */
     int getLabelFontSizeResId();
     /**
+     * Returns resource ID of sublabel's font size.
+     */
+    int getSublabelFontSizeResId();
+    /**
      * Returns whether label and sublabel should be on the same line.
      */
     boolean isLabelAndSublabelOnSameLine();
@@ -56,4 +60,12 @@
      * and sublabel.
      */
     boolean isIconAtStart();
+    /**
+     * Returns the resource ID of the icon's size, or 0 to use WRAP_CONTENT.
+     */
+    int getIconSizeResId();
+    /**
+     * Returns the resource ID of the icon's margin size.
+     */
+    int getIconMarginResId();
 }
diff --git a/ui/android/java/src/org/chromium/ui/DropdownItemBase.java b/ui/android/java/src/org/chromium/ui/DropdownItemBase.java
index 9a0c7658..d53dbe81 100644
--- a/ui/android/java/src/org/chromium/ui/DropdownItemBase.java
+++ b/ui/android/java/src/org/chromium/ui/DropdownItemBase.java
@@ -55,6 +55,11 @@
     }
 
     @Override
+    public int getSublabelFontSizeResId() {
+        return R.dimen.dropdown_item_sublabel_font_size;
+    }
+
+    @Override
     public boolean isLabelAndSublabelOnSameLine() {
         return false;
     }
@@ -63,4 +68,14 @@
     public boolean isIconAtStart() {
         return false;
     }
+
+    @Override
+    public int getIconSizeResId() {
+        return 0;
+    }
+
+    @Override
+    public int getIconMarginResId() {
+        return R.dimen.dropdown_icon_margin;
+    }
 }
diff --git a/ui/events/blink/web_input_event_unittest.cc b/ui/events/blink/web_input_event_unittest.cc
index f3a4e52d..783d981 100644
--- a/ui/events/blink/web_input_event_unittest.cc
+++ b/ui/events/blink/web_input_event_unittest.cc
@@ -438,6 +438,8 @@
     EXPECT_EQ(0, webkit_event.tiltX);
     EXPECT_EQ(0, webkit_event.tiltY);
     EXPECT_TRUE(std::isnan(webkit_event.force));
+    EXPECT_EQ(0.0f, webkit_event.tangentialPressure);
+    EXPECT_EQ(0, webkit_event.twist);
     EXPECT_EQ(123, webkit_event.x);
     EXPECT_EQ(123, webkit_event.windowX);
     EXPECT_EQ(321, webkit_event.y);
@@ -464,6 +466,8 @@
     EXPECT_EQ(90, webkit_event.tiltX);
     EXPECT_EQ(-90, webkit_event.tiltY);
     EXPECT_FLOAT_EQ(0.8f, webkit_event.force);
+    EXPECT_EQ(0.0f, webkit_event.tangentialPressure);
+    EXPECT_EQ(0, webkit_event.twist);
     EXPECT_EQ(123, webkit_event.x);
     EXPECT_EQ(123, webkit_event.windowX);
     EXPECT_EQ(321, webkit_event.y);
@@ -496,6 +500,8 @@
     EXPECT_EQ(0, webkit_event.tiltX);
     EXPECT_EQ(0, webkit_event.tiltY);
     EXPECT_TRUE(std::isnan(webkit_event.force));
+    EXPECT_EQ(0.0f, webkit_event.tangentialPressure);
+    EXPECT_EQ(0, webkit_event.twist);
     EXPECT_EQ(123, webkit_event.x);
     EXPECT_EQ(123, webkit_event.windowX);
     EXPECT_EQ(321, webkit_event.y);
diff --git a/ui/login/account_picker/user_pod_row.js b/ui/login/account_picker/user_pod_row.js
index 50bfff4e..85e8297f 100644
--- a/ui/login/account_picker/user_pod_row.js
+++ b/ui/login/account_picker/user_pod_row.js
@@ -1534,6 +1534,7 @@
         case 'Meta':
           break;
         case 'Escape':
+          this.actionBoxAreaElement.focus();
           this.isActionBoxMenuActive = false;
           e.stopPropagation();
           break;
diff --git a/ui/views/background.cc b/ui/views/background.cc
index 56f1eb3..f8bf1b6 100644
--- a/ui/views/background.cc
+++ b/ui/views/background.cc
@@ -38,23 +38,19 @@
 
 class BackgroundPainter : public Background {
  public:
-  BackgroundPainter(bool owns_painter, Painter* painter)
-      : owns_painter_(owns_painter), painter_(painter) {
-    DCHECK(painter);
+  explicit BackgroundPainter(std::unique_ptr<Painter> painter)
+      : painter_(std::move(painter)) {
+    DCHECK(painter_);
   }
 
-  ~BackgroundPainter() override {
-    if (owns_painter_)
-      delete painter_;
-  }
+  ~BackgroundPainter() override {}
 
   void Paint(gfx::Canvas* canvas, View* view) const override {
-    Painter::PaintPainterAt(canvas, painter_, view->GetLocalBounds());
+    Painter::PaintPainterAt(canvas, painter_.get(), view->GetLocalBounds());
   }
 
  private:
-  bool owns_painter_;
-  Painter* painter_;
+  std::unique_ptr<Painter> painter_;
 
   DISALLOW_COPY_AND_ASSIGN(BackgroundPainter);
 };
@@ -85,8 +81,8 @@
 // static
 Background* Background::CreateVerticalGradientBackground(SkColor color1,
                                                          SkColor color2) {
-  Background* background = CreateBackgroundPainter(
-      true, Painter::CreateVerticalGradient(color1, color2));
+  Background* background =
+      CreateBackgroundPainter(Painter::CreateVerticalGradient(color1, color2));
   background->SetNativeControlColor(
       color_utils::AlphaBlend(color1, color2, 128));
 
@@ -94,22 +90,9 @@
 }
 
 // static
-Background* Background::CreateVerticalMultiColorGradientBackground(
-    SkColor* colors,
-    SkScalar* pos,
-    size_t count) {
-  Background* background = CreateBackgroundPainter(
-      true, Painter::CreateVerticalMultiColorGradient(colors, pos, count));
-  background->SetNativeControlColor(
-      color_utils::AlphaBlend(colors[0], colors[count-1], 128));
-
-  return background;
-}
-
-// static
-Background* Background::CreateBackgroundPainter(bool owns_painter,
-                                                Painter* painter) {
-  return new BackgroundPainter(owns_painter, painter);
+Background* Background::CreateBackgroundPainter(
+    std::unique_ptr<Painter> painter) {
+  return new BackgroundPainter(std::move(painter));
 }
 
 }  // namespace views
diff --git a/ui/views/background.h b/ui/views/background.h
index d00418a..c89185d 100644
--- a/ui/views/background.h
+++ b/ui/views/background.h
@@ -7,6 +7,8 @@
 
 #include <stddef.h>
 
+#include <memory>
+
 #include "base/macros.h"
 #include "build/build_config.h"
 #include "third_party/skia/include/core/SkColor.h"
@@ -60,22 +62,11 @@
   static Background* CreateVerticalGradientBackground(SkColor color1,
                                                       SkColor color2);
 
-  // Creates a background that contains a vertical gradient. The gradient can
-  // have multiple |colors|. The |pos| array contains the relative positions of
-  // each corresponding color. |colors| and |pos| must be the same size. The
-  // first element in |pos| must be 0.0 and the last element must be 1.0.
-  // |count| contains the number of elements in |colors| and |pos|.
-  static Background* CreateVerticalMultiColorGradientBackground(SkColor* colors,
-                                                                SkScalar* pos,
-                                                                size_t count);
-
   // Creates Chrome's standard panel background
   static Background* CreateStandardPanelBackground();
 
-  // Creates a Background from the specified Painter. If owns_painter is
-  // true, the Painter is deleted when the Border is deleted.
-  static Background* CreateBackgroundPainter(bool owns_painter,
-                                             Painter* painter);
+  // Creates a Background from the specified Painter.
+  static Background* CreateBackgroundPainter(std::unique_ptr<Painter> painter);
 
   // Render the background for the provided view
   virtual void Paint(gfx::Canvas* canvas, View* view) const = 0;
diff --git a/ui/views/bubble/bubble_border.cc b/ui/views/bubble/bubble_border.cc
index f932250..0aed6ef 100644
--- a/ui/views/bubble/bubble_border.cc
+++ b/ui/views/bubble/bubble_border.cc
@@ -42,7 +42,7 @@
   if (!border_image_ids)
     return;
 
-  border_painter.reset(Painter::CreateImageGridPainter(border_image_ids));
+  border_painter = Painter::CreateImageGridPainter(border_image_ids);
   ResourceBundle& rb = ResourceBundle::GetSharedInstance();
   border_thickness = rb.GetImageSkiaNamed(border_image_ids[0])->width();
 
diff --git a/ui/views/controls/button/label_button_border.cc b/ui/views/controls/button/label_button_border.cc
index bf8b5842..b1ff3a56 100644
--- a/ui/views/controls/button/label_button_border.cc
+++ b/ui/views/controls/button/label_button_border.cc
@@ -183,8 +183,8 @@
 
 void LabelButtonAssetBorder::SetPainter(bool focused,
                                         Button::ButtonState state,
-                                        Painter* painter) {
-  painters_[focused ? 1 : 0][state].reset(painter);
+                                        std::unique_ptr<Painter> painter) {
+  painters_[focused ? 1 : 0][state] = std::move(painter);
 }
 
 }  // namespace views
diff --git a/ui/views/controls/button/label_button_border.h b/ui/views/controls/button/label_button_border.h
index fabbde5e..cdb5dc1 100644
--- a/ui/views/controls/button/label_button_border.h
+++ b/ui/views/controls/button/label_button_border.h
@@ -58,7 +58,9 @@
   // Get or set the painter used for the specified |focused| button |state|.
   // LabelButtonAssetBorder takes and retains ownership of |painter|.
   Painter* GetPainter(bool focused, Button::ButtonState state);
-  void SetPainter(bool focused, Button::ButtonState state, Painter* painter);
+  void SetPainter(bool focused,
+                  Button::ButtonState state,
+                  std::unique_ptr<Painter> painter);
 
  private:
   // The painters used for each unfocused or focused button state.
diff --git a/ui/views/controls/button/md_text_button.cc b/ui/views/controls/button/md_text_button.cc
index 093ea26..af31410 100644
--- a/ui/views/controls/button/md_text_button.cc
+++ b/ui/views/controls/button/md_text_button.cc
@@ -299,8 +299,8 @@
 
   DCHECK_EQ(SK_AlphaOPAQUE, static_cast<int>(SkColorGetA(bg_color)));
   set_background(Background::CreateBackgroundPainter(
-      true, Painter::CreateRoundRectWith1PxBorderPainter(
-                bg_color, stroke_color, kInkDropSmallCornerRadius)));
+      Painter::CreateRoundRectWith1PxBorderPainter(bg_color, stroke_color,
+                                                   kInkDropSmallCornerRadius)));
 }
 
 }  // namespace views
diff --git a/ui/views/controls/combobox/combobox.cc b/ui/views/controls/combobox/combobox.cc
index d50f554..42b79d9 100644
--- a/ui/views/controls/combobox/combobox.cc
+++ b/ui/views/controls/combobox/combobox.cc
@@ -428,8 +428,8 @@
       size_t num;
       bool focused = !!i;
       const int* ids = GetBodyButtonImageIds(focused, state, &num);
-      body_button_painters_[focused][state].reset(
-          Painter::CreateImageGridPainter(ids));
+      body_button_painters_[focused][state] =
+          Painter::CreateImageGridPainter(ids);
       menu_button_images_[focused][state] = GetMenuButtonImages(focused, state);
     }
   }
@@ -553,11 +553,11 @@
   if (!UseMd())
     return;
 
-  set_background(Background::CreateBackgroundPainter(
-      true, Painter::CreateSolidRoundRectPainter(
-                theme->GetSystemColor(
-                    ui::NativeTheme::kColorId_TextfieldDefaultBackground),
-                FocusableBorder::kCornerRadiusDp)));
+  set_background(
+      Background::CreateBackgroundPainter(Painter::CreateSolidRoundRectPainter(
+          theme->GetSystemColor(
+              ui::NativeTheme::kColorId_TextfieldDefaultBackground),
+          FocusableBorder::kCornerRadiusDp)));
 }
 
 int Combobox::GetRowCount() {
diff --git a/ui/views/controls/textfield/textfield.cc b/ui/views/controls/textfield/textfield.cc
index 217bb57a..d15a3e3 100644
--- a/ui/views/controls/textfield/textfield.cc
+++ b/ui/views/controls/textfield/textfield.cc
@@ -1847,8 +1847,8 @@
   const SkColor color = GetBackgroundColor();
   if (ui::MaterialDesignController::IsSecondaryUiMaterial()) {
     set_background(Background::CreateBackgroundPainter(
-        true, Painter::CreateSolidRoundRectPainter(
-                  color, FocusableBorder::kCornerRadiusDp)));
+        Painter::CreateSolidRoundRectPainter(
+            color, FocusableBorder::kCornerRadiusDp)));
   } else {
     set_background(Background::CreateSolidBackground(color));
   }
diff --git a/ui/views/corewm/tooltip_aura.cc b/ui/views/corewm/tooltip_aura.cc
index 4cce40b..478becc2 100644
--- a/ui/views/corewm/tooltip_aura.cc
+++ b/ui/views/corewm/tooltip_aura.cc
@@ -126,8 +126,8 @@
     views::Background* background =
         CanUseTranslucentTooltipWidget()
             ? views::Background::CreateBackgroundPainter(
-                  true, views::Painter::CreateSolidRoundRectPainter(
-                            background_color, kTooltipCornerRadius))
+                  views::Painter::CreateSolidRoundRectPainter(
+                      background_color, kTooltipCornerRadius))
             : views::Background::CreateSolidBackground(background_color);
     set_background(background);
     // Force the text color to be readable when |background_color| is not
diff --git a/ui/views/painter.cc b/ui/views/painter.cc
index e2ac629c..c64a0d7 100644
--- a/ui/views/painter.cc
+++ b/ui/views/painter.cc
@@ -297,51 +297,42 @@
 }
 
 // static
-Painter* Painter::CreateSolidRoundRectPainter(SkColor color, float radius) {
-  return new SolidRoundRectPainter(color, SK_ColorTRANSPARENT, radius);
+std::unique_ptr<Painter> Painter::CreateSolidRoundRectPainter(SkColor color,
+                                                              float radius) {
+  return base::MakeUnique<SolidRoundRectPainter>(color, SK_ColorTRANSPARENT,
+                                                 radius);
 }
 
 // static
-Painter* Painter::CreateRoundRectWith1PxBorderPainter(SkColor bg_color,
-                                                      SkColor stroke_color,
-                                                      float radius) {
-  return new SolidRoundRectPainter(bg_color, stroke_color, radius);
+std::unique_ptr<Painter> Painter::CreateRoundRectWith1PxBorderPainter(
+    SkColor bg_color,
+    SkColor stroke_color,
+    float radius) {
+  return base::MakeUnique<SolidRoundRectPainter>(bg_color, stroke_color,
+                                                 radius);
 }
 
 // static
-Painter* Painter::CreateHorizontalGradient(SkColor c1, SkColor c2) {
+std::unique_ptr<Painter> Painter::CreateVerticalGradient(SkColor c1,
+                                                         SkColor c2) {
   SkColor colors[2];
   colors[0] = c1;
   colors[1] = c2;
   SkScalar pos[] = {0, 1};
-  return new GradientPainter(true, colors, pos, 2);
+  return base::MakeUnique<GradientPainter>(false, colors, pos, 2);
 }
 
 // static
-Painter* Painter::CreateVerticalGradient(SkColor c1, SkColor c2) {
-  SkColor colors[2];
-  colors[0] = c1;
-  colors[1] = c2;
-  SkScalar pos[] = {0, 1};
-  return new GradientPainter(false, colors, pos, 2);
+std::unique_ptr<Painter> Painter::CreateImagePainter(
+    const gfx::ImageSkia& image,
+    const gfx::Insets& insets) {
+  return base::MakeUnique<ImagePainter>(image, insets);
 }
 
 // static
-Painter* Painter::CreateVerticalMultiColorGradient(SkColor* colors,
-                                                   SkScalar* pos,
-                                                   size_t count) {
-  return new GradientPainter(false, colors, pos, count);
-}
-
-// static
-Painter* Painter::CreateImagePainter(const gfx::ImageSkia& image,
-                                     const gfx::Insets& insets) {
-  return new ImagePainter(image, insets);
-}
-
-// static
-Painter* Painter::CreateImageGridPainter(const int image_ids[]) {
-  return new ImagePainter(image_ids);
+std::unique_ptr<Painter> Painter::CreateImageGridPainter(
+    const int image_ids[]) {
+  return base::MakeUnique<ImagePainter>(image_ids);
 }
 
 // static
diff --git a/ui/views/painter.h b/ui/views/painter.h
index f158c92..a018e04 100644
--- a/ui/views/painter.h
+++ b/ui/views/painter.h
@@ -50,39 +50,34 @@
 
   // Creates a painter that draws a RoundRect with a solid color and given
   // corner radius.
-  static Painter* CreateSolidRoundRectPainter(SkColor color, float radius);
+  static std::unique_ptr<Painter> CreateSolidRoundRectPainter(SkColor color,
+                                                              float radius);
 
   // Creates a painter that draws a RoundRect with a solid color and a given
   // corner radius, and also adds a 1px border (inset) in the given color.
-  static Painter* CreateRoundRectWith1PxBorderPainter(SkColor bg_color,
-                                                      SkColor stroke_color,
-                                                      float radius);
+  static std::unique_ptr<Painter> CreateRoundRectWith1PxBorderPainter(
+      SkColor bg_color,
+      SkColor stroke_color,
+      float radius);
 
-  // Creates a painter that draws a gradient between the two colors.
-  static Painter* CreateHorizontalGradient(SkColor c1, SkColor c2);
-  static Painter* CreateVerticalGradient(SkColor c1, SkColor c2);
-
-  // Creates a painter that draws a multi-color gradient. |colors| contains the
-  // gradient colors and |pos| the relative positions of the colors. The first
-  // element in |pos| must be 0.0 and the last element 1.0. |count| contains
-  // the number of elements in |colors| and |pos|.
-  static Painter* CreateVerticalMultiColorGradient(SkColor* colors,
-                                                   SkScalar* pos,
-                                                   size_t count);
+  // TODO(estade): remove. The last client (table_header.cc) is going away soon.
+  static std::unique_ptr<Painter> CreateVerticalGradient(SkColor c1,
+                                                         SkColor c2);
 
   // Creates a painter that divides |image| into nine regions. The four corners
   // are rendered at the size specified in insets (eg. the upper-left corner is
   // rendered at 0 x 0 with a size of insets.left() x insets.top()). The center
   // and edge images are stretched to fill the painted area.
-  static Painter* CreateImagePainter(const gfx::ImageSkia& image,
-                                     const gfx::Insets& insets);
+  static std::unique_ptr<Painter> CreateImagePainter(
+      const gfx::ImageSkia& image,
+      const gfx::Insets& insets);
 
   // Creates a painter that paints images in a scalable grid. The images must
   // share widths by column and heights by row. The corners are painted at full
   // size, while center and edge images are stretched to fill the painted area.
   // The center image may be zero (to be skipped). This ordering must be used:
   // Top-Left/Top/Top-Right/Left/[Center]/Right/Bottom-Left/Bottom/Bottom-Right.
-  static Painter* CreateImageGridPainter(const int image_ids[]);
+  static std::unique_ptr<Painter> CreateImageGridPainter(const int image_ids[]);
 
   // Factory methods for creating painters intended for rendering focus.
   static std::unique_ptr<Painter> CreateDashedFocusPainter();
diff --git a/ui/webui/resources/cr_elements/network/compiled_resources2.gyp b/ui/webui/resources/cr_elements/network/compiled_resources2.gyp
index ee80363a..b77b35b 100644
--- a/ui/webui/resources/cr_elements/network/compiled_resources2.gyp
+++ b/ui/webui/resources/cr_elements/network/compiled_resources2.gyp
@@ -29,8 +29,6 @@
       'dependencies': [
         '<(DEPTH)/ui/webui/resources/cr_elements/policy/compiled_resources2.gyp:cr_policy_network_behavior',
         '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:assert',
-        '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:i18n_behavior',
-        '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:load_time_data',
         'cr_network_list_types',
         'cr_onc_types',
       ],
@@ -55,7 +53,6 @@
     {
       'target_name': 'cr_onc_types',
       'dependencies': [
-        '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:i18n_behavior',
         '<(EXTERNS_GYP):networking_private',
       ],
       'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
diff --git a/ui/webui/resources/cr_elements/network/cr_network_list_item.html b/ui/webui/resources/cr_elements/network/cr_network_list_item.html
index 44c563d..88a6d9c 100644
--- a/ui/webui/resources/cr_elements/network/cr_network_list_item.html
+++ b/ui/webui/resources/cr_elements/network/cr_network_list_item.html
@@ -7,7 +7,6 @@
 <link rel="import" href="chrome://resources/cr_elements/policy/cr_policy_network_behavior.html">
 <link rel="import" href="chrome://resources/cr_elements/policy/cr_policy_network_indicator.html">
 <link rel="import" href="chrome://resources/cr_elements/shared_style_css.html">
-<link rel="import" href="chrome://resources/html/i18n_behavior.html">
 
 <dom-module id="cr-network-list-item">
   <template>
diff --git a/ui/webui/resources/cr_elements/network/cr_network_list_item.js b/ui/webui/resources/cr_elements/network/cr_network_list_item.js
index 4528e03..a54ddf3 100644
--- a/ui/webui/resources/cr_elements/network/cr_network_list_item.js
+++ b/ui/webui/resources/cr_elements/network/cr_network_list_item.js
@@ -57,7 +57,7 @@
     },
   },
 
-  behaviors: [I18nBehavior, CrPolicyNetworkBehavior],
+  behaviors: [CrPolicyNetworkBehavior],
 
   /** @private */
   itemChanged_: function() {
@@ -85,14 +85,14 @@
     if (this.item.hasOwnProperty('customItemName')) {
       let item = /** @type {!CrNetworkList.CustomItemState} */ (this.item);
       let name = item.customItemName || '';
-      if (this.i18nExists(item.customItemName))
-        name = this.i18n(item.customItemName);
+      if (CrOncStrings.hasOwnProperty(item.customItemName))
+        name = CrOncStrings[item.customItemName];
       return name;
     }
     let network = /** @type {!CrOnc.NetworkStateProperties} */ (this.item);
     if (this.isListItem)
-      return CrOnc.getNetworkName(network, this);
-    return this.i18n('OncType' + network.Type);
+      return CrOnc.getNetworkName(network);
+    return CrOncStrings['OncType' + network.Type];
   },
 
   /** @private */
@@ -115,33 +115,33 @@
     let network = this.networkState;
     if (this.isListItem) {
       if (this.isConnected_())
-        return this.i18n('networkListItemConnected');
+        return CrOncStrings.networkListItemConnected;
       return '';
     }
     if (network.Name && network.ConnectionState) {
       return this.getConnectionStateText_(
-          network.ConnectionState, CrOnc.getNetworkName(network, this));
+          network.ConnectionState, CrOnc.getNetworkName(network));
     }
-    return this.i18n('networkDisabled');
+    return CrOncStrings.networkDisabled;
   },
 
   /**
    * Returns the appropriate connection state text.
-   * @param {string} state The connection state.
+   * @param {CrOnc.ConnectionState} state The connection state.
    * @param {string} name The name of the network.
    * @return {string}
    * @private
    */
   getConnectionStateText_: function(state, name) {
-    if (state == CrOnc.ConnectionState.CONNECTED)
-      return name;
-    if (state == CrOnc.ConnectionState.CONNECTING)
-      return this.i18n('networkListItemConnecting', name);
-    if (state == CrOnc.ConnectionState.NOT_CONNECTED)
-      return this.i18n('networkListItemNotConnected');
-    // TODO(stevenjb): Audit state translations and remove test.
-    if (this.i18nExists(state))
-      return this.i18n(state);
+    switch (state) {
+      case CrOnc.ConnectionState.CONNECTED:
+        return name;
+      case CrOnc.ConnectionState.CONNECTING:
+        return CrOncStrings.networkListItemConnecting.replace('$1', name);
+      case CrOnc.ConnectionState.NOT_CONNECTED:
+        return CrOncStrings.networkListItemNotConnected;
+    }
+    assertNotReached();
     return state;
   },
 
diff --git a/ui/webui/resources/cr_elements/network/cr_network_select.js b/ui/webui/resources/cr_elements/network/cr_network_select.js
index d799bd7..dee8c87 100644
--- a/ui/webui/resources/cr_elements/network/cr_network_select.js
+++ b/ui/webui/resources/cr_elements/network/cr_network_select.js
@@ -10,8 +10,6 @@
 Polymer({
   is: 'cr-network-select',
 
-  behaviors: [I18nBehavior],
-
   properties: {
     /**
      * Show all buttons in list items.
diff --git a/ui/webui/resources/cr_elements/network/cr_onc_types.js b/ui/webui/resources/cr_elements/network/cr_onc_types.js
index 3e5a2d85..f7f37e3 100644
--- a/ui/webui/resources/cr_elements/network/cr_onc_types.js
+++ b/ui/webui/resources/cr_elements/network/cr_onc_types.js
@@ -3,18 +3,37 @@
 // found in the LICENSE file.
 
 /**
- * @fileoverview This file has two parts:
+ * @fileoverview This file has three parts:
  *
- * 1. Typedefs for network properties. Note: These 'types' define a subset of
+ * 1. A dictionary of strings for network element translations.
+ *
+ * 2. Typedefs for network properties. Note: These 'types' define a subset of
  * ONC properties in the ONC data dictionary. The first letter is capitalized to
  * match the ONC spec and avoid an extra layer of translation.
  * See components/onc/docs/onc_spec.html for the complete spec.
  * TODO(stevenjb): Replace with chrome.networkingPrivate.NetworkStateProperties
  * once that is fully defined.
  *
- * 2. Helper functions to facilitate extracting and setting ONC properties.
+ * 3. Helper functions to facilitate extracting and setting ONC properties.
  */
 
+/**
+ * Strings required for networking elements. These must be set at runtime.
+ * @type {{
+ *   OncTypeCellular: string,
+ *   OncTypeEthernet: string,
+ *   OncTypeVPN: string,
+ *   OncTypeWiFi: string,
+ *   OncTypeWiMAX: string,
+ *   networkDisabled: string,
+ *   networkListItemConnected: string,
+ *   networkListItemConnecting: string,
+ *   networkListItemNotConnected: string,
+ *   vpnNameTemplate: string,
+ * }}
+ */
+var CrOncStrings;
+
 var CrOnc = {};
 
 /** @typedef {chrome.networkingPrivate.NetworkStateProperties} */
@@ -80,10 +99,19 @@
 /** @typedef {chrome.networkingPrivate.PaymentPortal} */
 CrOnc.PaymentPortal;
 
+/** @enum {string} */
 CrOnc.ActivationState = chrome.networkingPrivate.ActivationStateType;
+
+/** @enum {string} */
 CrOnc.ConnectionState = chrome.networkingPrivate.ConnectionStateType;
+
+/** @enum {string} */
 CrOnc.IPConfigType = chrome.networkingPrivate.IPConfigType;
+
+/** @enum {string} */
 CrOnc.ProxySettingsType = chrome.networkingPrivate.ProxySettingsType;
+
+/** @enum {string} */
 CrOnc.Type = chrome.networkingPrivate.NetworkType;
 
 /** @enum {string} */
@@ -321,22 +349,23 @@
 /**
  * @param {!CrOnc.NetworkProperties|!CrOnc.NetworkStateProperties|undefined}
  *     properties The ONC network properties or state properties.
- * @param {!I18nBehavior.Proto} i18nBehavior An I18nBehavior instance.
  * @return {string} The name to display for |network|.
  */
-CrOnc.getNetworkName = function(properties, i18nBehavior) {
+CrOnc.getNetworkName = function(properties) {
   if (!properties)
     return '';
   let name = CrOnc.getStateOrActiveString(properties.Name);
   let type = CrOnc.getStateOrActiveString(properties.Type);
   if (!name)
-    return i18nBehavior.i18n('OncType' + type);
+    return CrOncStrings['OncType' + type];
   if (type == 'VPN' && properties.VPN) {
     let vpnType = CrOnc.getStateOrActiveString(properties.VPN.Type);
     if (vpnType == 'ThirdPartyVPN' && properties.VPN.ThirdPartyVPN) {
       let providerName = properties.VPN.ThirdPartyVPN.ProviderName;
-      if (providerName)
-        return i18nBehavior.i18n('vpnNameTemplate', providerName, name);
+      if (providerName) {
+        return CrOncStrings.vpnNameTemplate.replace('$1', providerName)
+            .replace('$2', name);
+      }
     }
   }
   return name;