diff --git a/BUILD.gn b/BUILD.gn
index ff313e6..dc6b3d3 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -130,7 +130,6 @@
       "//base:base_unittests",
       "//chrome/test:browser_tests",
       "//chrome/test:sync_integration_tests",
-      "//components/sync:sync_unit_tests",
       "//ipc:ipc_tests",
       "//media:media_unittests",
       "//media/midi:midi_unittests",
@@ -185,7 +184,6 @@
     "//base:base_unittests",
     "//chrome/installer",
     "//components:components_unittests",
-    "//components/sync:sync_unit_tests",
     "//net:net_unittests",
     "//skia:skia_unittests",
     "//sql:sql_unittests",
diff --git a/DEPS b/DEPS
index 2431f726..2874103 100644
--- a/DEPS
+++ b/DEPS
@@ -36,11 +36,11 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling Skia
   # and whatever else without interference from each other.
-  'skia_revision': '2825bad08cc2ad63f0f11f50039c944914d07e0a',
+  'skia_revision': 'ac09554dce518e9d4496771f648f3ae17eca857c',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling V8
   # and whatever else without interference from each other.
-  'v8_revision': '17edea67a345a36f19a6ef15dd34edb2c88b2cc1',
+  'v8_revision': '61be62536ea2689143396ddca6047016be8be5d2',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling swarming_client
   # and whatever else without interference from each other.
@@ -52,11 +52,11 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling build tools
   # and whatever else without interference from each other.
-  'buildtools_revision': '88c6fc5bde77b9477345f0885cd88d4a57ad1844',
+  'buildtools_revision': '9c6ad6f5cbc2f30989edc3504ec7f9d360542512',
   # 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': 'a72ab5e0908ca29cfda91b3037da9b74cb06b93f',
+  'pdfium_revision': '32e693fe13105fab5baf81b334e932fce62d89b5',
   # 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.
@@ -88,7 +88,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling catapult
   # and whatever else without interference from each other.
-  'catapult_revision': 'd7bc1bf8cb0bcbf2dd998828cc65486b901db11d',
+  'catapult_revision': 'd99dc42eec5fb0068857eb9e921940105a3e2a7d',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libFuzzer
   # and whatever else without interference from each other.
@@ -178,7 +178,7 @@
     Var('chromium_git') + '/external/bidichecker/lib.git' + '@' + '97f2aa645b74c28c57eca56992235c79850fa9e0',
 
   'src/third_party/webgl/src':
-   Var('chromium_git') + '/external/khronosgroup/webgl.git' + '@' + 'e3488c31e13202c8d41b92eb6b7358cd23e5e004',
+   Var('chromium_git') + '/external/khronosgroup/webgl.git' + '@' + 'b57946dc8d26325c332f3644c646dcc795c68bdc',
 
   'src/third_party/webdriver/pylib':
     Var('chromium_git') + '/external/selenium/py.git' + '@' + '5fd78261a75fe08d27ca4835fb6c5ce4b42275bd',
diff --git a/android_webview/browser/surfaces_instance.h b/android_webview/browser/surfaces_instance.h
index eb01f71..5dec3d8b 100644
--- a/android_webview/browser/surfaces_instance.h
+++ b/android_webview/browser/surfaces_instance.h
@@ -61,6 +61,10 @@
   // cc::DisplayClient overrides.
   void DisplayOutputSurfaceLost() override {}
   void DisplaySetMemoryPolicy(const cc::ManagedMemoryPolicy& policy) override {}
+  void DisplayWillDrawAndSwap(
+      bool will_draw_and_swap,
+      const cc::RenderPassList& render_passes) override {}
+  void DisplayDidDrawAndSwap() override {}
 
   // cc::SurfaceFactoryClient implementation.
   void ReturnResources(const cc::ReturnedResourceArray& resources) override;
diff --git a/android_webview/native/aw_autofill_client.cc b/android_webview/native/aw_autofill_client.cc
index f149041..be7a4ae 100644
--- a/android_webview/native/aw_autofill_client.cc
+++ b/android_webview/native/aw_autofill_client.cc
@@ -242,6 +242,12 @@
   NOTIMPLEMENTED();
 }
 
+void AwAutofillClient::ConfirmCreditCardFillAssist(
+    const autofill::CreditCard& card,
+    const base::Closure& callback) {
+  NOTIMPLEMENTED();
+}
+
 void AwAutofillClient::LoadRiskData(
     const base::Callback<void(const std::string&)>& callback) {
   NOTIMPLEMENTED();
diff --git a/android_webview/native/aw_autofill_client.h b/android_webview/native/aw_autofill_client.h
index ca4119d..ec350f5 100644
--- a/android_webview/native/aw_autofill_client.h
+++ b/android_webview/native/aw_autofill_client.h
@@ -78,6 +78,8 @@
       const autofill::CreditCard& card,
       std::unique_ptr<base::DictionaryValue> legal_message,
       const base::Closure& callback) override;
+  void ConfirmCreditCardFillAssist(const autofill::CreditCard& card,
+                                   const base::Closure& callback) override;
   void LoadRiskData(
       const base::Callback<void(const std::string&)>& callback) override;
   bool HasCreditCardScanFeature() override;
diff --git a/apps/DEPS b/apps/DEPS
index d1ec499..f524516 100644
--- a/apps/DEPS
+++ b/apps/DEPS
@@ -45,9 +45,11 @@
   "(.*test\.cc|.*test_mac\.mm)": [
     "+chrome/browser/browser_shutdown.h",
     "+chrome/browser/extensions/extension_browsertest.h",
+    "+chrome/browser/extensions/extension_error_reporter.h",
     "+chrome/browser/extensions/extension_test_message_listener.h",
     "+chrome/browser/extensions/test_extension_environment.h",
     "+chrome/browser/ui/browser.h",
+    "+chrome/browser/ui/simple_message_box_internal.h",
     "+chrome/test/base/in_process_browser_test.h",
     "+chrome/test/base/interactive_test_utils.h",
     "+chrome/test/base/testing_profile.h",
diff --git a/apps/app_load_service.cc b/apps/app_load_service.cc
index eb4b5c6..c89a369 100644
--- a/apps/app_load_service.cc
+++ b/apps/app_load_service.cc
@@ -64,8 +64,9 @@
   ExtensionService* extension_service =
       ExtensionSystem::Get(profile_)->extension_service();
   std::string extension_id;
-  if (!extensions::UnpackedInstaller::Create(extension_service)->
-          LoadFromCommandLine(base::FilePath(extension_path), &extension_id)) {
+  if (!extensions::UnpackedInstaller::Create(extension_service)
+           ->LoadFromCommandLine(base::FilePath(extension_path), &extension_id,
+                                 true /* only_allow_apps */)) {
     return false;
   }
 
@@ -81,8 +82,9 @@
   ExtensionService* extension_service =
       ExtensionSystem::Get(profile_)->extension_service();
   std::string extension_id;
-  return extensions::UnpackedInstaller::Create(extension_service)->
-      LoadFromCommandLine(base::FilePath(extension_path), &extension_id);
+  return extensions::UnpackedInstaller::Create(extension_service)
+      ->LoadFromCommandLine(base::FilePath(extension_path), &extension_id,
+                            true /* only_allow_apps */);
 }
 
 // static
diff --git a/apps/load_and_launch_browsertest.cc b/apps/load_and_launch_browsertest.cc
index fc95dae..330a4f44 100644
--- a/apps/load_and_launch_browsertest.cc
+++ b/apps/load_and_launch_browsertest.cc
@@ -8,13 +8,17 @@
 
 #include "apps/switches.h"
 #include "base/process/launch.h"
+#include "base/strings/utf_string_conversions.h"
 #include "base/test/test_timeouts.h"
 #include "chrome/browser/apps/app_browsertest_util.h"
 #include "chrome/browser/extensions/extension_browsertest.h"
+#include "chrome/browser/extensions/extension_error_reporter.h"
 #include "chrome/browser/profiles/profile_manager.h"
+#include "chrome/browser/ui/simple_message_box_internal.h"
 #include "chrome/common/chrome_switches.h"
 #include "content/public/common/content_switches.h"
 #include "content/public/test/test_launcher.h"
+#include "extensions/browser/extension_registry.h"
 #include "extensions/test/extension_test_message_listener.h"
 
 using extensions::PlatformAppBrowserTest;
@@ -28,6 +32,8 @@
     switches::kNoSandbox,
 };
 
+constexpr char kTestExtensionId[] = "behllobkkfkfnphdnhnkndlbkcpglgmj";
+
 }  // namespace
 
 // TODO(jackhou): Enable this test once it works on OSX. It currently does not
@@ -112,18 +118,17 @@
 
 namespace {
 
-// TestFixture that appends --load-and-launch-app before calling BrowserMain.
-class PlatformAppLoadAndLaunchBrowserTest : public PlatformAppBrowserTest {
+// TestFixture that appends --load-and-launch-app with an app before calling
+// BrowserMain.
+class LoadAndLaunchPlatformAppBrowserTest : public PlatformAppBrowserTest {
  protected:
-  PlatformAppLoadAndLaunchBrowserTest() {}
+  LoadAndLaunchPlatformAppBrowserTest() {}
 
   void SetUpCommandLine(base::CommandLine* command_line) override {
     PlatformAppBrowserTest::SetUpCommandLine(command_line);
-    app_path_ = test_data_dir_
-        .AppendASCII("platform_apps")
-        .AppendASCII("minimal");
-    command_line->AppendSwitchNative(apps::kLoadAndLaunchApp,
-                                     app_path_.value());
+    base::FilePath app_path =
+        test_data_dir_.AppendASCII("platform_apps").AppendASCII("minimal");
+    command_line->AppendSwitchNative(apps::kLoadAndLaunchApp, app_path.value());
   }
 
   void LoadAndLaunchApp() {
@@ -136,9 +141,32 @@
   }
 
  private:
-  base::FilePath app_path_;
+  DISALLOW_COPY_AND_ASSIGN(LoadAndLaunchPlatformAppBrowserTest);
+};
 
-  DISALLOW_COPY_AND_ASSIGN(PlatformAppLoadAndLaunchBrowserTest);
+// TestFixture that appends --load-and-launch-app with an extension before
+// calling BrowserMain.
+class LoadAndLaunchExtensionBrowserTest : public PlatformAppBrowserTest {
+ protected:
+  LoadAndLaunchExtensionBrowserTest() {}
+
+  void SetUpCommandLine(base::CommandLine* command_line) override {
+    PlatformAppBrowserTest::SetUpCommandLine(command_line);
+    base::FilePath app_path = test_data_dir_.AppendASCII("good")
+                                  .AppendASCII("Extensions")
+                                  .AppendASCII(kTestExtensionId)
+                                  .AppendASCII("1.0.0.0");
+    command_line->AppendSwitchNative(apps::kLoadAndLaunchApp, app_path.value());
+  }
+
+  void SetUpInProcessBrowserTestFixture() override {
+    PlatformAppBrowserTest::SetUpInProcessBrowserTestFixture();
+
+    // Skip showing the error message box to avoid freezing the main thread.
+    chrome::internal::g_should_skip_message_box_for_test = true;
+  }
+
+  DISALLOW_COPY_AND_ASSIGN(LoadAndLaunchExtensionBrowserTest);
 };
 
 }  // namespace
@@ -155,9 +183,32 @@
 #endif
 
 // Case where Chrome is not running.
-IN_PROC_BROWSER_TEST_F(PlatformAppLoadAndLaunchBrowserTest,
+IN_PROC_BROWSER_TEST_F(LoadAndLaunchPlatformAppBrowserTest,
                        MAYBE_LoadAndLaunchAppChromeNotRunning) {
   LoadAndLaunchApp();
 }
 
+IN_PROC_BROWSER_TEST_F(LoadAndLaunchExtensionBrowserTest,
+                       LoadAndLaunchExtension) {
+  const std::vector<base::string16>* errors =
+      ExtensionErrorReporter::GetInstance()->GetErrors();
+
+#if defined(GOOGLE_CHROME_BUILD)
+  // The error is skipped on official builds.
+  EXPECT_TRUE(errors->empty());
+#else
+  // Expect |extension_instead_of_app_error|.
+  EXPECT_EQ(1u, errors->size());
+  EXPECT_NE(base::string16::npos,
+            errors->at(0).find(base::ASCIIToUTF16(
+                "App loading flags cannot be used to load extensions")));
+#endif
+
+  extensions::ExtensionRegistry* registry =
+      extensions::ExtensionRegistry::Get(profile());
+  EXPECT_EQ(nullptr,
+            registry->GetExtensionById(
+                kTestExtensionId, extensions::ExtensionRegistry::EVERYTHING));
+}
+
 }  // namespace apps
diff --git a/ash/mus/window_manager_application.cc b/ash/mus/window_manager_application.cc
index 8e6aec9..66aab81 100644
--- a/ash/mus/window_manager_application.cc
+++ b/ash/mus/window_manager_application.cc
@@ -78,7 +78,7 @@
   // Destroy the WindowManager while still valid. This way we ensure
   // OnWillDestroyRootWindowController() is called (if it hasn't been already).
   window_manager_.reset();
-
+  gpu_service_.reset();
   ShutdownComponents();
 }
 
@@ -96,7 +96,7 @@
 }
 
 void WindowManagerApplication::OnStart(const shell::Identity& identity) {
-  ui::GpuService::Initialize(connector());
+  gpu_service_ = ui::GpuService::Initialize(connector());
   window_manager_.reset(new WindowManager(connector()));
 
   aura_init_.reset(new views::AuraInit(connector(), "ash_mus_resources.pak"));
diff --git a/ash/mus/window_manager_application.h b/ash/mus/window_manager_application.h
index d2f4d27b..15b6d88 100644
--- a/ash/mus/window_manager_application.h
+++ b/ash/mus/window_manager_application.h
@@ -28,6 +28,7 @@
 
 namespace ui {
 class Event;
+class GpuService;
 class WindowTreeClient;
 }
 
@@ -108,6 +109,7 @@
   std::vector<mojo::InterfaceRequest<mojom::UserWindowController>>
       user_window_controller_requests_;
 
+  std::unique_ptr<ui::GpuService> gpu_service_;
   std::unique_ptr<WindowManager> window_manager_;
 
   std::set<AcceleratorRegistrarImpl*> accelerator_registrars_;
diff --git a/ash/shelf/shelf_layout_manager.cc b/ash/shelf/shelf_layout_manager.cc
index 512b88fa..737785cb 100644
--- a/ash/shelf/shelf_layout_manager.cc
+++ b/ash/shelf/shelf_layout_manager.cc
@@ -194,8 +194,7 @@
 // ShelfLayoutManager ----------------------------------------------------------
 
 ShelfLayoutManager::ShelfLayoutManager(ShelfWidget* shelf_widget)
-    : SnapToPixelLayoutManager(shelf_widget->GetNativeView()->parent()),
-      root_window_(shelf_widget->GetNativeView()->GetRootWindow()),
+    : root_window_(shelf_widget->GetNativeView()->GetRootWindow()),
       updating_bounds_(false),
       shelf_widget_(shelf_widget),
       workspace_controller_(NULL),
@@ -500,20 +499,21 @@
 }
 
 ////////////////////////////////////////////////////////////////////////////////
-// ShelfLayoutManager, aura::LayoutManager implementation:
+// ShelfLayoutManager, wm::WmSnapToPixelLayoutManager implementation:
 
 void ShelfLayoutManager::OnWindowResized() {
   LayoutShelf();
 }
 
-void ShelfLayoutManager::SetChildBounds(aura::Window* child,
+void ShelfLayoutManager::SetChildBounds(WmWindow* child,
                                         const gfx::Rect& requested_bounds) {
-  SnapToPixelLayoutManager::SetChildBounds(child, requested_bounds);
+  wm::WmSnapToPixelLayoutManager::SetChildBounds(child, requested_bounds);
   // We may contain other widgets (such as frame maximize bubble) but they don't
   // effect the layout in anyway.
   if (!updating_bounds_ &&
-      ((shelf_widget_->GetNativeView() == child) ||
-       (shelf_widget_->status_area_widget()->GetNativeView() == child))) {
+      ((WmLookup::Get()->GetWindowForWidget(shelf_widget_) == child) ||
+       (WmLookup::Get()->GetWindowForWidget(
+            shelf_widget_->status_area_widget()) == child))) {
     LayoutShelf();
   }
 }
diff --git a/ash/shelf/shelf_layout_manager.h b/ash/shelf/shelf_layout_manager.h
index ebaa60a..1aa5039 100644
--- a/ash/shelf/shelf_layout_manager.h
+++ b/ash/shelf/shelf_layout_manager.h
@@ -14,10 +14,10 @@
 #include "ash/common/wm/background_animator.h"
 #include "ash/common/wm/dock/docked_window_layout_manager_observer.h"
 #include "ash/common/wm/lock_state_observer.h"
+#include "ash/common/wm/wm_snap_to_pixel_layout_manager.h"
 #include "ash/common/wm/workspace/workspace_types.h"
 #include "ash/common/wm_activation_observer.h"
 #include "ash/shelf/shelf_widget.h"
-#include "ash/snap_to_pixel_layout_manager.h"
 #include "ash/wm/gestures/shelf_gesture_handler.h"
 #include "base/macros.h"
 #include "base/observer_list.h"
@@ -52,7 +52,7 @@
       public DockedWindowLayoutManagerObserver,
       public keyboard::KeyboardControllerObserver,
       public LockStateObserver,
-      public SnapToPixelLayoutManager,
+      public wm::WmSnapToPixelLayoutManager,
       public SessionStateObserver {
  public:
   explicit ShelfLayoutManager(ShelfWidget* shelf_widget);
@@ -131,9 +131,9 @@
   // shelf. Specifying 0 leads to use the default.
   void SetAnimationDurationOverride(int duration_override_in_ms);
 
-  // Overridden from SnapLayoutManager:
+  // Overridden from wm::WmSnapToPixelLayoutManager:
   void OnWindowResized() override;
-  void SetChildBounds(aura::Window* child,
+  void SetChildBounds(WmWindow* child,
                       const gfx::Rect& requested_bounds) override;
 
   // Overridden from ShellObserver:
diff --git a/ash/shelf/shelf_widget.cc b/ash/shelf/shelf_widget.cc
index 4a9d08f..d57e62c 100644
--- a/ash/shelf/shelf_widget.cc
+++ b/ash/shelf/shelf_widget.cc
@@ -24,6 +24,7 @@
 #include "ash/shell.h"
 #include "ash/wm/status_area_layout_manager.h"
 #include "ash/wm/workspace_controller.h"
+#include "base/memory/ptr_util.h"
 #include "grit/ash_resources.h"
 #include "ui/aura/window.h"
 #include "ui/base/resource/resource_bundle.h"
@@ -364,9 +365,7 @@
 
   shelf_layout_manager_ = new ShelfLayoutManager(this);
   shelf_layout_manager_->AddObserver(this);
-  aura::Window* shelf_container =
-      WmWindowAura::GetAuraWindow(wm_shelf_container);
-  shelf_container->SetLayoutManager(shelf_layout_manager_);
+  wm_shelf_container->SetLayoutManager(base::WrapUnique(shelf_layout_manager_));
   shelf_layout_manager_->set_workspace_controller(workspace_controller);
   workspace_controller->SetShelf(shelf_layout_manager_);
   background_animator_.PaintBackground(
@@ -382,12 +381,13 @@
     status_area_widget_->Show();
   WmShell::Get()->focus_cycler()->AddWidget(status_area_widget_);
   background_animator_.AddObserver(status_area_widget_);
+  wm_status_container->SetLayoutManager(
+      base::MakeUnique<StatusAreaLayoutManager>(this));
 
+  aura::Window* shelf_container =
+      WmWindowAura::GetAuraWindow(wm_shelf_container);
   aura::Window* status_container =
       WmWindowAura::GetAuraWindow(wm_status_container);
-  status_container->SetLayoutManager(
-      new StatusAreaLayoutManager(status_container, this));
-
   shelf_container->SetEventTargeter(std::unique_ptr<ui::EventTargeter>(
       new ShelfWindowTargeter(shelf_container, shelf_layout_manager_)));
   status_container->SetEventTargeter(std::unique_ptr<ui::EventTargeter>(
diff --git a/ash/wm/status_area_layout_manager.cc b/ash/wm/status_area_layout_manager.cc
index 8eb8bc2..7c3a0fd2 100644
--- a/ash/wm/status_area_layout_manager.cc
+++ b/ash/wm/status_area_layout_manager.cc
@@ -5,20 +5,19 @@
 #include "ash/wm/status_area_layout_manager.h"
 
 #include "ash/common/system/status_area_widget.h"
+#include "ash/common/wm_lookup.h"
+#include "ash/common/wm_window.h"
 #include "ash/shelf/shelf_layout_manager.h"
 #include "ash/shelf/shelf_widget.h"
 #include "base/auto_reset.h"
-#include "ui/aura/window.h"
-#include "ui/views/widget/widget.h"
 
 namespace ash {
 
 ////////////////////////////////////////////////////////////////////////////////
 // StatusAreaLayoutManager, public:
 
-StatusAreaLayoutManager::StatusAreaLayoutManager(aura::Window* container,
-                                                 ShelfWidget* shelf)
-    : SnapToPixelLayoutManager(container), in_layout_(false), shelf_(shelf) {}
+StatusAreaLayoutManager::StatusAreaLayoutManager(ShelfWidget* shelf_widget)
+    : in_layout_(false), shelf_widget_(shelf_widget) {}
 
 StatusAreaLayoutManager::~StatusAreaLayoutManager() {}
 
@@ -30,12 +29,15 @@
 }
 
 void StatusAreaLayoutManager::SetChildBounds(
-    aura::Window* child,
+    WmWindow* child,
     const gfx::Rect& requested_bounds) {
   // Only need to have the shelf do a layout if the child changing is the status
   // area and the shelf isn't in the process of doing a layout.
-  if (child != shelf_->status_area_widget()->GetNativeView() || in_layout_) {
-    SnapToPixelLayoutManager::SetChildBounds(child, requested_bounds);
+  if (child !=
+          WmLookup::Get()->GetWindowForWidget(
+              shelf_widget_->status_area_widget()) ||
+      in_layout_) {
+    wm::WmSnapToPixelLayoutManager::SetChildBounds(child, requested_bounds);
     return;
   }
 
@@ -44,7 +46,7 @@
   if (requested_bounds == child->GetTargetBounds())
     return;
 
-  SnapToPixelLayoutManager::SetChildBounds(child, requested_bounds);
+  wm::WmSnapToPixelLayoutManager::SetChildBounds(child, requested_bounds);
   LayoutStatusArea();
 }
 
@@ -53,11 +55,11 @@
 
 void StatusAreaLayoutManager::LayoutStatusArea() {
   // Shelf layout manager may be already doing layout.
-  if (shelf_->shelf_layout_manager()->updating_bounds())
+  if (shelf_widget_->shelf_layout_manager()->updating_bounds())
     return;
 
   base::AutoReset<bool> auto_reset_in_layout(&in_layout_, true);
-  shelf_->shelf_layout_manager()->LayoutShelf();
+  shelf_widget_->shelf_layout_manager()->LayoutShelf();
 }
 
 }  // namespace ash
diff --git a/ash/wm/status_area_layout_manager.h b/ash/wm/status_area_layout_manager.h
index 77a844d2..9d276ae 100644
--- a/ash/wm/status_area_layout_manager.h
+++ b/ash/wm/status_area_layout_manager.h
@@ -5,25 +5,24 @@
 #ifndef ASH_WM_STATUS_AREA_LAYOUT_MANAGER_H_
 #define ASH_WM_STATUS_AREA_LAYOUT_MANAGER_H_
 
-#include "ash/snap_to_pixel_layout_manager.h"
-#include "base/compiler_specific.h"
+#include "ash/common/wm/wm_snap_to_pixel_layout_manager.h"
 #include "base/macros.h"
-#include "ui/aura/layout_manager.h"
 
 namespace ash {
+
 class ShelfWidget;
 
 // StatusAreaLayoutManager is a layout manager responsible for the status area.
 // In any case when status area needs relayout it redirects this call to
 // ShelfLayoutManager.
-class StatusAreaLayoutManager : public SnapToPixelLayoutManager {
+class StatusAreaLayoutManager : public wm::WmSnapToPixelLayoutManager {
  public:
-  StatusAreaLayoutManager(aura::Window* container, ShelfWidget* shelf);
+  explicit StatusAreaLayoutManager(ShelfWidget* shelf_widget);
   ~StatusAreaLayoutManager() override;
 
-  // Overridden from aura::LayoutManager:
+  // Overridden from wm::WmSnapToPixelLayoutManager:
   void OnWindowResized() override;
-  void SetChildBounds(aura::Window* child,
+  void SetChildBounds(WmWindow* child,
                       const gfx::Rect& requested_bounds) override;
 
  private:
@@ -35,7 +34,7 @@
   // Used to prevent calling itself again from SetChildBounds().
   bool in_layout_;
 
-  ShelfWidget* shelf_;
+  ShelfWidget* shelf_widget_;
 
   DISALLOW_COPY_AND_ASSIGN(StatusAreaLayoutManager);
 };
diff --git a/base/synchronization/lock.h b/base/synchronization/lock.h
index c2680cb..599984e 100644
--- a/base/synchronization/lock.h
+++ b/base/synchronization/lock.h
@@ -61,13 +61,22 @@
   void AssertAcquired() const;
 #endif  // DCHECK_IS_ON()
 
+  // Whether Lock mitigates priority inversion when used from different thread
+  // priorities.
+  static bool HandlesMultipleThreadPriorities() {
 #if defined(OS_POSIX)
-  // Whether this platform has priority inheritance available. All locks will
-  // attempt to use the priority inheritance version if available.
-  static bool PriorityInheritanceAvailable() {
+    // POSIX mitigates priority inversion by setting the priority of a thread
+    // holding a Lock to the maximum priority of any other thread waiting on it.
     return internal::LockImpl::PriorityInheritanceAvailable();
-  }
+#elif defined(OS_WIN)
+    // Windows mitigates priority inversion by randomly boosting the priority of
+    // ready threads.
+    // https://msdn.microsoft.com/library/windows/desktop/ms684831.aspx
+    return true;
+#else
+#error Unsupported platform
 #endif
+  }
 
 #if defined(OS_POSIX) || defined(OS_WIN)
   // Both Windows and POSIX implementations of ConditionVariable need to be
diff --git a/base/task_scheduler/scheduler_lock_impl.cc b/base/task_scheduler/scheduler_lock_impl.cc
index 7480e18..d60f259 100644
--- a/base/task_scheduler/scheduler_lock_impl.cc
+++ b/base/task_scheduler/scheduler_lock_impl.cc
@@ -67,19 +67,30 @@
     // Otherwise, make sure that the previous lock acquired is an allowed
     // predecessor.
     AutoLock auto_lock(allowed_predecessor_map_lock_);
+    // Using at() is exception-safe here as |lock| was registered already.
     const SchedulerLockImpl* allowed_predecessor =
         allowed_predecessor_map_.at(lock);
     DCHECK_EQ(acquired_locks->back(), allowed_predecessor);
   }
 
+  // Asserts that |lock|'s registered predecessor is safe. Because
+  // SchedulerLocks are registered at construction time and any predecessor
+  // specified on a SchedulerLock must already exist, the first registered
+  // SchedulerLock in a potential chain must have a null predecessor and is thus
+  // cycle-free. Any subsequent SchedulerLock with a predecessor must come from
+  // the set of registered SchedulerLocks. Since the registered SchedulerLocks
+  // only contain cycle-free SchedulerLocks, this subsequent SchedulerLock is
+  // itself cycle-free and may be safely added to the registered SchedulerLock
+  // set.
   void AssertSafePredecessor(const SchedulerLockImpl* lock) const {
     allowed_predecessor_map_lock_.AssertAcquired();
-    for (const SchedulerLockImpl* predecessor =
-             allowed_predecessor_map_.at(lock);
-         predecessor != nullptr;
-         predecessor = allowed_predecessor_map_.at(predecessor)) {
-      DCHECK_NE(predecessor, lock) <<
-          "Scheduler lock predecessor cycle detected.";
+    // Using at() is exception-safe here as |lock| was registered already.
+    const SchedulerLockImpl* predecessor = allowed_predecessor_map_.at(lock);
+    if (predecessor) {
+      DCHECK(allowed_predecessor_map_.find(predecessor) !=
+             allowed_predecessor_map_.end())
+          << "SchedulerLock was registered before its predecessor. "
+          << "Potential cycle detected";
     }
   }
 
diff --git a/base/task_scheduler/scheduler_worker.cc b/base/task_scheduler/scheduler_worker.cc
index 6ee52aca..8e37639e 100644
--- a/base/task_scheduler/scheduler_worker.cc
+++ b/base/task_scheduler/scheduler_worker.cc
@@ -49,9 +49,7 @@
       mac::ScopedNSAutoreleasePool autorelease_pool;
 #endif
 
-#if !defined(OS_LINUX)
       UpdateThreadPriority(GetDesiredThreadPriority());
-#endif
 
       // Get the sequence containing the next task to execute.
       scoped_refptr<Sequence> sequence = outer_->delegate_->GetWork(outer_);
@@ -131,22 +129,29 @@
     wake_up_event_.Reset();
   }
 
-  // Returns the desired thread priority based on the worker priority and the
-  // current shutdown state.
+  // Returns the priority for which the thread should be set based on the
+  // priority hint, current shutdown state, and platform capabilities.
   ThreadPriority GetDesiredThreadPriority() {
     DCHECK(outer_);
 
-    if (outer_->task_tracker_->HasShutdownStarted() &&
-        static_cast<int>(outer_->thread_priority_) <
-            static_cast<int>(ThreadPriority::NORMAL)) {
+    // All threads have a NORMAL priority when Lock doesn't handle multiple
+    // thread priorities.
+    if (!Lock::HandlesMultipleThreadPriorities())
+      return ThreadPriority::NORMAL;
+
+    // To avoid shutdown hangs, disallow a priority below NORMAL during
+    // shutdown. If thread priority cannot be increased, never allow a priority
+    // below NORMAL.
+    if (static_cast<int>(outer_->priority_hint_) <
+            static_cast<int>(ThreadPriority::NORMAL) &&
+        (outer_->task_tracker_->HasShutdownStarted() ||
+         !PlatformThread::CanIncreaseCurrentThreadPriority())) {
       return ThreadPriority::NORMAL;
     }
-    return outer_->thread_priority_;
+
+    return outer_->priority_hint_;
   }
 
-  // Increasing the thread priority requires the CAP_SYS_NICE capability on
-  // Linux.
-#if !defined(OS_LINUX)
   void UpdateThreadPriority(ThreadPriority desired_thread_priority) {
     if (desired_thread_priority == current_thread_priority_)
       return;
@@ -154,7 +159,6 @@
     PlatformThread::SetCurrentThreadPriority(desired_thread_priority);
     current_thread_priority_ = desired_thread_priority;
   }
-#endif  // !defined(OS_LINUX)
 
   PlatformThreadHandle thread_handle_;
 
@@ -164,19 +168,19 @@
   WaitableEvent wake_up_event_;
 
   // Current priority of this thread. May be different from
-  // |outer_->thread_priority_| during shutdown.
+  // |outer_->priority_hint_|.
   ThreadPriority current_thread_priority_;
 
   DISALLOW_COPY_AND_ASSIGN(Thread);
 };
 
 std::unique_ptr<SchedulerWorker> SchedulerWorker::Create(
-    ThreadPriority thread_priority,
+    ThreadPriority priority_hint,
     std::unique_ptr<Delegate> delegate,
     TaskTracker* task_tracker,
     InitialState initial_state) {
   std::unique_ptr<SchedulerWorker> worker(
-      new SchedulerWorker(thread_priority, std::move(delegate), task_tracker));
+      new SchedulerWorker(priority_hint, std::move(delegate), task_tracker));
   // Creation happens before any other thread can reference this one, so no
   // synchronization is necessary.
   if (initial_state == SchedulerWorker::InitialState::ALIVE) {
@@ -228,10 +232,10 @@
   return !!thread_;
 }
 
-SchedulerWorker::SchedulerWorker(ThreadPriority thread_priority,
+SchedulerWorker::SchedulerWorker(ThreadPriority priority_hint,
                                  std::unique_ptr<Delegate> delegate,
                                  TaskTracker* task_tracker)
-    : thread_priority_(thread_priority),
+    : priority_hint_(priority_hint),
       delegate_(std::move(delegate)),
       task_tracker_(task_tracker) {
   DCHECK(delegate_);
diff --git a/base/task_scheduler/scheduler_worker.h b/base/task_scheduler/scheduler_worker.h
index 71d4cbc..d741f95 100644
--- a/base/task_scheduler/scheduler_worker.h
+++ b/base/task_scheduler/scheduler_worker.h
@@ -77,13 +77,15 @@
 
   enum class InitialState { ALIVE, DETACHED };
 
-  // Creates a SchedulerWorker with priority |thread_priority| that runs Tasks
-  // from Sequences returned by |delegate|. |task_tracker| is used to handle
-  // shutdown behavior of Tasks. If |worker_state| is DETACHED, the thread will
-  // be created upon a WakeUp(). Returns nullptr if creating the underlying
-  // platform thread fails during Create().
+  // Creates a SchedulerWorker that runs Tasks from Sequences returned by
+  // |delegate|. |priority_hint| is the preferred thread priority; the actual
+  // thread priority depends on shutdown state and platform capabilities.
+  // |task_tracker| is used to handle shutdown behavior of Tasks. If
+  // |worker_state| is DETACHED, the thread will be created upon a WakeUp().
+  // Returns nullptr if creating the underlying platform thread fails during
+  // Create().
   static std::unique_ptr<SchedulerWorker> Create(
-      ThreadPriority thread_priority,
+      ThreadPriority priority_hint,
       std::unique_ptr<Delegate> delegate,
       TaskTracker* task_tracker,
       InitialState initial_state);
@@ -133,7 +135,7 @@
   // The underlying thread for this SchedulerWorker.
   std::unique_ptr<Thread> thread_;
 
-  const ThreadPriority thread_priority_;
+  const ThreadPriority priority_hint_;
   const std::unique_ptr<Delegate> delegate_;
   TaskTracker* const task_tracker_;
 
diff --git a/base/task_scheduler/scheduler_worker_pool_impl.cc b/base/task_scheduler/scheduler_worker_pool_impl.cc
index b97ce8dd..39a5e2e 100644
--- a/base/task_scheduler/scheduler_worker_pool_impl.cc
+++ b/base/task_scheduler/scheduler_worker_pool_impl.cc
@@ -253,8 +253,7 @@
                                   params.io_restriction(),
                                   params.suggested_reclaim_time(),
                                   task_tracker, delayed_task_manager));
-  if (worker_pool->Initialize(params.thread_priority(),
-                              params.max_threads(),
+  if (worker_pool->Initialize(params.priority_hint(), params.max_threads(),
                               re_enqueue_sequence_callback)) {
     return worker_pool;
   }
@@ -569,7 +568,7 @@
 }
 
 bool SchedulerWorkerPoolImpl::Initialize(
-    ThreadPriority thread_priority,
+    ThreadPriority priority_hint,
     size_t max_threads,
     const ReEnqueueSequenceCallback& re_enqueue_sequence_callback) {
   AutoSchedulerLock auto_lock(idle_workers_stack_lock_);
@@ -577,15 +576,12 @@
   DCHECK(workers_.empty());
 
   for (size_t i = 0; i < max_threads; ++i) {
-    std::unique_ptr<SchedulerWorker> worker =
-        SchedulerWorker::Create(
-            thread_priority, WrapUnique(new SchedulerWorkerDelegateImpl(
-                                 this, re_enqueue_sequence_callback,
-                                 &shared_priority_queue_, static_cast<int>(i))),
-            task_tracker_,
-            i == 0
-                ? SchedulerWorker::InitialState::ALIVE
-                : SchedulerWorker::InitialState::DETACHED);
+    std::unique_ptr<SchedulerWorker> worker = SchedulerWorker::Create(
+        priority_hint, WrapUnique(new SchedulerWorkerDelegateImpl(
+                           this, re_enqueue_sequence_callback,
+                           &shared_priority_queue_, static_cast<int>(i))),
+        task_tracker_, i == 0 ? SchedulerWorker::InitialState::ALIVE
+                              : SchedulerWorker::InitialState::DETACHED);
     if (!worker)
       break;
     idle_workers_stack_.Push(worker.get());
diff --git a/base/task_scheduler/scheduler_worker_pool_impl.h b/base/task_scheduler/scheduler_worker_pool_impl.h
index 39ec9b8..379f3286 100644
--- a/base/task_scheduler/scheduler_worker_pool_impl.h
+++ b/base/task_scheduler/scheduler_worker_pool_impl.h
@@ -104,7 +104,7 @@
                           DelayedTaskManager* delayed_task_manager);
 
   bool Initialize(
-      ThreadPriority thread_priority,
+      ThreadPriority priority_hint,
       size_t max_threads,
       const ReEnqueueSequenceCallback& re_enqueue_sequence_callback);
 
diff --git a/base/task_scheduler/scheduler_worker_pool_params.cc b/base/task_scheduler/scheduler_worker_pool_params.cc
index 14ee584..d820460 100644
--- a/base/task_scheduler/scheduler_worker_pool_params.cc
+++ b/base/task_scheduler/scheduler_worker_pool_params.cc
@@ -10,12 +10,12 @@
 
 SchedulerWorkerPoolParams::SchedulerWorkerPoolParams(
     const std::string& name,
-    ThreadPriority thread_priority,
+    ThreadPriority priority_hint,
     IORestriction io_restriction,
     int max_threads,
     const TimeDelta& suggested_reclaim_time)
     : name_(name),
-      thread_priority_(thread_priority),
+      priority_hint_(priority_hint),
       io_restriction_(io_restriction),
       max_threads_(max_threads),
       suggested_reclaim_time_(suggested_reclaim_time) {}
diff --git a/base/task_scheduler/scheduler_worker_pool_params.h b/base/task_scheduler/scheduler_worker_pool_params.h
index c66365b2..a084166 100644
--- a/base/task_scheduler/scheduler_worker_pool_params.h
+++ b/base/task_scheduler/scheduler_worker_pool_params.h
@@ -23,25 +23,25 @@
 
   // Construct a scheduler worker pool parameter object that instructs a
   // scheduler worker pool to use the label |name| and create up to
-  // |max_threads| threads of priority |thread_priority|. |io_restriction|
-  // indicates whether Tasks on the scheduler worker pool are allowed to make
-  // I/O calls. |suggested_reclaim_time| sets a suggestion on when to reclaim
-  // idle threads. The worker pool is free to ignore this value for performance
-  // or correctness reasons.
-  SchedulerWorkerPoolParams(
-      const std::string& name,
-      ThreadPriority thread_priority,
-      IORestriction io_restriction,
-      int max_threads,
-      const TimeDelta& suggested_reclaim_time);
+  // |max_threads| threads. |priority_hint| is the preferred thread priority;
+  // the actual thread priority depends on shutdown state and platform
+  // capabilities. |io_restriction| indicates whether Tasks on the scheduler
+  // worker pool are allowed to make I/O calls. |suggested_reclaim_time| sets a
+  // suggestion on when to reclaim idle threads. The worker pool is free to
+  // ignore this value for performance or correctness reasons.
+  SchedulerWorkerPoolParams(const std::string& name,
+                            ThreadPriority priority_hint,
+                            IORestriction io_restriction,
+                            int max_threads,
+                            const TimeDelta& suggested_reclaim_time);
   SchedulerWorkerPoolParams(SchedulerWorkerPoolParams&& other);
   SchedulerWorkerPoolParams& operator=(SchedulerWorkerPoolParams&& other);
 
   // Name of the pool. Used to label the pool's threads.
   const std::string& name() const { return name_; }
 
-  // Priority of the pool's threads.
-  ThreadPriority thread_priority() const { return thread_priority_; }
+  // Preferred priority for the pool's threads.
+  ThreadPriority priority_hint() const { return priority_hint_; }
 
   // Whether I/O is allowed in the pool.
   IORestriction io_restriction() const { return io_restriction_; }
@@ -56,7 +56,7 @@
 
  private:
   std::string name_;
-  ThreadPriority thread_priority_;
+  ThreadPriority priority_hint_;
   IORestriction io_restriction_;
   size_t max_threads_;
   TimeDelta suggested_reclaim_time_;
diff --git a/base/task_scheduler/scheduler_worker_unittest.cc b/base/task_scheduler/scheduler_worker_unittest.cc
index fb94edc..ce63787 100644
--- a/base/task_scheduler/scheduler_worker_unittest.cc
+++ b/base/task_scheduler/scheduler_worker_unittest.cc
@@ -474,21 +474,23 @@
 
 }  // namespace
 
-// Increasing the thread priority requires the CAP_SYS_NICE capability on Linux.
-#if !defined(OS_LINUX)
 TEST(TaskSchedulerWorkerTest, BumpPriorityOfAliveThreadDuringShutdown) {
   TaskTracker task_tracker;
 
   std::unique_ptr<ExpectThreadPriorityDelegate> delegate(
       new ExpectThreadPriorityDelegate);
   ExpectThreadPriorityDelegate* delegate_raw = delegate.get();
-  delegate_raw->SetExpectedThreadPriority(ThreadPriority::BACKGROUND);
+  delegate_raw->SetExpectedThreadPriority(
+      PlatformThread::CanIncreaseCurrentThreadPriority()
+          ? ThreadPriority::BACKGROUND
+          : ThreadPriority::NORMAL);
 
   std::unique_ptr<SchedulerWorker> worker = SchedulerWorker::Create(
       ThreadPriority::BACKGROUND, std::move(delegate), &task_tracker,
       SchedulerWorker::InitialState::ALIVE);
 
-  // Verify that the initial thread priority is BACKGROUND.
+  // Verify that the initial thread priority is BACKGROUND (or NORMAL if thread
+  // priority can't be increased).
   worker->WakeUp();
   delegate_raw->WaitForPriorityVerifiedInGetWork();
 
@@ -500,7 +502,6 @@
 
   worker->JoinForTesting();
 }
-#endif  // defined(OS_LINUX)
 
 TEST(TaskSchedulerWorkerTest, BumpPriorityOfDetachedThreadDuringShutdown) {
   TaskTracker task_tracker;
diff --git a/base/task_scheduler/task_scheduler_impl_unittest.cc b/base/task_scheduler/task_scheduler_impl_unittest.cc
index b49e5b9d..fe5a98f 100644
--- a/base/task_scheduler/task_scheduler_impl_unittest.cc
+++ b/base/task_scheduler/task_scheduler_impl_unittest.cc
@@ -15,6 +15,7 @@
 #include "base/callback.h"
 #include "base/macros.h"
 #include "base/memory/ptr_util.h"
+#include "base/synchronization/lock.h"
 #include "base/synchronization/waitable_event.h"
 #include "base/task_scheduler/scheduler_worker_pool_params.h"
 #include "base/task_scheduler/task_traits.h"
@@ -53,7 +54,12 @@
 // to run a Task with |traits|.
 // Note: ExecutionMode is verified inside TestTaskFactory.
 void VerifyTaskEnvironement(const TaskTraits& traits) {
-  EXPECT_EQ(traits.priority() == TaskPriority::BACKGROUND
+  const bool supports_background_priority =
+      Lock::HandlesMultipleThreadPriorities() &&
+      PlatformThread::CanIncreaseCurrentThreadPriority();
+
+  EXPECT_EQ(supports_background_priority &&
+                    traits.priority() == TaskPriority::BACKGROUND
                 ? ThreadPriority::BACKGROUND
                 : ThreadPriority::NORMAL,
             PlatformThread::GetCurrentThreadPriority());
diff --git a/build/all.gyp b/build/all.gyp
index 8a8417ed..04cd975 100644
--- a/build/all.gyp
+++ b/build/all.gyp
@@ -310,7 +310,6 @@
         '../net/net.gyp:net_unittests',
         '../skia/skia_tests.gyp:skia_unittests',
         '../sql/sql.gyp:sql_unittests',
-        '../components/sync.gyp:sync_unit_tests',
         '../ui/base/ui_base_tests.gyp:ui_base_unittests',
         '../ui/display/display.gyp:display_unittests',
         '../ui/gfx/gfx_tests.gyp:gfx_unittests',
@@ -795,7 +794,6 @@
             '../sandbox/sandbox.gyp:sandbox_linux_unittests_deps',
             '../skia/skia_tests.gyp:skia_unittests',
             '../sql/sql.gyp:sql_unittests',
-            '../components/sync.gyp:sync_unit_tests',
             '../testing/android/junit/junit_test.gyp:junit_unit_tests',
             '../third_party/leveldatabase/leveldatabase.gyp:env_chromium_unittests',
             '../third_party/WebKit/public/all.gyp:*',
@@ -826,7 +824,6 @@
             '../net/net.gyp:net_unittests_apk',
             '../skia/skia_tests.gyp:skia_unittests_apk',
             '../sql/sql.gyp:sql_unittests_apk',
-            '../components/sync.gyp:sync_unit_tests_apk',
             '../ui/android/ui_android.gyp:ui_android_unittests_apk',
             '../ui/android/ui_android.gyp:ui_junit_tests',
             '../ui/base/ui_base_tests.gyp:ui_base_unittests_apk',
@@ -910,7 +907,6 @@
             '../rlz/rlz.gyp:*',
             '../skia/skia_tests.gyp:skia_unittests',
             '../sql/sql.gyp:sql_unittests',
-            '../components/sync.gyp:sync_unit_tests',
             '../third_party/cacheinvalidation/cacheinvalidation.gyp:cacheinvalidation_unittests',
             '../third_party/leveldatabase/leveldatabase.gyp:env_chromium_unittests',
             '../third_party/libaddressinput/libaddressinput.gyp:libaddressinput_unittests',
@@ -949,7 +945,6 @@
             '../remoting/remoting.gyp:remoting_unittests',
             '../skia/skia_tests.gyp:skia_unittests',
             '../sql/sql.gyp:sql_unittests',
-            '../components/sync.gyp:sync_unit_tests',
             '../third_party/cacheinvalidation/cacheinvalidation.gyp:cacheinvalidation_unittests',
             '../third_party/leveldatabase/leveldatabase.gyp:env_chromium_unittests',
             '../third_party/libaddressinput/libaddressinput.gyp:libaddressinput_unittests',
@@ -1021,7 +1016,6 @@
             '../remoting/remoting.gyp:remoting_unittests',
             '../skia/skia_tests.gyp:skia_unittests',
             '../sql/sql.gyp:sql_unittests',
-            '../components/sync.gyp:sync_unit_tests',
             '../third_party/cacheinvalidation/cacheinvalidation.gyp:cacheinvalidation_unittests',
             '../third_party/leveldatabase/leveldatabase.gyp:env_chromium_unittests',
             '../third_party/libaddressinput/libaddressinput.gyp:libaddressinput_unittests',
@@ -1113,7 +1107,6 @@
             '../remoting/remoting.gyp:remoting_unittests',
             '../skia/skia_tests.gyp:skia_unittests',
             '../sql/sql.gyp:sql_unittests',
-            '../components/sync.gyp:sync_unit_tests',
             '../third_party/cacheinvalidation/cacheinvalidation.gyp:cacheinvalidation_unittests',
             '../third_party/leveldatabase/leveldatabase.gyp:env_chromium_unittests',
             '../third_party/libaddressinput/libaddressinput.gyp:libaddressinput_unittests',
@@ -1169,7 +1162,6 @@
             '../net/net.gyp:net_unittests',
             '../printing/printing.gyp:printing_unittests',
             '../sql/sql.gyp:sql_unittests',
-            '../components/sync.gyp:sync_unit_tests',
             '../ui/base/ui_base_tests.gyp:ui_base_unittests',
             '../ui/gfx/gfx_tests.gyp:gfx_unittests',
             '../ui/gl/gl_tests.gyp:gl_unittests',
@@ -1250,7 +1242,6 @@
                 '../base/base.gyp:base_unittests',
                 '../ipc/ipc.gyp:ipc_tests',
                 '../sql/sql.gyp:sql_unittests',
-                '../components/sync.gyp:sync_unit_tests',
               ],
             }],
             ['chromeos==1', {
diff --git a/build/android/pylib/gtest/gtest_config.py b/build/android/pylib/gtest/gtest_config.py
index c80ba7f4..9bc2c80 100644
--- a/build/android/pylib/gtest/gtest_config.py
+++ b/build/android/pylib/gtest/gtest_config.py
@@ -37,7 +37,6 @@
     'sandbox_linux_unittests',
     'skia_unittests',
     'sql_unittests',
-    'sync_unit_tests',
     'ui_android_unittests',
     'ui_base_unittests',
     'ui_touch_selection_unittests',
diff --git a/build/android/pylib/gtest/gtest_test_instance.py b/build/android/pylib/gtest/gtest_test_instance.py
index f41881a..56755ba 100644
--- a/build/android/pylib/gtest/gtest_test_instance.py
+++ b/build/android/pylib/gtest/gtest_test_instance.py
@@ -42,7 +42,6 @@
     'midi_unittests': 'media/midi/midi_unittests.isolate',
     'net_unittests': 'net/net_unittests.isolate',
     'sql_unittests': 'sql/sql_unittests.isolate',
-    'sync_unit_tests': 'components/sync/sync_unit_tests.isolate',
     'ui_base_unittests': 'ui/base/ui_base_tests.isolate',
     'unit_tests': 'chrome/unit_tests.isolate',
     'webkit_unit_tests':
diff --git a/build/android/pylib/instrumentation/instrumentation_test_instance.py b/build/android/pylib/instrumentation/instrumentation_test_instance.py
index 62e62b803..3a69c36 100644
--- a/build/android/pylib/instrumentation/instrumentation_test_instance.py
+++ b/build/android/pylib/instrumentation/instrumentation_test_instance.py
@@ -48,7 +48,7 @@
 
 _PARAMETERIZED_TEST_ANNOTATION = 'ParameterizedTest'
 _PARAMETERIZED_TEST_SET_ANNOTATION = 'ParameterizedTest$Set'
-_NATIVE_CRASH_RE = re.compile('native crash', re.IGNORECASE)
+_NATIVE_CRASH_RE = re.compile('(process|native) crash', re.IGNORECASE)
 _PICKLE_FORMAT_VERSION = 10
 
 
diff --git a/build/config/BUILDCONFIG.gn b/build/config/BUILDCONFIG.gn
index 8c565aa6..e539df78 100644
--- a/build/config/BUILDCONFIG.gn
+++ b/build/config/BUILDCONFIG.gn
@@ -144,6 +144,9 @@
   # Component build. Setting to true compiles targets declared as "components"
   # as shared libraries loaded dynamically. This speeds up development time.
   # When false, components will be linked statically.
+  #
+  # For more information see
+  # https://chromium.googlesource.com/chromium/src/+/master/docs/component_build.md
   is_component_build = is_debug && current_os != "ios"
 }
 
diff --git a/build/config/ios/BUILD.gn b/build/config/ios/BUILD.gn
index 6b8896c..ac709ae 100644
--- a/build/config/ios/BUILD.gn
+++ b/build/config/ios/BUILD.gn
@@ -28,13 +28,17 @@
   cflags = common_flags
   ldflags = common_flags
 
-  # TODO(ios): Remove once Xcode's libc++ has LLVM r256325.
-  if (use_xcode_clang) {
-    cflags += [
+  # TODO(crbug.com/634373): Remove once Xcode's libc++ has LLVM r256325. Most
+  # likely this means one Xcode 8 is released and required.
+  if (use_xcode_clang && get_path_info(ios_sdk_version, "name") != "10") {
+    common_cc_flags = [
       "-isystem",
       rebase_path("//third_party/llvm-build/Release+Asserts/include/c++/v1",
                   root_build_dir),
     ]
+
+    cflags_cc = common_cc_flags
+    cflags_objcc = common_cc_flags
   }
 }
 
diff --git a/build/config/ios/rules.gni b/build/config/ios/rules.gni
index aa78715..d3afc12 100644
--- a/build/config/ios/rules.gni
+++ b/build/config/ios/rules.gni
@@ -6,6 +6,13 @@
 import("//build/config/mac/base_rules.gni")
 import("//build/config/mac/symbols.gni")
 
+_toolchain_suffix = ""
+_is_fat_build = additional_toolchains != []
+if (_is_fat_build) {
+  _toolchain_suffix = "($default_toolchain)"
+  _is_fat_build_main_target = current_toolchain == default_toolchain
+}
+
 # Generates Info.plist files for Mac apps and frameworks.
 #
 # Arguments
@@ -146,11 +153,6 @@
   # The rest of the build, including the codesigning step, are the same for
   # thin and fat builds.
 
-  _is_fat_build = additional_toolchains != []
-  if (_is_fat_build) {
-    _is_fat_build_main_target = current_toolchain == default_toolchain
-  }
-
   _executable_extra_deps = []
   _executable_extra_inputs = []
   _executable_extra_ldflags = []
@@ -161,11 +163,6 @@
   #
   # As the generation of the entitlement depends on the
   if (use_ios_simulator) {
-    _toolchain_suffix = ""
-    if (_is_fat_build && !_is_fat_build_main_target) {
-      _toolchain_suffix = "($default_toolchain)"
-    }
-
     _generate_entitlements_target = _target_name + "_gen_entitlements"
     _generate_entitlements_target_with_toolchain_suffix =
         "$_generate_entitlements_target$_toolchain_suffix"
@@ -763,12 +760,11 @@
 
 # Template to package a shared library into an iOS framework bundle.
 #
-# This template provides two targets to control whether the framework is
-# merely built when targets depend on it, or whether it is linked as well:
-# "$target_name" and "$target_name+link".
-#
-# See the //build/config/mac/base_rules.gni:framework_bundle for a discussion
-# and examples.
+# By default, the bundle target this template generates does not link the
+# resulting framework into anything that depends on it. If a dependency wants
+# a link-time (as well as build-time) dependency on the framework bundle,
+# depend against "$target_name+link". If only the build-time dependency is
+# required (e.g., for copying into another bundle), then use "$target_name".
 #
 # Arguments
 #
@@ -791,6 +787,70 @@
 #         (optional) list of files. Needs to be defined and non-empty if
 #         public_headers is defined and non-empty.
 #
+# This template provides two targets for the resulting framework bundle. The
+# link-time behavior varies depending on which of the two targets below is
+# added as a dependency:
+#   - $target_name only adds a build-time dependency. Targets that depend on
+#     it will not link against the framework.
+#   - $target_name+link adds a build-time and link-time dependency. Targets
+#     that depend on it will link against the framework.
+#
+# The build-time-only dependency is used for when a target needs to use the
+# framework either only for resources, or because the target loads it at run-
+# time, via dlopen() or NSBundle. The link-time dependency will cause the
+# dependee to have the framework loaded by dyld at launch.
+#
+# Example of build-time only dependency:
+#
+#     framework_bundle("CoreTeleportation") {
+#       sources = [ ... ]
+#     }
+#
+#     bundle_data("core_teleportation_bundle_data") {
+#       deps = [ ":CoreTeleportation" ]
+#       sources = [ "$root_out_dir/CoreTeleportation.framework" ]
+#       outputs = [ "{{bundle_root_dir}}/Frameworks/{{source_file_part}}" ]
+#     }
+#
+#     app_bundle("GoatTeleporter") {
+#       sources = [ ... ]
+#       deps = [
+#         ":core_teleportation_bundle_data",
+#       ]
+#     }
+#
+# The GoatTeleporter.app will not directly link against
+# CoreTeleportation.framework, but it will be included in the bundle's
+# Frameworks directory.
+#
+# Example of link-time dependency:
+#
+#     framework_bundle("CoreTeleportation") {
+#       sources = [ ... ]
+#       ldflags = [
+#         "-install_name",
+#         "@executable_path/../Frameworks/$target_name.framework"
+#       ]
+#     }
+#
+#     bundle_data("core_teleportation_bundle_data") {
+#       deps = [ ":CoreTeleportation+link" ]
+#       sources = [ "$root_out_dir/CoreTeleportation.framework" ]
+#       outputs = [ "{{bundle_root_dir}}/Frameworks/{{source_file_part}}" ]
+#     }
+#
+#     app_bundle("GoatTeleporter") {
+#       sources = [ ... ]
+#       deps = [
+#         ":core_teleportation_bundle_data",
+#       ]
+#     }
+#
+# Note that the framework is still copied to the app's bundle, but dyld will
+# load this library when the app is launched because it uses the "+link"
+# target as a dependency. This also requires that the framework set its
+# install_name so that dyld can locate it.
+#
 # See "gn help shared_library" for more information on arguments supported
 # by shared library target.
 template("ios_framework_bundle") {
@@ -799,38 +859,80 @@
   if (defined(invoker.output_name)) {
     _output_name = invoker.output_name
   }
-  _framework_target = _target_name
 
   _has_public_headers =
       defined(invoker.public_headers) && invoker.public_headers != []
 
-  _is_fat_build = additional_toolchains != []
-  if (_is_fat_build) {
-    _is_fat_build_main_target = current_toolchain == default_toolchain
-  }
-
-  # This template has a different expansion depending on whether public headers
-  # are defined or not. If no public headers are speficied, then is forwards to
-  # the generic "framework_bundle" target, otherwise if expands to targets that
-  # create header map mapping and corresponding config and configure them as
-  # dependencies of the generic "framework_bundle" target.
-  #
-  # The expansion is a bit different for multi-architecture builds (aka fat
-  # binary builds). Then the targets build for the non-default toolchain uses
-  # the same header map (if available) as the one used by the default toolchain.
-
-  _toolchain_suffix = ""
-  if (_is_fat_build && !_is_fat_build_main_target) {
-    _toolchain_suffix = "($default_toolchain)"
-  }
-
   if (_has_public_headers) {
     _framework_headers_target = _target_name + "_framework_headers"
-    _framework_public_config = _target_name + "_ios_public_config"
-    _framework_target = target_name + "_internal"
+    _framework_headers_config = _target_name + "_framework_headers_config"
     _headers_map_config = _target_name + "_headers_map"
+  }
 
-    if (!_is_fat_build || _is_fat_build_main_target) {
+  # The expansion of the template is different for fat and thin builds. For
+  # thin build (and default toolchain of a fat build), the template expands
+  # to a "shared_library" target to create the bundle shared library and a
+  # "create_bundle" target (the main target) to create the bundle structure.
+  #
+  # For a fat build, the template just expands to the "shared_library" target
+  # for the non-default toolchain, while the final library is created using
+  # "lipo" in the expansion of the template for the default toolchain.
+  #
+  # The "$target_name+link" group for the non-default toolchain depends on the
+  # target of the same name from the default toolchain as this is the target
+  # that defines the real framework bundle (it will support the current cpu
+  # as it is a fat framework).
+
+  if (_is_fat_build && !_is_fat_build_main_target) {
+    shared_library(_target_name) {
+      forward_variables_from(invoker,
+                             "*",
+                             [
+                               "assert_no_deps",
+                               "bundle_deps",
+                               "code_signing_enabled",
+                               "data_deps",
+                               "info_plist",
+                               "info_plist_target",
+                               "output_name",
+                             ])
+      if (defined(visibility)) {
+        visibility += [ ":${_target_name}_shared_library($default_toolchain)" ]
+      }
+      output_name = _output_name
+      output_prefix_override = true
+      output_extension = ""
+      output_dir = "$target_out_dir/$_target_name"
+
+      if (_has_public_headers) {
+        configs += [
+          ":$_framework_headers_config$_toolchain_suffix",
+          ":$_headers_map_config$_toolchain_suffix",
+        ]
+
+        if (!defined(deps)) {
+          deps = []
+        }
+        deps += [ ":$_framework_headers_target$_toolchain_suffix" ]
+      }
+    }
+
+    group(_target_name + "+link") {
+      forward_variables_from(invoker,
+                             [
+                               "visibility",
+                               "testonly",
+                             ])
+      public_deps = [
+        ":$_target_name+link($default_toolchain)",
+      ]
+    }
+
+    if (defined(invoker.bundle_deps)) {
+      assert(invoker.bundle_deps != [], "mark bundle_deps as used")
+    }
+  } else {
+    if (_has_public_headers) {
       _public_headers = invoker.public_headers
       _framework_name = _output_name + ".framework"
       _framework_root = "$root_out_dir/$_framework_name"
@@ -901,7 +1003,7 @@
         ]
       }
 
-      config(_framework_public_config) {
+      config(_framework_headers_config) {
         # The link settings are inherited from the framework_bundle config.
         cflags = [
           "-F",
@@ -909,9 +1011,178 @@
         ]
       }
     }
-  }
 
-  if (!_is_fat_build || _is_fat_build_main_target) {
+    _code_signing_enabled = ios_enable_code_signing
+    if (defined(invoker.code_signing_enabled)) {
+      _code_signing_enabled =
+          invoker.code_signing_enabled && _code_signing_enabled
+    }
+
+    # If the framework is unversioned, the final _target_name will be the
+    # create_bundle(_framework_target), otherwise an action with the name
+    # _target_name will depends on the the create_bundle() in order to prepare
+    # the versioned directory structure.
+    _framework_target = _target_name
+    _framework_name = _output_name + ".framework"
+    _framework_root_dir = "$root_out_dir/$_framework_name"
+    if (defined(invoker.framework_version) && invoker.framework_version != "") {
+      _framework_version = invoker.framework_version
+      _framework_root_dir += "/Versions/$_framework_version"
+      _framework_target = _target_name + "_create_bundle"
+    }
+
+    _link_shared_library_target = target_name + "_shared_library"
+    _shared_library_dir = "$target_out_dir/$_link_shared_library_target"
+
+    if (_code_signing_enabled) {
+      _link_shared_library_visibility = [ ":$_framework_target" ]
+    } else {
+      _shared_library_bundle_data = target_name + "_shared_library_bundle_data"
+      _link_shared_library_visibility = [ ":$_shared_library_bundle_data" ]
+    }
+
+    if (_is_fat_build) {
+      _lipo_shared_library_target = _link_shared_library_target
+      _lipo_shared_library_visibility = _link_shared_library_visibility
+
+      _link_shared_library_visibility = []
+      _link_shared_library_visibility = [ ":$_lipo_shared_library_target" ]
+      _link_shared_library_target = target_name + "_arch_shared_library"
+
+      _arch_shared_library_dir = "$target_out_dir/$_link_shared_library_target"
+      _shared_library_dir = "$target_out_dir/$_lipo_shared_library_target"
+    }
+
+    shared_library(_link_shared_library_target) {
+      forward_variables_from(invoker,
+                             "*",
+                             [
+                               "assert_no_deps",
+                               "bundle_deps",
+                               "code_signing_enabled",
+                               "data_deps",
+                               "info_plist",
+                               "info_plist_target",
+                               "output_name",
+                               "visibility",
+                             ])
+      visibility = _link_shared_library_visibility
+      output_name = _output_name
+      output_prefix_override = true
+      output_extension = ""
+
+      if (!_is_fat_build) {
+        output_dir = _shared_library_dir
+      } else {
+        output_dir = _arch_shared_library_dir
+      }
+
+      if (_has_public_headers) {
+        configs += [ ":$_headers_map_config$_toolchain_suffix" ]
+
+        if (!defined(deps)) {
+          deps = []
+        }
+        deps += [ ":$_framework_headers_target$_toolchain_suffix" ]
+      }
+    }
+
+    if (_is_fat_build) {
+      action(_lipo_shared_library_target) {
+        forward_variables_from(invoker, [ "testonly" ])
+        visibility = _lipo_shared_library_visibility
+        script = "//build/toolchain/mac/linker_driver.py"
+        outputs = [
+          "$_shared_library_dir/$_output_name",
+        ]
+        inputs = [
+          "$_arch_shared_library_dir/$_output_name",
+        ]
+        deps = [
+          ":$_link_shared_library_target",
+        ]
+        foreach(_additional_toolchain, additional_toolchains) {
+          _additional_toolchain_target = "$_target_name($_additional_toolchain)"
+          deps += [ ":$_additional_toolchain_target" ]
+          inputs += [ get_label_info(_additional_toolchain_target,
+                                     "target_out_dir") + "/$_output_name" ]
+        }
+        args = [
+                 "xcrun",
+                 "lipo",
+                 "-create",
+                 "-output",
+                 rebase_path(outputs[0], root_build_dir),
+               ] + rebase_path(inputs, root_build_dir)
+
+        if (enable_dsyms) {
+          outputs += [ "$root_out_dir/$_output_name.dSYM/" ]
+          args +=
+              [ "-Wcrl,dsym," + rebase_path("$root_out_dir/.", root_build_dir) ]
+        }
+
+        if (enable_stripping) {
+          # Check whether //build/config/mac:strip_all has been removed from
+          # the configs variable (as this is how stripping is disabled for a
+          # single target).
+          _strip_all_in_config = false
+          if (defined(invoker.configs)) {
+            foreach(_config, invoker.configs) {
+              if (_config == "//build/config/mac:strip_all") {
+                _strip_all_in_config = true
+              }
+            }
+          }
+
+          if (_strip_all_in_config) {
+            args += [ "-Wcrl,strip,-x,-S" ]
+
+            if (save_unstripped_output) {
+              outputs += [ outputs[0] + ".unstripped" ]
+              args += [ "-Wcrl,unstripped," +
+                        rebase_path(get_path_info(outputs[0], "dir"),
+                                    root_build_dir) ]
+            }
+          }
+        }
+      }
+    }
+
+    if (!_code_signing_enabled) {
+      bundle_data(_shared_library_bundle_data) {
+        visibility = [ ":$_framework_target" ]
+        forward_variables_from(invoker, [ "testonly" ])
+        sources = [
+          "$_shared_library_dir/$_output_name",
+        ]
+        outputs = [
+          "{{bundle_executable_dir}}/$_output_name",
+        ]
+        if (_is_fat_build) {
+          public_deps = [
+            ":$_lipo_shared_library_target",
+          ]
+        } else {
+          public_deps = [
+            ":$_link_shared_library_target",
+          ]
+        }
+      }
+    }
+
+    _framework_public_config = _target_name + "_public_config"
+    config(_framework_public_config) {
+      # TODO(sdefresne): should we have a framework_dirs similar to lib_dirs
+      # and include_dirs to avoid duplicate values on the command-line.
+      visibility = [ ":$_framework_target" ]
+      ldflags = [
+        "-F",
+        rebase_path("$root_out_dir/.", root_build_dir),
+      ]
+      lib_dirs = [ root_out_dir ]
+      libs = [ _framework_name ]
+    }
+
     _info_plist_target = _target_name + "_info_plist"
     _info_plist_bundle = _target_name + "_info_plist_bundle"
     ios_info_plist(_info_plist_target) {
@@ -926,7 +1197,7 @@
     }
 
     bundle_data(_info_plist_bundle) {
-      visibility = [ ":$_framework_target" ]
+      visibility = [ ":$_target_name" ]
       forward_variables_from(invoker, [ "testonly" ])
       sources = get_target_outputs(":$_info_plist_target")
       outputs = [
@@ -936,83 +1207,131 @@
         ":$_info_plist_target",
       ]
     }
-  }
 
-  framework_bundle(_framework_target) {
-    forward_variables_from(invoker,
-                           "*",
-                           [
-                             "output_name",
-                             "public_headers",
-                             "visibility",
-                           ])
-    output_name = _output_name
+    create_bundle(_framework_target) {
+      forward_variables_from(invoker,
+                             [
+                               "data_deps",
+                               "deps",
+                               "public_configs",
+                               "public_deps",
+                               "testonly",
+                             ])
 
-    if (!_is_fat_build || _is_fat_build_main_target) {
-      if (!defined(bundle_deps)) {
-        bundle_deps = []
+      if (defined(_framework_version)) {
+        visibility = [ ":$_target_name" ]
+      } else {
+        if (defined(invoker.visibility)) {
+          visibility = invoker.visibility
+          visibility += [ ":$_target_name+link" ]
+        }
       }
-      bundle_deps += [ ":$_info_plist_bundle" ]
-    }
-
-    if (_has_public_headers) {
-      if (!defined(public_configs)) {
-        public_configs = []
-      }
-      public_configs += [ ":$_framework_public_config$_toolchain_suffix" ]
-    }
-
-    if (_has_public_headers) {
-      visibility = [
-        ":$_target_name$_toolchain_suffix",
-        ":$_target_name+link$_toolchain_suffix",
-        ":$_target_name+bundle$_toolchain_suffix",
-      ]
-      configs += [ ":$_headers_map_config$_toolchain_suffix" ]
 
       if (!defined(deps)) {
         deps = []
       }
-      deps += [ ":$_framework_headers_target$_toolchain_suffix" ]
-    } else {
-      if (defined(invoker.visibility)) {
-        visibility = invoker.visibility
-        visibility += [ ":$_target_name+link$_toolchain_suffix" ]
+      deps += [ ":$_info_plist_bundle" ]
+
+      if (defined(invoker.bundle_deps)) {
+        if (!defined(deps)) {
+          deps = []
+        }
+        deps += invoker.bundle_deps
+      }
+
+      if (!_code_signing_enabled) {
+        if (!defined(public_deps)) {
+          public_deps = []
+        }
+        public_deps += [ ":$_shared_library_bundle_data" ]
+      }
+
+      bundle_root_dir = _framework_root_dir
+      bundle_resources_dir = "$bundle_root_dir/Resources"
+      bundle_executable_dir = "$bundle_root_dir"
+
+      if (_code_signing_enabled) {
+        if (!defined(deps)) {
+          deps = []
+        }
+
+        if (_is_fat_build) {
+          deps += [ ":$_lipo_shared_library_target" ]
+        } else {
+          deps += [ ":$_link_shared_library_target" ]
+        }
+
+        _entitlements_path = "//build/config/ios/entitlements.plist"
+        if (defined(invoker.entitlements_path)) {
+          _entitlements_path = invoker.entitlements_path
+        }
+
+        code_signing_script = "//build/config/ios/codesign.py"
+        code_signing_sources = [
+          _entitlements_path,
+          "$_shared_library_dir/$_output_name",
+        ]
+        code_signing_outputs = [
+          "$bundle_root_dir/$_output_name",
+          "$bundle_root_dir/_CodeSignature/CodeResources",
+          "$bundle_root_dir/embedded.mobileprovision",
+        ]
+        code_signing_args = [
+          "-e=" + rebase_path(_entitlements_path, root_build_dir),
+          "code-sign-bundle",
+          "-i=" + ios_code_signing_identity,
+          "-b=" +
+              rebase_path("$_shared_library_dir/$_output_name", root_build_dir),
+          rebase_path(bundle_root_dir, root_build_dir),
+        ]
       }
     }
-  }
 
-  if (_has_public_headers) {
-    group(_target_name) {
-      forward_variables_from(invoker,
-                             [
-                               "testonly",
-                               "public_configs",
-                             ])
+    if (defined(_framework_version)) {
+      action(_target_name) {
+        forward_variables_from(invoker, [ "testonly" ])
 
-      if (defined(invoker.visibility)) {
-        visibility = invoker.visibility
-        visibility += [ ":$_target_name+link" ]
+        if (defined(invoker.visibility)) {
+          visibility = invoker.visibility
+          visibility += [ ":$_target_name+link" ]
+        }
+
+        script = "//build/config/mac/package_framework.py"
+        outputs = [
+          "$root_out_dir/$_framework_name/Versions/Current",
+        ]
+        args = [
+          "$_framework_name",
+          "$_framework_version",
+        ]
+        public_deps = [
+          ":$_framework_target",
+        ]
       }
-
-      public_deps = [
-        ":$_framework_target$_toolchain_suffix",
-      ]
     }
 
     group(_target_name + "+link") {
       forward_variables_from(invoker,
                              [
+                               "public_deps",
+                               "public_configs",
                                "testonly",
                                "visibility",
                              ])
-      public_deps = [
-        ":$_framework_target+link$_toolchain_suffix",
-      ]
-    }
-  }
+      if (!defined(public_deps)) {
+        public_deps = []
+      }
+      public_deps += [ ":$_target_name" ]
+      if (!defined(public_configs)) {
+        public_configs = []
+      }
+      public_configs += [ ":$_framework_public_config" ]
 
-  if (!_is_fat_build || _is_fat_build_main_target) {
+      if (_has_public_headers) {
+        public_configs += [ ":$_framework_headers_config" ]
+      }
+    }
+
     bundle_data(_target_name + "+bundle") {
       forward_variables_from(invoker,
                              [
@@ -1020,7 +1339,7 @@
                                "visibility",
                              ])
       public_deps = [
-        ":$_framework_target",
+        ":$_target_name",
       ]
       sources = [
         "$root_out_dir/$_output_name.framework",
@@ -1047,11 +1366,6 @@
     _output_name = invoker.output_name
   }
 
-  _is_fat_build = additional_toolchains != []
-  if (_is_fat_build) {
-    _is_fat_build_main_target = current_toolchain == default_toolchain
-  }
-
   _xctest_target = _target_name
   _xctest_output = _output_name
 
diff --git a/build/config/mac/base_rules.gni b/build/config/mac/base_rules.gni
index de36be4..4e34cb53c 100644
--- a/build/config/mac/base_rules.gni
+++ b/build/config/mac/base_rules.gni
@@ -126,430 +126,6 @@
   }
 }
 
-# This is used as the base template for both iOS and Mac frameworks.
-#
-# By default, the bundle target this template generates does not link the
-# resulting framework into anything that depends on it. If a dependency wants
-# a link-time (as well as build-time) dependency on the framework bundle,
-# depend against "$target_name+link". If only the build-time dependency is
-# required (e.g., for copying into another bundle), then use "$target_name".
-#
-# Arguments
-#
-#     output_name:
-#         (optional) string, name of the generated framework without the
-#         .framework suffix. If omitted, defaults to target_name.
-#
-#     framework_version:
-#         (optional) string, version of the framework. Typically this is a
-#         single letter, like "A". If omitted, the Versions/ subdirectory
-#         structure will not be created, and build output will go directly
-#         into the framework subdirectory.
-#
-# This template provides two targets for the resulting framework bundle. The
-# link-time behavior varies depending on which of the two targets below is
-# added as a dependency:
-#   - $target_name only adds a build-time dependency. Targets that depend on
-#     it will not link against the framework.
-#   - $target_name+link adds a build-time and link-time dependency. Targets
-#     that depend on it will link against the framework.
-#
-# The build-time-only dependency is used for when a target needs to use the
-# framework either only for resources, or because the target loads it at run-
-# time, via dlopen() or NSBundle. The link-time dependency will cause the
-# dependee to have the framework loaded by dyld at launch.
-#
-# Example of build-time only dependency:
-#
-#     framework_bundle("CoreTeleportation") {
-#       sources = [ ... ]
-#     }
-#
-#     bundle_data("core_teleportation_bundle_data") {
-#       deps = [ ":CoreTeleportation" ]
-#       sources = [ "$root_out_dir/CoreTeleportation.framework" ]
-#       outputs = [ "{{bundle_root_dir}}/Frameworks/{{source_file_part}}" ]
-#     }
-#
-#     app_bundle("GoatTeleporter") {
-#       sources = [ ... ]
-#       deps = [
-#         ":core_teleportation_bundle_data",
-#       ]
-#     }
-#
-# The GoatTeleporter.app will not directly link against
-# CoreTeleportation.framework, but it will be included in the bundle's
-# Frameworks directory.
-#
-# Example of link-time dependency:
-#
-#     framework_bundle("CoreTeleportation") {
-#       sources = [ ... ]
-#       ldflags = [
-#         "-install_name",
-#         "@executable_path/../Frameworks/$target_name.framework"
-#       ]
-#     }
-#
-#     bundle_data("core_teleportation_bundle_data") {
-#       deps = [ ":CoreTeleportation+link" ]
-#       sources = [ "$root_out_dir/CoreTeleportation.framework" ]
-#       outputs = [ "{{bundle_root_dir}}/Frameworks/{{source_file_part}}" ]
-#     }
-#
-#     app_bundle("GoatTeleporter") {
-#       sources = [ ... ]
-#       deps = [
-#         ":core_teleportation_bundle_data",
-#       ]
-#     }
-#
-# Note that the framework is still copied to the app's bundle, but dyld will
-# load this library when the app is launched because it uses the "+link"
-# target as a dependency. This also requires that the framework set its
-# install_name so that dyld can locate it.
-#
-# See "gn help shared_library" for more information on arguments supported
-# by shared library target.
-template("framework_bundle") {
-  _target_name = target_name
-  _output_name = target_name
-  if (defined(invoker.output_name)) {
-    _output_name = invoker.output_name
-  }
-
-  _is_fat_build = is_ios && additional_toolchains != []
-  if (_is_fat_build) {
-    _is_fat_build_main_target = current_toolchain == default_toolchain
-  }
-
-  # The expansion of the template is different for fat and thin builds. For
-  # thin build (and default toolchain of a fat build), the template expands
-  # to a "shared_library" target to create the bundle shared library and a
-  # "create_bundle" target (the main target) to create the bundle structure.
-  #
-  # For a fat build, the template just expands to the "shared_library" target
-  # for the non-default toolchain, while the final library is created using
-  # "lipo" in the expansion of the template for the default toolchain.
-  #
-  # The "$target_name+link" group for the non-default toolchain depends on the
-  # target of the same name from the default toolchain as this is the target
-  # that defines the real framework bundle (it will support the current cpu
-  # as it is a fat framework).
-
-  if (_is_fat_build && !_is_fat_build_main_target) {
-    shared_library(_target_name) {
-      forward_variables_from(invoker,
-                             "*",
-                             [
-                               "assert_no_deps",
-                               "bundle_deps",
-                               "code_signing_enabled",
-                               "data_deps",
-                               "info_plist",
-                               "info_plist_target",
-                               "output_name",
-                             ])
-      if (defined(visibility)) {
-        visibility += [ ":${_target_name}_shared_library($default_toolchain)" ]
-      }
-      output_name = _output_name
-      output_prefix_override = true
-      output_extension = ""
-      output_dir = "$target_out_dir/$_target_name"
-    }
-
-    group(_target_name + "+link") {
-      forward_variables_from(invoker,
-                             [
-                               "visibility",
-                               "testonly",
-                             ])
-      public_deps = [
-        ":$_target_name($default_toolchain)",
-      ]
-    }
-
-    if (defined(invoker.bundle_deps)) {
-      assert(invoker.bundle_deps != [], "mark bundle_deps as used")
-    }
-  } else {
-    _code_signing_enabled = is_ios && ios_enable_code_signing
-    if (defined(invoker.code_signing_enabled)) {
-      _code_signing_enabled =
-          invoker.code_signing_enabled && _code_signing_enabled
-    }
-
-    # If the framework is unversioned, the final _target_name will be the
-    # create_bundle(_framework_target), otherwise an action with the name
-    # _target_name will depends on the the create_bundle() in order to prepare
-    # the versioned directory structure.
-    _framework_target = _target_name
-    _framework_name = _output_name + ".framework"
-    _framework_root_dir = "$root_out_dir/$_framework_name"
-    if (defined(invoker.framework_version) && invoker.framework_version != "") {
-      _framework_version = invoker.framework_version
-      _framework_root_dir += "/Versions/$_framework_version"
-      _framework_target = _target_name + "_create_bundle"
-    }
-
-    _link_shared_library_target = target_name + "_shared_library"
-    _shared_library_dir = "$target_out_dir/$_link_shared_library_target"
-
-    if (_code_signing_enabled) {
-      _link_shared_library_visibility = [ ":$_framework_target" ]
-    } else {
-      _shared_library_bundle_data = target_name + "_shared_library_bundle_data"
-      _link_shared_library_visibility = [ ":$_shared_library_bundle_data" ]
-    }
-
-    if (_is_fat_build) {
-      _lipo_shared_library_target = _link_shared_library_target
-      _lipo_shared_library_visibility = _link_shared_library_visibility
-
-      _link_shared_library_visibility = []
-      _link_shared_library_visibility = [ ":$_lipo_shared_library_target" ]
-      _link_shared_library_target = target_name + "_arch_shared_library"
-
-      _arch_shared_library_dir = "$target_out_dir/$_link_shared_library_target"
-      _shared_library_dir = "$target_out_dir/$_lipo_shared_library_target"
-    }
-
-    shared_library(_link_shared_library_target) {
-      forward_variables_from(invoker,
-                             "*",
-                             [
-                               "assert_no_deps",
-                               "bundle_deps",
-                               "code_signing_enabled",
-                               "data_deps",
-                               "info_plist",
-                               "output_name",
-                               "visibility",
-                             ])
-      visibility = _link_shared_library_visibility
-      output_name = _output_name
-      output_prefix_override = true
-      output_extension = ""
-
-      if (!_is_fat_build) {
-        output_dir = _shared_library_dir
-      } else {
-        output_dir = _arch_shared_library_dir
-      }
-    }
-
-    if (_is_fat_build) {
-      action(_lipo_shared_library_target) {
-        forward_variables_from(invoker, [ "testonly" ])
-        visibility = _lipo_shared_library_visibility
-        script = "//build/toolchain/mac/linker_driver.py"
-        outputs = [
-          "$_shared_library_dir/$_output_name",
-        ]
-        inputs = [
-          "$_arch_shared_library_dir/$_output_name",
-        ]
-        deps = [
-          ":$_link_shared_library_target",
-        ]
-        foreach(_additional_toolchain, additional_toolchains) {
-          _additional_toolchain_target = "$_target_name($_additional_toolchain)"
-          deps += [ ":$_additional_toolchain_target" ]
-          inputs += [ get_label_info(_additional_toolchain_target,
-                                     "target_out_dir") + "/$_output_name" ]
-        }
-        args = [
-                 "xcrun",
-                 "lipo",
-                 "-create",
-                 "-output",
-                 rebase_path(outputs[0], root_build_dir),
-               ] + rebase_path(inputs, root_build_dir)
-
-        if (enable_dsyms) {
-          outputs += [ "$root_out_dir/$_output_name.dSYM/" ]
-          args +=
-              [ "-Wcrl,dsym," + rebase_path("$root_out_dir/.", root_build_dir) ]
-        }
-
-        if (enable_stripping) {
-          # Check whether //build/config/mac:strip_all has been removed from
-          # the configs variable (as this is how stripping is disabled for a
-          # single target).
-          _strip_all_in_config = false
-          if (defined(invoker.configs)) {
-            foreach(_config, invoker.configs) {
-              if (_config == "//build/config/mac:strip_all") {
-                _strip_all_in_config = true
-              }
-            }
-          }
-
-          if (_strip_all_in_config) {
-            args += [ "-Wcrl,strip,-x,-S" ]
-
-            if (save_unstripped_output) {
-              outputs += [ outputs[0] + ".unstripped" ]
-              args += [ "-Wcrl,unstripped," +
-                        rebase_path(get_path_info(outputs[0], "dir"),
-                                    root_build_dir) ]
-            }
-          }
-        }
-      }
-    }
-
-    if (!_code_signing_enabled) {
-      bundle_data(_shared_library_bundle_data) {
-        visibility = [ ":$_framework_target" ]
-        forward_variables_from(invoker, [ "testonly" ])
-        sources = [
-          "$_shared_library_dir/$_output_name",
-        ]
-        outputs = [
-          "{{bundle_executable_dir}}/$_output_name",
-        ]
-        if (_is_fat_build) {
-          public_deps = [
-            ":$_lipo_shared_library_target",
-          ]
-        } else {
-          public_deps = [
-            ":$_link_shared_library_target",
-          ]
-        }
-      }
-    }
-
-    _framework_public_config = _target_name + "_public_config"
-    config(_framework_public_config) {
-      # TODO(sdefresne): should we have a framework_dirs similar to lib_dirs
-      # and include_dirs to avoid duplicate values on the command-line.
-      visibility = [ ":$_framework_target" ]
-      ldflags = [
-        "-F",
-        rebase_path("$root_out_dir/.", root_build_dir),
-      ]
-      lib_dirs = [ root_out_dir ]
-      libs = [ _framework_name ]
-    }
-
-    create_bundle(_framework_target) {
-      forward_variables_from(invoker,
-                             [
-                               "data_deps",
-                               "deps",
-                               "public_deps",
-                               "testonly",
-                             ])
-
-      if (defined(_framework_version)) {
-        visibility = [ ":$_target_name" ]
-      } else {
-        if (defined(invoker.visibility)) {
-          visibility = invoker.visibility
-          visibility += [ ":$_target_name+link" ]
-        }
-      }
-
-      if (defined(invoker.bundle_deps)) {
-        if (!defined(deps)) {
-          deps = []
-        }
-        deps += invoker.bundle_deps
-      }
-
-      if (!_code_signing_enabled) {
-        if (!defined(public_deps)) {
-          public_deps = []
-        }
-        public_deps += [ ":$_shared_library_bundle_data" ]
-      }
-
-      bundle_root_dir = _framework_root_dir
-      bundle_resources_dir = "$bundle_root_dir/Resources"
-      bundle_executable_dir = "$bundle_root_dir"
-
-      if (_code_signing_enabled) {
-        if (!defined(deps)) {
-          deps = []
-        }
-
-        if (_is_fat_build) {
-          deps += [ ":$_lipo_shared_library_target" ]
-        } else {
-          deps += [ ":$_link_shared_library_target" ]
-        }
-
-        _entitlements_path = "//build/config/ios/entitlements.plist"
-        if (defined(invoker.entitlements_path)) {
-          _entitlements_path = invoker.entitlements_path
-        }
-
-        code_signing_script = "//build/config/ios/codesign.py"
-        code_signing_sources = [
-          _entitlements_path,
-          "$_shared_library_dir/$_output_name",
-        ]
-        code_signing_outputs = [
-          "$bundle_root_dir/$_output_name",
-          "$bundle_root_dir/_CodeSignature/CodeResources",
-          "$bundle_root_dir/embedded.mobileprovision",
-        ]
-        code_signing_args = [
-          "-e=" + rebase_path(_entitlements_path, root_build_dir),
-          "code-sign-bundle",
-          "-i=" + ios_code_signing_identity,
-          "-b=" +
-              rebase_path("$_shared_library_dir/$_output_name", root_build_dir),
-          rebase_path(bundle_root_dir, root_build_dir),
-        ]
-      }
-    }
-
-    if (defined(_framework_version)) {
-      action(_target_name) {
-        forward_variables_from(invoker, [ "testonly" ])
-
-        if (defined(invoker.visibility)) {
-          visibility = invoker.visibility
-          visibility += [ ":$_target_name+link" ]
-        }
-
-        script = "//build/config/mac/package_framework.py"
-        outputs = [
-          "$root_out_dir/$_framework_name/Versions/Current",
-        ]
-        args = [
-          "$_framework_name",
-          "$_framework_version",
-        ]
-        public_deps = [
-          ":$_framework_target",
-        ]
-      }
-    }
-
-    group(_target_name + "+link") {
-      forward_variables_from(invoker,
-                             [
-                               "public_configs",
-                               "testonly",
-                               "visibility",
-                             ])
-      public_deps = [
-        ":$_target_name",
-      ]
-      if (!defined(public_configs)) {
-        public_configs = []
-      }
-      public_configs += [ ":$_framework_public_config" ]
-    }
-  }
-}
-
 # Template to combile .xib or .storyboard files.
 #
 # Arguments
diff --git a/build/config/mac/rules.gni b/build/config/mac/rules.gni
index a221378..832f63595 100644
--- a/build/config/mac/rules.gni
+++ b/build/config/mac/rules.gni
@@ -116,12 +116,11 @@
 
 # Template to package a shared library into a Mac framework bundle.
 #
-# This template provides two targets to control whether the framework is
-# merely built when targets depend on it, or whether it is linked as well:
-# "$target_name" and "$target_name+link".
-#
-# See the //build/config/mac/base_rules.gni:framework_bundle for a discussion
-# and examples.
+# By default, the bundle target this template generates does not link the
+# resulting framework into anything that depends on it. If a dependency wants
+# a link-time (as well as build-time) dependency on the framework bundle,
+# depend against "$target_name+link". If only the build-time dependency is
+# required (e.g., for copying into another bundle), then use "$target_name".
 #
 # Arguments
 #
@@ -148,6 +147,70 @@
 #         (optional) string array, 'key=value' pairs for extra fields which are
 #         specified in a source Info.plist template.
 #
+# This template provides two targets for the resulting framework bundle. The
+# link-time behavior varies depending on which of the two targets below is
+# added as a dependency:
+#   - $target_name only adds a build-time dependency. Targets that depend on
+#     it will not link against the framework.
+#   - $target_name+link adds a build-time and link-time dependency. Targets
+#     that depend on it will link against the framework.
+#
+# The build-time-only dependency is used for when a target needs to use the
+# framework either only for resources, or because the target loads it at run-
+# time, via dlopen() or NSBundle. The link-time dependency will cause the
+# dependee to have the framework loaded by dyld at launch.
+#
+# Example of build-time only dependency:
+#
+#     mac_framework_bundle("CoreTeleportation") {
+#       sources = [ ... ]
+#     }
+#
+#     bundle_data("core_teleportation_bundle_data") {
+#       deps = [ ":CoreTeleportation" ]
+#       sources = [ "$root_out_dir/CoreTeleportation.framework" ]
+#       outputs = [ "{{bundle_root_dir}}/Frameworks/{{source_file_part}}" ]
+#     }
+#
+#     app_bundle("GoatTeleporter") {
+#       sources = [ ... ]
+#       deps = [
+#         ":core_teleportation_bundle_data",
+#       ]
+#     }
+#
+# The GoatTeleporter.app will not directly link against
+# CoreTeleportation.framework, but it will be included in the bundle's
+# Frameworks directory.
+#
+# Example of link-time dependency:
+#
+#     mac_framework_bundle("CoreTeleportation") {
+#       sources = [ ... ]
+#       ldflags = [
+#         "-install_name",
+#         "@executable_path/../Frameworks/$target_name.framework"
+#       ]
+#     }
+#
+#     bundle_data("core_teleportation_bundle_data") {
+#       deps = [ ":CoreTeleportation+link" ]
+#       sources = [ "$root_out_dir/CoreTeleportation.framework" ]
+#       outputs = [ "{{bundle_root_dir}}/Frameworks/{{source_file_part}}" ]
+#     }
+#
+#     app_bundle("GoatTeleporter") {
+#       sources = [ ... ]
+#       deps = [
+#         ":core_teleportation_bundle_data",
+#       ]
+#     }
+#
+# Note that the framework is still copied to the app's bundle, but dyld will
+# load this library when the app is launched because it uses the "+link"
+# target as a dependency. This also requires that the framework set its
+# install_name so that dyld can locate it.
+#
 # See "gn help shared_library" for more information on arguments supported
 # by shared library target.
 template("mac_framework_bundle") {
@@ -183,13 +246,149 @@
     ]
   }
 
-  framework_bundle(target_name) {
-    forward_variables_from(invoker, "*", [ "info_plist" ])
+  _target_name = target_name
+  _output_name = target_name
+  if (defined(invoker.output_name)) {
+    _output_name = invoker.output_name
+  }
+
+  # If the framework is unversioned, the final _target_name will be the
+  # create_bundle(_framework_target), otherwise an action with the name
+  # _target_name will depends on the the create_bundle() in order to prepare
+  # the versioned directory structure.
+  _framework_target = _target_name
+  _framework_name = _output_name + ".framework"
+  _framework_root_dir = "$root_out_dir/$_framework_name"
+  if (defined(invoker.framework_version) && invoker.framework_version != "") {
+    _framework_version = invoker.framework_version
+    _framework_root_dir += "/Versions/$_framework_version"
+    _framework_target = _target_name + "_create_bundle"
+  }
+
+  _link_shared_library_target = target_name + "_shared_library"
+  _shared_library_bundle_data = target_name + "_shared_library_bundle_data"
+
+  shared_library(_link_shared_library_target) {
+    forward_variables_from(invoker,
+                           "*",
+                           [
+                             "assert_no_deps",
+                             "bundle_deps",
+                             "code_signing_enabled",
+                             "data_deps",
+                             "info_plist",
+                             "info_plist_target",
+                             "output_name",
+                             "visibility",
+                           ])
+    visibility = [ ":$_shared_library_bundle_data" ]
+    output_name = _output_name
+    output_prefix_override = true
+    output_extension = ""
+    output_dir = "$target_out_dir/$_link_shared_library_target"
+  }
+
+  bundle_data(_shared_library_bundle_data) {
+    visibility = [ ":$_framework_target" ]
+    forward_variables_from(invoker, [ "testonly" ])
+    sources = [
+      "$target_out_dir/$_link_shared_library_target/$_output_name",
+    ]
+    outputs = [
+      "{{bundle_executable_dir}}/$_output_name",
+    ]
+    public_deps = [
+      ":$_link_shared_library_target",
+    ]
+  }
+
+  _framework_public_config = _target_name + "_public_config"
+  config(_framework_public_config) {
+    # TODO(sdefresne): should we have a framework_dirs similar to lib_dirs
+    # and include_dirs to avoid duplicate values on the command-line.
+    visibility = [ ":$_framework_target" ]
+    ldflags = [
+      "-F",
+      rebase_path("$root_out_dir/.", root_build_dir),
+    ]
+    lib_dirs = [ root_out_dir ]
+    libs = [ _framework_name ]
+  }
+
+  create_bundle(_framework_target) {
+    forward_variables_from(invoker,
+                           [
+                             "data_deps",
+                             "deps",
+                             "public_deps",
+                             "testonly",
+                           ])
+
+    if (defined(_framework_version)) {
+      visibility = [ ":$_target_name" ]
+    } else {
+      if (defined(invoker.visibility)) {
+        visibility = invoker.visibility
+        visibility += [ ":$_target_name+link" ]
+      }
+    }
 
     if (!defined(deps)) {
       deps = []
     }
     deps += [ ":$_info_plist_bundle_data" ]
+
+    if (defined(invoker.bundle_deps)) {
+      deps += invoker.bundle_deps
+    }
+
+    if (!defined(public_deps)) {
+      public_deps = []
+    }
+    public_deps += [ ":$_shared_library_bundle_data" ]
+
+    bundle_root_dir = _framework_root_dir
+    bundle_resources_dir = "$bundle_root_dir/Resources"
+    bundle_executable_dir = "$bundle_root_dir"
+  }
+
+  if (defined(_framework_version)) {
+    action(_target_name) {
+      forward_variables_from(invoker, [ "testonly" ])
+
+      if (defined(invoker.visibility)) {
+        visibility = invoker.visibility
+        visibility += [ ":$_target_name+link" ]
+      }
+
+      script = "//build/config/mac/package_framework.py"
+      outputs = [
+        "$root_out_dir/$_framework_name/Versions/Current",
+      ]
+      args = [
+        "$_framework_name",
+        "$_framework_version",
+      ]
+      public_deps = [
+        ":$_framework_target",
+      ]
+    }
+  }
+
+  group(_target_name + "+link") {
+    forward_variables_from(invoker,
+                           [
+                             "public_configs",
+                             "testonly",
+                             "visibility",
+                           ])
+    public_deps = [
+      ":$_target_name",
+    ]
+    if (!defined(public_configs)) {
+      public_configs = []
+    }
+    public_configs += [ ":$_framework_public_config" ]
   }
 }
 
diff --git a/build/config/sanitizers/BUILD.gn b/build/config/sanitizers/BUILD.gn
index 08ecb8d..359453b 100644
--- a/build/config/sanitizers/BUILD.gn
+++ b/build/config/sanitizers/BUILD.gn
@@ -191,6 +191,30 @@
         ]
       }
     }
+  } else if (is_win && is_asan) {
+    # Windows directly calls link.exe instead of the compiler driver when
+    # linking.  Hence, pass the runtime libraries instead of -fsanitize=address.
+    # In the static-library build, libraries are different for executables
+    # and dlls, see link_executable and link_shared_library below.
+    # This here handles only the component build.
+    if (target_cpu == "x64") {
+      # Windows 64-bit. TODO(etienneb): Remove the assert when this is ready.
+      if (is_component_build) {
+        assert(false, "win/asan does not work in 64-bit yet")
+        libs = [
+          "clang_rt.asan_dynamic-x86_64.lib",
+          "clang_rt.asan_dynamic_runtime_thunk-x86_64.lib",
+        ]
+      }
+    } else {
+      assert(target_cpu == "x86", "WinASan unsupported architecture")
+      if (is_component_build) {
+        libs = [
+          "clang_rt.asan_dynamic-i386.lib",
+          "clang_rt.asan_dynamic_runtime_thunk-i386.lib",
+        ]
+      }
+    }
   }
 }
 
@@ -246,36 +270,14 @@
           [ "-fsanitize-blacklist=" +
             rebase_path("//tools/memory/asan/blacklist.txt", root_build_dir) ]
     }
-
-    if (is_win) {
-      # In the static-library build, libraries are different for executables
-      # and dlls, see link_executable and link_shared_library below.
-      # This here handles only the component build.
-      if (target_cpu == "x64") {
-        # Windows 64-bit.
-        if (is_component_build) {
-          libs = [
-            "clang_rt.asan_dynamic-x86_64.lib",
-            "clang_rt.asan_dynamic_runtime_thunk-x86_64.lib",
-          ]
-        }
-      } else {
-        assert(target_cpu == "x86", "WinASan unsupported architecture")
-        if (is_component_build) {
-          libs = [
-            "clang_rt.asan_dynamic-i386.lib",
-            "clang_rt.asan_dynamic_runtime_thunk-i386.lib",
-          ]
-        }
-      }
-    }
   }
 }
 
 config("link_executable") {
   if (is_asan && is_win && !is_component_build) {
     if (target_cpu == "x64") {
-      # Windows 64-bit.
+      # Windows 64-bit. TODO(etienneb): Remove the assert when this is ready.
+      assert(false, "win/asan does not work in 64-bit yet")
       libs = [ "clang_rt.asan-x86_64.lib" ]
     } else {
       assert(target_cpu == "x86", "WinASan unsupported architecture")
@@ -287,7 +289,8 @@
 config("link_shared_library") {
   if (is_asan && is_win && !is_component_build) {
     if (target_cpu == "x64") {
-      # Windows 64-bit.
+      # Windows 64-bit. TODO(etienneb): Remove the assert when this is ready.
+      assert(false, "win/asan does not work in 64-bit yet")
       libs = [ "clang_rt.asan_dll_thunk-x86_64.lib" ]
     } else {
       assert(target_cpu == "x86", "WinASan unsupported architecture")
diff --git a/build/config/sanitizers/sanitizers.gni b/build/config/sanitizers/sanitizers.gni
index 16117223..ba1aec4 100644
--- a/build/config/sanitizers/sanitizers.gni
+++ b/build/config/sanitizers/sanitizers.gni
@@ -90,6 +90,30 @@
   sanitizer_coverage_flags = ""
 }
 
+# Disable sanitizers for non-default toolchains.
+if (current_toolchain != default_toolchain) {
+  is_asan = false
+  is_cfi = false
+  is_lsan = false
+  is_msan = false
+  is_syzyasan = false
+  is_tsan = false
+  is_ubsan = false
+  is_ubsan_null = false
+  is_ubsan_no_recover = false
+  is_ubsan_security = false
+  is_ubsan_vptr = false
+  msan_track_origins = 0
+  sanitizer_coverage_flags = ""
+  use_cfi_diag = false
+  use_custom_libcxx = false
+  use_drfuzz = false
+  use_libfuzzer = false
+  use_prebuilt_instrumented_libraries = false
+  use_locally_built_instrumented_libraries = false
+  use_sanitizer_coverage = false
+}
+
 # Args that are in turn dependent on other args must be in a separate
 # declare_args block. User overrides are only applied at the end of a
 # declare_args block.
diff --git a/build/experimental/install-build-deps.py b/build/experimental/install-build-deps.py
index 416eaa86..e5a2e80 100755
--- a/build/experimental/install-build-deps.py
+++ b/build/experimental/install-build-deps.py
@@ -137,6 +137,7 @@
   'libsqlite3-0',
   'libstdc++6',
   'libx11-6',
+  'libx11-xcb1',
   'libxau6',
   'libxcb1',
   'libxcomposite1',
@@ -167,6 +168,7 @@
   'libpixman-1-0-dbg',
   'libsqlite3-0-dbg',
   'libx11-6-dbg',
+  'libx11-xcb1-dbg',
   'libxau6-dbg',
   'libxcb1-dbg',
   'libxcomposite1-dbg',
diff --git a/build/gn_migration.gypi b/build/gn_migration.gypi
index c9c582dd..7535ff394 100644
--- a/build/gn_migration.gypi
+++ b/build/gn_migration.gypi
@@ -71,7 +71,6 @@
         '../printing/printing.gyp:printing_unittests',
         '../skia/skia_tests.gyp:skia_unittests',
         '../sql/sql.gyp:sql_unittests',
-        '../components/sync.gyp:sync_unit_tests',
         '../testing/gmock.gyp:gmock_main',
         '../third_party/WebKit/Source/platform/blink_platform_tests.gyp:blink_heap_unittests',
         '../third_party/WebKit/Source/platform/blink_platform_tests.gyp:blink_platform_unittests',
@@ -220,7 +219,6 @@
             '../sandbox/sandbox.gyp:sandbox_linux_unittests_deps',
             '../skia/skia_tests.gyp:skia_unittests_apk',
             '../sql/sql.gyp:sql_unittests_apk',
-            '../components/sync.gyp:sync_unit_tests_apk',
             '../testing/android/junit/junit_test.gyp:junit_unit_tests',
             '../third_party/smhasher/smhasher.gyp:murmurhash3',
             '../third_party/WebKit/Source/platform/blink_platform_tests.gyp:blink_heap_unittests_apk',
@@ -573,7 +571,6 @@
             '../remoting/remoting.gyp:remoting_unittests_run',
             '../skia/skia_tests.gyp:skia_unittests_run',
             '../sql/sql.gyp:sql_unittests_run',
-            '../components/sync.gyp:sync_unit_tests_run',
             '../third_party/WebKit/Source/platform/blink_platform_tests.gyp:blink_heap_unittests_run',
             '../third_party/WebKit/Source/platform/blink_platform_tests.gyp:blink_platform_unittests_run',
             '../third_party/WebKit/Source/web/web_tests.gyp:webkit_unit_tests_run',
diff --git a/build/install-build-deps.sh b/build/install-build-deps.sh
index f0ae0b14..832d116 100755
--- a/build/install-build-deps.sh
+++ b/build/install-build-deps.sh
@@ -125,18 +125,19 @@
 lib_list="libatk1.0-0 libc6 libasound2 libcairo2 libcap2 libcups2 libexpat1
           libffi6 libfontconfig1 libfreetype6 libglib2.0-0 libgnome-keyring0
           libgtk2.0-0 libpam0g libpango1.0-0 libpci3 libpcre3 libpixman-1-0
-          libpng12-0 libspeechd2 libstdc++6 libsqlite3-0 libx11-6 libxau6
-          libxcb1 libxcomposite1 libxcursor1 libxdamage1 libxdmcp6 libxext6
-          libxfixes3 libxi6 libxinerama1 libxrandr2 libxrender1 libxtst6
-          zlib1g $chromeos_lib_list"
+          libpng12-0 libspeechd2 libstdc++6 libsqlite3-0 libx11-6 libx11-xcb1
+          libxau6 libxcb1 libxcomposite1 libxcursor1 libxdamage1 libxdmcp6
+          libxext6 libxfixes3 libxi6 libxinerama1 libxrandr2 libxrender1
+          libxtst6 zlib1g $chromeos_lib_list"
 
 # Debugging symbols for all of the run-time libraries
 dbg_list="libatk1.0-dbg libc6-dbg libcairo2-dbg libffi6-dbg libfontconfig1-dbg
           libglib2.0-0-dbg libgtk2.0-0-dbg libpango1.0-0-dbg libpcre3-dbg
-          libpixman-1-0-dbg libsqlite3-0-dbg libx11-6-dbg libxau6-dbg
-          libxcb1-dbg libxcomposite1-dbg libxcursor1-dbg libxdamage1-dbg
-          libxdmcp6-dbg libxext6-dbg libxfixes3-dbg libxi6-dbg libxinerama1-dbg
-          libxrandr2-dbg libxrender1-dbg libxtst6-dbg zlib1g-dbg"
+          libpixman-1-0-dbg libsqlite3-0-dbg libx11-6-dbg libx11-xcb1-dbg
+          libxau6-dbg libxcb1-dbg libxcomposite1-dbg libxcursor1-dbg
+          libxdamage1-dbg libxdmcp6-dbg libxext6-dbg libxfixes3-dbg libxi6-dbg
+          libxinerama1-dbg libxrandr2-dbg libxrender1-dbg libxtst6-dbg
+          zlib1g-dbg"
 
 # Find the proper version of libstdc++6-4.x-dbg.
 if [ "x$lsb_release" = "xprecise" ]; then
diff --git a/build/sanitizers/tsan_suppressions.cc b/build/sanitizers/tsan_suppressions.cc
index 4b27af0a..ef7465a 100644
--- a/build/sanitizers/tsan_suppressions.cc
+++ b/build/sanitizers/tsan_suppressions.cc
@@ -270,6 +270,11 @@
 // http://crbug.com/633145
 "race:third_party/libjpeg_turbo/simd/jsimd_x86_64.c\n"
 
+// Intentional test-only race for otherwise untestable code, won't fix.
+// http://crbug.com/634383
+"race:ThreadTest_StartTwiceNonJoinableNotAllowed_Test::TestBody\n"
+"race:ThreadTest_StartWithOptions_NonJoinable_Test::TestBody\n"
+
 // End of suppressions.
 ;  // Please keep this semicolon.
 
diff --git a/build/toolchain/BUILD.gn b/build/toolchain/BUILD.gn
new file mode 100644
index 0000000..dacbd0f
--- /dev/null
+++ b/build/toolchain/BUILD.gn
@@ -0,0 +1,11 @@
+# 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.
+
+import("//build/toolchain/concurrent_links.gni")
+
+if (current_toolchain == default_toolchain) {
+  pool("link_pool") {
+    depth = concurrent_links
+  }
+}
diff --git a/build/toolchain/gcc_toolchain.gni b/build/toolchain/gcc_toolchain.gni
index 4cdd046..10a82bc 100644
--- a/build/toolchain/gcc_toolchain.gni
+++ b/build/toolchain/gcc_toolchain.gni
@@ -9,7 +9,6 @@
 import("//build/toolchain/cc_wrapper.gni")
 import("//build/toolchain/goma.gni")
 import("//build/toolchain/toolchain.gni")
-import("//build/toolchain/concurrent_links.gni")
 
 # This template defines a toolchain for something that works like gcc
 # (including clang).
@@ -114,8 +113,6 @@
     assert(defined(invoker.toolchain_os),
            "gcc_toolchain() must specify a \"toolchain_os\"")
 
-    # concurrent_links is picked up from the declare_arg().
-
     if (defined(invoker.cc_wrapper)) {
       cc_wrapper = invoker.cc_wrapper
     }
@@ -279,6 +276,7 @@
       soname = "{{target_output_name}}{{output_extension}}"  # e.g. "libfoo.so".
       sofile = "{{output_dir}}/$soname"  # Possibly including toolchain dir.
       rspfile = sofile + ".rsp"
+      pool = "//build/toolchain:link_pool($default_toolchain)"
 
       if (defined(invoker.strip)) {
         unstripped_sofile = "{{root_out_dir}}/lib.unstripped/$soname"
@@ -345,6 +343,7 @@
       soname = "{{target_output_name}}{{output_extension}}"  # e.g. "libfoo.so".
       sofile = "{{output_dir}}/$soname"
       rspfile = sofile + ".rsp"
+      pool = "//build/toolchain:link_pool($default_toolchain)"
 
       if (defined(invoker.strip)) {
         unstripped_sofile = "{{root_out_dir}}/lib.unstripped/$soname"
@@ -391,6 +390,7 @@
       outfile = "{{output_dir}}/$exename"
       rspfile = "$outfile.rsp"
       unstripped_outfile = outfile
+      pool = "//build/toolchain:link_pool($default_toolchain)"
 
       # Use this for {{output_extension}} expansions unless a target manually
       # overrides it (in which case {{output_extension}} will be what the target
@@ -474,28 +474,6 @@
       } else {
         v8_current_cpu = current_cpu
       }
-
-      # Disable sanitizers for non-default toolchains.
-      is_asan = false
-      is_cfi = false
-      is_lsan = false
-      is_msan = false
-      is_syzyasan = false
-      is_tsan = false
-      is_ubsan = false
-      is_ubsan_null = false
-      is_ubsan_no_recover = false
-      is_ubsan_security = false
-      is_ubsan_vptr = false
-      msan_track_origins = 0
-      sanitizer_coverage_flags = ""
-      use_cfi_diag = false
-      use_custom_libcxx = false
-      use_drfuzz = false
-      use_libfuzzer = false
-      use_prebuilt_instrumented_libraries = false
-      use_locally_built_instrumented_libraries = false
-      use_sanitizer_coverage = false
     }
 
     forward_variables_from(invoker, [ "deps" ])
diff --git a/build/toolchain/mac/BUILD.gn b/build/toolchain/mac/BUILD.gn
index a08e568a..dea16eb 100644
--- a/build/toolchain/mac/BUILD.gn
+++ b/build/toolchain/mac/BUILD.gn
@@ -70,8 +70,6 @@
     assert(defined(invoker.toolchain_os),
            "mac_toolchain() must specify a \"toolchain_os\"")
 
-    # concurrent_links is picked up from the declare_arg().
-
     if (use_goma) {
       assert(cc_wrapper == "", "Goma and cc_wrapper can't be used together.")
       _compiler_prefix = "$goma_dir/gomacc "
@@ -197,6 +195,7 @@
     tool("solink") {
       dylib = "{{output_dir}}/{{target_output_name}}{{output_extension}}"  # eg "./libfoo.dylib"
       rspfile = dylib + ".rsp"
+      pool = "//build/toolchain:link_pool($default_toolchain)"
 
       # These variables are not built into GN but are helpers that implement
       # (1) linking to produce a .dylib, (2) extracting the symbols from that
@@ -260,6 +259,7 @@
     tool("solink_module") {
       sofile = "{{output_dir}}/{{target_output_name}}{{output_extension}}"  # eg "./libfoo.so"
       rspfile = sofile + ".rsp"
+      pool = "//build/toolchain:link_pool($default_toolchain)"
 
       link_command = "$linker_driver $ld -bundle {{ldflags}} -o \"$sofile\" -Wl,-filelist,\"$rspfile\""
       if (is_component_build) {
@@ -294,6 +294,7 @@
     tool("link") {
       outfile = "{{output_dir}}/{{target_output_name}}{{output_extension}}"
       rspfile = "$outfile.rsp"
+      pool = "//build/toolchain:link_pool($default_toolchain)"
 
       # Note about --filelist: Apple's linker reads the file list file and
       # interprets each newline-separated chunk of text as a file name. It
diff --git a/build/toolchain/win/BUILD.gn b/build/toolchain/win/BUILD.gn
index 7d0b7d23..d726504 100644
--- a/build/toolchain/win/BUILD.gn
+++ b/build/toolchain/win/BUILD.gn
@@ -8,7 +8,6 @@
 import("//build/config/win/visual_studio_version.gni")
 import("//build/toolchain/goma.gni")
 import("//build/toolchain/toolchain.gni")
-import("//build/toolchain/concurrent_links.gni")
 
 # Should only be running on Windows.
 assert(is_win)
@@ -49,11 +48,6 @@
 #  toolchain_os: current_os to pass as a build arg
 #  environment: File name of environment file.
 template("msvc_toolchain") {
-  if (defined(invoker.concurrent_links)) {
-    # concurrent_links is picked up from the declare_arg() otherwise.
-    concurrent_links = invoker.concurrent_links
-  }
-
   env = invoker.environment
 
   if (invoker.is_clang && host_os != "win") {
@@ -182,6 +176,7 @@
       libname = "${dllname}.lib"  # e.g. foo.dll.lib
       pdbname = "${dllname}.pdb"
       rspfile = "${dllname}.rsp"
+      pool = "//build/toolchain:link_pool($default_toolchain)"
 
       command = "$python_path gyp-win-tool link-wrapper $env False $link /nologo /IMPLIB:$libname /DLL /OUT:$dllname /PDB:$pdbname @$rspfile"
 
@@ -214,6 +209,7 @@
       dllname = "{{output_dir}}/{{target_output_name}}{{output_extension}}"  # e.g. foo.dll
       pdbname = "${dllname}.pdb"
       rspfile = "${dllname}.rsp"
+      pool = "//build/toolchain:link_pool($default_toolchain)"
 
       command = "$python_path gyp-win-tool link-wrapper $env False $link /nologo /DLL /OUT:$dllname /PDB:$pdbname @$rspfile"
 
@@ -237,6 +233,7 @@
       exename = "{{output_dir}}/{{target_output_name}}{{output_extension}}"
       pdbname = "$exename.pdb"
       rspfile = "$exename.rsp"
+      pool = "//build/toolchain:link_pool($default_toolchain)"
 
       command = "$python_path gyp-win-tool link-wrapper $env False $link /nologo /OUT:$exename /PDB:$pdbname @$rspfile"
 
@@ -353,7 +350,6 @@
 template("win_x64_toolchains") {
   # TODO(mcgrathr): These assignments are only required because of
   # crbug.com/395883.  Drop them if that ever gets fixed in GN.
-  concurrent_links = invoker.concurrent_links
   goma_prefix = invoker.goma_prefix
   x64_toolchain_data = invoker.x64_toolchain_data
   clang_cl = invoker.clang_cl
@@ -391,7 +387,6 @@
 win_x64_toolchains("x64") {
   # TODO(mcgrathr): These assignments are only required because of
   # crbug.com/395883.  Drop them if that ever gets fixed in GN.
-  concurrent_links = concurrent_links
   goma_prefix = goma_prefix
   x64_toolchain_data = x64_toolchain_data
 }
@@ -406,7 +401,6 @@
 
   # TODO(mcgrathr): These assignments are only required because of
   # crbug.com/395883.  Drop them if that ever gets fixed in GN.
-  concurrent_links = concurrent_links
   goma_prefix = goma_prefix
   x64_toolchain_data = x64_toolchain_data
   clang_cl = clang_cl
diff --git a/cc/BUILD.gn b/cc/BUILD.gn
index 4137362..600920a7 100644
--- a/cc/BUILD.gn
+++ b/cc/BUILD.gn
@@ -604,8 +604,6 @@
     "test/begin_frame_args_test.h",
     "test/begin_frame_source_test.cc",
     "test/begin_frame_source_test.h",
-    "test/failure_output_surface.cc",
-    "test/failure_output_surface.h",
     "test/fake_channel_impl.cc",
     "test/fake_channel_impl.h",
     "test/fake_client_picture_cache.cc",
diff --git a/cc/base/switches.cc b/cc/base/switches.cc
index 82e4619..7de98ff 100644
--- a/cc/base/switches.cc
+++ b/cc/base/switches.cc
@@ -55,6 +55,11 @@
 const char kShowCompositedLayerBorders[] = "show-composited-layer-borders";
 const char kUIShowCompositedLayerBorders[] = "ui-show-layer-borders";
 
+// Renders a green border around GL composited texture quads to help
+// debug and study overlay support.
+const char kGlCompositedTextureQuadBorder[] =
+    "gl-composited-texture-quad-border";
+
 // Draws a heads-up-display showing Frames Per Second as well as GPU memory
 // usage. If you also use --enable-logging=stderr --vmodule="head*=1" then FPS
 // will also be output to the console log.
diff --git a/cc/base/switches.h b/cc/base/switches.h
index e39da61..439933765 100644
--- a/cc/base/switches.h
+++ b/cc/base/switches.h
@@ -34,6 +34,7 @@
 // Debug visualizations.
 CC_EXPORT extern const char kShowCompositedLayerBorders[];
 CC_EXPORT extern const char kUIShowCompositedLayerBorders[];
+CC_EXPORT extern const char kGlCompositedTextureQuadBorder[];
 CC_EXPORT extern const char kShowFPSCounter[];
 CC_EXPORT extern const char kUIShowFPSCounter[];
 CC_EXPORT extern const char kShowLayerAnimationBounds[];
diff --git a/cc/cc_tests.gyp b/cc/cc_tests.gyp
index d8250ea..a171014 100644
--- a/cc/cc_tests.gyp
+++ b/cc/cc_tests.gyp
@@ -176,8 +176,6 @@
       'test/begin_frame_args_test.h',
       'test/begin_frame_source_test.cc',
       'test/begin_frame_source_test.h',
-      'test/failure_output_surface.cc',
-      'test/failure_output_surface.h',
       'test/fake_channel_impl.cc',
       'test/fake_channel_impl.h',
       'test/fake_client_picture_cache.cc',
diff --git a/cc/layers/surface_layer_unittest.cc b/cc/layers/surface_layer_unittest.cc
index 5f40deb..0597cd76 100644
--- a/cc/layers/surface_layer_unittest.cc
+++ b/cc/layers/surface_layer_unittest.cc
@@ -174,14 +174,6 @@
 // Check that SurfaceSequence is sent through swap promise.
 class SurfaceLayerSwapPromiseWithDraw : public SurfaceLayerSwapPromise {
  public:
-  SurfaceLayerSwapPromiseWithDraw() : SurfaceLayerSwapPromise() {}
-
-  std::unique_ptr<OutputSurface> CreateOutputSurface() override {
-    auto ret = FakeOutputSurface::CreateDelegating3d();
-    output_surface_ = ret.get();
-    return std::move(ret);
-  }
-
   void ChangeTree() override {
     ++commit_count_;
     switch (commit_count_) {
@@ -197,9 +189,9 @@
     }
   }
 
-  void SwapBuffersCompleteOnThread() override {
-    std::vector<uint32_t>& satisfied =
-        output_surface_->last_sent_frame()->metadata.satisfies_sequences;
+  void DisplayReceivedCompositorFrameOnThread(
+      const CompositorFrame& frame) override {
+    const std::vector<uint32_t>& satisfied = frame.metadata.satisfies_sequences;
     EXPECT_LE(satisfied.size(), 1u);
     if (satisfied.size() == 1) {
       // Eventually the one SurfaceSequence should be satisfied, but only
@@ -219,8 +211,6 @@
     // callback.
     EXPECT_TRUE(satisfied_sequence_.is_null());
   }
-
-  FakeOutputSurface* output_surface_;
 };
 
 SINGLE_AND_MULTI_THREAD_TEST_F(SurfaceLayerSwapPromiseWithDraw);
diff --git a/cc/layers/texture_layer_unittest.cc b/cc/layers/texture_layer_unittest.cc
index 15d2131..39cad04 100644
--- a/cc/layers/texture_layer_unittest.cc
+++ b/cc/layers/texture_layer_unittest.cc
@@ -34,6 +34,7 @@
 #include "cc/test/layer_test_common.h"
 #include "cc/test/layer_tree_test.h"
 #include "cc/test/stub_layer_tree_host_single_thread_client.h"
+#include "cc/test/test_delegating_output_surface.h"
 #include "cc/test/test_task_graph_runner.h"
 #include "cc/test/test_web_graphics_context_3d.h"
 #include "cc/trees/blocking_task_runner.h"
@@ -631,12 +632,29 @@
 
 class TextureLayerImplWithMailboxThreadedCallback : public LayerTreeTest {
  public:
-  TextureLayerImplWithMailboxThreadedCallback()
-      : callback_count_(0),
-        commit_count_(0) {}
+  TextureLayerImplWithMailboxThreadedCallback() = default;
+
+  std::unique_ptr<TestDelegatingOutputSurface> CreateDelegatingOutputSurface(
+      scoped_refptr<ContextProvider> compositor_context_provider,
+      scoped_refptr<ContextProvider> worker_context_provider) override {
+    bool synchronous_composite =
+        !HasImplThread() &&
+        !layer_tree_host()->settings().single_thread_proxy_scheduler;
+    // Allow relaim resources for this test so that mailboxes in the display
+    // will be returned inside the commit that replaces them.
+    bool force_disable_reclaim_resources = false;
+    return base::MakeUnique<TestDelegatingOutputSurface>(
+        compositor_context_provider, std::move(worker_context_provider),
+        CreateDisplayOutputSurface(compositor_context_provider),
+        shared_bitmap_manager(), gpu_memory_buffer_manager(),
+        layer_tree_host()->settings().renderer_settings, ImplThreadTaskRunner(),
+        synchronous_composite, force_disable_reclaim_resources);
+  }
 
   // Make sure callback is received on main and doesn't block the impl thread.
-  void ReleaseCallback(const gpu::SyncToken& sync_token, bool lost_resource) {
+  void ReleaseCallback(char mailbox_char,
+                       const gpu::SyncToken& sync_token,
+                       bool lost_resource) {
     EXPECT_EQ(true, main_thread_.CalledOnValidThread());
     EXPECT_FALSE(lost_resource);
     ++callback_count_;
@@ -647,12 +665,15 @@
     std::unique_ptr<SingleReleaseCallback> callback =
         SingleReleaseCallback::Create(base::Bind(
             &TextureLayerImplWithMailboxThreadedCallback::ReleaseCallback,
-            base::Unretained(this)));
+            base::Unretained(this), mailbox_char));
     layer_->SetTextureMailbox(
         TextureMailbox(MailboxFromChar(mailbox_char),
                        SyncTokenFromUInt(static_cast<uint32_t>(mailbox_char)),
                        GL_TEXTURE_2D),
         std::move(callback));
+    // Damage the layer so we send a new frame with the new mailbox to the
+    // Display compositor.
+    layer_->SetNeedsDisplay();
   }
 
   void BeginTest() override {
@@ -703,32 +724,17 @@
         layer_->SetTextureMailbox(TextureMailbox(), nullptr);
         break;
       case 4:
-        // With impl painting, the texture mailbox will still be on the impl
-        // thread when the commit finishes, because the layer is not drawble
-        // when it has no texture mailbox, and thus does not block the commit
-        // on activation. So, we wait for activation.
-        // TODO(danakj): fix this. crbug.com/277953
-        layer_tree_host()->SetNeedsCommit();
-        break;
-      case 5:
         EXPECT_EQ(4, callback_count_);
         // Restore a mailbox for the next step.
         SetMailbox('5');
         break;
-      case 6:
+      case 5:
         // Case #5: remove layer from tree. Callback should *not* be called, the
         // mailbox is returned to the main thread.
         EXPECT_EQ(4, callback_count_);
         layer_->RemoveFromParent();
         break;
-      case 7:
-        // With impl painting, the texture mailbox will still be on the impl
-        // thread when the commit finishes, because the layer is not around to
-        // block the commit on activation anymore. So, we wait for activation.
-        // TODO(danakj): fix this. crbug.com/277953
-        layer_tree_host()->SetNeedsCommit();
-        break;
-      case 8:
+      case 6:
         EXPECT_EQ(4, callback_count_);
         // Resetting the mailbox will call the callback now.
         layer_->SetTextureMailbox(TextureMailbox(), nullptr);
@@ -745,8 +751,8 @@
 
  private:
   base::ThreadChecker main_thread_;
-  int callback_count_;
-  int commit_count_;
+  int callback_count_ = 0;
+  int commit_count_ = 0;
   scoped_refptr<Layer> root_;
   scoped_refptr<TextureLayer> layer_;
 };
diff --git a/cc/output/delegating_renderer_unittest.cc b/cc/output/delegating_renderer_unittest.cc
index 2af413d4..0394d12 100644
--- a/cc/output/delegating_renderer_unittest.cc
+++ b/cc/output/delegating_renderer_unittest.cc
@@ -13,22 +13,7 @@
 
 namespace cc {
 
-class DelegatingRendererTest : public LayerTreeTest {
- public:
-  DelegatingRendererTest() : LayerTreeTest(), output_surface_(NULL) {}
-  ~DelegatingRendererTest() override {}
-
-  std::unique_ptr<OutputSurface> CreateOutputSurface() override {
-    std::unique_ptr<FakeOutputSurface> output_surface =
-        FakeOutputSurface::CreateDelegating3d();
-    output_surface_ = output_surface.get();
-    return std::move(output_surface);
-  }
-
- protected:
-  TestWebGraphicsContext3D* context3d_;
-  FakeOutputSurface* output_surface_;
-};
+class DelegatingRendererTest : public LayerTreeTest {};
 
 class DelegatingRendererTestDraw : public DelegatingRendererTest {
  public:
@@ -39,40 +24,30 @@
 
   void AfterTest() override {}
 
-  DrawResult PrepareToDrawOnThread(LayerTreeHostImpl* host_impl,
-                                   LayerTreeHostImpl::FrameData* frame,
-                                   DrawResult draw_result) override {
-    EXPECT_EQ(0u, output_surface_->num_sent_frames());
-
-    const CompositorFrame* last_frame = output_surface_->last_sent_frame();
-    EXPECT_EQ(nullptr, last_frame);
-    return DRAW_SUCCESS;
-  }
-
   void DrawLayersOnThread(LayerTreeHostImpl* host_impl) override {
-    EXPECT_EQ(0u, output_surface_->num_sent_frames());
+    EXPECT_EQ(0, num_swaps_);
     drawn_viewport_ = host_impl->DeviceViewport();
   }
 
-  void SwapBuffersCompleteOnThread() override {
-    EXPECT_EQ(1u, output_surface_->num_sent_frames());
+  void DisplayReceivedCompositorFrameOnThread(
+      const CompositorFrame& frame) override {
+    EXPECT_EQ(1, ++num_swaps_);
 
-    const CompositorFrame* last_frame = output_surface_->last_sent_frame();
-    DelegatedFrameData* last_frame_data =
-        last_frame->delegated_frame_data.get();
-    ASSERT_TRUE(last_frame->delegated_frame_data);
-    EXPECT_FALSE(last_frame->gl_frame_data);
+    DelegatedFrameData* last_frame_data = frame.delegated_frame_data.get();
+    ASSERT_TRUE(frame.delegated_frame_data);
+    EXPECT_FALSE(frame.gl_frame_data);
     EXPECT_EQ(drawn_viewport_,
               last_frame_data->render_pass_list.back()->output_rect);
-    EXPECT_EQ(0.5f, last_frame->metadata.min_page_scale_factor);
-    EXPECT_EQ(4.f, last_frame->metadata.max_page_scale_factor);
+    EXPECT_EQ(0.5f, frame.metadata.min_page_scale_factor);
+    EXPECT_EQ(4.f, frame.metadata.max_page_scale_factor);
 
-    EXPECT_EQ(0u, last_frame->delegated_frame_data->resource_list.size());
-    EXPECT_EQ(1u, last_frame->delegated_frame_data->render_pass_list.size());
+    EXPECT_EQ(0u, frame.delegated_frame_data->resource_list.size());
+    EXPECT_EQ(1u, frame.delegated_frame_data->render_pass_list.size());
 
     EndTest();
   }
 
+  int num_swaps_ = 0;
   gfx::Rect drawn_viewport_;
 };
 
@@ -103,23 +78,17 @@
     return draw_result;
   }
 
-  void DrawLayersOnThread(LayerTreeHostImpl* host_impl) override {
-    EXPECT_EQ(0u, output_surface_->num_sent_frames());
-  }
+  void DisplayReceivedCompositorFrameOnThread(
+      const CompositorFrame& frame) override {
+    ASSERT_TRUE(frame.delegated_frame_data);
 
-  void SwapBuffersCompleteOnThread() override {
-    EXPECT_EQ(1u, output_surface_->num_sent_frames());
-
-    const CompositorFrame* last_frame = output_surface_->last_sent_frame();
-    ASSERT_TRUE(last_frame->delegated_frame_data);
-
-    EXPECT_EQ(2u, last_frame->delegated_frame_data->render_pass_list.size());
+    EXPECT_EQ(2u, frame.delegated_frame_data->render_pass_list.size());
     // Each render pass has 10 resources in it. And the root render pass has a
     // mask resource used when drawing the child render pass, as well as its
     // replica (it's added twice). The number 10 may change if
     // AppendOneOfEveryQuadType() is updated, and the value here should be
     // updated accordingly.
-    EXPECT_EQ(22u, last_frame->delegated_frame_data->resource_list.size());
+    EXPECT_EQ(22u, frame.delegated_frame_data->resource_list.size());
 
     EndTest();
   }
diff --git a/cc/output/gl_renderer.cc b/cc/output/gl_renderer.cc
index 7783adb..75a3db5 100644
--- a/cc/output/gl_renderer.cc
+++ b/cc/output/gl_renderer.cc
@@ -396,6 +396,8 @@
       highp_threshold_min_(highp_threshold_min),
       highp_threshold_cache_(0),
       use_sync_query_(false),
+      gl_composited_texture_quad_border_(
+          settings->gl_composited_texture_quad_border),
       bound_geometry_(NO_BINDING) {
   DCHECK(gl_);
   DCHECK(context_support_);
@@ -2554,6 +2556,28 @@
                     6 * static_cast<int>(draw_cache_.matrix_data.size()),
                     GL_UNSIGNED_SHORT, 0);
 
+  // Draw the border if requested.
+  if (gl_composited_texture_quad_border_) {
+    // When we draw the composited borders we have one flush per quad.
+    DCHECK_EQ(1u, draw_cache_.matrix_data.size());
+    SetBlendEnabled(false);
+    const DebugBorderProgram* program = GetDebugBorderProgram();
+    DCHECK(program && (program->initialized() || IsContextLost()));
+    SetUseProgram(program->program());
+
+    gl_->UniformMatrix4fv(
+        program->vertex_shader().matrix_location(), 1, false,
+        reinterpret_cast<float*>(&draw_cache_.matrix_data.front()));
+
+    gl_->Uniform4f(program->fragment_shader().color_location(), 0.0f, 1.0f,
+                   0.0f, 1.0f);
+
+    gl_->LineWidth(3.0f);
+    // The indices for the line are stored in the same array as the triangle
+    // indices.
+    gl_->DrawElements(GL_LINE_LOOP, 4, GL_UNSIGNED_SHORT, 0);
+  }
+
   // Clear the cache.
   draw_cache_.program_id = -1;
   draw_cache_.uv_xform_data.resize(0);
@@ -2678,6 +2702,8 @@
     PrepareGeometry(CLIPPED_BINDING);
     clipped_geometry_->InitializeCustomQuadWithUVs(scaled_region, uv);
     FlushTextureQuadCache(CLIPPED_BINDING);
+  } else if (gl_composited_texture_quad_border_) {
+    FlushTextureQuadCache(SHARED_BINDING);
   }
 }
 
diff --git a/cc/output/gl_renderer.h b/cc/output/gl_renderer.h
index 685b016..4e5c59c 100644
--- a/cc/output/gl_renderer.h
+++ b/cc/output/gl_renderer.h
@@ -532,6 +532,8 @@
   // overlay resource. This means the GLRenderer needs its own ResourcePool.
   std::unique_ptr<ResourcePool> overlay_resource_pool_;
 
+  // If true, draw a green border after compositing a texture quad using GL.
+  bool gl_composited_texture_quad_border_;
   BoundGeometry bound_geometry_;
   DISALLOW_COPY_AND_ASSIGN(GLRenderer);
 };
diff --git a/cc/output/renderer_settings.cc b/cc/output/renderer_settings.cc
index 23a3534f..308926c 100644
--- a/cc/output/renderer_settings.cc
+++ b/cc/output/renderer_settings.cc
@@ -21,6 +21,7 @@
       should_clear_root_render_pass(true),
       disable_display_vsync(false),
       release_overlay_resources_after_gpu_query(false),
+      gl_composited_texture_quad_border(false),
       refresh_rate(60.0),
       highp_threshold_min(0),
       texture_id_allocation_chunk_size(64),
diff --git a/cc/output/renderer_settings.h b/cc/output/renderer_settings.h
index eac84966..16e8be9 100644
--- a/cc/output/renderer_settings.h
+++ b/cc/output/renderer_settings.h
@@ -31,6 +31,8 @@
   bool should_clear_root_render_pass;
   bool disable_display_vsync;
   bool release_overlay_resources_after_gpu_query;
+  bool gl_composited_texture_quad_border;
+
   double refresh_rate;
   int highp_threshold_min;
   size_t texture_id_allocation_chunk_size;
diff --git a/cc/output/renderer_unittest.cc b/cc/output/renderer_unittest.cc
index 9fe079a..e02110d 100644
--- a/cc/output/renderer_unittest.cc
+++ b/cc/output/renderer_unittest.cc
@@ -42,7 +42,8 @@
  public:
   explicit MockContextProvider(
       std::unique_ptr<TestWebGraphicsContext3D> context)
-      : TestContextProvider(base::MakeUnique<TestGLES2Interface>(),
+      : TestContextProvider(base::MakeUnique<TestContextSupport>(),
+                            base::MakeUnique<TestGLES2Interface>(),
                             std::move(context)) {}
   MOCK_METHOD0(DeleteCachedResources, void());
 
diff --git a/cc/playback/display_item_list.h b/cc/playback/display_item_list.h
index bfc06c8..87a98fc 100644
--- a/cc/playback/display_item_list.h
+++ b/cc/playback/display_item_list.h
@@ -118,8 +118,6 @@
       const DisplayItemListSettings& display_list_settings);
   ~DisplayItemList();
 
-  void ProcessAppendedItem(const DisplayItem* item);
-
   RTree rtree_;
   // For testing purposes only. Whether to keep visual rects across calls to
   // Finalize().
diff --git a/cc/surfaces/display.cc b/cc/surfaces/display.cc
index fe35c7b..9ded1a21 100644
--- a/cc/surfaces/display.cc
+++ b/cc/surfaces/display.cc
@@ -288,6 +288,8 @@
     should_draw = false;
   }
 
+  client_->DisplayWillDrawAndSwap(should_draw, frame_data->render_pass_list);
+
   if (should_draw) {
     gfx::Rect device_viewport_rect = external_viewport_.IsEmpty()
                                          ? gfx::Rect(current_surface_size_)
@@ -339,6 +341,7 @@
     DidSwapBuffersComplete();
   }
 
+  client_->DisplayDidDrawAndSwap();
   return true;
 }
 
diff --git a/cc/surfaces/display.h b/cc/surfaces/display.h
index 24942a9..0fc2fb0 100644
--- a/cc/surfaces/display.h
+++ b/cc/surfaces/display.h
@@ -115,6 +115,7 @@
   }
 
   bool has_scheduler() const { return !!scheduler_; }
+  DirectRenderer* renderer_for_testing() const { return renderer_.get(); }
 
  private:
   void InitializeRenderer();
@@ -124,8 +125,8 @@
   gpu::GpuMemoryBufferManager* const gpu_memory_buffer_manager_;
   const RendererSettings settings_;
 
-  DisplayClient* client_;
-  SurfaceManager* surface_manager_;
+  DisplayClient* client_ = nullptr;
+  SurfaceManager* surface_manager_ = nullptr;
   uint32_t compositor_surface_namespace_;
   SurfaceId current_surface_id_;
   gfx::Size current_surface_size_;
diff --git a/cc/surfaces/display_client.h b/cc/surfaces/display_client.h
index 8f7be8b9..432b44ac 100644
--- a/cc/surfaces/display_client.h
+++ b/cc/surfaces/display_client.h
@@ -5,6 +5,8 @@
 #ifndef CC_SURFACES_DISPLAY_CLIENT_H_
 #define CC_SURFACES_DISPLAY_CLIENT_H_
 
+#include "cc/quads/render_pass.h"
+
 namespace cc {
 struct ManagedMemoryPolicy;
 
@@ -13,6 +15,9 @@
   virtual ~DisplayClient() {}
   virtual void DisplayOutputSurfaceLost() = 0;
   virtual void DisplaySetMemoryPolicy(const ManagedMemoryPolicy& policy) = 0;
+  virtual void DisplayWillDrawAndSwap(bool will_draw_and_swap,
+                                      const RenderPassList& render_passes) = 0;
+  virtual void DisplayDidDrawAndSwap() = 0;
 };
 
 }  // namespace cc
diff --git a/cc/surfaces/display_unittest.cc b/cc/surfaces/display_unittest.cc
index 74c6508..51e7fd6 100644
--- a/cc/surfaces/display_unittest.cc
+++ b/cc/surfaces/display_unittest.cc
@@ -164,6 +164,9 @@
  public:
   void DisplayOutputSurfaceLost() override {}
   void DisplaySetMemoryPolicy(const ManagedMemoryPolicy& policy) override {}
+  void DisplayWillDrawAndSwap(bool will_draw_and_swap,
+                              const RenderPassList& render_passes) override {}
+  void DisplayDidDrawAndSwap() override {}
 };
 
 void CopyCallback(bool* called, std::unique_ptr<CopyOutputResult> result) {
diff --git a/cc/surfaces/surface_display_output_surface.cc b/cc/surfaces/surface_display_output_surface.cc
index 3b1d59d..294840b 100644
--- a/cc/surfaces/surface_display_output_surface.cc
+++ b/cc/surfaces/surface_display_output_surface.cc
@@ -75,7 +75,7 @@
 
   factory_.SubmitCompositorFrame(
       delegated_surface_id_, std::move(frame),
-      base::Bind(&SurfaceDisplayOutputSurface::SwapBuffersComplete,
+      base::Bind(&SurfaceDisplayOutputSurface::DidDrawCallback,
                  base::Unretained(this)));
 }
 
@@ -153,7 +153,19 @@
   SetMemoryPolicy(policy);
 }
 
-void SurfaceDisplayOutputSurface::SwapBuffersComplete() {
+void SurfaceDisplayOutputSurface::DisplayWillDrawAndSwap(
+    bool will_draw_and_swap,
+    const RenderPassList& render_passes) {
+  // This notification is not relevant to our client outside of tests.
+}
+
+void SurfaceDisplayOutputSurface::DisplayDidDrawAndSwap() {
+  // This notification is not relevant to our client outside of tests. We
+  // unblock the client from DidDrawCallback() when the surface is going to
+  // be drawn.
+}
+
+void SurfaceDisplayOutputSurface::DidDrawCallback() {
   // TODO(danakj): Why the lost check?
   if (!output_surface_lost_)
     client_->DidSwapBuffersComplete();
diff --git a/cc/surfaces/surface_display_output_surface.h b/cc/surfaces/surface_display_output_surface.h
index f1bd5ea..d5f2d9f 100644
--- a/cc/surfaces/surface_display_output_surface.h
+++ b/cc/surfaces/surface_display_output_surface.h
@@ -55,9 +55,12 @@
   // DisplayClient implementation.
   void DisplayOutputSurfaceLost() override;
   void DisplaySetMemoryPolicy(const ManagedMemoryPolicy& policy) override;
+  void DisplayWillDrawAndSwap(bool will_draw_and_swap,
+                              const RenderPassList& render_passes) override;
+  void DisplayDidDrawAndSwap() override;
 
  private:
-  void SwapBuffersComplete();
+  void DidDrawCallback();
 
   // This class is only meant to be used on a single thread.
   base::ThreadChecker thread_checker_;
diff --git a/cc/test/failure_output_surface.cc b/cc/test/failure_output_surface.cc
deleted file mode 100644
index 64c9b8a..0000000
--- a/cc/test/failure_output_surface.cc
+++ /dev/null
@@ -1,18 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "cc/test/failure_output_surface.h"
-
-namespace cc {
-
-FailureOutputSurface::FailureOutputSurface(bool is_delegating)
-    : FakeOutputSurface(nullptr, nullptr, is_delegating) {}
-
-bool FailureOutputSurface::BindToClient(OutputSurfaceClient* client) {
-  // This will force this output surface to not initialize in LTHI
-  // and eventually get back to LTH::DidFailToInitializeOutputSurface;
-  return false;
-}
-
-}  // namespace cc
diff --git a/cc/test/failure_output_surface.h b/cc/test/failure_output_surface.h
deleted file mode 100644
index a7aca5b..0000000
--- a/cc/test/failure_output_surface.h
+++ /dev/null
@@ -1,25 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CC_TEST_FAILURE_OUTPUT_SURFACE_H_
-#define CC_TEST_FAILURE_OUTPUT_SURFACE_H_
-
-#include "base/macros.h"
-#include "cc/test/fake_output_surface.h"
-
-namespace cc {
-
-class FailureOutputSurface : public FakeOutputSurface {
- public:
-  explicit FailureOutputSurface(bool is_delegating);
-
-  bool BindToClient(OutputSurfaceClient* client) override;
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(FailureOutputSurface);
-};
-
-}  // namespace cc
-
-#endif  // CC_TEST_FAILURE_OUTPUT_SURFACE_H_
diff --git a/cc/test/fake_output_surface.h b/cc/test/fake_output_surface.h
index e985bcf5..f3748ca 100644
--- a/cc/test/fake_output_surface.h
+++ b/cc/test/fake_output_surface.h
@@ -46,9 +46,8 @@
 
   static std::unique_ptr<FakeOutputSurface> Create3d(
       std::unique_ptr<TestGLES2Interface> gl) {
-    return base::WrapUnique(
-        new FakeOutputSurface(TestContextProvider::Create(std::move(gl)),
-                              TestContextProvider::CreateWorker(), false));
+    return base::WrapUnique(new FakeOutputSurface(
+        TestContextProvider::Create(std::move(gl)), nullptr, false));
   }
 
   static std::unique_ptr<FakeOutputSurface> Create3d(
diff --git a/cc/test/layer_tree_pixel_test.cc b/cc/test/layer_tree_pixel_test.cc
index 901bff9..ae31dba 100644
--- a/cc/test/layer_tree_pixel_test.cc
+++ b/cc/test/layer_tree_pixel_test.cc
@@ -37,27 +37,49 @@
 
 LayerTreePixelTest::~LayerTreePixelTest() {}
 
-void LayerTreePixelTest::InitializeSettings(LayerTreeSettings* settings) {
-  // The PixelTestDelegatingOutputSurface will provide a BeginFrameSource.
-  settings->use_output_surface_begin_frame_source = true;
-}
-
-std::unique_ptr<OutputSurface> LayerTreePixelTest::CreateOutputSurface() {
-  // Always test Webview shenanigans.
-  gfx::Size surface_expansion_size(40, 60);
-
+std::unique_ptr<TestDelegatingOutputSurface>
+    LayerTreePixelTest::CreateDelegatingOutputSurface(
+        scoped_refptr<ContextProvider>,
+        scoped_refptr<ContextProvider>) {
   scoped_refptr<TestInProcessContextProvider> compositor_context_provider;
   scoped_refptr<TestInProcessContextProvider> worker_context_provider;
-  scoped_refptr<TestInProcessContextProvider> display_context_provider;
-  std::unique_ptr<PixelTestOutputSurface> display_output_surface;
   if (test_type_ == PIXEL_TEST_GL) {
     compositor_context_provider = new TestInProcessContextProvider(nullptr);
     worker_context_provider =
         new TestInProcessContextProvider(compositor_context_provider.get());
-    display_context_provider = new TestInProcessContextProvider(nullptr);
+  }
+  bool synchronous_composite =
+      !HasImplThread() &&
+      !layer_tree_host()->settings().single_thread_proxy_scheduler;
+  // Allow resource reclaiming for partial raster tests to get back
+  // resources from the Display.
+  bool force_disable_reclaim_resources = false;
+  auto delegating_output_surface =
+      base::MakeUnique<TestDelegatingOutputSurface>(
+          compositor_context_provider, std::move(worker_context_provider),
+          CreateDisplayOutputSurface(compositor_context_provider),
+          shared_bitmap_manager(), gpu_memory_buffer_manager(),
+          RendererSettings(), ImplThreadTaskRunner(), synchronous_composite,
+          force_disable_reclaim_resources);
+  delegating_output_surface->display()->SetEnlargePassTextureAmountForTesting(
+      enlarge_texture_amount_);
+  return delegating_output_surface;
+}
+
+std::unique_ptr<OutputSurface> LayerTreePixelTest::CreateDisplayOutputSurface(
+    scoped_refptr<ContextProvider> compositor_context_provider) {
+  // Always test Webview shenanigans.
+  gfx::Size surface_expansion_size(40, 60);
+
+  std::unique_ptr<PixelTestOutputSurface> display_output_surface;
+  if (test_type_ == PIXEL_TEST_GL) {
     bool flipped_output_surface = false;
     display_output_surface = base::MakeUnique<PixelTestOutputSurface>(
-        std::move(display_context_provider), nullptr, flipped_output_surface);
+        // Pixel tests use a separate context for the Display to more closely
+        // mimic texture transport from the renderer process to the Display
+        // compositor.
+        make_scoped_refptr(new TestInProcessContextProvider(nullptr)), nullptr,
+        flipped_output_surface);
   } else {
     std::unique_ptr<PixelTestSoftwareOutputDevice> software_output_device(
         new PixelTestSoftwareOutputDevice);
@@ -66,20 +88,7 @@
         std::move(software_output_device));
   }
   display_output_surface->set_surface_expansion_size(surface_expansion_size);
-
-  auto* task_runner = ImplThreadTaskRunner();
-  bool synchronous_composite =
-      !HasImplThread() &&
-      !layer_tree_host()->settings().single_thread_proxy_scheduler;
-  auto delegating_output_surface =
-      base::MakeUnique<TestDelegatingOutputSurface>(
-          std::move(compositor_context_provider),
-          std::move(worker_context_provider), std::move(display_output_surface),
-          shared_bitmap_manager(), gpu_memory_buffer_manager(),
-          RendererSettings(), task_runner, synchronous_composite);
-  delegating_output_surface->display()->SetEnlargePassTextureAmountForTesting(
-      enlarge_texture_amount_);
-  return std::move(delegating_output_surface);
+  return std::move(display_output_surface);
 }
 
 std::unique_ptr<CopyOutputRequest>
diff --git a/cc/test/layer_tree_pixel_test.h b/cc/test/layer_tree_pixel_test.h
index 3ab75b4..3e266cb2 100644
--- a/cc/test/layer_tree_pixel_test.h
+++ b/cc/test/layer_tree_pixel_test.h
@@ -41,8 +41,11 @@
   ~LayerTreePixelTest() override;
 
   // LayerTreeTest overrides.
-  void InitializeSettings(LayerTreeSettings* settings) override;
-  std::unique_ptr<OutputSurface> CreateOutputSurface() override;
+  std::unique_ptr<TestDelegatingOutputSurface> CreateDelegatingOutputSurface(
+      scoped_refptr<ContextProvider> compositor_context_provider,
+      scoped_refptr<ContextProvider> worker_context_provider) override;
+  std::unique_ptr<OutputSurface> CreateDisplayOutputSurface(
+      scoped_refptr<ContextProvider> compositor_context_provider) override;
 
   virtual std::unique_ptr<CopyOutputRequest> CreateCopyOutputRequest();
 
diff --git a/cc/test/layer_tree_test.cc b/cc/test/layer_tree_test.cc
index 49d4a70..5f64fc2c 100644
--- a/cc/test/layer_tree_test.cc
+++ b/cc/test/layer_tree_test.cc
@@ -28,9 +28,8 @@
 #include "cc/test/fake_layer_tree_host_client.h"
 #include "cc/test/fake_output_surface.h"
 #include "cc/test/test_context_provider.h"
-#include "cc/test/test_gpu_memory_buffer_manager.h"
+#include "cc/test/test_delegating_output_surface.h"
 #include "cc/test/test_shared_bitmap_manager.h"
-#include "cc/test/test_task_graph_runner.h"
 #include "cc/trees/layer_tree_host_client.h"
 #include "cc/trees/layer_tree_host_impl.h"
 #include "cc/trees/layer_tree_host_single_thread_client.h"
@@ -183,15 +182,6 @@
     test_hooks_->DrawLayersOnThread(this);
   }
 
-  void DidSwapBuffersComplete() override {
-    LayerTreeHostImpl::DidSwapBuffersComplete();
-    test_hooks_->SwapBuffersCompleteOnThread();
-  }
-
-  void ReclaimResources(const ReturnedResourceArray& resources) override {
-    LayerTreeHostImpl::ReclaimResources(resources);
-  }
-
   void NotifyReadyToActivate() override {
     if (block_notify_ready_to_activate_for_testing_) {
       notify_ready_to_activate_was_blocked_ = true;
@@ -441,19 +431,34 @@
   bool test_started_;
 };
 
+class LayerTreeTestDelegatingOutputSurfaceClient
+    : public TestDelegatingOutputSurfaceClient {
+ public:
+  explicit LayerTreeTestDelegatingOutputSurfaceClient(TestHooks* hooks)
+      : hooks_(hooks) {}
+
+  // TestDelegatingOutputSurfaceClient implementation.
+  void DisplayReceivedCompositorFrame(const CompositorFrame& frame) override {
+    hooks_->DisplayReceivedCompositorFrameOnThread(frame);
+  }
+  void DisplayWillDrawAndSwap(bool will_draw_and_swap,
+                              const RenderPassList& render_passes) override {
+    hooks_->DisplayWillDrawAndSwapOnThread(will_draw_and_swap, render_passes);
+  }
+  void DisplayDidDrawAndSwap() override {
+    hooks_->DisplayDidDrawAndSwapOnThread();
+  }
+
+ private:
+  TestHooks* hooks_;
+};
+
 LayerTreeTest::LayerTreeTest()
-    : external_begin_frame_source_(nullptr),
-      remote_proto_channel_bridge_(this),
+    : remote_proto_channel_bridge_(this),
       image_serialization_processor_(
           base::WrapUnique(new FakeImageSerializationProcessor)),
-      beginning_(false),
-      end_when_begin_returns_(false),
-      timed_out_(false),
-      scheduled_(false),
-      started_(false),
-      ended_(false),
-      delegating_renderer_(false),
-      timeout_seconds_(0),
+      delegating_output_surface_client_(
+          new LayerTreeTestDelegatingOutputSurfaceClient(this)),
       weak_factory_(this) {
   main_thread_weak_ptr_ = weak_factory_.GetWeakPtr();
 
@@ -600,16 +605,6 @@
                  main_thread_weak_ptr_));
 }
 
-void LayerTreeTest::SetOutputSurfaceOnLayerTreeHost(
-    std::unique_ptr<OutputSurface> output_surface) {
-  if (IsRemoteTest()) {
-    DCHECK(remote_client_layer_tree_host_);
-    remote_client_layer_tree_host_->SetOutputSurface(std::move(output_surface));
-  } else {
-    layer_tree_host_->SetOutputSurface(std::move(output_surface));
-  }
-}
-
 std::unique_ptr<OutputSurface>
 LayerTreeTest::ReleaseOutputSurfaceOnLayerTreeHost() {
   if (IsRemoteTest()) {
@@ -635,14 +630,6 @@
 void LayerTreeTest::DoBeginTest() {
   client_ = LayerTreeHostClientForTesting::Create(this);
 
-  std::unique_ptr<FakeExternalBeginFrameSource> external_begin_frame_source;
-  if (settings_.use_external_begin_frame_source) {
-    DCHECK(!IsRemoteTest());
-    external_begin_frame_source.reset(new FakeExternalBeginFrameSource(
-        settings_.renderer_settings.refresh_rate, true));
-    external_begin_frame_source_ = external_begin_frame_source.get();
-  }
-
   DCHECK(!impl_thread_ || impl_thread_->task_runner().get());
 
   if (IsRemoteTest()) {
@@ -650,8 +637,7 @@
     layer_tree_host_ = LayerTreeHostForTesting::Create(
         this, mode_, client_.get(), &remote_proto_channel_bridge_.channel_main,
         nullptr, nullptr, task_graph_runner_.get(), settings_,
-        base::ThreadTaskRunnerHandle::Get(), nullptr,
-        std::move(external_begin_frame_source),
+        base::ThreadTaskRunnerHandle::Get(), nullptr, nullptr,
         image_serialization_processor_.get());
     DCHECK(remote_proto_channel_bridge_.channel_main.HasReceiver());
   } else {
@@ -659,8 +645,7 @@
         this, mode_, client_.get(), nullptr, shared_bitmap_manager_.get(),
         gpu_memory_buffer_manager_.get(), task_graph_runner_.get(), settings_,
         base::ThreadTaskRunnerHandle::Get(),
-        impl_thread_ ? impl_thread_->task_runner() : NULL,
-        std::move(external_begin_frame_source),
+        impl_thread_ ? impl_thread_->task_runner() : nullptr, nullptr,
         image_serialization_processor_.get());
   }
 
@@ -828,7 +813,11 @@
   settings_.verify_transform_tree_calculations = true;
   settings_.renderer_settings.buffer_to_texture_target_map =
       DefaultBufferToTextureTargetMapForTesting();
+  // The TestDelegatingOutputSurface will provide a BeginFrameSource.
+  settings_.use_output_surface_begin_frame_source = true;
   InitializeSettings(&settings_);
+  DCHECK(settings_.use_output_surface_begin_frame_source);
+  DCHECK(!settings_.use_external_begin_frame_source);
 
   base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE,
@@ -849,22 +838,46 @@
 }
 
 void LayerTreeTest::RequestNewOutputSurface() {
-  if (settings_.use_external_begin_frame_source &&
-      settings_.wait_for_beginframe_interval) {
-    DCHECK(external_begin_frame_source_);
+  scoped_refptr<TestContextProvider> shared_context_provider =
+      TestContextProvider::Create();
+  scoped_refptr<TestContextProvider> worker_context_provider =
+      TestContextProvider::CreateWorker();
+
+  auto delegating_output_surface = CreateDelegatingOutputSurface(
+      std::move(shared_context_provider), std::move(worker_context_provider));
+  delegating_output_surface->SetClient(delegating_output_surface_client_.get());
+
+  if (IsRemoteTest()) {
+    DCHECK(remote_client_layer_tree_host_);
+    remote_client_layer_tree_host_->SetOutputSurface(
+        std::move(delegating_output_surface));
+  } else {
+    layer_tree_host_->SetOutputSurface(std::move(delegating_output_surface));
   }
-  SetOutputSurfaceOnLayerTreeHost(CreateOutputSurface());
 }
 
-std::unique_ptr<OutputSurface> LayerTreeTest::CreateOutputSurface() {
-  if (delegating_renderer_)
-    return FakeOutputSurface::CreateDelegating3d();
+std::unique_ptr<TestDelegatingOutputSurface>
+LayerTreeTest::CreateDelegatingOutputSurface(
+    scoped_refptr<ContextProvider> compositor_context_provider,
+    scoped_refptr<ContextProvider> worker_context_provider) {
+  bool synchronous_composite =
+      !HasImplThread() &&
+      !layer_tree_host()->settings().single_thread_proxy_scheduler;
+  // Disable reclaim resources by default to act like the Display lives
+  // out-of-process.
+  bool force_disable_reclaim_resources = true;
+  return base::MakeUnique<TestDelegatingOutputSurface>(
+      compositor_context_provider, std::move(worker_context_provider),
+      CreateDisplayOutputSurface(compositor_context_provider),
+      shared_bitmap_manager(), gpu_memory_buffer_manager(),
+      layer_tree_host()->settings().renderer_settings, ImplThreadTaskRunner(),
+      synchronous_composite, force_disable_reclaim_resources);
+}
 
-  // Make a worker context in a non-delegating OutputSurface. This is an
-  // exceptional situation for these tests as they put a non-delegating
-  // OutputSurface into the LayerTreeHost.
-  return FakeOutputSurface::Create3d(TestContextProvider::Create(),
-                                     TestContextProvider::CreateWorker());
+std::unique_ptr<OutputSurface> LayerTreeTest::CreateDisplayOutputSurface(
+    scoped_refptr<ContextProvider> compositor_context_provider) {
+  // By default the Display shares a context with the LayerTreeHostImpl.
+  return FakeOutputSurface::Create3d(std::move(compositor_context_provider));
 }
 
 void LayerTreeTest::DestroyLayerTreeHost() {
@@ -909,10 +922,6 @@
   DCHECK(task_runner_provider()->HasImplThread());
 }
 
-TaskGraphRunner* LayerTreeTest::task_graph_runner() const {
-  return task_graph_runner_.get();
-}
-
 TaskRunnerProvider* LayerTreeTest::task_runner_provider() const {
   // All LayerTreeTests can use the task runner provider to access the impl
   // thread. In the remote mode, the impl thread of the compositor lives on
diff --git a/cc/test/layer_tree_test.h b/cc/test/layer_tree_test.h
index 678b5d7..d682495 100644
--- a/cc/test/layer_tree_test.h
+++ b/cc/test/layer_tree_test.h
@@ -9,14 +9,15 @@
 #include "base/threading/thread.h"
 #include "cc/animation/animation_delegate.h"
 #include "cc/test/remote_proto_channel_bridge.h"
+#include "cc/test/test_gpu_memory_buffer_manager.h"
 #include "cc/test/test_hooks.h"
+#include "cc/test/test_task_graph_runner.h"
 #include "cc/trees/layer_tree_host.h"
 #include "cc/trees/layer_tree_host_impl.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace cc {
 class AnimationPlayer;
-class FakeExternalBeginFrameSource;
 class FakeLayerTreeHostClient;
 class FakeOutputSurface;
 class LayerImpl;
@@ -24,10 +25,12 @@
 class LayerTreeHostForTesting;
 class LayerTreeHostClient;
 class LayerTreeHostImpl;
+class LayerTreeTestDelegatingOutputSurfaceClient;
 class ProxyImpl;
 class ProxyMain;
 class RemoteChannelImplForTest;
 class TestContextProvider;
+class TestDelegatingOutputSurface;
 class TestGpuMemoryBufferManager;
 class TestTaskGraphRunner;
 class TestWebGraphicsContext3D;
@@ -113,8 +116,6 @@
   void DispatchCompositeImmediately();
   void DispatchNextCommitWaitsForActivation();
 
-  void SetOutputSurfaceOnLayerTreeHost(
-      std::unique_ptr<OutputSurface> output_surface);
   std::unique_ptr<OutputSurface> ReleaseOutputSurfaceOnLayerTreeHost();
   void SetVisibleOnLayerTreeHost(bool visible);
 
@@ -137,7 +138,9 @@
   }
   Proxy* remote_client_proxy() const;
   TaskRunnerProvider* task_runner_provider() const;
-  TaskGraphRunner* task_graph_runner() const;
+  TaskGraphRunner* task_graph_runner() const {
+    return task_graph_runner_.get();
+  }
   bool TestEnded() const { return ended_; }
 
   LayerTreeHost* layer_tree_host();
@@ -146,7 +149,7 @@
   SharedBitmapManager* shared_bitmap_manager() const {
     return shared_bitmap_manager_.get();
   }
-  TestGpuMemoryBufferManager* gpu_memory_buffer_manager() {
+  gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager() {
     return gpu_memory_buffer_manager_.get();
   }
 
@@ -158,9 +161,20 @@
 
   // By default, output surface recreation is synchronous.
   void RequestNewOutputSurface() override;
-  // Override this for pixel tests, where you need a real output surface, or
-  // if you want to control the output surface used for drawing.
-  virtual std::unique_ptr<OutputSurface> CreateOutputSurface();
+  // Override this and call the base class to change what ContextProviders will
+  // be used (such as for pixel tests). Or override it and create your own
+  // TestDelegatingOutputSurface to control how it is created.
+  virtual std::unique_ptr<TestDelegatingOutputSurface>
+  CreateDelegatingOutputSurface(
+      scoped_refptr<ContextProvider> compositor_context_provider,
+      scoped_refptr<ContextProvider> worker_context_provider);
+  // Override this and call the base class to change what ContextProvider will
+  // be used, such as to prevent sharing the context with the delegating
+  // OutputSurface. Or override it and create your own OutputSurface to change
+  // what type of OutputSurface is used, such as a real OutputSurface for pixel
+  // tests or a software-compositing OutputSurface.
+  virtual std::unique_ptr<OutputSurface> CreateDisplayOutputSurface(
+      scoped_refptr<ContextProvider> compositor_context_provider);
 
   bool IsRemoteTest() const;
 
@@ -177,21 +191,22 @@
   // The LayerTreeHost created by the cc embedder on the client in remote mode.
   std::unique_ptr<LayerTreeHostForTesting> remote_client_layer_tree_host_;
 
-  FakeExternalBeginFrameSource* external_begin_frame_source_;
   RemoteProtoChannelBridge remote_proto_channel_bridge_;
 
   std::unique_ptr<ImageSerializationProcessor> image_serialization_processor_;
 
-  bool beginning_;
-  bool end_when_begin_returns_;
-  bool timed_out_;
-  bool scheduled_;
-  bool started_;
-  bool ended_;
-  bool delegating_renderer_;
+  bool beginning_ = false;
+  bool end_when_begin_returns_ = false;
+  bool timed_out_ = false;
+  bool scheduled_ = false;
+  bool started_ = false;
+  bool ended_ = false;
+  bool delegating_renderer_ = false;
 
-  int timeout_seconds_;
+  int timeout_seconds_ = false;
 
+  std::unique_ptr<LayerTreeTestDelegatingOutputSurfaceClient>
+      delegating_output_surface_client_;
   scoped_refptr<base::SingleThreadTaskRunner> main_task_runner_;
   scoped_refptr<base::SingleThreadTaskRunner> impl_task_runner_;
   std::unique_ptr<base::Thread> impl_thread_;
diff --git a/cc/test/test_context_provider.cc b/cc/test/test_context_provider.cc
index 31ef12e9..2634aff 100644
--- a/cc/test/test_context_provider.cc
+++ b/cc/test/test_context_provider.cc
@@ -23,13 +23,17 @@
 
 // static
 scoped_refptr<TestContextProvider> TestContextProvider::Create() {
-  return Create(TestWebGraphicsContext3D::Create());
+  return new TestContextProvider(base::MakeUnique<TestContextSupport>(),
+                                 base::MakeUnique<TestGLES2Interface>(),
+                                 TestWebGraphicsContext3D::Create());
 }
 
 // static
 scoped_refptr<TestContextProvider> TestContextProvider::CreateWorker() {
-  scoped_refptr<TestContextProvider> worker_context_provider =
-      Create(TestWebGraphicsContext3D::Create());
+  scoped_refptr<TestContextProvider> worker_context_provider(
+      new TestContextProvider(base::MakeUnique<TestContextSupport>(),
+                              base::MakeUnique<TestGLES2Interface>(),
+                              TestWebGraphicsContext3D::Create()));
   // Worker contexts are bound to the thread they are created on.
   if (!worker_context_provider->BindToCurrentThread())
     return nullptr;
@@ -40,7 +44,8 @@
 scoped_refptr<TestContextProvider> TestContextProvider::Create(
     std::unique_ptr<TestWebGraphicsContext3D> context) {
   DCHECK(context);
-  return new TestContextProvider(base::MakeUnique<TestGLES2Interface>(),
+  return new TestContextProvider(base::MakeUnique<TestContextSupport>(),
+                                 base::MakeUnique<TestGLES2Interface>(),
                                  std::move(context));
 }
 
@@ -48,23 +53,36 @@
 scoped_refptr<TestContextProvider> TestContextProvider::Create(
     std::unique_ptr<TestGLES2Interface> gl) {
   DCHECK(gl);
-  return new TestContextProvider(std::move(gl),
+  return new TestContextProvider(base::MakeUnique<TestContextSupport>(),
+                                 std::move(gl),
                                  TestWebGraphicsContext3D::Create());
 }
 
+// static
+scoped_refptr<TestContextProvider> TestContextProvider::Create(
+    std::unique_ptr<TestWebGraphicsContext3D> context,
+    std::unique_ptr<TestContextSupport> support) {
+  DCHECK(context);
+  DCHECK(support);
+  return new TestContextProvider(std::move(support),
+                                 base::MakeUnique<TestGLES2Interface>(),
+                                 std::move(context));
+}
+
 TestContextProvider::TestContextProvider(
+    std::unique_ptr<TestContextSupport> support,
     std::unique_ptr<TestGLES2Interface> gl,
     std::unique_ptr<TestWebGraphicsContext3D> context)
-    : context3d_(std::move(context)),
+    : support_(std::move(support)),
+      context3d_(std::move(context)),
       context_gl_(std::move(gl)),
-      bound_(false),
       weak_ptr_factory_(this) {
   DCHECK(main_thread_checker_.CalledOnValidThread());
   DCHECK(context3d_);
   DCHECK(context_gl_);
   context_thread_checker_.DetachFromThread();
   context_gl_->set_test_context(context3d_.get());
-  context3d_->set_test_support(&support_);
+  context3d_->set_test_support(support_.get());
 }
 
 TestContextProvider::~TestContextProvider() {
@@ -110,7 +128,7 @@
 }
 
 gpu::ContextSupport* TestContextProvider::ContextSupport() {
-  return &support_;
+  return support();
 }
 
 class GrContext* TestContextProvider::GrContext() {
diff --git a/cc/test/test_context_provider.h b/cc/test/test_context_provider.h
index 97c7abc..d7c5627f 100644
--- a/cc/test/test_context_provider.h
+++ b/cc/test/test_context_provider.h
@@ -36,6 +36,9 @@
   static scoped_refptr<TestContextProvider> Create(
       std::unique_ptr<TestWebGraphicsContext3D> context);
   static scoped_refptr<TestContextProvider> Create(
+      std::unique_ptr<TestWebGraphicsContext3D> context,
+      std::unique_ptr<TestContextSupport> support);
+  static scoped_refptr<TestContextProvider> Create(
       std::unique_ptr<TestGLES2Interface> gl);
 
   bool BindToCurrentThread() override;
@@ -57,10 +60,11 @@
   // InitializeOnCurrentThread on the context returned from this method.
   TestWebGraphicsContext3D* UnboundTestContext3d();
 
-  TestContextSupport* support() { return &support_; }
+  TestContextSupport* support() { return support_.get(); }
 
  protected:
   explicit TestContextProvider(
+      std::unique_ptr<TestContextSupport> support,
       std::unique_ptr<TestGLES2Interface> gl,
       std::unique_ptr<TestWebGraphicsContext3D> context);
   ~TestContextProvider() override;
@@ -68,11 +72,10 @@
  private:
   void OnLostContext();
 
-  TestContextSupport support_;
-
+  std::unique_ptr<TestContextSupport> support_;
   std::unique_ptr<TestWebGraphicsContext3D> context3d_;
   std::unique_ptr<TestGLES2Interface> context_gl_;
-  bool bound_;
+  bool bound_ = false;
 
   base::ThreadChecker main_thread_checker_;
   base::ThreadChecker context_thread_checker_;
diff --git a/cc/test/test_delegating_output_surface.cc b/cc/test/test_delegating_output_surface.cc
index 8f586cf..9f980c3 100644
--- a/cc/test/test_delegating_output_surface.cc
+++ b/cc/test/test_delegating_output_surface.cc
@@ -24,7 +24,8 @@
     gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager,
     const RendererSettings& renderer_settings,
     base::SingleThreadTaskRunner* task_runner,
-    bool synchronous_composite)
+    bool synchronous_composite,
+    bool force_disable_reclaim_resources)
     : OutputSurface(std::move(compositor_context_provider),
                     std::move(worker_context_provider),
                     nullptr),
@@ -35,8 +36,16 @@
   std::unique_ptr<SyntheticBeginFrameSource> begin_frame_source;
   std::unique_ptr<DisplayScheduler> scheduler;
   if (!synchronous_composite) {
-    begin_frame_source.reset(new DelayBasedBeginFrameSource(
-        base::MakeUnique<DelayBasedTimeSource>(task_runner)));
+    if (renderer_settings.disable_display_vsync) {
+      begin_frame_source.reset(new BackToBackBeginFrameSource(
+          base::MakeUnique<DelayBasedTimeSource>(task_runner)));
+    } else {
+      begin_frame_source.reset(new DelayBasedBeginFrameSource(
+          base::MakeUnique<DelayBasedTimeSource>(task_runner)));
+      begin_frame_source->SetAuthoritativeVSyncInterval(
+          base::TimeDelta::FromMilliseconds(1000.f /
+                                            renderer_settings.refresh_rate));
+    }
     scheduler.reset(new DisplayScheduler(
         begin_frame_source.get(), task_runner,
         display_output_surface->capabilities().max_frames_pending));
@@ -52,8 +61,9 @@
   capabilities_.delegated_rendering = true;
   // Since this OutputSurface and the Display are tightly coupled and in the
   // same process/thread, the LayerTreeHostImpl can reclaim resources from
-  // the Display.
-  capabilities_.can_force_reclaim_resources = true;
+  // the Display. But we allow tests to disable this to mimic an out-of-process
+  // Display.
+  capabilities_.can_force_reclaim_resources = !force_disable_reclaim_resources;
   capabilities_.delegated_sync_points_required =
       !context_shared_with_compositor;
 }
@@ -107,6 +117,9 @@
 }
 
 void TestDelegatingOutputSurface::SwapBuffers(CompositorFrame frame) {
+  if (test_client_)
+    test_client_->DisplayReceivedCompositorFrame(frame);
+
   if (delegated_surface_id_.is_null()) {
     delegated_surface_id_ = surface_id_allocator_->GenerateId();
     surface_factory_->Create(delegated_surface_id_);
@@ -122,7 +135,7 @@
 
   surface_factory_->SubmitCompositorFrame(
       delegated_surface_id_, std::move(frame),
-      base::Bind(&TestDelegatingOutputSurface::DrawCallback,
+      base::Bind(&TestDelegatingOutputSurface::DidDrawCallback,
                  weak_ptrs_.GetWeakPtr(), synchronous));
 
   for (std::unique_ptr<CopyOutputRequest>& copy_request : copy_requests_)
@@ -130,11 +143,11 @@
                                            std::move(copy_request));
   copy_requests_.clear();
 
-  if (!display_->has_scheduler())
+  if (synchronous)
     display_->DrawAndSwap();
 }
 
-void TestDelegatingOutputSurface::DrawCallback(bool synchronous) {
+void TestDelegatingOutputSurface::DidDrawCallback(bool synchronous) {
   // This is the frame ack to unthrottle the next frame, not actually a notice
   // that drawing is done.
   if (synchronous) {
@@ -186,4 +199,16 @@
   SetMemoryPolicy(policy);
 }
 
+void TestDelegatingOutputSurface::DisplayWillDrawAndSwap(
+    bool will_draw_and_swap,
+    const RenderPassList& render_passes) {
+  if (test_client_)
+    test_client_->DisplayWillDrawAndSwap(will_draw_and_swap, render_passes);
+}
+
+void TestDelegatingOutputSurface::DisplayDidDrawAndSwap() {
+  if (test_client_)
+    test_client_->DisplayDidDrawAndSwap();
+}
+
 }  // namespace cc
diff --git a/cc/test/test_delegating_output_surface.h b/cc/test/test_delegating_output_surface.h
index 25ccb123..f5ac294 100644
--- a/cc/test/test_delegating_output_surface.h
+++ b/cc/test/test_delegating_output_surface.h
@@ -17,13 +17,24 @@
 #include "cc/surfaces/surface_manager.h"
 
 namespace cc {
-
 class CopyOutputRequest;
 
+class TestDelegatingOutputSurfaceClient {
+ public:
+  virtual ~TestDelegatingOutputSurfaceClient() {}
+
+  virtual void DisplayReceivedCompositorFrame(const CompositorFrame& frame) = 0;
+  virtual void DisplayWillDrawAndSwap(bool will_draw_and_swap,
+                                      const RenderPassList& render_passes) = 0;
+  virtual void DisplayDidDrawAndSwap() = 0;
+};
+
 class TestDelegatingOutputSurface : public OutputSurface,
                                     public SurfaceFactoryClient,
                                     public DisplayClient {
  public:
+  // Pass true for |force_disable_reclaim_resources| to act like the Display
+  // is out-of-process and can't return resources synchronously.
   TestDelegatingOutputSurface(
       scoped_refptr<ContextProvider> compositor_context_provider,
       scoped_refptr<ContextProvider> worker_context_provider,
@@ -32,9 +43,14 @@
       gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager,
       const RendererSettings& renderer_settings,
       base::SingleThreadTaskRunner* task_runner,
-      bool synchronous_composite);
+      bool synchronous_composite,
+      bool force_disable_reclaim_resources);
   ~TestDelegatingOutputSurface() override;
 
+  void SetClient(TestDelegatingOutputSurfaceClient* client) {
+    test_client_ = client;
+  }
+
   Display* display() const { return display_.get(); }
 
   // Will be submitted with the next SwapBuffers.
@@ -55,9 +71,12 @@
   // DisplayClient implementation.
   void DisplayOutputSurfaceLost() override;
   void DisplaySetMemoryPolicy(const ManagedMemoryPolicy& policy) override;
+  void DisplayWillDrawAndSwap(bool will_draw_and_swap,
+                              const RenderPassList& render_passes) override;
+  void DisplayDidDrawAndSwap() override;
 
  private:
-  void DrawCallback(bool synchronous);
+  void DidDrawCallback(bool synchronous);
 
   // TODO(danakj): These don't to be stored in unique_ptrs when OutputSurface
   // is owned/destroyed on the compositor thread.
@@ -72,6 +91,7 @@
   std::unique_ptr<Display> display_;
 
   bool bound_ = false;
+  TestDelegatingOutputSurfaceClient* test_client_ = nullptr;
 
   std::vector<std::unique_ptr<CopyOutputRequest>> copy_requests_;
 
diff --git a/cc/test/test_hooks.h b/cc/test/test_hooks.h
index f386091d..ff0737f 100644
--- a/cc/test/test_hooks.h
+++ b/cc/test/test_hooks.h
@@ -22,6 +22,7 @@
   TestHooks();
   ~TestHooks() override;
 
+  // Compositor thread hooks.
   virtual void CreateResourceAndRasterBufferProvider(
       LayerTreeHostImpl* host_impl,
       std::unique_ptr<RasterBufferProvider>* raster_buffer_provider,
@@ -45,22 +46,33 @@
       LayerTreeHostImpl::FrameData* frame_data,
       DrawResult draw_result);
   virtual void DrawLayersOnThread(LayerTreeHostImpl* host_impl) {}
-  // Note that this is called asynchronously from the LayerTreeHostImpl
-  // performing its draw, so you should record state you want to use here
-  // in DrawLayersOnThread() instead. For that reason this method does not
-  // receive a LayerTreeHostImpl pointer.
-  virtual void SwapBuffersCompleteOnThread() {}
   virtual void NotifyReadyToActivateOnThread(LayerTreeHostImpl* host_impl) {}
   virtual void NotifyReadyToDrawOnThread(LayerTreeHostImpl* host_impl) {}
   virtual void NotifyAllTileTasksCompleted(LayerTreeHostImpl* host_impl) {}
   virtual void NotifyTileStateChangedOnThread(LayerTreeHostImpl* host_impl,
                                               const Tile* tile) {}
+  virtual void DidSetVisibleOnImplTree(LayerTreeHostImpl* host_impl,
+                                       bool visible) {}
   virtual void AnimateLayers(LayerTreeHostImpl* host_impl,
                              base::TimeTicks monotonic_time) {}
   virtual void UpdateAnimationState(LayerTreeHostImpl* host_impl,
                                     bool has_unfinished_animation) {}
   virtual void WillAnimateLayers(LayerTreeHostImpl* host_impl,
                                  base::TimeTicks monotonic_time) {}
+
+  // Asynchronous compositor thread hooks.
+  // These are called asynchronously from the LayerTreeHostImpl performing its
+  // draw, so you should record state you want to use here in
+  // DrawLayersOnThread() instead. For that reason these methods do not receive
+  // a LayerTreeHostImpl pointer.
+  virtual void DisplayReceivedCompositorFrameOnThread(
+      const CompositorFrame& frame) {}
+  virtual void DisplayWillDrawAndSwapOnThread(
+      bool will_draw_and_swap,
+      const RenderPassList& render_passes) {}
+  virtual void DisplayDidDrawAndSwapOnThread() {}
+
+  // Main thread hooks.
   virtual void ApplyViewportDeltas(
       const gfx::Vector2dF& inner_delta,
       const gfx::Vector2dF& outer_delta,
@@ -79,8 +91,6 @@
   virtual void DidCommit() {}
   virtual void DidCommitAndDrawFrame() {}
   virtual void DidCompleteSwapBuffers() {}
-  virtual void DidSetVisibleOnImplTree(LayerTreeHostImpl* host_impl,
-                                       bool visible) {}
   virtual void ScheduleComposite() {}
   virtual void DidActivateSyncTree() {}
 
diff --git a/cc/test/test_web_graphics_context_3d.cc b/cc/test/test_web_graphics_context_3d.cc
index 2641c90..4f0e3e61 100644
--- a/cc/test/test_web_graphics_context_3d.cc
+++ b/cc/test/test_web_graphics_context_3d.cc
@@ -74,6 +74,7 @@
       weak_ptr_factory_(this) {
   CreateNamespace();
   set_support_image(true);
+  set_have_extension_egl_image(true);  // For stream textures.
 }
 
 TestWebGraphicsContext3D::~TestWebGraphicsContext3D() {
diff --git a/cc/trees/layer_tree_host_impl.cc b/cc/trees/layer_tree_host_impl.cc
index b32ed4e..243e81da 100644
--- a/cc/trees/layer_tree_host_impl.cc
+++ b/cc/trees/layer_tree_host_impl.cc
@@ -797,11 +797,12 @@
       !root_surface->layer_list().empty();
   bool hud_wants_to_draw_ = active_tree_->hud_layer() &&
                             active_tree_->hud_layer()->IsAnimatingHUDContents();
+  bool resources_must_be_resent =
+      output_surface_->capabilities().can_force_reclaim_resources;
   if (root_surface_has_contributing_layers &&
       root_surface_has_no_visible_damage &&
       !active_tree_->property_trees()->effect_tree.HasCopyRequests() &&
-      !output_surface_->capabilities().can_force_reclaim_resources &&
-      !hud_wants_to_draw_) {
+      !resources_must_be_resent && !hud_wants_to_draw_) {
     TRACE_EVENT0("cc",
                  "LayerTreeHostImpl::CalculateRenderPasses::EmptyDamageRect");
     frame->has_no_damage = true;
diff --git a/cc/trees/layer_tree_host_impl_unittest.cc b/cc/trees/layer_tree_host_impl_unittest.cc
index 862ef2f8..087ecd0a 100644
--- a/cc/trees/layer_tree_host_impl_unittest.cc
+++ b/cc/trees/layer_tree_host_impl_unittest.cc
@@ -7854,7 +7854,8 @@
           context_provider, TestContextProvider::CreateWorker(),
           FakeOutputSurface::Create3d(context_provider), nullptr, nullptr,
           RendererSettings(), base::ThreadTaskRunnerHandle::Get().get(),
-          true /* synchronous_composite */));
+          true /* synchronous_composite */,
+          false /* force_disable_reclaim_resources */));
 
   SetupRootLayerImpl(LayerImpl::Create(host_impl_->active_tree(), 1));
 
diff --git a/cc/trees/layer_tree_host_perftest.cc b/cc/trees/layer_tree_host_perftest.cc
index 9923f24..e288f52 100644
--- a/cc/trees/layer_tree_host_perftest.cc
+++ b/cc/trees/layer_tree_host_perftest.cc
@@ -73,21 +73,21 @@
     }
   }
 
-  void DrawLayersOnThread(LayerTreeHostImpl* impl) override {
+  void DrawLayersOnThread(LayerTreeHostImpl* host_impl) override {
     if (TestEnded() || CleanUpStarted())
       return;
     draw_timer_.NextLap();
     if (draw_timer_.HasTimeLimitExpired()) {
-      CleanUpAndEndTest(impl);
+      CleanUpAndEndTest();
       return;
     }
     if (!begin_frame_driven_drawing_)
-      impl->SetNeedsRedraw();
+      host_impl->SetNeedsRedraw();
     if (full_damage_each_frame_)
-      impl->SetFullRootLayerDamage();
+      host_impl->SetFullRootLayerDamage();
   }
 
-  virtual void CleanUpAndEndTest(LayerTreeHostImpl* host_impl) { EndTest(); }
+  virtual void CleanUpAndEndTest() { EndTest(); }
 
   virtual bool CleanUpStarted() { return false; }
 
@@ -253,17 +253,11 @@
   RunTest(CompositorMode::THREADED, false);
 }
 
-static void EmptyReleaseCallback(const gpu::SyncToken& sync_token,
-                                 bool lost_resource) {}
-
 // Simulates main-thread scrolling on each frame.
 class BrowserCompositorInvalidateLayerTreePerfTest
     : public LayerTreeHostPerfTestJsonReader {
  public:
-  BrowserCompositorInvalidateLayerTreePerfTest()
-      : LayerTreeHostPerfTestJsonReader(),
-        next_fence_sync_(1),
-        clean_up_started_(false) {}
+  BrowserCompositorInvalidateLayerTreePerfTest() = default;
 
   void BuildTree() override {
     LayerTreeHostPerfTestJsonReader::BuildTree();
@@ -285,7 +279,9 @@
     gpu_mailbox.SetName(
         reinterpret_cast<const int8_t*>(name_stream.str().c_str()));
     std::unique_ptr<SingleReleaseCallback> callback =
-        SingleReleaseCallback::Create(base::Bind(&EmptyReleaseCallback));
+        SingleReleaseCallback::Create(base::Bind(
+            &BrowserCompositorInvalidateLayerTreePerfTest::ReleaseMailbox,
+            base::Unretained(this)));
 
     gpu::SyncToken next_sync_token(gpu::CommandBufferNamespace::GPU_IO, 0,
                                    gpu::CommandBufferId::FromUnsafeValue(1),
@@ -295,6 +291,8 @@
     next_fence_sync_++;
 
     tab_contents_->SetTextureMailbox(mailbox, std::move(callback));
+    ++sent_mailboxes_count_;
+    tab_contents_->SetNeedsDisplay();
   }
 
   void DidCommit() override {
@@ -303,7 +301,7 @@
     layer_tree_host()->SetNeedsCommit();
   }
 
-  void CleanUpAndEndTest(LayerTreeHostImpl* host_impl) override {
+  void CleanUpAndEndTest() override {
     clean_up_started_ = true;
     MainThreadTaskRunner()->PostTask(
         FROM_HERE,
@@ -314,15 +312,25 @@
 
   void CleanUpAndEndTestOnMainThread() {
     tab_contents_->SetTextureMailbox(TextureMailbox(), nullptr);
-    EndTest();
+    // ReleaseMailbox will end the test when we get the last mailbox back.
+  }
+
+  void ReleaseMailbox(const gpu::SyncToken& sync_token, bool lost_resource) {
+    ++released_mailboxes_count_;
+    if (released_mailboxes_count_ == sent_mailboxes_count_) {
+      DCHECK(CleanUpStarted());
+      EndTest();
+    }
   }
 
   bool CleanUpStarted() override { return clean_up_started_; }
 
  private:
   scoped_refptr<TextureLayer> tab_contents_;
-  uint64_t next_fence_sync_;
-  bool clean_up_started_;
+  uint64_t next_fence_sync_ = 1;
+  bool clean_up_started_ = false;
+  int sent_mailboxes_count_ = 0;
+  int released_mailboxes_count_ = 0;
 };
 
 TEST_F(BrowserCompositorInvalidateLayerTreePerfTest, DenseBrowserUIThreaded) {
diff --git a/cc/trees/layer_tree_host_unittest.cc b/cc/trees/layer_tree_host_unittest.cc
index 4fb8e69..27f4ab21 100644
--- a/cc/trees/layer_tree_host_unittest.cc
+++ b/cc/trees/layer_tree_host_unittest.cc
@@ -47,6 +47,7 @@
 #include "cc/test/layer_internals_for_test.h"
 #include "cc/test/layer_tree_test.h"
 #include "cc/test/skia_common.h"
+#include "cc/test/test_delegating_output_surface.h"
 #include "cc/test/test_shared_bitmap_manager.h"
 #include "cc/test/test_web_graphics_context_3d.h"
 #include "cc/trees/effect_node.h"
@@ -432,25 +433,37 @@
 
 class LayerTreeHostFreeWorkerContextResourcesTest : public LayerTreeHostTest {
  public:
-  std::unique_ptr<OutputSurface> CreateOutputSurface() override {
-    auto output_surface = base::WrapUnique(
-        new testing::StrictMock<
-            MockSetWorkerContextShouldAggressivelyFreeResourcesOutputSurface>(
-            delegating_renderer()));
+  std::unique_ptr<TestDelegatingOutputSurface> CreateDelegatingOutputSurface(
+      scoped_refptr<ContextProvider> compositor_context_provider,
+      scoped_refptr<ContextProvider> worker_context_provider) override {
+    auto mock_worker_context_support_owned =
+        base::MakeUnique<MockContextSupport>();
+    auto* mock_worker_context_support = mock_worker_context_support_owned.get();
+
+    auto mock_worker_context_provider = make_scoped_refptr(
+        new MockContextProvider(std::move(mock_worker_context_support_owned)));
+
+    // Workers are bound on the main thread.
+    mock_worker_context_provider->BindToCurrentThread();
 
     // At init, we expect one call to set visibility to true.
     testing::Expectation visibility_true =
-        EXPECT_CALL(*output_surface,
-                    SetWorkerContextShouldAggressivelyFreeResources(false))
+        EXPECT_CALL(*mock_worker_context_support,
+                    SetAggressivelyFreeResources(false))
             .Times(1);
 
     // After running, we should get exactly one call to
-    // FreeWorkerContextGpuResources.
-    EXPECT_CALL(*output_surface,
-                SetWorkerContextShouldAggressivelyFreeResources(true))
+    // DeleteCachedResources, along with SetAggressivelyFreeResources.
+    EXPECT_CALL(*mock_worker_context_provider, DeleteCachedResources())
+        .After(visibility_true);
+    EXPECT_CALL(*mock_worker_context_support,
+                SetAggressivelyFreeResources(true))
         .After(visibility_true)
         .WillOnce(testing::Invoke([this](bool is_visible) { EndTest(); }));
-    return std::move(output_surface);
+
+    return LayerTreeHostTest::CreateDelegatingOutputSurface(
+        std::move(compositor_context_provider),
+        std::move(mock_worker_context_provider));
   }
 
   void InitializeSettings(LayerTreeSettings* settings) override {
@@ -458,27 +471,27 @@
     settings->gpu_rasterization_forced = true;
   }
 
-  void BeginTest() override {
-    // Logic is handled in InitializedRendererOnThread to ensure that our
-    // LTHI is fully set up.
-  }
-
-  void AfterTest() override {
-    // Expectations handled via mock.
-  }
+  void BeginTest() override {}
+  void AfterTest() override {}
 
  private:
-  class MockSetWorkerContextShouldAggressivelyFreeResourcesOutputSurface
-      : public FakeOutputSurface {
+  class MockContextProvider : public TestContextProvider {
    public:
-    ~MockSetWorkerContextShouldAggressivelyFreeResourcesOutputSurface() {}
-    explicit MockSetWorkerContextShouldAggressivelyFreeResourcesOutputSurface(
-        bool delegated_rendering)
-        : FakeOutputSurface(TestContextProvider::Create(),
-                            TestContextProvider::CreateWorker(),
-                            delegated_rendering) {}
-    MOCK_METHOD1(SetWorkerContextShouldAggressivelyFreeResources,
-                 void(bool is_visible));
+    explicit MockContextProvider(std::unique_ptr<TestContextSupport> support)
+        : TestContextProvider(std::move(support),
+                              base::MakeUnique<TestGLES2Interface>(),
+                              TestWebGraphicsContext3D::Create()) {}
+
+    MOCK_METHOD0(DeleteCachedResources, void());
+
+   private:
+    ~MockContextProvider() = default;
+  };
+
+  class MockContextSupport : public TestContextSupport {
+   public:
+    MOCK_METHOD1(SetAggressivelyFreeResources,
+                 void(bool aggressively_free_resources));
   };
 };
 
@@ -520,7 +533,6 @@
  public:
   void InitializeSettings(LayerTreeSettings* settings) override {
     LayerTreeHostFreeWorkerContextResourcesTest::InitializeSettings(settings);
-    settings->use_external_begin_frame_source = true;
     settings->using_synchronous_renderer_compositor = true;
   }
 };
@@ -2562,39 +2574,10 @@
 
 SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostTestLCDChange);
 
-// Verify that the BeginFrame notification is used to initiate rendering.
-class LayerTreeHostTestBeginFrameNotification : public LayerTreeHostTest {
- public:
-  void InitializeSettings(LayerTreeSettings* settings) override {
-    settings->use_external_begin_frame_source = true;
-  }
-
-  void BeginTest() override {
-    // This will trigger a SetNeedsBeginFrame which will trigger a
-    // BeginFrame.
-    PostSetNeedsCommitToMainThread();
-  }
-
-  DrawResult PrepareToDrawOnThread(LayerTreeHostImpl* host_impl,
-                                   LayerTreeHostImpl::FrameData* frame,
-                                   DrawResult draw_result) override {
-    EndTest();
-    return DRAW_SUCCESS;
-  }
-
-  void AfterTest() override {}
-
- private:
-  base::TimeTicks frame_time_;
-};
-
-MULTI_THREAD_TEST_F(LayerTreeHostTestBeginFrameNotification);
-
 class LayerTreeHostTestBeginFrameNotificationShutdownWhileEnabled
     : public LayerTreeHostTest {
  public:
   void InitializeSettings(LayerTreeSettings* settings) override {
-    settings->use_external_begin_frame_source = true;
     settings->using_synchronous_renderer_compositor = true;
   }
 
@@ -2605,8 +2588,7 @@
     // once we return. End test while it's enabled.
     ImplThreadTaskRunner()->PostTask(
         FROM_HERE,
-        base::Bind(&LayerTreeHostTestBeginFrameNotification::EndTest,
-                   base::Unretained(this)));
+        base::Bind(&LayerTreeHostTest::EndTest, base::Unretained(this)));
   }
 
   void AfterTest() override {}
@@ -2620,10 +2602,6 @@
   LayerTreeHostTestAbortedCommitDoesntStall()
       : commit_count_(0), commit_abort_count_(0), commit_complete_count_(0) {}
 
-  void InitializeSettings(LayerTreeSettings* settings) override {
-    settings->use_external_begin_frame_source = true;
-  }
-
   void BeginTest() override { PostSetNeedsCommitToMainThread(); }
 
   void DidCommit() override {
@@ -2664,35 +2642,41 @@
   int commit_complete_count_;
 };
 
-class OnDrawOutputSurface : public OutputSurface {
+class OnDrawOutputSurface : public TestDelegatingOutputSurface {
  public:
-  explicit OnDrawOutputSurface(base::Closure invalidate_callback)
-      : OutputSurface(TestContextProvider::Create(),
-                      TestContextProvider::CreateWorker(),
-                      nullptr),
-        invalidate_callback_(std::move(invalidate_callback)) {
-    capabilities_.delegated_rendering = true;
-  }
+  explicit OnDrawOutputSurface(
+      scoped_refptr<ContextProvider> compositor_context_provider,
+      scoped_refptr<ContextProvider> worker_context_provider,
+      std::unique_ptr<OutputSurface> display_output_surface,
+      SharedBitmapManager* shared_bitmap_manager,
+      gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager,
+      const RendererSettings& renderer_settings,
+      base::SingleThreadTaskRunner* task_runner,
+      bool synchronous_composite,
+      bool force_disable_reclaim_resources,
+      base::Closure invalidate_callback)
+      : TestDelegatingOutputSurface(std::move(compositor_context_provider),
+                                    std::move(worker_context_provider),
+                                    std::move(display_output_surface),
+                                    shared_bitmap_manager,
+                                    gpu_memory_buffer_manager,
+                                    renderer_settings,
+                                    task_runner,
+                                    synchronous_composite,
+                                    force_disable_reclaim_resources),
+        invalidate_callback_(std::move(invalidate_callback)) {}
 
-  // OutputSurface implementation.
-  void SwapBuffers(CompositorFrame frame) override { did_swap_ = true; }
-  uint32_t GetFramebufferCopyTextureFormat() override { return 0; }
+  // TestDelegatingOutputSurface overrides.
   void Invalidate() override { invalidate_callback_.Run(); }
 
   void OnDraw(bool resourceless_software_draw) {
     gfx::Transform identity;
     gfx::Rect empty_rect;
-    // SwapBuffers happens inside of OnDraw.
     client_->OnDraw(identity, empty_rect, resourceless_software_draw);
-    if (did_swap_) {
-      did_swap_ = false;
-      client_->DidSwapBuffersComplete();
-    }
   }
 
  private:
-  bool did_swap_ = false;
-  base::Closure invalidate_callback_;
+  const base::Closure invalidate_callback_;
 };
 
 class LayerTreeHostTestAbortedCommitDoesntStallSynchronousCompositor
@@ -2703,11 +2687,21 @@
     settings->using_synchronous_renderer_compositor = true;
   }
 
-  std::unique_ptr<OutputSurface> CreateOutputSurface() override {
-    auto output_surface = base::MakeUnique<OnDrawOutputSurface>(base::Bind(
+  std::unique_ptr<TestDelegatingOutputSurface> CreateDelegatingOutputSurface(
+      scoped_refptr<ContextProvider> compositor_context_provider,
+      scoped_refptr<ContextProvider> worker_context_provider) override {
+    auto on_draw_callback = base::Bind(
         &LayerTreeHostTestAbortedCommitDoesntStallSynchronousCompositor::
             CallOnDraw,
-        base::Unretained(this)));
+        base::Unretained(this));
+    auto output_surface = base::MakeUnique<OnDrawOutputSurface>(
+        compositor_context_provider, std::move(worker_context_provider),
+        CreateDisplayOutputSurface(compositor_context_provider),
+        shared_bitmap_manager(), gpu_memory_buffer_manager(),
+        layer_tree_host()->settings().renderer_settings, ImplThreadTaskRunner(),
+        false /* synchronous_composite */,
+        false /* force_disable_reclaim_resources */,
+        std::move(on_draw_callback));
     output_surface_ = output_surface.get();
     return std::move(output_surface);
   }
@@ -2843,10 +2837,20 @@
     client_.set_bounds(root_layer_->bounds());
   }
 
-  std::unique_ptr<OutputSurface> CreateOutputSurface() override {
-    auto output_surface = base::MakeUnique<OnDrawOutputSurface>(
+  std::unique_ptr<TestDelegatingOutputSurface> CreateDelegatingOutputSurface(
+      scoped_refptr<ContextProvider> compositor_context_provider,
+      scoped_refptr<ContextProvider> worker_context_provider) override {
+    auto on_draw_callback =
         base::Bind(&LayerTreeHostTestResourcelessSoftwareDraw::CallOnDraw,
-                   base::Unretained(this)));
+                   base::Unretained(this));
+    auto output_surface = base::MakeUnique<OnDrawOutputSurface>(
+        compositor_context_provider, std::move(worker_context_provider),
+        CreateDisplayOutputSurface(compositor_context_provider),
+        shared_bitmap_manager(), gpu_memory_buffer_manager(),
+        layer_tree_host()->settings().renderer_settings, ImplThreadTaskRunner(),
+        false /* synchronous_composite */,
+        false /* force_disable_reclaim_resources */,
+        std::move(on_draw_callback));
     output_surface_ = output_surface.get();
     return std::move(output_surface);
   }
@@ -4376,22 +4380,19 @@
       : first_output_surface_memory_limit_(4321234),
         second_output_surface_memory_limit_(1234321) {}
 
-  std::unique_ptr<OutputSurface> CreateOutputSurface() override {
-    if (!first_context_provider_.get()) {
+  std::unique_ptr<OutputSurface> CreateDisplayOutputSurface(
+      scoped_refptr<ContextProvider> compositor_context_provider) override {
+    if (!first_context_provider_) {
       first_context_provider_ = TestContextProvider::Create();
+      compositor_context_provider = first_context_provider_;
     } else {
-      EXPECT_FALSE(second_context_provider_.get());
+      EXPECT_FALSE(second_context_provider_);
       second_context_provider_ = TestContextProvider::Create();
+      compositor_context_provider = second_context_provider_;
     }
 
-    scoped_refptr<TestContextProvider> provider(second_context_provider_.get()
-                                                    ? second_context_provider_
-                                                    : first_context_provider_);
-    std::unique_ptr<FakeOutputSurface> output_surface;
-    if (delegating_renderer())
-      output_surface = FakeOutputSurface::CreateDelegating3d(provider);
-    else
-      output_surface = FakeOutputSurface::Create3d(provider);
+    auto output_surface =
+        FakeOutputSurface::Create3d(std::move(compositor_context_provider));
     output_surface->SetMemoryPolicyToSetAtBind(
         base::WrapUnique(new ManagedMemoryPolicy(
             second_context_provider_.get() ? second_output_surface_memory_limit_
@@ -4527,7 +4528,7 @@
     }
   }
 
-  void SwapBuffersCompleteOnThread() override { EndTest(); }
+  void DisplayDidDrawAndSwapOnThread() override { EndTest(); }
 
   void AfterTest() override {
     // The pending swap promise should activate and swap.
@@ -4719,7 +4720,7 @@
             : base::Closure());
   }
 
-  void SwapBuffersCompleteOnThread() override {
+  void DisplayDidDrawAndSwapOnThread() override {
     if (num_swaps_++ >= 1) {
       // The commit changes layers so it should cause a swap.
       base::AutoLock lock(swap_promise_result_.lock);
@@ -5463,13 +5464,29 @@
 class LayerTreeHostTestSynchronousCompositeSwapPromise
     : public LayerTreeHostTest {
  public:
-  LayerTreeHostTestSynchronousCompositeSwapPromise() : commit_count_(0) {}
+  LayerTreeHostTestSynchronousCompositeSwapPromise() = default;
 
   void InitializeSettings(LayerTreeSettings* settings) override {
     settings->single_thread_proxy_scheduler = false;
     settings->use_zero_copy = true;
   }
 
+  std::unique_ptr<TestDelegatingOutputSurface> CreateDelegatingOutputSurface(
+      scoped_refptr<ContextProvider> compositor_context_provider,
+      scoped_refptr<ContextProvider> worker_context_provider) override {
+    bool synchronous_composite =
+        !HasImplThread() &&
+        !layer_tree_host()->settings().single_thread_proxy_scheduler;
+    // Relaiming resources is parameterized for this test.
+    bool force_disable_reclaim_resources = !reclaim_resources_;
+    return base::MakeUnique<TestDelegatingOutputSurface>(
+        compositor_context_provider, std::move(worker_context_provider),
+        CreateDisplayOutputSurface(compositor_context_provider),
+        shared_bitmap_manager(), gpu_memory_buffer_manager(),
+        layer_tree_host()->settings().renderer_settings, ImplThreadTaskRunner(),
+        synchronous_composite, force_disable_reclaim_resources);
+  }
+
   void BeginTest() override {
     // Successful composite.
     std::unique_ptr<SwapPromise> swap_promise0(
@@ -5477,7 +5494,7 @@
     layer_tree_host()->QueueSwapPromise(std::move(swap_promise0));
     layer_tree_host()->Composite(base::TimeTicks::Now());
 
-    // Fail to swap (no damage).
+    // Fail to swap (no damage) if not reclaiming resources from the Display.
     std::unique_ptr<SwapPromise> swap_promise1(
         new TestSwapPromise(&swap_promise_result_[1]));
     layer_tree_host()->QueueSwapPromise(std::move(swap_promise1));
@@ -5511,13 +5528,19 @@
       EXPECT_TRUE(swap_promise_result_[0].dtor_called);
     }
 
-    // Second swap promise fails to swap.
+    // Second swap promise fails to swap if not reclaiming resources from the
+    // Display.
     {
       base::AutoLock lock(swap_promise_result_[1].lock);
       EXPECT_TRUE(swap_promise_result_[1].did_activate_called);
-      EXPECT_FALSE(swap_promise_result_[1].did_swap_called);
-      EXPECT_TRUE(swap_promise_result_[1].did_not_swap_called);
-      EXPECT_EQ(SwapPromise::SWAP_FAILS, swap_promise_result_[1].reason);
+      if (!reclaim_resources_) {
+        EXPECT_FALSE(swap_promise_result_[1].did_swap_called);
+        EXPECT_TRUE(swap_promise_result_[1].did_not_swap_called);
+        EXPECT_EQ(SwapPromise::SWAP_FAILS, swap_promise_result_[1].reason);
+      } else {
+        EXPECT_TRUE(swap_promise_result_[1].did_swap_called);
+        EXPECT_FALSE(swap_promise_result_[1].did_not_swap_called);
+      }
       EXPECT_TRUE(swap_promise_result_[1].dtor_called);
     }
 
@@ -5532,11 +5555,20 @@
     }
   }
 
-  int commit_count_;
+  bool reclaim_resources_;
+  int commit_count_ = 0;
   TestSwapPromiseResult swap_promise_result_[3];
 };
 
-SINGLE_THREAD_TEST_F(LayerTreeHostTestSynchronousCompositeSwapPromise);
+TEST_F(LayerTreeHostTestSynchronousCompositeSwapPromise, NoReclaim) {
+  reclaim_resources_ = false;
+  RunTest(CompositorMode::SINGLE_THREADED, true);
+}
+
+TEST_F(LayerTreeHostTestSynchronousCompositeSwapPromise, Reclaim) {
+  reclaim_resources_ = true;
+  RunTest(CompositorMode::SINGLE_THREADED, true);
+}
 
 // Make sure page scale and top control deltas are applied to the client even
 // when the LayerTreeHost doesn't have a root layer.
@@ -5774,19 +5806,18 @@
 class LayerTreeHostTestCrispUpAfterPinchEndsWithOneCopy
     : public LayerTreeHostTestCrispUpAfterPinchEnds {
  protected:
-  std::unique_ptr<OutputSurface> CreateOutputSurface() override {
-    std::unique_ptr<TestWebGraphicsContext3D> context3d =
-        TestWebGraphicsContext3D::Create();
-    context3d->set_support_image(true);
+  std::unique_ptr<OutputSurface> CreateDisplayOutputSurface(
+      scoped_refptr<ContextProvider> compositor_context_provider) override {
+    scoped_refptr<TestContextProvider> display_context_provider =
+        TestContextProvider::Create();
+    TestWebGraphicsContext3D* context3d =
+        display_context_provider->UnboundTestContext3d();
     context3d->set_support_sync_query(true);
 #if defined(OS_MACOSX)
     context3d->set_support_texture_rectangle(true);
 #endif
-
-    if (delegating_renderer())
-      return FakeOutputSurface::CreateDelegating3d(std::move(context3d));
-    else
-      return FakeOutputSurface::Create3d(std::move(context3d));
+    return LayerTreeTest::CreateDisplayOutputSurface(
+        std::move(display_context_provider));
   }
 };
 
@@ -6826,14 +6857,6 @@
 // frame's metadata.
 class LayerTreeHostTestPaintedDeviceScaleFactor : public LayerTreeHostTest {
  protected:
-  LayerTreeHostTestPaintedDeviceScaleFactor() = default;
-
-  std::unique_ptr<OutputSurface> CreateOutputSurface() override {
-    auto ret = FakeOutputSurface::CreateDelegating3d();
-    fake_output_surface_ = ret.get();
-    return std::move(ret);
-  }
-
   void BeginTest() override {
     layer_tree_host()->SetPaintedDeviceScaleFactor(2.0f);
     EXPECT_EQ(1.0f, layer_tree_host()->device_scale_factor());
@@ -6845,16 +6868,13 @@
     EXPECT_EQ(1.0f, host_impl->active_tree()->device_scale_factor());
   }
 
-  void SwapBuffersCompleteOnThread() override {
-    EXPECT_EQ(
-        2.0f,
-        fake_output_surface_->last_sent_frame()->metadata.device_scale_factor);
+  void DisplayReceivedCompositorFrameOnThread(
+      const CompositorFrame& frame) override {
+    EXPECT_EQ(2.0f, frame.metadata.device_scale_factor);
     EndTest();
   }
 
   void AfterTest() override {}
-
-  FakeOutputSurface* fake_output_surface_ = nullptr;
 };
 
 SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostTestPaintedDeviceScaleFactor);
diff --git a/cc/trees/layer_tree_host_unittest_context.cc b/cc/trees/layer_tree_host_unittest_context.cc
index c9a0291..23d344fd 100644
--- a/cc/trees/layer_tree_host_unittest_context.cc
+++ b/cc/trees/layer_tree_host_unittest_context.cc
@@ -16,7 +16,6 @@
 #include "cc/layers/video_layer_impl.h"
 #include "cc/output/filter_operations.h"
 #include "cc/resources/single_release_callback.h"
-#include "cc/test/failure_output_surface.h"
 #include "cc/test/fake_content_layer_client.h"
 #include "cc/test/fake_layer_tree_host_client.h"
 #include "cc/test/fake_output_surface.h"
@@ -31,6 +30,7 @@
 #include "cc/test/layer_tree_test.h"
 #include "cc/test/render_pass_test_utils.h"
 #include "cc/test/test_context_provider.h"
+#include "cc/test/test_delegating_output_surface.h"
 #include "cc/test/test_shared_bitmap_manager.h"
 #include "cc/test/test_web_graphics_context_3d.h"
 #include "cc/trees/layer_tree_host.h"
@@ -80,24 +80,35 @@
     return TestWebGraphicsContext3D::Create();
   }
 
-  std::unique_ptr<OutputSurface> CreateOutputSurface() override {
+  std::unique_ptr<TestDelegatingOutputSurface> CreateDelegatingOutputSurface(
+      scoped_refptr<ContextProvider> compositor_context_provider,
+      scoped_refptr<ContextProvider> worker_context_provider) override {
     if (times_to_fail_create_) {
       --times_to_fail_create_;
       ExpectCreateToFail();
-      return base::WrapUnique(new FailureOutputSurface(delegating_renderer()));
+      auto test_compositor_context_provider = TestContextProvider::Create();
+      test_compositor_context_provider->UnboundTestContext3d()
+          ->loseContextCHROMIUM(GL_GUILTY_CONTEXT_RESET_ARB,
+                                GL_INNOCENT_CONTEXT_RESET_ARB);
+      compositor_context_provider = std::move(test_compositor_context_provider);
+    }
+    return LayerTreeTest::CreateDelegatingOutputSurface(
+        std::move(compositor_context_provider),
+        std::move(worker_context_provider));
+  }
+
+  std::unique_ptr<OutputSurface> CreateDisplayOutputSurface(
+      scoped_refptr<ContextProvider> compositor_context_provider) override {
+    std::unique_ptr<TestWebGraphicsContext3D> context3d = CreateContext3d();
+    if (context_should_support_io_surface_) {
+      context3d->set_have_extension_io_surface(true);
+      context3d->set_have_extension_egl_image(true);
     }
 
-    std::unique_ptr<TestWebGraphicsContext3D> context3d = CreateContext3d();
     base::AutoLock lock(context3d_lock_);
     context3d_ = context3d.get();
-
-    if (context_should_support_io_surface_) {
-      context3d_->set_have_extension_io_surface(true);
-      context3d_->set_have_extension_egl_image(true);
-    }
-
-    DCHECK(delegating_renderer());
-    return FakeOutputSurface::CreateDelegating3d(std::move(context3d));
+    return LayerTreeTest::CreateDisplayOutputSurface(
+        TestContextProvider::Create(std::move(context3d)));
   }
 
   DrawResult PrepareToDrawOnThread(LayerTreeHostImpl* host_impl,
@@ -178,18 +189,15 @@
     if (async_output_surface_creation_) {
       MainThreadTaskRunner()->PostTask(
           FROM_HERE, base::Bind(&LayerTreeHostContextTestLostContextSucceeds::
-                                    CreateAndSetOutputSurface,
+                                    AsyncRequestNewOutputSurface,
                                 base::Unretained(this)));
     } else {
-      CreateAndSetOutputSurface();
+      AsyncRequestNewOutputSurface();
     }
   }
 
-  void CreateAndSetOutputSurface() {
-    std::unique_ptr<OutputSurface> surface(
-        LayerTreeHostContextTest::CreateOutputSurface());
-    CHECK(surface);
-    layer_tree_host()->SetOutputSurface(std::move(surface));
+  void AsyncRequestNewOutputSurface() {
+    LayerTreeHostContextTest::RequestNewOutputSurface();
   }
 
   void DidInitializeOutputSurface() override {
@@ -365,9 +373,8 @@
     EndTest();
   }
 
-  std::unique_ptr<OutputSurface> CreateOutputSurface() override {
-    EXPECT_TRUE(false);
-    return nullptr;
+  void RequestNewOutputSurface() override {
+    ADD_FAILURE() << "RequestNewOutputSurface() should not be called";
   }
 
   void DidInitializeOutputSurface() override { EXPECT_TRUE(false); }
@@ -394,16 +401,10 @@
   void BeginTest() override { PostSetNeedsCommitToMainThread(); }
 
   void RequestNewOutputSurface() override {
-    if (layer_tree_host()->visible())
-      CreateAndSetOutputSurface();
-  }
-
-  void CreateAndSetOutputSurface() {
-    std::unique_ptr<OutputSurface> surface =
-        LayerTreeHostContextTest::CreateOutputSurface();
-    CHECK(surface);
-    setos_counter_++;
-    layer_tree_host()->SetOutputSurface(std::move(surface));
+    if (layer_tree_host()->visible()) {
+      setos_counter_++;
+      LayerTreeHostContextTest::RequestNewOutputSurface();
+    }
   }
 
   void HideAndReleaseOutputSurface() {
@@ -463,11 +464,6 @@
     layer_tree_host()->Composite(base::TimeTicks::FromInternalValue(2));
   }
 
-  std::unique_ptr<OutputSurface> CreateOutputSurface() override {
-    EXPECT_TRUE(false);
-    return nullptr;
-  }
-
   void DidInitializeOutputSurface() override { EXPECT_TRUE(false); }
 
   void AfterTest() override {}
@@ -500,9 +496,20 @@
     EXPECT_LE(num_requests_, 2);
     if (num_requests_ > 1)
       return;
+    LayerTreeHostContextTest::RequestNewOutputSurface();
+  }
+
+  std::unique_ptr<TestDelegatingOutputSurface> CreateDelegatingOutputSurface(
+      scoped_refptr<ContextProvider> compositor_context_provider,
+      scoped_refptr<ContextProvider> worker_context_provider) override {
     ExpectCreateToFail();
-    layer_tree_host()->SetOutputSurface(
-        base::WrapUnique(new FailureOutputSurface(false)));
+    auto test_compositor_context_provider = TestContextProvider::Create();
+    test_compositor_context_provider->UnboundTestContext3d()
+        ->loseContextCHROMIUM(GL_GUILTY_CONTEXT_RESET_ARB,
+                              GL_INNOCENT_CONTEXT_RESET_ARB);
+    return LayerTreeTest::CreateDelegatingOutputSurface(
+        std::move(test_compositor_context_provider),
+        std::move(worker_context_provider));
   }
 
   void BeginTest() override {
@@ -555,8 +562,7 @@
 
   void CreateAndSetOutputSurface() {
     creating_output_ = true;
-    layer_tree_host()->SetOutputSurface(
-        LayerTreeHostContextTest::CreateOutputSurface());
+    LayerTreeHostContextTest::RequestNewOutputSurface();
   }
 
   void BeginTest() override {
@@ -588,8 +594,7 @@
   }
 
   void RequestNewOutputSurface() override {
-    layer_tree_host()->SetOutputSurface(
-        LayerTreeHostContextTest::CreateOutputSurface());
+    LayerTreeHostContextTest::RequestNewOutputSurface();
     EndTest();
   }
 
@@ -1036,14 +1041,14 @@
     return draw_result;
   }
 
-  std::unique_ptr<OutputSurface> CreateOutputSurface() override {
+  void RequestNewOutputSurface() override {
     // This will get called twice:
     // First when we create the initial output surface...
     if (layer_tree_host()->source_frame_number() > 0) {
       // ... and then again after we forced the context to be lost.
       lost_context_ = true;
     }
-    return LayerTreeHostContextTest::CreateOutputSurface();
+    LayerTreeHostContextTest::RequestNewOutputSurface();
   }
 
   void DidCommitAndDrawFrame() override {
diff --git a/cc/trees/layer_tree_host_unittest_copyrequest.cc b/cc/trees/layer_tree_host_unittest_copyrequest.cc
index 623d403..7177580c 100644
--- a/cc/trees/layer_tree_host_unittest_copyrequest.cc
+++ b/cc/trees/layer_tree_host_unittest_copyrequest.cc
@@ -11,10 +11,13 @@
 #include "cc/layers/layer_iterator.h"
 #include "cc/output/copy_output_request.h"
 #include "cc/output/copy_output_result.h"
+#include "cc/output/direct_renderer.h"
+#include "cc/surfaces/display.h"
 #include "cc/test/fake_content_layer_client.h"
 #include "cc/test/fake_output_surface.h"
 #include "cc/test/fake_picture_layer.h"
 #include "cc/test/layer_tree_test.h"
+#include "cc/test/test_delegating_output_surface.h"
 #include "cc/trees/layer_tree_impl.h"
 #include "gpu/GLES2/gl2extchromium.h"
 
@@ -126,19 +129,19 @@
 
   void AfterTest() override { EXPECT_EQ(4u, callbacks_.size()); }
 
-  std::unique_ptr<OutputSurface> CreateOutputSurface() override {
+  std::unique_ptr<OutputSurface> CreateDisplayOutputSurface(
+      scoped_refptr<ContextProvider> compositor_context_provider) override {
     if (!use_gl_renderer_) {
       return FakeOutputSurface::CreateSoftware(
           base::WrapUnique(new SoftwareOutputDevice));
     }
 
-    std::unique_ptr<FakeOutputSurface> output_surface =
-        FakeOutputSurface::Create3d(TestContextProvider::Create(),
-                                    TestContextProvider::CreateWorker());
-    TestContextSupport* context_support = static_cast<TestContextSupport*>(
-        output_surface->context_provider()->ContextSupport());
+    scoped_refptr<TestContextProvider> display_context_provider =
+        TestContextProvider::Create();
+    TestContextSupport* context_support = display_context_provider->support();
     context_support->set_out_of_order_callbacks(out_of_order_callbacks_);
-    return std::move(output_surface);
+
+    return FakeOutputSurface::Create3d(std::move(display_context_provider));
   }
 
   bool use_gl_renderer_;
@@ -463,8 +466,17 @@
     client_.set_bounds(root_->bounds());
   }
 
+  std::unique_ptr<TestDelegatingOutputSurface> CreateDelegatingOutputSurface(
+      scoped_refptr<ContextProvider> compositor_context_provider,
+      scoped_refptr<ContextProvider> worker_context_provider) override {
+    auto surface = LayerTreeHostCopyRequestTest::CreateDelegatingOutputSurface(
+        std::move(compositor_context_provider),
+        std::move(worker_context_provider));
+    display_ = surface->display();
+    return surface;
+  }
+
   void BeginTest() override {
-    did_draw_ = false;
     PostSetNeedsCommitToMainThread();
 
     copy_layer_->RequestCopyOfOutput(
@@ -480,37 +492,53 @@
     EndTest();
   }
 
-  void DrawLayersOnThread(LayerTreeHostImpl* host_impl) override {
-    Renderer* renderer = host_impl->renderer();
+  void DisplayWillDrawAndSwapOnThread(
+      bool will_draw_and_swap,
+      const RenderPassList& render_passes) override {
+    EXPECT_TRUE(will_draw_and_swap) << did_swap_;
+    if (did_swap_) {
+      // TODO(crbug.com/564832): Ignore the extra frame that occurs due to copy
+      // completion. This can be removed when the extra commit is removed.
+      EXPECT_EQ(1u, render_passes.size());
+      return;
+    }
 
-    LayerImpl* parent =
-        host_impl->active_tree()->LayerById(parent_layer_->id());
-    LayerImpl* copy_layer =
-        host_impl->active_tree()->LayerById(copy_layer_->id());
+    EXPECT_EQ(2u, render_passes.size());
+    // The root pass is the back of the list.
+    copy_layer_render_pass_id = render_passes[0]->id;
+    parent_render_pass_id = render_passes[1]->id;
+  }
+
+  void DisplayDidDrawAndSwapOnThread() override {
+    DirectRenderer* renderer = display_->renderer_for_testing();
 
     // |parent| owns a surface, but it was hidden and not part of the copy
     // request so it should not allocate any resource.
-    EXPECT_FALSE(renderer->HasAllocatedResourcesForTesting(
-        parent->render_surface()->GetRenderPassId()));
+    EXPECT_FALSE(
+        renderer->HasAllocatedResourcesForTesting(parent_render_pass_id));
 
-    // |copy_layer| should have been rendered to a texture since it was needed
-    // for a copy request.
-    if (did_draw_) {
-      // TODO(crbug.com/564832): Ignore the extra frame that occurs due to copy
-      // completion. This can be removed when the extra commit is removed.
-      EXPECT_FALSE(copy_layer->render_surface());
+    // TODO(crbug.com/564832): Ignore the extra frame that occurs due to copy
+    // completion. This can be removed when the extra commit is removed.
+    if (did_swap_) {
+      EXPECT_FALSE(
+          renderer->HasAllocatedResourcesForTesting(copy_layer_render_pass_id));
     } else {
-      EXPECT_TRUE(renderer->HasAllocatedResourcesForTesting(
-          copy_layer->render_surface()->GetRenderPassId()));
+      // |copy_layer| should have been rendered to a texture since it was needed
+      // for a copy request.
+      EXPECT_TRUE(
+          renderer->HasAllocatedResourcesForTesting(copy_layer_render_pass_id));
     }
 
-    did_draw_ = true;
+    did_swap_ = true;
   }
 
-  void AfterTest() override { EXPECT_TRUE(did_draw_); }
+  void AfterTest() override { EXPECT_TRUE(did_swap_); }
 
+  RenderPassId parent_render_pass_id;
+  RenderPassId copy_layer_render_pass_id;
+  Display* display_ = nullptr;
+  bool did_swap_ = false;
   FakeContentLayerClient client_;
-  bool did_draw_;
   scoped_refptr<FakePictureLayer> root_;
   scoped_refptr<FakePictureLayer> grand_parent_layer_;
   scoped_refptr<FakePictureLayer> parent_layer_;
@@ -707,18 +735,13 @@
 SINGLE_AND_MULTI_THREAD_DIRECT_RENDERER_TEST_F(
     LayerTreeHostTestAsyncTwoReadbacksWithoutDraw);
 
-class LayerTreeHostCopyRequestTestLostOutputSurface
+class LayerTreeHostCopyRequestTestDeleteTexture
     : public LayerTreeHostCopyRequestTest {
  protected:
-  std::unique_ptr<OutputSurface> CreateOutputSurface() override {
-    if (!first_context_provider_) {
-      first_context_provider_ = TestContextProvider::Create();
-      return FakeOutputSurface::Create3d(first_context_provider_);
-    }
-
-    EXPECT_FALSE(second_context_provider_);
-    second_context_provider_ = TestContextProvider::Create();
-    return FakeOutputSurface::Create3d(second_context_provider_);
+  std::unique_ptr<OutputSurface> CreateDisplayOutputSurface(
+      scoped_refptr<ContextProvider> compositor_context_provider) override {
+    display_context_provider_ = TestContextProvider::Create();
+    return FakeOutputSurface::Create3d(display_context_provider_);
   }
 
   void SetupTree() override {
@@ -752,7 +775,7 @@
 
   void InsertCopyRequest() {
     copy_layer_->RequestCopyOfOutput(CopyOutputRequest::CreateRequest(
-        base::Bind(&LayerTreeHostCopyRequestTestLostOutputSurface::
+        base::Bind(&LayerTreeHostCopyRequestTestDeleteTexture::
                        ReceiveCopyRequestOutputAndCommit,
                    base::Unretained(this))));
   }
@@ -762,78 +785,59 @@
     result_ = nullptr;
 
     ImplThreadTaskRunner()->PostTask(
-        FROM_HERE, base::Bind(&LayerTreeHostCopyRequestTestLostOutputSurface::
+        FROM_HERE, base::Bind(&LayerTreeHostCopyRequestTestDeleteTexture::
                                   CheckNumTexturesAfterReadbackDestroyed,
                               base::Unretained(this)));
   }
 
   void CheckNumTexturesAfterReadbackDestroyed() {
-    // After the loss we had |num_textures_after_loss_| many textures, but
-    // releasing the copy output request will cause the texture in the request
-    // to be released, so we should have 1 less by now.
-    EXPECT_EQ(num_textures_after_loss_ - 1,
-              first_context_provider_->TestContext3d()->NumTextures());
+    // After the copy we had |num_textures_after_readback_| many textures, but
+    // releasing the copy output request should cause the texture in the request
+    // to be destroyed by the compositor, so we should have 1 less by now.
+    EXPECT_EQ(num_textures_after_readback_ - 1,
+              display_context_provider_->TestContext3d()->NumTextures());
     EndTest();
   }
 
-  void SwapBuffersCompleteOnThread() override {
+  void DisplayDidDrawAndSwapOnThread() override {
     switch (num_swaps_++) {
       case 0:
-        // The layers have been drawn, so their textures have been allocated.
+        // The layers have been drawn, so any textures required for drawing have
+        // been allocated.
         EXPECT_FALSE(result_);
         num_textures_without_readback_ =
-            first_context_provider_->TestContext3d()->NumTextures();
+            display_context_provider_->TestContext3d()->NumTextures();
 
         // Request a copy of the layer. This will use another texture.
         MainThreadTaskRunner()->PostTask(
             FROM_HERE,
-            base::Bind(&LayerTreeHostCopyRequestTestLostOutputSurface::
-                           InsertCopyRequest,
-                       base::Unretained(this)));
+            base::Bind(
+                &LayerTreeHostCopyRequestTestDeleteTexture::InsertCopyRequest,
+                base::Unretained(this)));
         break;
       case 1:
         // We did a readback, so there will be a readback texture around now.
-        EXPECT_LT(num_textures_without_readback_,
-                  first_context_provider_->TestContext3d()->NumTextures());
-
-        // The copy request will be serviced and the result sent to
-        // ReceiveCopyRequestOutputAndCommit, which posts a new commit causing
-        // the test to advance to the next case.
-        break;
-      case 2:
-        // The readback texture is collected.
-        EXPECT_TRUE(result_);
-
-        // Lose the output surface.
-        first_context_provider_->TestContext3d()->loseContextCHROMIUM(
-            GL_GUILTY_CONTEXT_RESET_ARB, GL_INNOCENT_CONTEXT_RESET_ARB);
-        break;
-      case 3:
-        // The output surface has been recreated.
-        EXPECT_TRUE(second_context_provider_);
-
-        num_textures_after_loss_ =
-            first_context_provider_->TestContext3d()->NumTextures();
+        num_textures_after_readback_ =
+            display_context_provider_->TestContext3d()->NumTextures();
+        EXPECT_LT(num_textures_without_readback_, num_textures_after_readback_);
 
         // Now destroy the CopyOutputResult, releasing the texture inside back
         // to the compositor. Then check the resulting number of allocated
         // textures.
         MainThreadTaskRunner()->PostTask(
-            FROM_HERE,
-            base::Bind(&LayerTreeHostCopyRequestTestLostOutputSurface::
-                           DestroyCopyResultAndCheckNumTextures,
-                       base::Unretained(this)));
+            FROM_HERE, base::Bind(&LayerTreeHostCopyRequestTestDeleteTexture::
+                                      DestroyCopyResultAndCheckNumTextures,
+                                  base::Unretained(this)));
         break;
     }
   }
 
   void AfterTest() override {}
 
-  scoped_refptr<TestContextProvider> first_context_provider_;
-  scoped_refptr<TestContextProvider> second_context_provider_;
+  scoped_refptr<TestContextProvider> display_context_provider_;
   int num_swaps_ = 0;
   size_t num_textures_without_readback_ = 0;
-  size_t num_textures_after_loss_ = 0;
+  size_t num_textures_after_readback_ = 0;
   FakeContentLayerClient client_;
   scoped_refptr<FakePictureLayer> root_;
   scoped_refptr<FakePictureLayer> copy_layer_;
@@ -841,29 +845,47 @@
 };
 
 SINGLE_AND_MULTI_THREAD_DIRECT_RENDERER_TEST_F(
-    LayerTreeHostCopyRequestTestLostOutputSurface);
+    LayerTreeHostCopyRequestTestDeleteTexture);
 
 class LayerTreeHostCopyRequestTestCountTextures
     : public LayerTreeHostCopyRequestTest {
  protected:
-  std::unique_ptr<OutputSurface> CreateOutputSurface() override {
-    context_provider_ = TestContextProvider::Create();
-    return FakeOutputSurface::Create3d(context_provider_);
+  void InitializeSettings(LayerTreeSettings* settings) override {
+    // Always allocate only a single texture at a time through ResourceProvider.
+    settings->renderer_settings.texture_id_allocation_chunk_size = 1;
+  }
+
+  std::unique_ptr<OutputSurface> CreateDisplayOutputSurface(
+      scoped_refptr<ContextProvider> compositor_context_provider) override {
+    // These tests expect the LayerTreeHostImpl to share a context with
+    // the Display so that sync points are not needed and the texture counts
+    // are visible together.
+    // Since this test does not override CreateDelegatingOutputSurface, the
+    // |compositor_context_provider| will be a TestContextProvider.
+    display_context_provider_ =
+        static_cast<TestContextProvider*>(compositor_context_provider.get());
+    return FakeOutputSurface::Create3d(std::move(compositor_context_provider));
   }
 
   void SetupTree() override {
-    client_.set_fill_with_nonsolid_color(true);
+    // The layers in this test have solid color content, so they don't
+    // actually allocate any textures, making counting easier.
 
-    root_ = FakePictureLayer::Create(&client_);
+    root_ = FakePictureLayer::Create(&root_client_);
     root_->SetBounds(gfx::Size(20, 20));
+    root_client_.set_bounds(root_->bounds());
 
-    copy_layer_ = FakePictureLayer::Create(&client_);
+    copy_layer_ = FakePictureLayer::Create(&copy_client_);
     copy_layer_->SetBounds(gfx::Size(10, 10));
+    copy_client_.set_bounds(copy_layer_->bounds());
+    // Doing a copy makes the layer have a render surface which can cause
+    // texture allocations. So get those allocations out of the way in the
+    // first frame by forcing it to have a render surface.
+    copy_layer_->SetForceRenderSurfaceForTesting(true);
     root_->AddChild(copy_layer_);
 
     layer_tree_host()->SetRootLayer(root_);
     LayerTreeHostCopyRequestTest::SetupTree();
-    client_.set_bounds(root_->bounds());
   }
 
   void BeginTest() override {
@@ -876,27 +898,31 @@
   void DidCommit() override {
     switch (layer_tree_host()->source_frame_number()) {
       case 1:
-        // The layers have been pushed to the impl side. The layer textures have
-        // been allocated.
+        // The layers have been pushed to the impl side and drawn. Any textures
+        // that are created in that process will have been allocated.
         RequestCopy(copy_layer_.get());
         break;
     }
   }
 
-  void SwapBuffersCompleteOnThread() override {
+  void DisplayDidDrawAndSwapOnThread() override {
     switch (num_swaps_++) {
       case 0:
-        // The layers have been drawn, so their textures have been allocated.
+        // The first frame has been drawn, so textures for drawing have been
+        // allocated.
         num_textures_without_readback_ =
-            context_provider_->TestContext3d()->NumTextures();
+            display_context_provider_->TestContext3d()->NumTextures();
         break;
       case 1:
         // We did a readback, so there will be a readback texture around now.
         num_textures_with_readback_ =
-            context_provider_->TestContext3d()->NumTextures();
+            display_context_provider_->TestContext3d()->NumTextures();
         waited_sync_token_after_readback_ =
-            context_provider_->TestContext3d()->last_waited_sync_token();
+            display_context_provider_->TestContext3d()
+                ->last_waited_sync_token();
 
+        // End the test after main thread has a chance to hear about the
+        // readback.
         MainThreadTaskRunner()->PostTask(
             FROM_HERE,
             base::Bind(&LayerTreeHostCopyRequestTestCountTextures::DoEndTest,
@@ -907,12 +933,13 @@
 
   virtual void DoEndTest() { EndTest(); }
 
-  scoped_refptr<TestContextProvider> context_provider_;
+  scoped_refptr<TestContextProvider> display_context_provider_;
   int num_swaps_ = 0;
   size_t num_textures_without_readback_ = 0;
   size_t num_textures_with_readback_ = 0;
   gpu::SyncToken waited_sync_token_after_readback_;
-  FakeContentLayerClient client_;
+  FakeContentLayerClient root_client_;
+  FakeContentLayerClient copy_client_;
   scoped_refptr<FakePictureLayer> root_;
   scoped_refptr<FakePictureLayer> copy_layer_;
 };
diff --git a/cc/trees/layer_tree_host_unittest_damage.cc b/cc/trees/layer_tree_host_unittest_damage.cc
index 405d837..d8bde90 100644
--- a/cc/trees/layer_tree_host_unittest_damage.cc
+++ b/cc/trees/layer_tree_host_unittest_damage.cc
@@ -197,7 +197,7 @@
     return draw_result;
   }
 
-  void SwapBuffersCompleteOnThread() override {
+  void DisplayDidDrawAndSwapOnThread() override {
     ++did_swap_;
     EXPECT_EQ(expect_swap_, did_swap_);
   }
diff --git a/chrome/android/BUILD.gn b/chrome/android/BUILD.gn
index 22f6ce17..0490b4a4 100644
--- a/chrome/android/BUILD.gn
+++ b/chrome/android/BUILD.gn
@@ -148,6 +148,7 @@
     "//base:base_java",
     "//chrome/android/webapk/libs/client:client_java",
     "//chrome/android/webapk/libs/common:common_java",
+    "//chrome/android/webapk/libs/runtime_library:webapk_service_aidl_java",
     "//components/safe_json/android:safe_json_java",
     "//components/variations/android:variations_java",
     "//components/web_contents_delegate_android:web_contents_delegate_android_java",
@@ -360,6 +361,7 @@
     "//base:base_java_test_support",
     "//chrome/android:chrome_java",
     "//chrome/android/webapk/libs/common:common_java",
+    "//chrome/android/webapk/libs/runtime_library:webapk_service_aidl_java",
     "//chrome/test/android:chrome_java_test_support",
     "//components/bookmarks/common/android:bookmarks_java",
     "//components/dom_distiller/android:dom_distiller_core_java",
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/readermode/ReaderModePanel.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/readermode/ReaderModePanel.java
index cf00f5c..1bff649 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/readermode/ReaderModePanel.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/readermode/ReaderModePanel.java
@@ -4,8 +4,10 @@
 
 package org.chromium.chrome.browser.compositor.bottombar.readermode;
 
+import android.app.Activity;
 import android.content.Context;
 
+import org.chromium.base.ActivityState;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.compositor.LayerTitleCache;
 import org.chromium.chrome.browser.compositor.bottombar.OverlayContentDelegate;
@@ -326,6 +328,13 @@
         return -getToolbarHeight();
     }
 
+    @Override
+    public void onActivityStateChange(Activity activity, int newState) {
+        // If the activity is only resuming, don't do anything.
+        if (newState == ActivityState.RESUMED) return;
+        super.onActivityStateChange(activity, newState);
+    }
+
     // ============================================================================================
     // ReaderModeBarControl
     // ============================================================================================
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/infobar/AutofillCreditCardFillingInfoBar.java b/chrome/android/java/src/org/chromium/chrome/browser/infobar/AutofillCreditCardFillingInfoBar.java
new file mode 100644
index 0000000..b34ca865
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/infobar/AutofillCreditCardFillingInfoBar.java
@@ -0,0 +1,84 @@
+// 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.
+
+package org.chromium.chrome.browser.infobar;
+
+import android.graphics.Bitmap;
+
+import org.chromium.base.annotations.CalledByNative;
+import org.chromium.chrome.browser.ResourceId;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * An infobar for assisted credit card filling.
+ */
+public class AutofillCreditCardFillingInfoBar extends ConfirmInfoBar {
+    private final List<CardDetail> mCardDetails = new ArrayList<>();
+
+    /**
+     * Creates a new instance of the infobar.
+     *
+     * @param nativeAutofillCreditCardFillingInfoBar The pointer to the native object for callbacks.
+     * @param enumeratedIconId ID corresponding to the icon that will be shown for the InfoBar.
+     *                         The ID must have been mapped using the ResourceMapper class before
+     *                         passing it to this function.
+     * @param iconBitmap Bitmap to use if there is no equivalent Java resource for enumeratedIconId.
+     * @param message Message to display to the user indicating what the InfoBar is for.
+     * @param buttonOk String to display on the OK button.
+     * @param buttonCancel String to display on the Cancel button.
+     */
+    private AutofillCreditCardFillingInfoBar(long nativeAutofillCreditCardFillingInfoBar,
+            int enumeratedIconId, Bitmap iconBitmap, String message, String buttonOk,
+            String buttonCancel) {
+        super(ResourceId.mapToDrawableId(enumeratedIconId), iconBitmap, message, null, buttonOk,
+                buttonCancel);
+    }
+
+    /**
+     * Creates an infobar for assisted credit card filling.
+     *
+     * @param nativeAutofillCreditCardFillingInfoBar The pointer to the native object for callbacks.
+     * @param enumeratedIconId ID corresponding to the icon that will be shown for the InfoBar.
+     *                         The ID must have been mapped using the ResourceMapper class before
+     *                         passing it to this function.
+     * @param iconBitmap Bitmap to use if there is no equivalent Java resource for enumeratedIconId.
+     * @param message Message to display to the user indicating what the InfoBar is for.
+     * @param buttonOk String to display on the OK button.
+     * @param buttonCancel String to display on the Cancel button.
+     * @return A new instance of the infobar.
+     */
+    @CalledByNative
+    private static AutofillCreditCardFillingInfoBar create(
+            long nativeAutofillCreditCardFillingInfoBar, int enumeratedIconId, Bitmap iconBitmap,
+            String message, String buttonOk, String buttonCancel) {
+        return new AutofillCreditCardFillingInfoBar(nativeAutofillCreditCardFillingInfoBar,
+                enumeratedIconId, iconBitmap, message, buttonOk, buttonCancel);
+    }
+
+    /**
+     * Adds information to the infobar about the credit card that will be proposed for the assist.
+     *
+     * @param enumeratedIconId ID corresponding to the icon that will be shown for this credit card.
+     *                         The ID must have been mapped using the ResourceMapper class before
+     *                         passing it to this function.
+     * @param label The credit card label, for example "***1234".
+     * @param subLabel The credit card sub-label, for example "Exp: 06/17".
+     */
+    @CalledByNative
+    private void addDetail(int enumeratedIconId, String label, String subLabel) {
+        mCardDetails.add(new CardDetail(enumeratedIconId, label, subLabel));
+    }
+
+    @Override
+    public void createContent(InfoBarLayout layout) {
+        super.createContent(layout);
+        InfoBarControlLayout control = layout.addControlLayout();
+        for (int i = 0; i < mCardDetails.size(); i++) {
+            CardDetail detail = mCardDetails.get(i);
+            control.addIcon(detail.issuerIconDrawableId, 0, detail.label, detail.subLabel);
+        }
+    }
+}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/infobar/AutofillSaveCardInfoBar.java b/chrome/android/java/src/org/chromium/chrome/browser/infobar/AutofillSaveCardInfoBar.java
index d4d09b5..151a58d 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/infobar/AutofillSaveCardInfoBar.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/infobar/AutofillSaveCardInfoBar.java
@@ -13,6 +13,7 @@
 import org.chromium.base.annotations.CalledByNative;
 import org.chromium.chrome.browser.ResourceId;
 
+import java.util.ArrayList;
 import java.util.LinkedList;
 import java.util.List;
 
@@ -21,41 +22,6 @@
  */
 public class AutofillSaveCardInfoBar extends ConfirmInfoBar {
     /**
-     * Detailed card information to show in the infobar.
-     */
-    public static class CardDetail {
-        /**
-         * The identifier of the drawable of the card issuer icon.
-         */
-        public int issuerIconDrawableId;
-
-        /**
-         * The label for the card.
-         */
-        public String label;
-
-        /**
-         * The sub-label for the card.
-         */
-        public String subLabel;
-
-        /**
-         * Creates a new instance of the detailed card information.
-         *
-         * @param enumeratedIconId ID corresponding to the icon that will be shown for this credit
-         *                         card. The ID must have been mapped using the ResourceMapper class
-         *                         before passing it to this function.
-         * @param label The credit card label, for example "***1234".
-         * @param subLabel The credit card sub-label, for example "Exp: 06/17".
-         */
-        public CardDetail(int enumeratedIconId, String label, String subLabel) {
-            this.issuerIconDrawableId = ResourceId.mapToDrawableId(enumeratedIconId);
-            this.label = label;
-            this.subLabel = subLabel;
-        }
-    }
-
-    /**
      * Legal message line with links to show in the infobar.
      */
     public static class LegalMessageLine {
@@ -113,7 +79,7 @@
     }
 
     private final long mNativeAutofillSaveCardInfoBar;
-    private final List<CardDetail> mCardDetails = new LinkedList<CardDetail>();
+    private final List<CardDetail> mCardDetails = new ArrayList<>();
     private final LinkedList<LegalMessageLine> mLegalMessageLines =
             new LinkedList<LegalMessageLine>();
 
@@ -200,7 +166,8 @@
     public void createContent(InfoBarLayout layout) {
         super.createContent(layout);
         InfoBarControlLayout control = layout.addControlLayout();
-        for (CardDetail detail : mCardDetails) {
+        for (int i = 0; i < mCardDetails.size(); i++) {
+            CardDetail detail = mCardDetails.get(i);
             control.addIcon(detail.issuerIconDrawableId, 0, detail.label, detail.subLabel);
         }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/infobar/CardDetail.java b/chrome/android/java/src/org/chromium/chrome/browser/infobar/CardDetail.java
new file mode 100644
index 0000000..4a20552c
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/infobar/CardDetail.java
@@ -0,0 +1,42 @@
+// 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.
+
+package org.chromium.chrome.browser.infobar;
+
+import org.chromium.chrome.browser.ResourceId;
+
+/**
+ * Detailed card information to show in the various Autofill infobars.
+ */
+public class CardDetail {
+    /**
+     * The identifier of the drawable of the card issuer icon.
+     */
+    public int issuerIconDrawableId;
+
+    /**
+     * The label for the card.
+     */
+    public String label;
+
+    /**
+     * The sub-label for the card.
+     */
+    public String subLabel;
+
+    /**
+     * Creates a new instance of the detailed card information.
+     *
+     * @param enumeratedIconId ID corresponding to the icon that will be shown for this credit
+     *                         card. The ID must have been mapped using the ResourceMapper class
+     *                         before passing it to this function.
+     * @param label The credit card label, for example "***1234".
+     * @param subLabel The credit card sub-label, for example "Exp: 06/17".
+     */
+    public CardDetail(int enumeratedIconId, String label, String subLabel) {
+        this.issuerIconDrawableId = ResourceId.mapToDrawableId(enumeratedIconId);
+        this.label = label;
+        this.subLabel = subLabel;
+    }
+}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/physicalweb/PwsClientImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/physicalweb/PwsClientImpl.java
index c5632d1f..2bd35ad 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/physicalweb/PwsClientImpl.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/physicalweb/PwsClientImpl.java
@@ -96,16 +96,7 @@
         // Loop through the metadata for each url.
         for (int i = 0; i < metadata.length(); i++) {
             try {
-                JSONObject obj = metadata.getJSONObject(i);
-                JSONObject pageInfo = obj.getJSONObject("pageInfo");
-                String scannedUrl = obj.getString("scannedUrl");
-                String resolvedUrl = obj.getString("resolvedUrl");
-                String iconUrl = pageInfo.optString("icon", null);
-                String title = pageInfo.optString("title", "");
-                String description = pageInfo.optString("description", null);
-                String groupId = pageInfo.optString("groupId", null);
-                pwsResults.add(new PwsResult(
-                        scannedUrl, resolvedUrl, iconUrl, title, description, groupId));
+                pwsResults.add(PwsResult.jsonDeserialize(metadata.getJSONObject(i)));
             } catch (JSONException e) {
                 Log.e(TAG, "PWS returned invalid data", e);
                 continue;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/physicalweb/PwsResult.java b/chrome/android/java/src/org/chromium/chrome/browser/physicalweb/PwsResult.java
index 87d7fc5..8db0ade1 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/physicalweb/PwsResult.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/physicalweb/PwsResult.java
@@ -5,6 +5,9 @@
 
 import org.chromium.base.Log;
 
+import org.json.JSONException;
+import org.json.JSONObject;
+
 import java.net.MalformedURLException;
 import java.net.URL;
 
@@ -17,6 +20,13 @@
  */
 class PwsResult {
     private static final String TAG = "PhysicalWeb";
+    private static final String PAGE_INFO_KEY = "pageInfo";
+    private static final String REQUEST_URL_KEY = "scannedUrl";
+    private static final String SITE_URL_KEY = "resolvedUrl";
+    private static final String ICON_KEY = "icon";
+    private static final String TITLE_KEY = "title";
+    private static final String DESCRIPTION_KEY = "description";
+    private static final String GROUP_ID_KEY = "groupId";
 
     /**
      * The URL that was set in the request to the PWS.
@@ -72,4 +82,37 @@
         }
         this.groupId = groupIdToSet;
     }
+
+    /**
+     * Creates a JSON object that represents this data structure.
+     * @return a JSON serialization of this data structure.
+     * @throws JSONException if the values cannot be deserialized.
+     */
+    public JSONObject jsonSerialize() throws JSONException {
+        return new JSONObject()
+                .put(REQUEST_URL_KEY, requestUrl)
+                .put(SITE_URL_KEY, siteUrl)
+                .put(PAGE_INFO_KEY, new JSONObject()
+                    .put(ICON_KEY, iconUrl)
+                    .put(TITLE_KEY, title)
+                    .put(DESCRIPTION_KEY, description)
+                    .put(GROUP_ID_KEY, groupId));
+    }
+
+    /**
+     * Populates a PwsResult with data from a given JSON object.
+     * @param jsonObject a serialized PwsResult.
+     * @return The PwsResult represented by the serialized object.
+     * @throws JSONException if the values cannot be serialized.
+     */
+    public static PwsResult jsonDeserialize(JSONObject jsonObject) throws JSONException {
+        JSONObject pageInfo = jsonObject.getJSONObject(PAGE_INFO_KEY);
+        return new PwsResult(
+                jsonObject.getString(REQUEST_URL_KEY),
+                jsonObject.getString(SITE_URL_KEY),
+                pageInfo.optString(ICON_KEY, null),
+                pageInfo.optString(TITLE_KEY, ""),
+                pageInfo.optString(DESCRIPTION_KEY, null),
+                pageInfo.optString(GROUP_ID_KEY, null));
+    }
 }
diff --git a/chrome/android/java_sources.gni b/chrome/android/java_sources.gni
index 6f8c6db..f945f167 100644
--- a/chrome/android/java_sources.gni
+++ b/chrome/android/java_sources.gni
@@ -383,7 +383,9 @@
   "java/src/org/chromium/chrome/browser/incognito/IncognitoNotificationService.java",
   "java/src/org/chromium/chrome/browser/infobar/AppBannerInfoBarAndroid.java",
   "java/src/org/chromium/chrome/browser/infobar/AppBannerInfoBarDelegateAndroid.java",
+  "java/src/org/chromium/chrome/browser/infobar/AutofillCreditCardFillingInfoBar.java",
   "java/src/org/chromium/chrome/browser/infobar/AutofillSaveCardInfoBar.java",
+  "java/src/org/chromium/chrome/browser/infobar/CardDetail.java",
   "java/src/org/chromium/chrome/browser/infobar/ConfirmInfoBar.java",
   "java/src/org/chromium/chrome/browser/infobar/DataReductionPromoInfoBar.java",
   "java/src/org/chromium/chrome/browser/infobar/DataReductionPromoInfoBarDelegate.java",
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/physicalweb/PwsResultTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/physicalweb/PwsResultTest.java
new file mode 100644
index 0000000..a3547a0e
--- /dev/null
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/physicalweb/PwsResultTest.java
@@ -0,0 +1,58 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.physicalweb;
+
+import android.test.suitebuilder.annotation.SmallTest;
+
+import junit.framework.TestCase;
+
+import org.json.JSONException;
+import org.json.JSONObject;
+
+/**
+ * Tests for {@link PwsResult}.
+ */
+public class PwsResultTest extends TestCase {
+    PwsResult mReferencePwsResult = null;
+    JSONObject mReferenceJsonObject = null;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        mReferencePwsResult = new PwsResult(
+                "https://shorturl.com",
+                "https://longurl.com",
+                "https://longurl.com/favicon.ico",
+                "This is a page",
+                "Pages are the best",
+                "group1");
+        // Because we can't print JSON sorted by keys, the order is important here.
+        mReferenceJsonObject = new JSONObject("{"
+                + "    \"scannedUrl\": \"https://shorturl.com\","
+                + "    \"resolvedUrl\": \"https://longurl.com\","
+                + "    \"icon\": \"https://longurl.com/favicon.ico\","
+                + "    \"title\": \"This is a page\","
+                + "    \"description\": \"Pages are the best\","
+                + "    \"group\": \"group1\""
+                + "}");
+    }
+
+    @SmallTest
+    public void testJsonSerializeWorks() throws JSONException {
+        assertEquals(mReferenceJsonObject.toString(),
+                mReferencePwsResult.jsonSerialize().toString());
+    }
+
+    @SmallTest
+    public void testJsonDeserializeWorks() throws JSONException {
+        PwsResult pwsResult = PwsResult.jsonDeserialize(mReferenceJsonObject);
+        assertEquals(mReferencePwsResult.requestUrl, pwsResult.requestUrl);
+        assertEquals(mReferencePwsResult.responseUrl, pwsResult.responseUrl);
+        assertEquals(mReferencePwsResult.iconUrl, pwsResult.iconUrl);
+        assertEquals(mReferencePwsResult.title, pwsResult.title);
+        assertEquals(mReferencePwsResult.description, pwsResult.description);
+        assertEquals(mReferencePwsResult.group, pwsResult.group);
+    }
+}
diff --git a/chrome/android/webapk/libs/client/BUILD.gn b/chrome/android/webapk/libs/client/BUILD.gn
index 57d4a97..b0b7cd9 100644
--- a/chrome/android/webapk/libs/client/BUILD.gn
+++ b/chrome/android/webapk/libs/client/BUILD.gn
@@ -14,11 +14,9 @@
   ]
   deps = [
     "//chrome/android/webapk/libs/common:common_java",
+    "//chrome/android/webapk/libs/runtime_library:webapk_service_aidl_java",
   ]
-  srcjar_deps = [
-    ":runtime_library_version_java",
-    "//chrome/android/webapk/libs/runtime_library:webapk_service_aidl",
-  ]
+  srcjar_deps = [ ":runtime_library_version_java" ]
 }
 
 java_cpp_template("runtime_library_version_java") {
@@ -37,5 +35,6 @@
   deps = [
     ":client_java",
     "//base:base_junit_test_support",
+    "//chrome/android/webapk/libs/runtime_library:webapk_service_aidl_java",
   ]
 }
diff --git a/chrome/android/webapk/libs/runtime_library/BUILD.gn b/chrome/android/webapk/libs/runtime_library/BUILD.gn
index ef80ff21..30beb23 100644
--- a/chrome/android/webapk/libs/runtime_library/BUILD.gn
+++ b/chrome/android/webapk/libs/runtime_library/BUILD.gn
@@ -21,6 +21,12 @@
   ]
 }
 
+# A standalone jar for the aidl's generated java files so that multiple places
+# can depend on the aidl.
+android_library("webapk_service_aidl_java") {
+  srcjar_deps = [ ":webapk_service_aidl" ]
+}
+
 # runtime_library_from_assets_java cannot be used as a dependency of another
 # library because the dx tool expects files ending in .dex.jar
 android_library("runtime_library_for_assets_java") {
@@ -29,8 +35,8 @@
     "src/org/chromium/webapk/lib/runtime_library/HostBrowserLauncher.java",
     "src/org/chromium/webapk/lib/runtime_library/WebApkServiceImpl.java",
   ]
-  srcjar_deps = [ ":webapk_service_aidl" ]
   deps = [
+    ":webapk_service_aidl_java",
     "//chrome/android/webapk/libs/common:common_java",
   ]
 }
@@ -39,7 +45,9 @@
 android_library("runtime_library_for_tests_java") {
   java_files =
       [ "src/org/chromium/webapk/lib/runtime_library/WebApkServiceImpl.java" ]
-  srcjar_deps = [ ":webapk_service_aidl" ]
+  deps = [
+    ":webapk_service_aidl_java",
+  ]
 }
 
 android_assets("runtime_library_assets") {
@@ -61,6 +69,7 @@
   java_files = [ "javatests/src/org/chromium/webapk/lib/runtime_library/WebApkServiceImplTest.java" ]
   deps = [
     ":runtime_library_for_tests_java",
+    ":webapk_service_aidl_java",
     "//base:base_java_test_support",
     "//chrome/test/android:chrome_java_test_support",
     "//content/public/test/android:content_java_test_support",
diff --git a/chrome/android/webapk/libs/runtime_library/javatests/DEPS b/chrome/android/webapk/libs/runtime_library/javatests/DEPS
index 7528863..185d7a0 100644
--- a/chrome/android/webapk/libs/runtime_library/javatests/DEPS
+++ b/chrome/android/webapk/libs/runtime_library/javatests/DEPS
@@ -1,4 +1,5 @@
 include_rules = [
+  "+base",
   "+chrome/test",
   "+content/public/test",
 ]
diff --git a/chrome/android/webapk/libs/runtime_library/javatests/src/org/chromium/webapk/lib/runtime_library/WebApkServiceImplTest.java b/chrome/android/webapk/libs/runtime_library/javatests/src/org/chromium/webapk/lib/runtime_library/WebApkServiceImplTest.java
index 110a931e..916c9b22 100644
--- a/chrome/android/webapk/libs/runtime_library/javatests/src/org/chromium/webapk/lib/runtime_library/WebApkServiceImplTest.java
+++ b/chrome/android/webapk/libs/runtime_library/javatests/src/org/chromium/webapk/lib/runtime_library/WebApkServiceImplTest.java
@@ -12,8 +12,8 @@
 import android.content.pm.PackageManager;
 import android.os.IBinder;
 import android.test.InstrumentationTestCase;
-import android.test.suitebuilder.annotation.SmallTest;
 
+import org.chromium.base.test.util.DisabledTest;
 import org.chromium.chrome.test.webapk.TestWebApkServiceImplWrapper;
 import org.chromium.content.browser.test.util.CallbackHelper;
 
@@ -62,8 +62,11 @@
 
     /**
      * Test that an application which is not allowed to use the WebAPK service actually cannot.
+     *
+     * @SmallTest
+     * crbug.com/634390
      */
-    @SmallTest
+    @DisabledTest
     public void testApiFailsIfNoPermission() throws Exception {
         IWebApkApi api = bindService(mContext, mTargetUid + 1, SMALL_ICON_ID);
         try {
@@ -76,8 +79,11 @@
 
     /**
      * Test that an application which is allowed to use the WebAPK service actually can.
+     *
+     * @SmallTest
+     * crbug.com/634390
      */
-    @SmallTest
+    @DisabledTest
     public void testApiWorksIfHasPermission() throws Exception {
         IWebApkApi api = bindService(mContext, mTargetUid, SMALL_ICON_ID);
         try {
diff --git a/chrome/app/chromeos_strings.grdp b/chrome/app/chromeos_strings.grdp
index f9f0561..0cbfdfe9 100644
--- a/chrome/app/chromeos_strings.grdp
+++ b/chrome/app/chromeos_strings.grdp
@@ -2497,14 +2497,65 @@
   <message name="IDS_OPTIONS_SETTINGS_ACCESSIBILITY_FOCUS_HIGHLIGHT_DESCRIPTION" desc="In the settings tab, the text next to the checkbox to highlight the focused object to make it easier to see.">
     Highlight the object with keyboard focus when it changes
   </message>
-  <message name="IDS_OPTIONS_SETTINGS_ACCESSIBILITY_SELECT_TO_SPEAK_DESCRIPTION" desc="In the settings tab, the text next to the checkbox to enable an option to hold a key and click to speak any on-screen text out loud.">
-    Select-to-speak: Hold down Search and click or drag to speak anything
+  <message name="IDS_OPTIONS_SETTINGS_ACCESSIBILITY_SELECT_TO_SPEAK_TITLE" desc="In the settings tab, the text next to the checkbox to enable an option to hold a key and click to speak any on-screen text out loud.">
+    Select-to-speak
+  </message>
+  <message name="IDS_OPTIONS_SETTINGS_ACCESSIBILITY_SELECT_TO_SPEAK_DESCRIPTION" desc="In the settings tab, the description of an option to hold a key and click to speak any on-screen text out loud.">
+    Hold down Search and click or drag to speak anything
   </message>
   <message name="IDS_OPTIONS_SETTINGS_ACCESSIBILITY_SWITCH_ACCESS_DESCRIPTION" desc="In the settings tab, the text next to the checkbox to enable switch access (for users with limited motor control).">
     Switch access (control the computer with just one or two switches)
   </message>
+  <message name="IDS_OPTIONS_SETTINGS_ACCESSIBILITY_MANAGE_ACCESSIBILITY_FEATURES" desc="In the settings tab, the title of a link that opens a screen allowing the user to change accessibility features.">
+    Manage accessibility features
+  </message>
+  <message name="IDS_OPTIONS_SETTINGS_ACCESSIBILITY_TEXT_TO_SPEECH_HEADING" desc="In the settings tab, the heading for accessibility features that enable the computer to speak text from the computer screen.">
+    Text-to-Speech
+  </message>
+  <message name="IDS_OPTIONS_SETTINGS_ACCESSIBILITY_DISPLAY_HEADING" desc="In the settings tab, the heading for accessibility features related to the computer's display.">
+    Display
+  </message>
+  <message name="IDS_OPTIONS_SETTINGS_ACCESSIBILITY_DISPLAY_SETTINGS_TITLE" desc="In the settings tab, the title of a link to open display settings.">
+    Open display device settings
+  </message>
+  <message name="IDS_OPTIONS_SETTINGS_ACCESSIBILITY_DISPLAY_SETTINGS_DESCRIPTION" desc="In the settings tab, an explanation that the display settings have options to adjust the screen resolution.">
+    Allows you to adjust your screen resolution
+  </message>
+  <message name="IDS_OPTIONS_SETTINGS_ACCESSIBILITY_APPEARANCE_SETTINGS_TITLE" desc="In the settings tab, the title of a link to open appearance settings.">
+    Open appearance settings
+  </message>
+  <message name="IDS_OPTIONS_SETTINGS_ACCESSIBILITY_APPEARANCE_SETTINGS_DESCRIPTION" desc="In the settings tab, an explanation that the appearance settings allows you to change the size of text on the screen.">
+    Customize your text size
+  </message>
+  <message name="IDS_OPTIONS_SETTINGS_ACCESSIBILITY_KEYBOARD_HEADING" desc="In the settings tab, the heading above settings related to the keyboard.">
+    Keyboard
+  </message>
+  <message name="IDS_OPTIONS_SETTINGS_ACCESSIBILITY_KEYBOARD_SETTINGS_TITLE" desc="In the settings tab, the title of a link to open keyboard settings.">
+    Open keyboard device settings
+  </message>
+  <message name="IDS_OPTIONS_SETTINGS_ACCESSIBILITY_KEYBOARD_SETTINGS_DESCRIPTION" desc="In the settings tab, an explanation that the keyboard settings let you adjust the rate at which keys automatically repeat when held down, automatic prediction of words, and more.">
+    Allows you to adjust your keyboard repeat rate, word prediction, and more
+  </message>
+  <message name="IDS_OPTIONS_SETTINGS_ACCESSIBILITY_MOUSE_AND_TOUCHPAD_HEADING" desc="In the settings tab, the heading for the section on mouse and touchpad settings.">
+    Mouse and touchpad
+  </message>
+  <message name="IDS_OPTIONS_SETTINGS_ACCESSIBILITY_MOUSE_SETTINGS_TITLE" desc="In the settings tab, the title of a link to open mouse and touchpad settings.">
+    Open mouse and touchpad device settings
+  </message>
+  <message name="IDS_OPTIONS_SETTINGS_ACCESSIBILITY_MOUSE_SETTINGS_DESCRIPTION" desc="In the settings tab, an explanation that the mouse and touchpad settings allows you to turn the tap-to-click feature on and off.">
+    Allows you to enable/disable tap-to-click
+  </message>
+  <message name="IDS_OPTIONS_SETTINGS_ACCESSIBILITY_AUDIO_HEADING" desc="In the settings tab, the heading for the section on audio / sound settings.">
+    Audio
+  </message>
+  <message name="IDS_OPTIONS_SETTINGS_ACCESSIBILITY_ADDITIONAL_FEATURES_TITLE" desc="In the settings tab, the title of a link that adds additional accessibility features not found in the built-in settings.">
+    Add additional features
+  </message>
+  <message name="IDS_OPTIONS_SETTINGS_ACCESSIBILITY_ADDITIONAL_FEATURES_DESCRIPTION" desc="In the settings tab, an explanation that additional accessibility features are found on the Chrome Web Store.">
+    Choose from the Chrome Web Store
+  </message>
   <message name="IDS_FLAGS_EXPERIMENTAL_ACCESSIBILITY_FEATURES_NAME" desc="Name of the about:flag option for experimental accessibility features.">
-    Experimental acecssibility features
+    Experimental accessibility features
   </message>
   <message name="IDS_FLAGS_EXPERIMENTAL_ACCESSIBILITY_FEATURES_DESCRIPTION" desc="Description of the about:flag option for experimental accessibility features.">
     Enable additional accessibility features in the Settings page.
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd
index 54438e4..919656a 100644
--- a/chrome/app/generated_resources.grd
+++ b/chrome/app/generated_resources.grd
@@ -5373,6 +5373,12 @@
       <message name="IDS_FLAGS_COMPOSITED_LAYER_BORDERS_DESCRIPTION" desc="Description of the 'Composited layer borders' lab.">
         Renders a border around composited Render Layers to help debug and study layer compositing.
       </message>
+      <message name="IDS_FLAGS_GL_COMPOSITED_TEXTURE_QUAD_BORDERS" desc="Name of the 'Composited layer borders' lab.">
+        GL composited texture quad borders
+      </message>
+      <message name="IDS_FLAGS_GL_COMPOSITED_TEXTURE_QUAD_BORDERS_DESCRIPTION" desc="Description of the 'Composited layer borders' lab.">
+        Renders a border around GL composited texture quads to help debug and study overlay support.
+      </message>
       <message name="IDS_FLAGS_DEBUG_SHORTCUTS_NAME" desc="Name of the 'Debugging keyboard shortcuts' lab.">
         Debugging keyboard shortcuts
       </message>
@@ -13522,6 +13528,14 @@
         </message>
       </if>
 
+      <!-- Strings for controlling credit card assist feature in about:flags. -->
+      <message name="IDS_FLAGS_CREDIT_CARD_ASSIST_NAME" desc="The name of about:flags option to enable the credit card assisted filling.">
+        Credit Card Assisted Filling
+      </message>
+      <message name="IDS_FLAGS_CREDIT_CARD_ASSIST_DESCRIPTION" desc="The description of about:flags option to enable the credit card assisted filling..">
+        Enable assisted credit card filling on certain sites.
+      </message>
+
       <!-- Strings for controlling credit card scanning feature in about:flags. -->
       <message name="IDS_FLAGS_CREDIT_CARD_SCAN_NAME" desc="The name of about:flags option to enable scanning of credit cards using device camera.">
         Credit card scanning
diff --git a/chrome/app/settings_strings.grdp b/chrome/app/settings_strings.grdp
index 190012e32..414ab0c7 100644
--- a/chrome/app/settings_strings.grdp
+++ b/chrome/app/settings_strings.grdp
@@ -723,6 +723,36 @@
     <message name="IDS_SETTINGS_PRINTING_CUPS_PRINTERS" desc="In Printing Settings, the title of the CUPS printers setting section.">
       Printers
     </message>
+    <message name="IDS_SETTINGS_PRINTING_CUPS_PRINTERS_ADD_PRINTER" desc="In CUPS printing settings subpage, text for the link adding a new CUPS printer.">
+      Add Printer
+    </message>
+    <message name="IDS_SETTINGS_PRINTING_CUPS_PRINTERS_DETAILS" desc="Text for the drop down menu which allows the user to see the printer details.">
+      Details
+    </message>
+    <message name="IDS_SETTINGS_PRINTING_CUPS_PRINTERS_REMOVE" desc="Text for the drop down menu which allows the user to remove the selected printer.">
+      Remove
+    </message>
+    <message name="IDS_SETTINGS_PRINTING_CUPS_SEARCH_LABEL" desc="The placeholder text in the printer search field.">
+      printer name
+    </message>
+    <message name="IDS_SETTINGS_PRINTING_CUPS_ADD_PRINTER_TITLE" desc="Text for the title of the Add Printer dialog.">
+      Add Printer
+    </message>
+    <message name="IDS_SETTINGS_PRINTING_CUPS_PRINTER_DETAILS_TITLE" desc="Text for the title of the Printer Details subpage.">
+      Printer details
+    </message>
+    <message name="IDS_SETTINGS_PRINTING_CUPS_PRINTER_DETAILS_NAME" desc="Lable for the CUPS printer name in the printer details page.">
+      Name
+    </message>
+    <message name="IDS_SETTINGS_PRINTING_CUPS_PRINTER_DETAILS_MODEL" desc="Lable for the CUPS printer model in the printer details page.">
+      Model
+    </message>
+    <message name="IDS_SETTINGS_PRINTING_CUPS_ADD_PRINTER_BUTTON_CANCEL" desc="Text for the button which cancels adding a CUPS printer.">
+      Cancel
+    </message>
+    <message name="IDS_SETTINGS_PRINTING_CUPS_ADD_PRINTER_BUTTON_ADD" desc="Text for the button which allows the user to add a CUPS printer.">
+      Add
+    </message>
   </if>
   <message name="IDS_SETTINGS_PRINTING_CLOUD_PRINTERS" desc="In Printing Settings, the title of the google cloud printers setting section.">
     Google Cloud Print
@@ -1104,9 +1134,6 @@
   <message name="IDS_SETTINGS_SITE_SETTINGS_CATEGORY" desc="Name of the settings page which allows users to modify a specific category under site settings.">
     Permission Category
   </message>
-  <message name="IDS_SETTINGS_SITE_SETTINGS_SITE_DETAILS" desc="Name of the settings page which allows users to modify details about a particular site.">
-    Site Details
-  </message>
   <message name="IDS_SETTINGS_SITE_SETTINGS_ALL_SITES" desc="Label for the all sites site settings.">
     All sites
   </message>
@@ -1294,7 +1321,7 @@
     Permissions
   </message>
   <message name="IDS_SETTINGS_SITE_SETTINGS_CLEAR_BUTTON" desc="The Clear and Reset button, used to clear all permissions and storage for a given site.">
-    Clear &amp; Reset
+    Clear and reset
   </message>
   <message name="IDS_SETTINGS_SITE_SETTINGS_DELETE" desc="Label for the trashcan icon used to delete storage on the Site Details page.">
     Delete
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index 5ce5565..f31f319 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -620,7 +620,6 @@
       "//ui/compositor",
       "//ui/views/mus",
     ]
-    defines += [ "MOJO_SHELL_CLIENT" ]
   }
   if (ui_compositor_image_transport) {
     deps += [ "//ui/gl" ]
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index f7887bb..dd8e952 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -707,6 +707,10 @@
     {"composited-layer-borders", IDS_FLAGS_COMPOSITED_LAYER_BORDERS,
      IDS_FLAGS_COMPOSITED_LAYER_BORDERS_DESCRIPTION, kOsAll,
      SINGLE_VALUE_TYPE(cc::switches::kShowCompositedLayerBorders)},
+    {"gl-composited-texture-quad-borders",
+     IDS_FLAGS_GL_COMPOSITED_TEXTURE_QUAD_BORDERS,
+     IDS_FLAGS_GL_COMPOSITED_TEXTURE_QUAD_BORDERS_DESCRIPTION, kOsAll,
+     SINGLE_VALUE_TYPE(cc::switches::kGlCompositedTextureQuadBorder)},
 #if defined(ENABLE_WEBRTC)
     {"disable-webrtc-hw-decoding", IDS_FLAGS_WEBRTC_HW_DECODING_NAME,
      IDS_FLAGS_WEBRTC_HW_DECODING_DESCRIPTION, kOsAndroid | kOsCrOS,
@@ -1499,6 +1503,13 @@
     {"disable-new-zip-unpacker", IDS_FLAGS_NEW_ZIP_UNPACKER_NAME,
      IDS_FLAGS_NEW_ZIP_UNPACKER_DESCRIPTION, kOsCrOS,
      SINGLE_DISABLE_VALUE_TYPE(chromeos::switches::kDisableNewZIPUnpacker)},
+#endif  // defined(OS_CHROMEOS)
+#if defined(OS_ANDROID)
+    {"enable-credit-card-assist", IDS_FLAGS_CREDIT_CARD_ASSIST_NAME,
+     IDS_FLAGS_CREDIT_CARD_ASSIST_DESCRIPTION, kOsAndroid,
+     FEATURE_VALUE_TYPE(autofill::kAutofillCreditCardAssist)},
+#endif  // defined(OS_ANDROID)
+#if defined(OS_CHROMEOS)
     {"disable-captive-portal-bypass-proxy",
      IDS_FLAGS_CAPTIVE_PORTAL_BYPASS_PROXY_NAME,
      IDS_FLAGS_CAPTIVE_PORTAL_BYPASS_PROXY_DESCRIPTION, kOsCrOS,
diff --git a/chrome/browser/android/chrome_jni_registrar.cc b/chrome/browser/android/chrome_jni_registrar.cc
index b0d717c..c93b323 100644
--- a/chrome/browser/android/chrome_jni_registrar.cc
+++ b/chrome/browser/android/chrome_jni_registrar.cc
@@ -134,6 +134,7 @@
 #include "chrome/browser/ui/android/chrome_http_auth_handler.h"
 #include "chrome/browser/ui/android/connection_info_popup_android.h"
 #include "chrome/browser/ui/android/context_menu_helper.h"
+#include "chrome/browser/ui/android/infobars/app_banner_infobar_android.h"
 #include "chrome/browser/ui/android/infobars/autofill_save_card_infobar.h"
 #include "chrome/browser/ui/android/infobars/grouped_permission_infobar.h"
 #include "chrome/browser/ui/android/infobars/infobar_android.h"
diff --git a/chrome/browser/android/offline_pages/prerendering_offliner.cc b/chrome/browser/android/offline_pages/prerendering_offliner.cc
index 9579bed..e86f3cb 100644
--- a/chrome/browser/android/offline_pages/prerendering_offliner.cc
+++ b/chrome/browser/android/offline_pages/prerendering_offliner.cc
@@ -107,6 +107,8 @@
 
 bool PrerenderingOffliner::LoadAndSave(const SavePageRequest& request,
                                        const CompletionCallback& callback) {
+  DCHECK(!pending_request_.get());
+
   if (pending_request_) {
     DVLOG(1) << "Already have pending request";
     return false;
diff --git a/chrome/browser/android/omnibox/autocomplete_controller_android.cc b/chrome/browser/android/omnibox/autocomplete_controller_android.cc
index 8061733..4a6b524 100644
--- a/chrome/browser/android/omnibox/autocomplete_controller_android.cc
+++ b/chrome/browser/android/omnibox/autocomplete_controller_android.cc
@@ -203,14 +203,14 @@
 void AutocompleteControllerAndroid::Stop(JNIEnv* env,
                                          const JavaParamRef<jobject>& obj,
                                          bool clear_results) {
-  if (autocomplete_controller_ != NULL)
+  if (autocomplete_controller_ != nullptr)
     autocomplete_controller_->Stop(clear_results);
 }
 
 void AutocompleteControllerAndroid::ResetSession(
     JNIEnv* env,
     const JavaParamRef<jobject>& obj) {
-  if (autocomplete_controller_ != NULL)
+  if (autocomplete_controller_ != nullptr)
     autocomplete_controller_->ResetSession();
 }
 
@@ -566,8 +566,8 @@
         obj,
         j_text,
         -1,
-        NULL,
-        NULL,
+        nullptr,
+        nullptr,
         prevent_inline_autocomplete,
         false,
         false,
@@ -608,7 +608,7 @@
       false,
       OmniboxEventProto::INVALID_SPEC,
       &match,
-      NULL);
+      nullptr);
   if (!match.destination_url.is_valid())
     return ScopedJavaLocalRef<jstring>();
 
diff --git a/chrome/browser/android/tab_web_contents_delegate_android.cc b/chrome/browser/android/tab_web_contents_delegate_android.cc
index ddbee41..d27dd7b 100644
--- a/chrome/browser/android/tab_web_contents_delegate_android.cc
+++ b/chrome/browser/android/tab_web_contents_delegate_android.cc
@@ -112,7 +112,7 @@
 
 void TabWebContentsDelegateAndroid::LoadingStateChanged(
     WebContents* source, bool to_different_document) {
-  bool has_stopped = source == NULL || !source->IsLoading();
+  bool has_stopped = source == nullptr || !source->IsLoading();
   WebContentsDelegateAndroid::LoadingStateChanged(
       source, to_different_document);
   LoadProgressChanged(source, has_stopped ? 1 : 0);
@@ -279,7 +279,7 @@
     const content::MediaStreamRequest& request,
     const content::MediaResponseCallback& callback) {
   MediaCaptureDevicesDispatcher::GetInstance()->ProcessMediaAccessRequest(
-      web_contents, request, callback, NULL);
+      web_contents, request, callback, nullptr);
 }
 
 bool TabWebContentsDelegateAndroid::CheckMediaAccessPermission(
@@ -346,7 +346,7 @@
           switches::kDisablePopupBlocking)) {
     if (popup_blocker_helper->MaybeBlockPopup(nav_params,
                                               blink::WebWindowFeatures())) {
-      return NULL;
+      return nullptr;
     }
   }
 
@@ -407,7 +407,7 @@
         jsource.obj(),
         jnew_contents.obj(),
         static_cast<jint>(disposition),
-        NULL,
+        nullptr,
         user_gesture);
   }
 
diff --git a/chrome/browser/autofill/autofill_credit_card_filling_infobar_delegate_mobile_unittest.cc b/chrome/browser/autofill/autofill_credit_card_filling_infobar_delegate_mobile_unittest.cc
new file mode 100644
index 0000000..a3eabe1
--- /dev/null
+++ b/chrome/browser/autofill/autofill_credit_card_filling_infobar_delegate_mobile_unittest.cc
@@ -0,0 +1,113 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/autofill/core/browser/autofill_credit_card_filling_infobar_delegate_mobile.h"
+
+#include <memory>
+
+#include "base/macros.h"
+#include "base/test/histogram_tester.h"
+#include "chrome/test/base/chrome_render_view_host_test_harness.h"
+#include "components/autofill/core/browser/autofill_test_utils.h"
+#include "components/infobars/core/confirm_infobar_delegate.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace autofill {
+
+class AutofillCreditCardFillingInfoBarDelegateMobileTest
+    : public ChromeRenderViewHostTestHarness {
+ public:
+  AutofillCreditCardFillingInfoBarDelegateMobileTest()
+      : infobar_callback_has_run_(false) {}
+  ~AutofillCreditCardFillingInfoBarDelegateMobileTest() override {}
+
+ protected:
+  std::unique_ptr<AutofillCreditCardFillingInfoBarDelegateMobile>
+  CreateDelegate();
+
+  void AcceptInfoBarCallback() { infobar_callback_has_run_ = true; }
+
+  bool infobar_callback_has_run_;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(AutofillCreditCardFillingInfoBarDelegateMobileTest);
+};
+
+std::unique_ptr<AutofillCreditCardFillingInfoBarDelegateMobile>
+AutofillCreditCardFillingInfoBarDelegateMobileTest::CreateDelegate() {
+  infobar_callback_has_run_ = false;
+  CreditCard credit_card;
+  std::unique_ptr<AutofillCreditCardFillingInfoBarDelegateMobile> delegate(
+      new AutofillCreditCardFillingInfoBarDelegateMobile(
+          credit_card,
+          base::Bind(&AutofillCreditCardFillingInfoBarDelegateMobileTest::
+                         AcceptInfoBarCallback,
+                     base::Unretained(this))));
+  delegate->set_was_shown();
+  return delegate;
+}
+
+// Test that credit card infobar metrics are logged correctly.
+TEST_F(AutofillCreditCardFillingInfoBarDelegateMobileTest, Metrics) {
+  // Accept the infobar.
+  {
+    std::unique_ptr<AutofillCreditCardFillingInfoBarDelegateMobile> infobar(
+        CreateDelegate());
+
+    base::HistogramTester histogram_tester;
+    EXPECT_TRUE(infobar->Accept());
+    EXPECT_TRUE(infobar_callback_has_run_);
+    histogram_tester.ExpectBucketCount("Autofill.CreditCardFillingInfoBar",
+                                       AutofillMetrics::INFOBAR_ACCEPTED, 1);
+    infobar.reset();
+    histogram_tester.ExpectBucketCount("Autofill.CreditCardFillingInfoBar",
+                                       AutofillMetrics::INFOBAR_SHOWN, 1);
+  }
+
+  // Cancel the infobar.
+  {
+    std::unique_ptr<AutofillCreditCardFillingInfoBarDelegateMobile> infobar(
+        CreateDelegate());
+
+    base::HistogramTester histogram_tester;
+    EXPECT_TRUE(infobar->Cancel());
+    EXPECT_FALSE(infobar_callback_has_run_);
+    histogram_tester.ExpectBucketCount("Autofill.CreditCardFillingInfoBar",
+                                       AutofillMetrics::INFOBAR_DENIED, 1);
+    infobar.reset();
+    histogram_tester.ExpectBucketCount("Autofill.CreditCardFillingInfoBar",
+                                       AutofillMetrics::INFOBAR_SHOWN, 1);
+  }
+
+  // Dismiss the infobar.
+  {
+    std::unique_ptr<AutofillCreditCardFillingInfoBarDelegateMobile> infobar(
+        CreateDelegate());
+
+    base::HistogramTester histogram_tester;
+    infobar->InfoBarDismissed();
+    EXPECT_FALSE(infobar_callback_has_run_);
+    histogram_tester.ExpectBucketCount("Autofill.CreditCardFillingInfoBar",
+                                       AutofillMetrics::INFOBAR_DENIED, 1);
+    infobar.reset();
+    histogram_tester.ExpectBucketCount("Autofill.CreditCardFillingInfoBar",
+                                       AutofillMetrics::INFOBAR_SHOWN, 1);
+  }
+
+  // Ignore the infobar.
+  {
+    std::unique_ptr<AutofillCreditCardFillingInfoBarDelegateMobile> infobar(
+        CreateDelegate());
+
+    base::HistogramTester histogram_tester;
+    infobar.reset();
+    EXPECT_FALSE(infobar_callback_has_run_);
+    histogram_tester.ExpectBucketCount("Autofill.CreditCardFillingInfoBar",
+                                       AutofillMetrics::INFOBAR_SHOWN, 1);
+    histogram_tester.ExpectBucketCount("Autofill.CreditCardFillingInfoBar",
+                                       AutofillMetrics::INFOBAR_IGNORED, 1);
+  }
+}
+
+}  // namespace autofill
diff --git a/chrome/browser/chrome_browser_main.cc b/chrome/browser/chrome_browser_main.cc
index c7e82fe..d1a7a6e3 100644
--- a/chrome/browser/chrome_browser_main.cc
+++ b/chrome/browser/chrome_browser_main.cc
@@ -268,7 +268,7 @@
 #include "chrome/browser/usb/web_usb_detector.h"
 #endif
 
-#if defined(MOJO_SHELL_CLIENT)
+#if defined(USE_AURA)
 #include "chrome/browser/lifetime/application_lifetime.h"
 #include "content/public/common/mojo_shell_connection.h"
 #include "services/shell/runner/common/client_util.h"
@@ -1224,7 +1224,7 @@
 }
 
 void ChromeBrowserMainParts::PreMainMessageLoopRun() {
-#if defined(MOJO_SHELL_CLIENT)
+#if defined(USE_AURA)
   if (content::MojoShellConnection::GetForProcess() && shell::ShellIsRemote()) {
     content::MojoShellConnection::GetForProcess()->SetConnectionLostClosure(
         base::Bind(&chrome::SessionEnding));
diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc
index c00b4891..4f0bf8e 100644
--- a/chrome/browser/chrome_content_browser_client.cc
+++ b/chrome/browser/chrome_content_browser_client.cc
@@ -191,6 +191,7 @@
 #include "chrome/browser/chromeos/arc/arc_navigation_throttle.h"
 #include "chrome/browser/chromeos/attestation/platform_verification_impl.h"
 #include "chrome/browser/chromeos/chrome_browser_main_chromeos.h"
+#include "chrome/browser/chromeos/chrome_interface_factory.h"
 #include "chrome/browser/chromeos/drive/fileapi/file_system_backend_delegate.h"
 #include "chrome/browser/chromeos/file_manager/app_id.h"
 #include "chrome/browser/chromeos/file_system_provider/fileapi/backend_delegate.h"
@@ -201,15 +202,12 @@
 #include "chrome/browser/chromeos/login/startup_utils.h"
 #include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h"
 #include "chrome/browser/chromeos/system/input_device_settings.h"
+#include "chrome/browser/ui/ash/ash_util.h"
 #include "chrome/browser/ui/browser_dialogs.h"
 #include "chromeos/chromeos_switches.h"
 #include "components/arc/arc_service_manager.h"
 #include "components/arc/intent_helper/local_activity_resolver.h"
 #include "components/user_manager/user_manager.h"
-#if defined(MOJO_SHELL_CLIENT)
-#include "chrome/browser/chromeos/chrome_interface_factory.h"
-#include "chrome/browser/ui/ash/ash_util.h"
-#endif  // MOJO_SHELL_CLIENT
 #elif defined(OS_LINUX)
 #include "chrome/browser/chrome_browser_main_linux.h"
 #elif defined(OS_ANDROID)
@@ -2846,12 +2844,10 @@
   apps->insert(std::make_pair("mojo:media", app_info));
 #endif
 #if defined(OS_CHROMEOS)
-#if defined(MOJO_SHELL_CLIENT)
   if (chrome::IsRunningInMash()) {
     content::MojoShellConnection::GetForProcess()->AddConnectionFilter(
         base::MakeUnique<chromeos::ChromeInterfaceFactory>());
   }
-#endif  // MOJO_SHELL_CLIENT
 #endif  // OS_CHROMEOS
 }
 
diff --git a/chrome/browser/chromeos/BUILD.gn b/chrome/browser/chromeos/BUILD.gn
index a686f5a0..a4bfb97 100644
--- a/chrome/browser/chromeos/BUILD.gn
+++ b/chrome/browser/chromeos/BUILD.gn
@@ -133,8 +133,6 @@
     "//v8",
   ]
 
-  defines = [ "MOJO_SHELL_CLIENT" ]
-
   sources = rebase_path(gypi_values.browser_chromeos_sources, ".", "//chrome") +
             rebase_path(gypi_values.browser_chromeos_extension_sources,
                         ".",
@@ -169,7 +167,7 @@
   }
 
   if (use_cras) {
-    defines += [ "USE_CRAS" ]
+    defines = [ "USE_CRAS" ]
   }
 
   if (ui_compositor_image_transport) {
diff --git a/chrome/browser/chromeos/accessibility/accessibility_manager.cc b/chrome/browser/chromeos/accessibility/accessibility_manager.cc
index 8dee3337..30f50be 100644
--- a/chrome/browser/chromeos/accessibility/accessibility_manager.cc
+++ b/chrome/browser/chromeos/accessibility/accessibility_manager.cc
@@ -227,7 +227,9 @@
         render_view_host->GetRoutingID(),
         done_cb);
   }
-  extension_service->component_loader()->AddChromeVoxExtension(done_cb);
+
+  extension_service->component_loader()->AddComponentFromDir(
+      GetChromeVoxPath(), extension_misc::kChromeVoxExtensionId, done_cb);
 }
 
 void InjectChromeVoxContentScript(
diff --git a/chrome/browser/chromeos/arc/arc_auth_service.cc b/chrome/browser/chromeos/arc/arc_auth_service.cc
index 3aaffd8..105058e7 100644
--- a/chrome/browser/chromeos/arc/arc_auth_service.cc
+++ b/chrome/browser/chromeos/arc/arc_auth_service.cc
@@ -153,9 +153,9 @@
 // static
 void ArcAuthService::RegisterProfilePrefs(
     user_prefs::PrefRegistrySyncable* registry) {
-  // TODO(dspaid): Add a syncable default preference so that new
-  // devices get the last opt-in preference.
-  registry->RegisterBooleanPref(prefs::kArcEnabled, false);
+  registry->RegisterBooleanPref(
+      prefs::kArcEnabled, false,
+      user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
   registry->RegisterBooleanPref(prefs::kArcSignedIn, false);
   registry->RegisterBooleanPref(prefs::kArcBackupRestoreEnabled, true);
   registry->RegisterBooleanPref(prefs::kArcLocationServiceEnabled, true);
diff --git a/chrome/browser/chromeos/hats/hats_notification_controller.cc b/chrome/browser/chromeos/hats/hats_notification_controller.cc
index 26941c1..70efb15 100644
--- a/chrome/browser/chromeos/hats/hats_notification_controller.cc
+++ b/chrome/browser/chromeos/hats/hats_notification_controller.cc
@@ -35,6 +35,17 @@
 const float kScale_1x = 1.0f;
 const float kScale_2x = 2.0f;
 
+// Minimum amount of time before the notification is displayed again after a
+// user has interacted with it.
+const int kHatsThresholdDays = 90;
+
+// The threshold for a googler is less.
+const int kHatsGooglerThresholdDays = 30;
+
+// Minimum amount of time after initial login or oobe after which we can show
+// the HaTS notification.
+const int kHatsNewDeviceThresholdDays = 7;
+
 // Returns true if the given |profile| interacted with HaTS by either
 // dismissing the notification or taking the survey within a given threshold
 // days |threshold_days|.
@@ -86,12 +97,6 @@
 const char HatsNotificationController::kGoogleIcon2xUrl[] =
     "https://www.gstatic.com/images/branding/product/2x/googleg_48dp.png";
 
-// static
-const int HatsNotificationController::kHatsThresholdDays = 90;
-
-// static
-const int HatsNotificationController::kHatsNewDeviceThresholdDays = 7;
-
 HatsNotificationController::HatsNotificationController(
     Profile* profile,
     image_fetcher::ImageFetcher* image_fetcher)
@@ -146,9 +151,12 @@
     return false;
   }
 
+  int threshold_days = IsGoogleUser(profile->GetProfileUserName())
+                           ? kHatsGooglerThresholdDays
+                           : kHatsThresholdDays;
   // Do not show survey to user if user has interacted with HaTS within the past
   // |kHatsThresholdTime| time delta.
-  if (DidShowSurveyToProfileRecently(profile, kHatsThresholdDays))
+  if (DidShowSurveyToProfileRecently(profile, threshold_days))
     return false;
 
   return true;
diff --git a/chrome/browser/chromeos/hats/hats_notification_controller.h b/chrome/browser/chromeos/hats/hats_notification_controller.h
index bab57b4f..8f856d2 100644
--- a/chrome/browser/chromeos/hats/hats_notification_controller.h
+++ b/chrome/browser/chromeos/hats/hats_notification_controller.h
@@ -31,12 +31,6 @@
 class HatsNotificationController : public NotificationDelegate,
                                    public NetworkPortalDetector::Observer {
  public:
-  // Minimum amount of time before the notification is displayed again after a
-  // user has interacted with it.
-  static const int kHatsThresholdDays;
-  // Minimum amount of time after initial login or oobe after which we can show
-  // the HaTS notification.
-  static const int kHatsNewDeviceThresholdDays;
   static const char kDelegateId[];
   static const char kNotificationId[];
   static const char kImageFetcher1xId[];
diff --git a/chrome/browser/chromeos/login/quick_unlock/quick_unlock_utils.cc b/chrome/browser/chromeos/login/quick_unlock/quick_unlock_utils.cc
index ff7c536..afd4e68 100644
--- a/chrome/browser/chromeos/login/quick_unlock/quick_unlock_utils.cc
+++ b/chrome/browser/chromeos/login/quick_unlock/quick_unlock_utils.cc
@@ -8,6 +8,7 @@
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h"
 #include "chrome/common/chrome_features.h"
+#include "components/user_manager/user_manager.h"
 
 namespace chromeos {
 
@@ -27,6 +28,12 @@
     return false;
   }
 
+  // TODO(jdufault): Disable PIN for supervised users until we allow the owner
+  // to set the PIN. See crbug.com/632797.
+  user_manager::User* user = user_manager::UserManager::Get()->GetActiveUser();
+  if (user && user->IsSupervised())
+    return false;
+
   // Enable quick unlock only if the switch is present.
   return base::FeatureList::IsEnabled(features::kQuickUnlockPin);
 }
diff --git a/chrome/browser/chromeos/login/ui/login_display_host_impl.cc b/chrome/browser/chromeos/login/ui/login_display_host_impl.cc
index ebcb944..c549694e 100644
--- a/chrome/browser/chromeos/login/ui/login_display_host_impl.cc
+++ b/chrome/browser/chromeos/login/ui/login_display_host_impl.cc
@@ -11,6 +11,7 @@
 #include "ash/common/wm_shell.h"
 #include "ash/desktop_background/desktop_background_controller.h"
 #include "ash/desktop_background/user_wallpaper_delegate.h"
+#include "ash/public/interfaces/container.mojom.h"
 #include "ash/shell.h"
 #include "base/bind.h"
 #include "base/command_line.h"
@@ -87,6 +88,7 @@
 #include "content/public/browser/web_contents.h"
 #include "content/public/browser/web_ui.h"
 #include "media/audio/sounds/sounds_manager.h"
+#include "services/ui/public/cpp/property_type_converters.h"
 #include "ui/aura/window.h"
 #include "ui/base/ime/chromeos/extension_ime_util.h"
 #include "ui/base/ime/chromeos/input_method_manager.h"
@@ -107,11 +109,6 @@
 #include "ui/views/widget/widget_delegate.h"
 #include "url/gurl.h"
 
-#if defined(MOJO_SHELL_CLIENT)
-#include "ash/public/interfaces/container.mojom.h"
-#include "services/ui/public/cpp/property_type_converters.h"
-#endif
-
 namespace {
 
 // Maximum delay for startup sound after 'loginPromptVisible' signal.
@@ -1141,13 +1138,9 @@
         ash::Shell::GetContainer(ash::Shell::GetPrimaryRootWindow(),
                                  ash::kShellWindowId_LockScreenContainer);
   } else {
-#if defined(MOJO_SHELL_CLIENT)
     params.mus_properties[ash::mojom::kWindowContainer_Property] =
         mojo::ConvertTo<std::vector<uint8_t>>(
             static_cast<int32_t>(ash::mojom::Container::LOGIN_WINDOWS));
-#else
-    NOTREACHED();
-#endif
   }
   login_window_ = new views::Widget;
   params.delegate = new LoginWidgetDelegate(login_window_);
diff --git a/chrome/browser/chromeos/login/users/wallpaper/wallpaper_manager.cc b/chrome/browser/chromeos/login/users/wallpaper/wallpaper_manager.cc
index 764531d6..44b02c8 100644
--- a/chrome/browser/chromeos/login/users/wallpaper/wallpaper_manager.cc
+++ b/chrome/browser/chromeos/login/users/wallpaper/wallpaper_manager.cc
@@ -13,6 +13,7 @@
 #include "ash/common/ash_switches.h"
 #include "ash/desktop_background/desktop_background_controller.h"
 #include "ash/shell.h"
+#include "ash/sysui/public/interfaces/wallpaper.mojom.h"
 #include "base/bind.h"
 #include "base/command_line.h"
 #include "base/files/file_enumerator.h"
@@ -66,10 +67,6 @@
 #include "ui/gfx/image/image_skia_operations.h"
 #include "ui/gfx/skia_util.h"
 
-#if defined(MOJO_SHELL_CLIENT)
-#include "ash/sysui/public/interfaces/wallpaper.mojom.h"
-#endif
-
 using content::BrowserThread;
 using wallpaper::WallpaperManagerBase;
 using wallpaper::WallpaperInfo;
@@ -180,7 +177,6 @@
                                           wallpaper_files_id.id());
 }
 
-#if defined(MOJO_SHELL_CLIENT)
 ash::sysui::mojom::WallpaperLayout WallpaperLayoutToMojo(
     wallpaper::WallpaperLayout layout) {
   switch (layout) {
@@ -199,12 +195,10 @@
   NOTREACHED();
   return ash::sysui::mojom::WallpaperLayout::CENTER;
 }
-#endif
 
 // A helper to set the wallpaper image for Ash and Mash.
 void SetWallpaper(const gfx::ImageSkia& image,
                   wallpaper::WallpaperLayout layout) {
-#if defined(MOJO_SHELL_CLIENT)
   if (chrome::IsRunningInMash()) {
     shell::Connector* connector =
         content::MojoShellConnection::GetForProcess()->GetConnector();
@@ -214,7 +208,6 @@
                                        WallpaperLayoutToMojo(layout));
     return;
   }
-#endif
   // Avoid loading unnecessary wallpapers in tests without a shell instance.
   if (ash::Shell::HasInstance()) {
     ash::Shell::GetInstance()
diff --git a/chrome/browser/chromeos/system/input_device_settings_impl_ozone.cc b/chrome/browser/chromeos/system/input_device_settings_impl_ozone.cc
index 2151480..10808ff3 100644
--- a/chrome/browser/chromeos/system/input_device_settings_impl_ozone.cc
+++ b/chrome/browser/chromeos/system/input_device_settings_impl_ozone.cc
@@ -8,13 +8,10 @@
 #include "base/sys_info.h"
 #include "chrome/browser/chromeos/system/fake_input_device_settings.h"
 #include "content/public/browser/browser_thread.h"
+#include "services/shell/runner/common/client_util.h"
 #include "ui/ozone/public/input_controller.h"
 #include "ui/ozone/public/ozone_platform.h"
 
-#if defined(MOJO_SHELL_CLIENT)
-#include "services/shell/runner/common/client_util.h"
-#endif
-
 namespace chromeos {
 namespace system {
 
@@ -23,11 +20,7 @@
 InputDeviceSettings* g_instance = nullptr;
 
 std::unique_ptr<ui::InputController> CreateStubInputControllerIfNecessary() {
-#if defined(MOJO_SHELL_CLIENT)
   return shell::ShellIsRemote() ? ui::CreateStubInputController() : nullptr;
-#else
-  return nullptr;
-#endif
 }
 
 // InputDeviceSettings for Linux without X11 (a.k.a. Ozone).
diff --git a/chrome/browser/extensions/api/processes/processes_apitest.cc b/chrome/browser/extensions/api/processes/processes_apitest.cc
index 074d1eb..626e6a3 100644
--- a/chrome/browser/extensions/api/processes/processes_apitest.cc
+++ b/chrome/browser/extensions/api/processes/processes_apitest.cc
@@ -27,13 +27,8 @@
 };
 
 
-// This test is flaky on Win7 Tests (dbg)(1). https://crbug.com/598445
-#if defined(OS_WIN)
-#define MAYBE_Processes DISABLED_Processes
-#else
-#define MAYBE_Processes Processes
-#endif
-IN_PROC_BROWSER_TEST_F(ProcessesApiTest, MAYBE_Processes) {
+// This test is flaky. https://crbug.com/598445
+IN_PROC_BROWSER_TEST_F(ProcessesApiTest, DISABLED_Processes) {
   ASSERT_TRUE(RunExtensionTest("processes/api")) << message_;
 }
 
diff --git a/chrome/browser/extensions/component_loader.cc b/chrome/browser/extensions/component_loader.cc
index c6289573..a85f217c 100644
--- a/chrome/browser/extensions/component_loader.cc
+++ b/chrome/browser/extensions/component_loader.cc
@@ -56,7 +56,6 @@
 #endif
 
 #if defined(OS_CHROMEOS)
-#include "chrome/browser/chromeos/accessibility/accessibility_manager.h"
 #include "chromeos/chromeos_switches.h"
 #include "content/public/browser/site_instance.h"
 #include "content/public/browser/storage_partition.h"
@@ -377,30 +376,8 @@
 }
 
 #if defined(OS_CHROMEOS)
-void ComponentLoader::AddChromeVoxExtension(
-    const base::Closure& done_cb) {
-  base::FilePath resources_path;
-  CHECK(PathService::Get(chrome::DIR_RESOURCES, &resources_path));
-
-  base::FilePath chromevox_path =
-      resources_path.Append(extension_misc::kChromeVoxExtensionPath);
-
-  const base::FilePath::CharType* manifest_filename =
-      IsNormalSession() ? extensions::kManifestFilename
-                        : extension_misc::kGuestManifestFilename;
-  AddWithManifestFile(
-      manifest_filename,
-      chromevox_path,
-      extension_misc::kChromeVoxExtensionId,
-      done_cb);
-}
-
 void ComponentLoader::AddChromeOsSpeechSynthesisExtension() {
-  const base::FilePath::CharType* manifest_filename =
-      IsNormalSession() ? extensions::kManifestFilename
-                        : extension_misc::kGuestManifestFilename;
-  AddWithManifestFile(
-      manifest_filename,
+  AddComponentFromDir(
       base::FilePath(extension_misc::kSpeechSynthesisExtensionPath),
       extension_misc::kSpeechSynthesisExtensionId,
       base::Bind(&ComponentLoader::EnableFileSystemInGuestMode,
@@ -625,12 +602,6 @@
     Add(IDR_ARC_SUPPORT_MANIFEST,
         base::FilePath(FILE_PATH_LITERAL("chromeos/arc_support")));
   }
-
-  // Load ChromeVox extension now if spoken feedback is enabled.
-  if (chromeos::AccessibilityManager::Get() &&
-      chromeos::AccessibilityManager::Get()->IsSpokenFeedbackEnabled()) {
-    AddChromeVoxExtension(base::Closure());
-  }
 #endif  // defined(OS_CHROMEOS)
 
 #if defined(GOOGLE_CHROME_BUILD)
@@ -689,24 +660,26 @@
 }
 
 #if defined(OS_CHROMEOS)
-void ComponentLoader::AddWithManifestFile(
-    const base::FilePath::CharType* manifest_filename,
+void ComponentLoader::AddComponentFromDir(
     const base::FilePath& root_directory,
     const char* extension_id,
     const base::Closure& done_cb) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+  const base::FilePath::CharType* manifest_filename =
+      IsNormalSession() ? extensions::kManifestFilename
+                        : extension_misc::kGuestManifestFilename;
   BrowserThread::PostTaskAndReplyWithResult(
       BrowserThread::FILE,
       FROM_HERE,
       base::Bind(&LoadManifestOnFileThread, root_directory, manifest_filename),
-      base::Bind(&ComponentLoader::FinishAddWithManifestFile,
+      base::Bind(&ComponentLoader::FinishAddComponentFromDir,
                  weak_factory_.GetWeakPtr(),
                  root_directory,
                  extension_id,
                  done_cb));
 }
 
-void ComponentLoader::FinishAddWithManifestFile(
+void ComponentLoader::FinishAddComponentFromDir(
     const base::FilePath& root_directory,
     const char* extension_id,
     const base::Closure& done_cb,
diff --git a/chrome/browser/extensions/component_loader.h b/chrome/browser/extensions/component_loader.h
index c9d8f654..d71d360 100644
--- a/chrome/browser/extensions/component_loader.h
+++ b/chrome/browser/extensions/component_loader.h
@@ -99,10 +99,15 @@
   void Reload(const std::string& extension_id);
 
 #if defined(OS_CHROMEOS)
-  // Calls |done_cb|, if not a null callback, on success.
-  // NOTE: |done_cb| is not called if the component loader is shut down
-  // during loading.
-  void AddChromeVoxExtension(const base::Closure& done_cb);
+  // Add a component extension from a specific directory. Assumes that the
+  // extension uses a different manifest file when this is a guest session.
+  // Calls |done_cb| on success, unless the component loader is
+  // shut down during loading.
+  void AddComponentFromDir(
+      const base::FilePath& root_directory,
+      const char* extension_id,
+      const base::Closure& done_cb);
+
   void AddChromeOsSpeechSynthesisExtension();
 #endif
 
@@ -175,18 +180,10 @@
   void EnableFileSystemInGuestMode(const std::string& id);
 
 #if defined(OS_CHROMEOS)
-  // Adds an extension where the manifest file is stored on the file system.
-  // |manifest_filename| can be relative to the |root_directory|.
-  void AddWithManifestFile(
-      const base::FilePath::CharType* manifest_filename,
-      const base::FilePath& root_directory,
-      const char* extension_id,
-      const base::Closure& done_cb);
-
-  // Used as a reply callback by |AddWithManifestFile|.
+  // Used as a reply callback by |AddComponentFromDir|.
   // Called with a |root_directory| and parsed |manifest| and invokes
   // |done_cb| after adding the extension.
-  void FinishAddWithManifestFile(
+  void FinishAddComponentFromDir(
       const base::FilePath& root_directory,
       const char* extension_id,
       const base::Closure& done_cb,
diff --git a/chrome/browser/extensions/extension_service.cc b/chrome/browser/extensions/extension_service.cc
index e738185..53de0608 100644
--- a/chrome/browser/extensions/extension_service.cc
+++ b/chrome/browser/extensions/extension_service.cc
@@ -1106,7 +1106,7 @@
       content::Source<Profile>(profile_),
       content::Details<UnloadedExtensionInfo>(&details));
 
-  renderer_helper_->OnExtensionUnloaded(extension->id());
+  renderer_helper_->OnExtensionUnloaded(*extension);
 
   system_->UnregisterExtensionWithRequestContexts(extension->id(), reason);
 
diff --git a/chrome/browser/extensions/extension_system_impl.cc b/chrome/browser/extensions/extension_system_impl.cc
index fa7596f..7ad271f 100644
--- a/chrome/browser/extensions/extension_system_impl.cc
+++ b/chrome/browser/extensions/extension_system_impl.cc
@@ -275,8 +275,9 @@
           t(path_list, FILE_PATH_LITERAL(","));
       while (t.GetNext()) {
         std::string extension_id;
-        UnpackedInstaller::Create(extension_service_.get())->
-            LoadFromCommandLine(base::FilePath(t.token()), &extension_id);
+        UnpackedInstaller::Create(extension_service_.get())
+            ->LoadFromCommandLine(base::FilePath(t.token()), &extension_id,
+                                  false /* only_allow_apps */);
       }
     }
   }
diff --git a/chrome/browser/extensions/renderer_initialization_browsertest.cc b/chrome/browser/extensions/renderer_initialization_browsertest.cc
index 4664435..63fbe88 100644
--- a/chrome/browser/extensions/renderer_initialization_browsertest.cc
+++ b/chrome/browser/extensions/renderer_initialization_browsertest.cc
@@ -37,4 +37,22 @@
   ASSERT_FALSE(web_contents->IsCrashed());
 }
 
+// Tests that loading a file from a theme in a tab doesn't crash anything.
+// Another part of crbug.com/528026 and related.
+IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest,
+                       TestRendererInitializationWithThemesTab) {
+  const Extension* extension = LoadExtensionWithFlags(
+      test_data_dir_.AppendASCII("theme"), kFlagAllowOldManifestVersions);
+  ASSERT_TRUE(extension);
+  ASSERT_TRUE(extension->is_theme());
+  GURL url = extension->GetResourceURL("manifest.json");
+  ui_test_utils::NavigateToURL(browser(), url);
+  content::WebContents* web_contents =
+      browser()->tab_strip_model()->GetActiveWebContents();
+  // Wait for the web contents to stop loading.
+  content::WaitForLoadStop(web_contents);
+  EXPECT_EQ(url, web_contents->GetLastCommittedURL());
+  ASSERT_FALSE(web_contents->IsCrashed());
+}
+
 }  // namespace extensions
diff --git a/chrome/browser/extensions/unpacked_installer.cc b/chrome/browser/extensions/unpacked_installer.cc
index c00bad4..1808fa7 100644
--- a/chrome/browser/extensions/unpacked_installer.cc
+++ b/chrome/browser/extensions/unpacked_installer.cc
@@ -130,7 +130,8 @@
 }
 
 bool UnpackedInstaller::LoadFromCommandLine(const base::FilePath& path_in,
-                                            std::string* extension_id) {
+                                            std::string* extension_id,
+                                            bool only_allow_apps) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   DCHECK(extension_path_.empty());
 
@@ -152,6 +153,20 @@
       file_util::LoadExtension(
           extension_path_, Manifest::COMMAND_LINE, GetFlags(), &error).get());
 
+  if (only_allow_apps && !extension()->is_platform_app()) {
+#if defined(GOOGLE_CHROME_BUILD)
+    // Avoid crashing for users with hijacked shortcuts.
+    return true;
+#else
+    // Defined here to avoid unused variable errors in official builds.
+    const char extension_instead_of_app_error[] =
+        "App loading flags cannot be used to load extensions. Please use "
+        "--load-extension instead.";
+    ReportExtensionLoadError(extension_instead_of_app_error);
+    return false;
+#endif
+  }
+
   if (!extension() ||
       !extension_l10n_util::ValidateExtensionLocales(
           extension_path_, extension()->manifest()->value(), &error)) {
diff --git a/chrome/browser/extensions/unpacked_installer.h b/chrome/browser/extensions/unpacked_installer.h
index 2bdc85e..c0416a2 100644
--- a/chrome/browser/extensions/unpacked_installer.h
+++ b/chrome/browser/extensions/unpacked_installer.h
@@ -50,8 +50,10 @@
   // |extension_path| synchronously.
   // The return value indicates whether the installation has begun successfully.
   // The id of the extension being loaded is returned in |extension_id|.
+  // |only_allow_apps| is used to avoid side-loading of non-app extensions.
   bool LoadFromCommandLine(const base::FilePath& extension_path,
-                           std::string* extension_id);
+                           std::string* extension_id,
+                           bool only_allow_apps);
 
   // Allows prompting for plugins to be disabled; intended for testing only.
   bool prompt_for_plugins() { return prompt_for_plugins_; }
diff --git a/chrome/browser/media/android/remote/remote_media_player_bridge.cc b/chrome/browser/media/android/remote/remote_media_player_bridge.cc
index fa30672..4bcd1cff 100644
--- a/chrome/browser/media/android/remote/remote_media_player_bridge.cc
+++ b/chrome/browser/media/android/remote/remote_media_player_bridge.cc
@@ -321,7 +321,8 @@
   CHECK(env);
 
   if (bitmaps.empty()) {
-    Java_RemoteMediaPlayerBridge_setPosterBitmap(env, java_bridge_.obj(), NULL);
+    Java_RemoteMediaPlayerBridge_setPosterBitmap(env, java_bridge_.obj(),
+                                                 nullptr);
   } else {
     ScopedJavaLocalRef<jobject> j_poster_bitmap;
     j_poster_bitmap = gfx::ConvertToJavaBitmap(&(bitmaps[0]));
diff --git a/chrome/browser/page_load_metrics/metrics_web_contents_observer.cc b/chrome/browser/page_load_metrics/metrics_web_contents_observer.cc
index dbb7721..f34a995 100644
--- a/chrome/browser/page_load_metrics/metrics_web_contents_observer.cc
+++ b/chrome/browser/page_load_metrics/metrics_web_contents_observer.cc
@@ -191,6 +191,9 @@
 // TODO(csharrison): Add a case for client side redirects, which is what JS
 // initiated window.location / window.history navigations get set to.
 UserAbortType AbortTypeForPageTransition(ui::PageTransition transition) {
+  if (transition & ui::PAGE_TRANSITION_CLIENT_REDIRECT) {
+    return ABORT_CLIENT_REDIRECT;
+  }
   if (ui::PageTransitionCoreTypeIs(transition, ui::PAGE_TRANSITION_RELOAD))
     return ABORT_RELOAD;
   if (transition & ui::PAGE_TRANSITION_FORWARD_BACK)
@@ -334,6 +337,12 @@
       UMA_HISTOGRAM_COUNTS(internal::kAbortChainSizeForwardBack,
                            aborted_chain_size_);
       return;
+    // TODO(csharrison): Refactor this code so it is based on the WillStart*
+    // code path instead of the committed load code path. Then, for every abort
+    // chain, log a histogram of the counts of each of these metrics. For now,
+    // merge client redirects with new navigations, which was (basically) the
+    // previous behavior.
+    case ABORT_CLIENT_REDIRECT:
     case ABORT_NEW_NAVIGATION:
       UMA_HISTOGRAM_COUNTS(internal::kAbortChainSizeNewNavigation,
                            aborted_chain_size_);
diff --git a/chrome/browser/page_load_metrics/observers/aborts_page_load_metrics_observer.cc b/chrome/browser/page_load_metrics/observers/aborts_page_load_metrics_observer.cc
index 28e31d0..f6c32ab 100644
--- a/chrome/browser/page_load_metrics/observers/aborts_page_load_metrics_observer.cc
+++ b/chrome/browser/page_load_metrics/observers/aborts_page_load_metrics_observer.cc
@@ -10,6 +10,8 @@
 
 namespace internal {
 
+const char kHistogramAbortClientRedirectBeforeCommit[] =
+    "PageLoad.AbortTiming.ClientRedirect.BeforeCommit";
 const char kHistogramAbortForwardBackBeforeCommit[] =
     "PageLoad.AbortTiming.ForwardBackNavigation.BeforeCommit";
 const char kHistogramAbortReloadBeforeCommit[] =
@@ -23,6 +25,8 @@
 const char kHistogramAbortOtherBeforeCommit[] =
     "PageLoad.AbortTiming.Other.BeforeCommit";
 
+const char kHistogramAbortClientRedirectBeforePaint[] =
+    "PageLoad.AbortTiming.ClientRedirect.AfterCommit.BeforePaint";
 const char kHistogramAbortForwardBackBeforePaint[] =
     "PageLoad.AbortTiming.ForwardBackNavigation.AfterCommit.BeforePaint";
 const char kHistogramAbortReloadBeforePaint[] =
@@ -34,6 +38,8 @@
 const char kHistogramAbortCloseBeforePaint[] =
     "PageLoad.AbortTiming.Close.AfterCommit.BeforePaint";
 
+const char kHistogramAbortClientRedirectDuringParse[] =
+    "PageLoad.AbortTiming.ClientRedirect.DuringParse";
 const char kHistogramAbortForwardBackDuringParse[] =
     "PageLoad.AbortTiming.ForwardBackNavigation.DuringParse";
 const char kHistogramAbortReloadDuringParse[] =
@@ -60,6 +66,10 @@
       PAGE_LOAD_HISTOGRAM(internal::kHistogramAbortForwardBackBeforeCommit,
                           time_to_abort);
       return;
+    case UserAbortType::ABORT_CLIENT_REDIRECT:
+      PAGE_LOAD_HISTOGRAM(internal::kHistogramAbortClientRedirectBeforeCommit,
+                          time_to_abort);
+      return;
     case UserAbortType::ABORT_NEW_NAVIGATION:
       PAGE_LOAD_HISTOGRAM(internal::kHistogramAbortNewNavigationBeforeCommit,
                           time_to_abort);
@@ -95,6 +105,10 @@
       PAGE_LOAD_HISTOGRAM(internal::kHistogramAbortForwardBackBeforePaint,
                           time_to_abort);
       return;
+    case UserAbortType::ABORT_CLIENT_REDIRECT:
+      PAGE_LOAD_HISTOGRAM(internal::kHistogramAbortClientRedirectBeforePaint,
+                          time_to_abort);
+      return;
     case UserAbortType::ABORT_NEW_NAVIGATION:
       PAGE_LOAD_HISTOGRAM(internal::kHistogramAbortNewNavigationBeforePaint,
                           time_to_abort);
@@ -129,6 +143,10 @@
       PAGE_LOAD_HISTOGRAM(internal::kHistogramAbortForwardBackDuringParse,
                           time_to_abort);
       return;
+    case UserAbortType::ABORT_CLIENT_REDIRECT:
+      PAGE_LOAD_HISTOGRAM(internal::kHistogramAbortClientRedirectDuringParse,
+                          time_to_abort);
+      return;
     case UserAbortType::ABORT_NEW_NAVIGATION:
       PAGE_LOAD_HISTOGRAM(internal::kHistogramAbortNewNavigationDuringParse,
                           time_to_abort);
diff --git a/chrome/browser/page_load_metrics/observers/aborts_page_load_metrics_observer.h b/chrome/browser/page_load_metrics/observers/aborts_page_load_metrics_observer.h
index 2132d336..6d18d481 100644
--- a/chrome/browser/page_load_metrics/observers/aborts_page_load_metrics_observer.h
+++ b/chrome/browser/page_load_metrics/observers/aborts_page_load_metrics_observer.h
@@ -13,6 +13,7 @@
 extern const char kHistogramAbortForwardBackBeforeCommit[];
 extern const char kHistogramAbortReloadBeforeCommit[];
 extern const char kHistogramAbortNewNavigationBeforeCommit[];
+extern const char kHistogramAbortClientRedirectBeforeCommit[];
 extern const char kHistogramAbortStopBeforeCommit[];
 extern const char kHistogramAbortCloseBeforeCommit[];
 extern const char kHistogramAbortOtherBeforeCommit[];
diff --git a/chrome/browser/page_load_metrics/observers/core_page_load_metrics_observer.cc b/chrome/browser/page_load_metrics/observers/core_page_load_metrics_observer.cc
index 4cdc73f..cc5c8d9 100644
--- a/chrome/browser/page_load_metrics/observers/core_page_load_metrics_observer.cc
+++ b/chrome/browser/page_load_metrics/observers/core_page_load_metrics_observer.cc
@@ -12,6 +12,7 @@
 #include "chrome/browser/page_load_metrics/page_load_metrics_util.h"
 #include "components/rappor/rappor_service.h"
 #include "components/rappor/rappor_utils.h"
+#include "net/http/http_response_headers.h"
 #include "ui/base/page_transition_types.h"
 
 namespace {
@@ -120,6 +121,9 @@
     "PageLoad.ParseTiming.ParseBlockedOnScriptLoadFromDocumentWrite."
     "Background";
 
+const char kHistogramFirstContentfulPaintNoStore[] =
+    "PageLoad.PaintTiming.NavigationToFirstContentfulPaint.NoStore";
+
 const char kHistogramLoadTypeFirstContentfulPaintReload[] =
     "PageLoad.PaintTiming.NavigationToFirstContentfulPaint.LoadType."
     "Reload";
@@ -129,6 +133,9 @@
 const char kHistogramLoadTypeFirstContentfulPaintForwardBack[] =
     "PageLoad.PaintTiming.NavigationToFirstContentfulPaint.LoadType."
     "ForwardBackNavigation";
+const char kHistogramLoadTypeFirstContentfulPaintForwardBackNoStore[] =
+    "PageLoad.PaintTiming.NavigationToFirstContentfulPaint.LoadType."
+    "ForwardBackNavigation.NoStore";
 const char kHistogramLoadTypeFirstContentfulPaintNewNavigation[] =
     "PageLoad.PaintTiming.NavigationToFirstContentfulPaint.LoadType."
     "NewNavigation";
@@ -138,6 +145,9 @@
 const char kHistogramLoadTypeParseStartForwardBack[] =
     "PageLoad.ParseTiming.NavigationToParseStart.LoadType."
     "ForwardBackNavigation";
+const char kHistogramLoadTypeParseStartForwardBackNoStore[] =
+    "PageLoad.ParseTiming.NavigationToParseStart.LoadType."
+    "ForwardBackNavigation.NoStore";
 const char kHistogramLoadTypeParseStartNewNavigation[] =
     "PageLoad.ParseTiming.NavigationToParseStart.LoadType.NewNavigation";
 
@@ -165,7 +175,8 @@
 
 CorePageLoadMetricsObserver::CorePageLoadMetricsObserver()
     : transition_(ui::PAGE_TRANSITION_LINK),
-      initiated_by_user_gesture_(false) {}
+      initiated_by_user_gesture_(false),
+      was_no_store_main_resource_(false) {}
 
 CorePageLoadMetricsObserver::~CorePageLoadMetricsObserver() {}
 
@@ -173,6 +184,12 @@
     content::NavigationHandle* navigation_handle) {
   transition_ = navigation_handle->GetPageTransition();
   initiated_by_user_gesture_ = navigation_handle->HasUserGesture();
+  const net::HttpResponseHeaders* headers =
+      navigation_handle->GetResponseHeaders();
+  if (headers) {
+    was_no_store_main_resource_ =
+        headers->HasHeaderValue("cache-control", "no-store");
+  }
 }
 
 void CorePageLoadMetricsObserver::OnDomContentLoadedEventStart(
@@ -277,6 +294,11 @@
         internal::kHistogramParseStartToFirstContentfulPaint,
         timing.first_contentful_paint.value() - timing.parse_start.value());
 
+    if (was_no_store_main_resource_) {
+      PAGE_LOAD_HISTOGRAM(internal::kHistogramFirstContentfulPaintNoStore,
+                          timing.first_contentful_paint.value());
+    }
+
     switch (GetPageLoadType(transition_)) {
       case LOAD_TYPE_RELOAD:
         PAGE_LOAD_HISTOGRAM(
@@ -292,6 +314,12 @@
         PAGE_LOAD_HISTOGRAM(
             internal::kHistogramLoadTypeFirstContentfulPaintForwardBack,
             timing.first_contentful_paint.value());
+        if (was_no_store_main_resource_) {
+          PAGE_LOAD_HISTOGRAM(
+              internal::
+                  kHistogramLoadTypeFirstContentfulPaintForwardBackNoStore,
+              timing.first_contentful_paint.value());
+        }
         break;
       case LOAD_TYPE_NEW_NAVIGATION:
         PAGE_LOAD_HISTOGRAM(
@@ -327,6 +355,11 @@
       case LOAD_TYPE_FORWARD_BACK:
         PAGE_LOAD_HISTOGRAM(internal::kHistogramLoadTypeParseStartForwardBack,
                             timing.parse_start.value());
+        if (was_no_store_main_resource_) {
+          PAGE_LOAD_HISTOGRAM(
+              internal::kHistogramLoadTypeParseStartForwardBackNoStore,
+              timing.parse_start.value());
+        }
         break;
       case LOAD_TYPE_NEW_NAVIGATION:
         PAGE_LOAD_HISTOGRAM(internal::kHistogramLoadTypeParseStartNewNavigation,
diff --git a/chrome/browser/page_load_metrics/observers/core_page_load_metrics_observer.h b/chrome/browser/page_load_metrics/observers/core_page_load_metrics_observer.h
index b33bc568..a7d06d5 100644
--- a/chrome/browser/page_load_metrics/observers/core_page_load_metrics_observer.h
+++ b/chrome/browser/page_load_metrics/observers/core_page_load_metrics_observer.h
@@ -97,6 +97,7 @@
 
   ui::PageTransition transition_;
   bool initiated_by_user_gesture_;
+  bool was_no_store_main_resource_;
 
   DISALLOW_COPY_AND_ASSIGN(CorePageLoadMetricsObserver);
 };
diff --git a/chrome/browser/page_load_metrics/page_load_metrics_browsertest.cc b/chrome/browser/page_load_metrics/page_load_metrics_browsertest.cc
index 4773621..6f6a801 100644
--- a/chrome/browser/page_load_metrics/page_load_metrics_browsertest.cc
+++ b/chrome/browser/page_load_metrics/page_load_metrics_browsertest.cc
@@ -348,3 +348,32 @@
   histogram_tester_.ExpectTotalCount(
       internal::kHistogramAbortNewNavigationBeforeCommit, 2);
 }
+
+IN_PROC_BROWSER_TEST_F(MetricsWebContentsObserverBrowserTest,
+                       AbortClientRedirect) {
+  ASSERT_TRUE(embedded_test_server()->Start());
+
+  GURL first_url(embedded_test_server()->GetURL("/title1.html"));
+  ui_test_utils::NavigateToURL(browser(), first_url);
+
+  GURL second_url(embedded_test_server()->GetURL("/title2.html"));
+  chrome::NavigateParams params(browser(), second_url,
+                                ui::PAGE_TRANSITION_LINK);
+  content::TestNavigationManager manager(
+      browser()->tab_strip_model()->GetActiveWebContents(), second_url);
+  chrome::Navigate(&params);
+  EXPECT_TRUE(manager.WaitForWillStartRequest());
+
+  {
+    content::TestNavigationManager reload_manager(
+        browser()->tab_strip_model()->GetActiveWebContents(), first_url);
+    EXPECT_TRUE(content::ExecuteScript(
+        browser()->tab_strip_model()->GetActiveWebContents(),
+        "window.location.reload();"));
+  }
+
+  manager.WaitForNavigationFinished();
+
+  histogram_tester_.ExpectTotalCount(
+      internal::kHistogramAbortClientRedirectBeforeCommit, 1);
+}
diff --git a/chrome/browser/page_load_metrics/page_load_metrics_observer.h b/chrome/browser/page_load_metrics/page_load_metrics_observer.h
index f8268d7d..52e28264 100644
--- a/chrome/browser/page_load_metrics/page_load_metrics_observer.h
+++ b/chrome/browser/page_load_metrics/page_load_metrics_observer.h
@@ -27,6 +27,11 @@
   // The user presses the back/forward button.
   ABORT_FORWARD_BACK,
 
+  // The navigation is replaced with a navigation with the qualifier
+  // ui::PAGE_TRANSITION_CLIENT_REDIRECT, which is caused by Javascript, or the
+  // meta refresh tag.
+  ABORT_CLIENT_REDIRECT,
+
   // If the navigation is replaced by a new navigation. This includes link
   // clicks, typing in the omnibox (not a reload), and form submissions.
   ABORT_NEW_NAVIGATION,
diff --git a/chrome/browser/plugins/chrome_plugin_service_filter.cc b/chrome/browser/plugins/chrome_plugin_service_filter.cc
index d785f95..c045356f 100644
--- a/chrome/browser/plugins/chrome_plugin_service_filter.cc
+++ b/chrome/browser/plugins/chrome_plugin_service_filter.cc
@@ -112,7 +112,11 @@
 
   // Check whether the plugin is disabled.
   ResourceContextMap::iterator prefs_it = plugin_prefs_.find(context);
-  DCHECK(prefs_it != plugin_prefs_.end());
+  // The context might not be found because RenderFrameMessageFilter might
+  // outlive the Profile (the context is unregistered during the Profile
+  // destructor).
+  if (prefs_it == plugin_prefs_.end())
+    return false;
 
   if (!prefs_it->second.get()->IsPluginEnabled(*plugin))
     return false;
diff --git a/chrome/browser/profiles/profile_manager.cc b/chrome/browser/profiles/profile_manager.cc
index 1c992d4..becbbe8 100644
--- a/chrome/browser/profiles/profile_manager.cc
+++ b/chrome/browser/profiles/profile_manager.cc
@@ -6,6 +6,7 @@
 
 #include <stdint.h>
 
+#include <map>
 #include <set>
 #include <string>
 
@@ -130,9 +131,18 @@
 
 namespace {
 
-// Profiles that should be deleted on shutdown.
-std::vector<base::FilePath>& ProfilesToDelete() {
-  CR_DEFINE_STATIC_LOCAL(std::vector<base::FilePath>, profiles_to_delete, ());
+// Profile deletion can pass through two stages:
+enum class ProfileDeletionStage {
+  // At SCHEDULED stage will be performed necessary activity prior to
+  // profile deletion. Such as new profile creation, if none is left, or load
+  // fallback profile for Macs, if it not loaded yet.
+  SCHEDULED,
+  // At MARKED stage profile can be safely removed from disk.
+  MARKED
+};
+using ProfileDeletionMap = std::map<base::FilePath, ProfileDeletionStage>;
+ProfileDeletionMap& ProfilesToDelete() {
+  CR_DEFINE_STATIC_LOCAL(ProfileDeletionMap, profiles_to_delete, ());
   return profiles_to_delete;
 }
 
@@ -201,14 +211,26 @@
 }
 
 #if !defined(OS_ANDROID)
-void QueueProfileDirectoryForDeletion(const base::FilePath& path) {
-  ProfilesToDelete().push_back(path);
+// Schedule a profile for deletion if it isn't already scheduled.
+// Returns whether the profile has been newly scheduled.
+bool ScheduleProfileDirectoryForDeletion(const base::FilePath& path) {
+  if (ContainsKey(ProfilesToDelete(), path))
+    return false;
+  ProfilesToDelete()[path] = ProfileDeletionStage::SCHEDULED;
+  return true;
+}
+
+void MarkProfileDirectoryForDeletion(const base::FilePath& path) {
+  DCHECK(!ContainsKey(ProfilesToDelete(), path) ||
+         ProfilesToDelete()[path] == ProfileDeletionStage::SCHEDULED);
+  ProfilesToDelete()[path] = ProfileDeletionStage::MARKED;
 }
 #endif
 
-bool IsProfileMarkedForDeletion(const base::FilePath& profile_path) {
-  return std::find(ProfilesToDelete().begin(), ProfilesToDelete().end(),
-      profile_path) != ProfilesToDelete().end();
+bool IsProfileDirectoryMarkedForDeletion(const base::FilePath& profile_path) {
+  auto it = ProfilesToDelete().find(profile_path);
+  return it != ProfilesToDelete().end() &&
+         it->second == ProfileDeletionStage::MARKED;
 }
 
 // Physically remove deleted profile directories from disk.
@@ -333,11 +355,9 @@
 
 // static
 void ProfileManager::NukeDeletedProfilesFromDisk() {
-  for (std::vector<base::FilePath>::iterator it =
-          ProfilesToDelete().begin();
-       it != ProfilesToDelete().end();
-       ++it) {
-    NukeProfileFromDisk(*it);
+  for (const auto& item : ProfilesToDelete()) {
+    if (item.second == ProfileDeletionStage::MARKED)
+      NukeProfileFromDisk(item.first);
   }
   ProfilesToDelete().clear();
 }
@@ -467,7 +487,7 @@
                profile_path.AsUTF8Unsafe());
 
   // Make sure that this profile is not pending deletion.
-  if (IsProfileMarkedForDeletion(profile_path)) {
+  if (IsProfileDirectoryMarkedForDeletion(profile_path)) {
     if (!callback.is_null())
       callback.Run(NULL, Profile::CREATE_STATUS_LOCAL_FAIL);
     return;
@@ -735,7 +755,7 @@
     const base::FilePath& profile_dir,
     const CreateCallback& callback,
     ProfileMetrics::ProfileDelete deletion_source) {
-  if (IsProfileMarkedForDeletion(profile_dir))
+  if (!ScheduleProfileDirectoryForDeletion(profile_dir))
     return false;
   ScheduleProfileForDeletion(profile_dir, callback);
   ProfileMetrics::LogProfileDeleteUser(deletion_source);
@@ -746,7 +766,7 @@
     const base::FilePath& profile_dir,
     const CreateCallback& callback) {
   DCHECK(profiles::IsMultipleProfilesEnabled());
-  DCHECK(!IsProfileMarkedForDeletion(profile_dir));
+  DCHECK(!IsProfileDirectoryMarkedForDeletion(profile_dir));
 
   // Cancel all in-progress downloads before deleting the profile to prevent a
   // "Do you want to exit Google Chrome and cancel the downloads?" prompt
@@ -770,7 +790,7 @@
     // legacy-supervised.
     if (cur_path != profile_dir &&
         !entry->IsLegacySupervised() &&
-        !IsProfileMarkedForDeletion(cur_path)) {
+        !IsProfileDirectoryMarkedForDeletion(cur_path)) {
       last_non_supervised_profile_path = cur_path;
       break;
     }
@@ -1403,7 +1423,7 @@
 
   // Queue even a profile that was nuked so it will be MarkedForDeletion and so
   // CreateProfileAsync can't create it.
-  QueueProfileDirectoryForDeletion(profile_dir);
+  MarkProfileDirectoryForDeletion(profile_dir);
   storage.RemoveProfile(profile_dir);
   ProfileMetrics::UpdateReportedProfilesStatistics(this);
 }
@@ -1566,7 +1586,7 @@
   }
 
   base::FilePath path = profile->GetPath();
-  if (IsProfileMarkedForDeletion(path)) {
+  if (IsProfileDirectoryMarkedForDeletion(path)) {
     // Do nothing if the profile is already being deleted.
   } else if (profile->GetPrefs()->GetBoolean(prefs::kForceEphemeralProfiles)) {
     // Delete if the profile is an ephemeral profile.
@@ -1617,7 +1637,7 @@
   if (status != Profile::CREATE_STATUS_INITIALIZED)
     return;
 
-  if (IsProfileMarkedForDeletion(new_active_profile_path)) {
+  if (IsProfileDirectoryMarkedForDeletion(new_active_profile_path)) {
     // If the profile we tried to load as the next active profile has been
     // deleted, then retry deleting this profile to redo the logic to load
     // the next available profile.
diff --git a/chrome/browser/resources/chromeos/chromevox/BUILD.gn b/chrome/browser/resources/chromeos/chromevox/BUILD.gn
index 717722b..ca38116 100644
--- a/chrome/browser/resources/chromeos/chromevox/BUILD.gn
+++ b/chrome/browser/resources/chromeos/chromevox/BUILD.gn
@@ -340,6 +340,8 @@
     "//chrome/test:test_support",
     "//chrome/test:test_support_ui",
     "//content/test:test_support",
+    "//services/shell/background:lib",
+    "//services/shell/background/tests:test_support",
     "//testing/gmock",
     "//testing/gtest",
     "//ui/keyboard:resources",
diff --git a/chrome/browser/resources/chromeos/keyboard_overlay.js b/chrome/browser/resources/chromeos/keyboard_overlay.js
index fca7f74c..1d4c9b9 100644
--- a/chrome/browser/resources/chromeos/keyboard_overlay.js
+++ b/chrome/browser/resources/chromeos/keyboard_overlay.js
@@ -555,6 +555,15 @@
 
     classes.push('keyboard-overlay-key-background');
 
+    if ((shortcutId == 'keyboardOverlayGoBack' ||
+         shortcutId == 'keyboardOverlayGoForward') &&
+        !loadTimeData.getBoolean('backspaceGoesBackFeatureEnabled')) {
+      // If the "backspace key goes back" experiment is not enabled, then we
+      // clear the shortcuts for Backspace and Shift+Backspace to go back or
+      // forward respectively.
+      shortcutId = null;
+    }
+
     if (shortcutId) {
       classes.push('is-shortcut');
       classes.push('keyboard-overlay-shortcut-key-background');
diff --git a/chrome/browser/resources/md_downloads/vulcanized.html b/chrome/browser/resources/md_downloads/vulcanized.html
index 02e96c2..894990a9 100644
--- a/chrome/browser/resources/md_downloads/vulcanized.html
+++ b/chrome/browser/resources/md_downloads/vulcanized.html
@@ -1635,6 +1635,7 @@
  * Use of this source code is governed by a BSD-style license that can be
  * found in the LICENSE file. */
 
+<if expr="not chromeos">
 @font-face {
   font-family: 'Roboto';
   font-style: normal;
@@ -1658,6 +1659,7 @@
   src: local('Roboto Bold'), local('Roboto-Bold'),
       url("chrome://resources/roboto/roboto-bold.woff2") format('woff2');
 }
+</if>
 
 </style>
 <style is="custom-style">
@@ -2781,4 +2783,4 @@
   <command id="find-command" shortcut="Ctrl|f"></command>
 </if>
   <link rel="import" href="chrome://resources/html/polymer.html">
-  <script src="crisper.js"></script></body></html>
\ No newline at end of file
+  <script src="crisper.js"></script></body></html>
diff --git a/chrome/browser/resources/md_extensions/manager.js b/chrome/browser/resources/md_extensions/manager.js
index 4f0596e..bce1c2c 100644
--- a/chrome/browser/resources/md_extensions/manager.js
+++ b/chrome/browser/resources/md_extensions/manager.js
@@ -92,6 +92,14 @@
       this.readyPromiseResolver.resolve();
     },
 
+    get keyboardShortcuts() {
+      return this.$['keyboard-shortcuts'];
+    },
+
+    get packDialog() {
+      return this.$['pack-dialog'];
+    },
+
     /**
      * @param {!CustomEvent} event
      * @private
@@ -273,7 +281,7 @@
           break;
       }
 
-      this.manager_.$['items-list'].set('items', assert(items));
+      this.manager_.$/* hack */ ['items-list'].set('items', assert(items));
       this.manager_.changePage(Page.ITEM_LIST);
     },
 
@@ -284,7 +292,7 @@
 
     /** @override */
     showPackDialog: function() {
-      this.manager_.$['pack-dialog'].show();
+      this.manager_.packDialog.show();
     }
   };
 
diff --git a/chrome/browser/resources/md_extensions/service.js b/chrome/browser/resources/md_extensions/service.js
index 4f1f35c..0482a57 100644
--- a/chrome/browser/resources/md_extensions/service.js
+++ b/chrome/browser/resources/md_extensions/service.js
@@ -23,8 +23,8 @@
       this.manager_ = manager;
       this.manager_.sidebar.setDelegate(this);
       this.manager_.set('itemDelegate', this);
-      this.manager_.$['pack-dialog'].set('delegate', this);
-      var keyboardShortcuts = this.manager_.$['keyboard-shortcuts'];
+      this.manager_.packDialog.set('delegate', this);
+      var keyboardShortcuts = this.manager_.keyboardShortcuts;
       keyboardShortcuts.addEventListener(
           'shortcut-updated',
           this.onExtensionCommandUpdated_.bind(this));
diff --git a/chrome/browser/resources/md_user_manager/create_profile.html b/chrome/browser/resources/md_user_manager/create_profile.html
index af41dde6..b483d019 100644
--- a/chrome/browser/resources/md_user_manager/create_profile.html
+++ b/chrome/browser/resources/md_user_manager/create_profile.html
@@ -114,15 +114,8 @@
           font-size: inherit;
           min-height: 40px;
         };
-        --paper-item-focused-before: {
-          background: none;
-        };
       }
 
-      #supervised-user-container paper-listbox paper-item:hover {
-        background: rgba(0, 0, 0, .12);
-      };
-
       #supervised-user-container #import-user {
         -webkit-margin-start: 16px;
       }
diff --git a/chrome/browser/resources/media_router/elements/media_router_container/media_router_container.js b/chrome/browser/resources/media_router/elements/media_router_container/media_router_container.js
index 9bb0912..08a64afc 100644
--- a/chrome/browser/resources/media_router/elements/media_router_container/media_router_container.js
+++ b/chrome/browser/resources/media_router/elements/media_router_container/media_router_container.js
@@ -528,6 +528,10 @@
     this.userHasTakenInitialAction_ = true;
   },
 
+  get header() {
+    return this.$['container-header'];
+  },
+
   /**
    * Checks that the currently selected cast mode is still in the
    * updated list of available cast modes. If not, then update the selected
@@ -2317,7 +2321,7 @@
   updateElementPositioning_: function() {
     // Ensures that conditionally templated elements have finished stamping.
     this.async(function() {
-      var headerHeight = this.$$('#container-header').offsetHeight;
+      var headerHeight = this.header.offsetHeight;
       var firstRunFlowHeight = this.$$('#first-run-flow') &&
           this.$$('#first-run-flow').style.display != 'none' ?
               this.$$('#first-run-flow').offsetHeight : 0;
@@ -2330,7 +2334,7 @@
       var searchPadding =
           hasSearch ? this.computeElementVerticalPadding_(search) : 0;
 
-      this.$['container-header'].style.marginTop = firstRunFlowHeight + 'px';
+      this.header.style.marginTop = firstRunFlowHeight + 'px';
       this.$['content'].style.marginTop =
           firstRunFlowHeight + headerHeight + 'px';
 
diff --git a/chrome/browser/resources/media_router/media_router.js b/chrome/browser/resources/media_router/media_router.js
index afcee951..b0110d0c 100644
--- a/chrome/browser/resources/media_router/media_router.js
+++ b/chrome/browser/resources/media_router/media_router.js
@@ -28,8 +28,7 @@
         ($('media-router-container'));
 
     media_router.ui.setElements(container,
-        /** @type {!MediaRouterHeaderElement} */
-        (container.$['container-header']));
+        /** @type {!MediaRouterHeaderElement} */(container.header));
 
     container.addEventListener('acknowledge-first-run-flow',
                                onAcknowledgeFirstRunFlow);
diff --git a/chrome/browser/resources/settings/a11y_page/a11y_page.html b/chrome/browser/resources/settings/a11y_page/a11y_page.html
index 5fce820..543fd0f 100644
--- a/chrome/browser/resources/settings/a11y_page/a11y_page.html
+++ b/chrome/browser/resources/settings/a11y_page/a11y_page.html
@@ -1,95 +1,55 @@
 <link rel="import" href="chrome://resources/html/polymer.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/paper-button/paper-button.html">
-<if expr="chromeos">
-<link rel="import" href="/controls/settings_checkbox.html">
-</if>
-<link rel="import" href="/settings_shared_css.html">
 <link rel="import" href="/i18n_setup.html">
+<link rel="import" href="/settings_shared_css.html">
+
+<if expr="chromeos">
+<link rel="import" href="chrome://resources/polymer/v1_0/neon-animation/neon-animatable.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/paper-toggle-button/paper-toggle-button.html">
+<link rel="import" href="/a11y_page/manage_a11y_page.html">
+<link rel="import" href="/settings_page/settings_animated_pages.html">
+<link rel="import" href="/settings_page/settings_subpage.html">
+</if>
 
 <dom-module id="settings-a11y-page">
   <template>
     <style include="settings-shared"></style>
 <if expr="chromeos">
-    <div class="settings-box row first">
-      <span>
-        $i18n{a11yExplanation}
-        <a href="$i18nRaw{a11yLearnMoreUrl}" target="_blank">
-          $i18n{learnMore}
-        </a>
-      </span>
-    </div>
-
-    <div class="settings-box block">
-      <settings-checkbox label="$i18n{optionsInMenuLabel}"
-          pref="{{prefs.settings.a11y.enable_menu}}">
-      </settings-checkbox>
-      <settings-checkbox label="$i18n{largeMouseCursorLabel}"
-          pref="{{prefs.settings.a11y.large_cursor_enabled}}">
-      </settings-checkbox>
-      <settings-checkbox label="$i18n{highContrastLabel}"
-          pref="{{prefs.settings.a11y.high_contrast_enabled}}">
-      </settings-checkbox>
-      <settings-checkbox
-          pref="{{prefs.settings.a11y.sticky_keys_enabled}}"
-          label="$i18n{stickyKeysLabel}">
-      </settings-checkbox>
-      <settings-checkbox pref="{{prefs.settings.accessibility}}"
-          label="$i18n{chromeVoxLabel}">
-      </settings-checkbox>
-      <settings-checkbox label="$i18n{screenMagnifierLabel}"
-          pref="{{prefs.settings.a11y.screen_magnifier}}">
-      </settings-checkbox>
-      <settings-checkbox label="$i18n{tapDraggingLabel}"
-          pref="{{prefs.settings.touchpad.enable_tap_dragging}}">
-      </settings-checkbox>
-      <settings-checkbox label="$i18n{clickOnStopLabel}"
-          pref="{{prefs.settings.a11y.autoclick}}">
-      </settings-checkbox>
-
-      <div class="list-item settings-checkbox-spacer">
-        <div>$i18n{delayBeforeClickLabel}</div>
-        <settings-dropdown-menu
-            pref="{{prefs.settings.a11y.autoclick_delay_ms}}"
-            menu-options="[[autoClickDelayOptions_]]" no-label-float>
-        </settings-dropdown-menu>
-      </div>
-
-      <settings-checkbox pref="{{prefs.settings.a11y.virtual_keyboard}}"
-          label="$i18n{onScreenKeyboardLabel}">
-      </settings-checkbox>
-      <settings-checkbox pref="{{prefs.settings.a11y.mono_audio}}"
-          label="$i18n{monoAudioLabel}">
-      </settings-checkbox>
-      <settings-checkbox pref="{{prefs.settings.a11y.caret_highlight}}"
-          label="$i18n{caretHighlightLabel}">
-      </settings-checkbox>
-      <settings-checkbox pref="{{prefs.settings.a11y.cursor_highlight}}"
-          label="$i18n{cursorHighlightLabel}">
-      </settings-checkbox>
-      <settings-checkbox pref="{{prefs.settings.a11y.focus_highlight}}"
-          label="$i18n{focusHighlightLabel}">
-      </settings-checkbox>
-      <template is="dom-if" if="[[showExperimentalFeatures_]]">
-        <settings-checkbox pref="{{prefs.settings.a11y.select_to_speak}}"
-            label="$i18n{selectToSpeakLabel}">
-        </settings-checkbox>
-        <settings-checkbox pref="{{prefs.settings.a11y.switch_access}}"
-            label="$i18n{switchAccessLabel}">
-        </settings-checkbox>
+    <settings-animated-pages id="pages" current-route="{{currentRoute}}"
+        section="a11y">
+      <neon-animatable id="main">
+        <div class="settings-box first">
+          <div class="start">
+            $i18n{optionsInMenuLabel}
+          </div>
+          <paper-toggle-button id="optionsInMenuToggle"
+              checked="{{prefs.settings.a11y.enable_menu.value}}">
+          </paper-toggle-button>
+        </div>
+        <div class="settings-box">
+          <paper-button class="primary-button"
+              on-tap="onManageAccessibilityFeaturesTap_">
+            $i18n{manageAccessibilityFeatures}
+          </paper-button>
+        </div>
+      </neon-animatable>
+      <template is="dom-if" name="manage-a11y">
+        <settings-subpage page-title="$i18n{manageAccessibilityFeatures}">
+          <settings-manage-a11y-page prefs="{{prefs}}">
+          </settings-manage-a11y-page>
+        </settings-subpage>
       </template>
-    </div>
+    </settings-animated-pages>
 </if>
 
-<if expr="chromeos">
-    <div class="settings-box">
-</if>
 <if expr="not chromeos">
     <div class="settings-box first">
-</if>
       <paper-button class="primary-button" on-tap="onMoreFeaturesTap_">
         $i18n{moreFeaturesLink}
       </paper-button>
     </div>
+</if>
+
   </template>
   <script src="a11y_page.js"></script>
 </dom-module>
diff --git a/chrome/browser/resources/settings/a11y_page/a11y_page.js b/chrome/browser/resources/settings/a11y_page/a11y_page.js
index 2ee16f1..365655e 100644
--- a/chrome/browser/resources/settings/a11y_page/a11y_page.js
+++ b/chrome/browser/resources/settings/a11y_page/a11y_page.js
@@ -4,60 +4,37 @@
 
 /**
  * @fileoverview
- * 'settings-a11y-page' is the settings page containing accessibility
- * settings.
- *
- * Example:
- *
- *    <iron-animated-pages>
- *      <settings-a11y-page prefs="{{prefs}}"></settings-a11y-page>
- *      ... other pages ...
- *    </iron-animated-pages>
+ * 'settings-a11y-page' is the small section of advanced settings with
+ * a link to the web store accessibility page on most platforms, and
+ * a subpage with lots of other settings on Chrome OS.
  */
 Polymer({
   is: 'settings-a11y-page',
 
   properties: {
     /**
+     * The current active route.
+     */
+    currentRoute: {
+      type: Object,
+      notify: true,
+    },
+
+    /**
      * Preferences state.
      */
     prefs: {
       type: Object,
       notify: true,
     },
+  },
 
 <if expr="chromeos">
-    autoClickDelayOptions_: {
-      readOnly: true,
-      type: Array,
-      value: function() {
-        return [
-          {value: 600,
-           name: loadTimeData.getString('delayBeforeClickExtremelyShort')},
-          {value: 800,
-           name: loadTimeData.getString('delayBeforeClickVeryShort')},
-          {value: 1000,
-           name: loadTimeData.getString('delayBeforeClickShort')},
-          {value: 2000,
-           name: loadTimeData.getString('delayBeforeClickLong')},
-          {value: 4000,
-           name: loadTimeData.getString('delayBeforeClickVeryLong')},
-        ];
-      },
-    },
-
-    /**
-     * Whether to show experimental accessibility features.
-     * @private {boolean}
-     */
-    showExperimentalFeatures_: {
-      type: Boolean,
-      value: function() {
-        return loadTimeData.getBoolean('showExperimentalA11yFeatures');
-      },
-    }
-</if>
+  /** @private */
+  onManageAccessibilityFeaturesTap_: function() {
+    settings.navigateTo(settings.Route.MANAGE_ACCESSIBILITY);
   },
+</if>
 
   /** @private */
   onMoreFeaturesTap_: function() {
diff --git a/chrome/browser/resources/settings/a11y_page/compiled_resources2.gyp b/chrome/browser/resources/settings/a11y_page/compiled_resources2.gyp
index 5802b23..bbc7a563 100644
--- a/chrome/browser/resources/settings/a11y_page/compiled_resources2.gyp
+++ b/chrome/browser/resources/settings/a11y_page/compiled_resources2.gyp
@@ -6,7 +6,17 @@
     {
       'target_name': 'a11y_page',
       'dependencies': [
+        '../compiled_resources2.gyp:route',
+        '../settings_page/compiled_resources2.gyp:settings_animated_pages',
+      ],
+      'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
+    },
+    {
+      'target_name': 'manage_a11y_page',
+      'dependencies': [
         '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:load_time_data',
+        '<(EXTERNS_GYP):settings_private',
+        '../compiled_resources2.gyp:route',
       ],
       'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
     },
diff --git a/chrome/browser/resources/settings/a11y_page/manage_a11y_page.html b/chrome/browser/resources/settings/a11y_page/manage_a11y_page.html
new file mode 100644
index 0000000..f55d53a
--- /dev/null
+++ b/chrome/browser/resources/settings/a11y_page/manage_a11y_page.html
@@ -0,0 +1,162 @@
+<link rel="import" href="chrome://resources/html/polymer.html">
+<link rel="import" href="/controls/settings_checkbox.html">
+<link rel="import" href="/i18n_setup.html">
+<link rel="import" href="/route.html">
+<link rel="import" href="/settings_shared_css.html">
+<link rel="import" href="/settings_vars_css.html">
+
+<dom-module id="settings-manage-a11y-page">
+  <template>
+    <style include="settings-shared">
+      .indented {
+        -webkit-margin-start: 20px;
+      }
+
+      .no-top-border {
+        border-top: none;
+      }
+
+      h3 {
+        color: var(--settings-nav-grey);
+        font-weight: 500;
+      }
+
+      .settings-box iron-icon {
+        -webkit-margin-end: var(--iron-icon-spacing);
+      }
+
+      .settings-box settings-checkbox {
+        flex-grow: 1;
+      }
+    </style>
+    <div class="settings-box row first">
+      <span>
+        $i18n{a11yExplanation}
+        <a href="$i18nRaw{a11yLearnMoreUrl}" target="_blank">
+          $i18n{learnMore}
+        </a>
+      </span>
+    </div>
+
+    <div class="settings-box block">
+      <h3>$i18n{textToSpeechHeading}</h3>
+      <div class="settings-box first indented">
+        <settings-checkbox pref="{{prefs.settings.accessibility}}"
+            label="$i18n{chromeVoxLabel}">
+        </settings-checkbox>
+        <paper-icon-button icon="cr:settings" on-tap="onChromeVoxSettingsTap_">
+        </paper-icon-button>
+      </div>
+      <template is="dom-if" if="[[showExperimentalFeatures_]]">
+        <div class="settings-box no-top-border indented">
+          <settings-checkbox pref="{{prefs.settings.a11y.select_to_speak}}"
+              label="$i18n{selectToSpeakTitle}"
+              sub-label="$i18n{selectToSpeakDescription}">
+          </settings-checkbox>
+        </div>
+      </template>
+
+      <h3>$i18n{displayHeading}</h3>
+      <div class="settings-box block first indented">
+        <settings-checkbox label="$i18n{highContrastLabel}"
+            pref="{{prefs.settings.a11y.high_contrast_enabled}}">
+        </settings-checkbox>
+        <settings-checkbox label="$i18n{screenMagnifierLabel}"
+            pref="{{prefs.settings.a11y.screen_magnifier}}">
+        </settings-checkbox>
+      </div>
+      <div class="settings-box two-line indented" on-tap="onDisplayTap_"
+          actionable>
+        <iron-icon icon="settings:desktop-windows"></iron-icon>
+        <div class="start">
+          <div>$i18n{displaySettingsTitle}</div>
+          <div class="secondary">$i18n{displaySettingsDescription}</div>
+        </div>
+      </div>
+      <div class="settings-box two-line indented" on-tap="onAppearanceTap_"
+          actionable>
+        <iron-icon icon="settings:text-format"></iron-icon>
+        <div class="start">
+          <div>$i18n{appearanceSettingsTitle}</div>
+          <div class="secondary">$i18n{appearanceSettingsDescription}</div>
+        </div>
+      </div>
+
+      <h3>$i18n{keyboardHeading}</h3>
+      <div class="settings-box block first indented">
+        <settings-checkbox
+            pref="{{prefs.settings.a11y.sticky_keys_enabled}}"
+            label="$i18n{stickyKeysLabel}">
+        </settings-checkbox>
+        <settings-checkbox pref="{{prefs.settings.a11y.virtual_keyboard}}"
+            label="$i18n{onScreenKeyboardLabel}">
+        </settings-checkbox>
+        <settings-checkbox pref="{{prefs.settings.a11y.focus_highlight}}"
+            label="$i18n{focusHighlightLabel}">
+        </settings-checkbox>
+        <settings-checkbox pref="{{prefs.settings.a11y.caret_highlight}}"
+            label="$i18n{caretHighlightLabel}">
+        </settings-checkbox>
+        <template is="dom-if" if="[[showExperimentalFeatures_]]">
+          <settings-checkbox pref="{{prefs.settings.a11y.switch_access}}"
+              label="$i18n{switchAccessLabel}">
+          </settings-checkbox>
+        </template>
+      </div>
+      <div class="settings-box two-line indented" on-tap="onKeyboardTap_"
+          actionable>
+        <iron-icon icon="settings:keyboard"></iron-icon>
+        <div class="start">
+          <div>$i18n{keyboardSettingsTitle}</div>
+          <div class="secondary">$i18n{keyboardSettingsDescription}</div>
+        </div>
+      </div>
+
+      <h3>$i18n{mouseAndTouchpadHeading}</h3>
+      <div class="settings-box block first indented">
+        <settings-checkbox label="$i18n{clickOnStopLabel}"
+            pref="{{prefs.settings.a11y.autoclick}}">
+        </settings-checkbox>
+        <div class="list-item settings-checkbox-spacer">
+          <div>$i18n{delayBeforeClickLabel}</div>
+          <settings-dropdown-menu
+              pref="{{prefs.settings.a11y.autoclick_delay_ms}}"
+              menu-options="[[autoClickDelayOptions_]]" no-label-float>
+          </settings-dropdown-menu>
+        </div>
+        <settings-checkbox label="$i18n{tapDraggingLabel}"
+            pref="{{prefs.settings.touchpad.enable_tap_dragging}}">
+        </settings-checkbox>
+        <settings-checkbox label="$i18n{largeMouseCursorLabel}"
+            pref="{{prefs.settings.a11y.large_cursor_enabled}}">
+        </settings-checkbox>
+        <settings-checkbox pref="{{prefs.settings.a11y.cursor_highlight}}"
+            label="$i18n{cursorHighlightLabel}">
+        </settings-checkbox>
+      </div>
+      <div class="settings-box two-line indented" on-tap="onMouseTap_"
+          actionable>
+        <iron-icon icon="settings:mouse"></iron-icon>
+        <div class="start">
+          <div>$i18n{mouseSettingsTitle}</div>
+          <div class="secondary">$i18n{mouseSettingsDescription}</div>
+        </div>
+      </div>
+
+      <h3>$i18n{audioHeading}</h3>
+      <div class="settings-box block first indented">
+        <settings-checkbox pref="{{prefs.settings.a11y.mono_audio}}"
+            label="$i18n{monoAudioLabel}">
+        </settings-checkbox>
+      </div>
+    </div>
+
+    <div class="settings-box two-line" on-tap="onMoreFeaturesTap_" actionable>
+      <div class="start">
+        <div>$i18n{additionalFeaturesTitle}</div>
+        <div class="secondary">$i18n{additionalFeaturesDescription}</div>
+      </div>
+    </div>
+  </template>
+  <script src="manage_a11y_page.js"></script>
+</dom-module>
diff --git a/chrome/browser/resources/settings/a11y_page/manage_a11y_page.js b/chrome/browser/resources/settings/a11y_page/manage_a11y_page.js
new file mode 100644
index 0000000..c8c2437d
--- /dev/null
+++ b/chrome/browser/resources/settings/a11y_page/manage_a11y_page.js
@@ -0,0 +1,83 @@
+// 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.
+
+/**
+ * @fileoverview
+ * 'settings-manage-a11y-page' is the subpage with the accessibility
+ * settings.
+ */
+Polymer({
+  is: 'settings-manage-a11y-page',
+
+  properties: {
+    /**
+     * Preferences state.
+     */
+    prefs: {
+      type: Object,
+      notify: true,
+    },
+
+    autoClickDelayOptions_: {
+      readOnly: true,
+      type: Array,
+      value: function() {
+        return [
+          {value: 600,
+           name: loadTimeData.getString('delayBeforeClickExtremelyShort')},
+          {value: 800,
+           name: loadTimeData.getString('delayBeforeClickVeryShort')},
+          {value: 1000,
+           name: loadTimeData.getString('delayBeforeClickShort')},
+          {value: 2000,
+           name: loadTimeData.getString('delayBeforeClickLong')},
+          {value: 4000,
+           name: loadTimeData.getString('delayBeforeClickVeryLong')},
+        ];
+      },
+    },
+
+    /**
+     * Whether to show experimental accessibility features.
+     * @private {boolean}
+     */
+    showExperimentalFeatures_: {
+      type: Boolean,
+      value: function() {
+        return loadTimeData.getBoolean('showExperimentalA11yFeatures');
+      },
+    },
+  },
+
+  /** @private */
+  onChromeVoxSettingsTap_: function() {
+    chrome.send('showChromeVoxSettings');
+  },
+
+  /** @private */
+  onDisplayTap_: function() {
+    settings.navigateTo(settings.Route.DISPLAY);
+  },
+
+  /** @private */
+  onAppearanceTap_: function() {
+    settings.navigateTo(settings.Route.APPEARANCE);
+  },
+
+  /** @private */
+  onKeyboardTap_: function() {
+    settings.navigateTo(settings.Route.KEYBOARD);
+  },
+
+  /** @private */
+  onMouseTap_: function() {
+    settings.navigateTo(settings.Route.POINTERS);
+  },
+
+  /** @private */
+  onMoreFeaturesTap_: function() {
+    window.open(
+        'https://chrome.google.com/webstore/category/collection/accessibility');
+  },
+});
diff --git a/chrome/browser/resources/settings/about_page/about_page.js b/chrome/browser/resources/settings/about_page/about_page.js
index 50861b9..07d8eaa 100644
--- a/chrome/browser/resources/settings/about_page/about_page.js
+++ b/chrome/browser/resources/settings/about_page/about_page.js
@@ -55,13 +55,6 @@
   /** @private {?settings.LifetimeBrowserProxy} */
   lifetimeBrowserProxy_: null,
 
-  /**
-   * @type {string} Selector to get the sections.
-   * TODO(michaelpg): replace duplicate docs with @override once b/24294625
-   * is fixed.
-   */
-  sectionSelector: 'settings-section',
-
   /** @override */
   attached: function() {
     this.aboutBrowserProxy_ = settings.AboutPageBrowserProxyImpl.getInstance();
diff --git a/chrome/browser/resources/settings/about_page/channel_switcher_dialog.html b/chrome/browser/resources/settings/about_page/channel_switcher_dialog.html
index 3ca6fc2..a04b0f5ab 100644
--- a/chrome/browser/resources/settings/about_page/channel_switcher_dialog.html
+++ b/chrome/browser/resources/settings/about_page/channel_switcher_dialog.html
@@ -13,6 +13,9 @@
     <dialog is="cr-dialog" id="dialog">
       <div class="title">$i18n{aboutChangeChannel}</div>
       <div class="body">
+        <!-- TODO(dbeam): this can be policy-controlled. Show this in the UI.
+             https://www.chromium.org/administrators/policy-list-3#ChromeOsReleaseChannel
+        -->
         <paper-radio-group
             on-paper-radio-group-changed="onChannelSelectionChanged_">
           <paper-radio-button name="[[browserChannelEnum_.STABLE]]">
diff --git a/chrome/browser/resources/settings/advanced_page/advanced_page.html b/chrome/browser/resources/settings/advanced_page/advanced_page.html
index b2c83a19..c65c24a 100644
--- a/chrome/browser/resources/settings/advanced_page/advanced_page.html
+++ b/chrome/browser/resources/settings/advanced_page/advanced_page.html
@@ -93,7 +93,9 @@
       <template is="dom-if" if="[[showPage(pageVisibility.a11y)]]" restamp>
         <settings-section page-title="$i18n{a11yPageTitle}"
             current-route="[[currentRoute]]" section="a11y">
-          <settings-a11y-page prefs="{{prefs}}"></settings-a11y-page>
+          <settings-a11y-page prefs="{{prefs}}"
+              current-route="{{currentRoute}}">
+          </settings-a11y-page>
         </settings-section>
       </template>
 <if expr="not chromeos">
diff --git a/chrome/browser/resources/settings/advanced_page/advanced_page.js b/chrome/browser/resources/settings/advanced_page/advanced_page.js
index def015b..18e7c81 100644
--- a/chrome/browser/resources/settings/advanced_page/advanced_page.js
+++ b/chrome/browser/resources/settings/advanced_page/advanced_page.js
@@ -30,11 +30,4 @@
       notify: true,
     },
   },
-
-  /**
-   * @type {string} Selector to get the sections.
-   * TODO(michaelpg): replace duplicate docs with @override once b/24294625
-   * is fixed.
-   */
-  sectionSelector: 'settings-section',
 });
diff --git a/chrome/browser/resources/settings/appearance_page/appearance_page.html b/chrome/browser/resources/settings/appearance_page/appearance_page.html
index 195d3578..0936c41 100644
--- a/chrome/browser/resources/settings/appearance_page/appearance_page.html
+++ b/chrome/browser/resources/settings/appearance_page/appearance_page.html
@@ -4,8 +4,8 @@
 <link rel="import" href="chrome://resources/polymer/v1_0/iron-icon/iron-icon.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/neon-animation/neon-animatable.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/paper-button/paper-button.html">
-<link rel="import" href="chrome://resources/polymer/v1_0/paper-radio-button/paper-radio-button.html">
 <link rel="import" href="/appearance_page/appearance_browser_proxy.html">
+<link rel="import" href="/controls/controlled_radio_button.html">
 <link rel="import" href="/controls/settings_dropdown_menu.html">
 <link rel="import" href="/controls/settings_input.html">
 <link rel="import" href="/controls/settings_radio_group.html">
@@ -72,16 +72,21 @@
           <div class="list-frame"
               hidden="[[!pageVisibility.homeButton]]">
             <settings-radio-group pref="{{prefs.homepage_is_newtabpage}}">
-              <paper-radio-button class="list-item" name="true">
+              <controlled-radio-button class="list-item" name="true"
+                  pref="[[prefs.homepage_is_newtabpage]]">
                 $i18n{homePageNtp}
-              </paper-radio-button>
-              <paper-radio-button class="list-item" name="false">
+              </controlled-radio-button>
+              <controlled-radio-button class="list-item" name="false"
+                  pref="[[prefs.homepage_is_newtabpage]]">
                 $i18n{other}
+                <!-- TODO(dbeam): this can show double indicators when both
+                     homepage and whether to use the NTP as the homepage are
+                     managed. -->
                 <settings-input no-label-float pref="{{prefs.homepage}}"
                     label="$i18n{exampleDotCom}"
                     stop-keyboard-event-propagation>
                 </settings-input>
-              </paper-radio-button>
+              </controlled-radio-button>
             </settings-radio-group>
           </div>
         </template>
diff --git a/chrome/browser/resources/settings/basic_page/basic_page.html b/chrome/browser/resources/settings/basic_page/basic_page.html
index 450c3b6..abb32bf 100644
--- a/chrome/browser/resources/settings/basic_page/basic_page.html
+++ b/chrome/browser/resources/settings/basic_page/basic_page.html
@@ -75,7 +75,6 @@
       <template is="dom-if" if="[[showPage(pageVisibility.defaultBrowser)]]"
           restamp>
         <settings-section page-title="$i18n{defaultBrowser}"
-            expand-container="{{expandContainer}}"
             current-route="[[currentRoute]]" section="defaultBrowser">
           <settings-default-browser-page>
           </settings-default-browser-page>
diff --git a/chrome/browser/resources/settings/basic_page/basic_page.js b/chrome/browser/resources/settings/basic_page/basic_page.js
index 4fa3a0a..8db640c 100644
--- a/chrome/browser/resources/settings/basic_page/basic_page.js
+++ b/chrome/browser/resources/settings/basic_page/basic_page.js
@@ -42,13 +42,6 @@
 
   },
 
-  /**
-   * @type {string} Selector to get the sections.
-   * TODO(michaelpg): replace duplicate docs with @override once b/24294625
-   * is fixed.
-   */
-  sectionSelector: 'settings-section',
-
   onResetDone_: function() {
     this.showResetProfileBanner_ = false;
   },
diff --git a/chrome/browser/resources/settings/controls/compiled_resources2.gyp b/chrome/browser/resources/settings/controls/compiled_resources2.gyp
index 72fe9d2..4552cf1 100644
--- a/chrome/browser/resources/settings/controls/compiled_resources2.gyp
+++ b/chrome/browser/resources/settings/controls/compiled_resources2.gyp
@@ -4,6 +4,15 @@
 {
   'targets': [
     {
+      'target_name': 'controlled_button',
+      'dependencies': [
+        '<(DEPTH)/ui/webui/resources/cr_elements/policy/compiled_resources2.gyp:cr_policy_pref_behavior',
+        '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:assert',
+        'pref_control_behavior',
+      ],
+      'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
+    },
+    {
       'target_name': 'pref_control_behavior',
       'dependencies': [
         '../prefs/compiled_resources2.gyp:prefs_types',
diff --git a/chrome/browser/resources/settings/controls/controlled_button.html b/chrome/browser/resources/settings/controls/controlled_button.html
index 5c02834..9868ce0 100644
--- a/chrome/browser/resources/settings/controls/controlled_button.html
+++ b/chrome/browser/resources/settings/controls/controlled_button.html
@@ -1,3 +1,4 @@
+<link rel="import" href="chrome://resources/html/assert.html">
 <link rel="import" href="chrome://resources/html/polymer.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/paper-button/paper-button.html">
 <link rel="import" href="chrome://resources/cr_elements/policy/cr_policy_pref_behavior.html">
diff --git a/chrome/browser/resources/settings/controls/controlled_button.js b/chrome/browser/resources/settings/controls/controlled_button.js
index a072e37d..36392db 100644
--- a/chrome/browser/resources/settings/controls/controlled_button.js
+++ b/chrome/browser/resources/settings/controls/controlled_button.js
@@ -11,18 +11,17 @@
     /** @private */
     controlled_: {
       type: Boolean,
-      computed: 'computeControlled_(pref)',
+      computed: 'computeControlled_(pref.*)',
       reflectToAttribute: true,
     },
   },
 
   /**
-   * @param {!chrome.settingsPrivate.PrefObject} pref
    * @return {boolean} Whether the button is disabled.
    * @private
    */
-  computeControlled_: function(pref) {
-    return this.isPrefPolicyControlled(pref);
+  computeControlled_: function() {
+    return this.isPrefPolicyControlled(assert(this.pref));
   },
 
   /**
diff --git a/chrome/browser/resources/settings/controls/controlled_radio_button.html b/chrome/browser/resources/settings/controls/controlled_radio_button.html
new file mode 100644
index 0000000..09073ce
--- /dev/null
+++ b/chrome/browser/resources/settings/controls/controlled_radio_button.html
@@ -0,0 +1,43 @@
+<link rel="import" href="chrome://resources/html/polymer.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/paper-radio-button/paper-radio-button.html">
+<link rel="import" href="chrome://resources/cr_elements/policy/cr_policy_pref_behavior.html">
+<link rel="import" href="chrome://resources/cr_elements/policy/cr_policy_pref_indicator.html">
+<link rel="import" href="/controls/pref_control_behavior.html">
+<link rel="import" href="/prefs/pref_util.html">
+<link rel="import" href="/settings_shared_css.html">
+
+<dom-module id="controlled-radio-button">
+  <template>
+    <style include="settings-shared">
+      :host {
+        align-items: center;
+        display: flex;
+      }
+
+      :host([controlled_]) {
+        /* Disable pointer events for this whole element, as outer on-tap gets
+         * triggered when clicking/tapping anywhere in :host. */
+        pointer-events: none;
+      }
+
+      cr-policy-pref-indicator {
+        -webkit-margin-start: var(--checkbox-spacing);
+        /* Enable pointer events for the indicator so :hover works. Disable
+         * clicks/taps via onIndicatorTap_ so outer on-tap doesn't trigger. */
+        pointer-events: all;
+      }
+    </style>
+
+    <paper-radio-button name="{{name}}" disabled="[[controlled_]]"
+        checked="{{checked}}">
+      <content></content>
+    </paper-radio-button>
+
+    <template is="dom-if" if="[[showIndicator_(controlled_, name, pref)]]">
+      <cr-policy-pref-indicator pref="[[pref]]" on-tap="onIndicatorTap_">
+      </cr-policy-pref-indicator>
+    </template>
+
+  </template>
+  <script src="/controls/controlled_radio_button.js"></script>
+</dom-module>
diff --git a/chrome/browser/resources/settings/controls/controlled_radio_button.js b/chrome/browser/resources/settings/controls/controlled_radio_button.js
new file mode 100644
index 0000000..dd758323
--- /dev/null
+++ b/chrome/browser/resources/settings/controls/controlled_radio_button.js
@@ -0,0 +1,54 @@
+// 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.
+
+Polymer({
+  is: 'controlled-radio-button',
+
+  behaviors: [CrPolicyPrefBehavior, PrefControlBehavior],
+
+  properties: {
+    name: {
+      type: String,
+      notify: true,
+    },
+
+    /** @private */
+    controlled_: {
+      type: Boolean,
+      computed: 'computeControlled_(pref)',
+      reflectToAttribute: true,
+    },
+  },
+
+  /**
+   * @param {chrome.settingsPrivate.PrefObject} pref
+   * @return {boolean} Whether the button is disabled.
+   * @private
+   */
+  computeControlled_: function(pref) {
+    var pref = /** @type {!chrome.settingsPrivate.PrefObject} */(this.pref);
+    return this.isPrefPolicyControlled(pref);
+  },
+
+  /**
+   * @param {boolean} controlled
+   * @param {string} name
+   * @param {chrome.settingsPrivate.PrefObject} pref
+   * @return {boolean}
+   * @private
+   */
+  showIndicator_: function(controlled, name, pref) {
+    return controlled && name == Settings.PrefUtil.prefToString(pref);
+  },
+
+  /**
+   * @param {!Event} e
+   * @private
+   */
+  onIndicatorTap_: function(e) {
+    // Disallow <controlled-radio-button on-tap="..."> when controlled.
+    e.preventDefault();
+    e.stopPropagation();
+  },
+});
diff --git a/chrome/browser/resources/settings/controls/settings_radio_group.html b/chrome/browser/resources/settings/controls/settings_radio_group.html
index 665c531..3b1d8772 100644
--- a/chrome/browser/resources/settings/controls/settings_radio_group.html
+++ b/chrome/browser/resources/settings/controls/settings_radio_group.html
@@ -1,5 +1,4 @@
 <link rel="import" href="chrome://resources/html/polymer.html">
-<link rel="import" href="chrome://resources/cr_elements/policy/cr_policy_pref_behavior.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/paper-radio-group/paper-radio-group.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/paper-radio-button/paper-radio-button.html">
 <link rel="import" href="/controls/pref_control_behavior.html">
@@ -10,7 +9,8 @@
   <style include="settings-shared"></style>
   <template>
     <div>[[label]]</div>
-    <paper-radio-group selected="{{selected}}">
+    <paper-radio-group selected="{{selected}}"
+        selectable="paper-radio-button, controlled-radio-button">
       <content></content>
     </paper-radio-group>
   </template>
diff --git a/chrome/browser/resources/settings/controls/settings_radio_group.js b/chrome/browser/resources/settings/controls/settings_radio_group.js
index 389ebcd..f0bedec 100644
--- a/chrome/browser/resources/settings/controls/settings_radio_group.js
+++ b/chrome/browser/resources/settings/controls/settings_radio_group.js
@@ -15,15 +15,9 @@
 Polymer({
   is: 'settings-radio-group',
 
-  behaviors: [CrPolicyPrefBehavior, PrefControlBehavior],
+  behaviors: [PrefControlBehavior],
 
   properties: {
-    disabled_: {
-      observer: 'disabledChanged_',
-      type: Boolean,
-      value: false,
-    },
-
     /**
      * IronSelectableBehavior selected attribute.
      */
@@ -41,19 +35,10 @@
   /** @private */
   prefChanged_: function() {
     var pref = /** @type {!chrome.settingsPrivate.PrefObject} */(this.pref);
-    this.disabled_ = this.isPrefPolicyControlled(pref);
     this.selected = Settings.PrefUtil.prefToString(pref);
   },
 
   /** @private */
-  disabledChanged_: function() {
-    var radioButtons = this.queryAllEffectiveChildren('paper-radio-button');
-    for (var i = 0; i < radioButtons.length; ++i) {
-      radioButtons[i].disabled = this.disabled_;
-    }
-  },
-
-  /** @private */
   selectedChanged_: function(selected) {
     if (!this.pref)
       return;
diff --git a/chrome/browser/resources/settings/icons.html b/chrome/browser/resources/settings/icons.html
index 7279594..18d6350 100644
--- a/chrome/browser/resources/settings/icons.html
+++ b/chrome/browser/resources/settings/icons.html
@@ -102,6 +102,7 @@
       <g id="sync-disabled"><path d="M10 6.35V4.26c-.8.21-1.55.54-2.23.96l1.46 1.46c.25-.12.5-.24.77-.33zm-7.14-.94l2.36 2.36C4.45 8.99 4 10.44 4 12c0 2.21.91 4.2 2.36 5.64L4 20h6v-6l-2.24 2.24C6.68 15.15 6 13.66 6 12c0-1 .25-1.94.68-2.77l8.08 8.08c-.25.13-.5.25-.77.34v2.09c.8-.21 1.55-.54 2.23-.96l2.36 2.36 1.27-1.27L4.14 4.14 2.86 5.41zM20 4h-6v6l2.24-2.24C17.32 8.85 18 10.34 18 12c0 1-.25 1.94-.68 2.77l1.46 1.46C19.55 15.01 20 13.56 20 12c0-2.21-.91-4.2-2.36-5.64L20 4z"></path></g>
       <g id="sync-problem"><path d="M3 12c0 2.21.91 4.2 2.36 5.64L3 20h6v-6l-2.24 2.24C5.68 15.15 5 13.66 5 12c0-2.61 1.67-4.83 4-5.65V4.26C5.55 5.15 3 8.27 3 12zm8 5h2v-2h-2v2zM21 4h-6v6l2.24-2.24C18.32 8.85 19 10.34 19 12c0 2.61-1.67 4.83-4 5.65v2.09c3.45-.89 6-4.01 6-7.74 0-2.21-.91-4.2-2.36-5.64L21 4zm-10 9h2V7h-2v6z"></path></g>
 <if expr="chromeos">
+      <g id="text-format"><path d="M5 17v2h14v-2H5zm4.5-4.2h5l.9 2.2h2.1L12.75 4h-1.5L6.5 15h2.1l.9-2.2zM12 5.98L13.87 11h-3.74L12 5.98z"></path></g>
       <g id="touch-app"><path d="M9 11.24V7.5C9 6.12 10.12 5 11.5 5S14 6.12 14 7.5v3.74c1.21-.81 2-2.18 2-3.74C16 5.01 13.99 3 11.5 3S7 5.01 7 7.5c0 1.56.79 2.93 2 3.74zm9.84 4.63l-4.54-2.26c-.17-.07-.35-.11-.54-.11H13v-6c0-.83-.67-1.5-1.5-1.5S10 6.67 10 7.5v10.74l-3.43-.72c-.08-.01-.15-.03-.24-.03-.31 0-.59.13-.79.33l-.79.8 4.94 4.94c.27.27.65.44 1.06.44h6.79c.75 0 1.33-.55 1.44-1.28l.75-5.27c.01-.07.02-.14.02-.2 0-.62-.38-1.16-.91-1.38z"></path></g>
 </if>
       <g id="usb"><path d="M15 7v4h1v2h-3V5h2l-3-4-3 4h2v8H8v-2.07c.7-.37 1.2-1.08 1.2-1.93 0-1.21-.99-2.2-2.2-2.2-1.21 0-2.2.99-2.2 2.2 0 .85.5 1.56 1.2 1.93V13c0 1.11.89 2 2 2h3v3.05c-.71.37-1.2 1.1-1.2 1.95 0 1.22.99 2.2 2.2 2.2 1.21 0 2.2-.98 2.2-2.2 0-.85-.49-1.58-1.2-1.95V15h3c1.11 0 2-.89 2-2v-2h1V7h-4z"></path></g>
diff --git a/chrome/browser/resources/settings/internet_page/compiled_resources2.gyp b/chrome/browser/resources/settings/internet_page/compiled_resources2.gyp
index 0e312d02..d965d3ae 100644
--- a/chrome/browser/resources/settings/internet_page/compiled_resources2.gyp
+++ b/chrome/browser/resources/settings/internet_page/compiled_resources2.gyp
@@ -86,6 +86,7 @@
     {
       'target_name': 'network_siminfo',
       'dependencies': [
+        '<(DEPTH)/third_party/polymer/v1_0/components-chromium/paper-input/compiled_resources2.gyp:paper-input-extracted',
         '<(DEPTH)/ui/webui/resources/cr_elements/network/compiled_resources2.gyp:cr_onc_types',
         '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:assert',
         '<(INTERFACES_GYP):networking_private_interface',
diff --git a/chrome/browser/resources/settings/internet_page/network_siminfo.js b/chrome/browser/resources/settings/internet_page/network_siminfo.js
index b6977dd..1e69b0f 100644
--- a/chrome/browser/resources/settings/internet_page/network_siminfo.js
+++ b/chrome/browser/resources/settings/internet_page/network_siminfo.js
@@ -137,7 +137,7 @@
     this.networkingPrivate.setCellularSimState(guid, simState, function() {
       if (chrome.runtime.lastError) {
         this.error = ErrorType.INCORRECT_PIN;
-        this.$.enterPin.$.input.select();
+        this.$.enterPin.inputElement.select();
       } else {
         this.error = ErrorType.NONE;
         this.$.enterPinDialog.close();
@@ -182,7 +182,7 @@
     this.networkingPrivate.setCellularSimState(guid, simState, function() {
       if (chrome.runtime.lastError) {
         this.error = ErrorType.INCORRECT_PIN;
-        this.$.changePinOld.$.input.select();
+        this.$.changePinOld.inputElement.select();
       } else {
         this.error = ErrorType.NONE;
         this.$.changePinDialog.close();
@@ -217,7 +217,7 @@
     this.networkingPrivate.unlockCellularSim(guid, pin, '', function() {
       if (chrome.runtime.lastError) {
         this.error = ErrorType.INCORRECT_PIN;
-        this.$.unlockPin.$.input.select();
+        this.$.unlockPin.inputElement.select();
       } else {
         this.error = ErrorType.NONE;
         this.$.unlockPinDialog.close();
@@ -258,7 +258,7 @@
     this.networkingPrivate.unlockCellularSim(guid, pin, puk, function() {
       if (chrome.runtime.lastError) {
         this.error = ErrorType.INCORRECT_PUK;
-        this.$.unlockPuk.$.input.select();
+        this.$.unlockPuk.inputElement.select();
       } else {
         this.error = ErrorType.NONE;
         this.$.unlockPukDialog.close();
diff --git a/chrome/browser/resources/settings/on_startup_page/on_startup_page.html b/chrome/browser/resources/settings/on_startup_page/on_startup_page.html
index f66a6693..841f56b9 100644
--- a/chrome/browser/resources/settings/on_startup_page/on_startup_page.html
+++ b/chrome/browser/resources/settings/on_startup_page/on_startup_page.html
@@ -1,6 +1,6 @@
 <link rel="import" href="chrome://resources/html/polymer.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/iron-flex-layout/classes/iron-flex-layout.html">
-<link rel="import" href="chrome://resources/polymer/v1_0/paper-radio-button/paper-radio-button.html">
+<link rel="import" href="/controls/controlled_radio_button.html">
 <link rel="import" href="/controls/settings_radio_group.html">
 <link rel="import" href="/on_startup_page/startup_urls_page.html">
 <link rel="import" href="/settings_shared_css.html">
@@ -11,15 +11,18 @@
     <div class="settings-box block first">
       <settings-radio-group id="onStartupRadioGroup"
           pref="{{prefs.session.restore_on_startup}}">
-        <paper-radio-button name="[[prefValues_.OPEN_NEW_TAB]]">
+        <controlled-radio-button name="[[prefValues_.OPEN_NEW_TAB]]"
+            pref="[[prefs.session.restore_on_startup]]">
           $i18n{onStartupOpenNewTab}
-        </paper-radio-button>
-        <paper-radio-button name="[[prefValues_.CONTINUE]]">
+        </controlled-radio-button>
+        <controlled-radio-button name="[[prefValues_.CONTINUE]]"
+            pref="[[prefs.session.restore_on_startup]]">
           $i18n{onStartupContinue}
-        </paper-radio-button>
-        <paper-radio-button name="[[prefValues_.OPEN_SPECIFIC]]">
+        </controlled-radio-button>
+        <controlled-radio-button name="[[prefValues_.OPEN_SPECIFIC]]"
+            pref="[[prefs.session.restore_on_startup]]">
           $i18n{onStartupOpenSpecific}
-        </paper-radio-button>
+        </controlled-radio-button>
       </settings-radio-group>
     </div>
     <template is="dom-if"
diff --git a/chrome/browser/resources/settings/on_startup_page/startup_urls_page.html b/chrome/browser/resources/settings/on_startup_page/startup_urls_page.html
index 8dee9a45..1e2ee2ac 100644
--- a/chrome/browser/resources/settings/on_startup_page/startup_urls_page.html
+++ b/chrome/browser/resources/settings/on_startup_page/startup_urls_page.html
@@ -8,10 +8,6 @@
 <dom-module id="settings-startup-urls-page">
   <template>
     <style include="settings-shared">
-      paper-radio-button {
-        display: block;
-      }
-
       .list-button {
         @apply(--settings-actionable);
       }
diff --git a/chrome/browser/resources/settings/passwords_and_forms_page/address_edit_dialog.js b/chrome/browser/resources/settings/passwords_and_forms_page/address_edit_dialog.js
index 7159694..7f790c0 100644
--- a/chrome/browser/resources/settings/passwords_and_forms_page/address_edit_dialog.js
+++ b/chrome/browser/resources/settings/passwords_and_forms_page/address_edit_dialog.js
@@ -88,33 +88,26 @@
    * @private
    */
   updateAddressWrapper_: function() {
-    var self = this;
-
     // Default to the last country used if no country code is provided.
-    var countryCode = self.countryCode_ || self.countries_[0].countryCode;
-    self.countryInfo.getAddressFormat(countryCode).then(function(format) {
-      self.addressWrapper_ = format.components.map(function(component) {
+    var countryCode = this.countryCode_ || this.countries_[0].countryCode;
+    this.countryInfo.getAddressFormat(countryCode).then(function(format) {
+      this.addressWrapper_ = format.components.map(function(component) {
         return component.row.map(function(c) {
-          return new settings.address.AddressComponentUI(self.address, c);
-        });
-      });
+          return new settings.address.AddressComponentUI(this.address, c);
+        }.bind(this));
+      }.bind(this));
 
       // Flush dom before resize and savability updates.
       Polymer.dom.flush();
 
-/**
- * TODO(hcarmona): Fix closure compiler to better understand |SettingsDialog|.
- * @suppress {missingProperties}
- */
-(function() {
-      self.updateCanSave_();
+      this.updateCanSave_();
 
-      self.fire('on-update-address-wrapper');  // For easier testing.
+      this.fire('on-update-address-wrapper');  // For easier testing.
 
-      if (!self.$.dialog.open)
-        self.$.dialog.showModal();
-})();
-    });
+      var dialog = /** @type {HTMLDialogElement} */(this.$.dialog);
+      if (!dialog.open)
+        dialog.showModal();
+    }.bind(this));
   },
 
   updateCanSave_: function() {
diff --git a/chrome/browser/resources/settings/printing_page/cloud_printers.js b/chrome/browser/resources/settings/printing_page/cloud_printers.js
index 1f96323b..3537e5d 100644
--- a/chrome/browser/resources/settings/printing_page/cloud_printers.js
+++ b/chrome/browser/resources/settings/printing_page/cloud_printers.js
@@ -2,6 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+/**
+ * @fileoverview 'settings-cloud-printers' is a component for showing Google
+ * Cloud Printer settings subpage (chrome://md-settings/cloudPrinters).
+ */
+// TODO(xdai): Rename it to 'settings-cloud-printers-page'.
 Polymer({
   is: 'settings-cloud-printers',
 
diff --git a/chrome/browser/resources/settings/printing_page/compiled_resources2.gyp b/chrome/browser/resources/settings/printing_page/compiled_resources2.gyp
index 331656fb..2058a33 100644
--- a/chrome/browser/resources/settings/printing_page/compiled_resources2.gyp
+++ b/chrome/browser/resources/settings/printing_page/compiled_resources2.gyp
@@ -4,21 +4,53 @@
 {
   'targets': [
     {
-      'target_name': 'printing_page',
+      'target_name': 'cloud_printers',
       'dependencies': [
-        '../compiled_resources2.gyp:route',
+        '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:load_time_data',
+      ],
+      'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
+    },
+    {
+      'target_name': 'cups_add_printer_dialog',
+      'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
+    },
+    {
+      'target_name': 'cups_printer_details_page',
+      'dependencies': [
         '../settings_page/compiled_resources2.gyp:settings_animated_pages',
+        'cups_printers_browser_proxy',
       ],
       'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
     },
     {
       'target_name': 'cups_printers',
+      'dependencies': [
+        'cups_printers_browser_proxy',
+      ],
       'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
     },
     {
-      'target_name': 'cloud_printers',
+      'target_name': 'cups_printers_browser_proxy',
       'dependencies': [
-        '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:load_time_data',
+        '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:cr',
+      ],
+      'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
+    },
+    {
+      'target_name': 'cups_printers_list',
+      'dependencies': [
+        '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:cr',
+        '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:icon',
+        'cups_printers_browser_proxy',
+      ],
+      'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
+    },
+    {
+      'target_name': 'printing_page',
+      'dependencies': [
+        '../compiled_resources2.gyp:route',
+        '../settings_page/compiled_resources2.gyp:settings_animated_pages',
+        'cups_printer_details_page',
       ],
       'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
     },
diff --git a/chrome/browser/resources/settings/printing_page/cups_add_printer_dialog.html b/chrome/browser/resources/settings/printing_page/cups_add_printer_dialog.html
new file mode 100644
index 0000000..a10117cb
--- /dev/null
+++ b/chrome/browser/resources/settings/printing_page/cups_add_printer_dialog.html
@@ -0,0 +1,39 @@
+<link rel="import" href="chrome://resources/cr_elements/cr_dialog/cr_dialog.html">
+<link rel="import" href="chrome://resources/html/polymer.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/paper-button/paper-button.html">
+<link rel="import" href="/settings_shared_css.html">
+
+<dom-module id="settings-cups-add-printer-dialog">
+  <template>
+    <style include="settings-shared"></style>
+    <style>      
+      #dialog .body {
+        height: 350px;
+      }
+      
+      #dialog .button-container {
+        border-top: 1px solid rgba(0, 0, 0, 0.14);
+        font-size: 15px;
+        font-weight: bold;
+        margin-top: 0;
+        padding-top: 10px;
+      }
+    </style>
+    <dialog is="cr-dialog" id="dialog">
+      <div class="title">$i18n{addPrinterTitle}</div>
+      <div class="body">
+        <!--TODO(xdai): Add printer settings go here. -->
+        (coming soon) Add printer settings go here.
+      </div>
+      <div class="button-container">
+        <paper-button on-tap="onCancelTap_">
+          $i18n{cancelButtonText}
+        </paper-button>
+        <paper-button disabled>
+          $i18n{addPrinterButtonText}
+        </paper-button>
+      </div>
+    </dialog>
+  </template>
+  <script src="cups_add_printer_dialog.js"></script>
+</dom-module>
diff --git a/chrome/browser/resources/settings/printing_page/cups_add_printer_dialog.js b/chrome/browser/resources/settings/printing_page/cups_add_printer_dialog.js
new file mode 100644
index 0000000..24e8f78
--- /dev/null
+++ b/chrome/browser/resources/settings/printing_page/cups_add_printer_dialog.js
@@ -0,0 +1,21 @@
+// 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.
+
+/**
+ * @fileoverview 'settings-cups-add-printer-dialog' is the dialog for setting up
+ * a new CUPS printer.
+ */
+Polymer({
+  is: 'settings-cups-add-printer-dialog',
+
+  /** Opens the Add printer dialog. */
+  open: function() {
+    this.$.dialog.showModal();
+  },
+
+  /** @private */
+  onCancelTap_: function() {
+    this.$.dialog.close();
+  },
+});
diff --git a/chrome/browser/resources/settings/printing_page/cups_printer_details_page.html b/chrome/browser/resources/settings/printing_page/cups_printer_details_page.html
new file mode 100644
index 0000000..8745ac1b
--- /dev/null
+++ b/chrome/browser/resources/settings/printing_page/cups_printer_details_page.html
@@ -0,0 +1,35 @@
+<link rel="import" href="chrome://resources/html/polymer.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/paper-input/paper-input.html">
+<link rel="import" href="/settings_shared_css.html">
+
+<dom-module id="settings-cups-printer-details-page">
+  <template>
+    <style include="settings-shared"></style>
+    <style>
+      paper-input {
+        width: 20em;
+        --paper-input-container-input: {
+          font-size: inherit;
+          color: inherit;
+        };
+      }
+    </style>
+    <div class="settings-box first two-line">
+      <div class="start">
+        <div>$i18n{printerName}</div>
+        <div class="secondary">
+          <paper-input no-label-float value="{{printer.printerName}}"
+              on-blur="onValueChanged_">
+          </paper-input>
+        </div>
+      </div>
+    </div>
+    <div class="settings-box two-line">
+      <div class="start">
+        <div>$i18n{printerModel}</div>
+        <div class="secondary">[[printer.printerModel]]</div>
+      </div>
+    </div>
+  </template>
+  <script src="cups_printer_details_page.js"></script>
+</dom-module>
diff --git a/chrome/browser/resources/settings/printing_page/cups_printer_details_page.js b/chrome/browser/resources/settings/printing_page/cups_printer_details_page.js
new file mode 100644
index 0000000..61cefab
--- /dev/null
+++ b/chrome/browser/resources/settings/printing_page/cups_printer_details_page.js
@@ -0,0 +1,36 @@
+// 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.
+
+/**
+ * @fileoverview 'settings-cups-printer-details-page' is the subpage for
+ * viewing the details of a CUPS printer.
+ */
+Polymer({
+  is: 'settings-cups-printer-details-page',
+
+  properties: {
+    /** @type {!CupsPrinterInfo} */
+    printer: {
+      type: Object,
+      notify: true,
+    },
+  },
+
+  /** @private {settings.CupsPrintersBrowserProxy} */
+  browserProxy_: null,
+
+  /** @override */
+  created: function() {
+    this.browserProxy_ = settings.CupsPrintersBrowserProxyImpl.getInstance();
+  },
+
+  /**
+   * Event triggered when the input value changes.
+   * @private
+   */
+  onValueChanged_: function() {
+    this.browserProxy_.updateCupsPrinter(this.printer.printerId,
+                                         this.printer.printerName);
+  },
+});
diff --git a/chrome/browser/resources/settings/printing_page/cups_printers.html b/chrome/browser/resources/settings/printing_page/cups_printers.html
index 053805eb..abf54e72 100644
--- a/chrome/browser/resources/settings/printing_page/cups_printers.html
+++ b/chrome/browser/resources/settings/printing_page/cups_printers.html
@@ -1,13 +1,36 @@
 <link rel="import" href="chrome://resources/html/polymer.html">
+<link rel="import" href="/printing_page/cups_add_printer_dialog.html">
+<link rel="import" href="/printing_page/cups_printers_list.html">
 <link rel="import" href="/settings_shared_css.html">
 
 <dom-module id="settings-cups-printers">
   <template>
     <style include="settings-shared"></style>
-    <!--TODO(xdai): Implement the cups printing subpage. -->
+    <style>
+      a[is='action-link'] {
+        display: inline-block;
+        text-decoration: none;
+      }
+
+      a[is='action-link']:hover {
+        color: blue;
+        text-decoration: underline;
+      }
+    </style>
+
+    <!-- TODO(xdai): Implement the search field as seen in the mock. -->
+
     <div class="settings-box first">
-      CUPS printers settings go here.
+      <a is="action-link" on-tap="onAddPrinterTap_" actionable>
+        $i18n{addCupsPrinter}
+      </a>
     </div>
+
+    <settings-cups-add-printer-dialog id="addPrinterDialog">
+    </settings-cups-add-printer-dialog>
+
+    <settings-cups-printers-list printers="{{printers}}">
+    </settings-cups-printers-list>
   </template>
   <script src="cups_printers.js"></script>
 </dom-module>
diff --git a/chrome/browser/resources/settings/printing_page/cups_printers.js b/chrome/browser/resources/settings/printing_page/cups_printers.js
index 7472b1f0..12b11d7 100644
--- a/chrome/browser/resources/settings/printing_page/cups_printers.js
+++ b/chrome/browser/resources/settings/printing_page/cups_printers.js
@@ -2,6 +2,40 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+/**
+ * @fileoverview 'settings-cups-printers' is a component for showing CUPS
+ * Printer settings subpage (chrome://md-settings/cupsPrinters). It is used to
+ * set up legacy & non-CloudPrint printers on ChromeOS by leveraging CUPS (the
+ * unix printing system) and the many open source drivers built for CUPS.
+ */
+// TODO(xdai): Rename it to 'settings-cups-printers-page'.
 Polymer({
   is: 'settings-cups-printers',
+
+  properties: {
+    /** @type {!Array<!CupsPrinterInfo>} */
+    printers: {
+      type: Array,
+      notify: true,
+    },
+  },
+
+  /** @override */
+  ready: function() {
+    settings.CupsPrintersBrowserProxyImpl.getInstance().
+        getCupsPrintersList().then(this.printersChanged_.bind(this));
+  },
+
+  /**
+   * @param {!CupsPrintersList} cupsPrintersList
+   * @private
+   */
+  printersChanged_: function(cupsPrintersList) {
+    this.printers = cupsPrintersList.printerList;
+  },
+
+  /** @private */
+  onAddPrinterTap_: function() {
+    this.$.addPrinterDialog.open();
+  },
 });
diff --git a/chrome/browser/resources/settings/printing_page/cups_printers_browser_proxy.html b/chrome/browser/resources/settings/printing_page/cups_printers_browser_proxy.html
new file mode 100644
index 0000000..1423729
--- /dev/null
+++ b/chrome/browser/resources/settings/printing_page/cups_printers_browser_proxy.html
@@ -0,0 +1,2 @@
+<link rel="import" href="chrome://resources/html/cr.html">
+<script src="/printing_page/cups_printers_browser_proxy.js"></script>
diff --git a/chrome/browser/resources/settings/printing_page/cups_printers_browser_proxy.js b/chrome/browser/resources/settings/printing_page/cups_printers_browser_proxy.js
new file mode 100644
index 0000000..cf80912
--- /dev/null
+++ b/chrome/browser/resources/settings/printing_page/cups_printers_browser_proxy.js
@@ -0,0 +1,83 @@
+// 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.
+
+/**
+ * @fileoverview A helper object used from the "CUPS printing" section to
+ * interact with the browser.
+ */
+
+/**
+ * @typedef {{
+ *   printerId: string,
+ *   printerName: string,
+ *   printerDescription: string,
+ *   printerManufacturer: string,
+ *   printerModel: string,
+ *   printerStatus: string,
+ *   printerAddress: string,
+ *   printerProtocol: string,
+ * }}
+ */
+var CupsPrinterInfo;
+
+/**
+ * @typedef {{
+ *   printerList: !Array<!CupsPrinterInfo>,
+ * }}
+ */
+var CupsPrintersList;
+
+cr.define('settings', function() {
+  /** @interface */
+  function CupsPrintersBrowserProxy() {}
+
+  CupsPrintersBrowserProxy.prototype = {
+
+    /**
+     * @return {!Promise<!CupsPrintersList>}
+     */
+    getCupsPrintersList: function() {},
+
+    /**
+     * @param {string} printerId
+     * @param {string} printerName
+     */
+    updateCupsPrinter: function(printerId, printerName) {},
+
+    /**
+     * @param {string} printerId
+     */
+    removeCupsPrinter: function(printerId) {},
+
+  };
+
+  /**
+   * @constructor
+   * @implements {settings.CupsPrintersBrowserProxy}
+   */
+  function CupsPrintersBrowserProxyImpl() {}
+  cr.addSingletonGetter(CupsPrintersBrowserProxyImpl);
+
+  CupsPrintersBrowserProxyImpl.prototype = {
+    /** override */
+    getCupsPrintersList: function() {
+      return cr.sendWithPromise('getCupsPrintersList');
+    },
+
+    /** override */
+    updateCupsPrinter: function(printerId, printerName) {
+      chrome.send('updateCupsPrinter', [printerId, printerName]);
+    },
+
+    /** override */
+    removeCupsPrinter: function(printerId) {
+      chrome.send('removeCupsPrinter', [printerId]);
+    },
+  };
+
+  return {
+    CupsPrintersBrowserProxy: CupsPrintersBrowserProxy,
+    CupsPrintersBrowserProxyImpl: CupsPrintersBrowserProxyImpl,
+  };
+});
diff --git a/chrome/browser/resources/settings/printing_page/cups_printers_list.html b/chrome/browser/resources/settings/printing_page/cups_printers_list.html
new file mode 100644
index 0000000..e8aec3d
--- /dev/null
+++ b/chrome/browser/resources/settings/printing_page/cups_printers_list.html
@@ -0,0 +1,57 @@
+<link rel="import" href="chrome://resources/cr_elements/icons.html">
+<link rel="import" href="chrome://resources/html/polymer.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/iron-dropdown/iron-dropdown.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/paper-icon-button/paper-icon-button.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/paper-item/paper-item.html">
+<link rel="import" href="/printing_page/cups_printers_browser_proxy.html">
+<link rel="import" href="/settings_shared_css.html">
+
+<dom-module id="settings-cups-printers-list">
+  <template>
+    <style include="settings-shared"></style>
+    <style>
+      #container {
+        border-top: 1px solid lightgray;
+        display: flex;
+        padding: 2px 20px;
+      }
+
+      .name-column {
+        flex: 1;
+        margin: 2px;
+      }
+
+      .list-item {
+        min-height: 20px;
+      }
+      
+      iron-dropdown {
+        width: 120px;
+      }
+    </style>
+
+    <template is="dom-repeat" items="{{printers}}">
+      <div id="container" class="list-item">
+        <div class="name-column">
+          <span class="name" id="printer-name">[[item.printerName]]</span>
+          <!--TODO(xdai): Add icon for enterprise CUPS printer. -->
+        </div>
+        <paper-icon-button icon="cr:more-vert" toggles
+            active="{{item.menuOpened}}">
+        </paper-icon-button>
+        <iron-dropdown opened="{{item.menuOpened}}" horizontal-align="right"
+            vertical-align="top" horizontal-offset="15" vertical-offset="5">
+          <div class="dropdown-content">
+            <paper-item on-tap="onDetailsTap_">
+                $i18n{cupsPrinterDetails}
+            </paper-item>
+            <paper-item on-tap="onRemoveTap_">
+                $i18n{removePrinter}
+            </paper-item>
+          <div>
+        </iron-dropdown>
+      </div>
+    </template>
+  </template>
+  <script src="cups_printers_list.js"></script>
+</dom-module>
diff --git a/chrome/browser/resources/settings/printing_page/cups_printers_list.js b/chrome/browser/resources/settings/printing_page/cups_printers_list.js
new file mode 100644
index 0000000..ffdc535
--- /dev/null
+++ b/chrome/browser/resources/settings/printing_page/cups_printers_list.js
@@ -0,0 +1,55 @@
+// 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.
+
+/**
+ * @fileoverview 'settings-cups-printers-list' is a component for a list of
+ * CUPS printers.
+ */
+Polymer({
+  is: 'settings-cups-printers-list',
+
+  properties: {
+    /** @type {!Array<!CupsPrinterInfo>} */
+    printers: {
+      type: Array,
+      notify: true,
+    },
+  },
+
+  /** @private {settings.CupsPrintersBrowserProxy} */
+  browserProxy_: null,
+
+  /** @override */
+  created: function() {
+    this.browserProxy_ = settings.CupsPrintersBrowserProxyImpl.getInstance();
+  },
+
+  /**
+   * @param {{model:Object}} event
+   * @private
+   */
+  onDetailsTap_: function(event) {
+    this.closeDropdownMenu_();
+
+    // Event is caught by 'settings-printing-page'.
+    this.fire('show-cups-printer-details', event.model.item);
+  },
+
+  /**
+   * @param {{model:Object}} event
+   * @private
+   */
+  onRemoveTap_: function(event) {
+    this.closeDropdownMenu_();
+
+    var index = this.printers.indexOf(event.model.item);
+    this.splice('printers', index, 1);
+    this.browserProxy_.removeCupsPrinter(event.model.item.printerId);
+  },
+
+  /** @private */
+  closeDropdownMenu_: function() {
+    this.$$('iron-dropdown').close();
+  },
+});
diff --git a/chrome/browser/resources/settings/printing_page/printing_page.html b/chrome/browser/resources/settings/printing_page/printing_page.html
index bd854609..d905e71 100644
--- a/chrome/browser/resources/settings/printing_page/printing_page.html
+++ b/chrome/browser/resources/settings/printing_page/printing_page.html
@@ -3,19 +3,23 @@
 <link rel="import" href="chrome://resources/polymer/v1_0/neon-animation/neon-animatable.html">
 <link rel="import" href="/icons.html">
 <link rel="import" href="/printing_page/cloud_printers.html">
-<if expr="chromeos">
-<link rel="import" href="/printing_page/cups_printers.html">
-</if>
 <link rel="import" href="/route.html">
 <link rel="import" href="/settings_page/settings_animated_pages.html">
 <link rel="import" href="/settings_page/settings_subpage.html">
 <link rel="import" href="/settings_shared_css.html">
+<if expr="chromeos">
+<link rel="import" href="/printing_page/cups_printer_details_page.html">
+<link rel="import" href="/printing_page/cups_printers.html">
+</if>
 
 <dom-module id="settings-printing-page">
   <template>
     <style include="settings-shared"></style>
     <settings-animated-pages id="pages" current-route="{{currentRoute}}"
         section="printing">
+      <array-selector id="arraySelector" items="{{cupsPrinters}}"
+          selected="{{detailPrinter_}}">
+      </array-selector>
       <neon-animatable id="main">
 <if expr="chromeos">
         <div id="cupsPrinters" class="settings-box first"
@@ -33,7 +37,14 @@
 <if expr="chromeos">
       <template is="dom-if" name="cups-printers">
         <settings-subpage page-title="$i18n{cupsPrintersTitle}">
-          <settings-cups-printers></settings-cups-printers>
+          <settings-cups-printers printers="{{cupsPrinters}}">
+          </settings-cups-printers>
+        </settings-subpage>
+      </template>
+      <template is="dom-if" name="cups-printer-details-page" restamp>
+        <settings-subpage page-title="$i18n{printerDetailsTitle}">
+          <settings-cups-printer-details-page printer="{{detailPrinter_}}">
+          </settings-cups-printer-details-page>
         </settings-subpage>
       </template>
 </if>
diff --git a/chrome/browser/resources/settings/printing_page/printing_page.js b/chrome/browser/resources/settings/printing_page/printing_page.js
index d6ba00a..4b4598e 100644
--- a/chrome/browser/resources/settings/printing_page/printing_page.js
+++ b/chrome/browser/resources/settings/printing_page/printing_page.js
@@ -17,6 +17,16 @@
       type: Object,
       notify: true,
     },
+
+    /** @type {!Array<!CupsPrinterInfo>} */
+    cupsPrinters: {
+      type: Array,
+      notify: true,
+    },
+  },
+
+  listeners: {
+    'show-cups-printer-details': 'onShowCupsPrinterDetailsPage_',
   },
 
 <if expr="chromeos">
@@ -24,6 +34,12 @@
   onTapCupsPrinters_: function() {
     settings.navigateTo(settings.Route.CUPS_PRINTERS);
   },
+
+  /** @private */
+  onShowCupsPrinterDetailsPage_: function(event) {
+    settings.navigateTo(settings.Route.CUPS_PRINTER_DETAIL);
+    this.$.arraySelector.select(event.detail);
+  },
 </if>
 
   /** @private */
diff --git a/chrome/browser/resources/settings/privacy_page/privacy_page.html b/chrome/browser/resources/settings/privacy_page/privacy_page.html
index 396235f..c07326f 100644
--- a/chrome/browser/resources/settings/privacy_page/privacy_page.html
+++ b/chrome/browser/resources/settings/privacy_page/privacy_page.html
@@ -266,7 +266,7 @@
 
       <template is="dom-if" name="site-details">
         <settings-subpage
-            page-title="$i18n{siteSettingsSiteDetailsPageTitle}">
+            page-title="[[selectedSite.originForDisplay]]">
           <site-details site="[[selectedSite]]"></site-details>
         </settings-subpage>
       </template>
diff --git a/chrome/browser/resources/settings/route.js b/chrome/browser/resources/settings/route.js
index 806176c4..728caf4 100644
--- a/chrome/browser/resources/settings/route.js
+++ b/chrome/browser/resources/settings/route.js
@@ -243,9 +243,14 @@
   r.CLOUD_PRINTERS = r.PRINTING.createChild('/cloudPrinters', 'cloud-printers');
 <if expr="chromeos">
   r.CUPS_PRINTERS = r.PRINTING.createChild('/cupsPrinters', 'cups-printers');
+  r.CUPS_PRINTER_DETAIL = r.CUPS_PRINTERS.createChild(
+      '/cupsPrinterDetails', 'cups-printer-details-page');
 </if>
 
   r.ACCESSIBILITY = r.ADVANCED.createSection('/accessibility', 'a11y');
+  r.MANAGE_ACCESSIBILITY = r.ACCESSIBILITY.createChild(
+      '/manageAccessibility', 'manage-a11y');
+
   r.SYSTEM = r.ADVANCED.createSection('/system', 'system');
   r.RESET = r.ADVANCED.createSection('/reset', 'reset');
 
diff --git a/chrome/browser/resources/settings/search_settings.js b/chrome/browser/resources/settings/search_settings.js
index f001427..4d195ce 100644
--- a/chrome/browser/resources/settings/search_settings.js
+++ b/chrome/browser/resources/settings/search_settings.js
@@ -100,7 +100,7 @@
    * ensures that <settings-section> instances become visible if any matches
    * occurred under their subtree.
    *
-   * @param {!SearchRequest} request
+   * @param {!settings.SearchRequest} request
    * @param {!Node} root The root of the sub-tree to be searched
    * @private
    */
@@ -167,11 +167,11 @@
   /**
    * @constructor
    *
-   * @param {!SearchRequest} request
+   * @param {!settings.SearchRequest} request
    * @param {!Node} node
    */
   function Task(request, node) {
-    /** @protected {!SearchRequest} */
+    /** @protected {!settings.SearchRequest} */
     this.request = request;
 
     /** @protected {!Node} */
@@ -193,7 +193,7 @@
    * @constructor
    * @extends {Task}
    *
-   * @param {!SearchRequest} request
+   * @param {!settings.SearchRequest} request
    * @param {!Node} node
    */
   function RenderTask(request, node) {
@@ -227,7 +227,7 @@
    * @constructor
    * @extends {Task}
    *
-   * @param {!SearchRequest} request
+   * @param {!settings.SearchRequest} request
    * @param {!Node} node
    */
   function SearchAndHighlightTask(request, node) {
@@ -247,7 +247,7 @@
    * @constructor
    * @extends {Task}
    *
-   * @param {!SearchRequest} request
+   * @param {!settings.SearchRequest} request
    * @param {!Node} page
    */
   function TopLevelSearchTask(request, page) {
@@ -454,11 +454,25 @@
     },
   };
 
+  /** @interface */
+  var SearchManager = function() {};
+
+  SearchManager.prototype = {
+    /**
+     * @param {string} text The text to search for.
+     * @param {!Node} page
+     * @return {!Promise<!settings.SearchRequest>} A signal indicating that
+     *     searching finished.
+     */
+    search: function(text, page) {}
+  };
+
   /**
    * @constructor
+   * @implements {SearchManager}
    */
-  var SearchManager = function() {
-    /** @private {?SearchRequest} */
+  var SearchManagerImpl = function() {
+    /** @private {?settings.SearchRequest} */
     this.activeRequest_ = null;
 
     /** @private {!TaskQueue} */
@@ -469,20 +483,15 @@
       this.activeRequest_ = null;
     }.bind(this));
   };
-  cr.addSingletonGetter(SearchManager);
+  cr.addSingletonGetter(SearchManagerImpl);
 
-  SearchManager.prototype = {
-    /**
-     * @param {string} text The text to search for.
-     * @param {!Node} page
-     * @return {!Promise<!SearchRequest>} A signal indicating that searching
-     *     finished.
-     */
+  SearchManagerImpl.prototype = {
+    /** @override */
     search: function(text, page) {
       // Creating a new request only if the |text| changed.
       if (!this.activeRequest_ || !this.activeRequest_.isSame(text)) {
         // Resolving previous search request without marking it as
-        // 'finisthed', if any, and droping all pending tasks.
+        // 'finished', if any, and dropping all pending tasks.
         this.queue_.reset();
         if (this.activeRequest_)
           this.activeRequest_.resolver.resolve(this.activeRequest_);
@@ -499,10 +508,20 @@
 
   /** @return {!SearchManager} */
   function getSearchManager() {
-    return SearchManager.getInstance();
+    return SearchManagerImpl.getInstance();
+  }
+
+  /**
+   * Sets the SearchManager singleton instance, useful for testing.
+   * @param {!SearchManager} searchManager
+   */
+  function setSearchManagerForTesting(searchManager) {
+    SearchManagerImpl.instance_ = searchManager;
   }
 
   return {
     getSearchManager: getSearchManager,
+    setSearchManagerForTesting: setSearchManagerForTesting,
+    SearchRequest: SearchRequest,
   };
 });
diff --git a/chrome/browser/resources/settings/settings_main/settings_main.html b/chrome/browser/resources/settings/settings_main/settings_main.html
index e18bfb2..5b4e489 100644
--- a/chrome/browser/resources/settings/settings_main/settings_main.html
+++ b/chrome/browser/resources/settings/settings_main/settings_main.html
@@ -1,5 +1,6 @@
 <link rel="import" href="chrome://resources/cr_elements/icons.html">
 <link rel="import" href="chrome://resources/html/polymer.html">
+<link rel="import" href="chrome://resources/html/promise_resolver.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/iron-icon/iron-icon.html">
 <link rel="import" href="/about_page/about_page.html">
 <link rel="import" href="/advanced_page/advanced_page.html">
@@ -39,20 +40,20 @@
         -webkit-margin-start: 16px;
       }
 
-      #no-search-results {
+      #noSearchResults {
         align-items: center;
         display: flex;
         flex-direction: column;
         margin-top: 80px;
       }
 
-      #no-search-results div:first-child {
+      #noSearchResults div:first-child {
         font-size: 120%;
         margin-bottom: 10px;
       }
     </style>
     <content select="paper-icon-button"></content>
-    <div id="no-search-results" hidden$="[[!showNoResultsFound_]]">
+    <div id="noSearchResults" hidden$="[[!showNoResultsFound_]]">
       <div>$i18n{searchNoResults}</div>
       <div>$i18nRaw{searchNoResultsHelp}</div>
     </div>
diff --git a/chrome/browser/resources/settings/settings_main/settings_main.js b/chrome/browser/resources/settings/settings_main/settings_main.js
index c840fbe..30eb7448 100644
--- a/chrome/browser/resources/settings/settings_main/settings_main.js
+++ b/chrome/browser/resources/settings/settings_main/settings_main.js
@@ -206,6 +206,7 @@
 
   /**
    * @param {string} query
+   * @return {!Promise} A promise indicating that searching finished.
    */
   searchContents: function(query) {
     this.ensureInDefaultSearchPage_();
@@ -214,26 +215,30 @@
     // Trigger rendering of the basic and advanced pages and search once ready.
     this.showPages_ = {about: false, basic: true, advanced: true};
 
-    setTimeout(function() {
-      settings.getSearchManager().search(
-          query, assert(this.$$('settings-basic-page')));
-    }.bind(this), 0);
-    setTimeout(function() {
-      settings.getSearchManager().search(
-          query, assert(this.$$('settings-advanced-page'))).then(
-          function(request) {
-            if (!request.finished) {
-              // Nothing to do here. A previous search request was canceled
-              // because a new search request was issued before the first one
-              // completed.
-              return;
-            }
+    return new Promise(function(resolve, reject) {
+      setTimeout(function() {
+        var whenSearchDone = settings.getSearchManager().search(
+            query, assert(this.$$('settings-basic-page')));
+        assert(
+            whenSearchDone ===
+                settings.getSearchManager().search(
+                    query, assert(this.$$('settings-advanced-page'))));
 
-            this.toolbarSpinnerActive = false;
-            this.showNoResultsFound_ =
-                !request.isSame('') && !request.didFindMatches();
-          }.bind(this));
-    }.bind(this), 0);
+        whenSearchDone.then(function(request) {
+          resolve();
+          if (!request.finished) {
+            // Nothing to do here. A previous search request was canceled
+            // because a new search request was issued before the first one
+            // completed.
+            return;
+          }
+
+          this.toolbarSpinnerActive = false;
+          this.showNoResultsFound_ =
+              !request.isSame('') && !request.didFindMatches();
+        }.bind(this));
+      }.bind(this), 0);
+    }.bind(this));
   },
 
   /**
diff --git a/chrome/browser/resources/settings/settings_page/main_page_behavior.js b/chrome/browser/resources/settings/settings_page/main_page_behavior.js
index c6844a9..532418a 100644
--- a/chrome/browser/resources/settings/settings_page/main_page_behavior.js
+++ b/chrome/browser/resources/settings/settings_page/main_page_behavior.js
@@ -30,18 +30,15 @@
  * @polymerBehavior Polymer.MainPageBehavior
  */
 var MainPageBehaviorImpl = {
-  /**
-   * @type {string} Selector to get the sections. Derived elements
-   *     must override.
-   */
-  sectionSelector: '',
-
   /** @type {?Element} The scrolling container. */
   scroller: null,
 
   /** @override */
   attached: function() {
-    this.scroller = this.domHost && this.domHost.parentNode.$.mainContainer;
+    if (this.domHost && this.domHost.parentNode.tagName == 'PAPER-HEADER-PANEL')
+      this.scroller = this.domHost.parentNode.$.mainContainer;
+    else
+      this.scroller = document.body; // Used in unit tests.
   },
 
   /**
@@ -52,7 +49,7 @@
    */
   toggleOtherSectionsHidden_: function(sectionName, hidden) {
     var sections = Polymer.dom(this.root).querySelectorAll(
-        this.sectionSelector);
+        'settings-section');
     for (var section of sections)
       section.hidden = hidden && (section.section != sectionName);
   },
diff --git a/chrome/browser/resources/settings/settings_resources.grd b/chrome/browser/resources/settings/settings_resources.grd
index b7a50fd..32734a3 100644
--- a/chrome/browser/resources/settings/settings_resources.grd
+++ b/chrome/browser/resources/settings/settings_resources.grd
@@ -21,6 +21,14 @@
                  type="chrome_html"
                  flattenhtml="true"
                  allowexternalscript="true" />
+      <if expr="chromeos">
+        <structure name="IDR_SETTINGS_MANAGE_A11Y_PAGE_JS"
+                   file="a11y_page/manage_a11y_page.js"
+                   type="chrome_html" />
+        <structure name="IDR_SETTINGS_MANAGE_A11Y_PAGE_HTML"
+                   file="a11y_page/manage_a11y_page.html"
+                   type="chrome_html" />
+      </if>
       <structure name="IDR_SETTINGS_ABOUT_PAGE_BROWSER_PROXY_HTML"
                  file="about_page/about_page_browser_proxy.html"
                  type="chrome_html" />
@@ -329,6 +337,12 @@
       <structure name="IDR_SETTINGS_CONTROLS_CONTROLLED_BUTTON_HTML"
                  file="controls/controlled_button.html"
                  type="chrome_html" />
+      <structure name="IDR_SETTINGS_CONTROLS_CONTROLLED_RADIO_BUTTON_JS"
+                 file="controls/controlled_radio_button.js"
+                 type="chrome_html" />
+      <structure name="IDR_SETTINGS_CONTROLS_CONTROLLED_RADIO_BUTTON_HTML"
+                 file="controls/controlled_radio_button.html"
+                 type="chrome_html" />
       <structure name="IDR_SETTINGS_CONTROLS_CHECKBOX_HTML"
                  file="controls/settings_checkbox.html"
                  type="chrome_html" />
@@ -664,6 +678,30 @@
         <structure name="IDR_SETTINGS_CUPS_PRINTING_PAGE_JS"
                    file="printing_page/cups_printers.js"
                    type="chrome_html" />
+        <structure name="IDR_SETTINGS_CUPS_PRINTERS_BROWSER_PROXY_HTML"
+                   file="printing_page/cups_printers_browser_proxy.html"
+                   type="chrome_html" />
+        <structure name="IDR_SETTINGS_CUPS_PRINTERS_BROWSER_PROXY_JS"
+                   file="printing_page/cups_printers_browser_proxy.js"
+                   type="chrome_html" />
+        <structure name="IDR_SETTINGS_CUPS_PRINTERS_LIST_HTML"
+                   file="printing_page/cups_printers_list.html"
+                   type="chrome_html" />
+        <structure name="IDR_SETTINGS_CUPS_PRINTERS_LIST_JS"
+                   file="printing_page/cups_printers_list.js"
+                   type="chrome_html" />
+        <structure name="IDR_SETTINGS_CUPS_PRINTER_DETAILS_HTML"
+                   file="printing_page/cups_printer_details_page.html"
+                   type="chrome_html" />
+        <structure name="IDR_SETTINGS_CUPS_PRINTER_DETAILS_JS"
+                   file="printing_page/cups_printer_details_page.js"
+                   type="chrome_html" />
+        <structure name="IDR_SETTINGS_CUPS_ADD_PRINTER_DIALOG_HTML"
+                   file="printing_page/cups_add_printer_dialog.html"
+                   type="chrome_html" />
+        <structure name="IDR_SETTINGS_CUPS_ADD_PRINTER_DIALOG_JS"
+                   file="printing_page/cups_add_printer_dialog.js"
+                   type="chrome_html" />
       </if>
       <structure name="IDR_SETTINGS_CLOUD_PRINTING_PAGE_HTML"
                  file="printing_page/cloud_printers.html"
diff --git a/chrome/browser/resources/settings/site_settings/site_details.html b/chrome/browser/resources/settings/site_settings/site_details.html
index 38ff9db..22d9184 100644
--- a/chrome/browser/resources/settings/site_settings/site_details.html
+++ b/chrome/browser/resources/settings/site_settings/site_details.html
@@ -12,50 +12,27 @@
 <dom-module id="site-details">
   <template>
     <style include="settings-shared">
-      :host {
-        -webkit-margin-start: 4px;
-        display: block;
-      }
-
-      .origin-box {
-        margin-bottom: 20px;
-      }
-
-      .origin {
-        -webkit-margin-start: 10px;
-        font-weight: 500;
-      }
-
-      .reset-button {
-        -webkit-margin-start: 15px;
-      }
-
       #storage {
         -webkit-padding-end: 0;
       }
-
-      .website-icon {
-        background-repeat: no-repeat;
-        background-size: contain;
-        height: 16px;
-        width: 16px;
-      }
     </style>
-    <div class="settings-box block">
-      <div class="horizontal layout origin-box">
-        <div class="website-icon"
-            style$="[[computeSiteIcon(site.originForDisplay)]]"></div>
-        <div class="origin flex">[[site.originForDisplay]]</div>
+    <div id="usage" hidden$="[[!storedData_]]">
+      <div class="settings-box first">
+        <h2>$i18n{siteSettingsUsage}</h2>
       </div>
-      <h2 id="usage" hidden$="[[!storedData_]]">$i18n{siteSettingsUsage}</h2>
-      <paper-item id="storage" hidden$="[[!storedData_]]">
-        <div class="flex">[[storedData_]]</div>
-        <paper-icon-button icon="settings:delete"
-            on-tap="onClearStorage_"
-            alt="$i18n{siteSettingsDelete}"></paper-icon-button>
-      </paper-item>
+      <div class="list-frame">
+        <paper-item id="storage" hidden$="[[!storedData_]]">
+          <div class="flex">[[storedData_]]</div>
+          <paper-icon-button icon="settings:delete"
+              on-tap="onClearStorage_"
+              alt="$i18n{siteSettingsDelete}"></paper-icon-button>
+        </paper-item>
+      </div>
+    </div>
+    <div class="settings-box">
       <h2>$i18n{siteSettingsPermissions}</h2>
-
+    </div>
+    <div class="list-frame">
       <site-details-permission site="[[site]]" id="cookies"
           category="{{ContentSettingsTypes.COOKIES}}">
       </site-details-permission>
@@ -96,9 +73,9 @@
           category="{{ContentSettingsTypes.FULLSCREEN}}">
       </site-details-permission>
 
-      <paper-button on-tap="onClearAndReset_" raised class="reset-button">
+      <div on-tap="onClearAndReset_" raised class="list-item list-button">
         $i18n{siteSettingsClearAndReset}
-      </paper-button>
+      </div>
     </div>
     <website-usage-private-api id="usageApi"
         website-data-usage="{{storedData_}}"
diff --git a/chrome/browser/resources/settings/site_settings/site_details_permission.html b/chrome/browser/resources/settings/site_settings/site_details_permission.html
index 58fa36d..b69122b3 100644
--- a/chrome/browser/resources/settings/site_settings/site_details_permission.html
+++ b/chrome/browser/resources/settings/site_settings/site_details_permission.html
@@ -12,7 +12,7 @@
   <template>
     <style include="settings-shared">
     </style>
-    <div id="details" class="list-frame" hidden>
+    <div id="details" hidden>
       <div class="list-item underbar">
         <div>
           <iron-icon icon="[[computeIconForContentCategory(category)]]">
diff --git a/chrome/browser/resources/settings/site_settings/site_list.html b/chrome/browser/resources/settings/site_settings/site_list.html
index 57a4323..27f4bee 100644
--- a/chrome/browser/resources/settings/site_settings/site_list.html
+++ b/chrome/browser/resources/settings/site_settings/site_list.html
@@ -84,7 +84,7 @@
           </div>
         </template>
 
-        <template is="dom-if" if="{{!allSites}}">
+        <template is="dom-if" if="[[!allSites]]">
           <div class="button-container">
             <paper-button on-tap="onAddSiteTap_"
                 class="primary-button no-upper">
diff --git a/chrome/browser/sync/sessions/sessions_sync_manager_unittest.cc b/chrome/browser/sync/sessions/sessions_sync_manager_unittest.cc
index f2661974..25e41f3 100644
--- a/chrome/browser/sync/sessions/sessions_sync_manager_unittest.cc
+++ b/chrome/browser/sync/sessions/sessions_sync_manager_unittest.cc
@@ -83,7 +83,8 @@
   bool HasWindow() const override { return wrapped_->HasWindow(); }
 
   SessionID::id_type GetSessionId() const override {
-    return wrapped_->GetSessionId();
+    return session_id_override_ >= 0 ? session_id_override_
+                                     : wrapped_->GetSessionId();
   }
 
   int GetTabCount() const override { return wrapped_->GetTabCount(); }
@@ -107,6 +108,8 @@
     return wrapped_->GetTabAt(index);
   }
 
+  void OverrideSessionId(SessionID::id_type id) { session_id_override_ = id; }
+
   void OverrideTabAt(int index,
                      SyncedTabDelegate* delegate,
                      SessionID::id_type tab_id) {
@@ -130,6 +133,7 @@
   std::map<int, SyncedTabDelegate*> tab_overrides_;
   std::map<int, SessionID::id_type> tab_id_overrides_;
   const SyncedWindowDelegate* const wrapped_;
+  SessionID::id_type session_id_override_ = -1;
 };
 
 class TestSyncedWindowDelegatesGetter : public SyncedWindowDelegatesGetter {
@@ -394,32 +398,34 @@
 
   sync_driver::SyncPrefs* sync_prefs() { return sync_prefs_.get(); }
 
+  browser_sync::SyncedWindowDelegatesGetter* get_synced_window_getter() {
+    return manager()->synced_window_delegates_getter();
+  }
+
   void set_synced_window_getter(
       browser_sync::SyncedWindowDelegatesGetter* synced_window_getter) {
     sessions_client_shim_->set_synced_window_getter(synced_window_getter);
   }
 
   syncer::SyncChange MakeRemoteChange(
-      int64_t id,
       const sync_pb::SessionSpecifics& specifics,
       SyncChange::SyncChangeType type) const {
-    return syncer::SyncChange(FROM_HERE, type, CreateRemoteData(specifics, id));
+    return syncer::SyncChange(FROM_HERE, type, CreateRemoteData(specifics));
   }
 
   void AddTabsToChangeList(const std::vector<sync_pb::SessionSpecifics>& batch,
                            SyncChange::SyncChangeType type,
                            syncer::SyncChangeList* change_list) const {
     for (const auto& specifics : batch) {
-      change_list->push_back(syncer::SyncChange(
-          FROM_HERE, type,
-          CreateRemoteData(specifics, specifics.tab_node_id())));
+      change_list->push_back(
+          syncer::SyncChange(FROM_HERE, type, CreateRemoteData(specifics)));
     }
   }
 
   void AddToSyncDataList(const sync_pb::SessionSpecifics& specifics,
                          syncer::SyncDataList* list,
                          base::Time mtime) const {
-    list->push_back(CreateRemoteData(specifics, 1, mtime));
+    list->push_back(CreateRemoteData(specifics, mtime));
   }
 
   void AddTabsToSyncDataList(const std::vector<sync_pb::SessionSpecifics>& tabs,
@@ -430,18 +436,17 @@
   }
 
   syncer::SyncData CreateRemoteData(const sync_pb::SessionSpecifics& specifics,
-                                    int64_t id = 1,
                                     base::Time mtime = base::Time()) const {
     sync_pb::EntitySpecifics entity;
     entity.mutable_session()->CopyFrom(specifics);
-    return CreateRemoteData(entity, id, mtime);
+    return CreateRemoteData(entity, mtime);
   }
 
   syncer::SyncData CreateRemoteData(const sync_pb::EntitySpecifics& entity,
-                                    int64_t id,
-                                    base::Time mtime) const {
+                                    base::Time mtime = base::Time()) const {
+    // The server ID is never relevant to these tests, so just use 1.
     return SyncData::CreateRemoteData(
-        id, entity, mtime, syncer::AttachmentIdList(),
+        1, entity, mtime, syncer::AttachmentIdList(),
         syncer::AttachmentServiceProxyForTest::Create(),
         SessionsSyncManager::TagHashFromSpecifics(entity.session()));
   }
@@ -925,12 +930,7 @@
   EXPECT_EQ(0, header_s2.window_size());
 
   // Now take that header node and feed it in as input.
-  SyncData d(SyncData::CreateRemoteData(
-      1,
-      data.GetSpecifics(),
-      base::Time(),
-      syncer::AttachmentIdList(),
-      syncer::AttachmentServiceProxyForTest::Create()));
+  SyncData d = CreateRemoteData(data.GetSpecifics());
   syncer::SyncDataList in(&d, &d + 1);
   out.clear();
   SessionsSyncManager manager2(GetSyncSessionsClient(), sync_prefs(),
@@ -970,29 +970,13 @@
   // * one "normal" fully loaded tab
   // * one "frozen" tab with no WebContents and a tab_id change
   // * one "frozen" tab with no WebContents and no tab_id change
-  SyncData t0(SyncData::CreateRemoteData(
-      1,
-      out[2].sync_data().GetSpecifics(),
-      base::Time(),
-      syncer::AttachmentIdList(),
-      syncer::AttachmentServiceProxyForTest::Create()));
-  sync_pb::EntitySpecifics entity(out[4].sync_data().GetSpecifics());
-  entity.mutable_session()->mutable_tab()->set_tab_id(kRestoredTabId);
-  SyncData t1(SyncData::CreateRemoteData(
-      2,
-      entity,
-      base::Time(),
-      syncer::AttachmentIdList(),
-      syncer::AttachmentServiceProxyForTest::Create()));
-  SyncData t2(SyncData::CreateRemoteData(
-      3,
-      out[6].sync_data().GetSpecifics(),
-      base::Time(),
-      syncer::AttachmentIdList(),
-      syncer::AttachmentServiceProxyForTest::Create()));
-  in.push_back(t0);
-  in.push_back(t1);
-  in.push_back(t2);
+  sync_pb::EntitySpecifics t0_entity = out[2].sync_data().GetSpecifics();
+  sync_pb::EntitySpecifics t1_entity = out[4].sync_data().GetSpecifics();
+  sync_pb::EntitySpecifics t2_entity = out[6].sync_data().GetSpecifics();
+  t1_entity.mutable_session()->mutable_tab()->set_tab_id(kRestoredTabId);
+  in.push_back(CreateRemoteData(t0_entity));
+  in.push_back(CreateRemoteData(t1_entity));
+  in.push_back(CreateRemoteData(t2_entity));
   out.clear();
   manager()->StopSyncing(syncer::SESSIONS);
 
@@ -1005,7 +989,7 @@
   SyncedWindowDelegateOverride window_override(*windows.begin());
   window_override.OverrideTabAt(1, &t1_override, kNewTabId);
   window_override.OverrideTabAt(2, &t2_override,
-                                t2.GetSpecifics().session().tab().tab_id());
+                                t2_entity.session().tab().tab_id());
   std::set<const SyncedWindowDelegate*> delegates;
   delegates.insert(&window_override);
   std::unique_ptr<TestSyncedWindowDelegatesGetter> getter(
@@ -1029,7 +1013,7 @@
   // Verify TabLinks.
   SessionsSyncManager::TabLinksMap tab_map = manager()->local_tab_map_;
   ASSERT_EQ(3U, tab_map.size());
-  int t2_tab_id = t2.GetSpecifics().session().tab().tab_id();
+  int t2_tab_id = t2_entity.session().tab().tab_id();
   EXPECT_EQ(2, tab_map.find(t2_tab_id)->second->tab_node_id());
   EXPECT_EQ(1, tab_map.find(kNewTabId)->second->tab_node_id());
   int t0_tab_id = out[0].sync_data().GetSpecifics().session().tab().tab_id();
@@ -1040,6 +1024,59 @@
   // (similar to how SessionsSyncManagerTest.OnLocalTabModified works.)
 }
 
+// Ensure model association updates the window ID for tabs whose window's ID has
+// changed.
+TEST_F(SessionsSyncManagerTest, WindowIdUpdatedOnRestore) {
+  const int kNewWindowId = 1337;
+  syncer::SyncDataList in;
+  syncer::SyncChangeList out;
+
+  // Set up one tab and start sync with it.
+  AddTab(browser(), GURL("http://foo1"));
+  NavigateAndCommitActiveTab(GURL("http://foo2"));
+  InitWithSyncDataTakeOutput(in, &out);
+
+  // Should be one header add, 1 tab add/update pair, and one header update.
+  ASSERT_EQ(4U, out.size());
+  const sync_pb::EntitySpecifics t0_entity = out[2].sync_data().GetSpecifics();
+
+  in.push_back(CreateRemoteData(t0_entity));
+  out.clear();
+  manager()->StopSyncing(syncer::SESSIONS);
+
+  // SyncedTabDelegateFake is a placeholder (no WebContents) by default.
+  SyncedTabDelegateFake t0_override;
+  t0_override.SetSyncId(t0_entity.session().tab_node_id());
+
+  // Set up the window override with the new window ID and placeholder tab.
+  const std::set<const SyncedWindowDelegate*>& windows =
+      get_synced_window_getter()->GetSyncedWindowDelegates();
+  ASSERT_EQ(1U, windows.size());
+  SyncedWindowDelegateOverride window_override(*windows.begin());
+  window_override.OverrideSessionId(kNewWindowId);
+  window_override.OverrideTabAt(0, &t0_override,
+                                t0_entity.session().tab().tab_id());
+
+  // Inject the window override.
+  std::set<const SyncedWindowDelegate*> delegates;
+  delegates.insert(&window_override);
+  std::unique_ptr<TestSyncedWindowDelegatesGetter> getter(
+      new TestSyncedWindowDelegatesGetter(delegates));
+  set_synced_window_getter(getter.get());
+
+  syncer::SyncMergeResult result = manager()->MergeDataAndStartSyncing(
+      syncer::SESSIONS, in, std::unique_ptr<syncer::SyncChangeProcessor>(
+                                new TestSyncProcessorStub(&out)),
+      std::unique_ptr<syncer::SyncErrorFactory>(
+          new syncer::SyncErrorFactoryMock()));
+
+  // There should be one change for t0's window ID update.
+  ASSERT_EQ(1U, FilterOutLocalHeaderChanges(&out)->size());
+  EXPECT_EQ(SyncChange::ACTION_UPDATE, out[0].change_type());
+  EXPECT_EQ(kNewWindowId,
+            out[0].sync_data().GetSpecifics().session().tab().window_id());
+}
+
 // Tests MergeDataAndStartSyncing with sync data but no local data.
 TEST_F(SessionsSyncManagerTest, MergeWithInitialForeignSession) {
   std::string tag = "tag1";
@@ -1063,7 +1100,7 @@
     sync_pb::EntitySpecifics entity;
     helper()->BuildTabSpecifics(tag, 0, tab_list2[i],
                                 entity.mutable_session());
-    initial_data.push_back(CreateRemoteData(entity, i + 10, base::Time()));
+    initial_data.push_back(CreateRemoteData(entity));
   }
 
   syncer::SyncChangeList output;
@@ -1192,7 +1229,7 @@
   }
 
   syncer::SyncChangeList changes;
-  changes.push_back(MakeRemoteChange(1, meta1, SyncChange::ACTION_UPDATE));
+  changes.push_back(MakeRemoteChange(meta1, SyncChange::ACTION_UPDATE));
   AddTabsToChangeList(tabs2, SyncChange::ACTION_ADD, &changes);
   manager()->ProcessSyncChanges(FROM_HERE, changes);
   changes.clear();
@@ -1212,7 +1249,7 @@
   std::vector<sync_pb::SessionSpecifics> tag2_tabs;
   sync_pb::SessionSpecifics meta2(helper()->BuildForeignSession(
       tag2, tag2_tab_list, &tag2_tabs));
-  changes.push_back(MakeRemoteChange(100, meta2, SyncChange::ACTION_ADD));
+  changes.push_back(MakeRemoteChange(meta2, SyncChange::ACTION_ADD));
   AddTabsToChangeList(tag2_tabs, SyncChange::ACTION_ADD, &changes);
 
   manager()->ProcessSyncChanges(FROM_HERE, changes);
@@ -1236,7 +1273,7 @@
     win->add_tab(*iter);
   }
   syncer::SyncChangeList removal;
-  removal.push_back(MakeRemoteChange(1, meta1, SyncChange::ACTION_UPDATE));
+  removal.push_back(MakeRemoteChange(meta1, SyncChange::ACTION_UPDATE));
   AddTabsToChangeList(tabs1, SyncChange::ACTION_UPDATE, &removal);
   manager()->ProcessSyncChanges(FROM_HERE, removal);
 
@@ -1311,7 +1348,7 @@
   syncer::SyncChangeList adds;
   // Add tabs for first window, then the meta node.
   AddTabsToChangeList(tabs1, SyncChange::ACTION_ADD, &adds);
-  adds.push_back(MakeRemoteChange(1, meta, SyncChange::ACTION_ADD));
+  adds.push_back(MakeRemoteChange(meta, SyncChange::ACTION_ADD));
   manager()->ProcessSyncChanges(FROM_HERE, adds);
 
   // Check that the foreign session was associated and retrieve the data.
@@ -1347,7 +1384,7 @@
   }
 
   syncer::SyncChangeList changes;
-  changes.push_back(MakeRemoteChange(1, meta, SyncChange::ACTION_ADD));
+  changes.push_back(MakeRemoteChange(meta, SyncChange::ACTION_ADD));
   AddTabsToChangeList(tabs1, SyncChange::ACTION_ADD, &changes);
   AddTabsToChangeList(tabs2, SyncChange::ACTION_ADD, &changes);
   manager()->ProcessSyncChanges(FROM_HERE, changes);
@@ -1364,7 +1401,7 @@
   // Close the second window.
   meta.mutable_header()->clear_window();
   helper()->AddWindowSpecifics(0, tab_list1, &meta);
-  changes.push_back(MakeRemoteChange(1, meta, SyncChange::ACTION_UPDATE));
+  changes.push_back(MakeRemoteChange(meta, SyncChange::ACTION_UPDATE));
   // Update associator with the session's meta node containing one window.
   manager()->ProcessSyncChanges(FROM_HERE, changes);
 
@@ -1385,18 +1422,13 @@
   InitWithSyncDataTakeOutput(syncer::SyncDataList(), &out);
   ASSERT_EQ(2U, out.size());
   sync_pb::EntitySpecifics entity(out[0].sync_data().GetSpecifics());
-  SyncData d(SyncData::CreateRemoteData(
-      1,
-      entity,
-      base::Time(),
-      syncer::AttachmentIdList(),
-      syncer::AttachmentServiceProxyForTest::Create()));
+  SyncData d = CreateRemoteData(entity);
   SetSyncData(syncer::SyncDataList(&d, &d + 1));
   out.clear();
 
   syncer::SyncChangeList changes;
   changes.push_back(
-      MakeRemoteChange(1, entity.session(), SyncChange::ACTION_DELETE));
+      MakeRemoteChange(entity.session(), SyncChange::ACTION_DELETE));
   manager()->ProcessSyncChanges(FROM_HERE, changes);
   EXPECT_TRUE(manager()->local_tab_pool_out_of_sync_);
   EXPECT_TRUE(out.empty());  // ChangeProcessor shouldn't see any activity.
@@ -1457,7 +1489,7 @@
       "tag1", tab_list, &tabs1));
 
   syncer::SyncChangeList changes;
-  changes.push_back(MakeRemoteChange(1, meta, SyncChange::ACTION_ADD));
+  changes.push_back(MakeRemoteChange(meta, SyncChange::ACTION_ADD));
   AddTabsToChangeList(tabs1, SyncChange::ACTION_ADD, &changes);
   manager()->ProcessSyncChanges(FROM_HERE, changes);
 
@@ -1467,7 +1499,7 @@
 
   changes.clear();
   foreign_sessions.clear();
-  changes.push_back(MakeRemoteChange(1, meta, SyncChange::ACTION_DELETE));
+  changes.push_back(MakeRemoteChange(meta, SyncChange::ACTION_DELETE));
   manager()->ProcessSyncChanges(FROM_HERE, changes);
 
   EXPECT_FALSE(manager()->GetAllForeignSessions(&foreign_sessions));
@@ -1516,13 +1548,13 @@
   }
 
   syncer::SyncChangeList changes;
-  changes.push_back(MakeRemoteChange(1, tabs[2], SyncChange::ACTION_DELETE));
-  changes.push_back(MakeRemoteChange(1, tabs[4], SyncChange::ACTION_DELETE));
-  changes.push_back(MakeRemoteChange(1, orphan6, SyncChange::ACTION_DELETE));
-  changes.push_back(MakeRemoteChange(1, meta, SyncChange::ACTION_UPDATE));
-  changes.push_back(MakeRemoteChange(1, tabs[3], SyncChange::ACTION_DELETE));
-  changes.push_back(MakeRemoteChange(1, tabs[5], SyncChange::ACTION_DELETE));
-  changes.push_back(MakeRemoteChange(1, orphan7, SyncChange::ACTION_DELETE));
+  changes.push_back(MakeRemoteChange(tabs[2], SyncChange::ACTION_DELETE));
+  changes.push_back(MakeRemoteChange(tabs[4], SyncChange::ACTION_DELETE));
+  changes.push_back(MakeRemoteChange(orphan6, SyncChange::ACTION_DELETE));
+  changes.push_back(MakeRemoteChange(meta, SyncChange::ACTION_UPDATE));
+  changes.push_back(MakeRemoteChange(tabs[3], SyncChange::ACTION_DELETE));
+  changes.push_back(MakeRemoteChange(tabs[5], SyncChange::ACTION_DELETE));
+  changes.push_back(MakeRemoteChange(orphan7, SyncChange::ACTION_DELETE));
   manager()->ProcessSyncChanges(FROM_HERE, changes);
 
   std::vector<const SyncedSession*> foreign_sessions;
@@ -1597,9 +1629,9 @@
   EXPECT_TRUE(tab_node_ids.find(tab2C.tab_node_id()) != tab_node_ids.end());
 
   syncer::SyncChangeList changes;
-  changes.push_back(MakeRemoteChange(1, tab1A, SyncChange::ACTION_DELETE));
-  changes.push_back(MakeRemoteChange(1, tab1B, SyncChange::ACTION_DELETE));
-  changes.push_back(MakeRemoteChange(1, tab2C, SyncChange::ACTION_DELETE));
+  changes.push_back(MakeRemoteChange(tab1A, SyncChange::ACTION_DELETE));
+  changes.push_back(MakeRemoteChange(tab1B, SyncChange::ACTION_DELETE));
+  changes.push_back(MakeRemoteChange(tab2C, SyncChange::ACTION_DELETE));
   manager()->ProcessSyncChanges(FROM_HERE, changes);
 
   tab_node_ids.clear();
@@ -1647,7 +1679,7 @@
   EXPECT_TRUE(tab_node_ids.find(tab_node_id_unique) != tab_node_ids.end());
 
   syncer::SyncChangeList changes;
-  changes.push_back(MakeRemoteChange(1, tab1A, SyncChange::ACTION_DELETE));
+  changes.push_back(MakeRemoteChange(tab1A, SyncChange::ACTION_DELETE));
   manager()->ProcessSyncChanges(FROM_HERE, changes);
 
   tab_node_ids.clear();
@@ -1674,12 +1706,7 @@
   // will be deleted before being added to the tab node pool.
   sync_pb::EntitySpecifics entity(changes[0].sync_data().GetSpecifics());
   entity.mutable_session()->mutable_tab()->set_tab_id(1);
-  SyncData d(SyncData::CreateRemoteData(
-      1,
-      entity,
-      base::Time(),
-      syncer::AttachmentIdList(),
-      syncer::AttachmentServiceProxyForTest::Create()));
+  SyncData d = CreateRemoteData(entity);
   syncer::SyncDataList in(&d, &d + 1);
   changes.clear();
   SessionsSyncManager manager2(GetSyncSessionsClient(), sync_prefs(),
@@ -1700,12 +1727,7 @@
 
   std::string local_tag = manager()->current_machine_tag();
   int tab_node_id = manager()->local_tab_pool_.GetFreeTabNode(&changes);
-  SyncData d(SyncData::CreateRemoteData(
-      1,
-      changes[0].sync_data().GetSpecifics(),
-      base::Time(),
-      syncer::AttachmentIdList(),
-      syncer::AttachmentServiceProxyForTest::Create()));
+  SyncData d = CreateRemoteData(changes[0].sync_data().GetSpecifics());
   syncer::SyncDataList in(&d, &d + 1);
   changes.clear();
   TearDown();
@@ -2129,8 +2151,8 @@
   base::Time tag2_time = base::Time::Now() - base::TimeDelta::FromDays(5);
 
   syncer::SyncDataList foreign_data;
-  foreign_data.push_back(CreateRemoteData(meta, 1, tag1_time));
-  foreign_data.push_back(CreateRemoteData(meta2, 1, tag2_time));
+  foreign_data.push_back(CreateRemoteData(meta, tag1_time));
+  foreign_data.push_back(CreateRemoteData(meta2, tag2_time));
   AddTabsToSyncDataList(tabs1, &foreign_data);
   AddTabsToSyncDataList(tabs2, &foreign_data);
 
@@ -2239,7 +2261,7 @@
       tag1, tab_list1, &tabs1));
   syncer::SyncDataList foreign_data;
   base::Time tag1_time = base::Time::Now() - base::TimeDelta::FromDays(21);
-  foreign_data.push_back(CreateRemoteData(meta, 1, tag1_time));
+  foreign_data.push_back(CreateRemoteData(meta, tag1_time));
   AddTabsToSyncDataList(tabs1, &foreign_data);
   syncer::SyncChangeList output;
   InitWithSyncDataTakeOutput(foreign_data, &output);
@@ -2251,7 +2273,7 @@
   syncer::SyncChangeList changes;
   changes.push_back(
       syncer::SyncChange(FROM_HERE, SyncChange::ACTION_UPDATE,
-                         CreateRemoteData(tabs1[0], 1, base::Time::Now())));
+                         CreateRemoteData(tabs1[0], base::Time::Now())));
   manager()->ProcessSyncChanges(FROM_HERE, changes);
 
   // Check that the foreign session was associated and retrieve the data.
@@ -2332,7 +2354,7 @@
       "tag1", tab_list, &tabs1));
 
   syncer::SyncChangeList changes;
-  changes.push_back(MakeRemoteChange(1, meta, SyncChange::ACTION_ADD));
+  changes.push_back(MakeRemoteChange(meta, SyncChange::ACTION_ADD));
   manager()->ProcessSyncChanges(FROM_HERE, changes);
   EXPECT_TRUE(observer()->notified_of_update());
 
@@ -2344,7 +2366,7 @@
 
   changes.clear();
   observer()->Reset();
-  changes.push_back(MakeRemoteChange(1, meta, SyncChange::ACTION_DELETE));
+  changes.push_back(MakeRemoteChange(meta, SyncChange::ACTION_DELETE));
   manager()->ProcessSyncChanges(FROM_HERE, changes);
   EXPECT_TRUE(observer()->notified_of_update());
 }
@@ -2361,7 +2383,7 @@
       tag, tab_list, &tabs1));
 
   syncer::SyncChangeList changes;
-  changes.push_back(MakeRemoteChange(1, meta, SyncChange::ACTION_ADD));
+  changes.push_back(MakeRemoteChange(meta, SyncChange::ACTION_ADD));
   manager()->ProcessSyncChanges(FROM_HERE, changes);
 
   observer()->Reset();
@@ -2401,12 +2423,7 @@
   syncer::SyncDataList initial_data;
   sync_pb::EntitySpecifics entity;
   entity.mutable_session()->CopyFrom(meta);
-  initial_data.push_back(SyncData::CreateRemoteData(
-      1,
-      entity,
-      base::Time(),
-      syncer::AttachmentIdList(),
-      syncer::AttachmentServiceProxyForTest::Create()));
+  initial_data.push_back(CreateRemoteData(entity));
   AddTabsToSyncDataList(tabs1, &initial_data);
 
   syncer::SyncChangeList output;
@@ -2435,23 +2452,13 @@
   syncer::SyncDataList initial_data;
   sync_pb::EntitySpecifics entity;
   entity.mutable_session()->CopyFrom(meta);
-  initial_data.push_back(SyncData::CreateRemoteData(
-      1,
-      entity,
-      base::Time(),
-      syncer::AttachmentIdList(),
-      syncer::AttachmentServiceProxyForTest::Create()));
+  initial_data.push_back(CreateRemoteData(entity));
   AddTabsToSyncDataList(tabs1, &initial_data);
 
   for (size_t i = 0; i < tab_list2.size(); ++i) {
     sync_pb::EntitySpecifics entity;
     helper()->BuildTabSpecifics(tag, 0, tab_list2[i], entity.mutable_session());
-    initial_data.push_back(SyncData::CreateRemoteData(
-        i + 10,
-        entity,
-        base::Time(),
-        syncer::AttachmentIdList(),
-        syncer::AttachmentServiceProxyForTest::Create()));
+    initial_data.push_back(CreateRemoteData(entity));
   }
 
   syncer::SyncChangeList output;
@@ -2473,13 +2480,12 @@
   syncer::SyncDataList initial_data;
   initial_data.push_back(CreateRemoteData(meta));
 
-  int node_id = 2;
   sync_pb::EntitySpecifics entity;
 
   for (size_t i = 0; i < tabs1.size(); i++) {
     entity.mutable_session()->CopyFrom(tabs1[i]);
     initial_data.push_back(
-        CreateRemoteData(entity, node_id++, base::Time::FromDoubleT(2000)));
+        CreateRemoteData(entity, base::Time::FromDoubleT(2000)));
   }
 
   // Add two more tabs with duplicating IDs but with different modification
@@ -2491,14 +2497,14 @@
   duplicating_tab1.mutable_tab()->set_tab_visual_index(2);
   entity.mutable_session()->CopyFrom(duplicating_tab1);
   initial_data.push_back(
-      CreateRemoteData(entity, node_id++, base::Time::FromDoubleT(1000)));
+      CreateRemoteData(entity, base::Time::FromDoubleT(1000)));
 
   sync_pb::SessionSpecifics duplicating_tab2;
   helper()->BuildTabSpecifics(tag, 0, 17, &duplicating_tab2);
   duplicating_tab2.mutable_tab()->set_tab_visual_index(3);
   entity.mutable_session()->CopyFrom(duplicating_tab2);
   initial_data.push_back(
-      CreateRemoteData(entity, node_id++, base::Time::FromDoubleT(3000)));
+      CreateRemoteData(entity, base::Time::FromDoubleT(3000)));
 
   syncer::SyncChangeList output;
   InitWithSyncDataTakeOutput(initial_data, &output);
@@ -2534,10 +2540,10 @@
 
   syncer::SyncDataList initial_data;
   initial_data.push_back(
-      CreateRemoteData(meta1, 1, base::Time::FromInternalValue(10)));
+      CreateRemoteData(meta1, base::Time::FromInternalValue(10)));
   AddTabsToSyncDataList(tabs1, &initial_data);
   initial_data.push_back(
-      CreateRemoteData(meta2, 2, base::Time::FromInternalValue(200)));
+      CreateRemoteData(meta2, base::Time::FromInternalValue(200)));
   AddTabsToSyncDataList(tabs2, &initial_data);
 
   syncer::SyncChangeList output;
@@ -2580,7 +2586,7 @@
     // Order the tabs oldest to most ReceiveDuplicateUnassociatedTabs and
     // left to right visually.
     initial_data.push_back(
-        CreateRemoteData(entity, i + 10, base::Time::FromInternalValue(i + 1)));
+        CreateRemoteData(entity, base::Time::FromInternalValue(i + 1)));
   }
 
   syncer::SyncChangeList output;
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn
index db85b4d..e2b7875 100644
--- a/chrome/browser/ui/BUILD.gn
+++ b/chrome/browser/ui/BUILD.gn
@@ -385,7 +385,6 @@
       "//ui/keyboard:resources",
       "//ui/wm",
     ]
-    defines += [ "MOJO_SHELL_CLIENT" ]
     if (!is_chromeos) {
       sources += rebase_path(gypi_values.chrome_browser_ui_aura_non_chromeos,
                              ".",
diff --git a/chrome/browser/ui/android/autofill/credit_card_scanner_view_android.cc b/chrome/browser/ui/android/autofill/credit_card_scanner_view_android.cc
index 576f1d0..48b3082 100644
--- a/chrome/browser/ui/android/autofill/credit_card_scanner_view_android.cc
+++ b/chrome/browser/ui/android/autofill/credit_card_scanner_view_android.cc
@@ -26,7 +26,7 @@
   JNIEnv* env = base::android::AttachCurrentThread();
   base::android::ScopedJavaGlobalRef<jobject> java_object(
       Java_CreditCardScanner_create(
-          env, 0, base::android::GetApplicationContext(), 0));
+          env, 0, base::android::GetApplicationContext(), nullptr));
   return Java_CreditCardScanner_canScan(env, java_object.obj());
 }
 
diff --git a/chrome/browser/ui/android/connection_info_popup_android.cc b/chrome/browser/ui/android/connection_info_popup_android.cc
index b0bf613..faea509a 100644
--- a/chrome/browser/ui/android/connection_info_popup_android.cc
+++ b/chrome/browser/ui/android/connection_info_popup_android.cc
@@ -89,7 +89,7 @@
   // Important to use GetVisibleEntry to match what's showing in the omnibox.
   content::NavigationEntry* nav_entry =
       web_contents->GetController().GetVisibleEntry();
-  if (nav_entry == NULL)
+  if (nav_entry == nullptr)
     return;
 
   popup_jobject_.Reset(env, java_website_settings_pop);
@@ -176,7 +176,7 @@
     ScopedJavaLocalRef<jstring> description = ConvertUTF8ToJavaString(
         env, identity_info.connection_status_description);
     Java_ConnectionInfoPopup_addDescriptionSection(
-        env, popup_jobject_.obj(), icon_id, NULL, description.obj());
+        env, popup_jobject_.obj(), icon_id, nullptr, description.obj());
   }
 
   Java_ConnectionInfoPopup_addMoreInfoLink(
diff --git a/chrome/browser/ui/android/infobars/autofill_credit_card_filling_infobar.cc b/chrome/browser/ui/android/infobars/autofill_credit_card_filling_infobar.cc
new file mode 100644
index 0000000..47c5b27
--- /dev/null
+++ b/chrome/browser/ui/android/infobars/autofill_credit_card_filling_infobar.cc
@@ -0,0 +1,61 @@
+// 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 "chrome/browser/ui/android/infobars/autofill_credit_card_filling_infobar.h"
+
+#include <utility>
+
+#include "base/android/jni_android.h"
+#include "base/android/jni_string.h"
+#include "base/memory/ptr_util.h"
+#include "chrome/browser/android/resource_mapper.h"
+#include "chrome/browser/infobars/infobar_service.h"
+#include "components/autofill/core/browser/autofill_credit_card_filling_infobar_delegate_mobile.h"
+#include "jni/AutofillCreditCardFillingInfoBar_jni.h"
+#include "ui/gfx/android/java_bitmap.h"
+#include "ui/gfx/image/image.h"
+#include "url/gurl.h"
+
+AutofillCreditCardFillingInfoBar::AutofillCreditCardFillingInfoBar(
+    std::unique_ptr<autofill::AutofillCreditCardFillingInfoBarDelegateMobile>
+        delegate)
+    : ConfirmInfoBar(std::move(delegate)) {}
+
+AutofillCreditCardFillingInfoBar::~AutofillCreditCardFillingInfoBar() {}
+
+base::android::ScopedJavaLocalRef<jobject>
+AutofillCreditCardFillingInfoBar::CreateRenderInfoBar(JNIEnv* env) {
+  autofill::AutofillCreditCardFillingInfoBarDelegateMobile* delegate =
+      static_cast<autofill::AutofillCreditCardFillingInfoBarDelegateMobile*>(
+          GetDelegate());
+  ScopedJavaLocalRef<jobject> java_bitmap;
+  if (delegate->GetIconId() == infobars::InfoBarDelegate::kNoIconID &&
+      !delegate->GetIcon().IsEmpty()) {
+    java_bitmap = gfx::ConvertToJavaBitmap(delegate->GetIcon().ToSkBitmap());
+  }
+
+  base::android::ScopedJavaLocalRef<jobject> java_delegate =
+      Java_AutofillCreditCardFillingInfoBar_create(
+          env, reinterpret_cast<intptr_t>(this), GetEnumeratedIconId(),
+          java_bitmap.obj(),
+          base::android::ConvertUTF16ToJavaString(
+              env, delegate->GetMessageText())
+              .obj(),
+          base::android::ConvertUTF16ToJavaString(
+              env, GetTextFor(ConfirmInfoBarDelegate::BUTTON_OK))
+              .obj(),
+          base::android::ConvertUTF16ToJavaString(
+              env, GetTextFor(ConfirmInfoBarDelegate::BUTTON_CANCEL))
+              .obj());
+
+  Java_AutofillCreditCardFillingInfoBar_addDetail(
+      env, java_delegate.obj(),
+      ResourceMapper::MapFromChromiumId(delegate->issuer_icon_id()),
+      base::android::ConvertUTF16ToJavaString(env, delegate->card_label())
+          .obj(),
+      base::android::ConvertUTF16ToJavaString(env, delegate->card_sub_label())
+          .obj());
+
+  return java_delegate;
+}
diff --git a/chrome/browser/ui/android/infobars/autofill_credit_card_filling_infobar.h b/chrome/browser/ui/android/infobars/autofill_credit_card_filling_infobar.h
new file mode 100644
index 0000000..8a2a8d3
--- /dev/null
+++ b/chrome/browser/ui/android/infobars/autofill_credit_card_filling_infobar.h
@@ -0,0 +1,38 @@
+// 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 CHROME_BROWSER_UI_ANDROID_INFOBARS_AUTOFILL_CREDIT_CARD_FILLING_INFOBAR_H_
+#define CHROME_BROWSER_UI_ANDROID_INFOBARS_AUTOFILL_CREDIT_CARD_FILLING_INFOBAR_H_
+
+#include <jni.h>
+
+#include <memory>
+
+#include "base/macros.h"
+#include "chrome/browser/ui/android/infobars/confirm_infobar.h"
+
+namespace autofill {
+class AutofillCreditCardFillingInfoBarDelegateMobile;
+}
+
+// Android implementation of the infobar for credit card assisted filling, which
+// proposes to autofill user data into the detected credit card form in the
+// page. Upon accepting the infobar, the form is filled automatically. If
+// the infobar is dismissed, nothing happens.
+class AutofillCreditCardFillingInfoBar : public ConfirmInfoBar {
+ public:
+  explicit AutofillCreditCardFillingInfoBar(
+      std::unique_ptr<autofill::AutofillCreditCardFillingInfoBarDelegateMobile>
+          delegate);
+  ~AutofillCreditCardFillingInfoBar() override;
+
+ private:
+  // ConfirmInfoBar:
+  base::android::ScopedJavaLocalRef<jobject> CreateRenderInfoBar(
+      JNIEnv* env) override;
+
+  DISALLOW_COPY_AND_ASSIGN(AutofillCreditCardFillingInfoBar);
+};
+
+#endif  // CHROME_BROWSER_UI_ANDROID_INFOBARS_AUTOFILL_CREDIT_CARD_FILLING_INFOBAR_H_
diff --git a/chrome/browser/ui/ash/ash_init.cc b/chrome/browser/ui/ash/ash_init.cc
index ceca12f..ad74f02 100644
--- a/chrome/browser/ui/ash/ash_init.cc
+++ b/chrome/browser/ui/ash/ash_init.cc
@@ -29,6 +29,7 @@
 #include "chrome/browser/ui/ash/chrome_shell_content_state.h"
 #include "chrome/browser/ui/ash/chrome_shell_delegate.h"
 #include "chrome/browser/ui/ash/ime_controller_chromeos.h"
+#include "chrome/browser/ui/ash/launcher/chrome_launcher_controller_mus.h"
 #include "chrome/browser/ui/ash/volume_controller_chromeos.h"
 #include "chrome/common/chrome_switches.h"
 #include "chromeos/accelerometer/accelerometer_reader.h"
@@ -43,10 +44,6 @@
 #include "ui/base/x/x11_util.h"
 #endif
 
-#if defined(MOJO_SHELL_CLIENT)
-#include "chrome/browser/ui/ash/launcher/chrome_launcher_controller_mus.h"
-#endif
-
 namespace chrome {
 
 void OpenAsh(gfx::AcceleratedWidget remote_window) {
@@ -106,10 +103,8 @@
 }
 
 void InitializeMash() {
-#if defined(MOJO_SHELL_CLIENT)
   DCHECK(!ash::Shell::HasInstance());
   ChromeLauncherControllerMus::CreateInstance()->Init();
-#endif
 }
 
 void CloseAsh() {
diff --git a/chrome/browser/ui/ash/ash_util.cc b/chrome/browser/ui/ash/ash_util.cc
index eeb288a..30605b6 100644
--- a/chrome/browser/ui/ash/ash_util.cc
+++ b/chrome/browser/ui/ash/ash_util.cc
@@ -8,11 +8,8 @@
 #include "ash/common/wm_shell.h"
 #include "build/build_config.h"
 #include "chrome/browser/ui/ash/ash_init.h"
-#include "ui/aura/window_event_dispatcher.h"
-
-#if defined(MOJO_SHELL_CLIENT)
 #include "services/shell/runner/common/client_util.h"
-#endif
+#include "ui/aura/window_event_dispatcher.h"
 
 namespace chrome {
 
@@ -21,11 +18,7 @@
 }
 
 bool IsRunningInMash() {
-#if defined(MOJO_SHELL_CLIENT)
   return shell::ShellIsRemote();
-#else
-  return false;
-#endif
 }
 
 bool IsAcceleratorDeprecated(const ui::Accelerator& accelerator) {
diff --git a/chrome/browser/ui/ash/launcher/chrome_launcher_controller.h b/chrome/browser/ui/ash/launcher/chrome_launcher_controller.h
index eb963f9..17600d306 100644
--- a/chrome/browser/ui/ash/launcher/chrome_launcher_controller.h
+++ b/chrome/browser/ui/ash/launcher/chrome_launcher_controller.h
@@ -16,6 +16,7 @@
 #include "chrome/browser/ui/ash/launcher/chrome_launcher_types.h"
 #include "extensions/common/constants.h"
 
+class AccountId;
 class ArcAppDeferredLauncherController;
 class Browser;
 class BrowserShortcutLauncherItemController;
@@ -234,7 +235,7 @@
   // animation predictions.
   virtual bool ShelfBoundsChangesProbablyWithUser(
       ash::Shelf* shelf,
-      const std::string& user_id) const = 0;
+      const AccountId& account_id) const = 0;
 
   // Called when the user profile is fully loaded and ready to switch to.
   virtual void OnUserProfileReadyToSwitch(Profile* profile) = 0;
diff --git a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_impl.cc b/chrome/browser/ui/ash/launcher/chrome_launcher_controller_impl.cc
index 676aae2d..c48e651 100644
--- a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_impl.cc
+++ b/chrome/browser/ui/ash/launcher/chrome_launcher_controller_impl.cc
@@ -824,10 +824,9 @@
 
 bool ChromeLauncherControllerImpl::ShelfBoundsChangesProbablyWithUser(
     ash::Shelf* shelf,
-    const std::string& user_id) const {
-  Profile* other_profile = multi_user_util::GetProfileFromAccountId(
-      AccountId::FromUserEmail(user_id));
-  if (other_profile == profile_)
+    const AccountId& account_id) const {
+  Profile* other_profile = multi_user_util::GetProfileFromAccountId(account_id);
+  if (!other_profile || other_profile == profile_)
     return false;
 
   // Note: The Auto hide state from preferences is not the same as the actual
diff --git a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_impl.h b/chrome/browser/ui/ash/launcher/chrome_launcher_controller_impl.h
index 17dd0c7..d3007c6 100644
--- a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_impl.h
+++ b/chrome/browser/ui/ash/launcher/chrome_launcher_controller_impl.h
@@ -134,7 +134,7 @@
       const ash::ShelfID id) override;
   bool ShelfBoundsChangesProbablyWithUser(
       ash::Shelf* shelf,
-      const std::string& user_id) const override;
+      const AccountId& account_id) const override;
   void OnUserProfileReadyToSwitch(Profile* profile) override;
   ArcAppDeferredLauncherController* GetArcDeferredLauncher() override;
 
diff --git a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_mus.cc b/chrome/browser/ui/ash/launcher/chrome_launcher_controller_mus.cc
index 3115403f..e98778f 100644
--- a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_mus.cc
+++ b/chrome/browser/ui/ash/launcher/chrome_launcher_controller_mus.cc
@@ -225,7 +225,7 @@
 
 bool ChromeLauncherControllerMus::ShelfBoundsChangesProbablyWithUser(
     ash::Shelf* shelf,
-    const std::string& user_id) const {
+    const AccountId& account_id) const {
   NOTIMPLEMENTED();
   return false;
 }
diff --git a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_mus.h b/chrome/browser/ui/ash/launcher/chrome_launcher_controller_mus.h
index 2d7082e..4e4b368 100644
--- a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_mus.h
+++ b/chrome/browser/ui/ash/launcher/chrome_launcher_controller_mus.h
@@ -81,7 +81,7 @@
       const ash::ShelfID id) override;
   bool ShelfBoundsChangesProbablyWithUser(
       ash::Shelf* shelf,
-      const std::string& user_id) const override;
+      const AccountId& account_id) const override;
   void OnUserProfileReadyToSwitch(Profile* profile) override;
   ArcAppDeferredLauncherController* GetArcDeferredLauncher() override;
 
diff --git a/chrome/browser/ui/ash/multi_user/user_switch_animator_chromeos.cc b/chrome/browser/ui/ash/multi_user/user_switch_animator_chromeos.cc
index d469dbe2..c13ba13 100644
--- a/chrome/browser/ui/ash/multi_user/user_switch_animator_chromeos.cc
+++ b/chrome/browser/ui/ash/multi_user/user_switch_animator_chromeos.cc
@@ -268,7 +268,7 @@
     if (GetScreenCover(window) != NO_USER_COVERS_SCREEN &&
         (!chrome_launcher_controller ||
          !chrome_launcher_controller->ShelfBoundsChangesProbablyWithUser(
-             shelf, new_account_id_.GetUserEmail()))) {
+             shelf, new_account_id_))) {
       shelf->shelf_widget()->HideShelfBehindBlackBar(true, duration_override);
     } else {
       // This shelf change is only part of the animation and will be updated by
diff --git a/chrome/browser/ui/autofill/chrome_autofill_client.cc b/chrome/browser/ui/autofill/chrome_autofill_client.cc
index e9d8756..b071971 100644
--- a/chrome/browser/ui/autofill/chrome_autofill_client.cc
+++ b/chrome/browser/ui/autofill/chrome_autofill_client.cc
@@ -14,7 +14,6 @@
 #include "chrome/browser/autofill/personal_data_manager_factory.h"
 #include "chrome/browser/autofill/risk_util.h"
 #include "chrome/browser/browser_process.h"
-#include "chrome/browser/infobars/infobar_service.h"
 #include "chrome/browser/password_manager/chrome_password_manager_client.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_manager.h"
@@ -62,6 +61,9 @@
 #if defined(OS_ANDROID)
 #include "base/android/context_utils.h"
 #include "chrome/browser/android/signin/signin_promo_util_android.h"
+#include "chrome/browser/infobars/infobar_service.h"
+#include "chrome/browser/ui/android/infobars/autofill_credit_card_filling_infobar.h"
+#include "components/autofill/core/browser/autofill_credit_card_filling_infobar_delegate_mobile.h"
 #include "components/autofill/core/browser/autofill_save_card_infobar_delegate_mobile.h"
 #include "components/autofill/core/browser/autofill_save_card_infobar_mobile.h"
 #include "components/infobars/core/infobar.h"
@@ -211,6 +213,22 @@
 #endif
 }
 
+void ChromeAutofillClient::ConfirmCreditCardFillAssist(
+    const CreditCard& card,
+    const base::Closure& callback) {
+#if defined(OS_ANDROID)
+  auto infobar_delegate =
+      base::MakeUnique<AutofillCreditCardFillingInfoBarDelegateMobile>(
+          card, callback);
+  auto* raw_delegate = infobar_delegate.get();
+  if (InfoBarService::FromWebContents(web_contents())->AddInfoBar(
+          base::MakeUnique<AutofillCreditCardFillingInfoBar>(
+              std::move(infobar_delegate)))) {
+    raw_delegate->set_was_shown();
+  }
+#endif
+}
+
 void ChromeAutofillClient::LoadRiskData(
     const base::Callback<void(const std::string&)>& callback) {
   ::autofill::LoadRiskData(0, web_contents(), callback);
diff --git a/chrome/browser/ui/autofill/chrome_autofill_client.h b/chrome/browser/ui/autofill/chrome_autofill_client.h
index 81791fc..70fda229 100644
--- a/chrome/browser/ui/autofill/chrome_autofill_client.h
+++ b/chrome/browser/ui/autofill/chrome_autofill_client.h
@@ -58,6 +58,8 @@
       const CreditCard& card,
       std::unique_ptr<base::DictionaryValue> legal_message,
       const base::Closure& callback) override;
+  void ConfirmCreditCardFillAssist(const CreditCard& card,
+                                   const base::Closure& callback) override;
   void LoadRiskData(
       const base::Callback<void(const std::string&)>& callback) override;
   bool HasCreditCardScanFeature() override;
diff --git a/chrome/browser/ui/browser_command_controller.cc b/chrome/browser/ui/browser_command_controller.cc
index dbfd2ca..6da32e1 100644
--- a/chrome/browser/ui/browser_command_controller.cc
+++ b/chrome/browser/ui/browser_command_controller.cc
@@ -36,6 +36,7 @@
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/browser/ui/tabs/tab_strip_model_utils.h"
 #include "chrome/browser/ui/webui/inspect_ui.h"
+#include "chrome/common/chrome_features.h"
 #include "chrome/common/content_restriction.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/common/profiling.h"
@@ -115,10 +116,6 @@
 
 namespace chrome {
 
-const base::Feature kBackspaceGoesBackFeature {
-  "BackspaceGoesBack", base::FEATURE_DISABLED_BY_DEFAULT
-};
-
 ///////////////////////////////////////////////////////////////////////////////
 // BrowserCommandController, public:
 
@@ -318,7 +315,7 @@
   switch (id) {
     // Navigation commands
     case IDC_BACKSPACE_BACK:
-      if (base::FeatureList::IsEnabled(kBackspaceGoesBackFeature))
+      if (base::FeatureList::IsEnabled(features::kBackspaceGoesBackFeature))
         GoBack(browser_, disposition);
       else
         browser_->window()->MaybeShowNewBackShortcutBubble(false);
@@ -328,7 +325,7 @@
       GoBack(browser_, disposition);
       break;
     case IDC_BACKSPACE_FORWARD:
-      if (base::FeatureList::IsEnabled(kBackspaceGoesBackFeature))
+      if (base::FeatureList::IsEnabled(features::kBackspaceGoesBackFeature))
         GoForward(browser_, disposition);
       else
         browser_->window()->MaybeShowNewBackShortcutBubble(true);
diff --git a/chrome/browser/ui/cocoa/autofill/save_card_bubble_view_bridge.mm b/chrome/browser/ui/cocoa/autofill/save_card_bubble_view_bridge.mm
index 46bf2f6e..051bd0b 100644
--- a/chrome/browser/ui/cocoa/autofill/save_card_bubble_view_bridge.mm
+++ b/chrome/browser/ui/cocoa/autofill/save_card_bubble_view_bridge.mm
@@ -284,7 +284,7 @@
 
   // Cancel button.
   base::scoped_nsobject<NSButton> cancelButton([SaveCardBubbleViewCocoa
-      makeButton:l10n_util::GetNSString(IDS_AUTOFILL_SAVE_CARD_PROMPT_DENY)]);
+      makeButton:l10n_util::GetNSString(IDS_NO_THANKS)]);
   [cancelButton setTarget:self];
   [cancelButton setAction:@selector(onCancelButton:)];
   [cancelButton setKeyEquivalent:@"\e"];
diff --git a/chrome/browser/ui/views/apps/chrome_native_app_window_views_aura_ash.cc b/chrome/browser/ui/views/apps/chrome_native_app_window_views_aura_ash.cc
index 17f832f..27594c0 100644
--- a/chrome/browser/ui/views/apps/chrome_native_app_window_views_aura_ash.cc
+++ b/chrome/browser/ui/views/apps/chrome_native_app_window_views_aura_ash.cc
@@ -20,22 +20,19 @@
 #include "ash/wm/window_state_aura.h"
 #include "chrome/browser/ui/ash/ash_util.h"
 #include "chrome/browser/ui/ash/multi_user/multi_user_context_menu.h"
+#include "services/ui/public/cpp/property_type_converters.h"
+#include "services/ui/public/cpp/window.h"
+#include "services/ui/public/interfaces/window_manager.mojom.h"
 #include "ui/aura/client/aura_constants.h"
+#include "ui/aura/mus/mus_util.h"
 #include "ui/aura/window.h"
 #include "ui/aura/window_observer.h"
 #include "ui/base/hit_test.h"
 #include "ui/base/models/simple_menu_model.h"
+#include "ui/gfx/skia_util.h"
 #include "ui/views/controls/menu/menu_runner.h"
 #include "ui/views/widget/widget.h"
 
-#if defined(MOJO_SHELL_CLIENT)
-#include "services/ui/public/cpp/property_type_converters.h"
-#include "services/ui/public/cpp/window.h"
-#include "services/ui/public/interfaces/window_manager.mojom.h"
-#include "ui/aura/mus/mus_util.h"
-#include "ui/gfx/skia_util.h"
-#endif
-
 using extensions::AppWindow;
 
 namespace {
@@ -148,11 +145,9 @@
         ash::Shell::GetContainer(ash::Shell::GetPrimaryRootWindow(),
                                  ash::kShellWindowId_ImeWindowParentContainer);
   }
-#if defined(MOJO_SHELL_CLIENT)
   init_params->mus_properties
       [ui::mojom::WindowManager::kRemoveStandardFrame_Property] =
       mojo::ConvertTo<std::vector<uint8_t>>(init_params->remove_standard_frame);
-#endif
 }
 
 void ChromeNativeAppWindowViewsAuraAsh::OnBeforePanelWidgetInit(
@@ -330,7 +325,6 @@
     const std::vector<extensions::DraggableRegion>& regions) {
   ChromeNativeAppWindowViewsAura::UpdateDraggableRegions(regions);
 
-#if defined(MOJO_SHELL_CLIENT)
   SkRegion* draggable_region = GetDraggableRegion();
   // Set the NativeAppWindow's draggable region on the mus window.
   if (draggable_region && !draggable_region->isEmpty() && widget() &&
@@ -349,5 +343,4 @@
     GetMusWindow(widget()->GetNativeWindow())
         ->SetClientArea(insets, std::move(additional_client_regions));
   }
-#endif
 }
diff --git a/chrome/browser/ui/views/autofill/save_card_bubble_views.cc b/chrome/browser/ui/views/autofill/save_card_bubble_views.cc
index 09c8f60..40e964d 100644
--- a/chrome/browser/ui/views/autofill/save_card_bubble_views.cc
+++ b/chrome/browser/ui/views/autofill/save_card_bubble_views.cc
@@ -119,7 +119,7 @@
     ui::DialogButton button) const {
   return l10n_util::GetStringUTF16(button == ui::DIALOG_BUTTON_OK
                                        ? IDS_AUTOFILL_SAVE_CARD_PROMPT_ACCEPT
-                                       : IDS_AUTOFILL_SAVE_CARD_PROMPT_DENY);
+                                       : IDS_NO_THANKS);
 }
 
 bool SaveCardBubbleViews::ShouldDefaultButtonBeBlue() const {
diff --git a/chrome/browser/ui/views/chrome_browser_main_extra_parts_views.cc b/chrome/browser/ui/views/chrome_browser_main_extra_parts_views.cc
index d89ed32c..e8e44241 100644
--- a/chrome/browser/ui/views/chrome_browser_main_extra_parts_views.cc
+++ b/chrome/browser/ui/views/chrome_browser_main_extra_parts_views.cc
@@ -9,19 +9,16 @@
 #include "components/constrained_window/constrained_window_views.h"
 
 #if defined(USE_AURA)
-#include "ui/display/screen.h"
-#include "ui/views/widget/desktop_aura/desktop_screen.h"
-#include "ui/wm/core/wm_state.h"
-#endif
-
-#if defined(USE_AURA) && defined(MOJO_SHELL_CLIENT)
 #include "content/public/common/mojo_shell_connection.h"
 #include "services/shell/public/cpp/connector.h"
 #include "services/shell/runner/common/client_util.h"
 #include "services/ui/public/cpp/input_devices/input_device_client.h"
 #include "services/ui/public/interfaces/input_devices/input_device_server.mojom.h"
+#include "ui/display/screen.h"
 #include "ui/views/mus/window_manager_connection.h"
-#endif
+#include "ui/views/widget/desktop_aura/desktop_screen.h"
+#include "ui/wm/core/wm_state.h"
+#endif  // defined(USE_AURA)
 
 ChromeBrowserMainExtraPartsViews::ChromeBrowserMainExtraPartsViews() {
 }
@@ -50,7 +47,7 @@
 }
 
 void ChromeBrowserMainExtraPartsViews::PreProfileInit() {
-#if defined(USE_AURA) && defined(MOJO_SHELL_CLIENT)
+#if defined(USE_AURA)
   content::MojoShellConnection* mojo_shell_connection =
       content::MojoShellConnection::GetForProcess();
   if (mojo_shell_connection && shell::ShellIsRemote()) {
@@ -64,6 +61,6 @@
         mojo_shell_connection->GetConnector(),
         mojo_shell_connection->GetIdentity());
   }
-#endif  // defined(USE_AURA) && defined(MOJO_SHELL_CLIENT)
+#endif  // defined(USE_AURA)
   ChromeBrowserMainExtraParts::PreProfileInit();
 }
diff --git a/chrome/browser/ui/views/chrome_browser_main_extra_parts_views.h b/chrome/browser/ui/views/chrome_browser_main_extra_parts_views.h
index fa6c657..11785f5b 100644
--- a/chrome/browser/ui/views/chrome_browser_main_extra_parts_views.h
+++ b/chrome/browser/ui/views/chrome_browser_main_extra_parts_views.h
@@ -40,8 +40,6 @@
 
 #if defined(USE_AURA)
   std::unique_ptr<wm::WMState> wm_state_;
-#endif
-#if defined(USE_AURA) && defined(MOJO_SHELL_CLIENT)
   std::unique_ptr<views::WindowManagerConnection> window_manager_connection_;
 
   // Subscribes to updates about input-devices.
diff --git a/chrome/browser/ui/views/frame/browser_non_client_frame_view_factory_views.cc b/chrome/browser/ui/views/frame/browser_non_client_frame_view_factory_views.cc
index d757f26..e83af33 100644
--- a/chrome/browser/ui/views/frame/browser_non_client_frame_view_factory_views.cc
+++ b/chrome/browser/ui/views/frame/browser_non_client_frame_view_factory_views.cc
@@ -5,7 +5,7 @@
 #include "build/build_config.h"
 #include "chrome/browser/ui/views/frame/browser_view.h"
 
-#if defined(MOJO_SHELL_CLIENT)
+#if defined(USE_AURA)
 #include "chrome/browser/ui/views/frame/browser_non_client_frame_view_mus.h"
 #include "services/shell/runner/common/client_util.h"
 #endif
@@ -27,7 +27,7 @@
 BrowserNonClientFrameView* CreateBrowserNonClientFrameView(
     BrowserFrame* frame,
     BrowserView* browser_view) {
-#if defined(MOJO_SHELL_CLIENT)
+#if defined(USE_AURA)
   if (shell::ShellIsRemote()) {
     BrowserNonClientFrameViewMus* frame_view =
         new BrowserNonClientFrameViewMus(frame, browser_view);
diff --git a/chrome/browser/ui/views/frame/native_browser_frame_factory_auralinux.cc b/chrome/browser/ui/views/frame/native_browser_frame_factory_auralinux.cc
index cd956bc..7515c03 100644
--- a/chrome/browser/ui/views/frame/native_browser_frame_factory_auralinux.cc
+++ b/chrome/browser/ui/views/frame/native_browser_frame_factory_auralinux.cc
@@ -4,19 +4,14 @@
 
 #include "chrome/browser/ui/views/frame/native_browser_frame_factory.h"
 
-#include "chrome/browser/ui/views/frame/desktop_browser_frame_auralinux.h"
-
-#if defined(MOJO_SHELL_CLIENT)
 #include "chrome/browser/ui/views/frame/browser_frame_mus.h"
+#include "chrome/browser/ui/views/frame/desktop_browser_frame_auralinux.h"
 #include "services/shell/runner/common/client_util.h"
-#endif
 
 NativeBrowserFrame* NativeBrowserFrameFactory::Create(
     BrowserFrame* browser_frame,
     BrowserView* browser_view) {
-#if defined(MOJO_SHELL_CLIENT)
   if (shell::ShellIsRemote())
     return new BrowserFrameMus(browser_frame, browser_view);
-#endif
   return new DesktopBrowserFrameAuraLinux(browser_frame, browser_view);
 }
diff --git a/chrome/browser/ui/views/frame/native_browser_frame_factory_aurawin.cc b/chrome/browser/ui/views/frame/native_browser_frame_factory_aurawin.cc
index 24d5620..c29e013 100644
--- a/chrome/browser/ui/views/frame/native_browser_frame_factory_aurawin.cc
+++ b/chrome/browser/ui/views/frame/native_browser_frame_factory_aurawin.cc
@@ -4,20 +4,14 @@
 
 #include "chrome/browser/ui/views/frame/native_browser_frame_factory.h"
 
-#include "ash/shell.h"
-#include "chrome/browser/ui/views/frame/desktop_browser_frame_aura.h"
-
-#if defined(MOJO_SHELL_CLIENT)
 #include "chrome/browser/ui/views/frame/browser_frame_mus.h"
+#include "chrome/browser/ui/views/frame/desktop_browser_frame_aura.h"
 #include "services/shell/runner/common/client_util.h"
-#endif
 
 NativeBrowserFrame* NativeBrowserFrameFactory::Create(
     BrowserFrame* browser_frame,
     BrowserView* browser_view) {
-#if defined(MOJO_SHELL_CLIENT)
   if (shell::ShellIsRemote())
     return new BrowserFrameMus(browser_frame, browser_view);
-#endif
   return new DesktopBrowserFrameAura(browser_frame, browser_view);
 }
diff --git a/chrome/browser/ui/views/frame/native_browser_frame_factory_chromeos.cc b/chrome/browser/ui/views/frame/native_browser_frame_factory_chromeos.cc
index 5bbe5d5..f9b95c7 100644
--- a/chrome/browser/ui/views/frame/native_browser_frame_factory_chromeos.cc
+++ b/chrome/browser/ui/views/frame/native_browser_frame_factory_chromeos.cc
@@ -5,18 +5,13 @@
 #include "chrome/browser/ui/views/frame/native_browser_frame_factory.h"
 
 #include "chrome/browser/ui/views/frame/browser_frame_ash.h"
-
-#if defined(MOJO_SHELL_CLIENT)
 #include "chrome/browser/ui/views/frame/browser_frame_mus.h"
 #include "services/shell/runner/common/client_util.h"
-#endif
 
 NativeBrowserFrame* NativeBrowserFrameFactory::Create(
     BrowserFrame* browser_frame,
     BrowserView* browser_view) {
-#if defined(MOJO_SHELL_CLIENT)
   if (shell::ShellIsRemote())
     return new BrowserFrameMus(browser_frame, browser_view);
-#endif
   return new BrowserFrameAsh(browser_frame, browser_view);
 }
diff --git a/chrome/browser/ui/views/status_bubble_views.cc b/chrome/browser/ui/views/status_bubble_views.cc
index e6fd0ac..036f791a 100644
--- a/chrome/browser/ui/views/status_bubble_views.cc
+++ b/chrome/browser/ui/views/status_bubble_views.cc
@@ -43,7 +43,7 @@
 #include "ash/wm/window_state_aura.h"
 #endif
 
-#if defined(MOJO_SHELL_CLIENT)
+#if defined(USE_AURA)
 #include "services/ui/public/cpp/property_type_converters.h"
 #include "services/ui/public/interfaces/window_manager.mojom.h"
 #endif
@@ -597,17 +597,17 @@
 
     views::Widget::InitParams params(views::Widget::InitParams::TYPE_POPUP);
 #if defined(OS_WIN)
-  // On Windows use the software compositor to ensure that we don't block
-  // the UI thread blocking issue during command buffer creation. We can
-  // revert this change once http://crbug.com/125248 is fixed.
-  params.force_software_compositing = true;
+    // On Windows use the software compositor to ensure that we don't block
+    // the UI thread blocking issue during command buffer creation. We can
+    // revert this change once http://crbug.com/125248 is fixed.
+    params.force_software_compositing = true;
 #endif
     params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW;
     params.accept_events = false;
     params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
     params.parent = frame->GetNativeView();
     params.context = frame->GetNativeWindow();
-#if defined(MOJO_SHELL_CLIENT)
+#if defined(USE_AURA)
     params.mus_properties
         [ui::mojom::WindowManager::kWindowIgnoredByShelf_Property] =
         mojo::ConvertTo<std::vector<uint8_t>>(true);
diff --git a/chrome/browser/ui/views/tabs/tab_drag_controller.cc b/chrome/browser/ui/views/tabs/tab_drag_controller.cc
index 97e4fc3..10261b5 100644
--- a/chrome/browser/ui/views/tabs/tab_drag_controller.cc
+++ b/chrome/browser/ui/views/tabs/tab_drag_controller.cc
@@ -49,15 +49,12 @@
 #endif
 
 #if defined(USE_AURA)
-#include "ui/aura/env.h"
-#include "ui/aura/window.h"
-#include "ui/wm/core/window_modality_controller.h"
-#endif
-
-#if defined(MOJO_SHELL_CLIENT)
 #include "chrome/browser/ui/views/tabs/window_finder_mus.h"
 #include "content/public/common/mojo_shell_connection.h"
 #include "services/shell/runner/common/client_util.h"
+#include "ui/aura/env.h"
+#include "ui/aura/window.h"
+#include "ui/wm/core/window_modality_controller.h"
 #endif
 
 using base::UserMetricsAction;
@@ -231,7 +228,7 @@
       weak_factory_(this) {
   instance_ = this;
 
-#if defined(MOJO_SHELL_CLIENT)
+#if defined(USE_AURA)
   content::MojoShellConnection* mojo_shell_connection =
       content::MojoShellConnection::GetForProcess();
   if (mojo_shell_connection && shell::ShellIsRemote())
diff --git a/chrome/browser/ui/webui/chromeos/keyboard_overlay_ui.cc b/chrome/browser/ui/webui/chromeos/keyboard_overlay_ui.cc
index 412a39a..60e40df 100644
--- a/chrome/browser/ui/webui/chromeos/keyboard_overlay_ui.cc
+++ b/chrome/browser/ui/webui/chromeos/keyboard_overlay_ui.cc
@@ -11,11 +11,13 @@
 #include "base/bind.h"
 #include "base/bind_helpers.h"
 #include "base/command_line.h"
+#include "base/feature_list.h"
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/values.h"
 #include "chrome/browser/profiles/profile.h"
+#include "chrome/common/chrome_features.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/common/url_constants.h"
 #include "chrome/grit/chromium_strings.h"
@@ -307,6 +309,9 @@
   ash::DisplayManager* display_manager = shell->display_manager();
   source->AddBoolean("keyboardOverlayIsDisplayUIScalingEnabled",
                      display_manager->IsDisplayUIScalingEnabled());
+  source->AddBoolean(
+      "backspaceGoesBackFeatureEnabled",
+      base::FeatureList::IsEnabled(features::kBackspaceGoesBackFeature));
   source->SetJsonPath("strings.js");
   source->AddResourcePath("keyboard_overlay.js", IDR_KEYBOARD_OVERLAY_JS);
   source->SetDefaultResource(IDR_KEYBOARD_OVERLAY_HTML);
diff --git a/chrome/browser/ui/webui/settings/chromeos/accessibility_handler.cc b/chrome/browser/ui/webui/settings/chromeos/accessibility_handler.cc
new file mode 100644
index 0000000..b90787d9
--- /dev/null
+++ b/chrome/browser/ui/webui/settings/chromeos/accessibility_handler.cc
@@ -0,0 +1,46 @@
+// 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 "chrome/browser/ui/webui/settings/chromeos/accessibility_handler.h"
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "chrome/browser/extensions/extension_tab_util.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/browser_finder.h"
+#include "chrome/common/extensions/extension_constants.h"
+#include "content/public/browser/web_ui.h"
+#include "extensions/browser/extension_registry.h"
+
+namespace chromeos {
+namespace settings {
+
+AccessibilityHandler::AccessibilityHandler(content::WebUI* webui)
+    : profile_(Profile::FromWebUI(webui)) {
+}
+
+AccessibilityHandler::~AccessibilityHandler() {}
+
+void AccessibilityHandler::RegisterMessages() {
+  web_ui()->RegisterMessageCallback(
+      "showChromeVoxSettings",
+      base::Bind(&AccessibilityHandler::HandleShowChromeVoxSettings,
+                 base::Unretained(this)));
+}
+
+void AccessibilityHandler::HandleShowChromeVoxSettings(
+    const base::ListValue* args) {
+  const extensions::Extension* chromevox_extension =
+      extensions::ExtensionRegistry::Get(profile_)->GetExtensionById(
+          extension_misc::kChromeVoxExtensionId,
+          extensions::ExtensionRegistry::ENABLED);
+  if (!chromevox_extension)
+    return;
+  extensions::ExtensionTabUtil::OpenOptionsPage(
+      chromevox_extension,
+      chrome::FindBrowserWithWebContents(web_ui()->GetWebContents()));
+}
+
+}  // namespace settings
+}  // namespace chromeos
diff --git a/chrome/browser/ui/webui/settings/chromeos/accessibility_handler.h b/chrome/browser/ui/webui/settings/chromeos/accessibility_handler.h
new file mode 100644
index 0000000..33e1822
--- /dev/null
+++ b/chrome/browser/ui/webui/settings/chromeos/accessibility_handler.h
@@ -0,0 +1,46 @@
+// 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 CHROME_BROWSER_UI_WEBUI_SETTINGS_CHROMEOS_ACCESSIBILITY_HANDLER_H_
+#define CHROME_BROWSER_UI_WEBUI_SETTINGS_CHROMEOS_ACCESSIBILITY_HANDLER_H_
+
+#include "base/macros.h"
+#include "chrome/browser/ui/webui/settings/settings_page_ui_handler.h"
+
+namespace base {
+class ListValue;
+}
+
+namespace content {
+class WebUI;
+}
+
+class Profile;
+
+namespace chromeos {
+namespace settings {
+
+class AccessibilityHandler : public ::settings::SettingsPageUIHandler {
+ public:
+  explicit AccessibilityHandler(content::WebUI* webui);
+  ~AccessibilityHandler() override;
+
+  // SettingsPageUIHandler implementation.
+  void RegisterMessages() override;
+  void OnJavascriptAllowed() override {}
+  void OnJavascriptDisallowed() override {}
+
+ private:
+  // Callback for the "showChromeVoxSettings" message.
+  void HandleShowChromeVoxSettings(const base::ListValue* args);
+
+  Profile* profile_;  // Weak pointer.
+
+  DISALLOW_COPY_AND_ASSIGN(AccessibilityHandler);
+};
+
+}  // namespace settings
+}  // namespace chromeos
+
+#endif  // CHROME_BROWSER_UI_WEBUI_SETTINGS_CHROMEOS_ACCESSIBILITY_HANDLER_H_
diff --git a/chrome/browser/ui/webui/settings/chromeos/cups_printers_handler.cc b/chrome/browser/ui/webui/settings/chromeos/cups_printers_handler.cc
new file mode 100644
index 0000000..c37eec2
--- /dev/null
+++ b/chrome/browser/ui/webui/settings/chromeos/cups_printers_handler.cc
@@ -0,0 +1,102 @@
+// 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 "chrome/browser/ui/webui/settings/chromeos/cups_printers_handler.h"
+
+#include <memory>
+
+#include "base/bind.h"
+#include "base/memory/ref_counted.h"
+#include "base/values.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/web_ui.h"
+#include "printing/backend/print_backend.h"
+
+namespace {
+
+// TODO(xdai): Retrieve the CUPS printers list from user preference instead.
+void EnumeratePrintersOnBlockingPoolThread(base::ListValue* printers) {
+  scoped_refptr<printing::PrintBackend> print_backend(
+      printing::PrintBackend::CreateInstance(nullptr));
+
+  printing::PrinterList printer_list;
+  print_backend->EnumeratePrinters(&printer_list);
+
+  for (const printing::PrinterBasicInfo& printer : printer_list) {
+    std::unique_ptr<base::DictionaryValue> printer_info(
+        new base::DictionaryValue);
+    printer_info->SetString("printerName", printer.printer_name);
+    printer_info->SetString("printerDescription", printer.printer_description);
+    for (const auto opt_it : printer.options) {
+      // TODO(xdai): Get "printerAddress" and "printerProtocol" from URI.
+      if (opt_it.first == "printer-make-and-model")
+        printer_info->SetString("printerModel", opt_it.second);
+    }
+    printers->Append(std::move(printer_info));
+  }
+}
+
+}  // namespace
+
+namespace chromeos {
+namespace settings {
+
+CupsPrintersHandler::CupsPrintersHandler() : weak_factory_(this) {}
+
+CupsPrintersHandler::~CupsPrintersHandler() {}
+
+void CupsPrintersHandler::RegisterMessages() {
+  web_ui()->RegisterMessageCallback(
+      "getCupsPrintersList",
+      base::Bind(&CupsPrintersHandler::HandleGetCupsPrintersList,
+                 base::Unretained(this)));
+  web_ui()->RegisterMessageCallback(
+      "updateCupsPrinter",
+      base::Bind(&CupsPrintersHandler::HandleUpdateCupsPrinter,
+                 base::Unretained(this)));
+  web_ui()->RegisterMessageCallback(
+      "removeCupsPrinter",
+      base::Bind(&CupsPrintersHandler::HandleRemoveCupsPrinter,
+                 base::Unretained(this)));
+}
+
+// TODO(xdai): Retrieve the CUPS printer list from user preference instead after
+// the CL https://codereview.chromium.org/2161933003/ is landed.
+void CupsPrintersHandler::HandleGetCupsPrintersList(
+    const base::ListValue* args) {
+  AllowJavascript();
+
+  CHECK_EQ(1U, args->GetSize());
+  std::string callback_id;
+  CHECK(args->GetString(0, &callback_id));
+
+  base::ListValue* printers_list = new base::ListValue;
+  content::BrowserThread::PostBlockingPoolTaskAndReply(
+      FROM_HERE, base::Bind(&EnumeratePrintersOnBlockingPoolThread,
+                            base::Unretained(printers_list)),
+      base::Bind(&CupsPrintersHandler::OnGetCupsPrintersList,
+                 weak_factory_.GetWeakPtr(), callback_id,
+                 base::Owned(printers_list)));
+}
+
+void CupsPrintersHandler::OnGetCupsPrintersList(
+    const std::string callback_id,
+    base::ListValue* printers_list) {
+  std::unique_ptr<base::DictionaryValue> response(new base::DictionaryValue());
+  response->Set("printerList", printers_list->DeepCopy());
+  ResolveJavascriptCallback(base::StringValue(callback_id), *response);
+}
+
+void CupsPrintersHandler::HandleUpdateCupsPrinter(const base::ListValue* args) {
+  // TODO(xdai): Implement it after https://codereview.chromium.org/2161933003/
+  // is landed.
+}
+
+void CupsPrintersHandler::HandleRemoveCupsPrinter(const base::ListValue* args) {
+  // TODO(xdai): Implement it after https://codereview.chromium.org/2161933003/
+  // is landed.
+}
+
+}  // namespace settings
+}  // namespace chromeos
diff --git a/chrome/browser/ui/webui/settings/chromeos/cups_printers_handler.h b/chrome/browser/ui/webui/settings/chromeos/cups_printers_handler.h
new file mode 100644
index 0000000..375ae715
--- /dev/null
+++ b/chrome/browser/ui/webui/settings/chromeos/cups_printers_handler.h
@@ -0,0 +1,46 @@
+// 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 CHROME_BROWSER_UI_WEBUI_SETTINGS_CHROMEOS_CUPS_PRINTERS_HANDLER_H_
+#define CHROME_BROWSER_UI_WEBUI_SETTINGS_CHROMEOS_CUPS_PRINTERS_HANDLER_H_
+
+#include "base/memory/weak_ptr.h"
+#include "chrome/browser/ui/webui/settings/settings_page_ui_handler.h"
+
+namespace base {
+class ListValue;
+}  // namespace base
+
+namespace chromeos {
+namespace settings {
+
+// Chrome OS CUPS printing settings page UI handler.
+class CupsPrintersHandler : public ::settings::SettingsPageUIHandler {
+ public:
+  CupsPrintersHandler();
+  ~CupsPrintersHandler() override;
+
+  // SettingsPageUIHandler overrides:
+  void RegisterMessages() override;
+  void OnJavascriptAllowed() override{};
+  void OnJavascriptDisallowed() override{};
+
+ private:
+  // Gets all CUPS printers and return it to WebUI.
+  void HandleGetCupsPrintersList(const base::ListValue* args);
+  void OnGetCupsPrintersList(const std::string callback_id,
+                             base::ListValue* printers_list);
+
+  void HandleUpdateCupsPrinter(const base::ListValue* args);
+  void HandleRemoveCupsPrinter(const base::ListValue* args);
+
+  base::WeakPtrFactory<CupsPrintersHandler> weak_factory_;
+
+  DISALLOW_COPY_AND_ASSIGN(CupsPrintersHandler);
+};
+
+}  // namespace settings
+}  // namespace chromeos
+
+#endif  // CHROME_BROWSER_UI_WEBUI_SETTINGS_CHROMEOS_CUPS_PRINTERS_HANDLER_H_
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 b7ee8352..111a1258f 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
@@ -113,10 +113,44 @@
      IDS_OPTIONS_SETTINGS_ACCESSIBILITY_CURSOR_HIGHLIGHT_DESCRIPTION},
     {"focusHighlightLabel",
      IDS_OPTIONS_SETTINGS_ACCESSIBILITY_FOCUS_HIGHLIGHT_DESCRIPTION},
-    {"selectToSpeakLabel",
+    {"selectToSpeakTitle",
+     IDS_OPTIONS_SETTINGS_ACCESSIBILITY_SELECT_TO_SPEAK_TITLE},
+    {"selectToSpeakDescription",
      IDS_OPTIONS_SETTINGS_ACCESSIBILITY_SELECT_TO_SPEAK_DESCRIPTION},
     {"switchAccessLabel",
      IDS_OPTIONS_SETTINGS_ACCESSIBILITY_SWITCH_ACCESS_DESCRIPTION},
+    {"manageAccessibilityFeatures",
+     IDS_OPTIONS_SETTINGS_ACCESSIBILITY_MANAGE_ACCESSIBILITY_FEATURES},
+    {"textToSpeechHeading",
+     IDS_OPTIONS_SETTINGS_ACCESSIBILITY_TEXT_TO_SPEECH_HEADING},
+    {"displayHeading",
+     IDS_OPTIONS_SETTINGS_ACCESSIBILITY_DISPLAY_HEADING},
+    {"displaySettingsTitle",
+     IDS_OPTIONS_SETTINGS_ACCESSIBILITY_DISPLAY_SETTINGS_TITLE},
+    {"displaySettingsDescription",
+     IDS_OPTIONS_SETTINGS_ACCESSIBILITY_DISPLAY_SETTINGS_DESCRIPTION},
+    {"appearanceSettingsTitle",
+     IDS_OPTIONS_SETTINGS_ACCESSIBILITY_APPEARANCE_SETTINGS_TITLE},
+    {"appearanceSettingsDescription",
+     IDS_OPTIONS_SETTINGS_ACCESSIBILITY_APPEARANCE_SETTINGS_DESCRIPTION},
+    {"keyboardHeading",
+     IDS_OPTIONS_SETTINGS_ACCESSIBILITY_KEYBOARD_HEADING},
+    {"keyboardSettingsTitle",
+     IDS_OPTIONS_SETTINGS_ACCESSIBILITY_KEYBOARD_SETTINGS_TITLE},
+    {"keyboardSettingsDescription",
+     IDS_OPTIONS_SETTINGS_ACCESSIBILITY_KEYBOARD_SETTINGS_DESCRIPTION},
+    {"mouseAndTouchpadHeading",
+     IDS_OPTIONS_SETTINGS_ACCESSIBILITY_MOUSE_AND_TOUCHPAD_HEADING},
+    {"mouseSettingsTitle",
+     IDS_OPTIONS_SETTINGS_ACCESSIBILITY_MOUSE_SETTINGS_TITLE},
+    {"mouseSettingsDescription",
+     IDS_OPTIONS_SETTINGS_ACCESSIBILITY_MOUSE_SETTINGS_DESCRIPTION},
+    {"audioHeading",
+     IDS_OPTIONS_SETTINGS_ACCESSIBILITY_AUDIO_HEADING},
+    {"additionalFeaturesTitle",
+     IDS_OPTIONS_SETTINGS_ACCESSIBILITY_ADDITIONAL_FEATURES_TITLE},
+    {"additionalFeaturesDescription",
+     IDS_OPTIONS_SETTINGS_ACCESSIBILITY_ADDITIONAL_FEATURES_DESCRIPTION},
 #endif
   };
   AddLocalizedStringsBulk(html_source, localized_strings,
@@ -944,6 +978,16 @@
     {"cloudPrintersTitle", IDS_SETTINGS_PRINTING_CLOUD_PRINTERS},
 #if defined(OS_CHROMEOS)
     {"cupsPrintersTitle", IDS_SETTINGS_PRINTING_CUPS_PRINTERS},
+    {"addCupsPrinter", IDS_SETTINGS_PRINTING_CUPS_PRINTERS_ADD_PRINTER},
+    {"cupsPrinterDetails", IDS_SETTINGS_PRINTING_CUPS_PRINTERS_DETAILS},
+    {"removePrinter", IDS_SETTINGS_PRINTING_CUPS_PRINTERS_REMOVE},
+    {"searchLabel", IDS_SETTINGS_PRINTING_CUPS_SEARCH_LABEL},
+    {"printerDetailsTitle", IDS_SETTINGS_PRINTING_CUPS_PRINTER_DETAILS_TITLE},
+    {"printerName", IDS_SETTINGS_PRINTING_CUPS_PRINTER_DETAILS_NAME},
+    {"printerModel", IDS_SETTINGS_PRINTING_CUPS_PRINTER_DETAILS_MODEL},
+    {"addPrinterTitle", IDS_SETTINGS_PRINTING_CUPS_ADD_PRINTER_TITLE},
+    {"cancelButtonText", IDS_SETTINGS_PRINTING_CUPS_ADD_PRINTER_BUTTON_CANCEL},
+    {"addPrinterButtonText", IDS_SETTINGS_PRINTING_CUPS_ADD_PRINTER_BUTTON_ADD},
 #endif
   };
   AddLocalizedStringsBulk(html_source, localized_strings,
@@ -1116,8 +1160,6 @@
       {"siteSettingsCategoryNotifications",
        IDS_SETTINGS_SITE_SETTINGS_NOTIFICATIONS},
       {"siteSettingsCategoryPopups", IDS_SETTINGS_SITE_SETTINGS_POPUPS},
-      {"siteSettingsSiteDetailsPageTitle",
-       IDS_SETTINGS_SITE_SETTINGS_SITE_DETAILS},
       {"siteSettingsAllSites", IDS_SETTINGS_SITE_SETTINGS_ALL_SITES},
       {"siteSettingsAutomaticDownloads",
        IDS_SETTINGS_SITE_SETTINGS_AUTOMATIC_DOWNLOADS},
diff --git a/chrome/browser/ui/webui/settings/md_settings_ui.cc b/chrome/browser/ui/webui/settings/md_settings_ui.cc
index 7f90eb2..256485f4 100644
--- a/chrome/browser/ui/webui/settings/md_settings_ui.cc
+++ b/chrome/browser/ui/webui/settings/md_settings_ui.cc
@@ -38,7 +38,9 @@
 #if defined(OS_CHROMEOS)
 #include "ash/common/system/chromeos/palette/palette_utils.h"
 #include "chrome/browser/chromeos/login/quick_unlock/quick_unlock_utils.h"
+#include "chrome/browser/ui/webui/settings/chromeos/accessibility_handler.h"
 #include "chrome/browser/ui/webui/settings/chromeos/change_picture_handler.h"
+#include "chrome/browser/ui/webui/settings/chromeos/cups_printers_handler.h"
 #include "chrome/browser/ui/webui/settings/chromeos/device_keyboard_handler.h"
 #include "chrome/browser/ui/webui/settings/chromeos/device_pointer_handler.h"
 #include "chrome/browser/ui/webui/settings/chromeos/easy_unlock_settings_handler.h"
@@ -83,7 +85,10 @@
   AddSettingsPageUIHandler(new StartupPagesHandler(web_ui));
 
 #if defined(OS_CHROMEOS)
+  AddSettingsPageUIHandler(new chromeos::settings::AccessibilityHandler(
+      web_ui));
   AddSettingsPageUIHandler(new chromeos::settings::ChangePictureHandler());
+  AddSettingsPageUIHandler(new chromeos::settings::CupsPrintersHandler());
   AddSettingsPageUIHandler(new chromeos::settings::KeyboardHandler(web_ui));
   AddSettingsPageUIHandler(new chromeos::settings::PointerHandler());
 #else
diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi
index 450c826..0de83b5 100644
--- a/chrome/chrome_browser.gypi
+++ b/chrome/chrome_browser.gypi
@@ -2120,6 +2120,7 @@
       'android/java/src/org/chromium/chrome/browser/WebContentsFactory.java',
       'android/java/src/org/chromium/chrome/browser/infobar/AppBannerInfoBarAndroid.java',
       'android/java/src/org/chromium/chrome/browser/infobar/AppBannerInfoBarDelegateAndroid.java',
+      'android/java/src/org/chromium/chrome/browser/infobar/AutofillCreditCardFillingInfoBar.java',
       'android/java/src/org/chromium/chrome/browser/infobar/AutofillSaveCardInfoBar.java',
       'android/java/src/org/chromium/chrome/browser/infobar/ConfirmInfoBar.java',
       'android/java/src/org/chromium/chrome/browser/infobar/DataReductionPromoInfoBarDelegate.java',
diff --git a/chrome/chrome_browser_ui.gypi b/chrome/chrome_browser_ui.gypi
index 6908eef..6e6c0ad3 100644
--- a/chrome/chrome_browser_ui.gypi
+++ b/chrome/chrome_browser_ui.gypi
@@ -429,6 +429,8 @@
       'browser/ui/android/context_menu_helper.h',
       'browser/ui/android/infobars/app_banner_infobar_android.cc',
       'browser/ui/android/infobars/app_banner_infobar_android.h',
+      'browser/ui/android/infobars/autofill_credit_card_filling_infobar.cc',
+      'browser/ui/android/infobars/autofill_credit_card_filling_infobar.h',
       'browser/ui/android/infobars/autofill_save_card_infobar.cc',
       'browser/ui/android/infobars/autofill_save_card_infobar.h',
       'browser/ui/android/infobars/confirm_infobar.cc',
@@ -2043,8 +2045,12 @@
       'browser/ui/webui/settings/appearance_handler.h',
       'browser/ui/webui/settings/browser_lifetime_handler.cc',
       'browser/ui/webui/settings/browser_lifetime_handler.h',
+      'browser/ui/webui/settings/chromeos/accessibility_handler.cc',
+      'browser/ui/webui/settings/chromeos/accessibility_handler.h',
       'browser/ui/webui/settings/chromeos/change_picture_handler.cc',
       'browser/ui/webui/settings/chromeos/change_picture_handler.h',
+      'browser/ui/webui/settings/chromeos/cups_printers_handler.cc',
+      'browser/ui/webui/settings/chromeos/cups_printers_handler.h',
       'browser/ui/webui/settings/chromeos/device_keyboard_handler.cc',
       'browser/ui/webui/settings/chromeos/device_keyboard_handler.h',
       'browser/ui/webui/settings/chromeos/device_pointer_handler.cc',
diff --git a/chrome/chrome_tests_unit.gypi b/chrome/chrome_tests_unit.gypi
index e6d7f1d..0190250a 100644
--- a/chrome/chrome_tests_unit.gypi
+++ b/chrome/chrome_tests_unit.gypi
@@ -359,6 +359,7 @@
       '../tools/json_schema_compiler/test/simple_api_unittest.cc',
     ],
     'chrome_unit_tests_android_sources': [
+      'browser/autofill/autofill_credit_card_filling_infobar_delegate_mobile_unittest.cc',
       'browser/autofill/autofill_save_card_infobar_delegate_mobile_unittest.cc',
       'browser/password_manager/account_chooser_dialog_android_unittest.cc',
       'browser/password_manager/auto_signin_first_run_dialog_android_unittest.cc',
diff --git a/chrome/common/chrome_features.cc b/chrome/common/chrome_features.cc
index c8317f2..eb692fcb 100644
--- a/chrome/common/chrome_features.cc
+++ b/chrome/common/chrome_features.cc
@@ -28,6 +28,12 @@
     "BackgroundModeAllowRestart", base::FEATURE_DISABLED_BY_DEFAULT};
 #endif  // defined(OS_WIN) || defined(OS_LINUX)
 
+// Enables the Backspace key to navigate back in the browser, as well as
+// Shift+Backspace to navigate forward.
+const base::Feature kBackspaceGoesBackFeature {
+  "BackspaceGoesBack", base::FEATURE_DISABLED_BY_DEFAULT
+};
+
 // Experiment to disable small cross-origin content. (http://crbug.com/608886)
 const base::Feature kBlockSmallContent{"BlockSmallPluginContent",
                                        base::FEATURE_DISABLED_BY_DEFAULT};
diff --git a/chrome/common/chrome_features.h b/chrome/common/chrome_features.h
index 3471c2d86..aa7ebdc 100644
--- a/chrome/common/chrome_features.h
+++ b/chrome/common/chrome_features.h
@@ -27,6 +27,8 @@
 extern const base::Feature kBackgroundModeAllowRestart;
 #endif  // defined(OS_WIN) || defined(OS_LINUX)
 
+extern const base::Feature kBackspaceGoesBackFeature;
+
 extern const base::Feature kBlockSmallContent;
 
 extern const base::Feature kBrowserHangFixesExperiment;
diff --git a/chrome/installer/mini_installer/BUILD.gn b/chrome/installer/mini_installer/BUILD.gn
index 530e68c..1e269aa 100644
--- a/chrome/installer/mini_installer/BUILD.gn
+++ b/chrome/installer/mini_installer/BUILD.gn
@@ -233,6 +233,7 @@
     configs += [
       ":mini_installer_compiler_flags",
       "//build/config/compiler:optimize_no_wpo",
+      "//build/config/sanitizers:link_executable",
       "//build/config/win:sdk_link",
       "//build/config/win:windowed",
     ]
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index 14d3200f..1e99e3a 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -900,8 +900,6 @@
       "//chrome/app:mojo_manifests",
       "//mash/session",
     ]
-
-    defines = [ "MOJO_SHELL_CLIENT" ]
   }
 }
 
diff --git a/chrome/test/android/BUILD.gn b/chrome/test/android/BUILD.gn
index 4a276973..ce1ad49 100644
--- a/chrome/test/android/BUILD.gn
+++ b/chrome/test/android/BUILD.gn
@@ -63,6 +63,7 @@
     "//base:base_java_test_support",
     "//chrome/android:chrome_java",
     "//chrome/android/webapk/libs/runtime_library:runtime_library_for_tests_java",
+    "//chrome/android/webapk/libs/runtime_library:webapk_service_aidl_java",
     "//components/bookmarks/common/android:bookmarks_java",
     "//components/invalidation/impl:java",
     "//components/location/android:location_java",
diff --git a/chrome/test/base/browser_tests_main.cc b/chrome/test/base/browser_tests_main.cc
index cd12f3b..614091d 100644
--- a/chrome/test/base/browser_tests_main.cc
+++ b/chrome/test/base/browser_tests_main.cc
@@ -8,12 +8,12 @@
 #include "chrome/test/base/chrome_test_launcher.h"
 #include "chrome/test/base/chrome_test_suite.h"
 
-#if defined(MOJO_SHELL_CLIENT)
+#if defined(USE_AURA)
 #include "chrome/test/base/mash_browser_tests_main.h"
 #endif
 
 int main(int argc, char** argv) {
-#if defined(MOJO_SHELL_CLIENT)
+#if defined(USE_AURA)
   int exit_code = 0;
   if (RunMashBrowserTests(argc, argv, &exit_code))
     return exit_code;
diff --git a/chrome/test/data/extensions/theme/manifest.json b/chrome/test/data/extensions/theme/manifest.json
index ce99ab9c..48500b81 100644
--- a/chrome/test/data/extensions/theme/manifest.json
+++ b/chrome/test/data/extensions/theme/manifest.json
@@ -1,5 +1,6 @@
 {
    "name": "camo theme",
+   "manifest_version": 2,
    "theme": {
       "colors": {
          "frame": [ 71, 105, 91 ],
diff --git a/chrome/test/data/webui/settings/controlled_button_tests.js b/chrome/test/data/webui/settings/controlled_button_tests.js
new file mode 100644
index 0000000..edde16b
--- /dev/null
+++ b/chrome/test/data/webui/settings/controlled_button_tests.js
@@ -0,0 +1,38 @@
+// 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.
+
+suite('controlled button', function() {
+  /** @type {ControlledButtonElement} */
+  var button;
+
+  /** @type {!chrome.settingsPrivate.PrefObject} */
+  var pref = {
+    key: 'test',
+    type: chrome.settingsPrivate.PrefType.BOOLEAN,
+    value: true
+  };
+
+  setup(function() {
+    PolymerTest.clearBody();
+    button = document.createElement('controlled-button');
+    button.pref = pref;
+    document.body.appendChild(button);
+  });
+
+  test('disables when pref is managed', function() {
+    button.set('pref.policyEnforcement',
+               chrome.settingsPrivate.PolicyEnforcement.ENFORCED);
+    Polymer.dom.flush();
+    assertTrue(button.$$('paper-button').disabled);
+
+    var indicator = button.$$('cr-policy-pref-indicator');
+    assertTrue(!!indicator);
+    assertGT(indicator.clientHeight, 0);
+
+    button.set('pref.policyEnforcement', undefined);
+    Polymer.dom.flush();
+    assertFalse(button.$$('paper-button').disabled);
+    assertEquals(0, indicator.clientHeight);
+  });
+});
diff --git a/chrome/test/data/webui/settings/cr_settings_browsertest.js b/chrome/test/data/webui/settings/cr_settings_browsertest.js
index 26f76c0..926d7b8 100644
--- a/chrome/test/data/webui/settings/cr_settings_browsertest.js
+++ b/chrome/test/data/webui/settings/cr_settings_browsertest.js
@@ -621,28 +621,6 @@
  * @constructor
  * @extends {CrSettingsBrowserTest}
  */
-function CrSettingsRadioGroupTest() {}
-
-CrSettingsRadioGroupTest.prototype = {
-  __proto__: CrSettingsBrowserTest.prototype,
-
-  /** @override */
-  browsePreload: 'chrome://md-settings/controls/settings_radio_group.html',
-
-  /** @override */
-  extraLibraries: CrSettingsBrowserTest.prototype.extraLibraries.concat([
-    'radio_group_tests.js',
-  ]),
-};
-
-TEST_F('CrSettingsRadioGroupTest', 'All', function() {
-  mocha.run();
-});
-
-/**
- * @constructor
- * @extends {CrSettingsBrowserTest}
- */
 function CrSettingsRouteTest() {}
 
 CrSettingsRouteTest.prototype = {
@@ -663,7 +641,7 @@
 /**
  * @constructor
  * @extends {SettingsPageBrowserTest}
-*/
+ */
 function CrSettingsNonExistentRouteTest() {}
 
 CrSettingsNonExistentRouteTest.prototype = {
@@ -724,3 +702,48 @@
   });
   mocha.run();
 });
+
+/**
+ * Test fixture for chrome/browser/resources/settings/settings_main/.
+ * @constructor
+ * @extends {CrSettingsBrowserTest}
+*/
+function CrSettingsMainPageTest() {}
+
+CrSettingsMainPageTest.prototype = {
+  __proto__: CrSettingsBrowserTest.prototype,
+
+  /** @override */
+  browsePreload: 'chrome://md-settings/settings_main/settings_main.html',
+
+  /** @override */
+  extraLibraries: CrSettingsBrowserTest.prototype.extraLibraries.concat([
+    'settings_main_test.js',
+  ]),
+};
+
+TEST_F('CrSettingsMainPageTest', 'All', function() {
+  settings_main_page.registerTests();
+  mocha.run();
+});
+
+/**
+ * @constructor
+ * @extends {CrSettingsBrowserTest}
+ */
+function CrControlledButtonTest() {}
+
+CrControlledButtonTest.prototype = {
+  __proto__: CrSettingsBrowserTest.prototype,
+
+  /** @override */
+  browsePreload: 'chrome://md-settings/controls/controlled_button.html',
+
+  extraLibraries: CrSettingsBrowserTest.prototype.extraLibraries.concat([
+    'controlled_button_tests.js',
+  ]),
+};
+
+TEST_F('CrControlledButtonTest', 'All', function() {
+  mocha.run();
+});
diff --git a/chrome/test/data/webui/settings/radio_group_tests.js b/chrome/test/data/webui/settings/radio_group_tests.js
deleted file mode 100644
index 5c8083f..0000000
--- a/chrome/test/data/webui/settings/radio_group_tests.js
+++ /dev/null
@@ -1,47 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-suite('SettingsRadioGroup', function() {
-  /**
-   * Checkbox created before each test.
-   * @type {SettingsRadioGroup}
-   */
-  var testElement;
-
-  /**
-   * Pref value used in tests, should reflect checkbox 'checked' attribute.
-   * @type {PrefObject}
-   */
-  var pref = {
-    key: 'test',
-    type: chrome.settingsPrivate.PrefType.BOOLEAN,
-    value: true
-  };
-
-  suiteSetup(function() {
-    return PolymerTest.importHtml('chrome://resources/polymer/v1_0/' +
-                                  'paper-radio-button/paper-radio-button.html');
-  });
-
-  setup(function() {
-    PolymerTest.clearBody();
-    testElement = document.createElement('settings-radio-group');
-    testElement.set('pref', pref);
-    document.body.appendChild(testElement);
-  });
-
-  test('disables paper-radio-buttons when managed', function() {
-    testElement.appendChild(document.createElement('paper-radio-button'));
-
-    assertEquals('PAPER-RADIO-BUTTON', testElement.firstChild.tagName);
-    assertFalse(testElement.firstChild.disabled);
-
-    testElement.set('pref.policyEnforcement',
-                    chrome.settingsPrivate.PolicyEnforcement.ENFORCED);
-    assertTrue(testElement.firstChild.disabled);
-
-    testElement.set('pref.policyEnforcement', undefined);
-    assertFalse(testElement.firstChild.disabled);
-  });
-});
diff --git a/chrome/test/data/webui/settings/settings_main_test.js b/chrome/test/data/webui/settings/settings_main_test.js
new file mode 100644
index 0000000..e058e921
--- /dev/null
+++ b/chrome/test/data/webui/settings/settings_main_test.js
@@ -0,0 +1,104 @@
+// 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.
+
+cr.define('settings_main_page', function() {
+  /**
+   * @implements {SearchManager}
+   */
+  var TestSearchManager = function() {
+    /** @private {boolean} */
+    this.matchesFound_ = true;
+
+    /** @private {?settings.SearchRequest} */
+    this.searchRequest_ = null;
+  }
+
+  TestSearchManager.prototype = {
+    /**
+     * @param {boolean} matchesFound
+     */
+    setMatchesFound: function(matchesFound) {
+      this.matchesFound_ = matchesFound;
+    },
+
+    /** @override */
+    search: function(text, page) {
+      if (this.searchRequest_ == null || !this.searchRequest_.isSame(text)) {
+        this.searchRequest_ = new settings.SearchRequest(text);
+        this.searchRequest_.finished = true;
+        this.searchRequest_.updateMatches(this.matchesFound_);
+        this.searchRequest_.resolver.resolve(this.searchRequest_);
+      }
+      return this.searchRequest_.resolver.promise;
+    },
+  };
+
+  function registerTests() {
+    var settingsPrefs = null;
+
+    suiteSetup(function() {
+      settingsPrefs = document.createElement('settings-prefs');
+      return CrSettingsPrefs.initialized;
+    });
+
+    suite('SearchTests', function() {
+      /** @type {?TestSearchManager} */
+      var searchManager = null;
+
+      /** @type {?SettingsMainElement} */
+      var settingsMain = null;
+
+      // TODO(tommycli): Remove once settings.navigateTo is no longer a stub.
+      settings.navigateTo = function(route) {
+        settingsMain.currentRoute = route;
+      };
+
+      setup(function() {
+        searchManager = new TestSearchManager();
+        settings.setSearchManagerForTesting(searchManager);
+        PolymerTest.clearBody();
+        settingsMain = document.createElement('settings-main');
+        settingsMain.prefs = settingsPrefs.prefs;
+        settingsMain.toolbarSpinnerActive = false;
+        document.body.appendChild(settingsMain);
+      });
+
+      teardown(function() { settingsMain.remove(); });
+
+      test('no results page shows and hides', function() {
+        var noSearchResults = settingsMain.$.noSearchResults;
+        assertTrue(!!noSearchResults);
+        assertTrue(noSearchResults.hidden);
+
+        searchManager.setMatchesFound(false);
+        return settingsMain.searchContents('Query1').then(function() {
+          assertFalse(noSearchResults.hidden);
+
+          searchManager.setMatchesFound(true);
+          return settingsMain.searchContents('Query2');
+        }).then(function() {
+          assertTrue(noSearchResults.hidden);
+        });
+      });
+
+      // Ensure that when the user clears the search box, the "no results" page
+      // is hidden.
+      test('no results page hides on clear', function() {
+        var noSearchResults = settingsMain.$.noSearchResults;
+        assertTrue(!!noSearchResults);
+        assertTrue(noSearchResults.hidden);
+        searchManager.setMatchesFound(false);
+
+        // Clearing the search box is effectively a search for the empty string.
+        return settingsMain.searchContents('').then(function() {
+          assertTrue(noSearchResults.hidden);
+        });
+      });
+    });
+  }
+
+  return {
+    registerTests: registerTests,
+  };
+});
diff --git a/chrome/tools/build/win/FILES.cfg b/chrome/tools/build/win/FILES.cfg
index 827e599..f1783d8 100644
--- a/chrome/tools/build/win/FILES.cfg
+++ b/chrome/tools/build/win/FILES.cfg
@@ -521,11 +521,6 @@
     'buildtype': ['dev', 'official'],
     'optional': ['dev', 'official'],
   },
-  {
-    'filename': 'sync_unit_tests.exe',
-    'buildtype': ['official'],
-    'optional': ['official'],
-  },
   # Installer files (official build only):
   {
     'filename': 'setup.exe',
diff --git a/chromecast/BUILD.gn b/chromecast/BUILD.gn
index 6b817bcb..8e1c18e 100644
--- a/chromecast/BUILD.gn
+++ b/chromecast/BUILD.gn
@@ -40,7 +40,6 @@
     "//ppapi:ppapi_unittests",
     "//sandbox/linux:sandbox_linux_unittests",
     "//sql:sql_unittests",
-    "//components/sync:sync_unit_tests",
     "//third_party/cacheinvalidation:cacheinvalidation_unittests",
     "//ui/base:ui_base_unittests",
   ]
@@ -85,7 +84,6 @@
       #   SoundsManagerTest.Play
       # Disable AudioStreamHandlerTest.ConsecutivePlayRequests (b/16539293)
       "media_unittests --gtest_filter=-AudioOutputControllerTest.PlayDivertSwitchDeviceRevertClose:AudioOutputControllerTest.PlaySwitchDeviceClose:AudioStreamHandlerTest.Play:AudioStreamHandlerTest.ConsecutivePlayRequests:PipelineIntegrationTest.BasicPlayback_MediaSource_VP9_WebM:PipelineIntegrationTest.BasicPlayback_VideoOnly_VP9_WebM:PipelineIntegrationTest.BasicPlayback_VP9*:PipelineIntegrationTest.P444_VP9_WebM:PipelineIntegrationTest.BasicPlayback_VP8A*:OpusAudioDecoderTest/AudioDecoderTest.ProduceAudioSamples/0:SoundsManagerTest.Play",
-      "sync_unit_tests --gtest_filter=-SyncHttpBridgeTest.*",
 
       # DoAppendUTF8Invalid fails because of dcheck_always_on flag in Eng builds
       "url_unittests --gtest_filter=-URLCanonTest.DoAppendUTF8Invalid",
diff --git a/chromecast/base/BUILD.gn b/chromecast/base/BUILD.gn
index 54eb36a..ab77bca 100644
--- a/chromecast/base/BUILD.gn
+++ b/chromecast/base/BUILD.gn
@@ -14,11 +14,6 @@
   # Denotes the type of Cast product. This is #defined as CAST_PRODUCT_TYPE in
   # version.h. This is an integer in the range [0-4].
   cast_product_type = 0
-
-  # If true, IS_CAST_DEBUG_BUILD() will evaluate to 1 in version.h. Otherwise,
-  # it will evaluate to 0. Overriding this when is_debug=false is useful for
-  # doing engineering builds.
-  cast_is_debug = is_debug
 }
 
 assert(cast_product_type >= 0 && cast_product_type <= 4)
diff --git a/chromecast/chromecast.gni b/chromecast/chromecast.gni
index b327f79d..9e5a6ba 100644
--- a/chromecast/chromecast.gni
+++ b/chromecast/chromecast.gni
@@ -17,6 +17,11 @@
   # than any value the builder may assign to prevent attempted automatic updates
   # when the default value is used.
   cast_build_incremental = "999999"
+
+  # If true, IS_CAST_DEBUG_BUILD() will evaluate to 1 in version.h. Otherwise,
+  # it will evaluate to 0. Overriding this when is_debug=false is useful for
+  # doing engineering builds.
+  cast_is_debug = is_debug
 }
 
 declare_args() {
diff --git a/chromecast/chromecast_tests.gypi b/chromecast/chromecast_tests.gypi
index 68e6d47..cac841a 100644
--- a/chromecast/chromecast_tests.gypi
+++ b/chromecast/chromecast_tests.gypi
@@ -110,7 +110,6 @@
         '../ppapi/ppapi_internal.gyp:ppapi_unittests',
         '../sandbox/sandbox.gyp:sandbox_linux_unittests',
         '../sql/sql.gyp:sql_unittests',
-        '../components/sync.gyp:sync_unit_tests',
         '../third_party/cacheinvalidation/cacheinvalidation.gyp:cacheinvalidation_unittests',
         '../ui/base/ui_base_tests.gyp:ui_base_unittests',
         '../url/url.gyp:url_unittests',
@@ -153,7 +152,6 @@
               #   SoundsManagerTest.Play
               # Disable AudioStreamHandlerTest.ConsecutivePlayRequests (b/16539293)
               'media_unittests --gtest_filter=-AudioOutputControllerTest.PlayDivertSwitchDeviceRevertClose:AudioOutputControllerTest.PlaySwitchDeviceClose:AudioStreamHandlerTest.Play:AudioStreamHandlerTest.ConsecutivePlayRequests:PipelineIntegrationTest.BasicPlayback_MediaSource_VP9_WebM:PipelineIntegrationTest.BasicPlayback_VideoOnly_VP9_WebM:PipelineIntegrationTest.BasicPlayback_VP9*:PipelineIntegrationTest.P444_VP9_WebM:PipelineIntegrationTest.BasicPlayback_VP8A*:OpusAudioDecoderTest/AudioDecoderTest.ProduceAudioSamples/0:SoundsManagerTest.Play',
-              'sync_unit_tests --gtest_filter=-SyncHttpBridgeTest.*',
               # DoAppendUTF8Invalid fails because of dcheck_always_on flag in Eng builds
               'url_unittests --gtest_filter=-URLCanonTest.DoAppendUTF8Invalid',
             ],
@@ -262,7 +260,6 @@
             '../media/midi/midi.gyp:midi_unittests_apk',
             '../net/net.gyp:net_unittests_apk',
             '../sql/sql.gyp:sql_unittests_apk',
-            '../components/sync.gyp:sync_unit_tests_apk',
             '../ui/events/events_unittests.gyp:events_unittests_apk',
             '../ui/gfx/gfx_tests.gyp:gfx_unittests_apk',
           ],
diff --git a/chromecast/media/cma/base/demuxer_stream_for_test.cc b/chromecast/media/cma/base/demuxer_stream_for_test.cc
index 3115dcf0..bafaa8d7 100644
--- a/chromecast/media/cma/base/demuxer_stream_for_test.cc
+++ b/chromecast/media/cma/base/demuxer_stream_for_test.cc
@@ -86,7 +86,8 @@
   NOTIMPLEMENTED();
 }
 
-void DemuxerStreamForTest::SetStreamRestartedCB(const StreamRestartedCB& cb) {
+void DemuxerStreamForTest::SetStreamStatusChangeCB(
+    const StreamStatusChangeCB& cb) {
   NOTIMPLEMENTED();
 }
 
diff --git a/chromecast/media/cma/base/demuxer_stream_for_test.h b/chromecast/media/cma/base/demuxer_stream_for_test.h
index c3cc922c..aed460c 100644
--- a/chromecast/media/cma/base/demuxer_stream_for_test.h
+++ b/chromecast/media/cma/base/demuxer_stream_for_test.h
@@ -49,7 +49,7 @@
   ::media::VideoRotation video_rotation() override;
   bool enabled() const override;
   void set_enabled(bool enabled, base::TimeDelta time) override;
-  void SetStreamRestartedCB(const StreamRestartedCB& cb) override;
+  void SetStreamStatusChangeCB(const StreamStatusChangeCB& cb) override;
 
   bool has_pending_read() const { return has_pending_read_; }
 
diff --git a/components/BUILD.gn b/components/BUILD.gn
index e69e03926..609f3d3 100644
--- a/components/BUILD.gn
+++ b/components/BUILD.gn
@@ -127,6 +127,7 @@
     "//components/subresource_filter/core/common:unit_tests",
     "//components/suggestions:unit_tests",
     "//components/supervised_user_error_page:unit_tests",
+    "//components/sync:unit_tests",
     "//components/sync_bookmarks:unit_tests",
     "//components/sync_driver:unit_tests",
     "//components/sync_sessions:unit_tests",
diff --git a/components/arc/BUILD.gn b/components/arc/BUILD.gn
index fb45068..5c20c56 100644
--- a/components/arc/BUILD.gn
+++ b/components/arc/BUILD.gn
@@ -176,6 +176,8 @@
     "test/fake_arc_bridge_instance.h",
     "test/fake_arc_bridge_service.cc",
     "test/fake_arc_bridge_service.h",
+    "test/fake_bluetooth_instance.cc",
+    "test/fake_bluetooth_instance.h",
     "test/fake_notifications_instance.cc",
     "test/fake_notifications_instance.h",
     "test/fake_policy_instance.cc",
@@ -195,6 +197,8 @@
   testonly = true
   sources = [
     "arc_bridge_service_unittest.cc",
+    "bluetooth/arc_bluetooth_bridge_unittest.cc",
+    "bluetooth/bluetooth_type_converters_unittest.cc",
     "ime/arc_ime_service_unittest.cc",
     "intent_helper/activity_icon_loader_unittest.cc",
     "intent_helper/arc_intent_helper_bridge_unittest.cc",
@@ -209,6 +213,7 @@
     ":arc_test_support",
     "//base",
     "//chromeos",
+    "//device/bluetooth",
     "//mojo/public/cpp/system:system",
     "//testing/gtest",
     "//ui/aura",
diff --git a/components/arc/bluetooth/arc_bluetooth_bridge_unittest.cc b/components/arc/bluetooth/arc_bluetooth_bridge_unittest.cc
new file mode 100644
index 0000000..7953d1b1
--- /dev/null
+++ b/components/arc/bluetooth/arc_bluetooth_bridge_unittest.cc
@@ -0,0 +1,205 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/arc/bluetooth/arc_bluetooth_bridge.h"
+
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "base/message_loop/message_loop.h"
+#include "base/run_loop.h"
+#include "components/arc/bluetooth/bluetooth_type_converters.h"
+#include "components/arc/common/bluetooth.mojom.h"
+#include "components/arc/test/fake_arc_bridge_service.h"
+#include "components/arc/test/fake_bluetooth_instance.h"
+#include "device/bluetooth/dbus/bluez_dbus_manager.h"
+#include "device/bluetooth/dbus/fake_bluetooth_adapter_client.h"
+#include "device/bluetooth/dbus/fake_bluetooth_device_client.h"
+#include "device/bluetooth/dbus/fake_bluetooth_gatt_characteristic_client.h"
+#include "device/bluetooth/dbus/fake_bluetooth_gatt_descriptor_client.h"
+#include "device/bluetooth/dbus/fake_bluetooth_gatt_service_client.h"
+#include "mojo/public/cpp/bindings/array.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace arc {
+
+class ArcBluetoothBridgeTest : public testing::Test {
+ protected:
+  void AddTestDevice() {
+    bluez::BluezDBusManager* dbus_manager = bluez::BluezDBusManager::Get();
+    auto* fake_bluetooth_device_client =
+        static_cast<bluez::FakeBluetoothDeviceClient*>(
+            dbus_manager->GetBluetoothDeviceClient());
+    auto* fake_bluetooth_gatt_service_client =
+        static_cast<bluez::FakeBluetoothGattServiceClient*>(
+            dbus_manager->GetBluetoothGattServiceClient());
+    auto* fake_bluetooth_gatt_characteristic_client =
+        static_cast<bluez::FakeBluetoothGattCharacteristicClient*>(
+            dbus_manager->GetBluetoothGattCharacteristicClient());
+
+    fake_bluetooth_device_client->CreateDevice(
+        dbus::ObjectPath(bluez::FakeBluetoothAdapterClient::kAdapterPath),
+        dbus::ObjectPath(bluez::FakeBluetoothDeviceClient::kLowEnergyPath));
+    fake_bluetooth_gatt_service_client->ExposeHeartRateService(
+        dbus::ObjectPath(bluez::FakeBluetoothDeviceClient::kLowEnergyPath));
+    fake_bluetooth_gatt_characteristic_client->ExposeHeartRateCharacteristics(
+        fake_bluetooth_gatt_service_client->GetHeartRateServicePath());
+  }
+
+  void OnAdapterInitialized(scoped_refptr<device::BluetoothAdapter> adapter) {
+    adapter_ = adapter;
+    get_adapter_run_loop_.Quit();
+  }
+
+  void SetUp() override {
+    std::unique_ptr<bluez::BluezDBusManagerSetter> dbus_setter =
+        bluez::BluezDBusManager::GetSetterForTesting();
+    auto fake_bluetooth_device_client =
+        base::MakeUnique<bluez::FakeBluetoothDeviceClient>();
+    fake_bluetooth_device_client->RemoveAllDevices();
+    dbus_setter->SetBluetoothDeviceClient(
+        std::move(fake_bluetooth_device_client));
+    dbus_setter->SetBluetoothGattServiceClient(
+        base::MakeUnique<bluez::FakeBluetoothGattServiceClient>());
+    dbus_setter->SetBluetoothGattCharacteristicClient(
+        base::MakeUnique<bluez::FakeBluetoothGattCharacteristicClient>());
+    dbus_setter->SetBluetoothGattDescriptorClient(
+        base::MakeUnique<bluez::FakeBluetoothGattDescriptorClient>());
+
+    fake_arc_bridge_service_.reset(new FakeArcBridgeService());
+    fake_bluetooth_instance_.reset(new FakeBluetoothInstance());
+    fake_arc_bridge_service_->bluetooth()->SetInstance(
+        fake_bluetooth_instance_.get(), 2);
+    arc_bluetooth_bridge_.reset(
+        new ArcBluetoothBridge(fake_arc_bridge_service_.get()));
+
+    device::BluetoothAdapterFactory::GetAdapter(base::Bind(
+        &ArcBluetoothBridgeTest::OnAdapterInitialized, base::Unretained(this)));
+    // We will quit the loop once we get the adapter.
+    get_adapter_run_loop_.Run();
+  }
+
+  std::unique_ptr<FakeArcBridgeService> fake_arc_bridge_service_;
+  std::unique_ptr<FakeBluetoothInstance> fake_bluetooth_instance_;
+  std::unique_ptr<ArcBluetoothBridge> arc_bluetooth_bridge_;
+  scoped_refptr<device::BluetoothAdapter> adapter_;
+  base::MessageLoop message_loop_;
+  base::RunLoop get_adapter_run_loop_;
+};
+
+// When we add device to bluez::FakeBluetoothDeviceClient, ArcBluetoothBridge
+// should send new device data to Android. This test will then check
+// the correctness of the device properties sent via arc bridge.
+TEST_F(ArcBluetoothBridgeTest, DeviceFound) {
+  EXPECT_EQ(0u, fake_bluetooth_instance_->device_found_data().size());
+  AddTestDevice();
+  EXPECT_EQ(1u, fake_bluetooth_instance_->device_found_data().size());
+  const mojo::Array<mojom::BluetoothPropertyPtr>& prop =
+      fake_bluetooth_instance_->device_found_data().back();
+
+  EXPECT_EQ(7u, prop.size());
+  EXPECT_TRUE(prop[0]->is_bdname());
+  EXPECT_EQ(std::string(bluez::FakeBluetoothDeviceClient::kLowEnergyName),
+            prop[0]->get_bdname());
+  EXPECT_TRUE(prop[1]->is_bdaddr());
+  EXPECT_EQ(std::string(bluez::FakeBluetoothDeviceClient::kLowEnergyAddress),
+            prop[1]->get_bdaddr()->To<std::string>());
+  EXPECT_TRUE(prop[2]->is_uuids());
+  EXPECT_EQ(1u, prop[2]->get_uuids().size());
+  EXPECT_EQ(bluez::FakeBluetoothGattServiceClient::kHeartRateServiceUUID,
+            prop[2]->get_uuids()[0].To<device::BluetoothUUID>().value());
+  EXPECT_TRUE(prop[3]->is_device_class());
+  EXPECT_EQ(bluez::FakeBluetoothDeviceClient::kLowEnergyClass,
+            prop[3]->get_device_class());
+  EXPECT_TRUE(prop[4]->is_device_type());
+  // bluez::FakeBluetoothDeviceClient does not return proper device type.
+  EXPECT_TRUE(prop[5]->is_remote_friendly_name());
+  EXPECT_EQ(std::string(bluez::FakeBluetoothDeviceClient::kLowEnergyName),
+            prop[5]->get_remote_friendly_name());
+  EXPECT_TRUE(prop[6]->is_remote_rssi());
+}
+
+// Invoke OnDiscoveryStarted to send cached device to BT instance,
+// and check correctness of the Advertising data sent via arc bridge.
+TEST_F(ArcBluetoothBridgeTest, LEDeviceFound) {
+  EXPECT_EQ(0u, fake_bluetooth_instance_->device_found_data().size());
+  AddTestDevice();
+  EXPECT_EQ(1u, fake_bluetooth_instance_->le_device_found_data().size());
+
+  const mojom::BluetoothAddressPtr& addr =
+      fake_bluetooth_instance_->le_device_found_data().back()->addr();
+  const mojo::Array<mojom::BluetoothAdvertisingDataPtr>& adv_data =
+      fake_bluetooth_instance_->le_device_found_data().back()->adv_data();
+
+  EXPECT_EQ(std::string(bluez::FakeBluetoothDeviceClient::kLowEnergyAddress),
+            addr->To<std::string>());
+  EXPECT_EQ(1u, adv_data.size());
+
+  EXPECT_TRUE(adv_data[0]->is_local_name());
+  EXPECT_EQ(std::string(bluez::FakeBluetoothDeviceClient::kLowEnergyName),
+            adv_data[0]->get_local_name().To<std::string>());
+}
+
+// Invoke GetGattDB and check correctness of the GattDB sent via arc bridge.
+TEST_F(ArcBluetoothBridgeTest, GetGattDB) {
+  AddTestDevice();
+
+  arc_bluetooth_bridge_->GetGattDB(mojom::BluetoothAddress::From(
+      std::string(bluez::FakeBluetoothDeviceClient::kLowEnergyAddress)));
+  EXPECT_EQ(1u, fake_bluetooth_instance_->gatt_db_result().size());
+
+  const mojom::BluetoothAddressPtr& addr =
+      fake_bluetooth_instance_->gatt_db_result().back()->remote_addr();
+  EXPECT_EQ(std::string(bluez::FakeBluetoothDeviceClient::kLowEnergyAddress),
+            addr->To<std::string>());
+
+  // HeartRateService in bluez::FakeBluetoothDeviceClient consists of
+  // Service: HeartRateService
+  //     Characteristic: HeartRateMeasurement
+  //         Descriptor: ClientCharacteristicConfiguration
+  //     Characteristic: BodySensorLocation
+  //     Characteristic: HeartRateControlPoint
+  const mojo::Array<mojom::BluetoothGattDBElementPtr>& db =
+      fake_bluetooth_instance_->gatt_db_result().back()->db();
+  EXPECT_EQ(5u, db.size());
+
+  EXPECT_EQ(device::BluetoothUUID(
+                bluez::FakeBluetoothGattServiceClient::kHeartRateServiceUUID),
+            db[0]->uuid.To<device::BluetoothUUID>());
+  EXPECT_EQ(mojom::BluetoothGattDBAttributeType::BTGATT_DB_PRIMARY_SERVICE,
+            db[0]->type);
+
+  EXPECT_EQ(device::BluetoothUUID(bluez::FakeBluetoothGattCharacteristicClient::
+                                      kHeartRateMeasurementUUID),
+            db[1]->uuid.To<device::BluetoothUUID>());
+  EXPECT_EQ(mojom::BluetoothGattDBAttributeType::BTGATT_DB_CHARACTERISTIC,
+            db[1]->type);
+  EXPECT_EQ(device::BluetoothGattCharacteristic::PROPERTY_NOTIFY,
+            db[1]->properties);
+
+  EXPECT_EQ(device::BluetoothUUID(bluez::FakeBluetoothGattDescriptorClient::
+                                      kClientCharacteristicConfigurationUUID),
+            db[2]->uuid.To<device::BluetoothUUID>());
+  EXPECT_EQ(mojom::BluetoothGattDBAttributeType::BTGATT_DB_DESCRIPTOR,
+            db[2]->type);
+
+  EXPECT_EQ(device::BluetoothUUID(bluez::FakeBluetoothGattCharacteristicClient::
+                                      kBodySensorLocationUUID),
+            db[3]->uuid.To<device::BluetoothUUID>());
+  EXPECT_EQ(mojom::BluetoothGattDBAttributeType::BTGATT_DB_CHARACTERISTIC,
+            db[3]->type);
+  EXPECT_EQ(device::BluetoothGattCharacteristic::PROPERTY_READ,
+            db[3]->properties);
+
+  EXPECT_EQ(device::BluetoothUUID(bluez::FakeBluetoothGattCharacteristicClient::
+                                      kHeartRateControlPointUUID),
+            db[4]->uuid.To<device::BluetoothUUID>());
+  EXPECT_EQ(mojom::BluetoothGattDBAttributeType::BTGATT_DB_CHARACTERISTIC,
+            db[4]->type);
+  EXPECT_EQ(device::BluetoothGattCharacteristic::PROPERTY_WRITE,
+            db[4]->properties);
+}
+
+}  // namespace arc
diff --git a/components/arc/bluetooth/bluetooth_type_converters.cc b/components/arc/bluetooth/bluetooth_type_converters.cc
index af2e08b33..f91139d 100644
--- a/components/arc/bluetooth/bluetooth_type_converters.cc
+++ b/components/arc/bluetooth/bluetooth_type_converters.cc
@@ -19,6 +19,10 @@
 
 namespace {
 
+constexpr size_t kAddressSize = 6;
+constexpr size_t kUUIDSize = 16;
+constexpr char kInvalidAddress[] = "00:00:00:00:00:00";
+
 bool IsNonHex(char c) {
   return !isxdigit(c);
 }
@@ -35,8 +39,6 @@
 
 namespace mojo {
 
-// TODO(smbarber): Add unit tests for Bluetooth type converters.
-
 // static
 arc::mojom::BluetoothAddressPtr
 TypeConverter<arc::mojom::BluetoothAddressPtr, std::string>::Convert(
@@ -61,6 +63,9 @@
 
   const mojo::Array<uint8_t>& bytes = address.address;
 
+  if (address.address.size() != kAddressSize)
+    return std::string(kInvalidAddress);
+
   for (size_t k = 0; k < bytes.size(); k++) {
     addr_stream << std::setw(2) << (unsigned int)bytes[k];
     addr_stream << ((k == bytes.size() - 1) ? "" : ":");
@@ -90,6 +95,9 @@
     const arc::mojom::BluetoothUUIDPtr& uuid) {
   std::vector<uint8_t> address_bytes = uuid->uuid.To<std::vector<uint8_t>>();
 
+  if (address_bytes.size() != kUUIDSize)
+    return device::BluetoothUUID();
+
   // BluetoothUUID expects the format below with the dashes inserted.
   // xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
   std::string uuid_str =
diff --git a/components/arc/bluetooth/bluetooth_type_converters_unittest.cc b/components/arc/bluetooth/bluetooth_type_converters_unittest.cc
new file mode 100644
index 0000000..57e296d
--- /dev/null
+++ b/components/arc/bluetooth/bluetooth_type_converters_unittest.cc
@@ -0,0 +1,83 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/arc/bluetooth/bluetooth_type_converters.h"
+
+#include <string>
+#include <vector>
+
+#include "device/bluetooth/bluetooth_gatt_service.h"
+#include "device/bluetooth/bluetooth_uuid.h"
+#include "mojo/public/cpp/bindings/array.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+constexpr char kAddressStr[] = "1A:2B:3C:4D:5E:6F";
+constexpr char kInvalidAddressStr[] = "00:00:00:00:00:00";
+constexpr uint8_t kAddressArray[] = {0x1a, 0x2b, 0x3c, 0x4d, 0x5e, 0x6f};
+constexpr size_t kAddressSize = 6;
+constexpr char kUuidStr[] = "12345678-1234-5678-9abc-def123456789";
+constexpr uint8_t kUuidArray[] = {0x12, 0x34, 0x56, 0x78, 0x12, 0x34,
+                                  0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf1,
+                                  0x23, 0x45, 0x67, 0x89};
+constexpr size_t kUuidSize = 16;
+constexpr uint8_t kFillerByte = 0x79;
+}  // namespace
+
+namespace mojo {
+
+TEST(BluetoothTypeConvertorTest, ConvertMojoBluetoothAddressFromString) {
+  arc::mojom::BluetoothAddressPtr addressMojo =
+      arc::mojom::BluetoothAddress::From(std::string(kAddressStr));
+  EXPECT_EQ(kAddressSize, addressMojo->address.size());
+  for (size_t i = 0; i < kAddressSize; i++) {
+    EXPECT_EQ(kAddressArray[i], addressMojo->address[i]);
+  }
+}
+
+TEST(BluetoothTypeConvertorTest, ConvertMojoBluetoothAddressToString) {
+  arc::mojom::BluetoothAddressPtr addressMojo =
+      arc::mojom::BluetoothAddress::New();
+  for (size_t i = 0; i < kAddressSize - 1; i++) {
+    addressMojo->address.push_back(kAddressArray[i]);
+  }
+  EXPECT_EQ(std::string(kInvalidAddressStr), addressMojo->To<std::string>());
+
+  addressMojo->address.push_back(kAddressArray[kAddressSize - 1]);
+  EXPECT_EQ(std::string(kAddressStr), addressMojo->To<std::string>());
+
+  addressMojo->address.push_back(kFillerByte);
+
+  EXPECT_EQ(std::string(kInvalidAddressStr), addressMojo->To<std::string>());
+}
+
+TEST(BluetoothTypeConvertorTest,
+     ConvertMojoBluetoothUUIDFromDeviceBluetoothUUID) {
+  device::BluetoothUUID uuidDevice((std::string(kUuidStr)));
+  arc::mojom::BluetoothUUIDPtr uuidMojo =
+      arc::mojom::BluetoothUUID::From(uuidDevice);
+  EXPECT_EQ(kUuidSize, uuidMojo->uuid.size());
+  for (size_t i = 0; i < kUuidSize; i++) {
+    EXPECT_EQ(kUuidArray[i], uuidMojo->uuid[i]);
+  }
+}
+
+TEST(BluetoothTypeConvertorTest,
+     ConvertMojoBluetoothUUIDToDeviceBluetoothUUID) {
+  arc::mojom::BluetoothUUIDPtr uuidMojo = arc::mojom::BluetoothUUID::New();
+  for (size_t i = 0; i < kUuidSize - 1; i++) {
+    uuidMojo->uuid.push_back(kUuidArray[i]);
+  }
+  EXPECT_FALSE(uuidMojo.To<device::BluetoothUUID>().IsValid());
+
+  uuidMojo->uuid.push_back(kUuidArray[kUuidSize - 1]);
+  EXPECT_TRUE(uuidMojo.To<device::BluetoothUUID>().IsValid());
+  EXPECT_EQ(std::string(kUuidStr),
+            uuidMojo.To<device::BluetoothUUID>().canonical_value());
+
+  uuidMojo->uuid.push_back(kFillerByte);
+  EXPECT_FALSE(uuidMojo.To<device::BluetoothUUID>().IsValid());
+}
+
+}  // namespace mojo
diff --git a/components/arc/test/fake_bluetooth_instance.cc b/components/arc/test/fake_bluetooth_instance.cc
new file mode 100644
index 0000000..4db55a2
--- /dev/null
+++ b/components/arc/test/fake_bluetooth_instance.cc
@@ -0,0 +1,111 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/arc/test/fake_bluetooth_instance.h"
+
+#include <utility>
+
+namespace arc {
+
+FakeBluetoothInstance::FakeBluetoothInstance() = default;
+FakeBluetoothInstance::~FakeBluetoothInstance() = default;
+
+FakeBluetoothInstance::GattDBResult::GattDBResult(
+    mojom::BluetoothAddressPtr&& remote_addr,
+    mojo::Array<mojom::BluetoothGattDBElementPtr>&& db)
+    : remote_addr_(std::move(remote_addr)), db_(std::move(db)) {}
+
+FakeBluetoothInstance::GattDBResult::~GattDBResult() {}
+
+FakeBluetoothInstance::LEDeviceFoundData::LEDeviceFoundData(
+    mojom::BluetoothAddressPtr&& addr,
+    int32_t rssi,
+    mojo::Array<mojom::BluetoothAdvertisingDataPtr>&& adv_data)
+    : addr_(std::move(addr)), rssi_(rssi), adv_data_(std::move(adv_data)) {}
+
+FakeBluetoothInstance::LEDeviceFoundData::~LEDeviceFoundData() {}
+
+void FakeBluetoothInstance::Init(mojom::BluetoothHostPtr host_ptr) {}
+
+void FakeBluetoothInstance::OnAdapterProperties(
+    mojom::BluetoothStatus status,
+    mojo::Array<mojom::BluetoothPropertyPtr> properties) {}
+
+void FakeBluetoothInstance::OnRemoteDeviceProperties(
+    mojom::BluetoothStatus status,
+    mojom::BluetoothAddressPtr address,
+    mojo::Array<mojom::BluetoothPropertyPtr> properties) {}
+
+void FakeBluetoothInstance::OnDeviceFound(
+    mojo::Array<mojom::BluetoothPropertyPtr> properties) {
+  device_found_data_.push_back(std::move(properties));
+}
+
+void FakeBluetoothInstance::OnDiscoveryStateChanged(
+    mojom::BluetoothDiscoveryState state) {}
+
+void FakeBluetoothInstance::OnBondStateChanged(
+    mojom::BluetoothStatus status,
+    mojom::BluetoothAddressPtr remote_addr,
+    mojom::BluetoothBondState state) {}
+
+void FakeBluetoothInstance::OnAclStateChanged(
+    mojom::BluetoothStatus status,
+    mojom::BluetoothAddressPtr remote_addr,
+    mojom::BluetoothAclState state) {}
+
+void FakeBluetoothInstance::OnLEDeviceFound(
+    mojom::BluetoothAddressPtr addr,
+    int32_t rssi,
+    mojo::Array<mojom::BluetoothAdvertisingDataPtr> adv_data) {
+  le_device_found_data_.push_back(
+      new LEDeviceFoundData(std::move(addr), rssi, std::move(adv_data)));
+}
+
+void FakeBluetoothInstance::OnLEConnectionStateChange(
+    mojom::BluetoothAddressPtr remote_addr,
+    bool connected) {}
+
+void FakeBluetoothInstance::OnSearchComplete(
+    mojom::BluetoothAddressPtr remote_addr,
+    mojom::BluetoothGattStatus status) {}
+
+void FakeBluetoothInstance::OnGetGattDB(
+    mojom::BluetoothAddressPtr remote_addr,
+    mojo::Array<mojom::BluetoothGattDBElementPtr> db) {
+  gatt_db_result_.push_back(
+      new GattDBResult(std::move(remote_addr), std::move(db)));
+}
+
+void FakeBluetoothInstance::OnServicesRemoved(
+    mojom::BluetoothAddressPtr remote_addr,
+    uint16_t start_handle,
+    uint16_t end_handle) {}
+
+void FakeBluetoothInstance::OnServicesAdded(
+    mojom::BluetoothAddressPtr remote_addr,
+    mojo::Array<mojom::BluetoothGattDBElementPtr> db) {}
+
+void FakeBluetoothInstance::OnGattNotify(
+    mojom::BluetoothAddressPtr remote_addr,
+    mojom::BluetoothGattServiceIDPtr service_id,
+    mojom::BluetoothGattIDPtr char_id,
+    bool is_notify,
+    mojo::Array<uint8_t> value) {}
+
+void FakeBluetoothInstance::RequestGattRead(
+    mojom::BluetoothAddressPtr address,
+    int32_t attribute_handle,
+    int32_t offset,
+    bool is_long,
+    const RequestGattReadCallback& callback) {}
+
+void FakeBluetoothInstance::RequestGattWrite(
+    mojom::BluetoothAddressPtr address,
+    int32_t attribute_handle,
+    int32_t offset,
+    mojo::Array<uint8_t> value,
+    const RequestGattWriteCallback& callback) {}
+
+}  // namespace arc
diff --git a/components/arc/test/fake_bluetooth_instance.h b/components/arc/test/fake_bluetooth_instance.h
new file mode 100644
index 0000000..336d0b2
--- /dev/null
+++ b/components/arc/test/fake_bluetooth_instance.h
@@ -0,0 +1,143 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_ARC_TEST_FAKE_BLUETOOTH_INSTANCE_H_
+#define COMPONENTS_ARC_TEST_FAKE_BLUETOOTH_INSTANCE_H_
+
+#include <vector>
+
+#include "base/macros.h"
+#include "base/memory/scoped_vector.h"
+#include "components/arc/common/bluetooth.mojom.h"
+#include "mojo/public/cpp/bindings/binding.h"
+
+namespace arc {
+
+class FakeBluetoothInstance : public mojom::BluetoothInstance {
+ public:
+  class GattDBResult {
+   public:
+    GattDBResult(mojom::BluetoothAddressPtr&& remote_addr,
+                 mojo::Array<mojom::BluetoothGattDBElementPtr>&& db);
+    ~GattDBResult();
+
+    const mojom::BluetoothAddressPtr& remote_addr() const {
+      return remote_addr_;
+    }
+
+    const mojo::Array<mojom::BluetoothGattDBElementPtr>& db() const {
+      return db_;
+    }
+
+   private:
+    mojom::BluetoothAddressPtr remote_addr_;
+    mojo::Array<mojom::BluetoothGattDBElementPtr> db_;
+
+    DISALLOW_COPY_AND_ASSIGN(GattDBResult);
+  };
+
+  class LEDeviceFoundData {
+   public:
+    LEDeviceFoundData(
+        mojom::BluetoothAddressPtr&& addr,
+        int32_t rssi,
+        mojo::Array<mojom::BluetoothAdvertisingDataPtr>&& adv_data);
+    ~LEDeviceFoundData();
+
+    const mojom::BluetoothAddressPtr& addr() const { return addr_; }
+
+    int32_t rssi() const { return rssi_; }
+
+    const mojo::Array<mojom::BluetoothAdvertisingDataPtr>& adv_data() const {
+      return adv_data_;
+    }
+
+   private:
+    mojom::BluetoothAddressPtr addr_;
+    int32_t rssi_;
+    mojo::Array<mojom::BluetoothAdvertisingDataPtr> adv_data_;
+
+    DISALLOW_COPY_AND_ASSIGN(LEDeviceFoundData);
+  };
+
+  FakeBluetoothInstance();
+  ~FakeBluetoothInstance() override;
+
+  // interface BluetoothInstance
+  void Init(mojom::BluetoothHostPtr host_ptr) override;
+  void OnAdapterProperties(
+      mojom::BluetoothStatus status,
+      mojo::Array<mojom::BluetoothPropertyPtr> properties) override;
+  void OnRemoteDeviceProperties(
+      mojom::BluetoothStatus status,
+      mojom::BluetoothAddressPtr address,
+      mojo::Array<mojom::BluetoothPropertyPtr> properties) override;
+  void OnDeviceFound(
+      mojo::Array<mojom::BluetoothPropertyPtr> properties) override;
+  void OnDiscoveryStateChanged(mojom::BluetoothDiscoveryState state) override;
+  void OnBondStateChanged(mojom::BluetoothStatus status,
+                          mojom::BluetoothAddressPtr remote_addr,
+                          mojom::BluetoothBondState state) override;
+  void OnAclStateChanged(mojom::BluetoothStatus status,
+                         mojom::BluetoothAddressPtr remote_addr,
+                         mojom::BluetoothAclState state) override;
+  void OnLEDeviceFound(
+      mojom::BluetoothAddressPtr addr,
+      int32_t rssi,
+      mojo::Array<mojom::BluetoothAdvertisingDataPtr> adv_data) override;
+  void OnLEConnectionStateChange(mojom::BluetoothAddressPtr remote_addr,
+                                 bool connected) override;
+  void OnSearchComplete(mojom::BluetoothAddressPtr remote_addr,
+                        mojom::BluetoothGattStatus status) override;
+  void OnGetGattDB(mojom::BluetoothAddressPtr remote_addr,
+                   mojo::Array<mojom::BluetoothGattDBElementPtr> db) override;
+  void OnServicesRemoved(mojom::BluetoothAddressPtr remote_addr,
+                         uint16_t start_handle,
+                         uint16_t end_handle) override;
+  void OnServicesAdded(
+      mojom::BluetoothAddressPtr remote_addr,
+      mojo::Array<mojom::BluetoothGattDBElementPtr> db) override;
+
+  void OnGattNotify(mojom::BluetoothAddressPtr remote_addr,
+                    mojom::BluetoothGattServiceIDPtr service_id,
+                    mojom::BluetoothGattIDPtr char_id,
+                    bool is_notify,
+                    mojo::Array<uint8_t> value) override;
+
+  void RequestGattRead(mojom::BluetoothAddressPtr address,
+                       int32_t attribute_handle,
+                       int32_t offset,
+                       bool is_long,
+                       const RequestGattReadCallback& callback) override;
+
+  void RequestGattWrite(mojom::BluetoothAddressPtr address,
+                        int32_t attribute_handle,
+                        int32_t offset,
+                        mojo::Array<uint8_t> value,
+                        const RequestGattWriteCallback& callback) override;
+
+  const std::vector<mojo::Array<mojom::BluetoothPropertyPtr>>&
+  device_found_data() const {
+    return device_found_data_;
+  }
+
+  const std::vector<LEDeviceFoundData*>& le_device_found_data() const {
+    return le_device_found_data_;
+  }
+
+  const std::vector<GattDBResult*>& gatt_db_result() const {
+    return gatt_db_result_;
+  }
+
+ private:
+  std::vector<mojo::Array<mojom::BluetoothPropertyPtr>> device_found_data_;
+  std::vector<LEDeviceFoundData*> le_device_found_data_;
+  std::vector<GattDBResult*> gatt_db_result_;
+
+  DISALLOW_COPY_AND_ASSIGN(FakeBluetoothInstance);
+};
+
+}  // namespace arc
+
+#endif  // COMPONENTS_ARC_TEST_FAKE_BLUETOOTH_INSTANCE_H_
diff --git a/components/autofill.gypi b/components/autofill.gypi
index faa823a..860ae23 100644
--- a/components/autofill.gypi
+++ b/components/autofill.gypi
@@ -252,6 +252,14 @@
           'sources': [
             'autofill/core/browser/keyboard_accessory_metrics_logger.h',
             'autofill/core/browser/keyboard_accessory_metrics_logger.mm',
+        ],
+        }],
+        ['OS=="android"', {
+          'sources': [
+            'autofill/core/browser/autofill_assistant.cc',
+            'autofill/core/browser/autofill_assistant.h',
+            'autofill/core/browser/autofill_credit_card_filling_infobar_delegate_mobile.cc',
+            'autofill/core/browser/autofill_credit_card_filling_infobar_delegate_mobile.h',
           ],
         }],
         ['OS=="ios" or OS=="android"', {
@@ -296,6 +304,7 @@
         '../testing/gtest.gyp:gtest',
         'autofill_core_common',
         'autofill_core_browser',
+        'infobars',
         'os_crypt',
         'pref_registry',
         'prefs/prefs.gyp:prefs',
diff --git a/components/autofill/content/renderer/autofill_agent.cc b/components/autofill/content/renderer/autofill_agent.cc
index 9f32ae8..0a17887 100644
--- a/components/autofill/content/renderer/autofill_agent.cc
+++ b/components/autofill/content/renderer/autofill_agent.cc
@@ -468,7 +468,7 @@
 }
 
 void AutofillAgent::FillForm(int32_t id, const FormData& form) {
-  if (id != autofill_query_id_)
+  if (id != autofill_query_id_ && id != kNoQueryId)
     return;
 
   was_query_node_autofilled_ = element_.isAutofilled();
diff --git a/components/autofill/core/browser/BUILD.gn b/components/autofill/core/browser/BUILD.gn
index e9d6016..6643319 100644
--- a/components/autofill/core/browser/BUILD.gn
+++ b/components/autofill/core/browser/BUILD.gn
@@ -152,6 +152,15 @@
     ]
   }
 
+  if (is_android) {
+    sources += [
+      "autofill_assistant.cc",
+      "autofill_assistant.h",
+      "autofill_credit_card_filling_infobar_delegate_mobile.cc",
+      "autofill_credit_card_filling_infobar_delegate_mobile.h",
+    ]
+  }
+
   if (is_ios || is_android) {
     sources += [
       "autofill_save_card_infobar_delegate_mobile.cc",
@@ -321,6 +330,10 @@
     "webdata/web_data_service_unittest.cc",
   ]
 
+  if (is_android) {
+    sources += [ "autofill_assistant_unittest.cc" ]
+  }
+
   deps = [
     ":browser",
     ":test_support",
diff --git a/components/autofill/core/browser/autofill_assistant.cc b/components/autofill/core/browser/autofill_assistant.cc
new file mode 100644
index 0000000..c74776f9
--- /dev/null
+++ b/components/autofill/core/browser/autofill_assistant.cc
@@ -0,0 +1,60 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/autofill/core/browser/autofill_assistant.h"
+
+#include "base/containers/adapters.h"
+#include "base/strings/string16.h"
+#include "components/autofill/core/browser/autofill_experiments.h"
+#include "components/autofill/core/browser/autofill_manager.h"
+#include "components/autofill/core/browser/credit_card.h"
+#include "components/autofill/core/browser/form_structure.h"
+#include "components/autofill/core/common/autofill_constants.h"
+
+namespace autofill {
+
+AutofillAssistant::AutofillAssistant(AutofillManager* autofill_manager)
+    : credit_card_form_data_(nullptr),
+      autofill_manager_(autofill_manager),
+      weak_ptr_factory_(this) {}
+
+AutofillAssistant::~AutofillAssistant() {}
+
+void AutofillAssistant::Reset() {
+  credit_card_form_data_.reset();
+}
+
+bool AutofillAssistant::CanShowCreditCardAssist(
+    const std::vector<FormStructure*>& form_structures) {
+#if !defined(OS_ANDROID)
+  return false;
+#else
+  if (!IsAutofillCreditCardAssistEnabled() || credit_card_form_data_)
+    return false;
+
+  for (FormStructure* cur_form : base::Reversed(form_structures)) {
+    if (cur_form->IsCompleteCreditCardForm()) {
+      credit_card_form_data_.reset(new FormData(cur_form->ToFormData()));
+      break;
+    }
+  }
+  return !!credit_card_form_data_;
+#endif
+}
+
+void AutofillAssistant::ShowAssistForCreditCard(const CreditCard& card) {
+  DCHECK(credit_card_form_data_);
+  autofill_manager_->client()->ConfirmCreditCardFillAssist(
+      card, base::Bind(&AutofillAssistant::OnUserDidAcceptCreditCardFill,
+                       weak_ptr_factory_.GetWeakPtr(), card));
+}
+
+void AutofillAssistant::OnUserDidAcceptCreditCardFill(const CreditCard& card) {
+  // TODO(crbug.com/630656): Trigger CVC dialog flow for card filling.
+  autofill_manager_->FillCreditCardForm(kNoQueryId, *credit_card_form_data_,
+                                        credit_card_form_data_->fields[0], card,
+                                        base::string16());
+}
+
+}  // namespace autofill
diff --git a/components/autofill/core/browser/autofill_assistant.h b/components/autofill/core/browser/autofill_assistant.h
new file mode 100644
index 0000000..1a15b4c7
--- /dev/null
+++ b/components/autofill/core/browser/autofill_assistant.h
@@ -0,0 +1,59 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_AUTOFILL_ASSISTANT_H_
+#define COMPONENTS_AUTOFILL_CORE_BROWSER_AUTOFILL_ASSISTANT_H_
+
+#include <memory>
+#include <vector>
+
+#include "base/macros.h"
+#include "base/memory/weak_ptr.h"
+#include "components/autofill/core/common/form_data.h"
+
+namespace autofill {
+
+class AutofillManager;
+class CreditCard;
+class FormStructure;
+
+// This class encompasses the triggering rules and the logic for the autofill
+// assisted filling mechanisms.
+class AutofillAssistant {
+ public:
+  explicit AutofillAssistant(AutofillManager* autofill_manager);
+  ~AutofillAssistant();
+
+  // Should be called at every page navigation to clear state.
+  void Reset();
+
+  // Returns whether a credit card assist can be shown. Will go through the
+  // forms in |form_structures| and extract the credit card form.
+  bool CanShowCreditCardAssist(
+      const std::vector<FormStructure*>& form_structures);
+
+  // Will show an assist infobar for the previously extracted form proposing to
+  // autofill it. Should only be called if CanShowCreditCardAssist() returned
+  // true.
+  void ShowAssistForCreditCard(const CreditCard& card);
+
+ private:
+  // Called by the infobar delegate when the user accepts the infobar.
+  void OnUserDidAcceptCreditCardFill(const CreditCard& card);
+
+  // Holds the FormData to be filled with a credit card.
+  std::unique_ptr<FormData> credit_card_form_data_;
+
+  // Weak reference to the AutofillManager that created and maintains this
+  // AutofillAssistant.
+  AutofillManager* autofill_manager_;
+
+  base::WeakPtrFactory<AutofillAssistant> weak_ptr_factory_;
+
+  DISALLOW_COPY_AND_ASSIGN(AutofillAssistant);
+};
+
+}  // namespace autofill
+
+#endif  // COMPONENTS_AUTOFILL_CORE_BROWSER_AUTOFILL_ASSISTANT_H_
diff --git a/components/autofill/core/browser/autofill_assistant_unittest.cc b/components/autofill/core/browser/autofill_assistant_unittest.cc
new file mode 100644
index 0000000..b1a61d8
--- /dev/null
+++ b/components/autofill/core/browser/autofill_assistant_unittest.cc
@@ -0,0 +1,159 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/autofill/core/browser/autofill_assistant.h"
+
+#include <memory>
+
+#include "base/callback.h"
+#include "base/feature_list.h"
+#include "base/message_loop/message_loop.h"
+#include "base/strings/utf_string_conversions.h"
+#include "components/autofill/core/browser/autofill_driver.h"
+#include "components/autofill/core/browser/autofill_experiments.h"
+#include "components/autofill/core/browser/autofill_manager.h"
+#include "components/autofill/core/browser/autofill_test_utils.h"
+#include "components/autofill/core/browser/credit_card.h"
+#include "components/autofill/core/browser/form_structure.h"
+#include "components/autofill/core/browser/test_autofill_client.h"
+#include "components/autofill/core/browser/test_autofill_driver.h"
+#include "components/autofill/core/common/autofill_constants.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using testing::_;
+
+namespace autofill {
+namespace {
+
+class MockAutofillManager : public AutofillManager {
+ public:
+  MockAutofillManager(TestAutofillDriver* driver, TestAutofillClient* client)
+      // Force to use the constructor designated for unit test, but we don't
+      // really need personal_data in this test so we pass a NULL pointer.
+      : AutofillManager(driver, client, NULL) {}
+  virtual ~MockAutofillManager() {}
+
+  MOCK_METHOD5(FillCreditCardForm,
+               void(int query_id,
+                    const FormData& form,
+                    const FormFieldData& field,
+                    const CreditCard& credit_card,
+                    const base::string16& cvc));
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(MockAutofillManager);
+};
+
+}  // namespace
+
+class AutofillAssistantTest : public testing::Test {
+ protected:
+  AutofillAssistantTest()
+      : message_loop_(),
+        autofill_client_(),
+        autofill_driver_(),
+        autofill_manager_(&autofill_driver_, &autofill_client_),
+        autofill_assistant_(&autofill_manager_) {}
+
+  void EnableAutofillCreditCardAssist() {
+    base::FeatureList::ClearInstanceForTesting();
+    std::unique_ptr<base::FeatureList> feature_list(new base::FeatureList);
+    feature_list->InitializeFromCommandLine(kAutofillCreditCardAssist.name,
+                                            std::string());
+    base::FeatureList::SetInstance(std::move(feature_list));
+  }
+
+  // Returns an initialized FormStructure with credit card form data. To be
+  // owned by the caller.
+  std::unique_ptr<FormStructure> CreateValidCreditCardForm() {
+    std::unique_ptr<FormStructure> form_structure;
+    FormData form;
+
+    FormFieldData field;
+    field.form_control_type = "text";
+
+    field.label = base::ASCIIToUTF16("Name on Card");
+    field.name = base::ASCIIToUTF16("name_on_card");
+    form.fields.push_back(field);
+
+    field.label = base::ASCIIToUTF16("Card Number");
+    field.name = base::ASCIIToUTF16("card_number");
+    form.fields.push_back(field);
+
+    field.label = base::ASCIIToUTF16("Exp Month");
+    field.name = base::ASCIIToUTF16("ccmonth");
+    form.fields.push_back(field);
+
+    field.label = base::ASCIIToUTF16("Exp Year");
+    field.name = base::ASCIIToUTF16("ccyear");
+    form.fields.push_back(field);
+
+    field.label = base::ASCIIToUTF16("Verification");
+    field.name = base::ASCIIToUTF16("verification");
+    form.fields.push_back(field);
+
+    form_structure.reset(new FormStructure(form));
+    form_structure->DetermineHeuristicTypes();
+
+    return form_structure;
+  }
+
+  base::MessageLoop message_loop_;
+  TestAutofillClient autofill_client_;
+  testing::NiceMock<TestAutofillDriver> autofill_driver_;
+  MockAutofillManager autofill_manager_;
+  AutofillAssistant autofill_assistant_;
+};
+
+MATCHER_P(CreditCardMatches, guid, "") {
+  return arg.guid() == guid;
+}
+
+// If the feature is turned off, CanShowCreditCardAssist() always returns
+// false.
+TEST_F(AutofillAssistantTest, CanShowCreditCardAssist_FeatureOff) {
+  std::unique_ptr<FormStructure> form_structure = CreateValidCreditCardForm();
+
+  std::vector<FormStructure*> form_structures{form_structure.get()};
+  EXPECT_FALSE(autofill_assistant_.CanShowCreditCardAssist(form_structures));
+}
+
+// Tests that with the feature enabled and proper input,
+// CanShowCreditCardAssist() behaves as expected.
+TEST_F(AutofillAssistantTest, CanShowCreditCardAssist_FeatureOn) {
+  EnableAutofillCreditCardAssist();
+  std::unique_ptr<FormStructure> form_structure = CreateValidCreditCardForm();
+
+  std::vector<FormStructure*> form_structures;
+  EXPECT_FALSE(autofill_assistant_.CanShowCreditCardAssist(form_structures));
+
+  // With valid input, the function extracts the credit card form properly.
+  form_structures.push_back(form_structure.get());
+  EXPECT_TRUE(autofill_assistant_.CanShowCreditCardAssist(form_structures));
+}
+
+TEST_F(AutofillAssistantTest, ShowAssistForCreditCard_ValidCard) {
+  EnableAutofillCreditCardAssist();
+  std::unique_ptr<FormStructure> form_structure = CreateValidCreditCardForm();
+
+  // Will extract the credit card form data.
+  std::vector<FormStructure*> form_structures{form_structure.get()};
+  EXPECT_TRUE(autofill_assistant_.CanShowCreditCardAssist(form_structures));
+
+  // Create a valid card for the assist.
+  CreditCard card;
+  test::SetCreditCardInfo(&card, "John Doe", "4111111111111111", "05", "2999");
+
+  // FillCreditCardForm ends up being called after user has accepted the
+  // prompt.
+  EXPECT_CALL(
+      autofill_manager_,
+      FillCreditCardForm(kNoQueryId, _, _, CreditCardMatches(card.guid()),
+                         /* empty cvc */ base::string16()));
+
+  autofill_assistant_.ShowAssistForCreditCard(card);
+}
+
+}  // namespace autofill
diff --git a/components/autofill/core/browser/autofill_client.h b/components/autofill/core/browser/autofill_client.h
index 354610b..d475691 100644
--- a/components/autofill/core/browser/autofill_client.h
+++ b/components/autofill/core/browser/autofill_client.h
@@ -132,6 +132,11 @@
       std::unique_ptr<base::DictionaryValue> legal_message,
       const base::Closure& callback) = 0;
 
+  // Will show an infobar to get user consent for Credit Card assistive filling.
+  // Will run |callback| on success.
+  virtual void ConfirmCreditCardFillAssist(const CreditCard& card,
+                                           const base::Closure& callback) = 0;
+
   // Gathers risk data and provides it to |callback|.
   virtual void LoadRiskData(
       const base::Callback<void(const std::string&)>& callback) = 0;
diff --git a/components/autofill/core/browser/autofill_credit_card_filling_infobar_delegate_mobile.cc b/components/autofill/core/browser/autofill_credit_card_filling_infobar_delegate_mobile.cc
new file mode 100644
index 0000000..432bb26
--- /dev/null
+++ b/components/autofill/core/browser/autofill_credit_card_filling_infobar_delegate_mobile.cc
@@ -0,0 +1,89 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/autofill/core/browser/autofill_credit_card_filling_infobar_delegate_mobile.h"
+
+#include "base/memory/ptr_util.h"
+#include "components/autofill/core/browser/credit_card.h"
+#include "components/autofill/core/common/autofill_constants.h"
+#include "components/infobars/core/infobar_delegate.h"
+#include "grit/components_scaled_resources.h"
+#include "grit/components_strings.h"
+#include "ui/base/l10n/l10n_util.h"
+
+namespace autofill {
+
+AutofillCreditCardFillingInfoBarDelegateMobile::
+    AutofillCreditCardFillingInfoBarDelegateMobile(
+        const CreditCard& card,
+        const base::Closure& card_filling_callback)
+    : ConfirmInfoBarDelegate(),
+      card_filling_callback_(card_filling_callback),
+      had_user_interaction_(false),
+      was_shown_(false),
+      issuer_icon_id_(CreditCard::IconResourceId(card.type())),
+      card_label_(base::string16(kMidlineEllipsis) + card.LastFourDigits()),
+      card_sub_label_(card.AbbreviatedExpirationDateForDisplay()) {}
+
+AutofillCreditCardFillingInfoBarDelegateMobile::
+    ~AutofillCreditCardFillingInfoBarDelegateMobile() {
+  if (was_shown_) {
+    AutofillMetrics::LogCreditCardFillingInfoBarMetric(
+        AutofillMetrics::INFOBAR_SHOWN);
+    if (!had_user_interaction_)
+      LogUserAction(AutofillMetrics::INFOBAR_IGNORED);
+  }
+}
+
+int AutofillCreditCardFillingInfoBarDelegateMobile::GetIconId() const {
+  return IDR_INFOBAR_AUTOFILL_CC;
+}
+
+base::string16 AutofillCreditCardFillingInfoBarDelegateMobile::GetMessageText()
+    const {
+  return l10n_util::GetStringUTF16(
+      IDS_AUTOFILL_CREDIT_CARD_FILLING_INFOBAR_TITLE);
+}
+
+void AutofillCreditCardFillingInfoBarDelegateMobile::InfoBarDismissed() {
+  LogUserAction(AutofillMetrics::INFOBAR_DENIED);
+}
+
+bool AutofillCreditCardFillingInfoBarDelegateMobile::Accept() {
+  card_filling_callback_.Run();
+  LogUserAction(AutofillMetrics::INFOBAR_ACCEPTED);
+  return true;
+}
+
+bool AutofillCreditCardFillingInfoBarDelegateMobile::Cancel() {
+  LogUserAction(AutofillMetrics::INFOBAR_DENIED);
+  return true;
+}
+
+infobars::InfoBarDelegate::Type
+AutofillCreditCardFillingInfoBarDelegateMobile::GetInfoBarType() const {
+  return PAGE_ACTION_TYPE;
+}
+
+infobars::InfoBarDelegate::InfoBarIdentifier
+AutofillCreditCardFillingInfoBarDelegateMobile::GetIdentifier() const {
+  return AUTOFILL_CREDIT_CARD_FILLING_INFOBAR_DELEGATE_ANDROID;
+}
+
+base::string16 AutofillCreditCardFillingInfoBarDelegateMobile::GetButtonLabel(
+    InfoBarButton button) const {
+  return l10n_util::GetStringUTF16(
+      button == BUTTON_OK ? IDS_AUTOFILL_CREDIT_CARD_FILLING_INFOBAR_ACCEPT
+                          : IDS_NO_THANKS);
+}
+
+void AutofillCreditCardFillingInfoBarDelegateMobile::LogUserAction(
+    AutofillMetrics::InfoBarMetric user_action) {
+  DCHECK(!had_user_interaction_);
+
+  AutofillMetrics::LogCreditCardFillingInfoBarMetric(user_action);
+  had_user_interaction_ = true;
+}
+
+}  // namespace autofill
diff --git a/components/autofill/core/browser/autofill_credit_card_filling_infobar_delegate_mobile.h b/components/autofill/core/browser/autofill_credit_card_filling_infobar_delegate_mobile.h
new file mode 100644
index 0000000..fe1cc19
--- /dev/null
+++ b/components/autofill/core/browser/autofill_credit_card_filling_infobar_delegate_mobile.h
@@ -0,0 +1,75 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_AUTOFILL_CREDIT_CARD_FILLING_INFOBAR_DELEGATE_MOBILE_H_
+#define COMPONENTS_AUTOFILL_CORE_BROWSER_AUTOFILL_CREDIT_CARD_FILLING_INFOBAR_DELEGATE_MOBILE_H_
+
+#include <memory>
+
+#include "base/callback.h"
+#include "base/macros.h"
+#include "base/strings/string16.h"
+#include "components/autofill/core/browser/autofill_metrics.h"
+#include "components/infobars/core/confirm_infobar_delegate.h"
+
+namespace infobars {
+class InfoBarManager;
+}
+
+namespace autofill {
+
+class CreditCard;
+
+// An InfoBarDelegate that enables the user to allow or deny filling credit
+// card information on a website form. Only used on mobile.
+class AutofillCreditCardFillingInfoBarDelegateMobile
+    : public ConfirmInfoBarDelegate {
+ public:
+  AutofillCreditCardFillingInfoBarDelegateMobile(
+      const CreditCard& card,
+      const base::Closure& card_filling_callback);
+  ~AutofillCreditCardFillingInfoBarDelegateMobile() override;
+
+  int issuer_icon_id() const { return issuer_icon_id_; }
+  const base::string16& card_label() const { return card_label_; }
+  const base::string16& card_sub_label() const { return card_sub_label_; }
+  void set_was_shown() { was_shown_ = true; }
+
+  // ConfirmInfoBarDelegate (publicly exposed):
+  int GetIconId() const override;
+  base::string16 GetMessageText() const override;
+  void InfoBarDismissed() override;
+  bool Accept() override;
+  bool Cancel() override;
+
+ private:
+  // ConfirmInfoBarDelegate (continued):
+  Type GetInfoBarType() const override;
+  infobars::InfoBarDelegate::InfoBarIdentifier GetIdentifier() const override;
+  base::string16 GetButtonLabel(InfoBarButton button) const override;
+
+  void LogUserAction(AutofillMetrics::InfoBarMetric user_action);
+
+  // The callback after having accepted the infobar; will initiate filling the
+  // credit card information.
+  base::Closure card_filling_callback_;
+
+  // Did the user ever explicitly accept or dismiss this infobar?
+  bool had_user_interaction_;
+
+  // Tracks whether the infobar was shown.
+  bool was_shown_;
+
+  // The resource ID for the icon that identifies the issuer of the card.
+  int issuer_icon_id_;
+
+  base::string16 card_label_;
+  base::string16 card_sub_label_;
+
+  DISALLOW_COPY_AND_ASSIGN(AutofillCreditCardFillingInfoBarDelegateMobile);
+};
+
+}  // namespace autofill
+
+#endif  // COMPONENTS_AUTOFILL_CORE_BROWSER_AUTOFILL_CREDIT_CARD_FILLING_INFOBAR_DELEGATE_MOBILE_H_
diff --git a/components/autofill/core/browser/autofill_experiments.cc b/components/autofill/core/browser/autofill_experiments.cc
index 6136569..03731e98 100644
--- a/components/autofill/core/browser/autofill_experiments.cc
+++ b/components/autofill/core/browser/autofill_experiments.cc
@@ -19,6 +19,8 @@
 
 namespace autofill {
 
+const base::Feature kAutofillCreditCardAssist{
+    "AutofillCreditCardAssist", base::FEATURE_DISABLED_BY_DEFAULT};
 const base::Feature kAutofillProfileCleanup{"AutofillProfileCleanup",
                                             base::FEATURE_DISABLED_BY_DEFAULT};
 const base::Feature kAutofillCreditCardSigninPromo{
@@ -43,6 +45,10 @@
   return base::FeatureList::IsEnabled(kAutofillCreditCardSigninPromo);
 }
 
+bool IsAutofillCreditCardAssistEnabled() {
+  return base::FeatureList::IsEnabled(kAutofillCreditCardAssist);
+}
+
 int GetCreditCardSigninPromoImpressionLimit() {
   int impression_limit;
   std::string param_value = variations::GetVariationParamValueByFeature(
diff --git a/components/autofill/core/browser/autofill_experiments.h b/components/autofill/core/browser/autofill_experiments.h
index 70fc201f..700e41ee 100644
--- a/components/autofill/core/browser/autofill_experiments.h
+++ b/components/autofill/core/browser/autofill_experiments.h
@@ -19,6 +19,7 @@
 
 namespace autofill {
 
+extern const base::Feature kAutofillCreditCardAssist;
 extern const base::Feature kAutofillProfileCleanup;
 extern const base::Feature kAutofillCreditCardSigninPromo;
 extern const char kCreditCardSigninPromoImpressionLimitParamKey[];
@@ -39,6 +40,9 @@
 // Returns whether the Autofill credit card signin promo should be shown.
 bool IsAutofillCreditCardSigninPromoEnabled();
 
+// Returns whether the Autofill credit card assist infobar should be shown.
+bool IsAutofillCreditCardAssistEnabled();
+
 // Returns the maximum number of impressions of the credit card signin promo, or
 // 0 if there are no limits.
 int GetCreditCardSigninPromoImpressionLimit();
diff --git a/components/autofill/core/browser/autofill_manager.cc b/components/autofill/core/browser/autofill_manager.cc
index 3e353ee5..d8c306c 100644
--- a/components/autofill/core/browser/autofill_manager.cc
+++ b/components/autofill/core/browser/autofill_manager.cc
@@ -208,6 +208,9 @@
       user_did_accept_upload_prompt_(false),
       external_delegate_(NULL),
       test_delegate_(NULL),
+#if defined(OS_ANDROID)
+      autofill_assistant_(this),
+#endif
       weak_ptr_factory_(this) {
   if (enable_download_manager == ENABLE_AUTOFILL_DOWNLOAD_MANAGER) {
     download_manager_.reset(new AutofillDownloadManager(driver, this));
@@ -583,11 +586,12 @@
 
   // If there are no Autofill suggestions, consider showing Autocomplete
   // suggestions. We will not show Autocomplete suggestions for a field that
-  // specifies autocomplete=off or a field that we think is a credit card
-  // expiration, cvc or number.
+  // specifies autocomplete=off (or an unrecognized type) or a field that we
+  // think is a credit card expiration, cvc or number.
   if (suggestions.empty() && field.should_autocomplete &&
       !(autofill_field &&
         (IsCreditCardExpirationType(autofill_field->Type().GetStorableType()) ||
+         autofill_field->Type().html_type() == HTML_TYPE_UNRECOGNIZED ||
          autofill_field->Type().GetStorableType() == CREDIT_CARD_NUMBER ||
          autofill_field->Type().GetStorableType() ==
              CREDIT_CARD_VERIFICATION_CODE))) {
@@ -1285,6 +1289,9 @@
       new AutofillMetrics::FormEventLogger(false /* is_for_credit_card */));
   credit_card_form_event_logger_.reset(
       new AutofillMetrics::FormEventLogger(true /* is_for_credit_card */));
+#if defined(OS_ANDROID)
+  autofill_assistant_.Reset();
+#endif
   has_logged_autofill_enabled_ = false;
   has_logged_address_suggestions_count_ = false;
   did_show_suggestions_ = false;
@@ -1324,6 +1331,9 @@
       unmasking_query_id_(-1),
       external_delegate_(NULL),
       test_delegate_(NULL),
+#if defined(OS_ANDROID)
+      autofill_assistant_(this),
+#endif
       weak_ptr_factory_(this) {
   DCHECK(driver_);
   DCHECK(client_);
@@ -1772,6 +1782,21 @@
 #endif
   }
 
+#if defined(OS_ANDROID)
+  // When a credit card form is parsed and conditions are met, show an infobar
+  // prompt for credit card assisted filling. Upon accepting the infobar, the
+  // form will automatically be filled with the user's information through this
+  // class' FillCreditCardForm().
+  if (autofill_assistant_.CanShowCreditCardAssist(form_structures_.get())) {
+    const std::vector<CreditCard*> cards =
+        personal_data_->GetCreditCardsToSuggest();
+    // Expired cards are last in the sorted order, so if the first one is
+    // expired, they all are.
+    if (!cards.empty() && !cards.front()->IsExpired(base::Time::Now()))
+      autofill_assistant_.ShowAssistForCreditCard(*cards.front());
+  }
+#endif
+
   // For the |non_queryable_forms|, we have all the field type info we're ever
   // going to get about them.  For the other forms, we'll wait until we get a
   // response from the server.
diff --git a/components/autofill/core/browser/autofill_manager.h b/components/autofill/core/browser/autofill_manager.h
index 4b906a5..03026c9 100644
--- a/components/autofill/core/browser/autofill_manager.h
+++ b/components/autofill/core/browser/autofill_manager.h
@@ -32,6 +32,10 @@
 #include "components/autofill/core/browser/personal_data_manager.h"
 #include "components/autofill/core/common/form_data.h"
 
+#if defined(OS_ANDROID)
+#include "components/autofill/core/browser/autofill_assistant.h"
+#endif
+
 // This define protects some debugging code (see DumpAutofillData). This
 // is here to make it easier to delete this code when the test is complete,
 // and to prevent adding the code on mobile where there is no desktop (the
@@ -251,7 +255,6 @@
 
   ScopedVector<FormStructure>* form_structures() { return &form_structures_; }
 
- protected:
   // Exposed for testing.
   AutofillExternalDelegate* external_delegate() {
     return external_delegate_;
@@ -535,6 +538,10 @@
   // Delegate used in test to get notifications on certain events.
   AutofillManagerTestDelegate* test_delegate_;
 
+#if defined(OS_ANDROID)
+  AutofillAssistant autofill_assistant_;
+#endif
+
   base::WeakPtrFactory<AutofillManager> weak_ptr_factory_;
 
   friend class AutofillManagerTest;
@@ -574,33 +581,9 @@
                            UserHappinessFormLoadAndSubmission);
   FRIEND_TEST_ALL_PREFIXES(AutofillMetricsTest, UserHappinessFormInteraction);
   FRIEND_TEST_ALL_PREFIXES(AutofillManagerTest,
-                           FormSubmittedAutocompleteEnabled);
-  FRIEND_TEST_ALL_PREFIXES(AutofillManagerTest,
                            OnLoadedServerPredictions);
   FRIEND_TEST_ALL_PREFIXES(AutofillManagerTest,
                            OnLoadedServerPredictions_ResetManager);
-  FRIEND_TEST_ALL_PREFIXES(AutofillManagerTest,
-                           AutocompleteSuggestions_SomeWhenAutofillDisabled);
-  FRIEND_TEST_ALL_PREFIXES(AutofillManagerTest,
-                           AutocompleteSuggestions_SomeWhenAutofillEmpty);
-  FRIEND_TEST_ALL_PREFIXES(AutofillManagerTest,
-                           AutocompleteSuggestions_NoneWhenAutofillPresent);
-  FRIEND_TEST_ALL_PREFIXES(
-      AutofillManagerTest,
-      AutocompleteSuggestions_CreditCardNameFieldShouldAutocomplete);
-  FRIEND_TEST_ALL_PREFIXES(
-      AutofillManagerTest,
-      AutocompleteSuggestions_CreditCardNumberShouldNotAutocomplete);
-  FRIEND_TEST_ALL_PREFIXES(
-      AutofillManagerTest,
-      AutocompleteSuggestions_AutofillDisabledAndFieldShouldNotAutocomplete);
-  FRIEND_TEST_ALL_PREFIXES(
-      AutofillManagerTest,
-      AutocompleteSuggestions_NoneWhenAutofillEmptyFieldShouldNotAutocomplete);
-  FRIEND_TEST_ALL_PREFIXES(AutofillManagerTest,
-                           AutocompleteOffRespectedForAutocomplete);
-  FRIEND_TEST_ALL_PREFIXES(AutofillManagerTest,
-                           DontSaveCvcInAutocompleteHistory);
   FRIEND_TEST_ALL_PREFIXES(AutofillManagerTest, DontOfferToSavePaymentsCard);
   FRIEND_TEST_ALL_PREFIXES(AutofillManagerTest, FillInUpdatedExpirationDate);
   DISALLOW_COPY_AND_ASSIGN(AutofillManager);
diff --git a/components/autofill/core/browser/autofill_manager_unittest.cc b/components/autofill/core/browser/autofill_manager_unittest.cc
index a25be3c..fffcb83 100644
--- a/components/autofill/core/browser/autofill_manager_unittest.cc
+++ b/components/autofill/core/browser/autofill_manager_unittest.cc
@@ -701,10 +701,21 @@
     suggestion_vector.push_back(suggestion2);
     CheckSuggestions(expected_page_id, 3, &suggestion_vector[0]);
   }
+  // Check that the autofill suggestions were sent, and that they match a page
+  // but contain no results.
   void CheckNoSuggestions(int expected_page_id) {
-    EXPECT_TRUE(on_suggestions_returned_seen());
     CheckSuggestions(expected_page_id, 0, nullptr);
   }
+  // Check that the autofill suggestions were sent, and that they match a page
+  // and contain a specific number of suggestions.
+  void CheckSuggestionCount(int expected_page_id,
+                            size_t expected_num_suggestions) {
+    // Ensure that these results are from the most recent query.
+    EXPECT_TRUE(on_suggestions_returned_seen_);
+
+    EXPECT_EQ(expected_page_id, query_id_);
+    ASSERT_EQ(expected_num_suggestions, suggestions_.size());
+  }
 
   bool on_query_seen() const {
     return on_query_seen_;
@@ -961,6 +972,16 @@
         form->fields[0], *card);
   }
 
+  // Convenience method for using and retrieving a mock autocomplete history
+  // manager.
+  MockAutocompleteHistoryManager* RecreateMockAutocompleteHistoryManager() {
+    MockAutocompleteHistoryManager* manager = new
+        MockAutocompleteHistoryManager(autofill_driver_.get(),
+                                       autofill_manager_->client());
+    autofill_manager_->autocomplete_history_manager_.reset(manager);
+    return manager;
+  }
+
   // Convenience method to cast the FullCardRequest into a CardUnmaskDelegate.
   CardUnmaskDelegate* full_card_unmask_delegate() {
     DCHECK(autofill_manager_->full_card_request_);
@@ -1062,9 +1083,10 @@
   download_manager_->VerifyLastQueriedForms(forms);
 }
 
-// Test that no suggestions are returned for a field with an unrecognized
-// autocomplete attribute.
+// Test that no autofill suggestions are returned for a field with an
+// unrecognized autocomplete attribute.
 TEST_F(AutofillManagerTest, GetProfileSuggestions_UnrecognizedAttribute) {
+  // Set up our form data.
   FormData form;
   form.name = ASCIIToUTF16("MyForm");
   form.origin = GURL("https://myform.com/form.html");
@@ -1085,21 +1107,26 @@
   std::vector<FormData> forms(1, form);
   FormsSeen(forms);
 
-  // Suggestions should be returned for the first two fields
-  GetAutofillSuggestions(form, form.fields[0]);
-  EXPECT_TRUE(external_delegate_->on_suggestions_returned_seen());
-  GetAutofillSuggestions(form, form.fields[1]);
-  EXPECT_TRUE(external_delegate_->on_suggestions_returned_seen());
+  // Ensure that autocomplete manager is not called for suggestions either.
+  MockAutocompleteHistoryManager* m = RecreateMockAutocompleteHistoryManager();
+  EXPECT_CALL(*m, OnGetAutocompleteSuggestions(_, _, _, _)).Times(0);
 
-  // Suggestions should not be returned for the third field because of its
+  // Suggestions should be returned for the first two fields.
+  GetAutofillSuggestions(form, form.fields[0]);
+  external_delegate_->CheckSuggestionCount(kDefaultPageID, 2);
+  GetAutofillSuggestions(form, form.fields[1]);
+  external_delegate_->CheckSuggestionCount(kDefaultPageID, 2);
+
+  // No suggestions should not be provided for the third field because of its
   // unrecognized autocomplete attribute.
   GetAutofillSuggestions(form, form.fields[2]);
-  EXPECT_FALSE(external_delegate_->on_suggestions_returned_seen());
+  external_delegate_->CheckNoSuggestions(kDefaultPageID);
 }
 
 // Test that no suggestions are returned when there are less than three fields
 // and none of them have an autocomplete attribute.
 TEST_F(AutofillManagerTest, GetProfileSuggestions_SmallFormNoAutocomplete) {
+  // Set up our form data.
   FormData form;
   form.name = ASCIIToUTF16("MyForm");
   form.origin = GURL("https://myform.com/form.html");
@@ -1113,6 +1140,10 @@
   std::vector<FormData> forms(1, form);
   FormsSeen(forms);
 
+  // Ensure that autocomplete manager is called for both fields.
+  MockAutocompleteHistoryManager* m = RecreateMockAutocompleteHistoryManager();
+  EXPECT_CALL(*m, OnGetAutocompleteSuggestions(_, _, _, _)).Times(2);
+
   GetAutofillSuggestions(form, form.fields[0]);
   EXPECT_FALSE(external_delegate_->on_suggestions_returned_seen());
 
@@ -1124,6 +1155,7 @@
 // attribute, suggestions are only made for the one that has the attribute.
 TEST_F(AutofillManagerTest,
        GetProfileSuggestions_SmallFormWithOneAutocomplete) {
+  // Set up our form data.
   FormData form;
   form.name = ASCIIToUTF16("MyForm");
   form.origin = GURL("https://myform.com/form.html");
@@ -1156,6 +1188,7 @@
 // suggestions are made for both fields.
 TEST_F(AutofillManagerTest,
        GetProfileSuggestions_SmallFormWithTwoAutocomplete) {
+  // Set up our form data.
   FormData form;
   form.name = ASCIIToUTF16("MyForm");
   form.origin = GURL("https://myform.com/form.html");
@@ -1184,7 +1217,7 @@
 
 // Test that we return all address profile suggestions when all form fields are
 // empty.
-TEST_F(AutofillManagerTest, GetProfileSuggestionsEmptyValue) {
+TEST_F(AutofillManagerTest, GetProfileSuggestions_EmptyValue) {
   // Set up our form data.
   FormData form;
   test::CreateTestAddressFormData(&form);
@@ -1204,7 +1237,7 @@
 
 // Test that we return only matching address profile suggestions when the
 // selected form field has been partially filled out.
-TEST_F(AutofillManagerTest, GetProfileSuggestionsMatchCharacter) {
+TEST_F(AutofillManagerTest, GetProfileSuggestions_MatchCharacter) {
   // Set up our form data.
   FormData form;
   test::CreateTestAddressFormData(&form);
@@ -1296,7 +1329,7 @@
 }
 
 // Test that we return no suggestions when the form has no relevant fields.
-TEST_F(AutofillManagerTest, GetProfileSuggestionsUnknownFields) {
+TEST_F(AutofillManagerTest, GetProfileSuggestions_UnknownFields) {
   // Set up our form data.
   FormData form;
   form.name = ASCIIToUTF16("MyForm");
@@ -1321,7 +1354,7 @@
 }
 
 // Test that we cull duplicate profile suggestions.
-TEST_F(AutofillManagerTest, GetProfileSuggestionsWithDuplicates) {
+TEST_F(AutofillManagerTest, GetProfileSuggestions_WithDuplicates) {
   // Set up our form data.
   FormData form;
   test::CreateTestAddressFormData(&form);
@@ -1345,7 +1378,7 @@
 }
 
 // Test that we return no suggestions when autofill is disabled.
-TEST_F(AutofillManagerTest, GetProfileSuggestionsAutofillDisabledByUser) {
+TEST_F(AutofillManagerTest, GetProfileSuggestions_AutofillDisabledByUser) {
   // Set up our form data.
   FormData form;
   test::CreateTestAddressFormData(&form);
@@ -1466,7 +1499,7 @@
 
 // Test that we return only matching credit card profile suggestions when the
 // selected form field has been partially filled out.
-TEST_F(AutofillManagerTest, GetCreditCardSuggestionsMatchCharacter) {
+TEST_F(AutofillManagerTest, GetCreditCardSuggestions_MatchCharacter) {
   // Set up our form data.
   FormData form;
   CreateTestCreditCardFormData(&form, true, false);
@@ -1487,7 +1520,7 @@
 
 // Test that we return credit card profile suggestions when the selected form
 // field is not the credit card number field.
-TEST_F(AutofillManagerTest, GetCreditCardSuggestionsNonCCNumber) {
+TEST_F(AutofillManagerTest, GetCreditCardSuggestions_NonCCNumber) {
   // Set up our form data.
   FormData form;
   CreateTestCreditCardFormData(&form, true, false);
@@ -1520,7 +1553,7 @@
 
 // Test that we return a warning explaining that credit card profile suggestions
 // are unavailable when the form is not secure.
-TEST_F(AutofillManagerTest, GetCreditCardSuggestionsNonHTTPS) {
+TEST_F(AutofillManagerTest, GetCreditCardSuggestions_NonHTTPS) {
   // Set up our form data.
   FormData form;
   CreateTestCreditCardFormData(&form, false, false);
@@ -1546,7 +1579,7 @@
 
 // Test that we return all credit card suggestions in the case that two cards
 // have the same obfuscated number.
-TEST_F(AutofillManagerTest, GetCreditCardSuggestionsRepeatedObfuscatedNumber) {
+TEST_F(AutofillManagerTest, GetCreditCardSuggestions_RepeatedObfuscatedNumber) {
   // Add a credit card with the same obfuscated number as Elvis's.
   // |credit_card| will be owned by the mock PersonalDataManager.
   CreditCard* credit_card = new CreditCard;
@@ -1727,7 +1760,7 @@
       Suggestion("Elvis", "", "", 1));
 }
 
-TEST_F(AutofillManagerTest, GetProfileSuggestionsFancyPhone) {
+TEST_F(AutofillManagerTest, GetProfileSuggestions_FancyPhone) {
   // Set up our form data.
   FormData form;
   test::CreateTestAddressFormData(&form);
@@ -1754,7 +1787,7 @@
       Suggestion("12345678901", "3734 Elvis Presley Blvd.", "", 3));
 }
 
-TEST_F(AutofillManagerTest, GetProfileSuggestionsForPhonePrefixOrSuffix) {
+TEST_F(AutofillManagerTest, GetProfileSuggestions_ForPhonePrefixOrSuffix) {
   // Set up our form data.
   FormData form;
   form.name = ASCIIToUTF16("MyForm");
@@ -1870,7 +1903,7 @@
 }
 
 // Test that we correctly fill a credit card form.
-TEST_F(AutofillManagerTest, FillCreditCardForm) {
+TEST_F(AutofillManagerTest, FillCreditCardForm_Simple) {
   // Set up our form data.
   FormData form;
   CreateTestCreditCardFormData(&form, true, false);
@@ -1888,7 +1921,7 @@
 }
 
 // Test that whitespace is stripped from the credit card number.
-TEST_F(AutofillManagerTest, FillCreditCardFormStripCardNumberWhitespace) {
+TEST_F(AutofillManagerTest, FillCreditCardForm_StripCardNumberWhitespace) {
   // Same as the SetUp(), but generate Elvis card with whitespace in credit
   // card number.
   personal_data_.CreateTestCreditCardWithWhitespace();
@@ -1909,7 +1942,7 @@
 }
 
 // Test that separator characters are stripped from the credit card number.
-TEST_F(AutofillManagerTest, FillCreditCardFormStripCardNumberSeparators) {
+TEST_F(AutofillManagerTest, FillCreditCardForm_StripCardNumberSeparators) {
   // Same as the SetUp(), but generate Elvis card with separator characters in
   // credit card number.
   personal_data_.CreateTestCreditCardWithSeparators();
@@ -1931,7 +1964,7 @@
 
 // Test that we correctly fill a credit card form with month input type.
 // 1. year empty, month empty
-TEST_F(AutofillManagerTest, FillCreditCardFormNoYearNoMonth) {
+TEST_F(AutofillManagerTest, FillCreditCardForm_NoYearNoMonth) {
   // Same as the SetUp(), but generate 4 credit cards with year month
   // combination.
   personal_data_.CreateTestCreditCardsYearAndMonth("", "");
@@ -1954,7 +1987,7 @@
 
 // Test that we correctly fill a credit card form with month input type.
 // 2. year empty, month non-empty
-TEST_F(AutofillManagerTest, FillCreditCardFormNoYearMonth) {
+TEST_F(AutofillManagerTest, FillCreditCardForm_NoYearMonth) {
   // Same as the SetUp(), but generate 4 credit cards with year month
   // combination.
   personal_data_.CreateTestCreditCardsYearAndMonth("", "04");
@@ -1976,7 +2009,7 @@
 
 // Test that we correctly fill a credit card form with month input type.
 // 3. year non-empty, month empty
-TEST_F(AutofillManagerTest, FillCreditCardFormYearNoMonth) {
+TEST_F(AutofillManagerTest, FillCreditCardForm_YearNoMonth) {
   // Same as the SetUp(), but generate 4 credit cards with year month
   // combination.
   personal_data_.CreateTestCreditCardsYearAndMonth("2999", "");
@@ -1998,7 +2031,7 @@
 
 // Test that we correctly fill a credit card form with month input type.
 // 4. year non-empty, month empty
-TEST_F(AutofillManagerTest, FillCreditCardFormYearMonth) {
+TEST_F(AutofillManagerTest, FillCreditCardForm_YearMonth) {
   // Same as the SetUp(), but generate 4 credit cards with year month
   // combination.
   personal_data_.ClearCreditCards();
@@ -2021,7 +2054,7 @@
 
 // Test that we correctly fill a credit card form with first and last cardholder
 // name.
-TEST_F(AutofillManagerTest, FillCreditCardFormSplitName) {
+TEST_F(AutofillManagerTest, FillCreditCardForm_SplitName) {
   // Set up our form data.
   FormData form;
   form.name = ASCIIToUTF16("MyForm");
@@ -2966,15 +2999,12 @@
   autofill_manager_.reset(
       new TestAutofillManager(autofill_driver_.get(), &client, NULL));
   autofill_manager_->set_autofill_enabled(false);
-  autofill_manager_->autocomplete_history_manager_.reset(
-      new MockAutocompleteHistoryManager(autofill_driver_.get(), &client));
 
   // Set up our form data.
   FormData form;
   test::CreateTestAddressFormData(&form);
-  MockAutocompleteHistoryManager* m = static_cast<
-      MockAutocompleteHistoryManager*>(
-          autofill_manager_->autocomplete_history_manager_.get());
+
+  MockAutocompleteHistoryManager* m = RecreateMockAutocompleteHistoryManager();
   EXPECT_CALL(*m, OnWillSubmitForm(_));
   FormSubmitted(form);
 }
@@ -2996,13 +3026,8 @@
   const FormFieldData& field = form.fields[0];
 
   // Expect Autocomplete manager to be called for suggestions.
-  autofill_manager_->autocomplete_history_manager_.reset(
-      new MockAutocompleteHistoryManager(autofill_driver_.get(), &client));
-  MockAutocompleteHistoryManager* m = static_cast<
-      MockAutocompleteHistoryManager*>(
-          autofill_manager_->autocomplete_history_manager_.get());
-  EXPECT_CALL(*m,
-      OnGetAutocompleteSuggestions(_, _, _, _));
+  MockAutocompleteHistoryManager* m = RecreateMockAutocompleteHistoryManager();
+  EXPECT_CALL(*m, OnGetAutocompleteSuggestions(_, _, _, _));
 
   GetAutofillSuggestions(form, field);
 }
@@ -3026,13 +3051,9 @@
   field.should_autocomplete = false;
 
   // Autocomplete manager is not called for suggestions.
-  autofill_manager_->autocomplete_history_manager_.reset(
-      new MockAutocompleteHistoryManager(autofill_driver_.get(), &client));
-  MockAutocompleteHistoryManager* m = static_cast<
-      MockAutocompleteHistoryManager*>(
-          autofill_manager_->autocomplete_history_manager_.get());
-  EXPECT_CALL(*m,
-      OnGetAutocompleteSuggestions(_, _, _, _)).Times(0);
+
+  MockAutocompleteHistoryManager* m = RecreateMockAutocompleteHistoryManager();
+  EXPECT_CALL(*m, OnGetAutocompleteSuggestions(_, _, _, _)).Times(0);
 
   GetAutofillSuggestions(form, field);
 }
@@ -3049,14 +3070,8 @@
   const FormFieldData& field = form.fields[0];
 
   // Autocomplete manager is not called for suggestions.
-  autofill_manager_->autocomplete_history_manager_.reset(
-      new MockAutocompleteHistoryManager(autofill_driver_.get(),
-          autofill_manager_->client()));
-  MockAutocompleteHistoryManager* m = static_cast<
-      MockAutocompleteHistoryManager*>(
-          autofill_manager_->autocomplete_history_manager_.get());
-  EXPECT_CALL(*m,
-      OnGetAutocompleteSuggestions(_, _, _, _)).Times(0);
+  MockAutocompleteHistoryManager* m = RecreateMockAutocompleteHistoryManager();
+  EXPECT_CALL(*m, OnGetAutocompleteSuggestions(_, _, _, _)).Times(0);
 
   GetAutofillSuggestions(form, field);
 
@@ -3082,14 +3097,8 @@
   test::CreateTestFormField("Email", "email", "donkey", "email", &field);
 
   // Autocomplete manager is called for suggestions because Autofill is empty.
-  autofill_manager_->autocomplete_history_manager_.reset(
-      new MockAutocompleteHistoryManager(autofill_driver_.get(),
-          autofill_manager_->client()));
-  MockAutocompleteHistoryManager* m = static_cast<
-      MockAutocompleteHistoryManager*>(
-          autofill_manager_->autocomplete_history_manager_.get());
-  EXPECT_CALL(*m,
-      OnGetAutocompleteSuggestions(_, _, _, _));
+  MockAutocompleteHistoryManager* m = RecreateMockAutocompleteHistoryManager();
+  EXPECT_CALL(*m, OnGetAutocompleteSuggestions(_, _, _, _));
 
   GetAutofillSuggestions(form, field);
 }
@@ -3115,12 +3124,7 @@
   field.should_autocomplete = true;
 
   // Autocomplete manager is not called for suggestions.
-  autofill_manager_->autocomplete_history_manager_.reset(
-      new MockAutocompleteHistoryManager(autofill_driver_.get(),
-                                         autofill_manager_->client()));
-  MockAutocompleteHistoryManager* m =
-      static_cast<MockAutocompleteHistoryManager*>(
-          autofill_manager_->autocomplete_history_manager_.get());
+  MockAutocompleteHistoryManager* m = RecreateMockAutocompleteHistoryManager();
   EXPECT_CALL(*m, OnGetAutocompleteSuggestions(_, _, _, _));
 
   GetAutofillSuggestions(form, field);
@@ -3146,11 +3150,7 @@
   field.should_autocomplete = true;
 
   // Autocomplete manager is not called for suggestions.
-  autofill_manager_->autocomplete_history_manager_.reset(
-      new MockAutocompleteHistoryManager(autofill_driver_.get(), &client));
-  MockAutocompleteHistoryManager* m =
-      static_cast<MockAutocompleteHistoryManager*>(
-          autofill_manager_->autocomplete_history_manager_.get());
+  MockAutocompleteHistoryManager* m = RecreateMockAutocompleteHistoryManager();
   EXPECT_CALL(*m, OnGetAutocompleteSuggestions(_, _, _, _)).Times(0);
 
   GetAutofillSuggestions(form, field);
@@ -3173,14 +3173,8 @@
   test::CreateTestFormField("Email", "email", "donkey", "email", &field);
 
   // Autocomplete manager is not called for suggestions.
-  autofill_manager_->autocomplete_history_manager_.reset(
-      new MockAutocompleteHistoryManager(autofill_driver_.get(),
-          autofill_manager_->client()));
-  MockAutocompleteHistoryManager* m = static_cast<
-      MockAutocompleteHistoryManager*>(
-          autofill_manager_->autocomplete_history_manager_.get());
-  EXPECT_CALL(*m,
-      OnGetAutocompleteSuggestions(_, _, _, _)).Times(0);
+  MockAutocompleteHistoryManager* m = RecreateMockAutocompleteHistoryManager();
+  EXPECT_CALL(*m, OnGetAutocompleteSuggestions(_, _, _, _)).Times(0);
 
   GetAutofillSuggestions(form, field);
 }
@@ -3192,13 +3186,8 @@
   autofill_manager_->set_autofill_enabled(false);
   autofill_manager_->SetExternalDelegate(external_delegate_.get());
 
-  autofill_manager_->autocomplete_history_manager_.reset(
-      new MockAutocompleteHistoryManager(autofill_driver_.get(), &client));
-  MockAutocompleteHistoryManager* m = static_cast<
-      MockAutocompleteHistoryManager*>(
-          autofill_manager_->autocomplete_history_manager_.get());
-  EXPECT_CALL(*m,
-      OnGetAutocompleteSuggestions(_, _, _, _)).Times(0);
+  MockAutocompleteHistoryManager* m = RecreateMockAutocompleteHistoryManager();
+  EXPECT_CALL(*m, OnGetAutocompleteSuggestions(_, _, _, _)).Times(0);
 
   // Set up our form data.
   FormData form;
@@ -4125,7 +4114,8 @@
 
 // Test to verify suggestions appears for forms having credit card number split
 // across fields.
-TEST_F(AutofillManagerTest, GetCreditCardSuggestionsForNumberSpitAcrossFields) {
+TEST_F(AutofillManagerTest,
+       GetCreditCardSuggestions_ForNumberSpitAcrossFields) {
   // Set up our form data with credit card number split across fields.
   FormData form;
   form.name = ASCIIToUTF16("MyForm");
@@ -4182,15 +4172,9 @@
 // Test that inputs detected to be CVC inputs are forced to
 // !should_autocomplete for AutocompleteHistoryManager::OnWillSubmitForm.
 TEST_F(AutofillManagerTest, DontSaveCvcInAutocompleteHistory) {
-  autofill_manager_->autocomplete_history_manager_.reset(
-      new MockAutocompleteHistoryManager(autofill_driver_.get(),
-                                         &autofill_client_));
   FormData form_seen_by_ahm;
-  MockAutocompleteHistoryManager* mock_ahm =
-      static_cast<MockAutocompleteHistoryManager*>(
-          autofill_manager_->autocomplete_history_manager_.get());
-  EXPECT_CALL(*mock_ahm, OnWillSubmitForm(_))
-      .WillOnce(SaveArg<0>(&form_seen_by_ahm));
+  MockAutocompleteHistoryManager* m = RecreateMockAutocompleteHistoryManager();
+  EXPECT_CALL(*m, OnWillSubmitForm(_)).WillOnce(SaveArg<0>(&form_seen_by_ahm));
 
   FormData form;
   form.name = ASCIIToUTF16("MyForm");
diff --git a/components/autofill/core/browser/autofill_metrics.cc b/components/autofill/core/browser/autofill_metrics.cc
index aed621c..7bcb4517 100644
--- a/components/autofill/core/browser/autofill_metrics.cc
+++ b/components/autofill/core/browser/autofill_metrics.cc
@@ -265,6 +265,13 @@
 }
 
 // static
+void AutofillMetrics::LogCreditCardFillingInfoBarMetric(InfoBarMetric metric) {
+  DCHECK_LT(metric, NUM_INFO_BAR_METRICS);
+  UMA_HISTOGRAM_ENUMERATION("Autofill.CreditCardFillingInfoBar", metric,
+                            NUM_INFO_BAR_METRICS);
+}
+
+// static
 void AutofillMetrics::LogSaveCardPromptMetric(SaveCardPromptMetric metric,
                                               bool is_uploading,
                                               bool is_reshow) {
diff --git a/components/autofill/core/browser/autofill_metrics.h b/components/autofill/core/browser/autofill_metrics.h
index d0fcb7c..8f8b4239 100644
--- a/components/autofill/core/browser/autofill_metrics.h
+++ b/components/autofill/core/browser/autofill_metrics.h
@@ -513,6 +513,7 @@
 
   static void LogCardUploadDecisionMetric(CardUploadDecisionMetric metric);
   static void LogCreditCardInfoBarMetric(InfoBarMetric metric);
+  static void LogCreditCardFillingInfoBarMetric(InfoBarMetric metric);
   static void LogSaveCardPromptMetric(SaveCardPromptMetric metric,
                                       bool is_uploading,
                                       bool is_reshow);
diff --git a/components/autofill/core/browser/autofill_save_card_infobar_delegate_mobile.cc b/components/autofill/core/browser/autofill_save_card_infobar_delegate_mobile.cc
index 471e0d2f..4343a1f 100644
--- a/components/autofill/core/browser/autofill_save_card_infobar_delegate_mobile.cc
+++ b/components/autofill/core/browser/autofill_save_card_infobar_delegate_mobile.cc
@@ -97,7 +97,7 @@
     InfoBarButton button) const {
   return l10n_util::GetStringUTF16(button == BUTTON_OK
                                        ? IDS_AUTOFILL_SAVE_CARD_PROMPT_ACCEPT
-                                       : IDS_AUTOFILL_SAVE_CARD_PROMPT_DENY);
+                                       : IDS_NO_THANKS);
 }
 
 bool AutofillSaveCardInfoBarDelegateMobile::Accept() {
diff --git a/components/autofill/core/browser/form_structure.cc b/components/autofill/core/browser/form_structure.cc
index 164bd717..5d6815f 100644
--- a/components/autofill/core/browser/form_structure.cc
+++ b/components/autofill/core/browser/form_structure.cc
@@ -290,6 +290,14 @@
   return out;
 }
 
+bool IsCreditCardExpirationType(ServerFieldType type) {
+  return type == CREDIT_CARD_EXP_MONTH ||
+         type == CREDIT_CARD_EXP_2_DIGIT_YEAR ||
+         type == CREDIT_CARD_EXP_4_DIGIT_YEAR ||
+         type == CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR ||
+         type == CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR;
+}
+
 }  // namespace
 
 FormStructure::FormStructure(const FormData& form)
@@ -577,6 +585,22 @@
   return ShouldBeParsed();
 }
 
+bool FormStructure::IsCompleteCreditCardForm() const {
+  bool found_cc_number = false;
+  bool found_cc_expiration = false;
+  for (const AutofillField* field : fields_) {
+    ServerFieldType type = field->Type().GetStorableType();
+    if (!found_cc_expiration && IsCreditCardExpirationType(type)) {
+      found_cc_expiration = true;
+    } else if (!found_cc_number && type == CREDIT_CARD_NUMBER) {
+      found_cc_number = true;
+    }
+    if (found_cc_expiration && found_cc_number)
+      return true;
+  }
+  return false;
+}
+
 void FormStructure::UpdateAutofillCount() {
   autofill_count_ = 0;
   for (const AutofillField* field : *this) {
diff --git a/components/autofill/core/browser/form_structure.h b/components/autofill/core/browser/form_structure.h
index aab2a66..074c229 100644
--- a/components/autofill/core/browser/form_structure.h
+++ b/components/autofill/core/browser/form_structure.h
@@ -99,6 +99,11 @@
   // auto-fillable, like google/yahoo/msn search, etc.
   bool IsAutofillable() const;
 
+  // Returns whether |this| form represents a complete Credit Card form, which
+  // consists in having at least a credit card number field and an expiration
+  // field.
+  bool IsCompleteCreditCardForm() const;
+
   // Resets |autofill_count_| and counts the number of auto-fillable fields.
   // This is used when we receive server data for form fields.  At that time,
   // we may have more known fields than just the number of fields we matched
diff --git a/components/autofill/core/browser/form_structure_unittest.cc b/components/autofill/core/browser/form_structure_unittest.cc
index 0463c67..8d7f6473 100644
--- a/components/autofill/core/browser/form_structure_unittest.cc
+++ b/components/autofill/core/browser/form_structure_unittest.cc
@@ -605,6 +605,129 @@
   EXPECT_EQ(ADDRESS_HOME_LINE3, form_structure->field(2)->heuristic_type());
 }
 
+TEST_F(FormStructureTest, IsCompleteCreditCardForm_Minimal) {
+  std::unique_ptr<FormStructure> form_structure;
+  FormData form;
+
+  FormFieldData field;
+  field.form_control_type = "text";
+
+  field.label = ASCIIToUTF16("Card Number");
+  field.name = ASCIIToUTF16("card_number");
+  form.fields.push_back(field);
+
+  field.label = ASCIIToUTF16("Expiration");
+  field.name = ASCIIToUTF16("cc_exp");
+  form.fields.push_back(field);
+
+  // Another field to reach the minimum 3.
+  field.label = ASCIIToUTF16("Zip");
+  field.name = ASCIIToUTF16("zip");
+  form.fields.push_back(field);
+
+  form_structure.reset(new FormStructure(form));
+  form_structure->DetermineHeuristicTypes();
+
+  EXPECT_TRUE(form_structure->IsCompleteCreditCardForm());
+}
+
+TEST_F(FormStructureTest, IsCompleteCreditCardForm_Full) {
+  std::unique_ptr<FormStructure> form_structure;
+  FormData form;
+
+  FormFieldData field;
+  field.form_control_type = "text";
+
+  field.label = ASCIIToUTF16("Name on Card");
+  field.name = ASCIIToUTF16("name_on_card");
+  form.fields.push_back(field);
+
+  field.label = ASCIIToUTF16("Card Number");
+  field.name = ASCIIToUTF16("card_number");
+  form.fields.push_back(field);
+
+  field.label = ASCIIToUTF16("Exp Month");
+  field.name = ASCIIToUTF16("ccmonth");
+  form.fields.push_back(field);
+
+  field.label = ASCIIToUTF16("Exp Year");
+  field.name = ASCIIToUTF16("ccyear");
+  form.fields.push_back(field);
+
+  field.label = ASCIIToUTF16("Verification");
+  field.name = ASCIIToUTF16("verification");
+  form.fields.push_back(field);
+
+  field.label = base::string16();
+  field.name = ASCIIToUTF16("Submit");
+  field.form_control_type = "submit";
+  form.fields.push_back(field);
+
+  form_structure.reset(new FormStructure(form));
+  form_structure->DetermineHeuristicTypes();
+
+  EXPECT_TRUE(form_structure->IsCompleteCreditCardForm());
+}
+
+// A form with only the credit card number is not considered sufficient.
+TEST_F(FormStructureTest, IsCompleteCreditCardForm_OnlyCCNumber) {
+  std::unique_ptr<FormStructure> form_structure;
+  FormData form;
+
+  FormFieldData field;
+  field.form_control_type = "text";
+
+  field.label = ASCIIToUTF16("Card Number");
+  field.name = ASCIIToUTF16("card_number");
+  form.fields.push_back(field);
+
+  form_structure.reset(new FormStructure(form));
+  form_structure->DetermineHeuristicTypes();
+
+  EXPECT_FALSE(form_structure->IsCompleteCreditCardForm());
+}
+
+// A form with only the credit card number is not considered sufficient.
+TEST_F(FormStructureTest, IsCompleteCreditCardForm_AddressForm) {
+  std::unique_ptr<FormStructure> form_structure;
+  FormData form;
+
+  FormFieldData field;
+  field.form_control_type = "text";
+
+  field.label = ASCIIToUTF16("First Name");
+  field.name = base::string16();
+  form.fields.push_back(field);
+
+  field.label = ASCIIToUTF16("Last Name");
+  field.name = base::string16();
+  form.fields.push_back(field);
+
+  field.label = ASCIIToUTF16("Email");
+  field.name = base::string16();
+  form.fields.push_back(field);
+
+  field.label = ASCIIToUTF16("Phone");
+  field.name = base::string16();
+  form.fields.push_back(field);
+
+  field.label = ASCIIToUTF16("Address");
+  field.name = base::string16();
+  form.fields.push_back(field);
+
+  field.label = ASCIIToUTF16("Address");
+  field.name = base::string16();
+  form.fields.push_back(field);
+
+  field.label = ASCIIToUTF16("Zip code");
+  field.name = base::string16();
+  form.fields.push_back(field);
+  form_structure.reset(new FormStructure(form));
+  form_structure->DetermineHeuristicTypes();
+
+  EXPECT_FALSE(form_structure->IsCompleteCreditCardForm());
+}
+
 // Verify that we can correctly process the 'autocomplete' attribute for phone
 // number types (especially phone prefixes and suffixes).
 TEST_F(FormStructureTest, HeuristicsAutocompleteAttributePhoneTypes) {
diff --git a/components/autofill/core/browser/test_autofill_client.cc b/components/autofill/core/browser/test_autofill_client.cc
index 647696c..37ea5b5 100644
--- a/components/autofill/core/browser/test_autofill_client.cc
+++ b/components/autofill/core/browser/test_autofill_client.cc
@@ -66,6 +66,12 @@
   callback.Run();
 }
 
+void TestAutofillClient::ConfirmCreditCardFillAssist(
+    const CreditCard& card,
+    const base::Closure& callback) {
+  callback.Run();
+}
+
 void TestAutofillClient::LoadRiskData(
     const base::Callback<void(const std::string&)>& callback) {
   callback.Run("some risk data");
diff --git a/components/autofill/core/browser/test_autofill_client.h b/components/autofill/core/browser/test_autofill_client.h
index ea36a9c..e936e42e 100644
--- a/components/autofill/core/browser/test_autofill_client.h
+++ b/components/autofill/core/browser/test_autofill_client.h
@@ -43,6 +43,8 @@
       const CreditCard& card,
       std::unique_ptr<base::DictionaryValue> legal_message,
       const base::Closure& callback) override;
+  void ConfirmCreditCardFillAssist(const CreditCard& card,
+                                   const base::Closure& callback) override;
   void LoadRiskData(
       const base::Callback<void(const std::string&)>& callback) override;
   bool HasCreditCardScanFeature() override;
diff --git a/components/autofill/core/common/autofill_constants.h b/components/autofill/core/common/autofill_constants.h
index ab09290..872f6974 100644
--- a/components/autofill/core/common/autofill_constants.h
+++ b/components/autofill/core/common/autofill_constants.h
@@ -32,6 +32,10 @@
 // upload the form to and request predictions from the Autofill servers.
 const size_t kRequiredFieldsForFormsWithOnlyPasswordFields = 2;
 
+// Special query id used between the browser and the renderer when the action
+// is initiated from the browser.
+const int kNoQueryId = -1;
+
 // Options bitmask values for AutofillHostMsg_ShowPasswordSuggestions IPC
 enum ShowPasswordSuggestionsOptions {
   SHOW_ALL = 1 << 0 /* show all credentials, not just ones matching username */,
diff --git a/components/autofill_strings.grdp b/components/autofill_strings.grdp
index 4b7b57e..1c8fef8a 100644
--- a/components/autofill_strings.grdp
+++ b/components/autofill_strings.grdp
@@ -174,13 +174,18 @@
     Use password for:
   </message>
 
+  <!-- Autofill Credit Card Assisted Filling Infobar -->
+  <message name="IDS_AUTOFILL_CREDIT_CARD_FILLING_INFOBAR_TITLE" desc="Title text for the Autofill Credit Card Assisted Filling Infobar">
+    Do you want to fill in your card info?
+  </message>
+  <message name="IDS_AUTOFILL_CREDIT_CARD_FILLING_INFOBAR_ACCEPT" desc="Text to show for the Autofill credit card Assisted Filling infobar accept button.">
+    Fill in
+  </message>
+
   <!-- Autofill save credit card bubble or infobar prompt -->
   <message name="IDS_AUTOFILL_SAVE_CARD_PROMPT_ACCEPT" desc="Text to show for the Autofill save credit card prompt accept button. The prompt can be either a bubble or an infobar.">
     Save
   </message>
-  <message name="IDS_AUTOFILL_SAVE_CARD_PROMPT_DENY" desc="Text to show for the Autofill save credit card prompt deny button. The prompt can be either a bubble or an infobar.">
-    No thanks
-  </message>
   <if expr="_google_chrome">
     <message name="IDS_AUTOFILL_SAVE_CARD_PROMPT_TITLE_LOCAL" desc="Title text for the Autofill save card prompt when the card is to be saved locally. The prompt can be either a bubble or an infobar.">
       Do you want Chrome to save this card?
diff --git a/components/browsing_data/content/storage_partition_http_cache_data_remover.cc b/components/browsing_data/content/storage_partition_http_cache_data_remover.cc
index b7126eee..c0f2051 100644
--- a/components/browsing_data/content/storage_partition_http_cache_data_remover.cc
+++ b/components/browsing_data/content/storage_partition_http_cache_data_remover.cc
@@ -155,7 +155,7 @@
         // Clear QUIC server information from memory and the disk cache.
         http_cache->GetSession()
             ->quic_stream_factory()
-            ->ClearCachedStatesInCryptoConfig();
+            ->ClearCachedStatesInCryptoConfig(url_predicate_);
 
         // Clear SDCH dictionary state.
         net::SdchManager* sdch_manager =
diff --git a/components/cast_certificate/cast_cert_validator.cc b/components/cast_certificate/cast_cert_validator.cc
index f7c62dd..9dcff2f 100644
--- a/components/cast_certificate/cast_cert_validator.cc
+++ b/components/cast_certificate/cast_cert_validator.cc
@@ -251,14 +251,14 @@
   return options;
 }
 
-}  // namespace
-
+// Verifies a cast device certficate given a chain of DER-encoded certificates.
 bool VerifyDeviceCert(const std::vector<std::string>& certs,
                       const base::Time& time,
                       std::unique_ptr<CertVerificationContext>* context,
                       CastDeviceCertPolicy* policy,
                       const CastCRL* crl,
-                      CRLPolicy crl_policy) {
+                      CRLPolicy crl_policy,
+                      net::TrustStore* trust_store) {
   if (certs.empty())
     return false;
 
@@ -290,7 +290,7 @@
   if (!net::der::EncodeTimeAsGeneralizedTime(time, &verification_time))
     return false;
   net::CertPathBuilder::Result result;
-  net::CertPathBuilder path_builder(target_cert.get(), &CastTrustStore::Get(),
+  net::CertPathBuilder path_builder(target_cert.get(), trust_store,
                                     signature_policy.get(), verification_time,
                                     &result);
   path_builder.AddCertIssuerSource(&intermediate_cert_issuer_source);
@@ -322,6 +322,29 @@
   return true;
 }
 
+}  // namespace
+
+bool VerifyDeviceCert(const std::vector<std::string>& certs,
+                      const base::Time& time,
+                      std::unique_ptr<CertVerificationContext>* context,
+                      CastDeviceCertPolicy* policy,
+                      const CastCRL* crl,
+                      CRLPolicy crl_policy) {
+  return VerifyDeviceCert(certs, time, context, policy, crl, crl_policy,
+                          &CastTrustStore::Get());
+}
+
+bool VerifyDeviceCertForTest(const std::vector<std::string>& certs,
+                             const base::Time& time,
+                             std::unique_ptr<CertVerificationContext>* context,
+                             CastDeviceCertPolicy* policy,
+                             const CastCRL* crl,
+                             CRLPolicy crl_policy,
+                             net::TrustStore* trust_store) {
+  return VerifyDeviceCert(certs, time, context, policy, crl, crl_policy,
+                          trust_store);
+}
+
 std::unique_ptr<CertVerificationContext> CertVerificationContextImplForTest(
     const base::StringPiece& spki) {
   // Use a bogus CommonName, since this is just exposed for testing signature
@@ -330,15 +353,4 @@
       new CertVerificationContextImpl(net::der::Input(spki), "CommonName"));
 }
 
-bool SetTrustAnchorForTest(const std::string& cert) {
-  scoped_refptr<net::ParsedCertificate> anchor(
-      net::ParsedCertificate::CreateFromCertificateCopy(
-          cert, GetCertParsingOptions()));
-  if (!anchor)
-    return false;
-  CastTrustStore::Get().Clear();
-  CastTrustStore::Get().AddTrustedCertificate(std::move(anchor));
-  return true;
-}
-
 }  // namespace cast_certificate
diff --git a/components/cast_certificate/cast_cert_validator.h b/components/cast_certificate/cast_cert_validator.h
index be924be7..a918dd58 100644
--- a/components/cast_certificate/cast_cert_validator.h
+++ b/components/cast_certificate/cast_cert_validator.h
@@ -14,6 +14,9 @@
 #include "base/strings/string_piece.h"
 #include "base/time/time.h"
 
+namespace net {
+class TrustStore;
+}
 namespace cast_certificate {
 
 class CastCRL;
@@ -59,7 +62,8 @@
   DISALLOW_COPY_AND_ASSIGN(CertVerificationContext);
 };
 
-// Verifies a cast device certficate given a chain of DER-encoded certificates.
+// Verifies a cast device certficate given a chain of DER-encoded certificates,
+// using the built-in Cast trust anchors.
 //
 // Inputs:
 //
@@ -95,6 +99,18 @@
                       const CastCRL* crl,
                       CRLPolicy crl_policy) WARN_UNUSED_RESULT;
 
+// Exposed only for testing, not for use in production code.
+//
+// This is an overloaded version of VerifyDeviceCert that allows
+// the input of a custom TrustStore.
+bool VerifyDeviceCertForTest(const std::vector<std::string>& certs,
+                             const base::Time& time,
+                             std::unique_ptr<CertVerificationContext>* context,
+                             CastDeviceCertPolicy* policy,
+                             const CastCRL* crl,
+                             CRLPolicy crl_policy,
+                             net::TrustStore* trust_store) WARN_UNUSED_RESULT;
+
 // Exposed only for unit-tests, not for use in production code.
 // Production code would get a context from VerifyDeviceCert().
 //
@@ -103,12 +119,6 @@
 std::unique_ptr<CertVerificationContext> CertVerificationContextImplForTest(
     const base::StringPiece& spki);
 
-// Exposed only for testing, not for use in production code.
-//
-// Replaces trusted root certificates in the CastTrustStore.
-// Returns true if successful, false if nothing is changed.
-bool SetTrustAnchorForTest(const std::string& cert) WARN_UNUSED_RESULT;
-
 }  // namespace cast_certificate
 
 #endif  // COMPONENTS_CAST_CERTIFICATE_CAST_CERT_VALIDATOR_H_
diff --git a/components/cast_certificate/cast_crl.cc b/components/cast_certificate/cast_crl.cc
index 7efd90b..94ecb1a 100644
--- a/components/cast_certificate/cast_crl.cc
+++ b/components/cast_certificate/cast_crl.cc
@@ -62,13 +62,12 @@
 
   CastCRLTrustStore() {
     // Initialize the trust store with the root certificate.
-    // TODO(ryanchung): Add official Cast CRL Root here
-    // scoped_refptr<net::ParsedCertificate> root = net::ParsedCertificate::
-    //     net::ParsedCertificate::CreateFromCertificateData(
-    //         kCastCRLRootCaDer, sizeof(kCastCRLRootCaDer),
-    //         net::ParsedCertificate::DataSource::EXTERNAL_REFERENCE, {});
-    // CHECK(root);
-    // store_.AddTrustedCertificate(std::move(root));
+    scoped_refptr<net::ParsedCertificate> root =
+        net::ParsedCertificate::CreateFromCertificateData(
+            kCastCRLRootCaDer, sizeof(kCastCRLRootCaDer),
+            net::ParsedCertificate::DataSource::EXTERNAL_REFERENCE, {});
+    CHECK(root);
+    store_.AddTrustedCertificate(std::move(root));
   }
 
   net::TrustStore store_;
@@ -101,6 +100,7 @@
 bool VerifyCRL(const Crl& crl,
                const TbsCrl& tbs_crl,
                const base::Time& time,
+               net::TrustStore* trust_store,
                net::der::GeneralizedTime* overall_not_after) {
   // Verify the trust of the CRL authority.
   scoped_refptr<net::ParsedCertificate> parsed_cert =
@@ -136,9 +136,9 @@
     return false;
   }
   net::CertPathBuilder::Result result;
-  net::CertPathBuilder path_builder(
-      parsed_cert.get(), &CastCRLTrustStore::Get(), signature_policy.get(),
-      verification_time, &result);
+  net::CertPathBuilder path_builder(parsed_cert.get(), trust_store,
+                                    signature_policy.get(), verification_time,
+                                    &result);
   net::CompletionStatus rv = path_builder.Run(base::Closure());
   DCHECK_EQ(rv, net::CompletionStatus::SYNC);
   if (!result.is_success() || result.paths.empty() ||
@@ -298,10 +298,11 @@
   return true;
 }
 
-}  // namespace
-
+// Parses and verifies the CRL used to verify the revocation status of
+// Cast device certificates.
 std::unique_ptr<CastCRL> ParseAndVerifyCRL(const std::string& crl_proto,
-                                           const base::Time& time) {
+                                           const base::Time& time,
+                                           net::TrustStore* trust_store) {
   CrlBundle crl_bundle;
   if (!crl_bundle.ParseFromString(crl_proto)) {
     LOG(ERROR) << "CRL - Binary could not be parsed.";
@@ -317,7 +318,7 @@
       continue;
     }
     net::der::GeneralizedTime overall_not_after;
-    if (!VerifyCRL(crl, tbs_crl, time, &overall_not_after)) {
+    if (!VerifyCRL(crl, tbs_crl, time, trust_store, &overall_not_after)) {
       LOG(ERROR) << "CRL - Verification failed.";
       return nullptr;
     }
@@ -327,14 +328,18 @@
   return nullptr;
 }
 
-bool SetCRLTrustAnchorForTest(const std::string& cert) {
-  scoped_refptr<net::ParsedCertificate> anchor(
-      net::ParsedCertificate::CreateFromCertificateCopy(cert, {}));
-  if (!anchor)
-    return false;
-  CastCRLTrustStore::Get().Clear();
-  CastCRLTrustStore::Get().AddTrustedCertificate(std::move(anchor));
-  return true;
+}  // namespace
+
+std::unique_ptr<CastCRL> ParseAndVerifyCRL(const std::string& crl_proto,
+                                           const base::Time& time) {
+  return ParseAndVerifyCRL(crl_proto, time, &CastCRLTrustStore::Get());
+}
+
+std::unique_ptr<CastCRL> ParseAndVerifyCRLForTest(
+    const std::string& crl_proto,
+    const base::Time& time,
+    net::TrustStore* trust_store) {
+  return ParseAndVerifyCRL(crl_proto, time, trust_store);
 }
 
 }  // namespace cast_certificate
diff --git a/components/cast_certificate/cast_crl.h b/components/cast_certificate/cast_crl.h
index e95faf48..f7d102a9 100644
--- a/components/cast_certificate/cast_crl.h
+++ b/components/cast_certificate/cast_crl.h
@@ -14,6 +14,10 @@
 #include "base/time/time.h"
 #include "net/cert/internal/parsed_certificate.h"
 
+namespace net {
+class TrustStore;
+}
+
 namespace cast_certificate {
 
 // This class represents the CRL information parsed from the binary proto.
@@ -40,7 +44,7 @@
 };
 
 // Parses and verifies the CRL used to verify the revocation status of
-// Cast device certificates.
+// Cast device certificates, using the built-in Cast CRL trust anchors.
 //
 // Inputs:
 // * |crl_proto| is a serialized cast_certificate.CrlBundle proto.
@@ -53,11 +57,11 @@
 
 // Exposed only for testing, not for use in production code.
 //
-// Replaces trusted root certificates into the CastCRLTrustStore.
-//
-// Output:
-// Returns true if successful, false if nothing is changed.
-bool SetCRLTrustAnchorForTest(const std::string& cert) WARN_UNUSED_RESULT;
+// This is an overloaded version of ParseAndVerifyCRL that allows
+// the input of a custom TrustStore.
+std::unique_ptr<CastCRL> ParseAndVerifyCRLForTest(const std::string& crl_proto,
+                                                  const base::Time& time,
+                                                  net::TrustStore* trust_store);
 
 }  // namespace cast_certificate
 
diff --git a/components/cast_certificate/cast_crl_root_ca_cert_der-inc.h b/components/cast_certificate/cast_crl_root_ca_cert_der-inc.h
index 5463d19..75380151 100644
--- a/components/cast_certificate/cast_crl_root_ca_cert_der-inc.h
+++ b/components/cast_certificate/cast_crl_root_ca_cert_der-inc.h
@@ -2,7 +2,149 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-// TODO(ryanchung): Add Cast CRL Root here.
+// Certificate:
+//     Data:
+//         Version: 3 (0x2)
+//         Serial Number: 153 (0x99)
+//     Signature Algorithm: sha256WithRSAEncryption
+//         Issuer: C=US, ST=California, L=Mountain View, O=Google Inc,
+//                 OU=Cast, CN=Cast CRL Root CA
+//         Validity
+//             Not Before: Aug  1 21:47:47 2016 GMT
+//             Not After : Jul 27 21:47:47 2036 GMT
+//         Subject: C=US, ST=California, L=Mountain View, O=Google Inc, OU=Cast,
+//                  CN=Cast CRL Root CA
+//         Subject Public Key Info:
+//             Public Key Algorithm: rsaEncryption
+//                 Public-Key: (2048 bit)
+//                 Modulus:
+//                     00:c2:7f:c0:09:21:d3:60:89:28:b5:96:6e:fe:a6:
+//                     ad:fe:ae:e0:66:35:bd:99:6e:e8:93:85:29:ba:de:
+//                     44:5d:a8:6b:fc:e6:cc:37:dd:1d:0f:cf:1e:3a:32:
+//                     2c:7f:e0:1b:c9:bb:4c:34:a9:1c:97:b5:f8:6d:42:
+//                     9c:4d:06:6a:a0:2d:95:55:3f:78:1d:5c:ab:e9:3a:
+//                     a6:08:3b:5a:af:f4:ab:53:77:14:9a:6b:b2:37:2e:
+//                     cd:6e:ea:bc:22:5d:56:55:73:fd:bd:03:2f:54:5e:
+//                     7f:8b:c1:74:36:1a:18:1f:64:de:bf:08:80:4a:12:
+//                     0c:49:53:b8:c7:3b:db:5f:dc:59:77:2f:b8:3a:05:
+//                     8a:f6:b7:47:2a:9b:74:63:08:31:12:e6:7b:44:d1:
+//                     c1:7c:c8:87:b8:50:63:6d:9f:d7:ba:36:53:72:47:
+//                     5f:dc:43:43:eb:d7:2e:11:d1:8a:7a:a4:03:f2:6a:
+//                     d3:88:e6:a7:b8:9d:81:b2:b0:88:24:c8:a1:fa:b0:
+//                     aa:db:08:64:3e:8b:2a:07:5c:5a:82:05:99:c2:d5:
+//                     ca:52:75:21:a7:fa:c5:a1:da:ac:f7:fe:d0:c7:44:
+//                     76:9a:eb:6b:d3:bd:f4:7a:31:a6:ad:2f:5a:c4:31:
+//                     3a:6d:f1:dd:7b:44:81:37:cf:13:85:5d:96:ae:7b:
+//                     96:2b
+//                 Exponent: 65537 (0x10001)
+//         X509v3 extensions:
+//             X509v3 Basic Constraints:
+//                 CA:TRUE, pathlen:1
+//             X509v3 Subject Key Identifier:
+//                 1A:65:12:B4:A9:B9:B4:FC:91:0C:9E:67:E0:5B:D9:C9:AD:44:1C:B9
+//             X509v3 Authority Key Identifier:
+//                 keyid:1A:65:12:B4:A9:B9:B4:FC:91:0C:9E:67:E0:5B:D9:C9:AD:44
+//                      :1C:B9
+//
+//             X509v3 Key Usage:
+//                 Certificate Sign
+//     Signature Algorithm: sha256WithRSAEncryption
+//          af:5f:8b:c0:f7:c5:26:88:b9:ac:f7:ec:4d:0f:76:ab:e2:74:
+//          9a:44:3c:33:f6:74:3d:04:2a:59:76:a2:05:27:c4:e3:a2:c8:
+//          c2:af:7e:fd:be:b9:ca:e9:5b:a8:2a:cd:a7:1e:0e:37:f1:6f:
+//          84:5e:aa:42:1f:ba:f0:44:ba:db:87:61:68:91:bb:1d:5c:3a:
+//          f0:8e:02:20:76:aa:47:99:c7:73:0d:90:32:4a:b9:e3:fd:11:
+//          8b:5d:bd:22:4d:05:75:17:61:a2:a6:4f:b0:3d:52:8e:aa:c9:
+//          b4:8d:05:5a:1c:36:c1:7b:87:f7:f8:e4:81:36:27:ec:35:ae:
+//          b9:ce:15:47:e1:10:c9:16:69:3a:22:8e:63:18:31:cc:3b:56:
+//          69:c6:d4:24:dd:95:25:cf:34:e6:00:ae:e1:87:1e:ee:0c:14:
+//          dc:0d:82:81:31:1f:8f:6d:d2:c0:e1:7c:12:f7:9d:ca:02:e3:
+//          76:36:44:53:3a:87:71:7d:ed:32:4c:a4:96:e6:e5:2c:c7:0d:
+//          b7:96:c0:f3:7d:e5:58:32:f7:25:25:c0:13:76:d0:76:6c:73:
+//          ab:3d:15:cd:c5:e8:85:15:9a:02:52:e9:61:41:e2:66:01:c5:
+//          71:e5:db:c0:a5:b3:4c:1e:ac:93:8a:35:4c:4d:da:57:22:24:
+//          1d:3a:f6:bd
 const unsigned char kCastCRLRootCaDer[] = {
-    0x30,
+    0x30, 0x82, 0x03, 0xce, 0x30, 0x82, 0x02, 0xb6, 0xa0, 0x03, 0x02, 0x01,
+    0x02, 0x02, 0x02, 0x00, 0x99, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48,
+    0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x79, 0x31, 0x0b,
+    0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31,
+    0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0c, 0x0a, 0x43, 0x61,
+    0x6c, 0x69, 0x66, 0x6f, 0x72, 0x6e, 0x69, 0x61, 0x31, 0x16, 0x30, 0x14,
+    0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, 0x0d, 0x4d, 0x6f, 0x75, 0x6e, 0x74,
+    0x61, 0x69, 0x6e, 0x20, 0x56, 0x69, 0x65, 0x77, 0x31, 0x13, 0x30, 0x11,
+    0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x0a, 0x47, 0x6f, 0x6f, 0x67, 0x6c,
+    0x65, 0x20, 0x49, 0x6e, 0x63, 0x31, 0x0d, 0x30, 0x0b, 0x06, 0x03, 0x55,
+    0x04, 0x0b, 0x0c, 0x04, 0x43, 0x61, 0x73, 0x74, 0x31, 0x19, 0x30, 0x17,
+    0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x10, 0x43, 0x61, 0x73, 0x74, 0x20,
+    0x43, 0x52, 0x4c, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x30,
+    0x1e, 0x17, 0x0d, 0x31, 0x36, 0x30, 0x38, 0x30, 0x31, 0x32, 0x31, 0x34,
+    0x37, 0x34, 0x37, 0x5a, 0x17, 0x0d, 0x33, 0x36, 0x30, 0x37, 0x32, 0x37,
+    0x32, 0x31, 0x34, 0x37, 0x34, 0x37, 0x5a, 0x30, 0x79, 0x31, 0x0b, 0x30,
+    0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x13,
+    0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0c, 0x0a, 0x43, 0x61, 0x6c,
+    0x69, 0x66, 0x6f, 0x72, 0x6e, 0x69, 0x61, 0x31, 0x16, 0x30, 0x14, 0x06,
+    0x03, 0x55, 0x04, 0x07, 0x0c, 0x0d, 0x4d, 0x6f, 0x75, 0x6e, 0x74, 0x61,
+    0x69, 0x6e, 0x20, 0x56, 0x69, 0x65, 0x77, 0x31, 0x13, 0x30, 0x11, 0x06,
+    0x03, 0x55, 0x04, 0x0a, 0x0c, 0x0a, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65,
+    0x20, 0x49, 0x6e, 0x63, 0x31, 0x0d, 0x30, 0x0b, 0x06, 0x03, 0x55, 0x04,
+    0x0b, 0x0c, 0x04, 0x43, 0x61, 0x73, 0x74, 0x31, 0x19, 0x30, 0x17, 0x06,
+    0x03, 0x55, 0x04, 0x03, 0x0c, 0x10, 0x43, 0x61, 0x73, 0x74, 0x20, 0x43,
+    0x52, 0x4c, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x30, 0x82,
+    0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
+    0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82,
+    0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0xc2, 0x7f, 0xc0, 0x09, 0x21,
+    0xd3, 0x60, 0x89, 0x28, 0xb5, 0x96, 0x6e, 0xfe, 0xa6, 0xad, 0xfe, 0xae,
+    0xe0, 0x66, 0x35, 0xbd, 0x99, 0x6e, 0xe8, 0x93, 0x85, 0x29, 0xba, 0xde,
+    0x44, 0x5d, 0xa8, 0x6b, 0xfc, 0xe6, 0xcc, 0x37, 0xdd, 0x1d, 0x0f, 0xcf,
+    0x1e, 0x3a, 0x32, 0x2c, 0x7f, 0xe0, 0x1b, 0xc9, 0xbb, 0x4c, 0x34, 0xa9,
+    0x1c, 0x97, 0xb5, 0xf8, 0x6d, 0x42, 0x9c, 0x4d, 0x06, 0x6a, 0xa0, 0x2d,
+    0x95, 0x55, 0x3f, 0x78, 0x1d, 0x5c, 0xab, 0xe9, 0x3a, 0xa6, 0x08, 0x3b,
+    0x5a, 0xaf, 0xf4, 0xab, 0x53, 0x77, 0x14, 0x9a, 0x6b, 0xb2, 0x37, 0x2e,
+    0xcd, 0x6e, 0xea, 0xbc, 0x22, 0x5d, 0x56, 0x55, 0x73, 0xfd, 0xbd, 0x03,
+    0x2f, 0x54, 0x5e, 0x7f, 0x8b, 0xc1, 0x74, 0x36, 0x1a, 0x18, 0x1f, 0x64,
+    0xde, 0xbf, 0x08, 0x80, 0x4a, 0x12, 0x0c, 0x49, 0x53, 0xb8, 0xc7, 0x3b,
+    0xdb, 0x5f, 0xdc, 0x59, 0x77, 0x2f, 0xb8, 0x3a, 0x05, 0x8a, 0xf6, 0xb7,
+    0x47, 0x2a, 0x9b, 0x74, 0x63, 0x08, 0x31, 0x12, 0xe6, 0x7b, 0x44, 0xd1,
+    0xc1, 0x7c, 0xc8, 0x87, 0xb8, 0x50, 0x63, 0x6d, 0x9f, 0xd7, 0xba, 0x36,
+    0x53, 0x72, 0x47, 0x5f, 0xdc, 0x43, 0x43, 0xeb, 0xd7, 0x2e, 0x11, 0xd1,
+    0x8a, 0x7a, 0xa4, 0x03, 0xf2, 0x6a, 0xd3, 0x88, 0xe6, 0xa7, 0xb8, 0x9d,
+    0x81, 0xb2, 0xb0, 0x88, 0x24, 0xc8, 0xa1, 0xfa, 0xb0, 0xaa, 0xdb, 0x08,
+    0x64, 0x3e, 0x8b, 0x2a, 0x07, 0x5c, 0x5a, 0x82, 0x05, 0x99, 0xc2, 0xd5,
+    0xca, 0x52, 0x75, 0x21, 0xa7, 0xfa, 0xc5, 0xa1, 0xda, 0xac, 0xf7, 0xfe,
+    0xd0, 0xc7, 0x44, 0x76, 0x9a, 0xeb, 0x6b, 0xd3, 0xbd, 0xf4, 0x7a, 0x31,
+    0xa6, 0xad, 0x2f, 0x5a, 0xc4, 0x31, 0x3a, 0x6d, 0xf1, 0xdd, 0x7b, 0x44,
+    0x81, 0x37, 0xcf, 0x13, 0x85, 0x5d, 0x96, 0xae, 0x7b, 0x96, 0x2b, 0x02,
+    0x03, 0x01, 0x00, 0x01, 0xa3, 0x60, 0x30, 0x5e, 0x30, 0x0f, 0x06, 0x03,
+    0x55, 0x1d, 0x13, 0x04, 0x08, 0x30, 0x06, 0x01, 0x01, 0xff, 0x02, 0x01,
+    0x01, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14,
+    0x1a, 0x65, 0x12, 0xb4, 0xa9, 0xb9, 0xb4, 0xfc, 0x91, 0x0c, 0x9e, 0x67,
+    0xe0, 0x5b, 0xd9, 0xc9, 0xad, 0x44, 0x1c, 0xb9, 0x30, 0x1f, 0x06, 0x03,
+    0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0x1a, 0x65, 0x12,
+    0xb4, 0xa9, 0xb9, 0xb4, 0xfc, 0x91, 0x0c, 0x9e, 0x67, 0xe0, 0x5b, 0xd9,
+    0xc9, 0xad, 0x44, 0x1c, 0xb9, 0x30, 0x0b, 0x06, 0x03, 0x55, 0x1d, 0x0f,
+    0x04, 0x04, 0x03, 0x02, 0x02, 0x04, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86,
+    0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x01,
+    0x01, 0x00, 0xaf, 0x5f, 0x8b, 0xc0, 0xf7, 0xc5, 0x26, 0x88, 0xb9, 0xac,
+    0xf7, 0xec, 0x4d, 0x0f, 0x76, 0xab, 0xe2, 0x74, 0x9a, 0x44, 0x3c, 0x33,
+    0xf6, 0x74, 0x3d, 0x04, 0x2a, 0x59, 0x76, 0xa2, 0x05, 0x27, 0xc4, 0xe3,
+    0xa2, 0xc8, 0xc2, 0xaf, 0x7e, 0xfd, 0xbe, 0xb9, 0xca, 0xe9, 0x5b, 0xa8,
+    0x2a, 0xcd, 0xa7, 0x1e, 0x0e, 0x37, 0xf1, 0x6f, 0x84, 0x5e, 0xaa, 0x42,
+    0x1f, 0xba, 0xf0, 0x44, 0xba, 0xdb, 0x87, 0x61, 0x68, 0x91, 0xbb, 0x1d,
+    0x5c, 0x3a, 0xf0, 0x8e, 0x02, 0x20, 0x76, 0xaa, 0x47, 0x99, 0xc7, 0x73,
+    0x0d, 0x90, 0x32, 0x4a, 0xb9, 0xe3, 0xfd, 0x11, 0x8b, 0x5d, 0xbd, 0x22,
+    0x4d, 0x05, 0x75, 0x17, 0x61, 0xa2, 0xa6, 0x4f, 0xb0, 0x3d, 0x52, 0x8e,
+    0xaa, 0xc9, 0xb4, 0x8d, 0x05, 0x5a, 0x1c, 0x36, 0xc1, 0x7b, 0x87, 0xf7,
+    0xf8, 0xe4, 0x81, 0x36, 0x27, 0xec, 0x35, 0xae, 0xb9, 0xce, 0x15, 0x47,
+    0xe1, 0x10, 0xc9, 0x16, 0x69, 0x3a, 0x22, 0x8e, 0x63, 0x18, 0x31, 0xcc,
+    0x3b, 0x56, 0x69, 0xc6, 0xd4, 0x24, 0xdd, 0x95, 0x25, 0xcf, 0x34, 0xe6,
+    0x00, 0xae, 0xe1, 0x87, 0x1e, 0xee, 0x0c, 0x14, 0xdc, 0x0d, 0x82, 0x81,
+    0x31, 0x1f, 0x8f, 0x6d, 0xd2, 0xc0, 0xe1, 0x7c, 0x12, 0xf7, 0x9d, 0xca,
+    0x02, 0xe3, 0x76, 0x36, 0x44, 0x53, 0x3a, 0x87, 0x71, 0x7d, 0xed, 0x32,
+    0x4c, 0xa4, 0x96, 0xe6, 0xe5, 0x2c, 0xc7, 0x0d, 0xb7, 0x96, 0xc0, 0xf3,
+    0x7d, 0xe5, 0x58, 0x32, 0xf7, 0x25, 0x25, 0xc0, 0x13, 0x76, 0xd0, 0x76,
+    0x6c, 0x73, 0xab, 0x3d, 0x15, 0xcd, 0xc5, 0xe8, 0x85, 0x15, 0x9a, 0x02,
+    0x52, 0xe9, 0x61, 0x41, 0xe2, 0x66, 0x01, 0xc5, 0x71, 0xe5, 0xdb, 0xc0,
+    0xa5, 0xb3, 0x4c, 0x1e, 0xac, 0x93, 0x8a, 0x35, 0x4c, 0x4d, 0xda, 0x57,
+    0x22, 0x24, 0x1d, 0x3a, 0xf6, 0xbd,
 };
diff --git a/components/cast_certificate/cast_crl_unittest.cc b/components/cast_certificate/cast_crl_unittest.cc
index d65b3a63..5698dbe 100644
--- a/components/cast_certificate/cast_crl_unittest.cc
+++ b/components/cast_certificate/cast_crl_unittest.cc
@@ -7,11 +7,27 @@
 #include "components/cast_certificate/cast_cert_validator_test_helpers.h"
 #include "components/cast_certificate/cast_crl.h"
 #include "components/cast_certificate/proto/test_suite.pb.h"
+#include "net/cert/internal/trust_store.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace cast_certificate {
 namespace {
 
+// Creates a trust store using the test roots encoded in the PEM file at |path|.
+std::unique_ptr<net::TrustStore> CreateTrustStoreFromFile(
+    const std::string& path) {
+  std::unique_ptr<net::TrustStore> trust_store(new net::TrustStore());
+  const auto trusted_test_roots =
+      cast_certificate::testing::ReadCertificateChainFromFile(path);
+  for (const auto& trusted_root : trusted_test_roots) {
+    scoped_refptr<net::ParsedCertificate> anchor(
+        net::ParsedCertificate::CreateFromCertificateCopy(trusted_root, {}));
+    EXPECT_TRUE(anchor);
+    trust_store->AddTrustedCertificate(std::move(anchor));
+  }
+  return trust_store;
+}
+
 // Converts uint64_t unix timestamp in seconds to base::Time.
 base::Time ConvertUnixTimestampSeconds(uint64_t time) {
   return base::Time::UnixEpoch() +
@@ -28,11 +44,19 @@
 // and chains up to a trust anchor.
 bool TestVerifyCertificate(TestStepResult expected_result,
                            const std::vector<std::string>& certificate_chain,
-                           const base::Time& time) {
+                           const base::Time& time,
+                           net::TrustStore* cast_trust_store) {
   std::unique_ptr<CertVerificationContext> context;
   CastDeviceCertPolicy policy;
-  bool result = VerifyDeviceCert(certificate_chain, time, &context, &policy,
-                                 nullptr, CRLPolicy::CRL_OPTIONAL);
+  int result;
+  if (cast_trust_store != nullptr) {
+    result = VerifyDeviceCertForTest(certificate_chain, time, &context, &policy,
+                                     nullptr, CRLPolicy::CRL_OPTIONAL,
+                                     cast_trust_store);
+  } else {
+    result = VerifyDeviceCert(certificate_chain, time, &context, &policy,
+                              nullptr, CRLPolicy::CRL_OPTIONAL);
+  }
   if (expected_result != RESULT_SUCCESS) {
     EXPECT_FALSE(result);
     return !result;
@@ -46,8 +70,14 @@
 // The validity of the CRL is also checked at the specified time.
 bool TestVerifyCRL(TestStepResult expected_result,
                    const std::string& crl_bundle,
-                   const base::Time& time) {
-  std::unique_ptr<CastCRL> crl = ParseAndVerifyCRL(crl_bundle, time);
+                   const base::Time& time,
+                   net::TrustStore* crl_trust_store) {
+  std::unique_ptr<CastCRL> crl;
+  if (crl_trust_store != nullptr) {
+    crl = ParseAndVerifyCRLForTest(crl_bundle, time, crl_trust_store);
+  } else {
+    crl = ParseAndVerifyCRL(crl_bundle, time);
+  }
   if (expected_result != RESULT_SUCCESS) {
     EXPECT_EQ(crl, nullptr);
     return crl == nullptr;
@@ -66,10 +96,16 @@
                           const std::string& crl_bundle,
                           const base::Time& crl_time,
                           const base::Time& cert_time,
-                          bool crl_required) {
+                          bool crl_required,
+                          net::TrustStore* cast_trust_store,
+                          net::TrustStore* crl_trust_store) {
   std::unique_ptr<CastCRL> crl;
   if (!crl_bundle.empty()) {
-    crl = ParseAndVerifyCRL(crl_bundle, crl_time);
+    if (crl_trust_store != nullptr) {
+      crl = ParseAndVerifyCRLForTest(crl_bundle, crl_time, crl_trust_store);
+    } else {
+      crl = ParseAndVerifyCRL(crl_bundle, crl_time);
+    }
     EXPECT_NE(crl.get(), nullptr);
   }
 
@@ -78,8 +114,15 @@
   CRLPolicy crl_policy = CRLPolicy::CRL_REQUIRED;
   if (!crl_required)
     crl_policy = CRLPolicy::CRL_OPTIONAL;
-  int result = VerifyDeviceCert(certificate_chain, cert_time, &context, &policy,
-                                crl.get(), crl_policy);
+  int result;
+  if (cast_trust_store != nullptr) {
+    result =
+        VerifyDeviceCertForTest(certificate_chain, cert_time, &context, &policy,
+                                crl.get(), crl_policy, cast_trust_store);
+  } else {
+    result = VerifyDeviceCert(certificate_chain, cert_time, &context, &policy,
+                              crl.get(), crl_policy);
+  }
   if (expected_result != RESULT_SUCCESS) {
     EXPECT_FALSE(result);
     return !result;
@@ -90,21 +133,17 @@
 
 // Runs a single test case.
 bool RunTest(const DeviceCertTest& test_case) {
-  bool use_test_trust_anchors = test_case.use_test_trust_anchors();
-  if (use_test_trust_anchors) {
-    const auto crl_test_root =
-        cast_certificate::testing::ReadCertificateChainFromFile(
-            "certificates/cast_crl_test_root_ca.pem");
-    EXPECT_EQ(crl_test_root.size(), 1u);
-    EXPECT_TRUE(SetCRLTrustAnchorForTest(crl_test_root[0]));
-    const auto cast_test_root =
-        cast_certificate::testing::ReadCertificateChainFromFile(
-            "certificates/cast_test_root_ca.pem");
-    EXPECT_EQ(cast_test_root.size(), 1u);
-    EXPECT_TRUE(SetTrustAnchorForTest(cast_test_root[0]));
-  }
+  std::unique_ptr<net::TrustStore> crl_trust_store;
+  std::unique_ptr<net::TrustStore> cast_trust_store;
+  if (test_case.use_test_trust_anchors()) {
+    crl_trust_store =
+        CreateTrustStoreFromFile("certificates/cast_crl_test_root_ca.pem");
+    cast_trust_store =
+        CreateTrustStoreFromFile("certificates/cast_test_root_ca.pem");
 
-  VerificationResult expected_result = test_case.expected_result();
+    EXPECT_TRUE(crl_trust_store.get());
+    EXPECT_TRUE(cast_trust_store.get());
+  }
 
   std::vector<std::string> certificate_chain;
   for (auto const& cert : test_case.der_cert_path()) {
@@ -121,38 +160,49 @@
     crl_verification_time = cert_verification_time;
 
   std::string crl_bundle = test_case.crl_bundle();
-  switch (expected_result) {
+  switch (test_case.expected_result()) {
     case PATH_VERIFICATION_FAILED:
       return TestVerifyCertificate(RESULT_FAIL, certificate_chain,
-                                   cert_verification_time);
+                                   cert_verification_time,
+                                   cast_trust_store.get());
       break;
     case CRL_VERIFICATION_FAILED:
-      return TestVerifyCRL(RESULT_FAIL, crl_bundle, crl_verification_time);
+      return TestVerifyCRL(RESULT_FAIL, crl_bundle, crl_verification_time,
+                           crl_trust_store.get());
       break;
     case REVOCATION_CHECK_FAILED_WITHOUT_CRL:
       return TestVerifyCertificate(RESULT_SUCCESS, certificate_chain,
-                                   cert_verification_time) &&
-             TestVerifyCRL(RESULT_FAIL, crl_bundle, crl_verification_time) &&
+                                   cert_verification_time,
+                                   cast_trust_store.get()) &&
+             TestVerifyCRL(RESULT_FAIL, crl_bundle, crl_verification_time,
+                           crl_trust_store.get()) &&
              TestVerifyRevocation(RESULT_FAIL, certificate_chain, crl_bundle,
                                   crl_verification_time, cert_verification_time,
-                                  true);
+                                  true, cast_trust_store.get(),
+                                  crl_trust_store.get());
       break;
     case REVOCATION_CHECK_FAILED:
       return TestVerifyCertificate(RESULT_SUCCESS, certificate_chain,
-                                   cert_verification_time) &&
-             TestVerifyCRL(RESULT_SUCCESS, crl_bundle, crl_verification_time) &&
+                                   cert_verification_time,
+                                   cast_trust_store.get()) &&
+             TestVerifyCRL(RESULT_SUCCESS, crl_bundle, crl_verification_time,
+                           crl_trust_store.get()) &&
              TestVerifyRevocation(RESULT_FAIL, certificate_chain, crl_bundle,
                                   crl_verification_time, cert_verification_time,
-                                  false);
+                                  false, cast_trust_store.get(),
+                                  crl_trust_store.get());
       break;
     case SUCCESS:
-      return (crl_bundle.empty() || TestVerifyCRL(RESULT_SUCCESS, crl_bundle,
-                                                  crl_verification_time)) &&
+      return (crl_bundle.empty() ||
+              TestVerifyCRL(RESULT_SUCCESS, crl_bundle, crl_verification_time,
+                            crl_trust_store.get())) &&
              TestVerifyCertificate(RESULT_SUCCESS, certificate_chain,
-                                   cert_verification_time) &&
+                                   cert_verification_time,
+                                   cast_trust_store.get()) &&
              TestVerifyRevocation(RESULT_SUCCESS, certificate_chain, crl_bundle,
                                   crl_verification_time, cert_verification_time,
-                                  !crl_bundle.empty());
+                                  !crl_bundle.empty(), cast_trust_store.get(),
+                                  crl_trust_store.get());
       break;
     case UNSPECIFIED:
       return false;
diff --git a/components/components_strings.grd b/components/components_strings.grd
index bd5901b..8e1adc5 100644
--- a/components/components_strings.grd
+++ b/components/components_strings.grd
@@ -227,6 +227,9 @@
       <message name="IDS_OK" desc="Used for OK on buttons">
         OK
       </message>
+      <message name="IDS_NO_THANKS" desc="Used to dismiss various prompts.">
+        No thanks
+      </message>
       <if expr="not use_titlecase">
         <message name="IDS_NOT_NOW" desc="Used on a button that avoids taking a suggested action.  The action will likely be suggested again or automatically taken later.">
           Not now
diff --git a/components/components_tests.gyp b/components/components_tests.gyp
index 333b164..0ebb2f0 100644
--- a/components/components_tests.gyp
+++ b/components/components_tests.gyp
@@ -833,6 +833,90 @@
     'supervised_user_error_page_unittest_sources': [
       'supervised_user_error_page/supervised_user_error_page_unittest.cc',
     ],
+    'sync_unittest_sources': [
+      'sync/api/attachments/attachment_id_unittest.cc',
+      'sync/api/attachments/attachment_metadata_unittest.cc',
+      'sync/api/attachments/attachment_unittest.cc',
+      'sync/api/entity_data_unittest.cc',
+      'sync/api/model_type_service_unittest.cc',
+      'sync/api/sync_change_unittest.cc',
+      'sync/api/sync_data_unittest.cc',
+      'sync/api/sync_error_unittest.cc',
+      'sync/api/sync_merge_result_unittest.cc',
+      'sync/engine_impl/apply_control_data_updates_unittest.cc',
+      'sync/engine_impl/backoff_delay_provider_unittest.cc',
+      'sync/engine_impl/directory_commit_contribution_unittest.cc',
+      'sync/engine_impl/directory_update_handler_unittest.cc',
+      'sync/engine_impl/get_updates_processor_unittest.cc',
+      'sync/engine_impl/model_type_worker_unittest.cc',
+      'sync/engine_impl/sync_scheduler_unittest.cc',
+      'sync/engine_impl/syncer_proto_util_unittest.cc',
+      'sync/engine_impl/syncer_unittest.cc',
+      'sync/engine_impl/syncer_util_unittest.cc',
+      'sync/engine_impl/worker_entity_tracker_unittest.cc',
+      'sync/core_impl/attachments/attachment_downloader_impl_unittest.cc',
+      'sync/core_impl/attachments/attachment_service_impl_unittest.cc',
+      'sync/core_impl/attachments/attachment_service_proxy_unittest.cc',
+      'sync/core_impl/attachments/attachment_store_frontend_unittest.cc',
+      'sync/core_impl/attachments/attachment_store_test_template.h',
+      'sync/core_impl/attachments/attachment_uploader_impl_unittest.cc',
+      'sync/core_impl/attachments/fake_attachment_downloader_unittest.cc',
+      'sync/core_impl/attachments/fake_attachment_uploader_unittest.cc',
+      'sync/core_impl/attachments/in_memory_attachment_store_unittest.cc',
+      'sync/core_impl/attachments/on_disk_attachment_store_unittest.cc',
+      'sync/core_impl/attachments/task_queue_unittest.cc',
+      'sync/core_impl/debug_info_event_listener_unittest.cc',
+      'sync/core/http_bridge_unittest.cc',
+      'sync/core_impl/js_mutation_event_observer_unittest.cc',
+      'sync/core_impl/js_sync_encryption_handler_observer_unittest.cc',
+      'sync/core_impl/js_sync_manager_observer_unittest.cc',
+      'sync/core_impl/model_type_connector_proxy_unittest.cc',
+      'sync/core/model_type_store_backend_unittest.cc',
+      'sync/core/model_type_store_impl_unittest.cc',
+      'sync/core/processor_entity_tracker_unittest.cc',
+      'sync/core_impl/protocol_event_buffer_unittest.cc',
+      'sync/base/attachment_id_proto_unittest.cc',
+      'sync/base/cancelation_signal_unittest.cc',
+      'sync/base/enum_set_unittest.cc',
+      'sync/base/node_ordinal_unittest.cc',
+      'sync/base/ordinal_unittest.cc',
+      'sync/base/unique_position_unittest.cc',
+      'sync/core/change_record_unittest.cc',
+      'sync/core/data_batch_impl_unittest.cc',
+      'sync/engine/model_safe_worker_unittest.cc',
+      'sync/sessions/sync_session_snapshot_unittest.cc',
+      'sync/core/simple_metadata_change_list_unittest.cc',
+      'sync/base/immutable_unittest.cc',
+      'sync/base/proto_value_ptr_unittest.cc',
+      'sync/base/weak_handle_unittest.cc',
+      'sync/core/shared_model_type_processor_unittest.cc',
+      'sync/core_impl/sync_encryption_handler_impl_unittest.cc',
+      'sync/core_impl/sync_manager_impl_unittest.cc',
+      'sync/core_impl/syncapi_server_connection_manager_unittest.cc',
+      'sync/js/js_event_details_unittest.cc',
+      'sync/js/sync_js_controller_unittest.cc',
+      'sync/protocol/proto_enum_conversions_unittest.cc',
+      'sync/protocol/proto_value_conversions_unittest.cc',
+      'sync/sessions_impl/model_type_registry_unittest.cc',
+      'sync/sessions_impl/nudge_tracker_unittest.cc',
+      'sync/sessions_impl/status_controller_unittest.cc',
+      'sync/syncable/directory_backing_store_unittest.cc',
+      'sync/syncable/directory_unittest.cc',
+      'sync/syncable/directory_unittest.h',
+      'sync/syncable/entry_kernel_unittest.cc',
+      'sync/syncable/model_type_unittest.cc',
+      'sync/syncable/nigori_util_unittest.cc',
+      'sync/syncable/parent_child_index_unittest.cc',
+      'sync/syncable/syncable_enum_conversions_unittest.cc',
+      'sync/syncable/syncable_id_unittest.cc',
+      'sync/syncable/syncable_unittest.cc',
+      'sync/syncable/syncable_util_unittest.cc',
+      'sync/base/cryptographer_unittest.cc',
+      'sync/base/data_type_histogram_unittest.cc',
+      'sync/base/get_session_name_unittest.cc',
+      'sync/base/nigori_unittest.cc',
+      'sync/base/protobuf_unittest.cc',
+    ],
     'sync_bookmarks_unittest_sources': [
       'sync_bookmarks/bookmark_data_type_controller_unittest.cc',
     ],
@@ -1103,6 +1187,7 @@
         '<@(subresource_filter_core_common_unittest_sources)',
         '<@(suggestions_unittest_sources)',
         '<@(supervised_user_error_page_unittest_sources)',
+        '<@(sync_unittest_sources)',
         '<@(sync_bookmarks_unittest_sources)',
         '<@(sync_driver_unittest_sources)',
         '<@(sync_sessions_unittest_sources)',
@@ -1129,8 +1214,6 @@
         '../jingle/jingle.gyp:notifier_test_util',
         '../net/net.gyp:net_test_support',
         '../sql/sql.gyp:test_support_sql',
-        '../components/sync.gyp:sync',
-        '../components/sync.gyp:test_support_sync_api',
         '../testing/gmock.gyp:gmock',
         '../testing/gtest.gyp:gtest',
         '../third_party/icu/icu.gyp:icui18n',
@@ -1277,6 +1360,10 @@
         'mime_util/mime_util.gyp:mime_util',
         'prefs/prefs.gyp:prefs',
         'prefs/prefs.gyp:prefs_test_support',
+        'sync.gyp:sync',
+        'sync.gyp:test_support_sync_api',
+        'sync.gyp:test_support_sync_core',
+        'sync.gyp:test_support_sync_core_impl',
         'url_formatter/url_formatter.gyp:url_formatter',
       ],
       'conditions': [
@@ -1444,6 +1531,9 @@
             # component directory structure).
             ['exclude', '^[^/]*/content/'],
           ],
+          'sources!': [
+            'core/http_bridge_unittest.cc',
+          ],
           'mac_bundle_resources': [
             '<(PRODUCT_DIR)/ui_test.pak',
           ],
@@ -1500,6 +1590,7 @@
         }],
         ['OS == "android"', {
           'sources': [
+            'autofill/core/browser/autofill_assistant_unittest.cc',
             'data_usage/android/traffic_stats_amortizer_unittest.cc',
             'invalidation/impl/invalidation_logger_unittest.cc',
             'invalidation/impl/invalidation_service_android_unittest.cc',
diff --git a/components/cronet/android/BUILD.gn b/components/cronet/android/BUILD.gn
index 0496f19..3f3ed4b 100644
--- a/components/cronet/android/BUILD.gn
+++ b/components/cronet/android/BUILD.gn
@@ -30,12 +30,6 @@
   jni_package = "cronet"
 }
 
-java_cpp_enum("chromium_effective_connection_type_java") {
-  sources = [
-    "//net/nqe/effective_connection_type.h",
-  ]
-}
-
 java_cpp_enum("chromium_url_request_java") {
   sources = [
     "chromium_url_request.h",
@@ -280,7 +274,6 @@
     "api/src/org/chromium/net/ChunkedWritableByteChannel.java",
     "api/src/org/chromium/net/CronetEngine.java",
     "api/src/org/chromium/net/CronetException.java",
-    "api/src/org/chromium/net/EffectiveConnectionType.java",
     "api/src/org/chromium/net/HttpUrlConnectionUrlRequest.java",
     "api/src/org/chromium/net/HttpUrlConnectionUrlRequestFactory.java",
     "api/src/org/chromium/net/HttpUrlRequest.java",
@@ -311,7 +304,6 @@
   ]
 
   srcjar_deps = [
-    ":chromium_effective_connection_type_java",
     ":cronet_api_version_srcjar",
     ":http_cache_type_java",
     ":url_request_error_java",
diff --git a/components/cronet/android/api/src/org/chromium/net/CronetEngine.java b/components/cronet/android/api/src/org/chromium/net/CronetEngine.java
index 7a01c44..b7013e2f 100644
--- a/components/cronet/android/api/src/org/chromium/net/CronetEngine.java
+++ b/components/cronet/android/api/src/org/chromium/net/CronetEngine.java
@@ -958,13 +958,6 @@
     public abstract byte[] getGlobalMetricsDeltas();
 
     /**
-     * Returns the effective connection type computed by the network quality
-     * estimator.
-     * @hide as it's a prototype.
-     */
-    public abstract int getEffectiveConnectionType();
-
-    /**
      * Configures the network quality estimator for testing. This must be called
      * before round trip time and throughput listeners are added, and after the
      * network quality estimator has been enabled.
diff --git a/components/cronet/android/api/src/org/chromium/net/EffectiveConnectionType.java b/components/cronet/android/api/src/org/chromium/net/EffectiveConnectionType.java
deleted file mode 100644
index 32fa154ae..0000000
--- a/components/cronet/android/api/src/org/chromium/net/EffectiveConnectionType.java
+++ /dev/null
@@ -1,110 +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.
-
-package org.chromium.net;
-
-import android.support.annotation.IntDef;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-
-/**
- * Different values of the effective connection type as computed by the network
- * quality estimator. EffectiveConnectionType is the connection type whose
- * typical performance is most similar to the measured performance of the
- * network in use. In many cases, the "effective" connection type and the actual
- * type of connection in use are the same, but often a network connection
- * performs significantly differently, usually worse, from its expected
- * capabilities. EffectiveConnectionType of a network is independent of if the
- * current connection is metered or not. For example, an unmetered slow
- * connection may have EFFECTIVE_CONNECTION_TYPE_SLOW_2G as its effective
- * connection type.
- * {@hide} as it's a prototype.
- */
-public class EffectiveConnectionType {
-    /** {@hide} */
-    @IntDef({
-            EFFECTIVE_CONNECTION_TYPE_UNKNOWN, EFFECTIVE_CONNECTION_TYPE_OFFLINE,
-            EFFECTIVE_CONNECTION_TYPE_SLOW_2G, EFFECTIVE_CONNECTION_TYPE_2G,
-            EFFECTIVE_CONNECTION_TYPE_3G, EFFECTIVE_CONNECTION_TYPE_4G,
-            EFFECTIVE_CONNECTION_TYPE_BROADBAND,
-    })
-    @Retention(RetentionPolicy.SOURCE)
-    public @interface EffectiveConnectionTypeValues {}
-
-    /**
-     * Effective connection type reported when the network quality is unknown.
-     */
-    public static final int EFFECTIVE_CONNECTION_TYPE_UNKNOWN = 0;
-
-    /**
-     * Effective connection type reported when the Internet is unreachable,
-     * either because the device does not have a connection or because the
-     * connection is too slow to be usable.
-     */
-    public static final int EFFECTIVE_CONNECTION_TYPE_OFFLINE = 1;
-
-    /**
-     * Effective connection type reported when the network has the quality of a
-     * poor 2G connection.
-     */
-    public static final int EFFECTIVE_CONNECTION_TYPE_SLOW_2G = 2;
-
-    /**
-     * Effective connection type reported when the network has the quality of a
-     * faster 2G connection.
-     */
-    public static final int EFFECTIVE_CONNECTION_TYPE_2G = 3;
-
-    /**
-     * Effective connection type reported when the network has the quality of a
-     * 3G connection.
-     */
-    public static final int EFFECTIVE_CONNECTION_TYPE_3G = 4;
-
-    /**
-     * Effective connection type reported when the network has the quality of a
-     * 4G connection.
-     */
-    public static final int EFFECTIVE_CONNECTION_TYPE_4G = 5;
-
-    /**
-     * Effective connection type reported when the network has the quality of a
-     * broadband connection.
-     */
-    public static final int EFFECTIVE_CONNECTION_TYPE_BROADBAND = 6;
-
-    private EffectiveConnectionType() {}
-
-    /**
-     * Maps the effective connection type enum computed by the network quality
-     * estimator to {@link EffectiveConnectionType}.
-     * @param effectiveConnectionType Effective connection type enum computed by
-     *            the network quality estimator.
-     * @return {@link EffectiveConnectionType} corresponding to the provided enum.
-     * @hide only used by internal implementation.
-     */
-    @EffectiveConnectionTypeValues
-    public static int getEffectiveConnectionType(int effectiveConnectionType) {
-        assert ChromiumEffectiveConnectionType.EFFECTIVE_CONNECTION_TYPE_LAST == 7;
-        switch (effectiveConnectionType) {
-            case ChromiumEffectiveConnectionType.EFFECTIVE_CONNECTION_TYPE_UNKNOWN:
-                return EFFECTIVE_CONNECTION_TYPE_UNKNOWN;
-            case ChromiumEffectiveConnectionType.EFFECTIVE_CONNECTION_TYPE_OFFLINE:
-                return EFFECTIVE_CONNECTION_TYPE_OFFLINE;
-            case ChromiumEffectiveConnectionType.EFFECTIVE_CONNECTION_TYPE_SLOW_2G:
-                return EFFECTIVE_CONNECTION_TYPE_SLOW_2G;
-            case ChromiumEffectiveConnectionType.EFFECTIVE_CONNECTION_TYPE_2G:
-                return EFFECTIVE_CONNECTION_TYPE_2G;
-            case ChromiumEffectiveConnectionType.EFFECTIVE_CONNECTION_TYPE_3G:
-                return EFFECTIVE_CONNECTION_TYPE_3G;
-            case ChromiumEffectiveConnectionType.EFFECTIVE_CONNECTION_TYPE_4G:
-                return EFFECTIVE_CONNECTION_TYPE_4G;
-            case ChromiumEffectiveConnectionType.EFFECTIVE_CONNECTION_TYPE_BROADBAND:
-                return EFFECTIVE_CONNECTION_TYPE_BROADBAND;
-        }
-        throw new IllegalStateException(
-                "Effective connection type has an invalid value of " + effectiveConnectionType);
-    }
-}
\ No newline at end of file
diff --git a/components/cronet/android/api/src/org/chromium/net/JavaCronetEngine.java b/components/cronet/android/api/src/org/chromium/net/JavaCronetEngine.java
index 18de61a..d899a6ac4 100644
--- a/components/cronet/android/api/src/org/chromium/net/JavaCronetEngine.java
+++ b/components/cronet/android/api/src/org/chromium/net/JavaCronetEngine.java
@@ -104,11 +104,6 @@
     }
 
     @Override
-    public int getEffectiveConnectionType() {
-        return EffectiveConnectionType.EFFECTIVE_CONNECTION_TYPE_UNKNOWN;
-    }
-
-    @Override
     public void configureNetworkQualityEstimatorForTesting(
             boolean useLocalHostRequests, boolean useSmallerResponses) {}
 
diff --git a/components/cronet/android/chromium_url_request.cc b/components/cronet/android/chromium_url_request.cc
index 6f047e6..e52d6f4f 100644
--- a/components/cronet/android/chromium_url_request.cc
+++ b/components/cronet/android/chromium_url_request.cc
@@ -165,10 +165,10 @@
   DCHECK(request_adapter);
   SetPostContentType(env, request_adapter, jcontent_type);
 
-  if (jcontent != NULL) {
+  if (jcontent != nullptr) {
     jsize size = env->GetArrayLength(jcontent);
     if (size > 0) {
-      jbyte* content_bytes = env->GetByteArrayElements(jcontent, NULL);
+      jbyte* content_bytes = env->GetByteArrayElements(jcontent, nullptr);
       request_adapter->SetUploadContent(
           reinterpret_cast<const char*>(content_bytes), size);
       env->ReleaseByteArrayElements(jcontent, content_bytes, 0);
@@ -223,7 +223,7 @@
                   jlong jurl_request_adapter) {
   URLRequestAdapter* request_adapter =
       reinterpret_cast<URLRequestAdapter*>(jurl_request_adapter);
-  if (request_adapter != NULL)
+  if (request_adapter != nullptr)
     request_adapter->Start();
 }
 
@@ -233,7 +233,7 @@
                                   jlong jurl_request_adapter) {
   URLRequestAdapter* request_adapter =
       reinterpret_cast<URLRequestAdapter*>(jurl_request_adapter);
-  if (request_adapter != NULL)
+  if (request_adapter != nullptr)
     request_adapter->Destroy();
 }
 
@@ -243,7 +243,7 @@
                    jlong jurl_request_adapter) {
   URLRequestAdapter* request_adapter =
       reinterpret_cast<URLRequestAdapter*>(jurl_request_adapter);
-  if (request_adapter != NULL)
+  if (request_adapter != nullptr)
     request_adapter->Cancel();
 }
 
@@ -373,7 +373,7 @@
   DCHECK(request_adapter);
 
   net::HttpResponseHeaders* headers = request_adapter->GetResponseHeaders();
-  if (headers == NULL)
+  if (headers == nullptr)
     return;
 
   size_t iter = 0;
@@ -393,7 +393,7 @@
   ScopedJavaLocalRef<jstring> status_line =
       ConvertUTF8ToJavaString(env, headers->GetStatusLine());
   Java_ChromiumUrlRequest_onAppendResponseHeader(env, jcaller, jheaders_map,
-                                                 NULL, status_line.obj());
+                                                 nullptr, status_line.obj());
 }
 
 static ScopedJavaLocalRef<jstring> GetNegotiatedProtocol(
diff --git a/components/cronet/android/cronet_library_loader.cc b/components/cronet/android/cronet_library_loader.cc
index 6fd2e91..55929ef7 100644
--- a/components/cronet/android/cronet_library_loader.cc
+++ b/components/cronet/android/cronet_library_loader.cc
@@ -32,9 +32,7 @@
 #include "url/url_features.h"
 #include "url/url_util.h"
 
-#if BUILDFLAG(USE_PLATFORM_ICU_ALTERNATIVES)
-#include "url/android/url_jni_registrar.h"  // nogncheck
-#else
+#if !BUILDFLAG(USE_PLATFORM_ICU_ALTERNATIVES)
 #include "base/i18n/icu_util.h"  // nogncheck
 #endif
 
@@ -53,9 +51,6 @@
     {"CronetUrlRequestContextAdapter",
      CronetUrlRequestContextAdapterRegisterJni},
     {"NetAndroid", net::android::RegisterJni},
-#if BUILDFLAG(USE_PLATFORM_ICU_ALTERNATIVES)
-    {"UrlAndroid", url::android::RegisterJni},
-#endif
 };
 
 // MessageLoop on the main thread, which is where objects that receive Java
diff --git a/components/cronet/android/cronet_url_request_context_adapter.cc b/components/cronet/android/cronet_url_request_context_adapter.cc
index 73f618a..f9908ae 100644
--- a/components/cronet/android/cronet_url_request_context_adapter.cc
+++ b/components/cronet/android/cronet_url_request_context_adapter.cc
@@ -51,6 +51,7 @@
 #include "net/http/http_server_properties_manager.h"
 #include "net/log/write_to_file_net_log_observer.h"
 #include "net/nqe/external_estimate_provider.h"
+#include "net/nqe/network_quality_estimator.h"
 #include "net/proxy/proxy_config_service_android.h"
 #include "net/proxy/proxy_service.h"
 #include "net/sdch/sdch_owner.h"
@@ -415,7 +416,6 @@
   if (network_quality_estimator_) {
     network_quality_estimator_->RemoveRTTObserver(this);
     network_quality_estimator_->RemoveThroughputObserver(this);
-    network_quality_estimator_->RemoveEffectiveConnectionTypeObserver(this);
   }
   // Stop |write_to_file_observer_| if there is one.
   StopNetLogHelper();
@@ -597,23 +597,13 @@
 
   if (config->enable_network_quality_estimator) {
     DCHECK(!network_quality_estimator_);
-    std::map<std::string, std::string> variation_params;
-    // Configure network quality estimator: Specify the algorithm that should
-    // be used for computing the effective connection type. The algorithm
-    // is specified using the key-value pairs defined in
-    // //net/nqe/network_quality_estimator.cc.
-    // TODO(tbansal): Investigate a more robust way of configuring the network
-    // quality estimator.
-    variation_params["effective_connection_type_algorithm"] =
-        "TransportRTTOrDownstreamThroughput";
     network_quality_estimator_.reset(new net::NetworkQualityEstimator(
-        std::unique_ptr<net::ExternalEstimateProvider>(), variation_params,
-        false, false));
+        std::unique_ptr<net::ExternalEstimateProvider>(),
+        std::map<std::string, std::string>(), false, false));
     // Set the socket performance watcher factory so that network quality
     // estimator is notified of socket performance metrics from TCP and QUIC.
     context_builder.set_socket_performance_watcher_factory(
         network_quality_estimator_->GetSocketPerformanceWatcherFactory());
-    network_quality_estimator_->AddEffectiveConnectionTypeObserver(this);
   }
 
   context_ = context_builder.Build();
@@ -832,14 +822,6 @@
   return file_thread_.get();
 }
 
-void CronetURLRequestContextAdapter::OnEffectiveConnectionTypeChanged(
-    net::EffectiveConnectionType effective_connection_type) {
-  DCHECK(GetNetworkTaskRunner()->BelongsToCurrentThread());
-  Java_CronetUrlRequestContext_onEffectiveConnectionTypeChanged(
-      base::android::AttachCurrentThread(), jcronet_url_request_context_.obj(),
-      effective_connection_type);
-}
-
 void CronetURLRequestContextAdapter::OnRTTObservation(
     int32_t rtt_ms,
     const base::TimeTicks& timestamp,
diff --git a/components/cronet/android/cronet_url_request_context_adapter.h b/components/cronet/android/cronet_url_request_context_adapter.h
index 329b413..42626a3f 100644
--- a/components/cronet/android/cronet_url_request_context_adapter.h
+++ b/components/cronet/android/cronet_url_request_context_adapter.h
@@ -18,7 +18,6 @@
 #include "base/memory/ref_counted.h"
 #include "base/threading/thread.h"
 #include "components/prefs/json_pref_store.h"
-#include "net/nqe/effective_connection_type.h"
 #include "net/nqe/network_quality_estimator.h"
 #include "net/nqe/network_quality_observation_source.h"
 
@@ -50,8 +49,7 @@
 
 // Adapter between Java CronetUrlRequestContext and net::URLRequestContext.
 class CronetURLRequestContextAdapter
-    : public net::NetworkQualityEstimator::EffectiveConnectionTypeObserver,
-      public net::NetworkQualityEstimator::RTTObserver,
+    : public net::NetworkQualityEstimator::RTTObserver,
       public net::NetworkQualityEstimator::ThroughputObserver {
  public:
   explicit CronetURLRequestContextAdapter(
@@ -151,11 +149,6 @@
   void ProvideRTTObservationsOnNetworkThread(bool should);
   void ProvideThroughputObservationsOnNetworkThread(bool should);
 
-  // net::NetworkQualityEstimator::EffectiveConnectionTypeObserver
-  // implementation.
-  void OnEffectiveConnectionTypeChanged(
-      net::EffectiveConnectionType effective_connection_type) override;
-
   // net::NetworkQualityEstimator::RTTObserver implementation.
   void OnRTTObservation(int32_t rtt_ms,
                         const base::TimeTicks& timestamp,
diff --git a/components/cronet/android/java/src/org/chromium/net/impl/CronetUrlRequestContext.java b/components/cronet/android/java/src/org/chromium/net/impl/CronetUrlRequestContext.java
index 57daa09..47d4345 100644
--- a/components/cronet/android/java/src/org/chromium/net/impl/CronetUrlRequestContext.java
+++ b/components/cronet/android/java/src/org/chromium/net/impl/CronetUrlRequestContext.java
@@ -20,7 +20,6 @@
 import org.chromium.base.annotations.UsedByReflection;
 import org.chromium.net.BidirectionalStream;
 import org.chromium.net.CronetEngine;
-import org.chromium.net.EffectiveConnectionType;
 import org.chromium.net.NetworkQualityRttListener;
 import org.chromium.net.NetworkQualityThroughputListener;
 import org.chromium.net.RequestFinishedInfo;
@@ -78,14 +77,6 @@
      */
     private final Object mFinishedListenerLock = new Object();
 
-    /**
-     * Current effective connection type as computed by the network quality
-     * estimator.
-     */
-    @GuardedBy("mNetworkQualityLock")
-    private int mEffectiveConnectionType =
-            EffectiveConnectionType.EFFECTIVE_CONNECTION_TYPE_UNKNOWN;
-
     @GuardedBy("mNetworkQualityLock")
     private final ObserverList<NetworkQualityRttListener> mRttListenerList =
             new ObserverList<NetworkQualityRttListener>();
@@ -269,17 +260,6 @@
         return nativeGetHistogramDeltas();
     }
 
-    @Override
-    public int getEffectiveConnectionType() {
-        if (!mNetworkQualityEstimatorEnabled) {
-            throw new IllegalStateException("Network quality estimator must be enabled");
-        }
-        synchronized (mNetworkQualityLock) {
-            checkHaveAdapter();
-            return mEffectiveConnectionType;
-        }
-    }
-
     @VisibleForTesting
     @Override
     public void configureNetworkQualityEstimatorForTesting(
@@ -457,17 +437,6 @@
 
     @SuppressWarnings("unused")
     @CalledByNative
-    private void onEffectiveConnectionTypeChanged(int effectiveConnectionType) {
-        synchronized (mNetworkQualityLock) {
-            // Convert the enum returned by the network quality estimator to an enum of type
-            // EffectiveConnectionType.
-            mEffectiveConnectionType =
-                    EffectiveConnectionType.getEffectiveConnectionType(effectiveConnectionType);
-        }
-    }
-
-    @SuppressWarnings("unused")
-    @CalledByNative
     private void onRttObservation(final int rttMs, final long whenMs, final int source) {
         synchronized (mNetworkQualityLock) {
             for (final NetworkQualityRttListener listener : mRttListenerList) {
diff --git a/components/cronet/android/java/src/org/chromium/net/urlconnection/CronetHttpURLConnection.java b/components/cronet/android/java/src/org/chromium/net/urlconnection/CronetHttpURLConnection.java
index 227ae12..b08e40a 100644
--- a/components/cronet/android/java/src/org/chromium/net/urlconnection/CronetHttpURLConnection.java
+++ b/components/cronet/android/java/src/org/chromium/net/urlconnection/CronetHttpURLConnection.java
@@ -402,7 +402,7 @@
         // Sockets are assigned to requests according to request priorities
         // when sockets are connected. This requires requests with the same host,
         // domain and port to have same timeout.
-        Log.e(TAG, "setConnectTimeout is not supported by CronetHttpURLConnection");
+        Log.d(TAG, "setConnectTimeout is not supported by CronetHttpURLConnection");
     }
 
     /**
diff --git a/components/cronet/android/test/javatests/src/org/chromium/net/CronetUrlRequestContextTest.java b/components/cronet/android/test/javatests/src/org/chromium/net/CronetUrlRequestContextTest.java
index 92204d2..b9eeef9 100644
--- a/components/cronet/android/test/javatests/src/org/chromium/net/CronetUrlRequestContextTest.java
+++ b/components/cronet/android/test/javatests/src/org/chromium/net/CronetUrlRequestContextTest.java
@@ -326,11 +326,6 @@
         assertEquals(mNetworkQualityThread, rttListener.getThread());
         assertEquals(mNetworkQualityThread, throughputListener.getThread());
 
-        // Verify that effective connection type callback is received and
-        // effective connection type is correctly set.
-        assertTrue(mTestFramework.mCronetEngine.getEffectiveConnectionType()
-                != EffectiveConnectionType.EFFECTIVE_CONNECTION_TYPE_UNKNOWN);
-
         mTestFramework.mCronetEngine.shutdown();
     }
 
diff --git a/components/cronet/android/test/javatests/src/org/chromium/net/QuicTest.java b/components/cronet/android/test/javatests/src/org/chromium/net/QuicTest.java
index 09811e8c..59e134e2 100644
--- a/components/cronet/android/test/javatests/src/org/chromium/net/QuicTest.java
+++ b/components/cronet/android/test/javatests/src/org/chromium/net/QuicTest.java
@@ -223,11 +223,6 @@
         // NETWORK_QUALITY_OBSERVATION_SOURCE_QUIC
         assertTrue(rttListener.rttObservationCount(2) > 0);
 
-        // Verify that effective connection type callback is received and
-        // effective connection type is correctly set.
-        assertTrue(mTestFramework.mCronetEngine.getEffectiveConnectionType()
-                != EffectiveConnectionType.EFFECTIVE_CONNECTION_TYPE_UNKNOWN);
-
         mTestFramework.mCronetEngine.shutdown();
     }
 }
diff --git a/components/dom_distiller/core/experiments.cc b/components/dom_distiller/core/experiments.cc
index 168f23e..f3927b8 100644
--- a/components/dom_distiller/core/experiments.cc
+++ b/components/dom_distiller/core/experiments.cc
@@ -6,6 +6,7 @@
 
 #include "base/command_line.h"
 #include "base/metrics/field_trial.h"
+#include "base/strings/string_util.h"
 #include "components/dom_distiller/core/dom_distiller_switches.h"
 
 namespace dom_distiller {
@@ -31,10 +32,12 @@
     }
     NOTREACHED() << "Invalid value for " << switches::kReaderModeHeuristics;
   } else {
-    if (group_name == "AdaBoost") {
+    if (base::StartsWith(group_name, "AdaBoost",
+                         base::CompareCase::INSENSITIVE_ASCII)) {
       return DistillerHeuristicsType::ADABOOST_MODEL;
     }
-    if (group_name == "OGArticle") {
+    if (base::StartsWith(group_name, "OGArticle",
+                         base::CompareCase::INSENSITIVE_ASCII)) {
       return DistillerHeuristicsType::OG_ARTICLE;
     }
   }
diff --git a/components/infobars/core/infobar_delegate.h b/components/infobars/core/infobar_delegate.h
index 07d7ce7..7ab41b6 100644
--- a/components/infobars/core/infobar_delegate.h
+++ b/components/infobars/core/infobar_delegate.h
@@ -132,6 +132,7 @@
     // Removed: DESKTOP_SEARCH_REDIRECTION_INFOBAR_DELEGATE = 62,
     UPDATE_PASSWORD_INFOBAR_DELEGATE = 63,
     DATA_REDUCTION_PROMO_INFOBAR_DELEGATE_ANDROID = 64,
+    AUTOFILL_CREDIT_CARD_FILLING_INFOBAR_DELEGATE_ANDROID = 65,
   };
 
   // Describes navigation events, used to decide whether infobars should be
diff --git a/components/offline_pages/background/offliner.h b/components/offline_pages/background/offliner.h
index 8bc6468..daa6d18 100644
--- a/components/offline_pages/background/offliner.h
+++ b/components/offline_pages/background/offliner.h
@@ -5,6 +5,8 @@
 #ifndef COMPONENTS_OFFLINE_PAGES_BACKGROUND_OFFLINER_H_
 #define COMPONENTS_OFFLINE_PAGES_BACKGROUND_OFFLINER_H_
 
+#include <string>
+
 #include "base/callback.h"
 
 namespace offline_pages {
diff --git a/components/offline_pages/background/request_coordinator.cc b/components/offline_pages/background/request_coordinator.cc
index b32cfa2f..19906d78 100644
--- a/components/offline_pages/background/request_coordinator.cc
+++ b/components/offline_pages/background/request_coordinator.cc
@@ -16,6 +16,7 @@
 #include "components/offline_pages/background/request_picker.h"
 #include "components/offline_pages/background/save_page_request.h"
 #include "components/offline_pages/offline_page_item.h"
+#include "components/offline_pages/offline_page_model.h"
 
 namespace offline_pages {
 
@@ -56,6 +57,11 @@
     const GURL& url, const ClientId& client_id, bool was_user_requested) {
   DVLOG(2) << "URL is " << url << " " << __func__;
 
+  if (!OfflinePageModel::CanSaveURL(url)) {
+    DVLOG(1) << "Not able to save page for requested url: " << url;
+    return false;
+  }
+
   // TODO(petewil): We need a robust scheme for allocating new IDs.
   static int64_t id = 0;
 
@@ -99,7 +105,7 @@
 void RequestCoordinator::RemoveRequests(
     const std::vector<ClientId>& client_ids) {
   queue_->RemoveRequestsByClientId(
-      client_ids, base::Bind(&RequestCoordinator::UpdateRequestCallback,
+      client_ids, base::Bind(&RequestCoordinator::UpdateMultipleRequestCallback,
                              weak_ptr_factory_.GetWeakPtr()));
 }
 
@@ -113,20 +119,34 @@
 
 // Called in response to updating a request in the request queue.
 void RequestCoordinator::UpdateRequestCallback(
+    const ClientId& client_id,
     RequestQueue::UpdateRequestResult result) {
   // If the request succeeded, nothing to do.  If it failed, we can't really do
   // much, so just log it.
   if (result != RequestQueue::UpdateRequestResult::SUCCESS) {
-    // TODO(petewil): Consider adding UMA or showing on offline-internals page.
-    DLOG(WARNING) << "Failed to update a request retry count. "
-                  << static_cast<int>(result);
+    DVLOG(1) << "Failed to update request attempt details. "
+             << static_cast<int>(result);
+    event_logger_.RecordUpdateRequestFailed(client_id.name_space, result);
+  }
+}
+
+// Called in response to updating multiple requests in the request queue.
+void RequestCoordinator::UpdateMultipleRequestCallback(
+    RequestQueue::UpdateRequestResult result) {
+  // If the request succeeded, nothing to do.  If it failed, we can't really do
+  // much, so just log it.
+  if (result != RequestQueue::UpdateRequestResult::SUCCESS) {
+    DVLOG(1) << "Failed to update request attempt details. "
+             << static_cast<int>(result);
   }
 }
 
 void RequestCoordinator::StopProcessing() {
   is_canceled_ = true;
-  if (offliner_ && is_busy_)
+  if (offliner_ && is_busy_) {
+    // TODO(dougarnett): Find current request and mark attempt aborted.
     offliner_->Cancel();
+  }
 
   // Stopping offliner means it will not call callback.
   last_offlining_status_ =
@@ -210,14 +230,28 @@
   DCHECK(!is_busy_);
   is_busy_ = true;
 
-  // Start the load and save process in the offliner (Async).
-  offliner_->LoadAndSave(request,
-                         base::Bind(&RequestCoordinator::OfflinerDoneCallback,
-                                    weak_ptr_factory_.GetWeakPtr()));
+  // Prepare an updated request to attempt.
+  SavePageRequest updated_request(request);
+  updated_request.MarkAttemptStarted(base::Time::Now());
 
-  // Start a watchdog timer to catch pre-renders running too long
-  watchdog_timer_.Start(FROM_HERE, offliner_timeout_, this,
-                        &RequestCoordinator::StopProcessing);
+  // Start the load and save process in the offliner (Async).
+  if (offliner_->LoadAndSave(
+          updated_request, base::Bind(&RequestCoordinator::OfflinerDoneCallback,
+                                      weak_ptr_factory_.GetWeakPtr()))) {
+    // Offliner accepted request so update it in the queue.
+    queue_->UpdateRequest(updated_request,
+                          base::Bind(&RequestCoordinator::UpdateRequestCallback,
+                                     weak_ptr_factory_.GetWeakPtr(),
+                                     updated_request.client_id()));
+
+    // Start a watchdog timer to catch pre-renders running too long
+    watchdog_timer_.Start(FROM_HERE, offliner_timeout_, this,
+                          &RequestCoordinator::StopProcessing);
+  } else {
+    is_busy_ = false;
+    DVLOG(0) << "Unable to start LoadAndSave";
+    StopProcessing();
+  }
 }
 
 void RequestCoordinator::OfflinerDoneCallback(const SavePageRequest& request,
@@ -227,38 +261,42 @@
            << ", status: " << static_cast<int>(status) << ", " << __func__;
   DCHECK_NE(status, Offliner::RequestStatus::UNKNOWN);
   DCHECK_NE(status, Offliner::RequestStatus::LOADED);
-  event_logger_.RecordSavePageRequestUpdated(
-      request.client_id().name_space,
-      "Saved",
-      request.request_id());
+  event_logger_.RecordSavePageRequestUpdated(request.client_id().name_space,
+                                             status, request.request_id());
   last_offlining_status_ = status;
   RecordOfflinerResultUMA(last_offlining_status_);
   watchdog_timer_.Stop();
 
   is_busy_ = false;
 
-  int64_t new_attempt_count = request.attempt_count() + 1;
-
-  // Remove the request from the queue if it either succeeded or exceeded the
-  // max number of retries.
-  if (status == Offliner::RequestStatus::SAVED
-       || new_attempt_count > policy_->GetMaxTries()) {
-    queue_->RemoveRequest(request.request_id(),
+  if (status == Offliner::RequestStatus::FOREGROUND_CANCELED) {
+    // Update the request for the canceled attempt.
+    // TODO(dougarnett): See if we can conclusively identify other attempt
+    // aborted cases to treat this way (eg, for Render Process Killed).
+    SavePageRequest updated_request(request);
+    updated_request.MarkAttemptAborted();
+    queue_->UpdateRequest(updated_request,
                           base::Bind(&RequestCoordinator::UpdateRequestCallback,
-                                     weak_ptr_factory_.GetWeakPtr()));
+                                     weak_ptr_factory_.GetWeakPtr(),
+                                     updated_request.client_id()));
+
+  } else if (status == Offliner::RequestStatus::SAVED ||
+             request.attempt_count() >= policy_->GetMaxTries()) {
+    // Remove the request from the queue if it either succeeded or exceeded the
+    // max number of retries.
+    queue_->RemoveRequest(
+        request.request_id(),
+        base::Bind(&RequestCoordinator::UpdateRequestCallback,
+                   weak_ptr_factory_.GetWeakPtr(), request.client_id()));
   } else {
     // If we failed, but are not over the limit, update the request in the
     // queue.
     SavePageRequest updated_request(request);
-    updated_request.set_attempt_count(new_attempt_count);
-    updated_request.set_last_attempt_time(base::Time::Now());
-    RequestQueue::UpdateRequestCallback update_callback =
-        base::Bind(&RequestCoordinator::UpdateRequestCallback,
-                   weak_ptr_factory_.GetWeakPtr());
-    queue_->UpdateRequest(
-        updated_request,
-        base::Bind(&RequestCoordinator::UpdateRequestCallback,
-                   weak_ptr_factory_.GetWeakPtr()));
+    updated_request.MarkAttemptCompleted();
+    queue_->UpdateRequest(updated_request,
+                          base::Bind(&RequestCoordinator::UpdateRequestCallback,
+                                     weak_ptr_factory_.GetWeakPtr(),
+                                     updated_request.client_id()));
   }
 
   // Determine whether we might try another request in this
diff --git a/components/offline_pages/background/request_coordinator.h b/components/offline_pages/background/request_coordinator.h
index 1be33930..1e51f18 100644
--- a/components/offline_pages/background/request_coordinator.h
+++ b/components/offline_pages/background/request_coordinator.h
@@ -123,7 +123,10 @@
                                 const SavePageRequest& request);
 
   // Receives the result of update and delete requests to the request queue.
-  void UpdateRequestCallback(RequestQueue::UpdateRequestResult result);
+  void UpdateRequestCallback(const ClientId& client_id,
+                             RequestQueue::UpdateRequestResult result);
+
+  void UpdateMultipleRequestCallback(RequestQueue::UpdateRequestResult result);
 
   // Callback from the request picker when it has chosen our next request.
   void RequestPicked(const SavePageRequest& request);
diff --git a/components/offline_pages/background/request_coordinator_event_logger.cc b/components/offline_pages/background/request_coordinator_event_logger.cc
index 12ddf8c2..08702920a7 100644
--- a/components/offline_pages/background/request_coordinator_event_logger.cc
+++ b/components/offline_pages/background/request_coordinator_event_logger.cc
@@ -2,19 +2,69 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include <string>
-
 #include "components/offline_pages/background/request_coordinator_event_logger.h"
 
 namespace offline_pages {
 
+namespace {
+
+static std::string OfflinerRequestStatusToString(
+    Offliner::RequestStatus request_status) {
+  switch (request_status) {
+    case Offliner::UNKNOWN:
+      return "UNKNOWN";
+    case Offliner::LOADED:
+      return "LOADED";
+    case Offliner::SAVED:
+      return "SAVED";
+    case Offliner::REQUEST_COORDINATOR_CANCELED:
+      return "REQUEST_COORDINATOR_CANCELED";
+    case Offliner::PRERENDERING_CANCELED:
+      return "PRERENDERING_CANCELED";
+    case Offliner::PRERENDERING_FAILED:
+      return "PRERENDERING_FAILED";
+    case Offliner::SAVE_FAILED:
+      return "SAVE_FAILED";
+    case Offliner::FOREGROUND_CANCELED:
+      return "FOREGROUND_CANCELED";
+    default:
+      DCHECK(false);
+      return "";
+  }
+}
+
+static std::string UpdateRequestResultToString(
+    RequestQueue::UpdateRequestResult result) {
+  switch (result) {
+    case RequestQueue::UpdateRequestResult::SUCCESS:
+      return "SUCCESS";
+    case RequestQueue::UpdateRequestResult::STORE_FAILURE:
+      return "STORE_FAILURE";
+    case RequestQueue::UpdateRequestResult::REQUEST_DOES_NOT_EXIST:
+      return "REQUEST_DOES_NOT_EXIST";
+    default:
+      DCHECK(false);
+      return "";
+  }
+}
+
+}  // namespace
+
 void RequestCoordinatorEventLogger::RecordSavePageRequestUpdated(
     const std::string& name_space,
-    const std::string& new_status,
+    Offliner::RequestStatus new_status,
     int64_t id) {
   RecordActivity("Save page request for ID: " + std::to_string(id) +
                  " and namespace: " + name_space +
-                 " has been updated with status " + new_status);
+                 " has been updated with status " +
+                 OfflinerRequestStatusToString(new_status));
+}
+
+void RequestCoordinatorEventLogger::RecordUpdateRequestFailed(
+    const std::string& name_space,
+    RequestQueue::UpdateRequestResult result) {
+  RecordActivity("Updating queued request for namespace: " + name_space +
+                 " failed with result: " + UpdateRequestResultToString(result));
 }
 
 }  // namespace offline_pages
diff --git a/components/offline_pages/background/request_coordinator_event_logger.h b/components/offline_pages/background/request_coordinator_event_logger.h
index 0e0476435..4ac05e89 100644
--- a/components/offline_pages/background/request_coordinator_event_logger.h
+++ b/components/offline_pages/background/request_coordinator_event_logger.h
@@ -6,7 +6,10 @@
 #define COMPONENTS_OFFLINE_PAGES_BACKGROUND_REQUEST_COORDINATOR_EVENT_LOGGER_H_
 
 #include <stdint.h>
+#include <string>
 
+#include "components/offline_pages/background/offliner.h"
+#include "components/offline_pages/background/request_queue.h"
 #include "components/offline_pages/offline_event_logger.h"
 
 namespace offline_pages {
@@ -16,8 +19,11 @@
   // Records that a background task with SavePageRequest |request_id|
   // has been updated.
   void RecordSavePageRequestUpdated(const std::string& name_space,
-                                    const std::string& new_status,
+                                    Offliner::RequestStatus new_status,
                                     int64_t request_id);
+
+  void RecordUpdateRequestFailed(const std::string& name_space,
+                                 RequestQueue::UpdateRequestResult result);
 };
 
 }  // namespace offline_pages
diff --git a/components/offline_pages/background/request_coordinator_event_logger_unittest.cc b/components/offline_pages/background/request_coordinator_event_logger_unittest.cc
index a8189a95..b04e6b6e 100644
--- a/components/offline_pages/background/request_coordinator_event_logger_unittest.cc
+++ b/components/offline_pages/background/request_coordinator_event_logger_unittest.cc
@@ -11,11 +11,17 @@
 namespace {
 
 const char kNamespace[] = "last_n";
-const char kStatus[] = "pending";
+const Offliner::RequestStatus kStatus = Offliner::SAVED;
 const int64_t kId = 1234;
-const char kLogString[] =
+const RequestQueue::UpdateRequestResult kUpdateResult =
+    RequestQueue::UpdateRequestResult::STORE_FAILURE;
+
+const char kStatusLogString[] =
     "Save page request for ID: 1234 and namespace: "
-    "last_n has been updated with status pending";
+    "last_n has been updated with status SAVED";
+const char kUpdateResultLogString[] =
+    "Updating queued request for namespace: last_n failed with result: "
+    "STORE_FAILURE";
 const int kTimeLength = 21;
 
 }  // namespace
@@ -26,10 +32,12 @@
 
   logger.SetIsLogging(true);
   logger.RecordSavePageRequestUpdated(kNamespace, kStatus, kId);
+  logger.RecordUpdateRequestFailed(kNamespace, kUpdateResult);
   logger.GetLogs(&log);
 
-  EXPECT_EQ(1u, log.size());
-  EXPECT_EQ(std::string(kLogString), log[0].substr(kTimeLength));
+  EXPECT_EQ(2u, log.size());
+  EXPECT_EQ(std::string(kUpdateResultLogString), log[0].substr(kTimeLength));
+  EXPECT_EQ(std::string(kStatusLogString), log[1].substr(kTimeLength));
 }
 
 TEST(RequestCoordinatorEventLoggerTest, RecordsWhenLoggingIsOff) {
diff --git a/components/offline_pages/background/request_coordinator_unittest.cc b/components/offline_pages/background/request_coordinator_unittest.cc
index 68b9bac..cd81ccc 100644
--- a/components/offline_pages/background/request_coordinator_unittest.cc
+++ b/components/offline_pages/background/request_coordinator_unittest.cc
@@ -332,6 +332,7 @@
   // Add a request to the queue, wait for callbacks to finish.
   offline_pages::SavePageRequest request(
       kRequestId1, kUrl1, kClientId1, base::Time::Now(), kUserRequested);
+  request.MarkAttemptStarted(base::Time::Now());
   coordinator()->queue()->AddRequest(
       request,
       base::Bind(&RequestCoordinatorTest::AddRequestDone,
@@ -372,6 +373,7 @@
   // Add a request to the queue, wait for callbacks to finish.
   offline_pages::SavePageRequest request(
       kRequestId1, kUrl1, kClientId1, base::Time::Now(), kUserRequested);
+  request.MarkAttemptStarted(base::Time::Now());
   coordinator()->queue()->AddRequest(
       request,
       base::Bind(&RequestCoordinatorTest::AddRequestDone,
@@ -416,11 +418,48 @@
                  base::Unretained(this)));
   PumpLoop();
 
-  // Still two requests in the queue.
-  EXPECT_EQ(2UL, last_requests().size());
-  // Verify retry count was incremented for first request.
+  // Now just one request in the queue since failed request removed
+  // (for single attempt policy).
+  EXPECT_EQ(1UL, last_requests().size());
+}
+
+TEST_F(RequestCoordinatorTest, OfflinerDoneForegroundCancel) {
+  // Add a request to the queue, wait for callbacks to finish.
+  offline_pages::SavePageRequest request(
+      kRequestId1, kUrl1, kClientId1, base::Time::Now(), kUserRequested);
+  request.MarkAttemptStarted(base::Time::Now());
+  coordinator()->queue()->AddRequest(
+      request, base::Bind(&RequestCoordinatorTest::AddRequestDone,
+                          base::Unretained(this)));
+  PumpLoop();
+
+  // We need to give a callback to the request.
+  base::Callback<void(bool)> callback = base::Bind(
+      &RequestCoordinatorTest::EmptyCallbackFunction, base::Unretained(this));
+  coordinator()->SetProcessingCallbackForTest(callback);
+
+  // Set up device conditions for the test.
+  DeviceConditions device_conditions(false, 75,
+                                     net::NetworkChangeNotifier::CONNECTION_3G);
+  SetDeviceConditionsForTest(device_conditions);
+
+  // Call the OfflinerDoneCallback to simulate the request failed, wait
+  // for callbacks.
+  EnableOfflinerCallback(true);
+  SendOfflinerDoneCallback(request,
+                           Offliner::RequestStatus::FOREGROUND_CANCELED);
+  PumpLoop();
+
+  // Verify the request is not removed from the queue, and wait for callbacks.
+  coordinator()->queue()->GetRequests(base::Bind(
+      &RequestCoordinatorTest::GetRequestsDone, base::Unretained(this)));
+  PumpLoop();
+
+  // Request no longer in the queue (for single attempt policy).
+  EXPECT_EQ(1UL, last_requests().size());
+  // Verify foreground cancel not counted as an attempt after all.
   const SavePageRequest& found_request = last_requests().front();
-  EXPECT_EQ(1L, found_request.attempt_count());
+  EXPECT_EQ(0L, found_request.attempt_count());
 }
 
 // This tests a StopProcessing call before we have actually started the
@@ -498,7 +537,7 @@
   EXPECT_TRUE(OfflinerWasCanceled());
 }
 
-TEST_F(RequestCoordinatorTest, PrerendererTimeout) {
+TEST_F(RequestCoordinatorTest, WatchdogTimeout) {
   // Build a request to use with the pre-renderer, and put it on the queue.
   offline_pages::SavePageRequest request(
       kRequestId1, kUrl1, kClientId1, base::Time::Now(), kUserRequested);
diff --git a/components/offline_pages/background/request_queue.h b/components/offline_pages/background/request_queue.h
index 4c19550d..429c375 100644
--- a/components/offline_pages/background/request_queue.h
+++ b/components/offline_pages/background/request_queue.h
@@ -8,6 +8,7 @@
 #include <stdint.h>
 
 #include <memory>
+#include <string>
 #include <vector>
 
 #include "base/callback.h"
diff --git a/components/offline_pages/background/save_page_request.cc b/components/offline_pages/background/save_page_request.cc
index f9372f3..e5424d70 100644
--- a/components/offline_pages/background/save_page_request.cc
+++ b/components/offline_pages/background/save_page_request.cc
@@ -78,4 +78,12 @@
   last_attempt_time_ = base::Time();
 }
 
+void SavePageRequest::MarkAttemptAborted() {
+  DCHECK_GT(attempt_count_, 0);
+  last_attempt_time_ = base::Time();
+  // TODO(dougarnett): Would be safer if we had two persisted counters
+  // (attempts_started and attempts_completed) rather just one with decrement.
+  --attempt_count_;
+}
+
 }  // namespace offline_pages
diff --git a/components/offline_pages/background/save_page_request.h b/components/offline_pages/background/save_page_request.h
index 8c09562..d241dea 100644
--- a/components/offline_pages/background/save_page_request.h
+++ b/components/offline_pages/background/save_page_request.h
@@ -50,6 +50,10 @@
   // Marks attempt as completed and clears |last_attempt_time_|.
   void MarkAttemptCompleted();
 
+  // Marks attempt as aborted. Specifically it clears |last_attempt_time_|
+  // and decrements |attempt_count_|.
+  void MarkAttemptAborted();
+
   int64_t request_id() const { return request_id_; }
 
   const GURL& url() const { return url_; }
diff --git a/components/offline_pages/background/save_page_request_unittest.cc b/components/offline_pages/background/save_page_request_unittest.cc
index 63b970f..68f12fe 100644
--- a/components/offline_pages/background/save_page_request_unittest.cc
+++ b/components/offline_pages/background/save_page_request_unittest.cc
@@ -92,10 +92,43 @@
   ASSERT_EQ(creation_time, request.creation_time());
   ASSERT_EQ(activation_time, request.activation_time());
 
-  // Last attempt time, status and attempt count are updated.
+  // Last attempt time and status are updated.
   ASSERT_EQ(base::Time(), request.last_attempt_time());
   ASSERT_EQ(1, request.attempt_count());
   ASSERT_EQ(SavePageRequest::Status::PENDING, request.GetStatus(start_time));
 }
 
-}  // offline_pages
+TEST_F(SavePageRequestTest, StartAndAbortRequest) {
+  base::Time creation_time = base::Time::Now();
+  SavePageRequest request(kRequestId, kUrl, kClientId, creation_time,
+                          kUserRequested);
+  int start_attempt_count = 2;
+  request.set_attempt_count(start_attempt_count);
+
+  base::Time start_time = creation_time + base::TimeDelta::FromHours(3);
+  request.MarkAttemptStarted(start_time);
+
+  // Most things don't change about the request.
+  ASSERT_EQ(kRequestId, request.request_id());
+  ASSERT_EQ(kUrl, request.url());
+  ASSERT_EQ(kClientId, request.client_id());
+  ASSERT_EQ(creation_time, request.creation_time());
+
+  // Attempt time and attempt count will though.
+  ASSERT_EQ(start_time, request.last_attempt_time());
+  ASSERT_EQ(start_attempt_count + 1, request.attempt_count());
+
+  request.MarkAttemptAborted();
+
+  // Again, most things don't change about the request.
+  ASSERT_EQ(kRequestId, request.request_id());
+  ASSERT_EQ(kUrl, request.url());
+  ASSERT_EQ(kClientId, request.client_id());
+  ASSERT_EQ(creation_time, request.creation_time());
+
+  // Last attempt time is updated and attempt count decremented.
+  ASSERT_EQ(base::Time(), request.last_attempt_time());
+  ASSERT_EQ(start_attempt_count, request.attempt_count());
+}
+
+}  // namespace offline_pages
diff --git a/components/offline_pages/client_namespace_constants.cc b/components/offline_pages/client_namespace_constants.cc
index 098ab66..6b391de 100644
--- a/components/offline_pages/client_namespace_constants.cc
+++ b/components/offline_pages/client_namespace_constants.cc
@@ -10,6 +10,7 @@
 const char kLastNNamespace[] = "last_n";
 const char kAsyncNamespace[] = "async_loading";
 const char kCCTNamespace[] = "custom_tabs";
+const char kDownloadNamespace[] = "download";
 
 const char kDefaultNamespace[] = "default";
 
diff --git a/components/offline_pages/client_namespace_constants.h b/components/offline_pages/client_namespace_constants.h
index 7dc4ac5..28057d6 100644
--- a/components/offline_pages/client_namespace_constants.h
+++ b/components/offline_pages/client_namespace_constants.h
@@ -15,6 +15,7 @@
 extern const char kLastNNamespace[];
 extern const char kAsyncNamespace[];
 extern const char kCCTNamespace[];
+extern const char kDownloadNamespace[];
 
 // Currently used for fallbacks like tests.
 extern const char kDefaultNamespace[];
diff --git a/components/offline_pages/client_policy_controller.cc b/components/offline_pages/client_policy_controller.cc
index 3289eac..2d03bec 100644
--- a/components/offline_pages/client_policy_controller.cc
+++ b/components/offline_pages/client_policy_controller.cc
@@ -33,6 +33,13 @@
       MakePolicy(kCCTNamespace, LifetimeType::TEMPORARY,
                  base::TimeDelta::FromDays(2), kUnlimitedPages, 1)));
 
+  policies_.insert(std::make_pair(
+      kDownloadNamespace, MakePolicy(kDownloadNamespace,
+                                     LifetimeType::PERSISTENT,
+                                     base::TimeDelta::FromDays(0),
+                                     kUnlimitedPages,
+                                     kUnlimitedPages)));
+
   // Fallback policy.
   policies_.insert(std::make_pair(
       kDefaultNamespace, MakePolicy(kDefaultNamespace, LifetimeType::TEMPORARY,
diff --git a/components/offline_pages/client_policy_controller_unittest.cc b/components/offline_pages/client_policy_controller_unittest.cc
index 08c5d03..735d7a38 100644
--- a/components/offline_pages/client_policy_controller_unittest.cc
+++ b/components/offline_pages/client_policy_controller_unittest.cc
@@ -71,4 +71,10 @@
   EXPECT_TRUE(isTemporary(policy));
 }
 
+TEST_F(ClientPolicyControllerTest, CheckDownloadDefined) {
+  OfflinePageClientPolicy policy = controller()->GetPolicy(kDownloadNamespace);
+  EXPECT_EQ(policy.name_space, kDownloadNamespace);
+  EXPECT_FALSE(isTemporary(policy));
+}
+
 }  // namespace offline_pages
diff --git a/components/offline_pages/offline_page_model_impl_unittest.cc b/components/offline_pages/offline_page_model_impl_unittest.cc
index 040815a..94902093 100644
--- a/components/offline_pages/offline_page_model_impl_unittest.cc
+++ b/components/offline_pages/offline_page_model_impl_unittest.cc
@@ -1068,6 +1068,15 @@
                                   static_cast<int>(SavePageResult::SUCCESS), 1);
 }
 
+TEST_F(OfflinePageModelImplTest, DownloadNamespace) {
+  SavePage(kTestUrl, ClientId(kDownloadNamespace, "123"));
+  std::string histogram_name = "OfflinePages.SavePageResult.";
+  histogram_name += kDownloadNamespace;
+
+  histograms().ExpectUniqueSample(histogram_name,
+                                  static_cast<int>(SavePageResult::SUCCESS), 1);
+}
+
 TEST(CommandLineFlagsTest, OfflineBookmarks) {
   // Disabled by default.
   EXPECT_FALSE(offline_pages::IsOfflineBookmarksEnabled());
diff --git a/components/safe_browsing_db/v4_rice.cc b/components/safe_browsing_db/v4_rice.cc
index b053715..3016fac 100644
--- a/components/safe_browsing_db/v4_rice.cc
+++ b/components/safe_browsing_db/v4_rice.cc
@@ -106,10 +106,14 @@
   if (result != DECODE_SUCCESS) {
     return result;
   }
-
   out->reserve((num_entries + 1) * 4);
+
+  // Cast to unsigned since we don't look at the sign bit as a sign bit.
+  // first_value should have been an unsigned to begin with but proto don't
+  // allow that.
+  uint32_t first_value_unsigned = static_cast<uint32_t>(first_value);
+  base::CheckedNumeric<uint32_t> last_value(first_value_unsigned);
   char bytes[4];
-  base::CheckedNumeric<uint32_t> last_value(first_value);
   GetBytesFromUInt32(last_value.ValueOrDie(), bytes);
   out->append(bytes, 4);
 
diff --git a/components/safe_browsing_db/v4_store.cc b/components/safe_browsing_db/v4_store.cc
index 4e731ae..69d49a2 100644
--- a/components/safe_browsing_db/v4_store.cc
+++ b/components/safe_browsing_db/v4_store.cc
@@ -5,9 +5,11 @@
 #include "base/base64.h"
 #include "base/bind.h"
 #include "base/files/file_util.h"
+#include "base/memory/ptr_util.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/metrics/sparse_histogram.h"
 #include "base/strings/stringprintf.h"
+#include "components/safe_browsing_db/v4_rice.h"
 #include "components/safe_browsing_db/v4_store.h"
 #include "components/safe_browsing_db/v4_store.pb.h"
 
@@ -40,6 +42,18 @@
                             APPLY_UPDATE_RESULT_MAX);
 }
 
+void RecordDecodeAdditionsResult(V4DecodeResult result) {
+  UMA_HISTOGRAM_ENUMERATION("SafeBrowsing.V4DecodeAdditionsResult", result,
+                            DECODE_RESULT_MAX);
+}
+
+void RecordDecodeRemovalsResult(V4DecodeResult result) {
+  UMA_HISTOGRAM_ENUMERATION("SafeBrowsing.V4DecodeRemovalsResult", result,
+                            DECODE_RESULT_MAX);
+}
+
+// TODO(vakh): Collect and record the metrics for time taken to process updates.
+
 void RecordApplyUpdateResultWhenReadingFromDisk(ApplyUpdateResult result) {
   UMA_HISTOGRAM_ENUMERATION(
       "SafeBrowsing.V4ApplyUpdateResultWhenReadingFromDisk", result,
@@ -99,6 +113,68 @@
   return true;
 }
 
+ApplyUpdateResult V4Store::ProcessFullUpdate(
+    std::unique_ptr<ListUpdateResponse> response,
+    const std::unique_ptr<V4Store>& new_store) {
+  HashPrefixMap hash_prefix_map;
+  ApplyUpdateResult apply_update_result =
+      UpdateHashPrefixMapFromAdditions(response->additions(), &hash_prefix_map);
+  if (apply_update_result == APPLY_UPDATE_SUCCESS) {
+    new_store->hash_prefix_map_ = hash_prefix_map;
+    RecordStoreWriteResult(new_store->WriteToDisk(std::move(response)));
+  }
+  return apply_update_result;
+}
+
+ApplyUpdateResult V4Store::ProcessPartialUpdate(
+    std::unique_ptr<ListUpdateResponse> response,
+    const std::unique_ptr<V4Store>& new_store) {
+  // TODO(vakh):
+  // 1. Done: Merge the old store and the new update in new_store.
+  // 2. Create a ListUpdateResponse containing RICE encoded hash-prefixes and
+  // response_type as FULL_UPDATE, and write that to disk.
+  // 3. Remove this if condition after completing 1. and 2.
+
+  const RepeatedField<int32>* raw_removals = nullptr;
+  RepeatedField<int32> rice_removals;
+  size_t removals_size = response->removals_size();
+  DCHECK_LE(removals_size, 1u);
+  if (removals_size == 1) {
+    const ThreatEntrySet& removal = response->removals().Get(0);
+    const CompressionType compression_type = removal.compression_type();
+    if (compression_type == RAW) {
+      raw_removals = &removal.raw_indices().indices();
+    } else if (compression_type == RICE) {
+      DCHECK(removal.has_rice_indices());
+
+      const RiceDeltaEncoding& rice_indices = removal.rice_indices();
+      V4DecodeResult decode_result = V4RiceDecoder::DecodeIntegers(
+          rice_indices.first_value(), rice_indices.rice_parameter(),
+          rice_indices.num_entries(), rice_indices.encoded_data(),
+          &rice_removals);
+      RecordDecodeRemovalsResult(decode_result);
+      if (decode_result != DECODE_SUCCESS) {
+        return RICE_DECODING_FAILURE;
+      } else {
+        raw_removals = &rice_removals;
+      }
+    } else {
+      NOTREACHED() << "Unexpected compression_type type: " << compression_type;
+      return UNEXPECTED_COMPRESSION_TYPE_REMOVALS_FAILURE;
+    }
+  }
+
+  HashPrefixMap hash_prefix_map;
+  ApplyUpdateResult apply_update_result =
+      UpdateHashPrefixMapFromAdditions(response->additions(), &hash_prefix_map);
+
+  if (apply_update_result == APPLY_UPDATE_SUCCESS) {
+    apply_update_result =
+        new_store->MergeUpdate(hash_prefix_map_, hash_prefix_map, raw_removals);
+  }
+  return apply_update_result;
+}
+
 void V4Store::ApplyUpdate(
     std::unique_ptr<ListUpdateResponse> response,
     const scoped_refptr<base::SingleThreadTaskRunner>& callback_task_runner,
@@ -106,39 +182,12 @@
   std::unique_ptr<V4Store> new_store(
       new V4Store(this->task_runner_, this->store_path_));
   new_store->state_ = response->new_client_state();
-  // TODO(vakh):
-  // 1. Done: Merge the old store and the new update in new_store.
-  // 2. Create a ListUpdateResponse containing RICE encoded hash-prefixes and
-  // response_type as FULL_UPDATE, and write that to disk.
-  // 3. Remove this if condition after completing 1. and 2.
-  HashPrefixMap hash_prefix_map;
+
   ApplyUpdateResult apply_update_result;
   if (response->response_type() == ListUpdateResponse::PARTIAL_UPDATE) {
-    const RepeatedField<int32>* raw_removals = nullptr;
-    size_t removals_size = response->removals_size();
-    DCHECK_LE(removals_size, 1u);
-    if (removals_size == 1) {
-      const ThreatEntrySet& removal = response->removals().Get(0);
-      // TODO(vakh): Allow other compression types.
-      // See: https://bugs.chromium.org/p/chromium/issues/detail?id=624567
-      DCHECK_EQ(RAW, removal.compression_type());
-      raw_removals = &removal.raw_indices().indices();
-    }
-
-    apply_update_result = UpdateHashPrefixMapFromAdditions(
-        response->additions(), &hash_prefix_map);
-    if (apply_update_result == APPLY_UPDATE_SUCCESS) {
-      apply_update_result = new_store->MergeUpdate(
-          hash_prefix_map_, hash_prefix_map, raw_removals);
-    }
-    // TODO(vakh): Generate the updated ListUpdateResponse to write to disk.
+    apply_update_result = ProcessPartialUpdate(std::move(response), new_store);
   } else if (response->response_type() == ListUpdateResponse::FULL_UPDATE) {
-    apply_update_result = UpdateHashPrefixMapFromAdditions(
-        response->additions(), &hash_prefix_map);
-    if (apply_update_result == APPLY_UPDATE_SUCCESS) {
-      new_store->hash_prefix_map_ = hash_prefix_map;
-      RecordStoreWriteResult(new_store->WriteToDisk(std::move(response)));
-    }
+    apply_update_result = ProcessFullUpdate(std::move(response), new_store);
   } else {
     apply_update_result = UNEXPECTED_RESPONSE_TYPE_FAILURE;
     NOTREACHED() << "Unexpected response type: " << response->response_type();
@@ -161,21 +210,46 @@
     const RepeatedPtrField<ThreatEntrySet>& additions,
     HashPrefixMap* additions_map) {
   for (const auto& addition : additions) {
-    // TODO(vakh): Allow other compression types.
-    // See: https://bugs.chromium.org/p/chromium/issues/detail?id=624567
-    DCHECK_EQ(RAW, addition.compression_type());
+    ApplyUpdateResult apply_update_result = APPLY_UPDATE_SUCCESS;
+    const CompressionType compression_type = addition.compression_type();
+    if (compression_type == RAW) {
+      DCHECK(addition.has_raw_hashes());
+      DCHECK(addition.raw_hashes().has_raw_hashes());
 
-    DCHECK(addition.has_raw_hashes());
-    DCHECK(addition.raw_hashes().has_raw_hashes());
+      apply_update_result =
+          AddUnlumpedHashes(addition.raw_hashes().prefix_size(),
+                            addition.raw_hashes().raw_hashes(), additions_map);
+    } else if (compression_type == RICE) {
+      DCHECK(addition.has_rice_hashes());
 
-    PrefixSize prefix_size = addition.raw_hashes().prefix_size();
-    ApplyUpdateResult result = AddUnlumpedHashes(
-        prefix_size, addition.raw_hashes().raw_hashes(), additions_map);
-    if (result != APPLY_UPDATE_SUCCESS) {
+      const RiceDeltaEncoding& rice_hashes = addition.rice_hashes();
+      std::string raw_hashes;
+      V4DecodeResult decode_result = V4RiceDecoder::DecodeBytes(
+          rice_hashes.first_value(), rice_hashes.rice_parameter(),
+          rice_hashes.num_entries(), rice_hashes.encoded_data(), &raw_hashes);
+      RecordDecodeAdditionsResult(decode_result);
+      if (decode_result != DECODE_SUCCESS) {
+        return RICE_DECODING_FAILURE;
+      } else {
+        // Rice-Golomb encoding is used to send compressed compressed 4-byte
+        // hash prefixes. Hash prefixes longer than 4 bytes will not be
+        // compressed, and will be served in raw format instead.
+        // Source: https://developers.google.com/safe-browsing/v4/compression
+        const PrefixSize kPrefixSize = 4;
+        apply_update_result =
+            AddUnlumpedHashes(kPrefixSize, raw_hashes, additions_map);
+      }
+    } else {
+      NOTREACHED() << "Unexpected compression_type type: " << compression_type;
+      return UNEXPECTED_COMPRESSION_TYPE_ADDITIONS_FAILURE;
+    }
+
+    if (apply_update_result != APPLY_UPDATE_SUCCESS) {
       // If there was an error in updating the map, discard the update entirely.
-      return result;
+      return apply_update_result;
     }
   }
+
   return APPLY_UPDATE_SUCCESS;
 }
 
@@ -337,7 +411,7 @@
 
   return (!raw_removals || removals_iter == raw_removals->end())
              ? APPLY_UPDATE_SUCCESS
-             : REMOVALS_INDEX_TOO_LARGE;
+             : REMOVALS_INDEX_TOO_LARGE_FAILURE;
 }
 
 StoreReadResult V4Store::ReadFromDisk() {
@@ -418,7 +492,6 @@
   DCHECK_EQ(file_format_string.size(), written);
 
   if (!base::Move(new_filename, store_path_)) {
-    DVLOG(1) << "store_path_: " << store_path_.value();
     return UNABLE_TO_RENAME_FAILURE;
   }
 
diff --git a/components/safe_browsing_db/v4_store.h b/components/safe_browsing_db/v4_store.h
index 310004d..94621e5 100644
--- a/components/safe_browsing_db/v4_store.h
+++ b/components/safe_browsing_db/v4_store.h
@@ -133,7 +133,16 @@
 
   // One of more index(es) in removals field of the response is greater than
   // the number of hash prefixes currently in the (old) store.
-  REMOVALS_INDEX_TOO_LARGE = 7,
+  REMOVALS_INDEX_TOO_LARGE_FAILURE = 7,
+
+  // Failed to decode the Rice-encoded additions/removals field.
+  RICE_DECODING_FAILURE = 8,
+
+  // Compression type other than RAW and RICE for additions.
+  UNEXPECTED_COMPRESSION_TYPE_ADDITIONS_FAILURE = 9,
+
+  // Compression type other than RAW and RICE for removals.
+  UNEXPECTED_COMPRESSION_TYPE_REMOVALS_FAILURE = 10,
 
   // Memory space for histograms is determined by the max.  ALWAYS
   // ADD NEW VALUES BEFORE THIS ONE.
@@ -238,6 +247,11 @@
                            TestHashPrefixExistsInMapWithDifferentSizes);
   FRIEND_TEST_ALL_PREFIXES(V4StoreTest,
                            TestHashPrefixDoesNotExistInMapWithDifferentSizes);
+  FRIEND_TEST_ALL_PREFIXES(V4StoreTest,
+                           TestAdditionsWithRiceEncodingFailsWithInvalidInput);
+  FRIEND_TEST_ALL_PREFIXES(V4StoreTest, TestAdditionsWithRiceEncodingSucceeds);
+  FRIEND_TEST_ALL_PREFIXES(V4StoreTest, TestRemovalsWithRiceEncodingSucceeds);
+  friend class V4StoreTest;
 
   // If |prefix_size| is within expected range, and |raw_hashes| is not invalid,
   // then it sets |raw_hashes| as the value at key |prefix_size| in
@@ -287,6 +301,20 @@
                                 const ::google::protobuf::RepeatedField<
                                     ::google::protobuf::int32>* raw_removals);
 
+  // Processes the FULL_UPDATE |response| from the server and updates the
+  // V4Store in |new_store| and writes it to disk. If processing the |response|
+  // succeeds, it returns APPLY_UPDATE_SUCCESS.
+  ApplyUpdateResult ProcessFullUpdate(
+      std::unique_ptr<ListUpdateResponse> response,
+      const std::unique_ptr<V4Store>& new_store);
+
+  // Processes the PARTIAL_UPDATE |response| from the server and updates the
+  // V4Store in |new_store|. If processing the |response| succeeds, it returns
+  // APPLY_UPDATE_SUCCESS.
+  ApplyUpdateResult ProcessPartialUpdate(
+      std::unique_ptr<ListUpdateResponse> response,
+      const std::unique_ptr<V4Store>& new_store);
+
   // Reads the state of the store from the file on disk and returns the reason
   // for the failure or reports success.
   StoreReadResult ReadFromDisk();
diff --git a/components/safe_browsing_db/v4_store_unittest.cc b/components/safe_browsing_db/v4_store_unittest.cc
index 59d2ebb..f9bd1ba 100644
--- a/components/safe_browsing_db/v4_store_unittest.cc
+++ b/components/safe_browsing_db/v4_store_unittest.cc
@@ -2,6 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "base/bind.h"
 #include "base/files/file_util.h"
 #include "base/files/scoped_temp_dir.h"
 #include "base/memory/ptr_util.h"
@@ -16,6 +17,7 @@
 namespace safe_browsing {
 
 using ::google::protobuf::RepeatedField;
+using ::google::protobuf::RepeatedPtrField;
 using ::google::protobuf::int32;
 
 class V4StoreTest : public PlatformTest {
@@ -53,6 +55,14 @@
                     file_format_string.size());
   }
 
+  void UpdatedStoreReadyAfterRiceRemovals(bool* called_back,
+                                          std::unique_ptr<V4Store> new_store) {
+    *called_back = true;
+    EXPECT_EQ(2u, new_store->hash_prefix_map_.size());
+    EXPECT_EQ("22222", new_store->hash_prefix_map_[5]);
+    EXPECT_EQ("abcd", new_store->hash_prefix_map_[4]);
+  }
+
   base::ScopedTempDir temp_dir_;
   base::FilePath store_path_;
   scoped_refptr<base::TestSimpleTaskRunner> task_runner_;
@@ -339,7 +349,7 @@
   // old_store: ["2222"]
   raw_removals.Add(1);
   EXPECT_EQ(
-      REMOVALS_INDEX_TOO_LARGE,
+      REMOVALS_INDEX_TOO_LARGE_FAILURE,
       store.MergeUpdate(prefix_map_old, prefix_map_additions, &raw_removals));
 }
 
@@ -613,4 +623,79 @@
   EXPECT_TRUE(store.GetMatchingHashPrefix(full_hash).empty());
 }
 
+#if defined(NDEBUG) && !defined(DCHECK_ALWAYS_ON)
+// This test hits a NOTREACHED so it is a release mode only test.
+TEST_F(V4StoreTest, TestAdditionsWithRiceEncodingFailsWithInvalidInput) {
+  RepeatedPtrField<ThreatEntrySet> additions;
+  ThreatEntrySet* addition = additions.Add();
+  addition->set_compression_type(RICE);
+  addition->mutable_rice_hashes()->set_num_entries(-1);
+  HashPrefixMap additions_map;
+  EXPECT_EQ(RICE_DECODING_FAILURE, V4Store::UpdateHashPrefixMapFromAdditions(
+                                       additions, &additions_map));
+}
+#endif
+
+TEST_F(V4StoreTest, TestAdditionsWithRiceEncodingSucceeds) {
+  RepeatedPtrField<ThreatEntrySet> additions;
+  ThreatEntrySet* addition = additions.Add();
+  addition->set_compression_type(RICE);
+  RiceDeltaEncoding* rice_hashes = addition->mutable_rice_hashes();
+  rice_hashes->set_first_value(5);
+  rice_hashes->set_num_entries(3);
+  rice_hashes->set_rice_parameter(28);
+  // The following value is hand-crafted by getting inspiration from:
+  // https://goto.google.com/testlargenumbersriceencoded
+  // The value listed at that place fails the "integer overflow" check so I
+  // modified it until the decoder parsed it successfully.
+  rice_hashes->set_encoded_data(
+      "\xbf\xa8\x3f\xfb\xf\xf\x5e\x27\xe6\xc3\x1d\xc6\x38");
+  HashPrefixMap additions_map;
+  EXPECT_EQ(APPLY_UPDATE_SUCCESS, V4Store::UpdateHashPrefixMapFromAdditions(
+                                      additions, &additions_map));
+  EXPECT_EQ(1u, additions_map.size());
+  EXPECT_EQ(std::string("\x5\0\0\0V\x7F\xF6o\xCEo1\x81\fL\x93\xAD", 16),
+            additions_map[4]);
+}
+
+TEST_F(V4StoreTest, TestRemovalsWithRiceEncodingSucceeds) {
+  HashPrefixMap prefix_map_old;
+  EXPECT_EQ(APPLY_UPDATE_SUCCESS,
+            V4Store::AddUnlumpedHashes(4, "1111abcdefgh", &prefix_map_old));
+  HashPrefixMap prefix_map_additions;
+  EXPECT_EQ(APPLY_UPDATE_SUCCESS,
+            V4Store::AddUnlumpedHashes(5, "22222bcdef", &prefix_map_additions));
+
+  V4Store store(task_runner_, store_path_);
+  EXPECT_EQ(APPLY_UPDATE_SUCCESS,
+            store.MergeUpdate(prefix_map_old, prefix_map_additions, nullptr));
+
+  // At this point, the store map looks like this:
+  // 4: 1111abcdefgh
+  // 5: 22222bcdef
+  // sorted: 1111, 22222, abcd, bcdef, efgh
+  // We'll now try to delete hashes at indexes 0, 3 and 4 in the sorted list.
+
+  std::unique_ptr<ListUpdateResponse> lur(new ListUpdateResponse);
+  lur->set_response_type(ListUpdateResponse::PARTIAL_UPDATE);
+  ThreatEntrySet* removal = lur->add_removals();
+  removal->set_compression_type(RICE);
+  RiceDeltaEncoding* rice_indices = removal->mutable_rice_indices();
+  rice_indices->set_first_value(0);
+  rice_indices->set_num_entries(2);
+  rice_indices->set_rice_parameter(2);
+  rice_indices->set_encoded_data("\x16");
+
+  bool called_back = false;
+  UpdatedStoreReadyCallback store_ready_callback =
+      base::Bind(&V4StoreTest::UpdatedStoreReadyAfterRiceRemovals,
+                 base::Unretained(this), &called_back);
+  store.ApplyUpdate(std::move(lur), task_runner_, store_ready_callback);
+  task_runner_->RunPendingTasks();
+  base::RunLoop().RunUntilIdle();
+
+  // This ensures that the callback was called.
+  EXPECT_TRUE(called_back);
+}
+
 }  // namespace safe_browsing
diff --git a/components/sync/BUILD.gn b/components/sync/BUILD.gn
index 0ed9652..0cc8cce68 100644
--- a/components/sync/BUILD.gn
+++ b/components/sync/BUILD.gn
@@ -609,8 +609,22 @@
   ]
 }
 
-# GYP version: sync/sync_tests.gypi:sync_unit_tests
+# TODO(maxbogue): Remove this dummy target once bots are updated.
 test("sync_unit_tests") {
+  testonly = true
+  sources = [
+    "base/immutable_unittest.cc",
+  ]
+  deps = [
+    ":sync",
+    "//base",
+    "//base/test:run_all_unittests",
+    "//testing/gtest",
+  ]
+}
+
+source_set("unit_tests") {
+  testonly = true
   sources = [
     "api/attachments/attachment_id_unittest.cc",
     "api/attachments/attachment_metadata_unittest.cc",
@@ -712,7 +726,6 @@
     ":test_support_sync_core",
     ":test_support_sync_core_impl",
     "//base",
-    "//base/test:run_all_unittests",
     "//components/sync",
     "//components/sync/protocol",
     "//google_apis",
diff --git a/components/sync/sync_tests.gypi b/components/sync/sync_tests.gypi
index 6fdc321a..7a3ad9d 100644
--- a/components/sync/sync_tests.gypi
+++ b/components/sync/sync_tests.gypi
@@ -242,141 +242,6 @@
         'api/sync_error_factory_mock.h',
       ],
     },
-
-    # The unit test executable for sync tests.
-    # GN version: //components/sync:sync_unit_tests
-    {
-      'target_name': 'sync_unit_tests',
-      'type': '<(gtest_target_type)',
-      # Typed-parametrized tests generate exit-time destructors.
-      'variables': { 'enable_wexit_time_destructors': 0, },
-      'defines': [
-        'SYNC_TEST',
-      ],
-      'dependencies': [
-        '../base/base.gyp:base',
-        '../base/base.gyp:run_all_unittests',
-        '../google_apis/google_apis.gyp:google_apis',
-        '../google_apis/google_apis.gyp:google_apis_test_support',
-        '../net/net.gyp:net',
-        '../net/net.gyp:net_test_support',
-        '../sql/sql.gyp:sql',
-        '../sql/sql.gyp:test_support_sql',
-        '../testing/gmock.gyp:gmock',
-        '../testing/gtest.gyp:gtest',
-        '../third_party/leveldatabase/leveldatabase.gyp:leveldatabase',
-        '../third_party/protobuf/protobuf.gyp:protobuf_lite',
-        'sync',
-        'test_support_sync_api',
-        'test_support_sync_core',
-        'test_support_sync_core_impl',
-      ],
-      'include_dirs': [
-        '..',
-      ],
-      'sources': [
-        'api/attachments/attachment_id_unittest.cc',
-        'api/attachments/attachment_metadata_unittest.cc',
-        'api/attachments/attachment_unittest.cc',
-        'api/entity_data_unittest.cc',
-        'api/model_type_service_unittest.cc',
-        'api/sync_change_unittest.cc',
-        'api/sync_data_unittest.cc',
-        'api/sync_error_unittest.cc',
-        'api/sync_merge_result_unittest.cc',
-        'engine_impl/apply_control_data_updates_unittest.cc',
-        'engine_impl/backoff_delay_provider_unittest.cc',
-        'engine_impl/directory_commit_contribution_unittest.cc',
-        'engine_impl/directory_update_handler_unittest.cc',
-        'engine_impl/get_updates_processor_unittest.cc',
-        'engine_impl/model_type_worker_unittest.cc',
-        'engine_impl/sync_scheduler_unittest.cc',
-        'engine_impl/syncer_proto_util_unittest.cc',
-        'engine_impl/syncer_unittest.cc',
-        'engine_impl/syncer_util_unittest.cc',
-        'engine_impl/worker_entity_tracker_unittest.cc',
-        'core_impl/attachments/attachment_downloader_impl_unittest.cc',
-        'core_impl/attachments/attachment_service_impl_unittest.cc',
-        'core_impl/attachments/attachment_service_proxy_unittest.cc',
-        'core_impl/attachments/attachment_store_frontend_unittest.cc',
-        'core_impl/attachments/attachment_store_test_template.h',
-        'core_impl/attachments/attachment_uploader_impl_unittest.cc',
-        'core_impl/attachments/fake_attachment_downloader_unittest.cc',
-        'core_impl/attachments/fake_attachment_uploader_unittest.cc',
-        'core_impl/attachments/in_memory_attachment_store_unittest.cc',
-        'core_impl/attachments/on_disk_attachment_store_unittest.cc',
-        'core_impl/attachments/task_queue_unittest.cc',
-        'core_impl/debug_info_event_listener_unittest.cc',
-        'core/http_bridge_unittest.cc',
-        'core_impl/js_mutation_event_observer_unittest.cc',
-        'core_impl/js_sync_encryption_handler_observer_unittest.cc',
-        'core_impl/js_sync_manager_observer_unittest.cc',
-        'core_impl/model_type_connector_proxy_unittest.cc',
-        'core/model_type_store_backend_unittest.cc',
-        'core/model_type_store_impl_unittest.cc',
-        'core/processor_entity_tracker_unittest.cc',
-        'core_impl/protocol_event_buffer_unittest.cc',
-        'base/attachment_id_proto_unittest.cc',
-        'base/cancelation_signal_unittest.cc',
-        'base/enum_set_unittest.cc',
-        'base/node_ordinal_unittest.cc',
-        'base/ordinal_unittest.cc',
-        'base/unique_position_unittest.cc',
-        'core/change_record_unittest.cc',
-        'core/data_batch_impl_unittest.cc',
-        'engine/model_safe_worker_unittest.cc',
-        'sessions/sync_session_snapshot_unittest.cc',
-        'core/simple_metadata_change_list_unittest.cc',
-        'base/immutable_unittest.cc',
-        'base/proto_value_ptr_unittest.cc',
-        'base/weak_handle_unittest.cc',
-        'core/shared_model_type_processor_unittest.cc',
-        'core_impl/sync_encryption_handler_impl_unittest.cc',
-        'core_impl/sync_manager_impl_unittest.cc',
-        'core_impl/syncapi_server_connection_manager_unittest.cc',
-        'js/js_event_details_unittest.cc',
-        'js/sync_js_controller_unittest.cc',
-        'protocol/proto_enum_conversions_unittest.cc',
-        'protocol/proto_value_conversions_unittest.cc',
-        'sessions_impl/model_type_registry_unittest.cc',
-        'sessions_impl/nudge_tracker_unittest.cc',
-        'sessions_impl/status_controller_unittest.cc',
-        'syncable/directory_backing_store_unittest.cc',
-        'syncable/directory_unittest.cc',
-        'syncable/directory_unittest.h',
-        'syncable/entry_kernel_unittest.cc',
-        'syncable/model_type_unittest.cc',
-        'syncable/nigori_util_unittest.cc',
-        'syncable/parent_child_index_unittest.cc',
-        'syncable/syncable_enum_conversions_unittest.cc',
-        'syncable/syncable_id_unittest.cc',
-        'syncable/syncable_unittest.cc',
-        'syncable/syncable_util_unittest.cc',
-        'base/cryptographer_unittest.cc',
-        'base/data_type_histogram_unittest.cc',
-        'base/get_session_name_unittest.cc',
-        'base/nigori_unittest.cc',
-        'base/protobuf_unittest.cc',
-      ],
-      'conditions': [
-        ['OS == "android"', {
-          'dependencies': [
-            '../testing/android/native_test.gyp:native_test_native_code',
-          ],
-        }],
-        ['OS=="linux" and chromeos==1', {
-          # Required by get_session_name_unittest.cc on Chrome OS.
-          'dependencies': [
-            '../chromeos/chromeos.gyp:chromeos',
-          ],
-        }],
-        ['OS == "ios"', {
-          'sources!': [
-            'core/http_bridge_unittest.cc',
-          ],
-        }],
-      ],
-    },
   ],
   'conditions': [
     ['OS != "ios"', {
@@ -494,55 +359,6 @@
             'test/fake_server/android/fake_server_helper_android.h',
           ],
         },
-        {
-          # GN: //components/sync:sync_unit_tests_apk
-          'target_name': 'sync_unit_tests_apk',
-          'type': 'none',
-          'dependencies': [
-            'sync_unit_tests',
-          ],
-          'variables': {
-            'test_suite_name': 'sync_unit_tests',
-            'isolate_file': '../sync_unit_tests.isolate',
-          },
-          'includes': [ '../../build/apk_test.gypi' ],
-        },
-      ],
-      'conditions': [
-        ['test_isolation_mode != "noop"', {
-          'targets': [
-            {
-              'target_name': 'sync_unit_tests_apk_run',
-              'type': 'none',
-              'dependencies': [
-                'sync_unit_tests_apk',
-              ],
-              'includes': [
-                '../../build/isolate.gypi',
-              ],
-              'sources': [
-                'sync_unit_tests_apk.isolate',
-              ],
-            },
-          ],
-        }],
-      ],
-    }],
-    ['test_isolation_mode != "noop"', {
-      'targets': [
-        {
-          'target_name': 'sync_unit_tests_run',
-          'type': 'none',
-          'dependencies': [
-            'sync_unit_tests',
-          ],
-          'includes': [
-            '../../build/isolate.gypi',
-          ],
-          'sources': [
-            '../sync_unit_tests.isolate',
-          ],
-        },
       ],
     }],
   ],
diff --git a/components/sync/sync_unit_tests_apk.isolate b/components/sync/sync_unit_tests_apk.isolate
deleted file mode 100644
index dbd6410..0000000
--- a/components/sync/sync_unit_tests_apk.isolate
+++ /dev/null
@@ -1,24 +0,0 @@
-# Copyright 2015 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.
-{
-  'includes': [
-    '../../build/android/android.isolate',
-    'sync_unit_tests.isolate',
-  ],
-  'variables': {
-    'command': [
-      '<(PRODUCT_DIR)/bin/run_sync_unit_tests',
-      '--logcat-output-dir', '${ISOLATED_OUTDIR}/logcats',
-    ],
-    'files': [
-      '../../base/base.isolate',
-      '../../build/config/',
-      '../../third_party/icu/icu.isolate',
-      '../../third_party/instrumented_libraries/instrumented_libraries.isolate',
-      '<(PRODUCT_DIR)/bin/run_sync_unit_tests',
-      '<(PRODUCT_DIR)/sync_unit_tests_apk/',
-      'sync_unit_tests.isolate',
-    ]
-  },
-}
diff --git a/components/sync_sessions/sessions_sync_manager.cc b/components/sync_sessions/sessions_sync_manager.cc
index 4d9505d1..516999d 100644
--- a/components/sync_sessions/sessions_sync_manager.cc
+++ b/components/sync_sessions/sessions_sync_manager.cc
@@ -238,15 +238,15 @@
           continue;
 
         if (synced_tab->IsPlaceholderTab()) {
-          // For tabs without WebContents update the |tab_id|, as it could have
-          // changed after a session restore.
+          // For tabs without WebContents update the |tab_id| and |window_id|,
+          // as it could have changed after a session restore.
           // Note: We cannot check if a tab is valid if it has no WebContents.
           // We assume any such tab is valid and leave the contents of
           // corresponding sync node unchanged.
           if (synced_tab->GetSyncId() > TabNodePool::kInvalidTabNodeID &&
               tab_id > TabNodePool::kInvalidTabID) {
-            AssociateRestoredPlaceholderTab(*synced_tab, tab_id, restored_tabs,
-                                            change_output);
+            AssociateRestoredPlaceholderTab(*synced_tab, tab_id, window_id,
+                                            restored_tabs, change_output);
             found_tabs = true;
             window_s.add_tab(tab_id);
           }
@@ -948,6 +948,7 @@
 void SessionsSyncManager::AssociateRestoredPlaceholderTab(
     const SyncedTabDelegate& tab_delegate,
     SessionID::id_type new_tab_id,
+    SessionID::id_type new_window_id,
     const syncer::SyncDataList& restored_tabs,
     syncer::SyncChangeList* change_output) {
   DCHECK_NE(tab_delegate.GetSyncId(), TabNodePool::kInvalidTabNodeID);
@@ -974,11 +975,14 @@
     TabLink* tab_link = new TabLink(tab_delegate.GetSyncId(), &tab_delegate);
     local_tab_map_[new_tab_id] = make_linked_ptr<TabLink>(tab_link);
 
-    if (specifics->tab().tab_id() == new_tab_id)
+    if (specifics->tab().tab_id() == new_tab_id &&
+        specifics->tab().window_id() == new_window_id)
       return;
 
-    // The tab_id changed (e.g due to session restore), so update sync.
+    // Either the tab_id or window_id changed (e.g due to session restore), so
+    // update the sync node.
     specifics->mutable_tab()->set_tab_id(new_tab_id);
+    specifics->mutable_tab()->set_window_id(new_window_id);
     syncer::SyncData data = syncer::SyncData::CreateLocalData(
         TabNodePool::TabIdToTag(current_machine_tag_, specifics->tab_node_id()),
         current_session_name_, entity);
diff --git a/components/sync_sessions/sessions_sync_manager.h b/components/sync_sessions/sessions_sync_manager.h
index 8e0b53ff..e759fdc 100644
--- a/components/sync_sessions/sessions_sync_manager.h
+++ b/components/sync_sessions/sessions_sync_manager.h
@@ -289,8 +289,8 @@
   // into memory yet (e.g on android) and we don't have a WebContents. In this
   // case we can't do a full association, but we still want to update tab IDs
   // as they may have changed after a session was restored.  This method
-  // compares new_tab_id against the previously persisted tab ID (from
-  // our TabNodePool) and updates it if it differs.
+  // compares new_tab_id and new_window_id against the previously persisted tab
+  // ID and window ID (from our TabNodePool) and updates them if either differs.
   // |restored_tabs| is a filtered tab-only subset of initial sync data, if
   // available (during MergeDataAndStartSyncing). It can be used to obtain
   // baseline SessionSpecifics for tabs we can't fully associate any other
@@ -300,6 +300,7 @@
   void AssociateRestoredPlaceholderTab(
       const SyncedTabDelegate& tab_delegate,
       SessionID::id_type new_tab_id,
+      SessionID::id_type new_window_id,
       const syncer::SyncDataList& restored_tabs,
       syncer::SyncChangeList* change_output);
 
diff --git a/components/sync_unit_tests.isolate b/components/sync_unit_tests.isolate
deleted file mode 100644
index b180652..0000000
--- a/components/sync_unit_tests.isolate
+++ /dev/null
@@ -1,32 +0,0 @@
-# Copyright 2015 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.
-{
-  'conditions': [
-    ['OS=="linux" or OS=="mac" or OS=="win"', {
-      'variables': {
-        'command': [
-          '../../testing/test_env.py',
-          '<(PRODUCT_DIR)/sync_unit_tests<(EXECUTABLE_SUFFIX)',
-          '--brave-new-test-launcher',
-          '--test-launcher-bot-mode',
-          '--asan=<(asan)',
-          '--msan=<(msan)',
-          '--tsan=<(tsan)',
-        ],
-        'files': [
-          '../../chrome/test/data/sync/',
-          '../../net/tools/testserver/',
-          '../../testing/test_env.py',
-          '../../third_party/pyftpdlib/',
-          '../../third_party/pywebsocket/',
-          '../../third_party/tlslite/',
-          '<(PRODUCT_DIR)/pyproto/google/',
-        ],
-      },
-    }],
-  ],
-  'includes': [
-    '../../base/base.isolate',
-  ],
-}
diff --git a/components/test/data/cast_certificate/testsuite/testsuite1.pb b/components/test/data/cast_certificate/testsuite/testsuite1.pb
index c85079c..3f3b90de 100644
--- a/components/test/data/cast_certificate/testsuite/testsuite1.pb
+++ b/components/test/data/cast_certificate/testsuite/testsuite1.pb
Binary files differ
diff --git a/components/test/data/cast_certificate/testsuite/testsuite1.pb_text b/components/test/data/cast_certificate/testsuite/testsuite1.pb_text
index dcebb0eb..3a4fb31 100644
--- a/components/test/data/cast_certificate/testsuite/testsuite1.pb_text
+++ b/components/test/data/cast_certificate/testsuite/testsuite1.pb_text
@@ -217,3 +217,20 @@
   cert_verification_time_seconds: 1466642485
   crl_verification_time_seconds: 1466642483
 }
+tests {
+  description: "Prod: Valid cert, valid path, no revocation checking."
+  der_cert_path: "0\202\003\2420\202\002\212\240\003\002\001\002\002\004U\aG\3170\r\006\t*\206H\206\367\r\001\001\005\005\0000y1\v0\t\006\003U\004\006\023\002US1\0230\021\006\003U\004\b\f\nCalifornia1\0260\024\006\003U\004\a\f\rMountain View1\0230\021\006\003U\004\n\f\nGoogle Inc1\r0\v\006\003U\004\v\f\004Cast1\0310\027\006\003U\004\003\f\020Chromecast ICA 30\036\027\r150316211455Z\027\r350311211455Z0|1\v0\t\006\003U\004\006\023\002US1\r0\v\006\003U\004\v\f\004Cast1\0230\021\006\003U\004\n\f\nGoogle Inc1\0230\021\006\003U\004\b\f\nCalifornia1\0260\024\006\003U\004\a\f\rMountain View1\0340\032\006\003U\004\003\f\0233ZZAK6 FA8FCA3F0D350\202\001\"0\r\006\t*\206H\206\367\r\001\001\001\005\000\003\202\001\017\0000\202\001\n\002\202\001\001\000\341F_q\275\306-\344\002\246\r!\3173\240\350\352\373\210T\241\264\203I\236\236\020\304\335\303Z\376\233\211)\034\316\274;\322g\016\205\341\303\212\036K\375\233\272\227\2248Ct[\r\027\307\277\300\234\331\001\021\361\325\313\224A\254\201\n\373x9\357\303H\346\265\227\276\212\241V\364\237\324\373!\263\247\240\1770\203\036\'\032M\030\252-\361E\0032\252\f6\204\016\267\037i\264\355u\364\321\241\227p+\220\336\371\262\263\v\243\262\030\2665\365\273\004L\356\204RXk\312\226\v\272\314>1]\205gy.\005\005\3120\372*j#\002\002\327\331A\253\257\305\320\273\247d\327\004\335\310\vGh~\022\201\246/\\75$z\177S\304E\035\372\t\251W\030\220>\032&\201<\236\350\b\246U\214\336\034\302\261\233$lPH\357\271\271\232\310M;\263U\220\034\023?\215\031&Z\267\326\0370\213\305\254k\241\bJ\312Y\002\003\001\000\001\243/0-0\t\006\003U\035\023\004\0020\0000\v\006\003U\035\017\004\004\003\002\a\2000\023\006\003U\035%\004\f0\n\006\b+\006\001\005\005\a\003\0020\r\006\t*\206H\206\367\r\001\001\005\005\000\003\202\001\001\000c^\"\317\260\217\210\264d\242w\205)R\206\023\341\210\352t\006Q\376!E=b\335|\t\311\300d\225\231mU\231\3524#\330\037\252\331\275\266\221\031z-\016\\\377c\321\377\242\271\364\275\263\2464\203y\310\002\363g\"\312\251\252\252\365\357{\356}\v\357\362\367\346\351\312\354\305\315\274\030\377\fD\356n\346\tD9\372o\031\260\276_K\256h7\203\002\262\257\376k\005h\227e.y\025\313\221\201X\267\366N\362\357\341\266\223\213\240\242\235\215\351\005\333\334x\t\313\005\260r\263P\331\r\254\302\021\224{\232\026\334A4J\256\264\372\375\020_O\310F3y3n\250\225\326\222}\273\004m\001\231`{\261\331\024\273~\212/Q\344Y\002:R\324\322\322\223\323\363;\256\032lP\237\231P(\242.\341\341`\027\0341\027?\273u\247\274\326\235\fX\251\376i\024\271N\352\324&\362Z\256&\272\377\357C\356\003"
+  der_cert_path: "0\202\003\3110\202\002\261\240\003\002\001\002\002\001$0\r\006\t*\206H\206\367\r\001\001\v\005\0000u1\v0\t\006\003U\004\006\023\002US1\0230\021\006\003U\004\b\f\nCalifornia1\0260\024\006\003U\004\a\f\rMountain View1\0230\021\006\003U\004\n\f\nGoogle Inc1\r0\v\006\003U\004\v\f\004Cast1\0250\023\006\003U\004\003\f\fCast Root CA0\036\027\r150312164439Z\027\r250309164439Z0y1\v0\t\006\003U\004\006\023\002US1\0230\021\006\003U\004\b\f\nCalifornia1\0260\024\006\003U\004\a\f\rMountain View1\0230\021\006\003U\004\n\f\nGoogle Inc1\r0\v\006\003U\004\v\f\004Cast1\0310\027\006\003U\004\003\f\020Chromecast ICA 30\202\001\"0\r\006\t*\206H\206\367\r\001\001\001\005\000\003\202\001\017\0000\202\001\n\002\202\001\001\000\321\336\373\255\213C\a(\256V-\362s*\037cCvm\215\270\321\324\220)\033\221hJUA\240\325a\264\354\335\256\341\372\247\2668\304\336\031\3413M\232)\361H\342k\247,!\024\"?\207\201\363q,\346C\034\270\324\354\317g/\262\242u\213\020\275\371\347\311\\\336\005\251\264\206\267h}\247v\205\342e\270vQO\271`]~+dH\022f\331\247\273|\327H\210\212\211\371\030\024\212\0252j\033?@d<\200\323\345r\356;o\210\273\223\032\027<5\313\324[\330\364P\006\b\210\n\345\302<\265\215\233\231\202&\243\233\271\345\001\220\267\311\335\377\017\366\317\264\233\370Jp@\003\355\25285\222IJZ g\222^%\250klI(EA\263\225\035\241\255\357\303Z\0225\246/D\364\3736\314\371\377\324l\250`\346\t\027\246\240\023#\t\226o\335>\375\372Z\347\232\006\023\345\a\016}\\\017\321F\205\002\003\001\000\001\243`0^0\017\006\003U\035\023\004\b0\006\001\001\377\002\001\0000\035\006\003U\035\016\004\026\004\024B\326<\203NN\2036\364-\200\022\030\260\372d\355\313\221\3350\037\006\003U\035#\004\0300\026\200\024|\232\036}\337yT\274\327\314^\312\231\206Eyet(\0310\v\006\003U\035\017\004\004\003\002\001\0060\r\006\t*\206H\206\367\r\001\001\v\005\000\003\202\001\001\000L\307wK\tu\204\253\204\f\223\032\243\037\n\002\262(\000\363\353\301\351R\f{8{\002\32421!\321\205\260#B\340&\005\340\021!\374\264\263~=\252JT\251\b\346y\'\374\275\3751\330\322\302\336\226\0166\371\370g\312\363Yz\250\357\242\275\246s\352\350\253]%\005\235r-\377\n,\177\257\227\306\303\277\265v\005\240\000\021\033\203\231L\213\310\270Kvy\003V\313\352\314\362\002\274#\213\032\246\177\177K\235}ji\315\343Px\271\\\255Y>\335\323\214/\n\373\335\003\300w\204\346\251&\027\024$\242{=<\267<\330\b1\244Kh\213\f\203%i\353hB\242\207\240\241\335Z\032J\034\355(\001=\255Q\326\\\357K\200\322~#\374\275\032\0020\320F\270\261\253\017\307(\356\332\272\347\326>\244\251&\354\324sA\305\233h\212\250\306\02593MH~j/K\034m\257#\002m\350/\316\026\270K"
+  expected_result: SUCCESS
+  cert_verification_time_seconds: 1470182400
+  use_test_trust_anchors: false
+}
+tests {
+  description: "Prod: Empty CRL."
+  der_cert_path: "0\202\003\2420\202\002\212\240\003\002\001\002\002\004U\aG\3170\r\006\t*\206H\206\367\r\001\001\005\005\0000y1\v0\t\006\003U\004\006\023\002US1\0230\021\006\003U\004\b\f\nCalifornia1\0260\024\006\003U\004\a\f\rMountain View1\0230\021\006\003U\004\n\f\nGoogle Inc1\r0\v\006\003U\004\v\f\004Cast1\0310\027\006\003U\004\003\f\020Chromecast ICA 30\036\027\r150316211455Z\027\r350311211455Z0|1\v0\t\006\003U\004\006\023\002US1\r0\v\006\003U\004\v\f\004Cast1\0230\021\006\003U\004\n\f\nGoogle Inc1\0230\021\006\003U\004\b\f\nCalifornia1\0260\024\006\003U\004\a\f\rMountain View1\0340\032\006\003U\004\003\f\0233ZZAK6 FA8FCA3F0D350\202\001\"0\r\006\t*\206H\206\367\r\001\001\001\005\000\003\202\001\017\0000\202\001\n\002\202\001\001\000\341F_q\275\306-\344\002\246\r!\3173\240\350\352\373\210T\241\264\203I\236\236\020\304\335\303Z\376\233\211)\034\316\274;\322g\016\205\341\303\212\036K\375\233\272\227\2248Ct[\r\027\307\277\300\234\331\001\021\361\325\313\224A\254\201\n\373x9\357\303H\346\265\227\276\212\241V\364\237\324\373!\263\247\240\1770\203\036\'\032M\030\252-\361E\0032\252\f6\204\016\267\037i\264\355u\364\321\241\227p+\220\336\371\262\263\v\243\262\030\2665\365\273\004L\356\204RXk\312\226\v\272\314>1]\205gy.\005\005\3120\372*j#\002\002\327\331A\253\257\305\320\273\247d\327\004\335\310\vGh~\022\201\246/\\75$z\177S\304E\035\372\t\251W\030\220>\032&\201<\236\350\b\246U\214\336\034\302\261\233$lPH\357\271\271\232\310M;\263U\220\034\023?\215\031&Z\267\326\0370\213\305\254k\241\bJ\312Y\002\003\001\000\001\243/0-0\t\006\003U\035\023\004\0020\0000\v\006\003U\035\017\004\004\003\002\a\2000\023\006\003U\035%\004\f0\n\006\b+\006\001\005\005\a\003\0020\r\006\t*\206H\206\367\r\001\001\005\005\000\003\202\001\001\000c^\"\317\260\217\210\264d\242w\205)R\206\023\341\210\352t\006Q\376!E=b\335|\t\311\300d\225\231mU\231\3524#\330\037\252\331\275\266\221\031z-\016\\\377c\321\377\242\271\364\275\263\2464\203y\310\002\363g\"\312\251\252\252\365\357{\356}\v\357\362\367\346\351\312\354\305\315\274\030\377\fD\356n\346\tD9\372o\031\260\276_K\256h7\203\002\262\257\376k\005h\227e.y\025\313\221\201X\267\366N\362\357\341\266\223\213\240\242\235\215\351\005\333\334x\t\313\005\260r\263P\331\r\254\302\021\224{\232\026\334A4J\256\264\372\375\020_O\310F3y3n\250\225\326\222}\273\004m\001\231`{\261\331\024\273~\212/Q\344Y\002:R\324\322\322\223\323\363;\256\032lP\237\231P(\242.\341\341`\027\0341\027?\273u\247\274\326\235\fX\251\376i\024\271N\352\324&\362Z\256&\272\377\357C\356\003"
+  der_cert_path: "0\202\003\3110\202\002\261\240\003\002\001\002\002\001$0\r\006\t*\206H\206\367\r\001\001\v\005\0000u1\v0\t\006\003U\004\006\023\002US1\0230\021\006\003U\004\b\f\nCalifornia1\0260\024\006\003U\004\a\f\rMountain View1\0230\021\006\003U\004\n\f\nGoogle Inc1\r0\v\006\003U\004\v\f\004Cast1\0250\023\006\003U\004\003\f\fCast Root CA0\036\027\r150312164439Z\027\r250309164439Z0y1\v0\t\006\003U\004\006\023\002US1\0230\021\006\003U\004\b\f\nCalifornia1\0260\024\006\003U\004\a\f\rMountain View1\0230\021\006\003U\004\n\f\nGoogle Inc1\r0\v\006\003U\004\v\f\004Cast1\0310\027\006\003U\004\003\f\020Chromecast ICA 30\202\001\"0\r\006\t*\206H\206\367\r\001\001\001\005\000\003\202\001\017\0000\202\001\n\002\202\001\001\000\321\336\373\255\213C\a(\256V-\362s*\037cCvm\215\270\321\324\220)\033\221hJUA\240\325a\264\354\335\256\341\372\247\2668\304\336\031\3413M\232)\361H\342k\247,!\024\"?\207\201\363q,\346C\034\270\324\354\317g/\262\242u\213\020\275\371\347\311\\\336\005\251\264\206\267h}\247v\205\342e\270vQO\271`]~+dH\022f\331\247\273|\327H\210\212\211\371\030\024\212\0252j\033?@d<\200\323\345r\356;o\210\273\223\032\027<5\313\324[\330\364P\006\b\210\n\345\302<\265\215\233\231\202&\243\233\271\345\001\220\267\311\335\377\017\366\317\264\233\370Jp@\003\355\25285\222IJZ g\222^%\250klI(EA\263\225\035\241\255\357\303Z\0225\246/D\364\3736\314\371\377\324l\250`\346\t\027\246\240\023#\t\226o\335>\375\372Z\347\232\006\023\345\a\016}\\\017\321F\205\002\003\001\000\001\243`0^0\017\006\003U\035\023\004\b0\006\001\001\377\002\001\0000\035\006\003U\035\016\004\026\004\024B\326<\203NN\2036\364-\200\022\030\260\372d\355\313\221\3350\037\006\003U\035#\004\0300\026\200\024|\232\036}\337yT\274\327\314^\312\231\206Eyet(\0310\v\006\003U\035\017\004\004\003\002\001\0060\r\006\t*\206H\206\367\r\001\001\v\005\000\003\202\001\001\000L\307wK\tu\204\253\204\f\223\032\243\037\n\002\262(\000\363\353\301\351R\f{8{\002\32421!\321\205\260#B\340&\005\340\021!\374\264\263~=\252JT\251\b\346y\'\374\275\3751\330\322\302\336\226\0166\371\370g\312\363Yz\250\357\242\275\246s\352\350\253]%\005\235r-\377\n,\177\257\227\306\303\277\265v\005\240\000\021\033\203\231L\213\310\270Kvy\003V\313\352\314\362\002\274#\213\032\246\177\177K\235}ji\315\343Px\271\\\255Y>\335\323\214/\n\373\335\003\300w\204\346\251&\027\024$\242{=<\267<\330\b1\244Kh\213\f\203%i\353hB\242\207\240\241\335Z\032J\034\355(\001=\255Q\326\\\357K\200\322~#\374\275\032\0020\320F\270\261\253\017\307(\356\332\272\347\326>\244\251&\354\324sA\305\233h\212\250\306\02593MH~j/K\034m\257#\002m\350/\316\026\270K"
+  crl_bundle: "\n\337\t\n\f\020\270\362\203\275\005\030\270\347\250\275\005\022\313\a0\202\003\3070\202\002\257\240\003\002\001\002\002\002\000\2320\r\006\t*\206H\206\367\r\001\001\v\005\0000y1\v0\t\006\003U\004\006\023\002US1\0230\021\006\003U\004\b\f\nCalifornia1\0260\024\006\003U\004\a\f\rMountain View1\0230\021\006\003U\004\n\f\nGoogle Inc1\r0\v\006\003U\004\v\f\004Cast1\0310\027\006\003U\004\003\f\020Cast CRL Root CA0\036\027\r160801234632Z\027\r161109234632Z0x1\v0\t\006\003U\004\006\023\002US1\0230\021\006\003U\004\b\f\nCalifornia1\0260\024\006\003U\004\a\f\rMountain View1\0230\021\006\003U\004\n\f\nGoogle Inc1\r0\v\006\003U\004\v\f\004Cast1\0300\026\006\003U\004\003\f\017Cast CRL Signer0\202\001\"0\r\006\t*\206H\206\367\r\001\001\001\005\000\003\202\001\017\0000\202\001\n\002\202\001\001\000\312\323\264p\353\347\253W\266\315k\020`\274\202\034t[\262\245\037\340\265\245E\266\260\267\251\027\275a\367\237\016\307>\347\305X\273\341e-\325\2231d\276\351\271\264\257*\\\023\b\223\377Z\330\266-/\314JY\324\267`\240\370t2\177\247\003;8\321\024\315\022\242@\304;\253\rZ\352\305\232\005\314\245\241-\247n\251\240\021\tk\311\227\334\351h\004+6\231\274\213\n\357lt\0257A\353\200M#\245\317\230\346\211\257\216\312\301\2035!l\252\\\250/i\r\025\342\022D\343\343\375zU\261\265\246:=?\a\230\373\246\275\351\370\304\016#o\035\323\261\233&\315\006\312N\215\030\206\034_\221\204\302b<\336\327\317\006\227m\317K\370\351\301\037\266C\341\305\226s5\177\235:\233\257\032\317\0170\343\212\275\271(\355\213\272\360\fI\211^\264m\330\274\234\036-\250\006\210\353@@\016\"\330\n\a)\032\321\v\336\331\002\003\001\000\001\243Z0X0\t\006\003U\035\023\004\0020\0000\035\006\003U\035\016\004\026\004\024+\220\335<H\234\211#\264\254h\315^B\036^,\324\313\2430\037\006\003U\035#\004\0300\026\200\024\032e\022\264\251\271\264\374\221\f\236g\340[\331\311\255D\034\2710\v\006\003U\035\017\004\004\003\002\a\2000\r\006\t*\206H\206\367\r\001\001\v\005\000\003\202\001\001\000\215M\323\271\237\355\260\336\315\020_\315\3051\363i\365V\307\033\251/;\002\311M\2279.j\373\311\267\034\315\221\360\230\227\"\372\237\231\210\025Uk\b\206\360\236*$\277x+\362\022B\240\005\214\213\272\330\205\325+\346\221\303\r\036\004\357\021\371K\033;8\350\322H7\220\241\244a\234\2051C\333Z\376\316\205\350\320\r\266\201\002\003\250\236\000%\231\302\t6#\310K\305#\246+\346\027\255N\376}S\226s\366\317%-h\235\357Q\230\253Mc;\204\"\202I\230C \261\036^\257\335\374;Qe\001\333\2432\323\277\217Y\004\'q\356\311\210\\\322\244\233*\016\367 &~\3752\373\236\000\261o\260\2036\005\001SB\306g(\202\343\325\370\376\021UA\200UT\030\323\213\325\306\232&\275\377;5[\353\335yY*\372_\346\310\361\360\307\270U\207X\226\260\f!\273\237\206\307]z-\310j4\004\'4\240\032\200\002n\327,\252e\n\211=\224\241Ng\357tc\237-\246\a\226&GR\277\365dc2\342\344\335\311\001M\356A\026\000\247\035A;\\\332\335d\313\\\371xo\032P\361\266\347q\300\271\371E\250\255.VM\325\266\002\305\020\212\375\3721>\251J}M]\216{\205Twp\3208\330\232\271\341n@&a\225\222\205\302\022\226LA\211\343=}\233\340\325\330P\023\027=g\371\372\3162\370\355r\305\f\v\222`r|\266\222\212\327\3360J\310\221\220\316m_K\377I8\333\356\004\234L\340\267\315\270&\272\025\025\323#ed\366{\330\3273\332\326c\300}\000N2xS\255\327\206\224T\336\267\344^\225C\221e\220Wt\264S\022:\023\235ww\207\367=\320\267-\003+\v\265\250\330W\314\261\222>d\240\204\264R\006\316A\344\267#\213\216\005\301\272\375\310\336\210\373\033\341\316U_\324\307D}\311v\343\034"
+  expected_result: SUCCESS
+  cert_verification_time_seconds: 1470182400
+  use_test_trust_anchors: false
+}
diff --git a/components/tracing/BUILD.gn b/components/tracing/BUILD.gn
index 0e3c97f..c00cdd2b 100644
--- a/components/tracing/BUILD.gn
+++ b/components/tracing/BUILD.gn
@@ -63,7 +63,9 @@
   visibility = [ "//components/tracing/*" ]
 
   sources = [
-    "test/example_messages.proto",
+    "test/example_proto/library.proto",
+    "test/example_proto/library_internals/galaxies.proto",
+    "test/example_proto/test_messages.proto",
   ]
 
   generator_plugin_label = "tools/proto_zero_plugin:proto_zero_plugin"
diff --git a/components/tracing/test/example_proto/library.proto b/components/tracing/test/example_proto/library.proto
new file mode 100644
index 0000000..04f019e
--- /dev/null
+++ b/components/tracing/test/example_proto/library.proto
@@ -0,0 +1,16 @@
+// 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.
+
+syntax = "proto2";
+package foo.bar;
+
+import public "library_internals/galaxies.proto";
+
+message TransgalacticMessage {
+  optional Galaxy origin_galaxy = 1;
+  optional string origin_planet = 2;
+  optional Galaxy destination_galaxy = 3;
+  optional string destination_planet = 4;
+  optional bytes proto_message = 5;
+}
diff --git a/components/tracing/test/example_proto/library_internals/galaxies.proto b/components/tracing/test/example_proto/library_internals/galaxies.proto
new file mode 100644
index 0000000..21e9019
--- /dev/null
+++ b/components/tracing/test/example_proto/library_internals/galaxies.proto
@@ -0,0 +1,12 @@
+// 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.
+
+syntax = "proto2";
+package foo.bar;
+
+enum Galaxy {
+  MILKY_WAY = 1;
+  ANDROMEDA = 2;
+  SUNFLOWER = 3;
+}
diff --git a/components/tracing/test/example_messages.proto b/components/tracing/test/example_proto/test_messages.proto
similarity index 85%
rename from components/tracing/test/example_messages.proto
rename to components/tracing/test/example_proto/test_messages.proto
index c3210b82..588ec84 100644
--- a/components/tracing/test/example_messages.proto
+++ b/components/tracing/test/example_proto/test_messages.proto
@@ -5,9 +5,17 @@
 syntax = "proto2";
 package foo.bar;
 
+import "library.proto";
+
 // This file contains comprehensive set of supported message structures and
 // data types. Unit tests depends on the plugin-processed version of this file.
 
+// Tests importing message definition from another proto file.
+message TransgalacticParcel {
+  optional TransgalacticMessage message = 1;
+  optional string tracking_code = 2;
+}
+
 enum SmallEnum {
   TO_BE = 1;
   NOT_TO_BE = 0;
@@ -63,4 +71,5 @@
     optional NestedC value_b = 1;
   }
   repeated NestedB repeated_a = 2;
+  optional NestedB.NestedC super_nested = 3;
 }
diff --git a/components/tracing/test/proto_zero_generation_unittest.cc b/components/tracing/test/proto_zero_generation_unittest.cc
index 31fb8ea..531cadb 100644
--- a/components/tracing/test/proto_zero_generation_unittest.cc
+++ b/components/tracing/test/proto_zero_generation_unittest.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "components/tracing/test/example_messages.pbzero.h"
+#include "components/tracing/test/example_proto/test_messages.pbzero.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace tracing {
diff --git a/components/tracing/tools/proto_zero_plugin/proto_zero_generator.cc b/components/tracing/tools/proto_zero_plugin/proto_zero_generator.cc
index 12a32ab3..2165673 100644
--- a/components/tracing/tools/proto_zero_plugin/proto_zero_generator.cc
+++ b/components/tracing/tools/proto_zero_plugin/proto_zero_generator.cc
@@ -6,6 +6,7 @@
 
 #include <map>
 #include <memory>
+#include <set>
 #include <string>
 
 #include "third_party/protobuf/src/google/protobuf/descriptor.h"
@@ -33,6 +34,10 @@
 
 namespace {
 
+inline std::string ProtoStubName(const FileDescriptor* proto) {
+  return StripSuffixString(proto->name(), ".proto") + ".pbzero";
+}
+
 class GeneratorJob {
  public:
   GeneratorJob(const FileDescriptor *file,
@@ -102,14 +107,7 @@
     return true;
   }
 
-  void Preprocess() {
-    // Package name maps to a series of namespaces.
-    package_ = source_->package();
-    namespaces_ = Split(package_, ".");
-    full_namespace_prefix_ = "::";
-    for (const std::string& ns : namespaces_)
-      full_namespace_prefix_ += ns + "::";
-
+  void CollectDescriptors() {
     // Collect message descriptors in DFS order.
     std::vector<const Descriptor*> stack;
     for (int i = 0; i < source_->message_type_count(); ++i)
@@ -135,6 +133,74 @@
     }
   }
 
+  void CollectDependencies() {
+    // Public import basically means that callers only need to import this
+    // proto in order to use the stuff publicly imported by this proto.
+    for (int i = 0; i < source_->public_dependency_count(); ++i)
+      public_imports_.insert(source_->public_dependency(i));
+
+    if (source_->weak_dependency_count() > 0)
+      Abort("Weak imports are not supported.");
+
+    // Sanity check. Collect public imports (of collected imports) in DFS order.
+    // Visibilty for current proto:
+    // - all imports listed in current proto,
+    // - public imports of everything imported (recursive).
+    std::vector<const FileDescriptor*> stack;
+    for (int i = 0; i < source_->dependency_count(); ++i) {
+      const FileDescriptor* import = source_->dependency(i);
+      stack.push_back(import);
+      if (public_imports_.count(import) == 0) {
+        private_imports_.insert(import);
+      }
+    }
+
+    while (!stack.empty()) {
+      const FileDescriptor* import = stack.back();
+      stack.pop_back();
+      // Having imports under different packages leads to unnecessary
+      // complexity with namespaces.
+      if (import->package() != package_)
+        Abort("Imported proto must be in the same package.");
+
+      for (int i = 0; i < import->public_dependency_count(); ++i) {
+        stack.push_back(import->public_dependency(i));
+      }
+    }
+
+    // Collect descriptors of messages and enums used in current proto.
+    // It will be used to generate necessary forward declarations and performed
+    // sanity check guarantees that everything lays in the same namespace.
+    for (const Descriptor* message : messages_) {
+      for (int i = 0; i < message->field_count(); ++i) {
+        const FieldDescriptor* field = message->field(i);
+
+        if (field->type() == FieldDescriptor::TYPE_MESSAGE) {
+          if (public_imports_.count(field->message_type()->file()) == 0) {
+            // Avoid multiple forward declarations since
+            // public imports have been already included.
+            referenced_messages_.insert(field->message_type());
+          }
+        } else if (field->type() == FieldDescriptor::TYPE_ENUM) {
+          if (public_imports_.count(field->enum_type()->file()) == 0) {
+            referenced_enums_.insert(field->enum_type());
+          }
+        }
+      }
+    }
+  }
+
+  void Preprocess() {
+    // Package name maps to a series of namespaces.
+    package_ = source_->package();
+    namespaces_ = Split(package_, ".");
+    full_namespace_prefix_ = "::";
+    for (const std::string& ns : namespaces_)
+      full_namespace_prefix_ += ns + "::";
+    CollectDescriptors();
+    CollectDependencies();
+  }
+
   // Print top header, namespaces and forward declarations.
   void GeneratePrologue() {
     std::string greeting =
@@ -151,30 +217,65 @@
         "#define $guard$\n\n"
         "#include <stddef.h>\n"
         "#include <stdint.h>\n\n"
-        "#include \"components/tracing/core/proto_zero_message.h\"\n\n",
+        "#include \"components/tracing/core/proto_zero_message.h\"\n",
         "greeting", greeting,
         "guard", guard);
     stub_cc_->Print(
         "$greeting$\n"
-        "// This file intentionally left blank.\n",
-        "greeting", greeting);
+        "#include \"$name$.h\"\n",
+        "greeting", greeting,
+        "name", ProtoStubName(source_));
+
+    // Print includes for public imports.
+    for (const FileDescriptor* dependency : public_imports_) {
+      // Dependency name could contatin slashes but importing from upper-level
+      // directories is not possible anyway since build system process each
+      // proto file individually. Hence proto lookup path always equal to the
+      // directory where particular proto file is located and protoc does not
+      // allow reference to upper directory (aka ..) in import path.
+      //
+      // Laconically said:
+      // - source_->name() may never have slashes,
+      // - dependency->name() may have slashes but always reffers to inner path.
+      stub_h_->Print(
+          "#include \"$name$.h\"\n",
+          "name", ProtoStubName(dependency));
+    }
+    stub_h_->Print("\n");
+
+    // Print includes for private imports to .cc file.
+    for (const FileDescriptor* dependency : private_imports_) {
+      stub_cc_->Print(
+         "#include \"$name$.h\"\n",
+         "name", ProtoStubName(dependency));
+    }
+    stub_cc_->Print("\n");
 
     // Print namespaces.
-    for (const std::string& ns : namespaces_)
+    for (const std::string& ns : namespaces_) {
       stub_h_->Print("namespace $ns$ {\n", "ns", ns);
+      stub_cc_->Print("namespace $ns$ {\n", "ns", ns);
+    }
     stub_h_->Print("\n");
+    stub_cc_->Print("\n");
+
     // Print forward declarations.
-    for (const Descriptor* message : messages_) {
+    for (const Descriptor* message : referenced_messages_) {
       stub_h_->Print(
           "class $class$;\n",
           "class", GetCppClassName(message));
     }
+    for (const EnumDescriptor* enumeration : referenced_enums_) {
+      stub_h_->Print(
+          "enum $class$ : int32_t;\n",
+          "class", GetCppClassName(enumeration));
+    }
     stub_h_->Print("\n");
   }
 
   void GenerateEnumDescriptor(const EnumDescriptor* enumeration) {
     stub_h_->Print(
-        "enum $class$ {\n",
+        "enum $class$ : int32_t {\n",
         "class", GetCppClassName(enumeration));
     stub_h_->Indent();
 
@@ -302,14 +403,24 @@
   }
 
   void GenerateNestedMessageFieldDescriptor(const FieldDescriptor* field) {
+    std::string action = field->is_repeated() ? "add" : "set";
+    std::string inner_class = GetCppClassName(field->message_type());
+    std::string outer_class = GetCppClassName(field->containing_type());
+
     stub_h_->Print(
-        "$class$* $action$_$name$() {\n"
-        "  return BeginNestedMessage<$class$>($id$);\n"
-        "}\n",
+        "$inner_class$* $action$_$name$();\n",
+        "name", field->name(),
+        "action", action,
+        "inner_class", inner_class);
+    stub_cc_->Print(
+        "$inner_class$* $outer_class$::$action$_$name$() {\n"
+        "  return BeginNestedMessage<$inner_class$>($id$);\n"
+        "}\n\n",
         "id", std::to_string(field->number()),
         "name", field->name(),
-        "action", field->is_repeated() ? "add" : "set",
-        "class", GetCppClassName(field->message_type()));
+        "action", action,
+        "inner_class", inner_class,
+        "outer_class", outer_class);
   }
 
   void GenerateMessageDescriptor(const Descriptor* message) {
@@ -373,6 +484,7 @@
   void GenerateEpilogue() {
     for (unsigned i = 0; i < namespaces_.size(); ++i) {
       stub_h_->Print("} // Namespace.\n");
+      stub_cc_->Print("} // Namespace.\n");
     }
     stub_h_->Print("#endif  // Include guard.\n");
   }
@@ -387,6 +499,11 @@
   std::string full_namespace_prefix_;
   std::vector<const Descriptor*> messages_;
   std::vector<const EnumDescriptor*> enums_;
+
+  std::set<const FileDescriptor*> public_imports_;
+  std::set<const FileDescriptor*> private_imports_;
+  std::set<const Descriptor*> referenced_messages_;
+  std::set<const EnumDescriptor*> referenced_enums_;
 };
 
 }  // namespace
@@ -402,13 +519,10 @@
                                   GeneratorContext* context,
                                   std::string* error) const {
 
-  const std::string proto_stubs_name =
-      StripSuffixString(file->name(), ".proto") + ".pbzero";
-
   const std::unique_ptr<ZeroCopyOutputStream> stub_h_file_stream(
-      context->Open(proto_stubs_name + ".h"));
+      context->Open(ProtoStubName(file) + ".h"));
   const std::unique_ptr<ZeroCopyOutputStream> stub_cc_file_stream(
-      context->Open(proto_stubs_name + ".cc"));
+      context->Open(ProtoStubName(file) + ".cc"));
 
   // Variables are delimited by $.
   Printer stub_h_printer(stub_h_file_stream.get(), '$');
diff --git a/content/app/BUILD.gn b/content/app/BUILD.gn
index 116a1dbe..1c4e913 100644
--- a/content/app/BUILD.gn
+++ b/content/app/BUILD.gn
@@ -15,7 +15,6 @@
   extra_configs = [
     "//build/config/compiler:wexit_time_destructors",
     "//content:content_implementation",
-    "//content/public/common:mojo_shell_client",
     "//v8:external_startup_data",
   ]
 
diff --git a/content/browser/BUILD.gn b/content/browser/BUILD.gn
index ceba43c..e0bc7d1 100644
--- a/content/browser/BUILD.gn
+++ b/content/browser/BUILD.gn
@@ -23,7 +23,6 @@
   configs += [
     "//build/config:precompiled_headers",
     "//content:content_implementation",
-    "//content/public/common:mojo_shell_client",
     "//third_party/WebKit/public:debug_devtools",
     "//v8:external_startup_data",
   ]
diff --git a/content/browser/browser_main_loop.cc b/content/browser/browser_main_loop.cc
index 21c29ee..d7a1f39 100644
--- a/content/browser/browser_main_loop.cc
+++ b/content/browser/browser_main_loop.cc
@@ -277,7 +277,7 @@
 }
 #endif  // defined(USE_GLIB)
 
-#if defined(MOJO_SHELL_CLIENT) && defined(USE_AURA)
+#if defined(USE_AURA)
 void WaitForMojoShellInitialize() {
   // TODO(rockot): Remove this. http://crbug.com/594852.
   base::RunLoop wait_loop;
@@ -285,7 +285,7 @@
       wait_loop.QuitClosure());
   wait_loop.Run();
 }
-#endif  // defined(MOJO_SHELL_CLIENT) && defined(USE_AURA)
+#endif  // defined(USE_AURA)
 
 void OnStoppedStartupTracing(const base::FilePath& trace_file) {
   VLOG(0) << "Completed startup tracing to " << trace_file.value();
@@ -1196,7 +1196,7 @@
           ->task_runner()));
 
   mojo_shell_context_.reset(new MojoShellContext);
-#if defined(MOJO_SHELL_CLIENT) && defined(USE_AURA)
+#if defined(USE_AURA)
   // TODO(rockot): Remove the blocking wait for init.
   // http://crbug.com/594852.
   if (shell::ShellIsRemote() && MojoShellConnection::GetForProcess()) {
@@ -1243,11 +1243,8 @@
   BrowserGpuChannelHostFactory::Initialize(established_gpu_channel);
   ImageTransportFactory::Initialize();
 #if defined(USE_AURA)
-  bool use_mus_in_renderer = false;
-#if defined (MOJO_SHELL_CLIENT)
-  use_mus_in_renderer = base::CommandLine::ForCurrentProcess()->HasSwitch(
+  bool use_mus_in_renderer = base::CommandLine::ForCurrentProcess()->HasSwitch(
       switches::kUseMusInRenderer);
-#endif  // defined(MOJO_SHELL_CLIENT);
   if (aura::Env::GetInstance() && !use_mus_in_renderer) {
     aura::Env::GetInstance()->set_context_factory(GetContextFactory());
   }
diff --git a/content/browser/child_process_launcher.h b/content/browser/child_process_launcher.h
index 6f51a90a..f400f694 100644
--- a/content/browser/child_process_launcher.h
+++ b/content/browser/child_process_launcher.h
@@ -142,15 +142,6 @@
               base::Process process,
               int error_code);
 
-#if defined(MOJO_SHELL_CLIENT)
-  // When this process is run from an external Mojo shell, this function will
-  // create a channel and pass one end to the spawned process and register the
-  // other end with the external shell, allowing the spawned process to bind an
-  // Application request from the shell.
-  void CreateMojoShellChannel(base::CommandLine* command_line,
-                              int child_process_id);
-#endif
-
   Client* client_;
   BrowserThread::ID client_thread_id_;
   base::Process process_;
diff --git a/content/browser/frame_host/navigation_handle_impl.cc b/content/browser/frame_host/navigation_handle_impl.cc
index 0bc1ceb..7857c963 100644
--- a/content/browser/frame_host/navigation_handle_impl.cc
+++ b/content/browser/frame_host/navigation_handle_impl.cc
@@ -206,7 +206,8 @@
 }
 
 const net::HttpResponseHeaders* NavigationHandleImpl::GetResponseHeaders() {
-   return response_headers_.get();
+  DCHECK_GE(state_, WILL_REDIRECT_REQUEST);
+  return response_headers_.get();
 }
 
 bool NavigationHandleImpl::HasCommitted() {
diff --git a/content/browser/frame_host/navigation_handle_impl.h b/content/browser/frame_host/navigation_handle_impl.h
index 264bffa..677a167 100644
--- a/content/browser/frame_host/navigation_handle_impl.h
+++ b/content/browser/frame_host/navigation_handle_impl.h
@@ -98,6 +98,7 @@
   bool IsSamePage() override;
   bool HasCommitted() override;
   bool IsErrorPage() override;
+  const net::HttpResponseHeaders* GetResponseHeaders() override;
   void Resume() override;
   void CancelDeferredNavigation(
       NavigationThrottle::ThrottleCheckResult result) override;
@@ -123,12 +124,6 @@
 
   RequestContextType GetRequestContextType() const;
 
-  // Returns the response headers for the request or nullptr if there are none.
-  // This should only be accessed after a redirect was encountered or after the
-  // navigation is ready to commit. The headers returned should not be modified,
-  // as modifications will not be reflected in the network stack.
-  const net::HttpResponseHeaders* GetResponseHeaders();
-
   // Get the unique id from the NavigationEntry associated with this
   // NavigationHandle. Note that a synchronous, renderer-initiated navigation
   // will not have a NavigationEntry associated with it, and this will return 0.
diff --git a/content/browser/gpu/gpu_data_manager_impl_private.cc b/content/browser/gpu/gpu_data_manager_impl_private.cc
index 4d7367c..7f3ef1a 100644
--- a/content/browser/gpu/gpu_data_manager_impl_private.cc
+++ b/content/browser/gpu/gpu_data_manager_impl_private.cc
@@ -48,10 +48,6 @@
 #if defined(OS_WIN)
 #include "base/win/windows_version.h"
 #endif  // OS_WIN
-#if defined(MOJO_SHELL_CLIENT) && defined(USE_AURA)
-#include "services/shell/runner/common/client_util.h"  // nogncheck
-#include "services/ui/common/gpu_service.h"            // nogncheck
-#endif
 
 namespace content {
 
diff --git a/content/browser/gpu/gpu_process_host.cc b/content/browser/gpu/gpu_process_host.cc
index f394db3..a12b1c6 100644
--- a/content/browser/gpu/gpu_process_host.cc
+++ b/content/browser/gpu/gpu_process_host.cc
@@ -62,6 +62,7 @@
 #include "mojo/edk/embedder/embedder.h"
 #include "services/shell/public/cpp/connection.h"
 #include "services/shell/public/cpp/interface_provider.h"
+#include "services/shell/runner/common/client_util.h"
 #include "ui/base/ui_base_switches.h"
 #include "ui/events/latency_info.h"
 #include "ui/gl/gl_switches.h"
@@ -90,10 +91,6 @@
 #include "content/browser/gpu/gpu_surface_tracker.h"
 #endif
 
-#if defined(MOJO_SHELL_CLIENT)
-#include "services/shell/runner/common/client_util.h"
-#endif
-
 namespace content {
 
 bool GpuProcessHost::gpu_enabled_ = true;
@@ -119,7 +116,6 @@
 #endif
 #if defined(OS_WIN)
     switches::kEnableAcceleratedVpxDecode,
-    switches::kEnableMFH264Encoding,
 #endif
     switches::kEnableHeapProfiling,
     switches::kEnableLogging,
@@ -316,9 +312,7 @@
 
 // static
 GpuProcessHost* GpuProcessHost::Get(GpuProcessKind kind, bool force_create) {
-#if defined(MOJO_SHELL_CLIENT)
   DCHECK(!shell::ShellIsRemote());
-#endif
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
 
   // Don't grant further access to GPU if it is not allowed.
diff --git a/content/browser/media/session/media_session_visibility_browsertest.cc b/content/browser/media/session/media_session_visibility_browsertest.cc
index 659b3c1a..70ddbfbf 100644
--- a/content/browser/media/session/media_session_visibility_browsertest.cc
+++ b/content/browser/media/session/media_session_visibility_browsertest.cc
@@ -63,7 +63,24 @@
     media_session_state_callback_subscription_.reset();
   }
 
+  void EnableDisableResumingBackgroundVideos(bool enable) {
+    std::string enabled_features;
+    std::string disabled_features;
+    if (enable)
+      enabled_features = media::kResumeBackgroundVideo.name;
+    else
+      disabled_features = media::kResumeBackgroundVideo.name;
+
+    std::unique_ptr<base::FeatureList> feature_list(new base::FeatureList);
+    feature_list->InitializeFromCommandLine(
+        enabled_features, disabled_features);
+    base::FeatureList::ClearInstanceForTesting();
+    base::FeatureList::SetInstance(std::move(feature_list));
+  }
+
   void SetUpCommandLine(base::CommandLine* command_line) override {
+    EnableDisableResumingBackgroundVideos(false);
+
     command_line->AppendSwitch(
         switches::kDisableGestureRequirementForMediaPlayback);
 #if !defined(OS_ANDROID)
@@ -149,6 +166,24 @@
     LOG(INFO) << "Test succeeded";
   }
 
+  void TestSessionSuspendedWhenHiddenWhilePlaying() {
+    LoadTestPage();
+
+    LOG(INFO) << "Starting player";
+    ClearMediaSessionStateLoopRunners();
+    RunScript(kStartPlayerScript);
+    LOG(INFO) << "Waiting for Session to be active";
+    WaitForMediaSessionState(MediaSession::State::ACTIVE);
+
+    LOG(INFO) << "Hiding the tab";
+    ClearMediaSessionStateLoopRunners();
+    web_contents_->WasHidden();
+    LOG(INFO) << "Waiting for Session to be suspended";
+    WaitForMediaSessionState(MediaSession::State::SUSPENDED);
+
+    LOG(INFO) << "Test succeeded";
+  }
+
   void TestSessionSuspendedWhenHiddenAfterContentPause() {
     LoadTestPage();
 
@@ -239,6 +274,20 @@
     MediaSessionVisibilityBrowserTest_UnifiedPipeline_SuspendOnHide,
     TestSessionInactiveWhenHiddenWhilePlaying)
 
+IN_PROC_BROWSER_TEST_F(
+    MediaSessionVisibilityBrowserTest_UnifiedPipeline_SuspendOnHide,
+    TestSessionSuspendedWhenHiddenWhilePlaying) {
+  EnableDisableResumingBackgroundVideos(true);
+  TestSessionSuspendedWhenHiddenWhilePlaying();
+}
+
+IN_PROC_BROWSER_TEST_F(
+    MediaSessionVisibilityBrowserTest_UnifiedPipeline_SuspendOnHide,
+    TestSessionSuspendedWhenHiddenAfterContentPause) {
+  EnableDisableResumingBackgroundVideos(true);
+  TestSessionSuspendedWhenHiddenAfterContentPause();
+}
+
 // UnifiedPipeline + NosuspendOnHide
 class MediaSessionVisibilityBrowserTest_UnifiedPipeline_NosuspendOnHide :
       public MediaSessionVisibilityBrowserTest {
@@ -257,6 +306,13 @@
     MediaSessionVisibilityBrowserTest_UnifiedPipeline_NosuspendOnHide,
     TestSessionActiveWhenHiddenWhilePlaying)
 
+IN_PROC_BROWSER_TEST_F(
+    MediaSessionVisibilityBrowserTest_UnifiedPipeline_NosuspendOnHide,
+    TestSessionActiveWhenHiddenWhilePlayingWithResume) {
+  EnableDisableResumingBackgroundVideos(true);
+  TestSessionActiveWhenHiddenWhilePlaying();
+}
+
 #if defined(OS_ANDROID)
 // AndroidPipeline + SuspendOnHide
 class MediaSessionVisibilityBrowserTest_AndroidPipeline_SuspendOnHide :
diff --git a/content/browser/renderer_host/ime_adapter_android.cc b/content/browser/renderer_host/ime_adapter_android.cc
index a712e54..47a060f 100644
--- a/content/browser/renderer_host/ime_adapter_android.cc
+++ b/content/browser/renderer_host/ime_adapter_android.cc
@@ -329,18 +329,6 @@
   return true;
 }
 
-void ImeAdapterAndroid::RequestCursorUpdate(
-    JNIEnv* env,
-    const base::android::JavaParamRef<jobject>& obj,
-    bool immediate_request,
-    bool monitor_request) {
-  RenderWidgetHostImpl* rwhi = GetRenderWidgetHostImpl();
-  if (!rwhi)
-    return;
-  rwhi->Send(new InputMsg_RequestCompositionUpdate(
-      rwhi->GetRoutingID(), immediate_request, monitor_request));
-}
-
 bool ImeAdapterAndroid::IsImeThreadEnabled(
     JNIEnv* env,
     const base::android::JavaParamRef<jobject>&) {
diff --git a/content/browser/renderer_host/ime_adapter_android.h b/content/browser/renderer_host/ime_adapter_android.h
index ea88d543..1f559c6 100644
--- a/content/browser/renderer_host/ime_adapter_android.h
+++ b/content/browser/renderer_host/ime_adapter_android.h
@@ -78,8 +78,6 @@
                              int before,
                              int after);
   void ResetImeAdapter(JNIEnv*, const base::android::JavaParamRef<jobject>&);
-  void RequestCursorUpdate(JNIEnv*, const base::android::JavaParamRef<jobject>&,
-                           bool immediateRequest, bool monitorRequest);
   bool RequestTextInputStateUpdate(JNIEnv*,
                                    const base::android::JavaParamRef<jobject>&);
   bool IsImeThreadEnabled(JNIEnv*, const base::android::JavaParamRef<jobject>&);
diff --git a/content/browser/renderer_host/render_process_host_impl.cc b/content/browser/renderer_host/render_process_host_impl.cc
index 119edec2..394217d4 100644
--- a/content/browser/renderer_host/render_process_host_impl.cc
+++ b/content/browser/renderer_host/render_process_host_impl.cc
@@ -1642,9 +1642,7 @@
     switches::kIpcDumpDirectory,
     switches::kIpcFuzzerTestcase,
 #endif
-#if defined(MOJO_SHELL_CLIENT) && defined(USE_AURA)
     switches::kUseMusInRenderer,
-#endif
   };
   renderer_cmd->CopySwitchesFrom(browser_cmd, kSwitchNames,
                                  arraysize(kSwitchNames));
diff --git a/content/browser/renderer_host/render_widget_host_view_aura.cc b/content/browser/renderer_host/render_widget_host_view_aura.cc
index 3362aec..7286cec3 100644
--- a/content/browser/renderer_host/render_widget_host_view_aura.cc
+++ b/content/browser/renderer_host/render_widget_host_view_aura.cc
@@ -45,7 +45,6 @@
 #include "content/browser/renderer_host/ui_events_helper.h"
 #include "content/browser/renderer_host/web_input_event_aura.h"
 #include "content/common/content_switches_internal.h"
-#include "content/common/input_messages.h"
 #include "content/common/site_isolation_policy.h"
 #include "content/common/text_input_state.h"
 #include "content/common/view_messages.h"
@@ -108,6 +107,7 @@
 #endif
 
 #if defined(OS_LINUX) && !defined(OS_CHROMEOS)
+#include "content/common/input_messages.h"
 #include "ui/base/ime/linux/text_edit_command_auralinux.h"
 #include "ui/base/ime/linux/text_edit_key_bindings_delegate_auralinux.h"
 #endif
@@ -2996,23 +2996,8 @@
   const TextInputState* state = text_input_manager_->GetTextInputState();
 
   if (state && state->show_ime_if_needed &&
-      state->type != ui::TEXT_INPUT_TYPE_NONE) {
+      state->type != ui::TEXT_INPUT_TYPE_NONE)
     GetInputMethod()->ShowImeIfNeeded();
-
-    // Start monitoring the composition information if the focused node is
-    // editable.
-    host_->Send(new InputMsg_RequestCompositionUpdate(
-        host_->GetRoutingID(),
-        false /* immediate request */,
-        true /* monitor request */));
-  } else {
-    // Stop monitoring the composition information if the focused node is not
-    // editable.
-    host_->Send(new InputMsg_RequestCompositionUpdate(
-        host_->GetRoutingID(),
-        false /* immediate request */,
-        false /* monitor request */));
-  }
 }
 
 void RenderWidgetHostViewAura::OnImeCancelComposition(
diff --git a/content/browser/ssl/ssl_manager.cc b/content/browser/ssl/ssl_manager.cc
index ee764be..4526ab3 100644
--- a/content/browser/ssl/ssl_manager.cc
+++ b/content/browser/ssl/ssl_manager.cc
@@ -15,7 +15,6 @@
 #include "content/browser/loader/resource_request_info_impl.h"
 #include "content/browser/ssl/ssl_cert_error_handler.h"
 #include "content/browser/ssl/ssl_policy.h"
-#include "content/browser/ssl/ssl_request_info.h"
 #include "content/browser/web_contents/web_contents_impl.h"
 #include "content/common/ssl_status_serialization.h"
 #include "content/public/browser/browser_context.h"
@@ -144,32 +143,16 @@
 void SSLManager::DidLoadFromMemoryCache(
     const LoadFromMemoryCacheDetails& details) {
   // Simulate loading this resource through the usual path.
-  // Note that we specify SUB_RESOURCE as the resource type as WebCore only
-  // caches sub-resources.
-  // This resource must have been loaded with no filtering because filtered
-  // resouces aren't cachable.
-  scoped_refptr<SSLRequestInfo> info(new SSLRequestInfo(
-      details.url,
-      RESOURCE_TYPE_SUB_RESOURCE,
-      details.cert_id,
-      details.cert_status));
-
-  // Simulate loading this resource through the usual path.
-  policy()->OnRequestStarted(info.get());
+  policy()->OnRequestStarted(details.url, details.cert_id, details.cert_status);
 }
 
 void SSLManager::DidStartResourceResponse(
     const ResourceRequestDetails& details) {
-  scoped_refptr<SSLRequestInfo> info(new SSLRequestInfo(
-      details.url,
-      details.resource_type,
-      details.ssl_cert_id,
-      details.ssl_cert_status));
-
   // Notify our policy that we started a resource request.  Ideally, the
   // policy should have the ability to cancel the request, but we can't do
   // that yet.
-  policy()->OnRequestStarted(info.get());
+  policy()->OnRequestStarted(details.url, details.ssl_cert_id,
+                             details.ssl_cert_status);
 }
 
 void SSLManager::DidReceiveResourceRedirect(
diff --git a/content/browser/ssl/ssl_policy.cc b/content/browser/ssl/ssl_policy.cc
index e710e7c..a45e135 100644
--- a/content/browser/ssl/ssl_policy.cc
+++ b/content/browser/ssl/ssl_policy.cc
@@ -16,7 +16,6 @@
 #include "content/browser/renderer_host/render_view_host_impl.h"
 #include "content/browser/site_instance_impl.h"
 #include "content/browser/ssl/ssl_cert_error_handler.h"
-#include "content/browser/ssl/ssl_request_info.h"
 #include "content/browser/web_contents/web_contents_impl.h"
 #include "content/public/browser/content_browser_client.h"
 #include "content/public/browser/web_contents.h"
@@ -44,7 +43,7 @@
 }
 
 void SSLPolicy::OnCertError(SSLCertErrorHandler* handler) {
-  bool expired_previous_decision;
+  bool expired_previous_decision = false;
   // First we check if we know the policy for this error.
   DCHECK(handler->ssl_info().is_valid());
   SSLHostStateDelegate::CertJudgment judgment =
@@ -118,9 +117,11 @@
                                    site_instance->GetProcess()->GetID());
 }
 
-void SSLPolicy::OnRequestStarted(SSLRequestInfo* info) {
-  if (info->ssl_cert_id() && info->url().SchemeIsCryptographic() &&
-      !net::IsCertStatusError(info->ssl_cert_status())) {
+void SSLPolicy::OnRequestStarted(const GURL& url,
+                                 int cert_id,
+                                 net::CertStatus cert_status) {
+  if (cert_id && url.SchemeIsCryptographic() &&
+      !net::IsCertStatusError(cert_status)) {
     // If the scheme is https: or wss: *and* the security info for the
     // cert has been set (i.e. the cert id is not 0) and the cert did
     // not have any errors, revoke any previous decisions that
@@ -128,11 +129,11 @@
     // isn't known if the connection was actually a valid connection or if it
     // had a cert error.
     SSLGoodCertSeenEvent event = NO_PREVIOUS_EXCEPTION;
-    if (backend_->HasAllowException(info->url().host())) {
+    if (backend_->HasAllowException(url.host())) {
       // If there's no certificate error, a good certificate has been seen, so
       // clear out any exceptions that were made by the user for bad
       // certificates.
-      backend_->RevokeUserAllowExceptions(info->url().host());
+      backend_->RevokeUserAllowExceptions(url.host());
       event = HAD_PREVIOUS_EXCEPTION;
     }
     UMA_HISTOGRAM_ENUMERATION("interstitial.ssl.good_cert_seen", event,
diff --git a/content/browser/ssl/ssl_policy.h b/content/browser/ssl/ssl_policy.h
index a4644ef..8df01a1 100644
--- a/content/browser/ssl/ssl_policy.h
+++ b/content/browser/ssl/ssl_policy.h
@@ -19,7 +19,6 @@
 class NavigationEntryImpl;
 class SSLCertErrorHandler;
 class SSLPolicyBackend;
-class SSLRequestInfo;
 class WebContents;
 
 // SSLPolicy
@@ -38,8 +37,11 @@
   void DidRunInsecureContent(NavigationEntryImpl* entry,
                              const GURL& security_origin);
 
-  // We have started a resource request with the given info.
-  void OnRequestStarted(SSLRequestInfo* info);
+  // We have started a resource request for |url| with the given |cert_id| and
+  // |cert_status|.
+  void OnRequestStarted(const GURL& url,
+                        int cert_id,
+                        net::CertStatus cert_status);
 
   // Update the SSL information in |entry| to match the current state.
   // |web_contents| is the WebContents associated with this entry.
diff --git a/content/browser/ssl/ssl_request_info.cc b/content/browser/ssl/ssl_request_info.cc
deleted file mode 100644
index 4917a0a..0000000
--- a/content/browser/ssl/ssl_request_info.cc
+++ /dev/null
@@ -1,21 +0,0 @@
-// Copyright (c) 2010 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 "content/browser/ssl/ssl_request_info.h"
-
-namespace content {
-
-SSLRequestInfo::SSLRequestInfo(const GURL& url,
-                               ResourceType resource_type,
-                               int ssl_cert_id,
-                               net::CertStatus ssl_cert_status)
-    : url_(url),
-      resource_type_(resource_type),
-      ssl_cert_id_(ssl_cert_id),
-      ssl_cert_status_(ssl_cert_status) {
-}
-
-SSLRequestInfo::~SSLRequestInfo() {}
-
-}  // namespace content
diff --git a/content/browser/ssl/ssl_request_info.h b/content/browser/ssl/ssl_request_info.h
deleted file mode 100644
index f07f0f8..0000000
--- a/content/browser/ssl/ssl_request_info.h
+++ /dev/null
@@ -1,48 +0,0 @@
-// Copyright (c) 2012 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 CONTENT_BROWSER_SSL_SSL_REQUEST_INFO_H_
-#define CONTENT_BROWSER_SSL_SSL_REQUEST_INFO_H_
-
-#include <string>
-
-#include "base/macros.h"
-#include "base/memory/ref_counted.h"
-#include "content/public/common/resource_type.h"
-#include "net/cert/cert_status_flags.h"
-#include "url/gurl.h"
-
-namespace content {
-
-// SSLRequestInfo wraps up the information SSLPolicy needs about a request in
-// order to update our security UI.  SSLRequestInfo is RefCounted in case we
-// need to deal with the request asynchronously.
-class SSLRequestInfo : public base::RefCounted<SSLRequestInfo> {
- public:
-  SSLRequestInfo(const GURL& url,
-                 ResourceType resource_type,
-                 int ssl_cert_id,
-                 net::CertStatus ssl_cert_status);
-
-  const GURL& url() const { return url_; }
-  ResourceType resource_type() const { return resource_type_; }
-  int ssl_cert_id() const { return ssl_cert_id_; }
-  net::CertStatus ssl_cert_status() const { return ssl_cert_status_; }
-
- private:
-  friend class base::RefCounted<SSLRequestInfo>;
-
-  virtual ~SSLRequestInfo();
-
-  GURL url_;
-  ResourceType resource_type_;
-  int ssl_cert_id_;
-  net::CertStatus ssl_cert_status_;
-
-  DISALLOW_COPY_AND_ASSIGN(SSLRequestInfo);
-};
-
-}  // namespace content
-
-#endif  // CONTENT_BROWSER_SSL_SSL_REQUEST_INFO_H_
diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc
index 19d9d26..26e6d0a 100644
--- a/content/browser/web_contents/web_contents_impl.cc
+++ b/content/browser/web_contents/web_contents_impl.cc
@@ -143,7 +143,7 @@
 #include "base/mac/foundation_util.h"
 #endif
 
-#if defined(MOJO_SHELL_CLIENT)
+#if defined(USE_AURA)
 #include "content/browser/web_contents/web_contents_view_mus.h"
 #include "content/public/common/mojo_shell_connection.h"
 #include "ui/aura/mus/mus_util.h"
@@ -1545,7 +1545,7 @@
   WebContentsViewDelegate* delegate =
       GetContentClient()->browser()->GetWebContentsViewDelegate(this);
 
-#if defined(MOJO_SHELL_CLIENT)
+#if defined(USE_AURA)
   if (MojoShellConnection::GetForProcess() &&
       base::CommandLine::ForCurrentProcess()->HasSwitch(
           switches::kUseMusInRenderer)) {
diff --git a/content/browser/webrtc/webrtc_getusermedia_browsertest.cc b/content/browser/webrtc/webrtc_getusermedia_browsertest.cc
index 8899bb4b..8d60451 100644
--- a/content/browser/webrtc/webrtc_getusermedia_browsertest.cc
+++ b/content/browser/webrtc/webrtc_getusermedia_browsertest.cc
@@ -598,13 +598,19 @@
             ExecuteJavascriptAndReturnResult(gum_with_vga_constraints));
 }
 
+#if defined(OS_ANDROID) && defined(NDEBUG)
+#define MAYBE_TraceVideoCaptureControllerPerformanceDuringGetUserMedia DISABLED_TraceVideoCaptureControllerPerformanceDuringGetUserMedia
+#else
+#define MAYBE_TraceVideoCaptureControllerPerformanceDuringGetUserMedia TraceVideoCaptureControllerPerformanceDuringGetUserMedia
+#endif
+
 // This test will make a simple getUserMedia page, verify that video is playing
 // in a simple local <video>, and for a couple of seconds, collect some
 // performance traces from VideoCaptureController colorspace conversion and
 // potential resizing.
 IN_PROC_BROWSER_TEST_F(
     WebRtcGetUserMediaBrowserTest,
-    TraceVideoCaptureControllerPerformanceDuringGetUserMedia) {
+    MAYBE_TraceVideoCaptureControllerPerformanceDuringGetUserMedia) {
   RunGetUserMediaAndCollectMeasures(
       10,
       "VideoCaptureDeviceClient::OnIncomingCapturedData",
diff --git a/content/child/BUILD.gn b/content/child/BUILD.gn
index ad151b5..1466965a 100644
--- a/content/child/BUILD.gn
+++ b/content/child/BUILD.gn
@@ -34,10 +34,7 @@
                         ".",
                         "//content")
 
-  configs += [
-    "//build/config:precompiled_headers",
-    "//content/public/common:mojo_shell_client",
-  ]
+  configs += [ "//build/config:precompiled_headers" ]
 
   public_deps = [
     "//gpu/ipc/client:client",
diff --git a/content/common/input_messages.h b/content/common/input_messages.h
index 5ca7f71..4d3c0ce 100644
--- a/content/common/input_messages.h
+++ b/content/common/input_messages.h
@@ -262,11 +262,6 @@
 IPC_MESSAGE_ROUTED0(InputMsg_RequestTextInputStateUpdate)
 #endif
 
-// Request from browser to update the cursor and composition information.
-IPC_MESSAGE_ROUTED2(InputMsg_RequestCompositionUpdate,
-                    bool /* immediate request */,
-                    bool /* monitor request */)
-
 IPC_MESSAGE_ROUTED0(InputMsg_SyntheticGestureCompleted)
 
 // -----------------------------------------------------------------------------
diff --git a/content/content_browser.gypi b/content/content_browser.gypi
index 5f1c0ed..4fd4b67 100644
--- a/content/content_browser.gypi
+++ b/content/content_browser.gypi
@@ -1475,8 +1475,6 @@
       'browser/ssl/ssl_policy.h',
       'browser/ssl/ssl_policy_backend.cc',
       'browser/ssl/ssl_policy_backend.h',
-      'browser/ssl/ssl_request_info.cc',
-      'browser/ssl/ssl_request_info.h',
       'browser/startup_task_runner.cc',
       'browser/startup_task_runner.h',
       'browser/storage_partition_impl.cc',
diff --git a/content/public/android/java/src/org/chromium/content/browser/input/CursorAnchorInfoController.java b/content/public/android/java/src/org/chromium/content/browser/input/CursorAnchorInfoController.java
index 809f6dd..443e7d2 100644
--- a/content/public/android/java/src/org/chromium/content/browser/input/CursorAnchorInfoController.java
+++ b/content/public/android/java/src/org/chromium/content/browser/input/CursorAnchorInfoController.java
@@ -9,6 +9,7 @@
 import android.os.Build;
 import android.view.View;
 import android.view.inputmethod.CursorAnchorInfo;
+import android.view.inputmethod.InputConnection;
 
 import org.chromium.base.VisibleForTesting;
 import org.chromium.base.annotations.SuppressFBWarnings;
@@ -128,16 +129,14 @@
     /**
      * Sets positional information of composing text as an array of character bounds.
      * @param compositionCharacterBounds Array of character bounds in local coordinates.
-     * @param view The attached view.
      */
-    public void setCompositionCharacterBounds(float[] compositionCharacterBounds, View view) {
+    public void setCompositionCharacterBounds(float[] compositionCharacterBounds) {
         if (!mIsEditable) return;
 
         if (!Arrays.equals(compositionCharacterBounds, mCompositionCharacterBounds)) {
             mLastCursorAnchorInfo = null;
             mCompositionCharacterBounds = compositionCharacterBounds;
         }
-        updateCursorAnchorInfo(view);
     }
 
     /**
@@ -199,6 +198,14 @@
         }
     }
 
+    /**
+     * Resets the current state on update monitoring mode to the default (= do nothing.)
+     */
+    public void resetMonitoringState() {
+        mMonitorModeEnabled = false;
+        mHasPendingImmediateRequest = false;
+    }
+
     public void focusedNodeChanged(boolean isEditable) {
         mIsEditable = isEditable;
         mCompositionCharacterBounds = null;
@@ -206,18 +213,11 @@
         mLastCursorAnchorInfo = null;
     }
 
-    public boolean onRequestCursorUpdates(boolean immediateRequest, boolean monitorRequest,
-            View view) {
+    public boolean onRequestCursorUpdates(int cursorUpdateMode, View view) {
         if (!mIsEditable) return false;
 
-        if (mMonitorModeEnabled && !monitorRequest) {
-            // Invalidate saved cursor anchor info if monitor request is cancelled since no longer
-            // new values will be arrived from renderer and immediate request may return too old
-            // position.
-            invalidateLastCursorAnchorInfo();
-        }
-        mMonitorModeEnabled = monitorRequest;
-        if (immediateRequest) {
+        mMonitorModeEnabled = (cursorUpdateMode & InputConnection.CURSOR_UPDATE_MONITOR) != 0;
+        if ((cursorUpdateMode & InputConnection.CURSOR_UPDATE_IMMEDIATE) != 0) {
             mHasPendingImmediateRequest = true;
             updateCursorAnchorInfo(view);
         }
diff --git a/content/public/android/java/src/org/chromium/content/browser/input/ImeAdapter.java b/content/public/android/java/src/org/chromium/content/browser/input/ImeAdapter.java
index ade6398b..8c1ae7a 100644
--- a/content/public/android/java/src/org/chromium/content/browser/input/ImeAdapter.java
+++ b/content/public/android/java/src/org/chromium/content/browser/input/ImeAdapter.java
@@ -18,7 +18,6 @@
 import android.view.View;
 import android.view.inputmethod.BaseInputConnection;
 import android.view.inputmethod.EditorInfo;
-import android.view.inputmethod.InputConnection;
 
 import org.chromium.base.Log;
 import org.chromium.base.VisibleForTesting;
@@ -193,15 +192,8 @@
                 mViewEmbedder.getAttachedView(), this, mTextInputType, mTextInputFlags,
                 mLastSelectionStart, mLastSelectionEnd, outAttrs));
         if (DEBUG_LOGS) Log.w(TAG, "onCreateInputConnection: " + mInputConnection);
-
         if (mCursorAnchorInfoController != null) {
-            mCursorAnchorInfoController.onRequestCursorUpdates(
-                    false /* not an immediate request */, false /* disable monitoring */,
-                    mViewEmbedder.getAttachedView());
-        }
-        if (mNativeImeAdapterAndroid != 0) {
-            nativeRequestCursorUpdate(mNativeImeAdapterAndroid,
-                    false /* not an immediate request */, false /* disable monitoring */);
+            mCursorAnchorInfoController.resetMonitoringState();
         }
         return mInputConnection;
     }
@@ -682,16 +674,8 @@
      * Notified when IME requested Chrome to change the cursor update mode.
      */
     public boolean onRequestCursorUpdates(int cursorUpdateMode) {
-        final boolean immediateRequest =
-                (cursorUpdateMode & InputConnection.CURSOR_UPDATE_IMMEDIATE) != 0;
-        final boolean monitorRequest =
-                (cursorUpdateMode & InputConnection.CURSOR_UPDATE_MONITOR) != 0;
-
-        if (mNativeImeAdapterAndroid != 0) {
-            nativeRequestCursorUpdate(mNativeImeAdapterAndroid, immediateRequest, monitorRequest);
-        }
         if (mCursorAnchorInfoController == null) return false;
-        return mCursorAnchorInfoController.onRequestCursorUpdates(immediateRequest, monitorRequest,
+        return mCursorAnchorInfoController.onRequestCursorUpdates(cursorUpdateMode,
                 mViewEmbedder.getAttachedView());
     }
 
@@ -747,8 +731,7 @@
     @CalledByNative
     private void setCharacterBounds(float[] characterBounds) {
         if (mCursorAnchorInfoController == null) return;
-        mCursorAnchorInfoController.setCompositionCharacterBounds(characterBounds,
-                mViewEmbedder.getAttachedView());
+        mCursorAnchorInfoController.setCompositionCharacterBounds(characterBounds);
     }
 
     @CalledByNative
@@ -780,7 +763,5 @@
             int before, int after);
     private native void nativeResetImeAdapter(long nativeImeAdapterAndroid);
     private native boolean nativeRequestTextInputStateUpdate(long nativeImeAdapterAndroid);
-    private native void nativeRequestCursorUpdate(long nativeImeAdapterAndroid,
-            boolean immediateRequest, boolean monitorRequest);
     private native boolean nativeIsImeThreadEnabled(long nativeImeAdapterAndroid);
 }
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/input/CursorAnchorInfoControllerTest.java b/content/public/android/javatests/src/org/chromium/content/browser/input/CursorAnchorInfoControllerTest.java
index 2d488aa..768b6bbf 100644
--- a/content/public/android/javatests/src/org/chromium/content/browser/input/CursorAnchorInfoControllerTest.java
+++ b/content/public/android/javatests/src/org/chromium/content/browser/input/CursorAnchorInfoControllerTest.java
@@ -13,6 +13,7 @@
 import android.text.TextUtils;
 import android.view.View;
 import android.view.inputmethod.CursorAnchorInfo;
+import android.view.inputmethod.InputConnection;
 
 import org.chromium.base.test.util.Feature;
 import org.chromium.base.test.util.MinAndroidSdkLevel;
@@ -140,11 +141,10 @@
 
         assertFalse(
                 "IC#onRequestCursorUpdates() must be rejected if the focused node is not editable.",
-                controller.onRequestCursorUpdates(
-                        false /* immediate request */, true /* monitor request */, view));
+                controller.onRequestCursorUpdates(InputConnection.CURSOR_UPDATE_MONITOR, view));
 
         // Make sure that the focused node is considered to be non-editable by default.
-        controller.setCompositionCharacterBounds(new float[] {0.0f, 1.0f, 2.0f, 3.0f}, view);
+        controller.setCompositionCharacterBounds(new float[] {0.0f, 1.0f, 2.0f, 3.0f});
         composingTextDelegate.updateTextAndSelection(controller, "0", 0, 1, 0, 1);
         controller.onUpdateFrameInfo(createRenderCoordinates(1.0f, 0.0f),
                 true, true, 2.0f, 0.0f, 3.0f, view);
@@ -155,7 +155,7 @@
 
         // Make sure that the controller does not crash even if it is called while the focused node
         // is not editable.
-        controller.setCompositionCharacterBounds(new float[] {30.0f, 1.0f, 32.0f, 3.0f}, view);
+        controller.setCompositionCharacterBounds(new float[] {30.0f, 1.0f, 32.0f, 3.0f});
         composingTextDelegate.updateTextAndSelection(controller, "1", 0, 1, 0, 1);
         controller.onUpdateFrameInfo(createRenderCoordinates(1.0f, 100.0f),
                 true, true, 2.0f, 0.0f, 3.0f, view);
@@ -179,9 +179,9 @@
 
         // Make sure that #updateCursorAnchorInfo() is not be called until the matrix info becomes
         // available with #onUpdateFrameInfo().
-        assertTrue(controller.onRequestCursorUpdates(
-                true /* immediate request */, false /* monitor request */, view));
-        controller.setCompositionCharacterBounds(new float[] {0.0f, 1.0f, 2.0f, 3.0f}, view);
+        assertTrue(controller.onRequestCursorUpdates(InputConnection.CURSOR_UPDATE_IMMEDIATE,
+                view));
+        controller.setCompositionCharacterBounds(new float[] {0.0f, 1.0f, 2.0f, 3.0f});
         composingTextDelegate.updateTextAndSelection(controller, "0", 0, 1, 0, 1);
         assertEquals(0, immw.getUpdateCursorAnchorInfoCounter());
         controller.onUpdateFrameInfo(createRenderCoordinates(1.0f, 0.0f),
@@ -205,8 +205,8 @@
 
         // Make sure that #onUpdateFrameInfo() is immediately called because the matrix info is
         // already available.
-        assertTrue(controller.onRequestCursorUpdates(
-                true /* immediate request */, false /* monitor request */, view));
+        assertTrue(controller.onRequestCursorUpdates(InputConnection.CURSOR_UPDATE_IMMEDIATE,
+                view));
         assertEquals(2, immw.getUpdateCursorAnchorInfoCounter());
         assertScaleAndTranslate(2.0f, 0.0f, 0.0f, immw.getLastCursorAnchorInfo());
         assertHasInsertionMarker(CursorAnchorInfo.FLAG_HAS_VISIBLE_REGION, 2.0f, 0.0f, 3.0f,
@@ -222,7 +222,8 @@
         // Make sure that CURSOR_UPDATE_IMMEDIATE and CURSOR_UPDATE_MONITOR can be specified at
         // the same time.
         assertTrue(controller.onRequestCursorUpdates(
-                true /* immediate request*/, true /* monitor request */, view));
+                InputConnection.CURSOR_UPDATE_IMMEDIATE | InputConnection.CURSOR_UPDATE_MONITOR,
+                view));
         assertEquals(3, immw.getUpdateCursorAnchorInfoCounter());
         assertScaleAndTranslate(2.0f, 0.0f, 0.0f, immw.getLastCursorAnchorInfo());
         immw.clearLastCursorAnchorInfo();
@@ -245,8 +246,8 @@
         controller.focusedNodeChanged(false);
         controller.focusedNodeChanged(true);
         composingTextDelegate.clearTextAndSelection(controller);
-        assertTrue(controller.onRequestCursorUpdates(
-                true /* immediate request */, false /* monitor request */, view));
+        assertTrue(controller.onRequestCursorUpdates(InputConnection.CURSOR_UPDATE_IMMEDIATE,
+                view));
         controller.focusedNodeChanged(false);
         composingTextDelegate.clearTextAndSelection(controller);
         controller.onUpdateFrameInfo(createRenderCoordinates(1.0f, 100.0f),
@@ -256,8 +257,8 @@
         // Make sure that CURSOR_UPDATE_IMMEDIATE can be enabled again.
         controller.focusedNodeChanged(true);
         composingTextDelegate.clearTextAndSelection(controller);
-        assertTrue(controller.onRequestCursorUpdates(
-                true /* immediate request */, false /* monitor request */, view));
+        assertTrue(controller.onRequestCursorUpdates(InputConnection.CURSOR_UPDATE_IMMEDIATE,
+                view));
         controller.onUpdateFrameInfo(createRenderCoordinates(1.0f, 0.0f),
                 true, true, 2.0f, 0.0f, 3.0f, view);
         assertEquals(5, immw.getUpdateCursorAnchorInfoCounter());
@@ -288,9 +289,8 @@
 
         // Make sure that #updateCursorAnchorInfo() is not be called until the matrix info becomes
         // available with #onUpdateFrameInfo().
-        assertTrue(controller.onRequestCursorUpdates(
-                false /* immediate request */, true /* monitor request */, view));
-        controller.setCompositionCharacterBounds(new float[] {0.0f, 1.0f, 2.0f, 3.0f}, view);
+        assertTrue(controller.onRequestCursorUpdates(InputConnection.CURSOR_UPDATE_MONITOR, view));
+        controller.setCompositionCharacterBounds(new float[] {0.0f, 1.0f, 2.0f, 3.0f});
         composingTextDelegate.updateTextAndSelection(controller, "0", 0, 1, 0, 1);
         assertEquals(0, immw.getUpdateCursorAnchorInfoCounter());
         controller.onUpdateFrameInfo(createRenderCoordinates(1.0f, 0.0f),
@@ -309,14 +309,14 @@
 
         // Make sure that #updateCursorAnchorInfo() is not be called if any coordinate parameter is
         // changed for better performance.
-        controller.setCompositionCharacterBounds(new float[] {0.0f, 1.0f, 2.0f, 3.0f}, view);
+        controller.setCompositionCharacterBounds(new float[] {0.0f, 1.0f, 2.0f, 3.0f});
         controller.onUpdateFrameInfo(createRenderCoordinates(1.0f, 0.0f),
                 true, true, 2.0f, 0.0f, 3.0f, view);
         assertEquals(1, immw.getUpdateCursorAnchorInfoCounter());
 
         // Make sure that #updateCursorAnchorInfo() is called if #setCompositionCharacterBounds()
         // is called with a different parameter.
-        controller.setCompositionCharacterBounds(new float[] {30.0f, 1.0f, 32.0f, 3.0f}, view);
+        controller.setCompositionCharacterBounds(new float[] {30.0f, 1.0f, 32.0f, 3.0f});
         assertEquals(1, immw.getUpdateCursorAnchorInfoCounter());
         controller.onUpdateFrameInfo(createRenderCoordinates(1.0f, 0.0f),
                 true, true, 2.0f, 0.0f, 3.0f, view);
@@ -388,11 +388,10 @@
         controller.focusedNodeChanged(false);
         controller.focusedNodeChanged(true);
         composingTextDelegate.clearTextAndSelection(controller);
-        assertTrue(controller.onRequestCursorUpdates(
-                false /* immediate request */, true /* monitor request */, view));
+        assertTrue(controller.onRequestCursorUpdates(InputConnection.CURSOR_UPDATE_MONITOR, view));
         controller.focusedNodeChanged(false);
         composingTextDelegate.clearTextAndSelection(controller);
-        controller.setCompositionCharacterBounds(new float[] {0.0f, 1.0f, 2.0f, 3.0f}, view);
+        controller.setCompositionCharacterBounds(new float[] {0.0f, 1.0f, 2.0f, 3.0f});
         composingTextDelegate.updateTextAndSelection(controller, "0", 0, 1, 0, 1);
         controller.onUpdateFrameInfo(createRenderCoordinates(1.0f, 0.0f),
                 true, true, 2.0f, 0.0f, 3.0f, view);
@@ -401,9 +400,8 @@
         // Make sure that CURSOR_UPDATE_MONITOR can be enabled again.
         controller.focusedNodeChanged(true);
         composingTextDelegate.clearTextAndSelection(controller);
-        assertTrue(controller.onRequestCursorUpdates(
-                false /* immediate request */, true /* monitor request */, view));
-        controller.setCompositionCharacterBounds(new float[] {0.0f, 1.0f, 2.0f, 3.0f}, view);
+        assertTrue(controller.onRequestCursorUpdates(InputConnection.CURSOR_UPDATE_MONITOR, view));
+        controller.setCompositionCharacterBounds(new float[] {0.0f, 1.0f, 2.0f, 3.0f});
         composingTextDelegate.updateTextAndSelection(controller, "0", 0, 1, 0, 1);
         assertEquals(5, immw.getUpdateCursorAnchorInfoCounter());
         viewDelegate.locationX = 0;
@@ -438,12 +436,11 @@
 
         controller.focusedNodeChanged(true);
         composingTextDelegate.clearTextAndSelection(controller);
-        assertTrue(controller.onRequestCursorUpdates(
-                false /* immediate request */, true /* monitor request */, view));
+        assertTrue(controller.onRequestCursorUpdates(InputConnection.CURSOR_UPDATE_MONITOR, view));
 
         composingTextDelegate.updateTextAndSelection(controller, "01234", 1, 3, 1, 1);
         controller.setCompositionCharacterBounds(new float[] {0.0f, 1.0f, 2.0f, 3.0f,
-                4.0f, 1.1f, 6.0f, 2.9f}, view);
+                4.0f, 1.1f, 6.0f, 2.9f});
         controller.onUpdateFrameInfo(createRenderCoordinates(1.0f, 0.0f),
                 false, false, Float.NaN, Float.NaN, Float.NaN, view);
         assertEquals(1, immw.getUpdateCursorAnchorInfoCounter());
@@ -478,8 +475,7 @@
 
         controller.focusedNodeChanged(true);
         composingTextDelegate.clearTextAndSelection(controller);
-        assertTrue(controller.onRequestCursorUpdates(
-                false /* immediate request */, true /* monitor request */, view));
+        assertTrue(controller.onRequestCursorUpdates(InputConnection.CURSOR_UPDATE_MONITOR, view));
 
         composingTextDelegate.updateTextAndSelection(controller, "01234", 3, 3, 1, 1);
         controller.onUpdateFrameInfo(createRenderCoordinates(1.0f, 0.0f),
@@ -511,8 +507,7 @@
 
         controller.focusedNodeChanged(true);
         composingTextDelegate.clearTextAndSelection(controller);
-        assertTrue(controller.onRequestCursorUpdates(
-                false /* immediate request */, true /* monitor request */, view));
+        assertTrue(controller.onRequestCursorUpdates(InputConnection.CURSOR_UPDATE_MONITOR, view));
 
         // Test no insertion marker.
         controller.onUpdateFrameInfo(createRenderCoordinates(1.0f, 0.0f),
@@ -550,8 +545,7 @@
 
         controller.focusedNodeChanged(true);
         composingTextDelegate.clearTextAndSelection(controller);
-        assertTrue(controller.onRequestCursorUpdates(
-                false /* immediate request */, true /* monitor request */, view));
+        assertTrue(controller.onRequestCursorUpdates(InputConnection.CURSOR_UPDATE_MONITOR, view));
 
         // Test no transformation
         viewDelegate.locationX = 0;
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/input/ImeLollipopTest.java b/content/public/android/javatests/src/org/chromium/content/browser/input/ImeLollipopTest.java
index 26c51cb5..159d73a5 100644
--- a/content/public/android/javatests/src/org/chromium/content/browser/input/ImeLollipopTest.java
+++ b/content/public/android/javatests/src/org/chromium/content/browser/input/ImeLollipopTest.java
@@ -58,10 +58,6 @@
         });
         requestCursorUpdates(InputConnection.CURSOR_UPDATE_IMMEDIATE);
         waitForUpdateCursorAnchorInfoComposingText("abcd");
-
-        setComposingText("abcde", 2);
-        requestCursorUpdates(InputConnection.CURSOR_UPDATE_IMMEDIATE);
-        waitForUpdateCursorAnchorInfoComposingText("abcde");
     }
 
     private void requestCursorUpdates(final int cursorUpdateMode) {
diff --git a/content/public/browser/navigation_handle.h b/content/public/browser/navigation_handle.h
index ff190a7..007cd9d 100644
--- a/content/public/browser/navigation_handle.h
+++ b/content/public/browser/navigation_handle.h
@@ -15,6 +15,10 @@
 
 class GURL;
 
+namespace net {
+class HttpResponseHeaders;
+}  // namespace net
+
 namespace content {
 class NavigationData;
 class NavigationThrottle;
@@ -150,6 +154,12 @@
   // Whether the navigation resulted in an error page.
   virtual bool IsErrorPage() = 0;
 
+  // Returns the response headers for the request or nullptr if there are none.
+  // This should only be accessed after a redirect was encountered or after the
+  // navigation is ready to commit. The headers returned should not be modified,
+  // as modifications will not be reflected in the network stack.
+  virtual const net::HttpResponseHeaders* GetResponseHeaders() = 0;
+
   // Resumes a navigation that was previously deferred by a NavigationThrottle.
   virtual void Resume() = 0;
 
diff --git a/content/public/common/BUILD.gn b/content/public/common/BUILD.gn
index d3b05edf..2df12fd 100644
--- a/content/public/common/BUILD.gn
+++ b/content/public/common/BUILD.gn
@@ -53,15 +53,6 @@
   defines = [ "COMPILE_CONTENT_STATICALLY" ]
 }
 
-# Set in GN builds, triggering behavior in content when run from an external
-# Mojo shell.
-config("mojo_shell_client") {
-  # This configuration has only been tested on these platforms.
-  if ((is_win || is_linux || is_chromeos) && !is_chromecast) {
-    defines = [ "MOJO_SHELL_CLIENT" ]
-  }
-}
-
 # This target allows you to use the content_switches constants and statically
 # link to it, without depending on the rest of content. This is only for use
 # without content, or you will get multiply defined symbols.
diff --git a/content/renderer/BUILD.gn b/content/renderer/BUILD.gn
index c1778f7..a25ec7c 100644
--- a/content/renderer/BUILD.gn
+++ b/content/renderer/BUILD.gn
@@ -29,7 +29,6 @@
   configs += [
     "//content:content_implementation",
     "//build/config/compiler:no_size_t_to_int_warning",
-    "//content/public/common:mojo_shell_client",
   ]
   defines = []
 
diff --git a/content/renderer/android/synchronous_compositor_output_surface.h b/content/renderer/android/synchronous_compositor_output_surface.h
index 6a8f83a2..de8f1f0f 100644
--- a/content/renderer/android/synchronous_compositor_output_surface.h
+++ b/content/renderer/android/synchronous_compositor_output_surface.h
@@ -143,6 +143,10 @@
     void DisplayOutputSurfaceLost() override {}
     void DisplaySetMemoryPolicy(
         const cc::ManagedMemoryPolicy& policy) override {}
+    void DisplayWillDrawAndSwap(
+        bool will_draw_and_swap,
+        const cc::RenderPassList& render_passes) override {}
+    void DisplayDidDrawAndSwap() override {}
   };
 
   // TODO(danakj): These don't to be stored in unique_ptrs when OutputSurface
diff --git a/content/renderer/gpu/render_widget_compositor_unittest.cc b/content/renderer/gpu/render_widget_compositor_unittest.cc
index 47c1e21..3246db3 100644
--- a/content/renderer/gpu/render_widget_compositor_unittest.cc
+++ b/content/renderer/gpu/render_widget_compositor_unittest.cc
@@ -14,14 +14,16 @@
 #include "base/threading/thread_task_runner_handle.h"
 #include "cc/output/begin_frame_args.h"
 #include "cc/output/copy_output_request.h"
-#include "cc/test/failure_output_surface.h"
 #include "cc/test/fake_external_begin_frame_source.h"
+#include "cc/test/fake_output_surface.h"
+#include "cc/test/test_context_provider.h"
 #include "cc/trees/layer_tree_host.h"
 #include "components/scheduler/renderer/renderer_scheduler.h"
 #include "content/public/test/mock_render_thread.h"
 #include "content/renderer/render_widget.h"
 #include "content/test/fake_compositor_dependencies.h"
 #include "content/test/fake_renderer_scheduler.h"
+#include "gpu/GLES2/gl2extchromium.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/WebKit/public/platform/WebScreenInfo.h"
@@ -80,18 +82,20 @@
             RenderWidgetCompositor::OUTPUT_SURFACE_RETRIES_BEFORE_FALLBACK,
         fallback);
     last_create_was_fallback_ = fallback;
+
     bool success = num_failures_ >= num_failures_before_success_;
-    if (success) {
-      std::unique_ptr<cc::TestWebGraphicsContext3D> context =
-          cc::TestWebGraphicsContext3D::Create();
-      // Image support required for synchronous compositing.
-      context->set_support_image(true);
-      // Create delegating surface so that max_pending_frames = 1.
-      return cc::FakeOutputSurface::CreateDelegating3d(std::move(context));
+    if (!success && use_null_output_surface_)
+      return nullptr;
+
+    auto context_provider = cc::TestContextProvider::Create();
+    if (!success) {
+      context_provider->UnboundTestContext3d()->loseContextCHROMIUM(
+          GL_GUILTY_CONTEXT_RESET_ARB, GL_INNOCENT_CONTEXT_RESET_ARB);
     }
-    return use_null_output_surface_
-               ? nullptr
-               : base::WrapUnique(new cc::FailureOutputSurface(true));
+
+    // Create delegating surface so that max_pending_frames = 1.
+    return cc::FakeOutputSurface::CreateDelegating3d(
+        std::move(context_provider));
   }
 
   std::unique_ptr<cc::BeginFrameSource> CreateExternalBeginFrameSource()
diff --git a/content/renderer/media/android/webmediaplayer_android.cc b/content/renderer/media/android/webmediaplayer_android.cc
index 8dd8323..451ba42 100644
--- a/content/renderer/media/android/webmediaplayer_android.cc
+++ b/content/renderer/media/android/webmediaplayer_android.cc
@@ -374,11 +374,16 @@
 void WebMediaPlayerAndroid::play() {
   DCHECK(main_thread_checker_.CalledOnValidThread());
 
-  if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
-          switches::kDisableMediaSuspend) &&
-      hasVideo() && player_manager_->render_frame()->IsHidden()) {
-    is_play_pending_ = true;
-    return;
+  if (hasVideo() && player_manager_->render_frame()->IsHidden()) {
+    bool can_video_play_in_background =
+        base::CommandLine::ForCurrentProcess()->HasSwitch(
+            switches::kDisableMediaSuspend) ||
+        (IsBackgroundVideoCandidate() &&
+            delegate_ && delegate_->IsPlayingBackgroundVideo());
+    if (!can_video_play_in_background) {
+      is_play_pending_ = true;
+      return;
+    }
   }
   is_play_pending_ = false;
 
@@ -1511,6 +1516,13 @@
 }
 
 void WebMediaPlayerAndroid::OnHidden() {
+  // Pause audible video preserving its session.
+  if (hasVideo() && IsBackgroundVideoCandidate() && !paused()) {
+    Pause(false);
+    is_play_pending_ = true;
+    return;
+  }
+
   OnSuspendRequested(false);
 }
 
@@ -1528,8 +1540,10 @@
 
   // If we're idle or playing video, pause and release resources; audio only
   // players are allowed to continue unless indicated otherwise by the call.
-  if (must_suspend || (paused() && playback_completed_) || hasVideo())
+  if (must_suspend || (paused() && playback_completed_) ||
+      (hasVideo() && !IsBackgroundVideoCandidate())) {
     SuspendAndReleaseResources();
+  }
 }
 
 void WebMediaPlayerAndroid::OnPlay() {
@@ -1683,4 +1697,16 @@
       result, PREDICTION_RESULT_MAX);
 }
 
+bool WebMediaPlayerAndroid::IsBackgroundVideoCandidate() const {
+  DCHECK(hasVideo());
+
+  if (base::CommandLine::ForCurrentProcess()->HasSwitch(
+          switches::kDisableMediaSuspend)) {
+    return false;
+  }
+
+  return base::FeatureList::IsEnabled(media::kResumeBackgroundVideo) &&
+      hasAudio() && !isRemote() && delegate_ && delegate_->IsHidden();
+}
+
 }  // namespace content
diff --git a/content/renderer/media/android/webmediaplayer_android.h b/content/renderer/media/android/webmediaplayer_android.h
index 7eef73e..77e1b7d 100644
--- a/content/renderer/media/android/webmediaplayer_android.h
+++ b/content/renderer/media/android/webmediaplayer_android.h
@@ -324,6 +324,9 @@
   // |defer_load_cb_| is null this is called immediately.
   void DoLoad(LoadType load_type, const blink::WebURL& url, CORSMode cors_mode);
 
+  // Returns if this video can be resumed in the background.
+  bool IsBackgroundVideoCandidate() const;
+
   blink::WebFrame* const frame_;
 
   blink::WebMediaPlayerClient* const client_;
diff --git a/content/renderer/media/renderer_webmediaplayer_delegate.cc b/content/renderer/media/renderer_webmediaplayer_delegate.cc
index f3b8125..24dc39d 100644
--- a/content/renderer/media/renderer_webmediaplayer_delegate.cc
+++ b/content/renderer/media/renderer_webmediaplayer_delegate.cc
@@ -32,6 +32,7 @@
   DCHECK(id_map_.Lookup(delegate_id));
   id_map_.Remove(delegate_id);
   RemoveIdleDelegate(delegate_id);
+  playing_videos_.erase(delegate_id);
 }
 
 void RendererWebMediaPlayerDelegate::DidPlay(int delegate_id,
@@ -41,6 +42,10 @@
                                              base::TimeDelta duration) {
   DCHECK(id_map_.Lookup(delegate_id));
   has_played_media_ = true;
+  if (has_video && !is_remote)
+    playing_videos_.insert(delegate_id);
+  else
+    playing_videos_.erase(delegate_id);
   RemoveIdleDelegate(delegate_id);
   Send(new MediaPlayerDelegateHostMsg_OnMediaPlaying(
       routing_id(), delegate_id, has_video, has_audio, is_remote, duration));
@@ -50,6 +55,8 @@
                                               bool reached_end_of_stream) {
   DCHECK(id_map_.Lookup(delegate_id));
   AddIdleDelegate(delegate_id);
+  if (reached_end_of_stream)
+    playing_videos_.erase(delegate_id);
   Send(new MediaPlayerDelegateHostMsg_OnMediaPaused(routing_id(), delegate_id,
                                                     reached_end_of_stream));
 }
@@ -57,6 +64,7 @@
 void RendererWebMediaPlayerDelegate::PlayerGone(int delegate_id) {
   DCHECK(id_map_.Lookup(delegate_id));
   RemoveIdleDelegate(delegate_id);
+  playing_videos_.erase(delegate_id);
   Send(new MediaPlayerDelegateHostMsg_OnMediaDestroyed(routing_id(),
                                                        delegate_id));
 }
@@ -65,12 +73,17 @@
   return render_frame()->IsHidden();
 }
 
+bool RendererWebMediaPlayerDelegate::IsPlayingBackgroundVideo() {
+  return is_playing_background_video_;
+}
+
 void RendererWebMediaPlayerDelegate::WasHidden() {
   for (IDMap<Observer>::iterator it(&id_map_); !it.IsAtEnd(); it.Advance())
     it.GetCurrentValue()->OnHidden();
 }
 
 void RendererWebMediaPlayerDelegate::WasShown() {
+  is_playing_background_video_ = false;
   for (IDMap<Observer>::iterator it(&id_map_); !it.IsAtEnd(); it.Advance())
     it.GetCurrentValue()->OnShown();
 }
@@ -100,14 +113,20 @@
 
 void RendererWebMediaPlayerDelegate::OnMediaDelegatePause(int delegate_id) {
   Observer* observer = id_map_.Lookup(delegate_id);
-  if (observer)
+  if (observer) {
+    if (playing_videos_.find(delegate_id) != playing_videos_.end())
+      is_playing_background_video_ = false;
     observer->OnPause();
+  }
 }
 
 void RendererWebMediaPlayerDelegate::OnMediaDelegatePlay(int delegate_id) {
   Observer* observer = id_map_.Lookup(delegate_id);
-  if (observer)
+  if (observer) {
+    if (playing_videos_.find(delegate_id) != playing_videos_.end())
+      is_playing_background_video_ = IsHidden();
     observer->OnPlay();
+  }
 }
 
 void RendererWebMediaPlayerDelegate::OnMediaDelegateSuspendAllMediaPlayers() {
diff --git a/content/renderer/media/renderer_webmediaplayer_delegate.h b/content/renderer/media/renderer_webmediaplayer_delegate.h
index 0e830774..f8c8563d 100644
--- a/content/renderer/media/renderer_webmediaplayer_delegate.h
+++ b/content/renderer/media/renderer_webmediaplayer_delegate.h
@@ -7,6 +7,7 @@
 
 #include <map>
 #include <memory>
+#include <set>
 
 #include "base/id_map.h"
 #include "base/macros.h"
@@ -48,6 +49,7 @@
   void DidPause(int delegate_id, bool reached_end_of_stream) override;
   void PlayerGone(int delegate_id) override;
   bool IsHidden() override;
+  bool IsPlayingBackgroundVideo() override;
 
   // content::RenderFrameObserver overrides.
   void WasHidden() override;
@@ -64,6 +66,8 @@
     return idle_cleanup_timer_.IsRunning();
   }
 
+  friend class RendererWebMediaPlayerDelegateTest;
+
  private:
   void OnMediaDelegatePause(int delegate_id);
   void OnMediaDelegatePlay(int delegate_id);
@@ -101,6 +105,16 @@
   std::unique_ptr<base::DefaultTickClock> default_tick_clock_;
   base::TickClock* tick_clock_;
 
+  // If a video is playing in the background. Set when user resumes a video
+  // allowing it to play and reset when either user pauses it or it goes
+  // foreground.
+  bool is_playing_background_video_ = false;
+
+  // The currently playing local videos. Used to determine whether
+  // OnMediaDelegatePlay() should allow the videos to play in the background or
+  // not.
+  std::set<int> playing_videos_;
+
   DISALLOW_COPY_AND_ASSIGN(RendererWebMediaPlayerDelegate);
 };
 
diff --git a/content/renderer/media/renderer_webmediaplayer_delegate_browsertest.cc b/content/renderer/media/renderer_webmediaplayer_delegate_browsertest.cc
index 4fe4fdb..060f391c 100644
--- a/content/renderer/media/renderer_webmediaplayer_delegate_browsertest.cc
+++ b/content/renderer/media/renderer_webmediaplayer_delegate_browsertest.cc
@@ -61,6 +61,22 @@
  protected:
   IPC::TestSink& test_sink() { return render_thread_->sink(); }
 
+  bool HasPlayingVideo(int delegate_id) {
+    return delegate_manager_->playing_videos_.count(delegate_id);
+  }
+
+  void SetPlayingBackgroundVideo(bool is_playing) {
+    delegate_manager_->is_playing_background_video_ = is_playing;
+  }
+
+  void CallOnMediaDelegatePlay(int delegate_id) {
+    delegate_manager_->OnMediaDelegatePlay(delegate_id);
+  }
+
+  void CallOnMediaDelegatePause(int delegate_id) {
+    delegate_manager_->OnMediaDelegatePause(delegate_id);
+  }
+
   std::unique_ptr<RendererWebMediaPlayerDelegate> delegate_manager_;
 
  private:
@@ -271,4 +287,84 @@
   delegate_manager_->RemoveObserver(delegate_id_1);
 }
 
+TEST_F(RendererWebMediaPlayerDelegateTest, PlayingVideosSet) {
+  MockWebMediaPlayerDelegateObserver observer;
+  int delegate_id = delegate_manager_->AddObserver(&observer);
+  EXPECT_FALSE(HasPlayingVideo(delegate_id));
+
+  // Playing a local video adds it to the set.
+  delegate_manager_->DidPlay(delegate_id, true, true, false, base::TimeDelta());
+  EXPECT_TRUE(HasPlayingVideo(delegate_id));
+
+  // Pause doesn't remove the video from the set.
+  delegate_manager_->DidPause(delegate_id, false);
+  EXPECT_TRUE(HasPlayingVideo(delegate_id));
+
+  // Reaching the end removes the video from the set.
+  delegate_manager_->DidPause(delegate_id, true);
+  EXPECT_FALSE(HasPlayingVideo(delegate_id));
+
+  // Removing the player removes the video from the set.
+  delegate_manager_->DidPlay(delegate_id, true, true, false, base::TimeDelta());
+  delegate_manager_->PlayerGone(delegate_id);
+  EXPECT_FALSE(HasPlayingVideo(delegate_id));
+
+  // Playing a remote video removes it from the set.
+  delegate_manager_->DidPlay(delegate_id, true, true, false, base::TimeDelta());
+  delegate_manager_->DidPlay(delegate_id, true, true, true, base::TimeDelta());
+  EXPECT_FALSE(HasPlayingVideo(delegate_id));
+
+  // Playing a local video without audio adds it to the set (because of WMPA).
+  delegate_manager_->DidPlay(
+      delegate_id, true, false, false, base::TimeDelta());
+  EXPECT_TRUE(HasPlayingVideo(delegate_id));
+
+  // Playing a local audio removes it from the set.
+  delegate_manager_->DidPlay(
+      delegate_id, false, true, false, base::TimeDelta());
+  EXPECT_FALSE(HasPlayingVideo(delegate_id));
+
+  // Removing the observer also removes the video from the set.
+  delegate_manager_->DidPlay(delegate_id, true, true, false, base::TimeDelta());
+  delegate_manager_->RemoveObserver(delegate_id);
+  EXPECT_FALSE(HasPlayingVideo(delegate_id));
+}
+
+TEST_F(RendererWebMediaPlayerDelegateTest, IsPlayingBackgroundVideo) {
+  MockWebMediaPlayerDelegateObserver observer;
+  int delegate_id = delegate_manager_->AddObserver(&observer);
+  EXPECT_FALSE(delegate_manager_->IsPlayingBackgroundVideo());
+
+  // Showing the frame always clears the flag.
+  SetPlayingBackgroundVideo(true);
+  delegate_manager_->WasShown();
+  EXPECT_FALSE(delegate_manager_->IsPlayingBackgroundVideo());
+
+  // Pausing anything other than a local playing video doesn't affect the flag.
+  SetPlayingBackgroundVideo(true);
+  CallOnMediaDelegatePause(delegate_id);
+  EXPECT_TRUE(delegate_manager_->IsPlayingBackgroundVideo());
+
+  // Pausing a currently playing video does clears the flag.
+  delegate_manager_->DidPlay(
+      delegate_id, true, true, false, base::TimeDelta());
+  CallOnMediaDelegatePause(delegate_id);
+  EXPECT_FALSE(delegate_manager_->IsPlayingBackgroundVideo());
+
+  // TODO(avayvod): this test can't mock IsHidden() method.
+  // Just test that the value changes or doesn't depending on whether the video
+  // is currently playing.
+  bool old_value = !delegate_manager_->IsHidden();
+  SetPlayingBackgroundVideo(old_value);
+  delegate_manager_->DidPause(delegate_id, true);
+  CallOnMediaDelegatePlay(delegate_id);
+  EXPECT_EQ(old_value, delegate_manager_->IsPlayingBackgroundVideo());
+
+  delegate_manager_->DidPlay(
+      delegate_id, true, true, false, base::TimeDelta());
+  CallOnMediaDelegatePlay(delegate_id);
+  EXPECT_NE(old_value, delegate_manager_->IsPlayingBackgroundVideo());
+}
+
+
 }  // namespace media
diff --git a/content/renderer/media/webmediaplayer_ms_unittest.cc b/content/renderer/media/webmediaplayer_ms_unittest.cc
index 41f76bd..f27ff46 100644
--- a/content/renderer/media/webmediaplayer_ms_unittest.cc
+++ b/content/renderer/media/webmediaplayer_ms_unittest.cc
@@ -76,6 +76,8 @@
 
   bool IsHidden() override { return is_hidden_; }
 
+  bool IsPlayingBackgroundVideo() override { return false; }
+
   void set_hidden(bool is_hidden) { is_hidden_ = is_hidden; }
 
  private:
diff --git a/content/renderer/render_frame_impl.cc b/content/renderer/render_frame_impl.cc
index e52952d0..3bd70a5 100644
--- a/content/renderer/render_frame_impl.cc
+++ b/content/renderer/render_frame_impl.cc
@@ -1313,8 +1313,7 @@
     return;
   Send(new InputHostMsg_ImeCancelComposition(render_view_->GetRoutingID()));
 #if defined(OS_MACOSX) || defined(USE_AURA)
-  GetRenderWidget()->UpdateCompositionInfo(
-      false /* not an immediate request */);
+  GetRenderWidget()->UpdateCompositionInfo(true);
 #endif
 }
 
diff --git a/content/renderer/render_thread_impl.cc b/content/renderer/render_thread_impl.cc
index 3cedbac5..830fd3d6 100644
--- a/content/renderer/render_thread_impl.cc
+++ b/content/renderer/render_thread_impl.cc
@@ -200,7 +200,7 @@
 #include "v8/src/third_party/vtune/v8-vtune.h"
 #endif
 
-#if defined(MOJO_SHELL_CLIENT) && defined(USE_AURA)
+#if defined(USE_AURA)
 #include "content/public/common/mojo_shell_connection.h"
 #include "content/renderer/mus/render_widget_mus_connection.h"
 #include "content/renderer/mus/render_widget_window_tree_client_factory.h"
@@ -642,9 +642,10 @@
   // Register this object as the main thread.
   ChildProcess::current()->set_main_thread(this);
 
-#if defined(MOJO_SHELL_CLIENT)
+#if defined(USE_AURA)
   if (IsRunningInMash())
-    ui::GpuService::Initialize(GetMojoShellConnection()->GetConnector());
+    gpu_service_ =
+        ui::GpuService::Initialize(GetMojoShellConnection()->GetConnector());
 #endif
 
   InitializeWebKit(resource_task_queue);
@@ -718,7 +719,7 @@
 
   AddFilter((new ServiceWorkerContextMessageFilter())->GetFilter());
 
-#if defined(MOJO_SHELL_CLIENT) && defined(USE_AURA)
+#if defined(USE_AURA)
   if (base::CommandLine::ForCurrentProcess()->HasSwitch(
           switches::kUseMusInRenderer)) {
     CreateRenderWidgetWindowTreeClientFactory(GetMojoShellConnection());
@@ -1802,8 +1803,8 @@
                                     ChildProcess::current()->GetShutDownEvent(),
                                     gpu_memory_buffer_manager());
   } else {
-#if defined(MOJO_SHELL_CLIENT) && defined(USE_AURA)
-    gpu_channel_ = ui::GpuService::GetInstance()->EstablishGpuChannelSync();
+#if defined(USE_AURA)
+    gpu_channel_ = gpu_service_->EstablishGpuChannelSync();
 #else
     NOTREACHED();
 #endif
@@ -1822,7 +1823,7 @@
   if (command_line.HasSwitch(switches::kDisableGpuCompositing))
     use_software = true;
 
-#if defined(MOJO_SHELL_CLIENT) && defined(USE_AURA)
+#if defined(USE_AURA)
   if (GetMojoShellConnection() && !use_software &&
       command_line.HasSwitch(switches::kUseMusInRenderer)) {
     RenderWidgetMusConnection* connection =
diff --git a/content/renderer/render_thread_impl.h b/content/renderer/render_thread_impl.h
index b8c2371e..ad3e112 100644
--- a/content/renderer/render_thread_impl.h
+++ b/content/renderer/render_thread_impl.h
@@ -87,6 +87,10 @@
 class WebThreadBase;
 }
 
+namespace ui {
+class GpuService;
+}
+
 namespace v8 {
 class Extension;
 }
@@ -655,6 +659,10 @@
   std::unique_ptr<memory_coordinator::ChildMemoryCoordinatorImpl>
       memory_coordinator_;
 
+#if defined(USE_AURA)
+  std::unique_ptr<ui::GpuService> gpu_service_;
+#endif
+
   scoped_refptr<base::SingleThreadTaskRunner>
       main_thread_compositor_task_runner_;
 
diff --git a/content/renderer/render_widget.cc b/content/renderer/render_widget.cc
index e3382c9..b11681c 100644
--- a/content/renderer/render_widget.cc
+++ b/content/renderer/render_widget.cc
@@ -92,7 +92,7 @@
 #include "third_party/skia/include/core/SkPixelRef.h"
 #endif  // defined(OS_POSIX)
 
-#if defined(MOJO_SHELL_CLIENT)
+#if defined(USE_AURA)
 #include "content/public/common/mojo_shell_connection.h"
 #include "content/renderer/mus/render_widget_mus_connection.h"
 #endif
@@ -199,7 +199,7 @@
 
 content::RenderWidgetInputHandlerDelegate* GetRenderWidgetInputHandlerDelegate(
     content::RenderWidget* widget) {
-#if defined(MOJO_SHELL_CLIENT)
+#if defined(USE_AURA)
   const base::CommandLine& cmdline = *base::CommandLine::ForCurrentProcess();
   if (content::MojoShellConnection::GetForProcess() &&
       cmdline.HasSwitch(switches::kUseMusInRenderer)) {
@@ -247,7 +247,6 @@
       text_input_mode_(ui::TEXT_INPUT_MODE_DEFAULT),
       text_input_flags_(0),
       can_compose_inline_(true),
-      composition_range_(gfx::Range::InvalidRange()),
       popup_type_(popup_type),
       pending_window_rect_count_(0),
       screen_info_(screen_info),
@@ -255,7 +254,6 @@
 #if defined(OS_ANDROID)
       text_field_is_dirty_(false),
 #endif
-      monitor_composition_info_(false),
       popup_origin_scale_for_emulation_(0.f),
       frame_swap_message_queue_(new FrameSwapMessageQueue()),
       resizing_mode_selector_(new ResizingModeSelector()),
@@ -497,8 +495,6 @@
     IPC_MESSAGE_HANDLER(ViewMsg_SetSurfaceClientId, OnSetSurfaceClientId)
     IPC_MESSAGE_HANDLER(ViewMsg_WaitForNextFrameForTests,
                         OnWaitNextFrameForTests)
-    IPC_MESSAGE_HANDLER(InputMsg_RequestCompositionUpdate,
-                        OnRequestCompositionUpdate)
 #if defined(OS_ANDROID)
     IPC_MESSAGE_HANDLER(InputMsg_ImeEventAck, OnImeEventAck)
     IPC_MESSAGE_HANDLER(InputMsg_RequestTextInputStateUpdate,
@@ -1369,7 +1365,7 @@
     // sure we are in a consistent state.
     Send(new InputHostMsg_ImeCancelComposition(routing_id()));
   }
-  UpdateCompositionInfo(false /* not an immediate request */);
+  UpdateCompositionInfo(true);
 }
 
 void RenderWidget::OnImeConfirmComposition(const base::string16& text,
@@ -1398,7 +1394,7 @@
   else
     webwidget_->confirmComposition(WebWidget::DoNotKeepSelection);
   input_handler_->set_handling_input_event(false);
-  UpdateCompositionInfo(false /* not an immediate request */);
+  UpdateCompositionInfo(true);
 }
 
 void RenderWidget::OnDeviceScaleFactorChanged() {
@@ -1483,26 +1479,19 @@
   return ui::TEXT_INPUT_TYPE_NONE;
 }
 
-void RenderWidget::UpdateCompositionInfo(bool immediate_request) {
-  if (!monitor_composition_info_ && !immediate_request)
-    return;  // Do not calculate composition info if not requested.
-
+void RenderWidget::UpdateCompositionInfo(bool should_update_range) {
   TRACE_EVENT0("renderer", "RenderWidget::UpdateCompositionInfo");
-  gfx::Range range;
-  std::vector<gfx::Rect> character_bounds;
-
-  if (GetTextInputType() == ui::TEXT_INPUT_TYPE_NONE) {
-    // Composition information is only available on editable node.
-    range = gfx::Range::InvalidRange();
-  } else {
+  gfx::Range range = gfx::Range();
+  if (should_update_range) {
     GetCompositionRange(&range);
-    GetCompositionCharacterBounds(&character_bounds);
+  } else {
+    range = composition_range_;
   }
+  std::vector<gfx::Rect> character_bounds;
+  GetCompositionCharacterBounds(&character_bounds);
 
-  if (!immediate_request &&
-      !ShouldUpdateCompositionInfo(range, character_bounds)) {
+  if (!ShouldUpdateCompositionInfo(range, character_bounds))
     return;
-  }
   composition_character_bounds_ = character_bounds;
   composition_range_ = range;
   Send(new InputHostMsg_ImeCompositionRangeChanged(
@@ -1561,14 +1550,6 @@
 }
 #endif
 
-void RenderWidget::OnRequestCompositionUpdate(bool immediate_request,
-                                              bool monitor_request) {
-  monitor_composition_info_ = monitor_request;
-  if (!immediate_request)
-    return;
-  UpdateCompositionInfo(true /* immediate request */);
-}
-
 bool RenderWidget::ShouldHandleImeEvent() {
 #if defined(OS_ANDROID)
   if (!webwidget_)
@@ -1760,7 +1741,7 @@
     }
   }
 
-  UpdateCompositionInfo(false /* not an immediate request */);
+  UpdateCompositionInfo(false);
 }
 
 void RenderWidget::SetDeviceColorProfileForTesting(
@@ -1905,7 +1886,7 @@
       Send(new InputHostMsg_ImeCancelComposition(routing_id()));
   }
 
-  UpdateCompositionInfo(false /* not an immediate request */);
+  UpdateCompositionInfo(true);
 }
 
 #if defined(OS_ANDROID)
diff --git a/content/renderer/render_widget.h b/content/renderer/render_widget.h
index daee7170..c91e0b8 100644
--- a/content/renderer/render_widget.h
+++ b/content/renderer/render_widget.h
@@ -352,9 +352,7 @@
   // changed. If they are changed, the new value will be sent to the browser
   // process. This method does nothing when the browser process is not able to
   // handle composition range and composition character bounds.
-  // If immediate_request is true, render sends the latest composition info to
-  // the browser even if the composition info is not changed.
-  void UpdateCompositionInfo(bool immediate_request);
+  void UpdateCompositionInfo(bool should_update_range);
 
   // Change the device ICC color profile while running a layout test.
   void SetDeviceColorProfileForTesting(const std::vector<char>& color_profile);
@@ -496,10 +494,6 @@
   void OnRequestTextInputStateUpdate();
 #endif
 
-  // Called by the browser process to update the cursor and composition
-  // information.
-  void OnRequestCompositionUpdate(bool immediate_request, bool monitor_request);
-
   // Notify the compositor about a change in viewport size. This should be
   // used only with auto resize mode WebWidgets, as normal WebWidgets should
   // go through OnResize.
@@ -744,9 +738,6 @@
   std::deque<blink::WebTextInputInfo> text_input_info_history_;
 #endif
 
-  // True if the IME requests updated composition info.
-  bool monitor_composition_info_;
-
   std::unique_ptr<RenderWidgetScreenMetricsEmulator> screen_metrics_emulator_;
 
   // Popups may be displaced when screen metrics emulation is enabled.
diff --git a/content/test/layouttest_support.cc b/content/test/layouttest_support.cc
index d27892c..0caf15c 100644
--- a/content/test/layouttest_support.cc
+++ b/content/test/layouttest_support.cc
@@ -264,7 +264,8 @@
         std::move(compositor_context_provider),
         std::move(worker_context_provider), std::move(display_output_surface),
         deps->GetSharedBitmapManager(), deps->GetGpuMemoryBufferManager(),
-        settings.renderer_settings, task_runner, synchronous_composite);
+        settings.renderer_settings, task_runner, synchronous_composite,
+        false /* force_disable_reclaim_resources */);
     output_surfaces_[routing_id] = output_surface.get();
     return std::move(output_surface);
   }
diff --git a/device/geolocation/geolocation.gyp b/device/geolocation/geolocation.gyp
index 805ffae..a344ec7a 100644
--- a/device/geolocation/geolocation.gyp
+++ b/device/geolocation/geolocation.gyp
@@ -108,6 +108,7 @@
           'conditions': [
             ["use_dbus==1", {
               'dependencies': [
+                '<(DEPTH)/build/linux/system.gyp:dbus',
                 '<(DEPTH)/dbus/dbus.gyp:dbus',
               ],
               'sources!': [
diff --git a/device/serial/serial_io_handler_posix.cc b/device/serial/serial_io_handler_posix.cc
index 3685ec8..71b398c8 100644
--- a/device/serial/serial_io_handler_posix.cc
+++ b/device/serial/serial_io_handler_posix.cc
@@ -123,8 +123,6 @@
   DCHECK(pending_read_buffer());
   DCHECK(file().IsValid());
 
-  EnsureWatchingReads();
-
   // Try to read immediately. This is needed because on some platforms
   // (e.g., OSX) there may not be a notification from the message loop
   // when the fd is ready to read immediately after it is opened. There
@@ -303,7 +301,7 @@
   AttemptRead(false);
 }
 
-void SerialIoHandlerPosix::AttemptRead(bool within_read) {
+bool SerialIoHandlerPosix::AttemptRead(bool within_read) {
   if (pending_read_buffer()) {
     int bytes_read = HANDLE_EINTR(read(file().GetPlatformFile(),
                                        pending_read_buffer(),
@@ -311,7 +309,7 @@
     if (bytes_read < 0) {
       if (errno == EAGAIN) {
         // The fd does not have data to read yet so continue waiting.
-        return;
+        EnsureWatchingReads();
       } else if (errno == ENXIO) {
         RunReadCompleted(within_read, 0, serial::ReceiveError::DEVICE_LOST);
       } else {
@@ -343,6 +341,8 @@
     is_watching_reads_ = false;
     file_read_watcher_.StopWatchingFileDescriptor();
   }
+
+  return true;
 }
 
 void SerialIoHandlerPosix::RunReadCompleted(bool within_read,
diff --git a/device/serial/serial_io_handler_posix.h b/device/serial/serial_io_handler_posix.h
index 28f10c43..b25f7c87 100644
--- a/device/serial/serial_io_handler_posix.h
+++ b/device/serial/serial_io_handler_posix.h
@@ -49,7 +49,7 @@
       scoped_refptr<base::SingleThreadTaskRunner> ui_thread_task_runner);
   ~SerialIoHandlerPosix() override;
 
-  void AttemptRead(bool within_read);
+  bool AttemptRead(bool within_read);
   void RunReadCompleted(bool within_read,
                         int bytes_read,
                         serial::ReceiveError error);
diff --git a/docs/component_build.md b/docs/component_build.md
index fe36579..06341c2 100644
--- a/docs/component_build.md
+++ b/docs/component_build.md
@@ -5,17 +5,21 @@
 Release builds are “static” builds which compile to one executable and
 zero-to-two shared libraries (depending on the platform). This is efficient at
 runtime, but can take a long time to link because so much code goes into a
-single binary. When you set the GN build variable
+single binary.
+
+In a component build, many smaller shared libraries will be generated. This
+speeds up link times, and means that many changes only require that the local
+shared library be linked rather than the full executable, but at the expense of
+program load-time performance.
+
+The component build is currently the default for debug non-iOS builds (it
+doesn’t work for iOS). You can force it on for release builds using the
+[GN build arg](https://www.chromium.org/developers/gn-build-configuration):
 
 ```python
 is_component_build = true
 ```
 
-the build will generate many smaller shared libraries. This speeds up link
-times, and means that many changes only require that the local shared library
-be linked rather than the full executable, but at the expense of program
-load-time performance.
-
 ### How to make a component
 
 Defining a component just means using the GN “component” template instead
diff --git a/extensions/browser/api/bluetooth_socket/bluetooth_socket_apitest.cc b/extensions/browser/api/bluetooth_socket/bluetooth_socket_apitest.cc
index ab1b4d0..297effb8 100644
--- a/extensions/browser/api/bluetooth_socket/bluetooth_socket_apitest.cc
+++ b/extensions/browser/api/bluetooth_socket/bluetooth_socket_apitest.cc
@@ -137,13 +137,7 @@
   EXPECT_TRUE(catcher.GetNextResult()) << catcher.message();
 }
 
-#if defined(_LIBCPP_VERSION)
-// This test fails in libc++ builds, see http://crbug.com/392205.
-#define MAYBE_Listen DISABLED_Listen
-#else
-#define MAYBE_Listen Listen
-#endif
-IN_PROC_BROWSER_TEST_F(BluetoothSocketApiTest, MAYBE_Listen) {
+IN_PROC_BROWSER_TEST_F(BluetoothSocketApiTest, Listen) {
   ResultCatcher catcher;
   catcher.RestrictToBrowserContext(browser_context());
 
diff --git a/extensions/browser/extension_web_contents_observer.cc b/extensions/browser/extension_web_contents_observer.cc
index 12a2c7e9..52b9041 100644
--- a/extensions/browser/extension_web_contents_observer.cc
+++ b/extensions/browser/extension_web_contents_observer.cc
@@ -107,8 +107,7 @@
   // Plus, we can delete the concept of activating an extension once site
   // isolation is turned on.
   RendererStartupHelperFactory::GetForBrowserContext(browser_context_)
-      ->ActivateExtensionInProcess(extension->id(),
-                                   render_view_host->GetProcess());
+      ->ActivateExtensionInProcess(*extension, render_view_host->GetProcess());
 }
 
 void ExtensionWebContentsObserver::RenderFrameCreated(
diff --git a/extensions/browser/renderer_startup_helper.cc b/extensions/browser/renderer_startup_helper.cc
index b3aa205..452c8169 100644
--- a/extensions/browser/renderer_startup_helper.cc
+++ b/extensions/browser/renderer_startup_helper.cc
@@ -128,12 +128,18 @@
 }
 
 void RendererStartupHelper::ActivateExtensionInProcess(
-    const ExtensionId& id,
+    const Extension& extension,
     content::RenderProcessHost* process) {
+  // Renderers don't need to know about themes. We also don't normally
+  // "activate" themes, but this could happen if someone tries to open a tab
+  // to the e.g. theme's manifest.
+  if (extension.is_theme())
+    return;
+
   if (initialized_processes_.count(process))
-    process->Send(new ExtensionMsg_ActivateExtension(id));
+    process->Send(new ExtensionMsg_ActivateExtension(extension.id()));
   else
-    pending_active_extensions_[process].insert(id);
+    pending_active_extensions_[process].insert(extension.id());
 }
 
 void RendererStartupHelper::OnExtensionLoaded(const Extension& extension) {
@@ -152,11 +158,15 @@
     process->Send(new ExtensionMsg_Loaded(params));
 }
 
-void RendererStartupHelper::OnExtensionUnloaded(const ExtensionId& id) {
+void RendererStartupHelper::OnExtensionUnloaded(const Extension& extension) {
+  // Renderers don't need to know about themes.
+  if (extension.is_theme())
+    return;
+
   for (content::RenderProcessHost* process : initialized_processes_)
-    process->Send(new ExtensionMsg_Unloaded(id));
+    process->Send(new ExtensionMsg_Unloaded(extension.id()));
   for (auto& process_extensions_pair : pending_active_extensions_)
-    process_extensions_pair.second.erase(id);
+    process_extensions_pair.second.erase(extension.id());
 }
 
 //////////////////////////////////////////////////////////////////////////////
diff --git a/extensions/browser/renderer_startup_helper.h b/extensions/browser/renderer_startup_helper.h
index 9681f29..94ec383 100644
--- a/extensions/browser/renderer_startup_helper.h
+++ b/extensions/browser/renderer_startup_helper.h
@@ -48,14 +48,14 @@
 
   // Sends a message to the specified |process| activating the given extension
   // once the process is initialized.
-  void ActivateExtensionInProcess(const ExtensionId& id,
+  void ActivateExtensionInProcess(const Extension& extension,
                                   content::RenderProcessHost* process);
 
   // Sends a message to all initialized processes to [un]load the given
   // extension. We have explicit calls for these (rather than using an
   // ExtensionRegistryObserver) because this needs to happen before other
   // initialization which might rely on the renderers being notified.
-  void OnExtensionUnloaded(const ExtensionId& id);
+  void OnExtensionUnloaded(const Extension& extension);
   void OnExtensionLoaded(const Extension& extension);
 
  private:
diff --git a/extensions/test/data/api_test/bluetooth_socket/listen/runtest.js b/extensions/test/data/api_test/bluetooth_socket/listen/runtest.js
index 63a05af..4741167 100644
--- a/extensions/test/data/api_test/bluetooth_socket/listen/runtest.js
+++ b/extensions/test/data/api_test/bluetooth_socket/listen/runtest.js
@@ -7,25 +7,32 @@
 
 function testListen() {
   chrome.test.assertEq(2, sockets.length);
+  var serverSocket = sockets[0], clientSocket = sockets[1];
+
+  // In case the sockets don't come back to us in order.
+  if (sockets[0].socketId != serverSocketId) {
+    serverSocket = sockets[1];
+    clientSocket = sockets[0];
+  }
 
   // First socket should be the listening one.
-  chrome.test.assertEq(serverSocketId, sockets[0].socketId);
-  chrome.test.assertEq(false, sockets[0].persistent);
-  chrome.test.assertEq('MyServiceName', sockets[0].name);
-  chrome.test.assertEq(false, sockets[0].paused);
-  chrome.test.assertEq(false, sockets[0].connected);
-  chrome.test.assertEq(undefined, sockets[0].address);
-  chrome.test.assertEq(uuid, sockets[0].uuid);
+  chrome.test.assertEq(serverSocketId, serverSocket.socketId);
+  chrome.test.assertEq(false, serverSocket.persistent);
+  chrome.test.assertEq('MyServiceName', serverSocket.name);
+  chrome.test.assertEq(false, serverSocket.paused);
+  chrome.test.assertEq(false, serverSocket.connected);
+  chrome.test.assertEq(undefined, serverSocket.address);
+  chrome.test.assertEq(uuid, serverSocket.uuid);
 
   // Second socket should be the client one, which unlike the server should
   // be created paused.
-  chrome.test.assertEq(clientSocketId, sockets[1].socketId);
-  chrome.test.assertEq(false, sockets[1].persistent);
-  chrome.test.assertEq(undefined, sockets[1].name);
-  chrome.test.assertEq(true, sockets[1].paused);
-  chrome.test.assertEq(true, sockets[1].connected);
-  chrome.test.assertEq(clientAddress, sockets[1].address);
-  chrome.test.assertEq(uuid, sockets[1].uuid);
+  chrome.test.assertEq(clientSocketId, clientSocket.socketId);
+  chrome.test.assertEq(false, clientSocket.persistent);
+  chrome.test.assertEq(undefined, clientSocket.name);
+  chrome.test.assertEq(true, clientSocket.paused);
+  chrome.test.assertEq(true, clientSocket.connected);
+  chrome.test.assertEq(clientAddress, clientSocket.address);
+  chrome.test.assertEq(uuid, clientSocket.uuid);
 
   chrome.test.succeed();
 }
diff --git a/gpu/gles2_conform_support/native/egl_native_x11.cc b/gpu/gles2_conform_support/native/egl_native_x11.cc
index 7e4c42362..2c1d809 100644
--- a/gpu/gles2_conform_support/native/egl_native_x11.cc
+++ b/gpu/gles2_conform_support/native/egl_native_x11.cc
@@ -25,30 +25,23 @@
   };
 
   if (format != GL_RGBA && format != GL_RGB)
-    return static_cast<EGLImageKHR>(NULL);
+    return static_cast<EGLImageKHR>(nullptr);
 
   if (type != GL_UNSIGNED_BYTE)
-    return static_cast<EGLImageKHR>(NULL);
+    return static_cast<EGLImageKHR>(nullptr);
 
   GLuint texture;
   glGenTextures(1, &texture);
   glBindTexture(GL_TEXTURE_2D, texture);
-  glTexImage2D(GL_TEXTURE_2D,
-               0,
-               format,
-               width,
-               height,
-               0,
-               format,
-               type,
-               NULL);
+  glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, type,
+               nullptr);
 
   // Disable mip-maps because we do not require it.
   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
 
   if(glGetError() != GL_NO_ERROR)
-    return static_cast<EGLImageKHR>(NULL);
+    return static_cast<EGLImageKHR>(nullptr);
 
   EGLImageKHR egl_image =
       egl_create_image_khr_(eglGetCurrentDisplay(),
@@ -60,7 +53,7 @@
   if (eglGetError() == EGL_SUCCESS)
     return egl_image;
   else
-    return static_cast<EGLImageKHR>(NULL);
+    return static_cast<EGLImageKHR>(nullptr);
 }
 
 void GTFDestroyEGLImage(EGLImageKHR image) {
diff --git a/headless/app/headless_shell.cc b/headless/app/headless_shell.cc
index 39d226f..1410313 100644
--- a/headless/app/headless_shell.cc
+++ b/headless/app/headless_shell.cc
@@ -349,6 +349,7 @@
   if (command_line.HasSwitch(headless::switches::kUserDataDir)) {
     builder.SetUserDataDir(
         command_line.GetSwitchValuePath(headless::switches::kUserDataDir));
+    builder.SetIncognitoMode(false);
   }
 
   return HeadlessBrowserMain(
diff --git a/headless/lib/browser/headless_browser_context_impl.cc b/headless/lib/browser/headless_browser_context_impl.cc
index 458103d..2fb76e6 100644
--- a/headless/lib/browser/headless_browser_context_impl.cc
+++ b/headless/lib/browser/headless_browser_context_impl.cc
@@ -160,7 +160,7 @@
 }
 
 bool HeadlessBrowserContextImpl::IsOffTheRecord() const {
-  return false;
+  return context_options_->incognito_mode();
 }
 
 content::ResourceContext* HeadlessBrowserContextImpl::GetResourceContext() {
@@ -343,6 +343,12 @@
 }
 
 HeadlessBrowserContext::Builder&
+HeadlessBrowserContext::Builder::SetIncognitoMode(bool incognito_mode) {
+  options_->incognito_mode_ = incognito_mode;
+  return *this;
+}
+
+HeadlessBrowserContext::Builder&
 HeadlessBrowserContext::Builder::AddJsMojoBindings(
     const std::string& mojom_name,
     const std::string& js_bindings) {
diff --git a/headless/lib/browser/headless_browser_context_options.cc b/headless/lib/browser/headless_browser_context_options.cc
index 6f7a4d8..82e3d51a 100644
--- a/headless/lib/browser/headless_browser_context_options.cc
+++ b/headless/lib/browser/headless_browser_context_options.cc
@@ -56,6 +56,11 @@
   return ReturnOverriddenValue(user_data_dir_, browser_options_->user_data_dir);
 }
 
+bool HeadlessBrowserContextOptions::incognito_mode() const {
+  return ReturnOverriddenValue(incognito_mode_,
+                               browser_options_->incognito_mode);
+}
+
 const ProtocolHandlerMap& HeadlessBrowserContextOptions::protocol_handlers()
     const {
   return protocol_handlers_;
diff --git a/headless/lib/browser/headless_browser_context_options.h b/headless/lib/browser/headless_browser_context_options.h
index a3f97eac..af9b893 100644
--- a/headless/lib/browser/headless_browser_context_options.h
+++ b/headless/lib/browser/headless_browser_context_options.h
@@ -38,6 +38,9 @@
   // See HeadlessBrowser::Options::user_data_dir.
   const base::FilePath& user_data_dir() const;
 
+  // Set HeadlessBrowser::Options::incognito_mode.
+  bool incognito_mode() const;
+
   // Custom network protocol handlers. These can be used to override URL
   // fetching for different network schemes.
   const ProtocolHandlerMap& protocol_handlers() const;
@@ -56,6 +59,7 @@
   base::Optional<std::string> host_resolver_rules_;
   base::Optional<gfx::Size> window_size_;
   base::Optional<base::FilePath> user_data_dir_;
+  base::Optional<bool> incognito_mode_;
 
   ProtocolHandlerMap protocol_handlers_;
 
diff --git a/headless/lib/headless_browser_context_browsertest.cc b/headless/lib/headless_browser_context_browsertest.cc
index a6ad735..305dce41 100644
--- a/headless/lib/headless_browser_context_browsertest.cc
+++ b/headless/lib/headless_browser_context_browsertest.cc
@@ -219,6 +219,7 @@
       browser()
           ->CreateBrowserContextBuilder()
           .SetUserDataDir(user_data_dir.path())
+          .SetIncognitoMode(false)
           .Build();
 
   HeadlessWebContents* web_contents =
@@ -234,4 +235,36 @@
   EXPECT_FALSE(base::IsDirectoryEmpty(user_data_dir.path()));
 }
 
+IN_PROC_BROWSER_TEST_F(HeadlessBrowserTest, IncognitoMode) {
+  // We do not want to bother with posting tasks to create a temp dir.
+  // Just allow IO from main thread for now.
+  base::ThreadRestrictions::SetIOAllowed(true);
+
+  EXPECT_TRUE(embedded_test_server()->Start());
+
+  base::ScopedTempDir user_data_dir;
+  ASSERT_TRUE(user_data_dir.CreateUniqueTempDir());
+
+  // Newly created temp directory should be empty.
+  EXPECT_TRUE(base::IsDirectoryEmpty(user_data_dir.path()));
+
+  HeadlessBrowserContext* browser_context =
+      browser()
+          ->CreateBrowserContextBuilder()
+          .SetUserDataDir(user_data_dir.path())
+          .SetIncognitoMode(true)
+          .Build();
+
+  HeadlessWebContents* web_contents =
+      browser_context->CreateWebContentsBuilder()
+          .SetInitialURL(embedded_test_server()->GetURL("/hello.html"))
+          .Build();
+
+  EXPECT_TRUE(WaitForLoad(web_contents));
+
+  // Similar to test above, but now we are in incognito mode,
+  // so nothing should be written to this directory.
+  EXPECT_TRUE(base::IsDirectoryEmpty(user_data_dir.path()));
+}
+
 }  // namespace headless
diff --git a/headless/public/headless_browser.cc b/headless/public/headless_browser.cc
index 3a9e2f23..cbfbc5e 100644
--- a/headless/public/headless_browser.cc
+++ b/headless/public/headless_browser.cc
@@ -27,7 +27,8 @@
       disable_sandbox(false),
       gl_implementation("osmesa"),
       user_agent(content::BuildUserAgentFromProduct(kProductName)),
-      window_size(kDefaultWindowSize) {}
+      window_size(kDefaultWindowSize),
+      incognito_mode(true) {}
 
 Options::Options(Options&& options) = default;
 
@@ -91,6 +92,11 @@
   return *this;
 }
 
+Builder& Builder::SetIncognitoMode(bool incognito_mode) {
+  options_.incognito_mode = incognito_mode;
+  return *this;
+}
+
 Options Builder::Build() {
   return std::move(options_);
 }
diff --git a/headless/public/headless_browser.h b/headless/public/headless_browser.h
index ccc14369..6c7dfe4 100644
--- a/headless/public/headless_browser.h
+++ b/headless/public/headless_browser.h
@@ -131,6 +131,9 @@
   // If empty, default directory (where the binary is located) will be used.
   base::FilePath user_data_dir;
 
+  // Run a browser context in an incognito mode. Enabled by default.
+  bool incognito_mode;
+
   // Reminder: when adding a new field here, do not forget to add it to
   // HeadlessBrowserContextOptions (where appropriate).
  private:
@@ -160,6 +163,7 @@
   Builder& SetHostResolverRules(const std::string& host_resolver_rules);
   Builder& SetWindowSize(const gfx::Size& window_size);
   Builder& SetUserDataDir(const base::FilePath& user_data_dir);
+  Builder& SetIncognitoMode(bool incognito_mode);
 
   Options Build();
 
diff --git a/headless/public/headless_browser_context.h b/headless/public/headless_browser_context.h
index 702541e..4cdaf35 100644
--- a/headless/public/headless_browser_context.h
+++ b/headless/public/headless_browser_context.h
@@ -101,6 +101,7 @@
   Builder& SetHostResolverRules(const std::string& host_resolver_rules);
   Builder& SetWindowSize(const gfx::Size& window_size);
   Builder& SetUserDataDir(const base::FilePath& user_data_dir);
+  Builder& SetIncognitoMode(bool incognito_mode);
 
   HeadlessBrowserContext* Build();
 
diff --git a/ios/build/bots/chromium.mac/ios-simulator-swarming.json b/ios/build/bots/chromium.mac/ios-simulator-swarming.json
index 56f9121..4297caa 100644
--- a/ios/build/bots/chromium.mac/ios-simulator-swarming.json
+++ b/ios/build/bots/chromium.mac/ios-simulator-swarming.json
@@ -8,7 +8,7 @@
     "Tests run on iPhone 5s (64-bit) and iPad Retina (32-bit).",
     "Build is performed with gn+ninja."
   ],
-  "xcode version": "7.0",
+  "xcode version": "7.3",
   "GYP_DEFINES": [
     "OS=ios",
     "chromium_ios_signing=0",
@@ -31,17 +31,19 @@
   "compiler": "ninja",
   "additional_compile_targets": ["gn_all"],
   "configuration": "Debug",
-  "sdk": "iphonesimulator9.0",
+  "sdk": "iphonesimulator9.3",
   "tests": [
     {
       "include": "common_tests.json",
       "device type": "iPhone 5s",
-      "os": "9.0"
+      "os": "9.0",
+      "xcode version": "7.0"
     },
     {
       "include": "common_tests.json",
       "device type": "iPad Retina",
-      "os": "9.0"
+      "os": "9.0",
+      "xcode version": "7.0"
     }
   ]
 }
diff --git a/ios/build/bots/tests/common_tests.json b/ios/build/bots/tests/common_tests.json
index f5aca97..81f4634 100644
--- a/ios/build/bots/tests/common_tests.json
+++ b/ios/build/bots/tests/common_tests.json
@@ -37,9 +37,6 @@
       "app": "sql_unittests"
     },
     {
-      "app": "sync_unit_tests"
-    },
-    {
       "app": "ui_base_unittests"
     },
     {
diff --git a/ios/chrome/browser/ui/autofill/autofill_client_ios.h b/ios/chrome/browser/ui/autofill/autofill_client_ios.h
index 6c5575f..8ce38ae 100644
--- a/ios/chrome/browser/ui/autofill/autofill_client_ios.h
+++ b/ios/chrome/browser/ui/autofill/autofill_client_ios.h
@@ -66,6 +66,8 @@
       const CreditCard& card,
       std::unique_ptr<base::DictionaryValue> legal_message,
       const base::Closure& callback) override;
+  void ConfirmCreditCardFillAssist(const CreditCard& card,
+                                   const base::Closure& callback) override;
   void LoadRiskData(
       const base::Callback<void(const std::string&)>& callback) override;
   bool HasCreditCardScanFeature() override;
diff --git a/ios/chrome/browser/ui/autofill/autofill_client_ios.mm b/ios/chrome/browser/ui/autofill/autofill_client_ios.mm
index c7b6f59..b8a2e7f 100644
--- a/ios/chrome/browser/ui/autofill/autofill_client_ios.mm
+++ b/ios/chrome/browser/ui/autofill/autofill_client_ios.mm
@@ -109,6 +109,12 @@
           true, card, std::move(legal_message), callback))));
 }
 
+void AutofillClientIOS::ConfirmCreditCardFillAssist(
+    const CreditCard& card,
+    const base::Closure& callback) {
+  NOTREACHED();
+}
+
 void AutofillClientIOS::LoadRiskData(
     const base::Callback<void(const std::string&)>& callback) {
   callback.Run(ios::GetChromeBrowserProvider()->GetRiskData());
diff --git a/ios/net/http_cache_helper.cc b/ios/net/http_cache_helper.cc
index e9e185a4..5aa57a1 100644
--- a/ios/net/http_cache_helper.cc
+++ b/ios/net/http_cache_helper.cc
@@ -19,6 +19,7 @@
 #include "net/quic/chromium/quic_stream_factory.h"
 #include "net/url_request/url_request_context.h"
 #include "net/url_request/url_request_context_getter.h"
+#include "url/gurl.h"
 
 namespace {
 
@@ -55,7 +56,7 @@
   // Clear QUIC server information from memory and the disk cache.
   http_cache->GetSession()
       ->quic_stream_factory()
-      ->ClearCachedStatesInCryptoConfig();
+      ->ClearCachedStatesInCryptoConfig(base::Callback<bool(const GURL&)>());
 
   // Clear SDCH dictionary state.
   net::SdchManager* sdch_manager =
diff --git a/media/base/demuxer_stream.h b/media/base/demuxer_stream.h
index 17f193f..c90de79 100644
--- a/media/base/demuxer_stream.h
+++ b/media/base/demuxer_stream.h
@@ -102,9 +102,12 @@
   // reading data from a key frame preceeding the |timestamp|.
   virtual void set_enabled(bool enabled, base::TimeDelta timestamp) = 0;
 
-  using StreamRestartedCB =
-      base::Callback<void(DemuxerStream*, base::TimeDelta)>;
-  virtual void SetStreamRestartedCB(const StreamRestartedCB& cb) = 0;
+  // The StreamStatusChangeCB allows DemuxerStream clients to receive
+  // notifications about the stream being disabled or enabled.
+  // The first parameter indicates whether the stream is enabled or disabled.
+  // The second parameter is the playback position when the change occured.
+  using StreamStatusChangeCB = base::Callback<void(bool, base::TimeDelta)>;
+  virtual void SetStreamStatusChangeCB(const StreamStatusChangeCB& cb) = 0;
 
  protected:
   // Only allow concrete implementations to get deleted.
diff --git a/media/base/fake_demuxer_stream.cc b/media/base/fake_demuxer_stream.cc
index beb44f1..731e6b1d 100644
--- a/media/base/fake_demuxer_stream.cc
+++ b/media/base/fake_demuxer_stream.cc
@@ -112,7 +112,8 @@
   NOTIMPLEMENTED();
 }
 
-void FakeDemuxerStream::SetStreamRestartedCB(const StreamRestartedCB& cb) {
+void FakeDemuxerStream::SetStreamStatusChangeCB(
+    const StreamStatusChangeCB& cb) {
   NOTIMPLEMENTED();
 }
 
diff --git a/media/base/fake_demuxer_stream.h b/media/base/fake_demuxer_stream.h
index 95b1fae..385d8243 100644
--- a/media/base/fake_demuxer_stream.h
+++ b/media/base/fake_demuxer_stream.h
@@ -37,7 +37,7 @@
   VideoRotation video_rotation() override;
   bool enabled() const override;
   void set_enabled(bool enabled, base::TimeDelta timestamp) override;
-  void SetStreamRestartedCB(const StreamRestartedCB& cb) override;
+  void SetStreamStatusChangeCB(const StreamStatusChangeCB& cb) override;
 
   void Initialize();
 
diff --git a/media/base/fake_text_track_stream.cc b/media/base/fake_text_track_stream.cc
index c0a8ae48b..279fe39c 100644
--- a/media/base/fake_text_track_stream.cc
+++ b/media/base/fake_text_track_stream.cc
@@ -54,7 +54,8 @@
   NOTIMPLEMENTED();
 }
 
-void FakeTextTrackStream::SetStreamRestartedCB(const StreamRestartedCB& cb) {
+void FakeTextTrackStream::SetStreamStatusChangeCB(
+    const StreamStatusChangeCB& cb) {
   NOTIMPLEMENTED();
 }
 
diff --git a/media/base/fake_text_track_stream.h b/media/base/fake_text_track_stream.h
index 1e3c0a5..ee8b15c 100644
--- a/media/base/fake_text_track_stream.h
+++ b/media/base/fake_text_track_stream.h
@@ -31,7 +31,7 @@
   VideoRotation video_rotation() override;
   bool enabled() const override;
   void set_enabled(bool enabled, base::TimeDelta timestamp) override;
-  void SetStreamRestartedCB(const StreamRestartedCB& cb) override;
+  void SetStreamStatusChangeCB(const StreamStatusChangeCB& cb) override;
 
   void SatisfyPendingRead(const base::TimeDelta& start,
                           const base::TimeDelta& duration,
diff --git a/media/base/media_switches.cc b/media/base/media_switches.cc
index 16c3355..a292246 100644
--- a/media/base/media_switches.cc
+++ b/media/base/media_switches.cc
@@ -55,9 +55,6 @@
 // for details.
 const char kEnableExclusiveAudio[] = "enable-exclusive-audio";
 
-// Enables H264 HW encode acceleration using Media Foundation for Windows.
-const char kEnableMFH264Encoding[] = "enable-mf-h264-encoding";
-
 // Force the use of MediaFoundation for video capture. This is only supported in
 // Windows 7 and above. Used, like |kForceDirectShowVideoCapture|, to
 // troubleshoot problems in Windows platforms.
@@ -138,6 +135,12 @@
 
 namespace media {
 
+#if defined(OS_WIN)
+// Enables H264 HW encode acceleration using Media Foundation for Windows.
+const base::Feature kMediaFoundationH264Encoding{
+    "MediaFoundationH264Encoding", base::FEATURE_DISABLED_BY_DEFAULT};
+#endif  // defined(OS_WIN)
+
 #if defined(ENABLE_PLUGINS)
 // Let flash join and be controlled by media session, only valid when
 // |kEnableDefaultMediaSession| is on.
@@ -149,6 +152,18 @@
 const base::Feature kNewAudioRenderingMixingStrategy{
     "NewAudioRenderingMixingStrategy", base::FEATURE_DISABLED_BY_DEFAULT};
 
+// Let videos be resumed via remote controls (for example, the notification)
+// when in background.
+const base::Feature kResumeBackgroundVideo {
+  "resume-background-video",
+#if defined(OS_ANDROID)
+      base::FEATURE_ENABLED_BY_DEFAULT
+};
+#else
+      base::FEATURE_DISABLED_BY_DEFAULT
+};
+#endif
+
 // Use shared block-based buffering for media.
 const base::Feature kUseNewMediaCache{"use-new-media-cache",
                                       base::FEATURE_ENABLED_BY_DEFAULT};
diff --git a/media/base/media_switches.h b/media/base/media_switches.h
index 77ca1df..8e60f8f1 100644
--- a/media/base/media_switches.h
+++ b/media/base/media_switches.h
@@ -37,7 +37,6 @@
 
 #if defined(OS_WIN)
 MEDIA_EXPORT extern const char kEnableExclusiveAudio[];
-MEDIA_EXPORT extern const char kEnableMFH264Encoding[];
 MEDIA_EXPORT extern const char kForceMediaFoundationVideoCapture[];
 MEDIA_EXPORT extern const char kForceWaveAudio[];
 MEDIA_EXPORT extern const char kTrySupportedChannelLayouts[];
@@ -78,11 +77,16 @@
 // All features in alphabetical order. The features should be documented
 // alongside the definition of their values in the .cc file.
 
+#if defined(OS_WIN)
+MEDIA_EXPORT extern const base::Feature kMediaFoundationH264Encoding;
+#endif  // defined(OS_WIN)
+
 #if defined(ENABLE_PLUGINS)
 MEDIA_EXPORT extern const base::Feature kFlashJoinsMediaSession;
 #endif  // defined(ENABLE_PLUGINS)
 
 MEDIA_EXPORT extern const base::Feature kNewAudioRenderingMixingStrategy;
+MEDIA_EXPORT extern const base::Feature kResumeBackgroundVideo;
 MEDIA_EXPORT extern const base::Feature kUseNewMediaCache;
 
 }  // namespace media
diff --git a/media/base/mock_filters.h b/media/base/mock_filters.h
index ecd6848..598860f 100644
--- a/media/base/mock_filters.h
+++ b/media/base/mock_filters.h
@@ -158,7 +158,7 @@
   VideoRotation video_rotation() override;
   MOCK_CONST_METHOD0(enabled, bool());
   MOCK_METHOD2(set_enabled, void(bool, base::TimeDelta));
-  MOCK_METHOD1(SetStreamRestartedCB, void(const StreamRestartedCB&));
+  MOCK_METHOD1(SetStreamStatusChangeCB, void(const StreamStatusChangeCB&));
 
  private:
   Type type_;
diff --git a/media/blink/webmediaplayer_delegate.h b/media/blink/webmediaplayer_delegate.h
index c70b07f3..e33cc70 100644
--- a/media/blink/webmediaplayer_delegate.h
+++ b/media/blink/webmediaplayer_delegate.h
@@ -68,6 +68,10 @@
   // Returns whether the render frame is currently hidden.
   virtual bool IsHidden() = 0;
 
+  // Returns whether there's a video playing in background within the render
+  // frame.
+  virtual bool IsPlayingBackgroundVideo() = 0;
+
  protected:
   virtual ~WebMediaPlayerDelegate() {}
 };
diff --git a/media/blink/webmediaplayer_impl.cc b/media/blink/webmediaplayer_impl.cc
index 84dd78f..23a518d82 100644
--- a/media/blink/webmediaplayer_impl.cc
+++ b/media/blink/webmediaplayer_impl.cc
@@ -115,6 +115,10 @@
 #endif
 }
 
+bool IsResumeBackgroundVideosEnabled() {
+  return base::FeatureList::IsEnabled(kResumeBackgroundVideo);
+}
+
 bool IsNetworkStateError(blink::WebMediaPlayer::NetworkState state) {
   bool result = state == blink::WebMediaPlayer::NetworkStateFormatError ||
                 state == blink::WebMediaPlayer::NetworkStateNetworkError ||
@@ -386,7 +390,6 @@
     return;
   }
 #endif
-
   paused_ = false;
   is_idle_ = false;
   pipeline_.SetPlaybackRate(playback_rate_);
@@ -1160,6 +1163,7 @@
 
 void WebMediaPlayerImpl::OnHidden() {
   DCHECK(main_task_runner_->BelongsToCurrentThread());
+
   UpdatePlayState();
 
   // Schedule suspended playing media to be paused if the user doesn't come back
@@ -1171,6 +1175,7 @@
   DCHECK(main_task_runner_->BelongsToCurrentThread());
   must_suspend_ = false;
   background_pause_timer_.Stop();
+
   UpdatePlayState();
 }
 
@@ -1605,7 +1610,15 @@
 
   // Background suspend is not enabled for audio-only players unless paused,
   // though in the case of audio-only the session should be kept.
-  bool background_suspended = is_backgrounded && have_metadata && hasVideo();
+  // Videos are not suspended if the user resumed the playback via the remote
+  // controls earlier and it's still playing.
+  bool is_backgrounded_video = is_backgrounded && have_metadata && hasVideo();
+  bool can_play_backgrounded = is_backgrounded_video && !is_remote &&
+                               hasAudio() && IsResumeBackgroundVideosEnabled();
+  bool is_background_playing =
+      delegate_ && delegate_->IsPlayingBackgroundVideo();
+  bool background_suspended = is_backgrounded_video &&
+                              !(can_play_backgrounded && is_background_playing);
 
   // The |paused_| state is not reliable until we |have_future_data|.
   bool background_pause_suspended =
@@ -1650,11 +1663,20 @@
   // TODO(sandersd): If Blink told us the paused state sooner, we could create
   // the media session sooner.
   bool can_play = !has_error && !is_remote && have_future_data;
-  bool has_session = can_play && !must_suspend_ && !background_suspended;
+  bool has_session_playing =
+      can_play && !must_suspend_ && !background_suspended;
+
+  // |has_session_suspended| means the player is suspended from the media
+  // element point of view but paused and can be resumed from the delegate point
+  // of view. Therefore it behaves like |paused_| for the delegate.
+  bool has_session_suspended = can_play && !must_suspend_ &&
+                               background_suspended && can_play_backgrounded;
+
+  bool has_session = has_session_playing || has_session_suspended;
 
   if (!has_session) {
     result.delegate_state = DelegateState::GONE;
-  } else if (paused_) {
+  } else if (paused_ || has_session_suspended) {
     if (seeking() || overlay_enabled_) {
       result.delegate_state = DelegateState::PAUSED_BUT_NOT_IDLE;
     } else if (ended_) {
diff --git a/media/blink/webmediaplayer_impl.h b/media/blink/webmediaplayer_impl.h
index edee39b7..9fb661d 100644
--- a/media/blink/webmediaplayer_impl.h
+++ b/media/blink/webmediaplayer_impl.h
@@ -327,7 +327,7 @@
   //   - network_state_, ready_state_,
   //   - is_idle_, must_suspend_,
   //   - paused_, ended_,
-  //   - pending_suspend_resume_cycle_.
+  //   - pending_suspend_resume_cycle_,
   void UpdatePlayState();
 
   // Methods internal to UpdatePlayState().
diff --git a/media/blink/webmediaplayer_impl_unittest.cc b/media/blink/webmediaplayer_impl_unittest.cc
index e457440..4f7827c 100644
--- a/media/blink/webmediaplayer_impl_unittest.cc
+++ b/media/blink/webmediaplayer_impl_unittest.cc
@@ -10,6 +10,7 @@
 
 #include "base/bind.h"
 #include "base/callback_helpers.h"
+#include "base/command_line.h"
 #include "base/memory/ptr_util.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
@@ -18,6 +19,7 @@
 #include "base/threading/thread.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "media/base/media_log.h"
+#include "media/base/media_switches.h"
 #include "media/base/test_helpers.h"
 #include "media/blink/mock_webframeclient.h"
 #include "media/blink/webmediaplayer_delegate.h"
@@ -33,6 +35,10 @@
 #include "third_party/WebKit/public/web/WebView.h"
 #include "url/gurl.h"
 
+using ::testing::InSequence;
+using ::testing::Return;
+using ::testing::_;
+
 namespace media {
 
 int64_t OnAdjustAllocatedMemory(int64_t delta) {
@@ -84,6 +90,23 @@
   DISALLOW_COPY_AND_ASSIGN(DummyWebMediaPlayerClient);
 };
 
+class MockWebMediaPlayerDelegate
+    : public WebMediaPlayerDelegate,
+      public base::SupportsWeakPtr<MockWebMediaPlayerDelegate> {
+ public:
+  MockWebMediaPlayerDelegate() = default;
+  ~MockWebMediaPlayerDelegate() = default;
+
+  // WebMediaPlayerDelegate implementation.
+  MOCK_METHOD1(AddObserver, int(Observer*));
+  MOCK_METHOD1(RemoveObserver, void(int));
+  MOCK_METHOD5(DidPlay, void(int, bool, bool, bool, base::TimeDelta));
+  MOCK_METHOD2(DidPause, void(int, bool));
+  MOCK_METHOD1(PlayerGone, void(int));
+  MOCK_METHOD0(IsHidden, bool());
+  MOCK_METHOD0(IsPlayingBackgroundVideo, bool());
+};
+
 class WebMediaPlayerImplTest : public testing::Test {
  public:
   WebMediaPlayerImplTest()
@@ -99,8 +122,7 @@
     media_thread_.StartAndWaitForTesting();
 
     wmpi_.reset(new WebMediaPlayerImpl(
-        web_local_frame_, &client_, nullptr,
-        base::WeakPtr<WebMediaPlayerDelegate>(),
+        web_local_frame_, &client_, nullptr, delegate_.AsWeakPtr(),
         base::WrapUnique(new DefaultRendererFactory(
             media_log_, nullptr, DefaultRendererFactory::GetGpuFactoriesCB())),
         url_index_,
@@ -181,6 +203,18 @@
     return wmpi_->UpdatePlayState_ComputePlayState(false, false, false);
   }
 
+  void SetupForResumingBackgroundVideo() {
+#if !defined(OS_ANDROID)
+    // Need to enable media suspend to test resuming background videos.
+    base::CommandLine::ForCurrentProcess()->AppendSwitch(
+        switches::kEnableMediaSuspend);
+#endif  // !defined(OS_ANDROID)
+    std::unique_ptr<base::FeatureList> feature_list(new base::FeatureList);
+    feature_list->InitializeFromCommandLine(kResumeBackgroundVideo.name, "");
+    base::FeatureList::ClearInstanceForTesting();
+    base::FeatureList::SetInstance(std::move(feature_list));
+  }
+
   // "Renderer" thread.
   base::MessageLoop message_loop_;
 
@@ -203,6 +237,8 @@
   // may want a mock or intelligent fake.
   DummyWebMediaPlayerClient client_;
 
+  MockWebMediaPlayerDelegate delegate_;
+
   // The WebMediaPlayerImpl instance under test.
   std::unique_ptr<WebMediaPlayerImpl> wmpi_;
 
@@ -283,7 +319,11 @@
   EXPECT_FALSE(state.is_suspended);
 
   state = ComputeBackgroundedPlayState();
-  EXPECT_EQ(WebMediaPlayerImpl::DelegateState::GONE, state.delegate_state);
+
+  if (base::FeatureList::IsEnabled(kResumeBackgroundVideo))
+    EXPECT_EQ(WebMediaPlayerImpl::DelegateState::PAUSED, state.delegate_state);
+  else
+    EXPECT_EQ(WebMediaPlayerImpl::DelegateState::GONE, state.delegate_state);
   EXPECT_FALSE(state.is_memory_reporting_enabled);
   EXPECT_TRUE(state.is_suspended);
 
@@ -311,7 +351,10 @@
   EXPECT_FALSE(state.is_suspended);
 
   state = ComputeBackgroundedPlayState();
-  EXPECT_EQ(WebMediaPlayerImpl::DelegateState::GONE, state.delegate_state);
+  if (base::FeatureList::IsEnabled(kResumeBackgroundVideo))
+    EXPECT_EQ(WebMediaPlayerImpl::DelegateState::PAUSED, state.delegate_state);
+  else
+    EXPECT_EQ(WebMediaPlayerImpl::DelegateState::GONE, state.delegate_state);
   EXPECT_FALSE(state.is_memory_reporting_enabled);
   EXPECT_TRUE(state.is_suspended);
 
@@ -337,7 +380,10 @@
 
   // Background suspend should still be possible during underflow.
   state = ComputeBackgroundedPlayState();
-  EXPECT_EQ(WebMediaPlayerImpl::DelegateState::GONE, state.delegate_state);
+  if (base::FeatureList::IsEnabled(kResumeBackgroundVideo))
+    EXPECT_EQ(WebMediaPlayerImpl::DelegateState::PAUSED, state.delegate_state);
+  else
+    EXPECT_EQ(WebMediaPlayerImpl::DelegateState::GONE, state.delegate_state);
   EXPECT_FALSE(state.is_memory_reporting_enabled);
   EXPECT_TRUE(state.is_suspended);
 
@@ -502,4 +548,41 @@
   ASSERT_EQ(blink::WebSize(1080, 1920), wmpi_->naturalSize());
 }
 
+// Audible backgrounded videos are not suspended if delegate_ allows it.
+TEST_F(WebMediaPlayerImplTest, ComputePlayState_BackgroundedVideoPlaying) {
+  WebMediaPlayerImpl::PlayState state;
+  SetMetadata(true, true);
+  SetReadyState(blink::WebMediaPlayer::ReadyStateHaveFutureData);
+
+  SetupForResumingBackgroundVideo();
+
+  EXPECT_CALL(delegate_, IsPlayingBackgroundVideo())
+      .WillRepeatedly(Return(true));
+  EXPECT_CALL(delegate_, IsHidden()).WillRepeatedly(Return(true));
+
+  SetPaused(false);
+  state = ComputeBackgroundedPlayState();
+  EXPECT_EQ(WebMediaPlayerImpl::DelegateState::PLAYING, state.delegate_state);
+  EXPECT_TRUE(state.is_memory_reporting_enabled);
+  EXPECT_FALSE(state.is_suspended);
+}
+
+// Backgrounding audible videos should suspend them and report as paused, not
+// gone.
+TEST_F(WebMediaPlayerImplTest, ComputePlayState_BackgroundedVideoPaused) {
+  WebMediaPlayerImpl::PlayState state;
+  SetMetadata(true, true);
+  SetReadyState(blink::WebMediaPlayer::ReadyStateHaveFutureData);
+
+  SetupForResumingBackgroundVideo();
+
+  EXPECT_CALL(delegate_, IsPlayingBackgroundVideo()).WillOnce(Return(false));
+  EXPECT_CALL(delegate_, IsHidden()).WillRepeatedly(Return(true));
+
+  state = ComputeBackgroundedPlayState();
+  EXPECT_EQ(WebMediaPlayerImpl::DelegateState::PAUSED, state.delegate_state);
+  EXPECT_FALSE(state.is_memory_reporting_enabled);
+  EXPECT_TRUE(state.is_suspended);
+}
+
 }  // namespace media
diff --git a/media/filters/chunk_demuxer.cc b/media/filters/chunk_demuxer.cc
index 31f3de14..526cafee 100644
--- a/media/filters/chunk_demuxer.cc
+++ b/media/filters/chunk_demuxer.cc
@@ -300,18 +300,19 @@
   if (enabled) {
     DCHECK(stream_);
     stream_->Seek(timestamp);
-    if (!stream_restarted_cb_.is_null())
-      stream_restarted_cb_.Run(this, timestamp);
   } else if (!read_cb_.is_null()) {
     DVLOG(1) << "Read from disabled stream, returning EOS";
     base::ResetAndReturn(&read_cb_).Run(kOk,
                                         StreamParserBuffer::CreateEOSBuffer());
   }
+  if (!stream_status_change_cb_.is_null())
+    stream_status_change_cb_.Run(is_enabled_, timestamp);
 }
 
-void ChunkDemuxerStream::SetStreamRestartedCB(const StreamRestartedCB& cb) {
+void ChunkDemuxerStream::SetStreamStatusChangeCB(
+    const StreamStatusChangeCB& cb) {
   DCHECK(!cb.is_null());
-  stream_restarted_cb_ = BindToCurrentLoop(cb);
+  stream_status_change_cb_ = BindToCurrentLoop(cb);
 }
 
 TextTrackConfig ChunkDemuxerStream::text_track_config() {
diff --git a/media/filters/chunk_demuxer.h b/media/filters/chunk_demuxer.h
index 9065829..1e4f357f 100644
--- a/media/filters/chunk_demuxer.h
+++ b/media/filters/chunk_demuxer.h
@@ -113,7 +113,7 @@
   VideoRotation video_rotation() override;
   bool enabled() const override;
   void set_enabled(bool enabled, base::TimeDelta timestamp) override;
-  void SetStreamRestartedCB(const StreamRestartedCB& cb) override;
+  void SetStreamStatusChangeCB(const StreamStatusChangeCB& cb) override;
 
   // Returns the text track configuration.  It is an error to call this method
   // if type() != TEXT.
@@ -158,7 +158,7 @@
   bool splice_frames_enabled_;
   bool partial_append_window_trimming_enabled_;
   bool is_enabled_;
-  StreamRestartedCB stream_restarted_cb_;
+  StreamStatusChangeCB stream_status_change_cb_;
 
   DISALLOW_IMPLICIT_CONSTRUCTORS(ChunkDemuxerStream);
 };
diff --git a/media/filters/chunk_demuxer_unittest.cc b/media/filters/chunk_demuxer_unittest.cc
index 419c6cd..0d7c9a1 100644
--- a/media/filters/chunk_demuxer_unittest.cc
+++ b/media/filters/chunk_demuxer_unittest.cc
@@ -16,6 +16,7 @@
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_split.h"
 #include "base/strings/string_util.h"
+#include "base/synchronization/waitable_event.h"
 #include "media/base/audio_decoder_config.h"
 #include "media/base/decoder_buffer.h"
 #include "media/base/decrypt_config.h"
@@ -4706,4 +4707,41 @@
   CheckExpectedBuffers(video_stream, "71K 81");
 }
 
+void OnStreamStatusChanged(base::WaitableEvent* event,
+                           DemuxerStream* stream,
+                           bool enabled,
+                           base::TimeDelta) {
+  EXPECT_EQ(enabled, stream->enabled());
+  event->Signal();
+}
+
+void CheckStreamStatusNotifications(DemuxerStream* stream) {
+  base::WaitableEvent event(base::WaitableEvent::ResetPolicy::AUTOMATIC,
+                            base::WaitableEvent::InitialState::NOT_SIGNALED);
+
+  ASSERT_TRUE(stream->enabled());
+  stream->SetStreamStatusChangeCB(base::Bind(&OnStreamStatusChanged,
+                                             base::Unretained(&event),
+                                             base::Unretained(stream)));
+
+  stream->set_enabled(false, base::TimeDelta());
+  base::RunLoop().RunUntilIdle();
+  ASSERT_TRUE(event.IsSignaled());
+
+  event.Reset();
+  stream->set_enabled(true, base::TimeDelta());
+  base::RunLoop().RunUntilIdle();
+  ASSERT_TRUE(event.IsSignaled());
+}
+
+TEST_F(ChunkDemuxerTest, StreamStatusNotifications) {
+  ASSERT_TRUE(InitDemuxer(HAS_AUDIO | HAS_VIDEO));
+  DemuxerStream* audio_stream = demuxer_->GetStream(DemuxerStream::AUDIO);
+  EXPECT_NE(nullptr, audio_stream);
+  CheckStreamStatusNotifications(audio_stream);
+  DemuxerStream* video_stream = demuxer_->GetStream(DemuxerStream::VIDEO);
+  EXPECT_NE(nullptr, video_stream);
+  CheckStreamStatusNotifications(video_stream);
+}
+
 }  // namespace media
diff --git a/media/filters/decrypting_demuxer_stream.cc b/media/filters/decrypting_demuxer_stream.cc
index 293ecdb4..0e31ef4 100644
--- a/media/filters/decrypting_demuxer_stream.cc
+++ b/media/filters/decrypting_demuxer_stream.cc
@@ -161,9 +161,9 @@
   demuxer_stream_->set_enabled(enabled, timestamp);
 }
 
-void DecryptingDemuxerStream::SetStreamRestartedCB(
-    const StreamRestartedCB& cb) {
-  demuxer_stream_->SetStreamRestartedCB(cb);
+void DecryptingDemuxerStream::SetStreamStatusChangeCB(
+    const StreamStatusChangeCB& cb) {
+  demuxer_stream_->SetStreamStatusChangeCB(cb);
 }
 
 DecryptingDemuxerStream::~DecryptingDemuxerStream() {
diff --git a/media/filters/decrypting_demuxer_stream.h b/media/filters/decrypting_demuxer_stream.h
index 4c1e4be..ceed9e32 100644
--- a/media/filters/decrypting_demuxer_stream.h
+++ b/media/filters/decrypting_demuxer_stream.h
@@ -64,7 +64,7 @@
   VideoRotation video_rotation() override;
   bool enabled() const override;
   void set_enabled(bool enabled, base::TimeDelta timestamp) override;
-  void SetStreamRestartedCB(const StreamRestartedCB& cb) override;
+  void SetStreamStatusChangeCB(const StreamStatusChangeCB& cb) override;
 
  private:
   // For a detailed state diagram please see this link: http://goo.gl/8jAok
diff --git a/media/filters/ffmpeg_demuxer.cc b/media/filters/ffmpeg_demuxer.cc
index 2cf751d..b34d8bc 100644
--- a/media/filters/ffmpeg_demuxer.cc
+++ b/media/filters/ffmpeg_demuxer.cc
@@ -711,19 +711,20 @@
   is_enabled_ = enabled;
   if (is_enabled_) {
     waiting_for_keyframe_ = true;
-    if (!stream_restarted_cb_.is_null())
-      stream_restarted_cb_.Run(this, timestamp);
   }
   if (!is_enabled_ && !read_cb_.is_null()) {
     DVLOG(1) << "Read from disabled stream, returning EOS";
     base::ResetAndReturn(&read_cb_).Run(kOk, DecoderBuffer::CreateEOSBuffer());
     return;
   }
+  if (!stream_status_change_cb_.is_null())
+    stream_status_change_cb_.Run(is_enabled_, timestamp);
 }
 
-void FFmpegDemuxerStream::SetStreamRestartedCB(const StreamRestartedCB& cb) {
+void FFmpegDemuxerStream::SetStreamStatusChangeCB(
+    const StreamStatusChangeCB& cb) {
   DCHECK(!cb.is_null());
-  stream_restarted_cb_ = cb;
+  stream_status_change_cb_ = cb;
 }
 
 void FFmpegDemuxerStream::SetLiveness(Liveness liveness) {
diff --git a/media/filters/ffmpeg_demuxer.h b/media/filters/ffmpeg_demuxer.h
index 550316f8..1a95e11 100644
--- a/media/filters/ffmpeg_demuxer.h
+++ b/media/filters/ffmpeg_demuxer.h
@@ -112,7 +112,7 @@
   VideoRotation video_rotation() override;
   bool enabled() const override;
   void set_enabled(bool enabled, base::TimeDelta timestamp) override;
-  void SetStreamRestartedCB(const StreamRestartedCB& cb) override;
+  void SetStreamStatusChangeCB(const StreamStatusChangeCB& cb) override;
 
   void SetLiveness(Liveness liveness);
 
@@ -179,7 +179,7 @@
 
   DecoderBufferQueue buffer_queue_;
   ReadCB read_cb_;
-  StreamRestartedCB stream_restarted_cb_;
+  StreamStatusChangeCB stream_status_change_cb_;
 
 #if defined(USE_PROPRIETARY_CODECS)
   std::unique_ptr<FFmpegBitstreamConverter> bitstream_converter_;
diff --git a/media/gpu/ipc/service/gpu_video_encode_accelerator.cc b/media/gpu/ipc/service/gpu_video_encode_accelerator.cc
index 4c48a9f..23ce04e4 100644
--- a/media/gpu/ipc/service/gpu_video_encode_accelerator.cc
+++ b/media/gpu/ipc/service/gpu_video_encode_accelerator.cc
@@ -36,6 +36,7 @@
 #elif defined(OS_MACOSX)
 #include "media/gpu/vt_video_encode_accelerator_mac.h"
 #elif defined(OS_WIN)
+#include "base/feature_list.h"
 #include "media/base/media_switches.h"
 #include "media/gpu/media_foundation_video_encode_accelerator_win.h"
 #endif
@@ -212,8 +213,7 @@
   create_vea_fps.push_back(&GpuVideoEncodeAccelerator::CreateVTVEA);
 #endif
 #if defined(OS_WIN)
-  if (base::CommandLine::ForCurrentProcess()->HasSwitch(
-          switches::kEnableMFH264Encoding)) {
+  if (base::FeatureList::IsEnabled(kMediaFoundationH264Encoding)) {
     create_vea_fps.push_back(
         &GpuVideoEncodeAccelerator::CreateMediaFoundationVEA);
   }
diff --git a/media/gpu/media_foundation_video_encode_accelerator_win.cc b/media/gpu/media_foundation_video_encode_accelerator_win.cc
index bf292724..9e4b194 100644
--- a/media/gpu/media_foundation_video_encode_accelerator_win.cc
+++ b/media/gpu/media_foundation_video_encode_accelerator_win.cc
@@ -81,7 +81,7 @@
 
 MediaFoundationVideoEncodeAccelerator::
     ~MediaFoundationVideoEncodeAccelerator() {
-  DVLOG(3) << __FUNCTION__;
+  DVLOG(3) << __func__;
   DCHECK(sequence_checker_.CalledOnValidSequence());
 
   DCHECK(!encoder_thread_.IsRunning());
@@ -90,12 +90,17 @@
 
 VideoEncodeAccelerator::SupportedProfiles
 MediaFoundationVideoEncodeAccelerator::GetSupportedProfiles() {
-  DVLOG(3) << __FUNCTION__;
+  TRACE_EVENT0("gpu,startup",
+               "MediaFoundationVideoEncodeAccelerator::GetSupportedProfiles");
+  DVLOG(3) << __func__;
   DCHECK(sequence_checker_.CalledOnValidSequence());
 
   SupportedProfiles profiles;
-  if (base::win::GetVersion() < base::win::VERSION_WIN8) {
-    DLOG(ERROR) << "Windows versions earlier than 8 are not supported.";
+  const bool rv = CreateHardwareEncoderMFT();
+  encoder_.Release();
+  if (!rv) {
+    DVLOG(1)
+        << "Hardware encode acceleration is not available on this platform.";
     return profiles;
   }
 
@@ -116,8 +121,7 @@
     VideoCodecProfile output_profile,
     uint32_t initial_bitrate,
     Client* client) {
-  DVLOG(3) << __FUNCTION__
-           << ": input_format=" << VideoPixelFormatToString(format)
+  DVLOG(3) << __func__ << ": input_format=" << VideoPixelFormatToString(format)
            << ", input_visible_size=" << input_visible_size.ToString()
            << ", output_profile=" << output_profile
            << ", initial_bitrate=" << initial_bitrate;
@@ -134,13 +138,6 @@
     return false;
   }
 
-  for (const wchar_t* mfdll : kMediaFoundationVideoEncoderDLLs) {
-    if (!::GetModuleHandle(mfdll)) {
-      DLOG(ERROR) << mfdll << " is required for encoding";
-      return false;
-    }
-  }
-
   encoder_thread_.init_com_with_mta(false);
   if (!encoder_thread_.Start()) {
     DLOG(ERROR) << "Failed spawning encoder thread.";
@@ -148,25 +145,10 @@
   }
   encoder_thread_task_runner_ = encoder_thread_.task_runner();
 
-  InitializeMediaFoundation();
-
-  uint32_t flags = MFT_ENUM_FLAG_HARDWARE | MFT_ENUM_FLAG_SORTANDFILTER;
-  MFT_REGISTER_TYPE_INFO input_info;
-  input_info.guidMajorType = MFMediaType_Video;
-  input_info.guidSubtype = MFVideoFormat_NV12;
-  MFT_REGISTER_TYPE_INFO output_info;
-  output_info.guidMajorType = MFMediaType_Video;
-  output_info.guidSubtype = MFVideoFormat_H264;
-
-  base::win::ScopedCoMem<CLSID> CLSIDs;
-  uint32_t count = 0;
-  HRESULT hr = MFTEnum(MFT_CATEGORY_VIDEO_ENCODER, flags, NULL, &output_info,
-                       NULL, &CLSIDs, &count);
-  RETURN_ON_HR_FAILURE(hr, "Couldn't enumerate hardware encoder", false);
-  RETURN_ON_FAILURE((count > 0), "No HW encoder found", false);
-  DVLOG(3) << "HW encoder(s) found: " << count;
-  hr = encoder_.CreateInstance(CLSIDs[0]);
-  RETURN_ON_HR_FAILURE(hr, "Couldn't activate hardware encoder", false);
+  if (!CreateHardwareEncoderMFT()) {
+    DLOG(ERROR) << "Failed creating a hardware encoder MFT.";
+    return false;
+  }
 
   client_ptr_factory_.reset(new base::WeakPtrFactory<Client>(client));
   client_ = client_ptr_factory_->GetWeakPtr();
@@ -195,7 +177,8 @@
     return false;
   }
 
-  hr = encoder_->ProcessMessage(MFT_MESSAGE_NOTIFY_BEGIN_STREAMING, NULL);
+  HRESULT hr =
+      encoder_->ProcessMessage(MFT_MESSAGE_NOTIFY_BEGIN_STREAMING, NULL);
   RETURN_ON_HR_FAILURE(hr, "Couldn't set ProcessMessage", false);
 
   client_task_runner_->PostTask(
@@ -208,7 +191,7 @@
 void MediaFoundationVideoEncodeAccelerator::Encode(
     const scoped_refptr<VideoFrame>& frame,
     bool force_keyframe) {
-  DVLOG(3) << __FUNCTION__;
+  DVLOG(3) << __func__;
   DCHECK(sequence_checker_.CalledOnValidSequence());
 
   encoder_thread_task_runner_->PostTask(
@@ -219,7 +202,7 @@
 
 void MediaFoundationVideoEncodeAccelerator::UseOutputBitstreamBuffer(
     const BitstreamBuffer& buffer) {
-  DVLOG(3) << __FUNCTION__ << ": buffer size=" << buffer.size();
+  DVLOG(3) << __func__ << ": buffer size=" << buffer.size();
   DCHECK(sequence_checker_.CalledOnValidSequence());
 
   if (buffer.size() < bitstream_buffer_size_) {
@@ -249,7 +232,7 @@
 void MediaFoundationVideoEncodeAccelerator::RequestEncodingParametersChange(
     uint32_t bitrate,
     uint32_t framerate) {
-  DVLOG(3) << __FUNCTION__ << ": bitrate=" << bitrate
+  DVLOG(3) << __func__ << ": bitrate=" << bitrate
            << ": framerate=" << framerate;
   DCHECK(sequence_checker_.CalledOnValidSequence());
 
@@ -261,7 +244,7 @@
 }
 
 void MediaFoundationVideoEncodeAccelerator::Destroy() {
-  DVLOG(3) << __FUNCTION__;
+  DVLOG(3) << __func__;
   DCHECK(sequence_checker_.CalledOnValidSequence());
 
   // Cancel all callbacks.
@@ -284,6 +267,44 @@
     ::LoadLibrary(mfdll);
 }
 
+bool MediaFoundationVideoEncodeAccelerator::CreateHardwareEncoderMFT() {
+  DVLOG(3) << __func__;
+  DCHECK(sequence_checker_.CalledOnValidSequence());
+
+  if (base::win::GetVersion() < base::win::VERSION_WIN8) {
+    DVLOG(ERROR) << "Windows versions earlier than 8 are not supported.";
+    return false;
+  }
+
+  for (const wchar_t* mfdll : kMediaFoundationVideoEncoderDLLs) {
+    if (!::GetModuleHandle(mfdll)) {
+      DVLOG(ERROR) << mfdll << " is required for encoding";
+      return false;
+    }
+  }
+
+  InitializeMediaFoundation();
+
+  uint32_t flags = MFT_ENUM_FLAG_HARDWARE | MFT_ENUM_FLAG_SORTANDFILTER;
+  MFT_REGISTER_TYPE_INFO input_info;
+  input_info.guidMajorType = MFMediaType_Video;
+  input_info.guidSubtype = MFVideoFormat_NV12;
+  MFT_REGISTER_TYPE_INFO output_info;
+  output_info.guidMajorType = MFMediaType_Video;
+  output_info.guidSubtype = MFVideoFormat_H264;
+
+  base::win::ScopedCoMem<CLSID> CLSIDs;
+  uint32_t count = 0;
+  HRESULT hr = MFTEnum(MFT_CATEGORY_VIDEO_ENCODER, flags, &input_info,
+                       &output_info, NULL, &CLSIDs, &count);
+  RETURN_ON_HR_FAILURE(hr, "Couldn't enumerate hardware encoder", false);
+  RETURN_ON_FAILURE((count > 0), "No HW encoder found", false);
+  DVLOG(3) << "HW encoder(s) found: " << count;
+  hr = encoder_.CreateInstance(CLSIDs[0]);
+  RETURN_ON_HR_FAILURE(hr, "Couldn't activate hardware encoder", false);
+  return true;
+}
+
 bool MediaFoundationVideoEncodeAccelerator::InitializeInputOutputSamples() {
   DCHECK(sequence_checker_.CalledOnValidSequence());
 
@@ -383,7 +404,7 @@
 void MediaFoundationVideoEncodeAccelerator::EncodeTask(
     const scoped_refptr<VideoFrame>& frame,
     bool force_keyframe) {
-  DVLOG(3) << __FUNCTION__;
+  DVLOG(3) << __func__;
   DCHECK(encoder_thread_task_runner_->BelongsToCurrentThread());
 
   base::win::ScopedComPtr<IMFMediaBuffer> input_buffer;
@@ -430,7 +451,7 @@
 }
 
 void MediaFoundationVideoEncodeAccelerator::ProcessOutput() {
-  DVLOG(3) << __FUNCTION__;
+  DVLOG(3) << __func__;
   DCHECK(encoder_thread_task_runner_->BelongsToCurrentThread());
 
   MFT_OUTPUT_DATA_BUFFER output_data_buffer = {0};
@@ -493,7 +514,7 @@
 
 void MediaFoundationVideoEncodeAccelerator::UseOutputBitstreamBufferTask(
     std::unique_ptr<BitstreamBufferRef> buffer_ref) {
-  DVLOG(3) << __FUNCTION__;
+  DVLOG(3) << __func__;
   DCHECK(encoder_thread_task_runner_->BelongsToCurrentThread());
 
   // If there is already EncodeOutput waiting, copy its output first.
@@ -512,7 +533,7 @@
     std::unique_ptr<EncodeOutput> encode_output,
     std::unique_ptr<MediaFoundationVideoEncodeAccelerator::BitstreamBufferRef>
         buffer_ref) {
-  DVLOG(3) << __FUNCTION__;
+  DVLOG(3) << __func__;
   DCHECK(encoder_thread_task_runner_->BelongsToCurrentThread());
 
   memcpy(buffer_ref->shm->memory(), encode_output->memory(),
@@ -527,7 +548,7 @@
 void MediaFoundationVideoEncodeAccelerator::RequestEncodingParametersChangeTask(
     uint32_t bitrate,
     uint32_t framerate) {
-  DVLOG(3) << __FUNCTION__;
+  DVLOG(3) << __func__;
   DCHECK(encoder_thread_task_runner_->BelongsToCurrentThread());
 
   frame_rate_ = framerate ? framerate : 1;
@@ -550,7 +571,7 @@
 }
 
 void MediaFoundationVideoEncodeAccelerator::DestroyTask() {
-  DVLOG(3) << __FUNCTION__;
+  DVLOG(3) << __func__;
   DCHECK(encoder_thread_task_runner_->BelongsToCurrentThread());
 
   // Cancel all encoder thread callbacks.
diff --git a/media/gpu/media_foundation_video_encode_accelerator_win.h b/media/gpu/media_foundation_video_encode_accelerator_win.h
index f6b9a0d..d820e9d 100644
--- a/media/gpu/media_foundation_video_encode_accelerator_win.h
+++ b/media/gpu/media_foundation_video_encode_accelerator_win.h
@@ -62,6 +62,9 @@
   // Holds output buffers coming from the encoder.
   class EncodeOutput;
 
+  // Creates an hardware encoder backed IMFTransform instance on |encoder_|.
+  bool CreateHardwareEncoderMFT();
+
   // Initializes and allocates memory for input and output samples.
   bool InitializeInputOutputSamples();
 
diff --git a/media/mojo/services/mojo_demuxer_stream_adapter.cc b/media/mojo/services/mojo_demuxer_stream_adapter.cc
index 1a5a09f..f302a2ce 100644
--- a/media/mojo/services/mojo_demuxer_stream_adapter.cc
+++ b/media/mojo/services/mojo_demuxer_stream_adapter.cc
@@ -79,8 +79,8 @@
   NOTIMPLEMENTED();
 }
 
-void MojoDemuxerStreamAdapter::SetStreamRestartedCB(
-    const StreamRestartedCB& cb) {
+void MojoDemuxerStreamAdapter::SetStreamStatusChangeCB(
+    const StreamStatusChangeCB& cb) {
   NOTIMPLEMENTED();
 }
 
diff --git a/media/mojo/services/mojo_demuxer_stream_adapter.h b/media/mojo/services/mojo_demuxer_stream_adapter.h
index 43a97131..a195954 100644
--- a/media/mojo/services/mojo_demuxer_stream_adapter.h
+++ b/media/mojo/services/mojo_demuxer_stream_adapter.h
@@ -46,7 +46,7 @@
   VideoRotation video_rotation() override;
   bool enabled() const override;
   void set_enabled(bool enabled, base::TimeDelta timestamp) override;
-  void SetStreamRestartedCB(const StreamRestartedCB& cb) override;
+  void SetStreamStatusChangeCB(const StreamStatusChangeCB& cb) override;
 
  private:
   void OnStreamReady(mojom::DemuxerStream::Type type,
diff --git a/media/renderers/renderer_impl.cc b/media/renderers/renderer_impl.cc
index 007b4b0..7381e94e 100644
--- a/media/renderers/renderer_impl.cc
+++ b/media/renderers/renderer_impl.cc
@@ -134,13 +134,13 @@
   DemuxerStream* audio_stream =
       demuxer_stream_provider->GetStream(DemuxerStream::AUDIO);
   if (audio_stream)
-    audio_stream->SetStreamRestartedCB(
-        base::Bind(&RendererImpl::RestartStreamPlayback, weak_this_));
+    audio_stream->SetStreamStatusChangeCB(base::Bind(
+        &RendererImpl::RestartStreamPlayback, weak_this_, audio_stream));
   DemuxerStream* video_stream =
       demuxer_stream_provider->GetStream(DemuxerStream::VIDEO);
   if (video_stream)
-    video_stream->SetStreamRestartedCB(
-        base::Bind(&RendererImpl::RestartStreamPlayback, weak_this_));
+    video_stream->SetStreamStatusChangeCB(base::Bind(
+        &RendererImpl::RestartStreamPlayback, weak_this_, video_stream));
 
   if (HasEncryptedStream() && !cdm_context_) {
     state_ = STATE_INIT_PENDING_CDM;
@@ -215,9 +215,13 @@
 }
 
 void RendererImpl::RestartStreamPlayback(DemuxerStream* stream,
+                                         bool enabled,
                                          base::TimeDelta time) {
-  DVLOG(1) << __func__ << " stream=" << stream << " time=" << time.InSecondsF();
   DCHECK(task_runner_->BelongsToCurrentThread());
+  DCHECK(stream);
+  bool video = (stream->type() == DemuxerStream::VIDEO);
+  DVLOG(1) << __func__ << (video ? " video" : " audio") << " stream=" << stream
+           << " enabled=" << stream->enabled() << " time=" << time.InSecondsF();
   if (state_ != STATE_PLAYING)
     return;
   if (stream->type() == DemuxerStream::VIDEO) {
@@ -246,24 +250,22 @@
 }
 
 void RendererImpl::RestartVideoRenderer(base::TimeDelta time) {
+  DVLOG(3) << __func__;
   DCHECK(task_runner_->BelongsToCurrentThread());
-  DVLOG(2) << __func__;
+  DCHECK(video_renderer_);
+  DCHECK_EQ(state_, STATE_PLAYING);
   video_ended_ = false;
-  if (state_ == STATE_PLAYING) {
-    DCHECK(video_renderer_);
-    video_renderer_->StartPlayingFrom(time);
-  }
+  video_renderer_->StartPlayingFrom(time);
 }
 
 void RendererImpl::RestartAudioRenderer(base::TimeDelta time) {
+  DVLOG(3) << __func__;
   DCHECK(task_runner_->BelongsToCurrentThread());
-  DVLOG(2) << __func__;
+  DCHECK_EQ(state_, STATE_PLAYING);
+  DCHECK(time_source_);
+  DCHECK(audio_renderer_);
   audio_ended_ = false;
-  if (state_ == STATE_PLAYING) {
-    DCHECK(time_source_);
-    DCHECK(audio_renderer_);
-    audio_renderer_->StartPlaying();
-  }
+  audio_renderer_->StartPlaying();
 }
 
 void RendererImpl::SetPlaybackRate(double playback_rate) {
diff --git a/media/renderers/renderer_impl.h b/media/renderers/renderer_impl.h
index 76c496a..0752805f 100644
--- a/media/renderers/renderer_impl.h
+++ b/media/renderers/renderer_impl.h
@@ -62,7 +62,9 @@
   bool HasAudio() final;
   bool HasVideo() final;
 
-  void RestartStreamPlayback(DemuxerStream* stream, base::TimeDelta time);
+  void RestartStreamPlayback(DemuxerStream* stream,
+                             bool enabled,
+                             base::TimeDelta time);
 
   // Helper functions for testing purposes. Must be called before Initialize().
   void DisableUnderflowForTesting();
diff --git a/media/renderers/renderer_impl_unittest.cc b/media/renderers/renderer_impl_unittest.cc
index 62d6f85..1a280e1 100644
--- a/media/renderers/renderer_impl_unittest.cc
+++ b/media/renderers/renderer_impl_unittest.cc
@@ -87,7 +87,8 @@
       DemuxerStream::Type type) {
     std::unique_ptr<StrictMock<MockDemuxerStream>> stream(
         new StrictMock<MockDemuxerStream>(type));
-    EXPECT_CALL(*stream, SetStreamRestartedCB(_)).Times(testing::AnyNumber());
+    EXPECT_CALL(*stream, SetStreamStatusChangeCB(_))
+        .Times(testing::AnyNumber());
     return stream;
   }
 
@@ -713,4 +714,31 @@
   base::RunLoop().RunUntilIdle();
 }
 
+TEST_F(RendererImplTest, StreamStatusNotificationHandling) {
+  CreateAudioAndVideoStream();
+
+  DemuxerStream::StreamStatusChangeCB audio_stream_status_change_cb;
+  DemuxerStream::StreamStatusChangeCB video_stream_status_change_cb;
+  EXPECT_CALL(*audio_stream_, SetStreamStatusChangeCB(_))
+      .WillOnce(SaveArg<0>(&audio_stream_status_change_cb));
+  EXPECT_CALL(*video_stream_, SetStreamStatusChangeCB(_))
+      .WillOnce(SaveArg<0>(&video_stream_status_change_cb));
+  SetAudioRendererInitializeExpectations(PIPELINE_OK);
+  SetVideoRendererInitializeExpectations(PIPELINE_OK);
+  InitializeAndExpect(PIPELINE_OK);
+  Play();
+
+  // Verify that DemuxerStream status changes cause the corresponding
+  // audio/video renderer to be flushed and restarted.
+  base::TimeDelta time0;
+  EXPECT_CALL(time_source_, StopTicking());
+  EXPECT_CALL(*audio_renderer_, Flush(_)).WillOnce(RunClosure<0>());
+  EXPECT_CALL(*audio_renderer_, StartPlaying()).Times(1);
+  audio_stream_status_change_cb.Run(false, time0);
+
+  EXPECT_CALL(*video_renderer_, Flush(_)).WillOnce(RunClosure<0>());
+  EXPECT_CALL(*video_renderer_, StartPlayingFrom(_)).Times(1);
+  video_stream_status_change_cb.Run(false, time0);
+}
+
 }  // namespace media
diff --git a/mojo/android/javatests/validation_test_util.cc b/mojo/android/javatests/validation_test_util.cc
index 69ad15c5..989291d0 100644
--- a/mojo/android/javatests/validation_test_util.cc
+++ b/mojo/android/javatests/validation_test_util.cc
@@ -37,7 +37,7 @@
           input, &data, &num_handles, &error_message)) {
     ScopedJavaLocalRef<jstring> j_error_message =
         base::android::ConvertUTF8ToJavaString(env, error_message);
-    return Java_ValidationTestUtil_buildData(env, NULL, 0,
+    return Java_ValidationTestUtil_buildData(env, nullptr, 0,
                                              j_error_message.obj());
   }
   void* data_ptr = &data[0];
@@ -47,7 +47,8 @@
   }
   jobject byte_buffer =
       env->NewDirectByteBuffer(data_ptr, data.size());
-  return Java_ValidationTestUtil_buildData(env, byte_buffer, num_handles, NULL);
+  return Java_ValidationTestUtil_buildData(env, byte_buffer, num_handles,
+                                           nullptr);
 }
 
 }  // namespace android
diff --git a/mojo/public/tools/bindings/generators/cpp_templates/struct_declaration.tmpl b/mojo/public/tools/bindings/generators/cpp_templates/struct_declaration.tmpl
index 28d6399..3d97ccb7 100644
--- a/mojo/public/tools/bindings/generators/cpp_templates/struct_declaration.tmpl
+++ b/mojo/public/tools/bindings/generators/cpp_templates/struct_declaration.tmpl
@@ -48,7 +48,8 @@
 {%- endif %}
 
  private:
-  {{class_name}}();
+  {{class_name}}() : header_({sizeof(*this), {{struct.versions[-1].version}}}) {
+  }
   ~{{class_name}}() = delete;
 };
 static_assert(sizeof({{class_name}}) == {{struct.versions[-1].num_bytes}},
diff --git a/mojo/public/tools/bindings/generators/cpp_templates/struct_definition.tmpl b/mojo/public/tools/bindings/generators/cpp_templates/struct_definition.tmpl
index b5f4462..374b097 100644
--- a/mojo/public/tools/bindings/generators/cpp_templates/struct_definition.tmpl
+++ b/mojo/public/tools/bindings/generators/cpp_templates/struct_definition.tmpl
@@ -68,7 +68,3 @@
   return true;
 }
 
-{{class_name}}::{{class_name}}() {
-  header_.num_bytes = sizeof(*this);
-  header_.version = {{struct.versions[-1].version}};
-}
diff --git a/net/BUILD.gn b/net/BUILD.gn
index 423bbed3..ec96909 100644
--- a/net/BUILD.gn
+++ b/net/BUILD.gn
@@ -380,10 +380,7 @@
     if (use_platform_icu_alternatives) {
       if (is_android) {
         # Use ICU alternative on Android.
-        sources += [
-          "base/net_string_util_icu_alternatives_android.cc",
-          "base/net_string_util_icu_alternatives_android.h",
-        ]
+        sources += [ "base/net_string_util_icu_alternatives_android.cc" ]
         deps += [ ":net_jni_headers" ]
       } else if (is_ios) {
         # Use ICU alternative on iOS.
diff --git a/net/android/net_jni_registrar.cc b/net/android/net_jni_registrar.cc
index 48a1314..dfa5aef 100644
--- a/net/android/net_jni_registrar.cc
+++ b/net/android/net_jni_registrar.cc
@@ -14,10 +14,6 @@
 #include "net/proxy/proxy_config_service_android.h"
 #include "url/url_features.h"
 
-#if BUILDFLAG(USE_PLATFORM_ICU_ALTERNATIVES)
-#include "net/base/net_string_util_icu_alternatives_android.h"  // nogncheck
-#endif
-
 namespace net {
 namespace android {
 
@@ -27,9 +23,6 @@
     {"NetworkChangeNotifierAndroid", NetworkChangeNotifierAndroid::Register},
     {"ProxyConfigService", ProxyConfigServiceAndroid::Register},
     {"X509Util", RegisterX509Util},
-#if BUILDFLAG(USE_PLATFORM_ICU_ALTERNATIVES)
-    {"NetStringUtils", RegisterNetStringUtils}
-#endif
 };
 
 bool RegisterJni(JNIEnv* env) {
diff --git a/net/base/net_string_util_icu_alternatives_android.cc b/net/base/net_string_util_icu_alternatives_android.cc
index 0551a03..237b698 100644
--- a/net/base/net_string_util_icu_alternatives_android.cc
+++ b/net/base/net_string_util_icu_alternatives_android.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 "net/base/net_string_util_icu_alternatives_android.h"
-
 #include "base/android/jni_android.h"
 #include "base/android/jni_string.h"
 #include "base/strings/string16.h"
@@ -113,8 +111,4 @@
   return true;
 }
 
-bool RegisterNetStringUtils(JNIEnv* env) {
-  return android::RegisterNativesImpl(env);
-}
-
 }  // namespace net
diff --git a/net/base/net_string_util_icu_alternatives_android.h b/net/base/net_string_util_icu_alternatives_android.h
deleted file mode 100644
index c3a6cf50..0000000
--- a/net/base/net_string_util_icu_alternatives_android.h
+++ /dev/null
@@ -1,18 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef NET_BASE_NET_STRING_UTIL_ICU_ALTERNATIVES_ANDROID_H_
-#define NET_BASE_NET_STRING_UTIL_ICU_ALTERNATIVES_ANDROID_H_
-
-#include <jni.h>
-
-namespace net {
-
-// Explicitly register static JNI functions needed when not using ICU.
-bool RegisterNetStringUtils(JNIEnv* env);
-
-}  // namespace net
-
-#endif  // NET_BASE_NET_STRING_UTIL_ICU_ALTERNATIVES_ANDROID_H_
-
diff --git a/net/cert/x509_certificate_openssl.cc b/net/cert/x509_certificate_openssl.cc
index c2bd6aa..e22ea9f0 100644
--- a/net/cert/x509_certificate_openssl.cc
+++ b/net/cert/x509_certificate_openssl.cc
@@ -180,7 +180,8 @@
 X509Certificate::OSCertHandle X509Certificate::DupOSCertHandle(
     OSCertHandle cert_handle) {
   DCHECK(cert_handle);
-  return X509_up_ref(cert_handle);
+  X509_up_ref(cert_handle);
+  return cert_handle;
 }
 
 // static
diff --git a/net/net.gyp b/net/net.gyp
index e630835..ca18939b6 100644
--- a/net/net.gyp
+++ b/net/net.gyp
@@ -117,7 +117,6 @@
             ['OS == "android"', {
               'sources': [
                 'base/net_string_util_icu_alternatives_android.cc',
-                'base/net_string_util_icu_alternatives_android.h',
               ],
             }],
             ['OS == "ios"', {
diff --git a/net/net.gypi b/net/net.gypi
index 19b1d36..9e1397e5 100644
--- a/net/net.gypi
+++ b/net/net.gypi
@@ -1803,6 +1803,8 @@
       'spdy/spdy_http_stream_unittest.cc',
       'spdy/spdy_http_utils_unittest.cc',
       'spdy/spdy_network_transaction_unittest.cc',
+      'spdy/spdy_no_op_visitor.h',
+      'spdy/spdy_no_op_visitor.cc',
       'spdy/spdy_pinnable_buffer_piece_test.cc',
       'spdy/spdy_prefixed_buffer_reader_test.cc',
       'spdy/spdy_protocol_test.cc',
diff --git a/net/nqe/effective_connection_type.h b/net/nqe/effective_connection_type.h
index 0088c52..6160a4d 100644
--- a/net/nqe/effective_connection_type.h
+++ b/net/nqe/effective_connection_type.h
@@ -15,12 +15,6 @@
 // EffectiveConnectionType of a network is independent of if the current
 // connection is metered or not. For example, an unmetered slow connection may
 // have EFFECTIVE_CONNECTION_TYPE_SLOW_2G as its effective connection type.
-// An invalid Java prefix to strip is specified to prevent the Java class
-// generator from automatically stripping off the common prefix
-// ("EFFECTIVE_CONNECTION_TYPE_").
-// GENERATED_JAVA_ENUM_PACKAGE: org.chromium.net
-// GENERATED_JAVA_CLASS_NAME_OVERRIDE: ChromiumEffectiveConnectionType
-// GENERATED_JAVA_PREFIX_TO_STRIP: PREFIX_NOT_PRESENT_
 enum EffectiveConnectionType {
   // The connection types should be in increasing order of quality.
   EFFECTIVE_CONNECTION_TYPE_UNKNOWN = 0,
diff --git a/net/nqe/network_quality_estimator.cc b/net/nqe/network_quality_estimator.cc
index dbf4986..96c0f3c9 100644
--- a/net/nqe/network_quality_estimator.cc
+++ b/net/nqe/network_quality_estimator.cc
@@ -1647,14 +1647,10 @@
   // last computed or a connection change event was observed since the last
   // computation. Strict inequalities are used to ensure that effective
   // connection type is recomputed on connection change events even if the clock
-  // has not updated. Recompute the effective connection type if the effective
-  // connection type was previously unavailable. This is because the RTT
-  // observations are voluminous, so it may now be possible to compute the
-  // effective connection type.
+  // has not updated.
   if (now - last_effective_connection_type_computation_ <
           effective_connection_type_recomputation_interval_ &&
-      last_connection_change_ < last_effective_connection_type_computation_ &&
-      effective_connection_type_ != EFFECTIVE_CONNECTION_TYPE_UNKNOWN) {
+      last_connection_change_ < last_effective_connection_type_computation_) {
     return;
   }
 
@@ -1669,7 +1665,6 @@
 void NetworkQualityEstimator::
     NotifyObserversOfEffectiveConnectionTypeChanged() {
   DCHECK(thread_checker_.CalledOnValidThread());
-  DCHECK_NE(EFFECTIVE_CONNECTION_TYPE_LAST, effective_connection_type_);
 
   // TODO(tbansal): Add hysteresis in the notification.
   FOR_EACH_OBSERVER(
diff --git a/net/quic/chromium/quic_chromium_client_session.cc b/net/quic/chromium/quic_chromium_client_session.cc
index 5983029..3c0aad5 100644
--- a/net/quic/chromium/quic_chromium_client_session.cc
+++ b/net/quic/chromium/quic_chromium_client_session.cc
@@ -798,17 +798,19 @@
 void QuicChromiumClientSession::OnCryptoHandshakeMessageSent(
     const CryptoHandshakeMessage& message) {
   logger_->OnCryptoHandshakeMessageSent(message);
-
-  if (message.tag() == kREJ || message.tag() == kSREJ) {
-    UMA_HISTOGRAM_CUSTOM_COUNTS("Net.QuicSession.RejectLength",
-                                message.GetSerialized().length(), 1000, 10000,
-                                50);
-  }
 }
 
 void QuicChromiumClientSession::OnCryptoHandshakeMessageReceived(
     const CryptoHandshakeMessage& message) {
   logger_->OnCryptoHandshakeMessageReceived(message);
+  if (message.tag() == kREJ || message.tag() == kSREJ) {
+    UMA_HISTOGRAM_CUSTOM_COUNTS("Net.QuicSession.RejectLength",
+                                message.GetSerialized().length(), 1000, 10000,
+                                50);
+    base::StringPiece proof;
+    UMA_HISTOGRAM_BOOLEAN("Net.QuicSession.RejectHasProof",
+                          message.GetStringPiece(kPROF, &proof));
+  }
 }
 
 void QuicChromiumClientSession::OnGoAway(const QuicGoAwayFrame& frame) {
diff --git a/net/quic/chromium/quic_stream_factory.cc b/net/quic/chromium/quic_stream_factory.cc
index d3cafeb..a805a87a 100644
--- a/net/quic/chromium/quic_stream_factory.cc
+++ b/net/quic/chromium/quic_stream_factory.cc
@@ -54,6 +54,8 @@
 #include "net/socket/socket_performance_watcher_factory.h"
 #include "net/ssl/token_binding.h"
 #include "net/udp/udp_client_socket.h"
+#include "url/gurl.h"
+#include "url/url_constants.h"
 
 using std::min;
 using NetworkHandle = net::NetworkChangeNotifier::NetworkHandle;
@@ -167,6 +169,28 @@
   return config;
 }
 
+// An implementation of QuicCryptoClientConfig::ServerIdFilter that wraps
+// an |origin_filter|.
+class ServerIdOriginFilter : public QuicCryptoClientConfig::ServerIdFilter {
+ public:
+  ServerIdOriginFilter(const base::Callback<bool(const GURL&)> origin_filter)
+      : origin_filter_(origin_filter) {}
+
+  bool Matches(const QuicServerId& server_id) const override {
+    if (origin_filter_.is_null())
+      return true;
+
+    GURL url(base::StringPrintf("%s%s%s:%d", url::kHttpsScheme,
+                                url::kStandardSchemeSeparator,
+                                server_id.host().c_str(), server_id.port()));
+    DCHECK(url.is_valid());
+    return origin_filter_.Run(url);
+  }
+
+ private:
+  const base::Callback<bool(const GURL&)> origin_filter_;
+};
+
 }  // namespace
 
 // Responsible for verifying the certificates saved in
@@ -1413,8 +1437,10 @@
   return std::move(list);
 }
 
-void QuicStreamFactory::ClearCachedStatesInCryptoConfig() {
-  crypto_config_.ClearCachedStates();
+void QuicStreamFactory::ClearCachedStatesInCryptoConfig(
+    const base::Callback<bool(const GURL&)>& origin_filter) {
+  ServerIdOriginFilter filter(origin_filter);
+  crypto_config_.ClearCachedStates(filter);
 }
 
 void QuicStreamFactory::OnIPAddressChanged() {
diff --git a/net/quic/chromium/quic_stream_factory.h b/net/quic/chromium/quic_stream_factory.h
index fad86df..4a28209 100644
--- a/net/quic/chromium/quic_stream_factory.h
+++ b/net/quic/chromium/quic_stream_factory.h
@@ -264,8 +264,10 @@
 
   std::unique_ptr<base::Value> QuicStreamFactoryInfoToValue() const;
 
-  // Delete all cached state objects in |crypto_config_|.
-  void ClearCachedStatesInCryptoConfig();
+  // Delete cached state objects in |crypto_config_|. If |origin_filter| is not
+  // null, only objects on matching origins will be deleted.
+  void ClearCachedStatesInCryptoConfig(
+      const base::Callback<bool(const GURL&)>& origin_filter);
 
   // Helper method that configures a DatagramClientSocket. Socket is
   // bound to the default network if the |network| param is
diff --git a/net/quic/chromium/quic_stream_factory_test.cc b/net/quic/chromium/quic_stream_factory_test.cc
index 0528ca2c..165bb0e 100644
--- a/net/quic/chromium/quic_stream_factory_test.cc
+++ b/net/quic/chromium/quic_stream_factory_test.cc
@@ -7,6 +7,8 @@
 #include <ostream>
 #include <utility>
 
+#include "base/bind.h"
+#include "base/callback.h"
 #include "base/run_loop.h"
 #include "base/strings/string_util.h"
 #include "base/threading/thread_task_runner_handle.h"
@@ -46,6 +48,7 @@
 #include "net/test/test_data_directory.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "url/gurl.h"
 
 using net::test::IsError;
 using net::test::IsOk;
@@ -4876,5 +4879,52 @@
   EXPECT_TRUE(AllDataConsumed());
 }
 
+// This test verifies that QuicStreamFactory::ClearCachedStatesInCryptoConfig
+// correctly transform an origin filter to a ServerIdFilter. Whether the
+// deletion itself works correctly is tested in QuicCryptoClientConfigTest.
+TEST_P(QuicStreamFactoryTest, ClearCachedStatesInCryptoConfig) {
+  Initialize();
+  QuicCryptoClientConfig* crypto_config =
+      QuicStreamFactoryPeer::GetCryptoConfig(factory_.get());
+
+  struct TestCase {
+    TestCase(const std::string& host,
+             int port,
+             PrivacyMode privacy_mode,
+             QuicCryptoClientConfig* crypto_config)
+        : server_id(host, port, privacy_mode),
+          state(crypto_config->LookupOrCreate(server_id)) {
+      vector<string> certs(1);
+      certs[0] = "cert";
+      state->SetProof(certs, "cert_sct", "chlo_hash", "signature");
+      state->set_source_address_token("TOKEN");
+      state->SetProofValid();
+
+      EXPECT_FALSE(state->certs().empty());
+    }
+
+    QuicServerId server_id;
+    QuicCryptoClientConfig::CachedState* state;
+  } test_cases[] = {
+      TestCase("www.google.com", 443, privacy_mode_, crypto_config),
+      TestCase("www.example.com", 443, privacy_mode_, crypto_config),
+      TestCase("www.example.com", 4433, privacy_mode_, crypto_config)};
+
+  // Clear cached states for the origin https://www.example.com:4433.
+  GURL origin("https://www.example.com:4433");
+  factory_->ClearCachedStatesInCryptoConfig(
+      base::Bind(&GURL::operator==, base::Unretained(&origin)));
+  EXPECT_FALSE(test_cases[0].state->certs().empty());
+  EXPECT_FALSE(test_cases[1].state->certs().empty());
+  EXPECT_TRUE(test_cases[2].state->certs().empty());
+
+  // Clear all cached states.
+  factory_->ClearCachedStatesInCryptoConfig(
+      base::Callback<bool(const GURL&)>());
+  EXPECT_TRUE(test_cases[0].state->certs().empty());
+  EXPECT_TRUE(test_cases[1].state->certs().empty());
+  EXPECT_TRUE(test_cases[2].state->certs().empty());
+}
+
 }  // namespace test
 }  // namespace net
diff --git a/net/quic/core/crypto/quic_crypto_client_config.cc b/net/quic/core/crypto/quic_crypto_client_config.cc
index bf67be53..47c03a7 100644
--- a/net/quic/core/crypto/quic_crypto_client_config.cc
+++ b/net/quic/core/crypto/quic_crypto_client_config.cc
@@ -400,10 +400,11 @@
   return cached;
 }
 
-void QuicCryptoClientConfig::ClearCachedStates() {
+void QuicCryptoClientConfig::ClearCachedStates(const ServerIdFilter& filter) {
   for (CachedStateMap::const_iterator it = cached_states_.begin();
        it != cached_states_.end(); ++it) {
-    it->second->Clear();
+    if (filter.Matches(it->first))
+      it->second->Clear();
   }
 }
 
diff --git a/net/quic/core/crypto/quic_crypto_client_config.h b/net/quic/core/crypto/quic_crypto_client_config.h
index 56f996f..b671793 100644
--- a/net/quic/core/crypto/quic_crypto_client_config.h
+++ b/net/quic/core/crypto/quic_crypto_client_config.h
@@ -194,6 +194,13 @@
     DISALLOW_COPY_AND_ASSIGN(CachedState);
   };
 
+  // Used to filter server ids for partial config deletion.
+  class ServerIdFilter {
+   public:
+    // Returns true if |server_id| matches the filter.
+    virtual bool Matches(const QuicServerId& server_id) const = 0;
+  };
+
   explicit QuicCryptoClientConfig(
       std::unique_ptr<ProofVerifier> proof_verifier);
   ~QuicCryptoClientConfig();
@@ -202,8 +209,9 @@
   // CachedState currently exists, it will be created and cached.
   CachedState* LookupOrCreate(const QuicServerId& server_id);
 
-  // Delete all CachedState objects from cached_states_.
-  void ClearCachedStates();
+  // Delete CachedState objects whose server ids match |filter| from
+  // cached_states.
+  void ClearCachedStates(const ServerIdFilter& filter);
 
   // FillInchoateClientHello sets |out| to be a CHLO message that elicits a
   // source-address token or SCFG from a server. If |cached| is non-nullptr, the
diff --git a/net/quic/core/crypto/quic_crypto_client_config_test.cc b/net/quic/core/crypto/quic_crypto_client_config_test.cc
index c4656972..9555dd1 100644
--- a/net/quic/core/crypto/quic_crypto_client_config_test.cc
+++ b/net/quic/core/crypto/quic_crypto_client_config_test.cc
@@ -27,6 +27,23 @@
   }
 };
 
+class OneServerIdFilter : public QuicCryptoClientConfig::ServerIdFilter {
+ public:
+  OneServerIdFilter(const QuicServerId* server_id) : server_id_(*server_id) {}
+
+  bool Matches(const QuicServerId& server_id) const override {
+    return server_id == server_id_;
+  }
+
+ private:
+  const QuicServerId server_id_;
+};
+
+class AllServerIdsFilter : public QuicCryptoClientConfig::ServerIdFilter {
+ public:
+  bool Matches(const QuicServerId& server_id) const override { return true; }
+};
+
 }  // namespace
 
 TEST(QuicCryptoClientConfigTest, CachedState_IsEmpty) {
@@ -325,36 +342,88 @@
 
 TEST(QuicCryptoClientConfigTest, ClearCachedStates) {
   QuicCryptoClientConfig config(CryptoTestUtils::ProofVerifierForTesting());
-  QuicServerId server_id("www.google.com", 443, PRIVACY_MODE_DISABLED);
-  QuicCryptoClientConfig::CachedState* state = config.LookupOrCreate(server_id);
-  // TODO(rch): Populate other fields of |state|.
-  vector<string> certs(1);
-  certs[0] = "Hello Cert";
-  state->SetProof(certs, "cert_sct", "chlo_hash", "signature");
-  state->set_source_address_token("TOKEN");
-  state->SetProofValid();
-  EXPECT_EQ(1u, state->generation_counter());
+
+  // Create two states on different origins.
+  struct TestCase {
+    TestCase(const std::string& host, QuicCryptoClientConfig* config)
+        : server_id(host, 443, PRIVACY_MODE_DISABLED),
+          state(config->LookupOrCreate(server_id)) {
+      // TODO(rch): Populate other fields of |state|.
+      CryptoHandshakeMessage scfg;
+      scfg.set_tag(kSCFG);
+      uint64_t future = 1;
+      scfg.SetValue(kEXPY, future);
+      scfg.SetStringPiece(kSCID, "12345678");
+      string details;
+      state->SetServerConfig(scfg.GetSerialized().AsStringPiece(),
+                             QuicWallTime::FromUNIXSeconds(0), &details);
+
+      vector<string> certs(1);
+      certs[0] = "Hello Cert for " + host;
+      state->SetProof(certs, "cert_sct", "chlo_hash", "signature");
+      state->set_source_address_token("TOKEN");
+      state->SetProofValid();
+
+      // The generation counter starts at 2, because proof has been once
+      // invalidated in SetServerConfig().
+      EXPECT_EQ(2u, state->generation_counter());
+    }
+
+    QuicServerId server_id;
+    QuicCryptoClientConfig::CachedState* state;
+  } test_cases[] = {TestCase("www.google.com", &config),
+                    TestCase("www.example.com", &config)};
 
   // Verify LookupOrCreate returns the same data.
-  QuicCryptoClientConfig::CachedState* other = config.LookupOrCreate(server_id);
+  for (const TestCase& test_case : test_cases) {
+    QuicCryptoClientConfig::CachedState* other =
+        config.LookupOrCreate(test_case.server_id);
+    EXPECT_EQ(test_case.state, other);
+    EXPECT_EQ(2u, other->generation_counter());
+  }
 
-  EXPECT_EQ(state, other);
-  EXPECT_EQ(1u, other->generation_counter());
+  // Clear the cached state for www.google.com.
+  OneServerIdFilter google_com_filter(&test_cases[0].server_id);
+  config.ClearCachedStates(google_com_filter);
 
-  // Clear the cached states.
-  config.ClearCachedStates();
-
-  // Verify LookupOrCreate doesn't have any data.
+  // Verify LookupOrCreate doesn't have any data for google.com.
   QuicCryptoClientConfig::CachedState* cleared_cache =
-      config.LookupOrCreate(server_id);
+      config.LookupOrCreate(test_cases[0].server_id);
 
-  EXPECT_EQ(state, cleared_cache);
+  EXPECT_EQ(test_cases[0].state, cleared_cache);
   EXPECT_FALSE(cleared_cache->proof_valid());
   EXPECT_TRUE(cleared_cache->server_config().empty());
   EXPECT_TRUE(cleared_cache->certs().empty());
   EXPECT_TRUE(cleared_cache->cert_sct().empty());
   EXPECT_TRUE(cleared_cache->signature().empty());
-  EXPECT_EQ(2u, cleared_cache->generation_counter());
+  EXPECT_EQ(3u, cleared_cache->generation_counter());
+
+  // But it still does for www.example.com.
+  QuicCryptoClientConfig::CachedState* existing_cache =
+      config.LookupOrCreate(test_cases[1].server_id);
+
+  EXPECT_EQ(test_cases[1].state, existing_cache);
+  EXPECT_TRUE(existing_cache->proof_valid());
+  EXPECT_FALSE(existing_cache->server_config().empty());
+  EXPECT_FALSE(existing_cache->certs().empty());
+  EXPECT_FALSE(existing_cache->cert_sct().empty());
+  EXPECT_FALSE(existing_cache->signature().empty());
+  EXPECT_EQ(2u, existing_cache->generation_counter());
+
+  // Clear all cached states.
+  AllServerIdsFilter all_server_ids;
+  config.ClearCachedStates(all_server_ids);
+
+  // The data for www.example.com should now be cleared as well.
+  cleared_cache = config.LookupOrCreate(test_cases[1].server_id);
+
+  EXPECT_EQ(test_cases[1].state, cleared_cache);
+  EXPECT_FALSE(cleared_cache->proof_valid());
+  EXPECT_TRUE(cleared_cache->server_config().empty());
+  EXPECT_TRUE(cleared_cache->certs().empty());
+  EXPECT_TRUE(cleared_cache->cert_sct().empty());
+  EXPECT_TRUE(cleared_cache->signature().empty());
+  EXPECT_EQ(3u, cleared_cache->generation_counter());
 }
 
 TEST(QuicCryptoClientConfigTest, ProcessReject) {
diff --git a/net/spdy/spdy_headers_handler_interface.h b/net/spdy/spdy_headers_handler_interface.h
index 99944c67..2c48abfe 100644
--- a/net/spdy/spdy_headers_handler_interface.h
+++ b/net/spdy/spdy_headers_handler_interface.h
@@ -28,7 +28,7 @@
   virtual void OnHeader(base::StringPiece key, base::StringPiece value) = 0;
 
   // A callback method which notifies when the parser finishes handling a
-  // header block (i.e. the containing frame has the END_STREAM flag set).
+  // header block (i.e. the containing frame has the END_HEADERS flag set).
   // Also indicates the total number of bytes in this block.
   virtual void OnHeaderBlockEnd(size_t uncompressed_header_bytes) = 0;
 };
diff --git a/net/spdy/spdy_no_op_visitor.cc b/net/spdy/spdy_no_op_visitor.cc
new file mode 100644
index 0000000..b9ac395
--- /dev/null
+++ b/net/spdy/spdy_no_op_visitor.cc
@@ -0,0 +1,34 @@
+// Copyright (c) 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 "net/spdy/spdy_no_op_visitor.h"
+
+#include <type_traits>
+
+namespace net {
+namespace test {
+
+SpdyNoOpVisitor::SpdyNoOpVisitor() {
+  static_assert(std::is_abstract<SpdyNoOpVisitor>::value == false,
+                "Need to update SpdyNoOpVisitor.");
+}
+SpdyNoOpVisitor::~SpdyNoOpVisitor() {}
+
+net::SpdyHeadersHandlerInterface* SpdyNoOpVisitor::OnHeaderFrameStart(
+    SpdyStreamId stream_id) {
+  return this;
+}
+
+bool SpdyNoOpVisitor::OnControlFrameHeaderData(SpdyStreamId stream_id,
+                                               const char* header_data,
+                                               size_t header_data_len) {
+  return true;
+}
+
+bool SpdyNoOpVisitor::OnUnknownFrame(SpdyStreamId stream_id, int frame_type) {
+  return true;
+}
+
+}  // namespace test
+}  // namespace net
diff --git a/net/spdy/spdy_no_op_visitor.h b/net/spdy/spdy_no_op_visitor.h
new file mode 100644
index 0000000..e2cba101
--- /dev/null
+++ b/net/spdy/spdy_no_op_visitor.h
@@ -0,0 +1,95 @@
+// Copyright (c) 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.
+//
+// SpdyNoOpVisitor implements several of the visitor and handler interfaces
+// to make it easier to write tests that need to provide instances. Other
+// interfaces can be added as needed.
+
+#ifndef NET_SPDY_SPDY_NO_OP_VISITOR_H_
+#define NET_SPDY_SPDY_NO_OP_VISITOR_H_
+
+#include "net/spdy/spdy_framer.h"
+#include "net/spdy/spdy_protocol.h"
+
+namespace net {
+namespace test {
+
+class SpdyNoOpVisitor : public SpdyFramerVisitorInterface,
+                        public SpdyFramerDebugVisitorInterface,
+                        public SpdyHeadersHandlerInterface {
+ public:
+  SpdyNoOpVisitor();
+  ~SpdyNoOpVisitor() override;
+
+  // SpdyFramerVisitorInterface methods:
+  void OnError(SpdyFramer* framer) override {}
+  void OnSynStream(SpdyStreamId stream_id,
+                   SpdyStreamId associated_stream_id,
+                   SpdyPriority priority,
+                   bool fin,
+                   bool unidirectional) override {}
+  void OnSynReply(SpdyStreamId stream_id, bool fin) override {}
+  net::SpdyHeadersHandlerInterface* OnHeaderFrameStart(
+      SpdyStreamId stream_id) override;
+  void OnHeaderFrameEnd(SpdyStreamId stream_id, bool end_headers) override {}
+  bool OnControlFrameHeaderData(SpdyStreamId stream_id,
+                                const char* header_data,
+                                size_t header_data_len) override;
+  void OnDataFrameHeader(SpdyStreamId stream_id,
+                         size_t length,
+                         bool fin) override {}
+  void OnStreamFrameData(SpdyStreamId stream_id,
+                         const char* data,
+                         size_t len) override {}
+  void OnStreamEnd(SpdyStreamId stream_id) override {}
+  void OnStreamPadding(SpdyStreamId stream_id, size_t len) override {}
+  void OnRstStream(SpdyStreamId stream_id,
+                   SpdyRstStreamStatus status) override {}
+  void OnSetting(SpdySettingsIds id, uint8_t flags, uint32_t value) override {}
+  void OnPing(SpdyPingId unique_id, bool is_ack) override {}
+  void OnSettingsEnd() override {}
+  void OnSettingsAck() override {}
+  void OnGoAway(SpdyStreamId last_accepted_stream_id,
+                SpdyGoAwayStatus status) override {}
+  void OnHeaders(SpdyStreamId stream_id,
+                 bool has_priority,
+                 int weight,
+                 SpdyStreamId parent_stream_id,
+                 bool exclusive,
+                 bool fin,
+                 bool end) override {}
+  void OnWindowUpdate(SpdyStreamId stream_id, int delta_window_size) override {}
+  void OnPushPromise(SpdyStreamId stream_id,
+                     SpdyStreamId promised_stream_id,
+                     bool end) override {}
+  void OnContinuation(SpdyStreamId stream_id, bool end) override {}
+  void OnAltSvc(SpdyStreamId stream_id,
+                base::StringPiece origin,
+                const SpdyAltSvcWireFormat::AlternativeServiceVector&
+                    altsvc_vector) override {}
+  void OnPriority(SpdyStreamId stream_id,
+                  SpdyStreamId parent_stream_id,
+                  int weight,
+                  bool exclusive) override {}
+  bool OnUnknownFrame(SpdyStreamId stream_id, int frame_type) override;
+
+  // SpdyFramerDebugVisitorInterface methods:
+  void OnSendCompressedFrame(SpdyStreamId stream_id,
+                             SpdyFrameType type,
+                             size_t payload_len,
+                             size_t frame_len) override {}
+  void OnReceiveCompressedFrame(SpdyStreamId stream_id,
+                                SpdyFrameType type,
+                                size_t frame_len) override {}
+
+  // SpdyHeadersHandlerInterface methods:
+  void OnHeaderBlockStart() override {}
+  void OnHeader(base::StringPiece key, base::StringPiece value) override {}
+  void OnHeaderBlockEnd(size_t uncompressed_header_bytes) override {}
+};
+
+}  // namespace test
+}  // namespace net
+
+#endif  // NET_SPDY_SPDY_NO_OP_VISITOR_H_
diff --git a/net/ssl/ssl_client_session_cache.cc b/net/ssl/ssl_client_session_cache.cc
index 650d989..28a33da1 100644
--- a/net/ssl/ssl_client_session_cache.cc
+++ b/net/ssl/ssl_client_session_cache.cc
@@ -45,7 +45,10 @@
     cache_.Erase(iter);
     return nullptr;
   }
-  return ScopedSSL_SESSION(SSL_SESSION_up_ref(iter->second->session.get()));
+
+  SSL_SESSION* session = iter->second->session.get();
+  SSL_SESSION_up_ref(session);
+  return ScopedSSL_SESSION(session);
 }
 
 void SSLClientSessionCache::Insert(const std::string& cache_key,
@@ -54,7 +57,8 @@
 
   // Make a new entry.
   std::unique_ptr<CacheEntry> entry(new CacheEntry);
-  entry->session.reset(SSL_SESSION_up_ref(session));
+  SSL_SESSION_up_ref(session);
+  entry->session.reset(session);
   entry->creation_time = clock_->Now();
 
   // Takes ownership.
diff --git a/net/test/run_all_unittests.cc b/net/test/run_all_unittests.cc
index 0a4df22..15116aa 100644
--- a/net/test/run_all_unittests.cc
+++ b/net/test/run_all_unittests.cc
@@ -17,10 +17,6 @@
 #include "base/android/jni_registrar.h"
 #include "net/android/dummy_spnego_authenticator.h"
 #include "net/android/net_jni_registrar.h"
-#if BUILDFLAG(USE_PLATFORM_ICU_ALTERNATIVES)
-#include "url/android/url_jni_registrar.h"  // nogncheck
-#endif
-
 #endif
 
 #if !defined(OS_ANDROID) && !defined(OS_IOS)
@@ -39,9 +35,6 @@
     {"DummySpnegoAuthenticator",
      net::android::DummySpnegoAuthenticator::RegisterJni},
     {"NetAndroid", net::android::RegisterJni},
-#if BUILDFLAG(USE_PLATFORM_ICU_ALTERNATIVES)
-    {"UrlAndroid", url::android::RegisterJni},
-#endif
   };
 
   // Register JNI bindings for android. Doing it early as the test suite setup
diff --git a/services/shell/service_manager.cc b/services/shell/service_manager.cc
index 90893f5..f23222f 100644
--- a/services/shell/service_manager.cc
+++ b/services/shell/service_manager.cc
@@ -281,7 +281,8 @@
     params->set_local_interfaces(std::move(local_interfaces));
     params->set_client_process_connection(std::move(client_process_connection));
     params->set_connect_callback(callback);
-    service_manager_->Connect(std::move(params));
+    service_manager_->Connect(
+        std::move(params), nullptr, weak_factory_.GetWeakPtr());
   }
 
   void Clone(mojom::ConnectorRequest request) override {
@@ -517,7 +518,7 @@
 }
 
 void ServiceManager::Connect(std::unique_ptr<ConnectParams> params) {
-  Connect(std::move(params), nullptr);
+  Connect(std::move(params), nullptr, nullptr);
 }
 
 mojom::ServiceRequest ServiceManager::StartEmbedderService(
@@ -530,7 +531,7 @@
 
   mojom::ServicePtr service;
   mojom::ServiceRequest request = mojo::GetProxy(&service);
-  Connect(std::move(params), std::move(service));
+  Connect(std::move(params), std::move(service), nullptr);
 
   return request;
 }
@@ -605,7 +606,8 @@
 }
 
 void ServiceManager::Connect(std::unique_ptr<ConnectParams> params,
-                             mojom::ServicePtr service) {
+                             mojom::ServicePtr service,
+                             base::WeakPtr<Instance> source_instance) {
   TRACE_EVENT_INSTANT1("mojo_shell", "ServiceManager::Connect",
                        TRACE_EVENT_SCOPE_THREAD, "original_name",
                        params->target().name());
@@ -629,7 +631,8 @@
   resolver->ResolveMojoName(
       name, base::Bind(&shell::ServiceManager::OnGotResolvedName,
                        weak_ptr_factory_.GetWeakPtr(), base::Passed(&params),
-                       base::Passed(&service)));
+                       base::Passed(&service), !!source_instance,
+                       source_instance));
 }
 
 ServiceManager::Instance* ServiceManager::GetExistingInstance(
@@ -727,7 +730,14 @@
 
 void ServiceManager::OnGotResolvedName(std::unique_ptr<ConnectParams> params,
                                        mojom::ServicePtr service,
+                                       bool has_source_instance,
+                                       base::WeakPtr<Instance> source_instance,
                                        mojom::ResolveResultPtr result) {
+  // If this request was originated by a specific Instance and that Instance is
+  // no longer around, we ignore this response.
+  if (has_source_instance && !source_instance)
+    return;
+
   std::string instance_name = params->target().instance();
   if (instance_name == GetNamePath(params->target().name()) &&
       result->qualifier != GetNamePath(result->resolved_name)) {
@@ -790,8 +800,7 @@
       instance->StartWithService(std::move(service));
       Identity factory(result->resolved_name, target.user_id(),
                        instance_name);
-      CreateServiceWithFactory(factory, target.name(),
-                                   std::move(request));
+      CreateServiceWithFactory(factory, target.name(), std::move(request));
     } else {
       instance->StartWithFilePath(result->package_path);
     }
diff --git a/services/shell/service_manager.h b/services/shell/service_manager.h
index b6226f1..d6e6b5d73 100644
--- a/services/shell/service_manager.h
+++ b/services/shell/service_manager.h
@@ -102,8 +102,13 @@
   // If |service| is not null, there must not be an instance of the target
   // application already running. The Service Manager will create a new instance
   // and use |service| to control it.
+  //
+  // If |instance| is not null, the lifetime of the connection request is
+  // bounded by that of |instance|. The connection will be cancelled dropped if
+  // |instance| is destroyed.
   void Connect(std::unique_ptr<ConnectParams> params,
-               mojom::ServicePtr service);
+               mojom::ServicePtr service,
+               base::WeakPtr<Instance> source_instance);
 
   // Returns a running instance matching |identity|. This might be an instance
   // running as a different user if one is available that services all users.
@@ -139,6 +144,8 @@
   // |result| contains the result of the resolve operation.
   void OnGotResolvedName(std::unique_ptr<ConnectParams> params,
                          mojom::ServicePtr service,
+                         bool has_source_instance,
+                         base::WeakPtr<Instance> source_instance,
                          mojom::ResolveResultPtr result);
 
   base::WeakPtr<ServiceManager> GetWeakPtr();
diff --git a/services/ui/common/gpu_service.cc b/services/ui/common/gpu_service.cc
index f8bf9e79..9a2f4c56 100644
--- a/services/ui/common/gpu_service.cc
+++ b/services/ui/common/gpu_service.cc
@@ -47,21 +47,18 @@
 
 GpuService::~GpuService() {
   DCHECK(IsMainThread());
+  DCHECK_EQ(this, g_gpu_service);
   if (gpu_channel_)
     gpu_channel_->DestroyChannel();
+  g_gpu_service = nullptr;
 }
 
 // static
-void GpuService::Initialize(shell::Connector* connector) {
+std::unique_ptr<GpuService> GpuService::Initialize(
+    shell::Connector* connector) {
   DCHECK(!g_gpu_service);
   g_gpu_service = new GpuService(connector);
-}
-
-// static
-void GpuService::Terminate() {
-  DCHECK(g_gpu_service);
-  delete g_gpu_service;
-  g_gpu_service = nullptr;
+  return base::WrapUnique(g_gpu_service);
 }
 
 // static
diff --git a/services/ui/common/gpu_service.h b/services/ui/common/gpu_service.h
index 7308754..d00a60c 100644
--- a/services/ui/common/gpu_service.h
+++ b/services/ui/common/gpu_service.h
@@ -27,6 +27,8 @@
 
 class MUS_COMMON_EXPORT GpuService : public gpu::GpuChannelHostFactory {
  public:
+  ~GpuService() override;
+
   void EstablishGpuChannel(const base::Closure& callback);
   scoped_refptr<gpu::GpuChannelHost> EstablishGpuChannelSync();
   scoped_refptr<gpu::GpuChannelHost> GetGpuChannel();
@@ -36,16 +38,13 @@
 
   // The GpuService has to be initialized in the main thread before establishing
   // the gpu channel.
-  static void Initialize(shell::Connector* connector);
-  // The GpuService has to be terminated in the main thread.
-  static void Terminate();
+  static std::unique_ptr<GpuService> Initialize(shell::Connector* connector);
   static GpuService* GetInstance();
 
  private:
   friend struct base::DefaultSingletonTraits<GpuService>;
 
   explicit GpuService(shell::Connector* connector);
-  ~GpuService() override;
 
   scoped_refptr<gpu::GpuChannelHost> GetGpuChannelLocked();
   void EstablishGpuChannelOnMainThread();
diff --git a/services/ui/demo/mus_demo.cc b/services/ui/demo/mus_demo.cc
index 89b601e..3710de8d 100644
--- a/services/ui/demo/mus_demo.cc
+++ b/services/ui/demo/mus_demo.cc
@@ -65,7 +65,7 @@
 }
 
 void MusDemo::OnStart(const shell::Identity& identity) {
-  GpuService::Initialize(connector());
+  gpu_service_ = GpuService::Initialize(connector());
   window_tree_client_ = new WindowTreeClient(this, this, nullptr);
   window_tree_client_->ConnectAsWindowManager(connector());
 }
diff --git a/services/ui/demo/mus_demo.h b/services/ui/demo/mus_demo.h
index 8957cc4..78dbde7 100644
--- a/services/ui/demo/mus_demo.h
+++ b/services/ui/demo/mus_demo.h
@@ -21,6 +21,8 @@
 
 namespace ui {
 class BitmapUploader;
+class GpuService;
+
 namespace demo {
 
 // A simple MUS Demo mojo app. This app connects to the mojo:ui, creates a new
@@ -69,6 +71,7 @@
 
   Window* window_ = nullptr;
   WindowTreeClient* window_tree_client_ = nullptr;
+  std::unique_ptr<GpuService> gpu_service_;
 
   // Used to send frames to mus.
   std::unique_ptr<ui::BitmapUploader> uploader_;
diff --git a/services/ui/surfaces/display_compositor.cc b/services/ui/surfaces/display_compositor.cc
index 1f38c4f8..5cb51a1 100644
--- a/services/ui/surfaces/display_compositor.cc
+++ b/services/ui/surfaces/display_compositor.cc
@@ -121,4 +121,16 @@
 void DisplayCompositor::DisplaySetMemoryPolicy(
     const cc::ManagedMemoryPolicy& policy) {}
 
+void DisplayCompositor::DisplayWillDrawAndSwap(
+    bool will_draw_and_swap,
+    const cc::RenderPassList& render_passes) {
+  // This notification is not relevant to our client outside of tests.
+}
+
+void DisplayCompositor::DisplayDidDrawAndSwap() {
+  // This notification is not relevant to our client outside of tests. We
+  // unblock the client from the DrawCallback when the surface is going to
+  // be drawn.
+}
+
 }  // namespace ui
diff --git a/services/ui/surfaces/display_compositor.h b/services/ui/surfaces/display_compositor.h
index 13019cb1..dfeed0d 100644
--- a/services/ui/surfaces/display_compositor.h
+++ b/services/ui/surfaces/display_compositor.h
@@ -60,6 +60,9 @@
   // DisplayClient implementation.
   void DisplayOutputSurfaceLost() override;
   void DisplaySetMemoryPolicy(const cc::ManagedMemoryPolicy& policy) override;
+  void DisplayWillDrawAndSwap(bool will_draw_and_swap,
+                              const cc::RenderPassList& render_passes) override;
+  void DisplayDidDrawAndSwap() override;
 
   scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
   scoped_refptr<SurfacesState> surfaces_state_;
diff --git a/testing/buildbot/chromium.android.json b/testing/buildbot/chromium.android.json
index d70e33cb..1e9e202 100644
--- a/testing/buildbot/chromium.android.json
+++ b/testing/buildbot/chromium.android.json
@@ -470,19 +470,6 @@
         "test": "sql_unittests"
       },
       {
-        "override_isolate_target": "sync_unit_tests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "device_os": "MMB29Q",
-              "device_type": "bullhead"
-            }
-          ]
-        },
-        "test": "sync_unit_tests"
-      },
-      {
         "override_isolate_target": "ui_android_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
@@ -1021,19 +1008,6 @@
         "test": "sql_unittests"
       },
       {
-        "override_isolate_target": "sync_unit_tests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "device_os": "KTU84P",
-              "device_type": "hammerhead"
-            }
-          ]
-        },
-        "test": "sync_unit_tests"
-      },
-      {
         "override_isolate_target": "ui_android_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
@@ -1183,9 +1157,6 @@
         "test": "sql_unittests"
       },
       {
-        "test": "sync_unit_tests"
-      },
-      {
         "test": "ui_android_unittests"
       },
       {
@@ -1290,9 +1261,6 @@
         "test": "sql_unittests"
       },
       {
-        "test": "sync_unit_tests"
-      },
-      {
         "test": "ui_android_unittests"
       },
       {
@@ -1400,9 +1368,6 @@
         "test": "sql_unittests"
       },
       {
-        "test": "sync_unit_tests"
-      },
-      {
         "test": "ui_android_unittests"
       },
       {
@@ -1518,9 +1483,6 @@
         "test": "sql_unittests"
       },
       {
-        "test": "sync_unit_tests"
-      },
-      {
         "test": "ui_android_unittests"
       },
       {
@@ -1631,9 +1593,6 @@
         "test": "sql_unittests"
       },
       {
-        "test": "sync_unit_tests"
-      },
-      {
         "test": "ui_android_unittests"
       },
       {
@@ -1741,9 +1700,6 @@
         "test": "sql_unittests"
       },
       {
-        "test": "sync_unit_tests"
-      },
-      {
         "test": "ui_android_unittests"
       },
       {
@@ -1857,9 +1813,6 @@
         "test": "sql_unittests"
       },
       {
-        "test": "sync_unit_tests"
-      },
-      {
         "test": "ui_android_unittests"
       },
       {
@@ -1967,9 +1920,6 @@
         "test": "sql_unittests"
       },
       {
-        "test": "sync_unit_tests"
-      },
-      {
         "test": "ui_android_unittests"
       },
       {
diff --git a/testing/buildbot/chromium.chromiumos.json b/testing/buildbot/chromium.chromiumos.json
index d41b2de..79baad8 100644
--- a/testing/buildbot/chromium.chromiumos.json
+++ b/testing/buildbot/chromium.chromiumos.json
@@ -335,12 +335,6 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
-        "test": "sync_unit_tests"
-      },
-      {
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
         "test": "ui_arc_unittests"
       },
       {
@@ -701,12 +695,6 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
-        "test": "sync_unit_tests"
-      },
-      {
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
         "test": "ui_arc_unittests"
       },
       {
@@ -1029,12 +1017,6 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
-        "test": "sync_unit_tests"
-      },
-      {
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
         "test": "ui_arc_unittests"
       },
       {
diff --git a/testing/buildbot/chromium.full.json b/testing/buildbot/chromium.full.json
index 29f26fd..cd4c928 100644
--- a/testing/buildbot/chromium.full.json
+++ b/testing/buildbot/chromium.full.json
@@ -363,12 +363,6 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
-        "test": "sync_unit_tests"
-      },
-      {
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
         "test": "ui_base_unittests"
       },
       {
@@ -662,12 +656,6 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
-        "test": "sync_unit_tests"
-      },
-      {
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
         "test": "ui_base_unittests"
       },
       {
@@ -919,12 +907,6 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
-        "test": "sync_unit_tests"
-      },
-      {
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
         "test": "ui_base_unittests"
       },
       {
diff --git a/testing/buildbot/chromium.fyi.json b/testing/buildbot/chromium.fyi.json
index 82291b04..76288d5 100644
--- a/testing/buildbot/chromium.fyi.json
+++ b/testing/buildbot/chromium.fyi.json
@@ -113,12 +113,6 @@
         "args": [
           "--tool=asan"
         ],
-        "test": "sync_unit_tests"
-      },
-      {
-        "args": [
-          "--tool=asan"
-        ],
         "test": "ui_android_unittests"
       },
       {
@@ -608,19 +602,6 @@
         "test": "sql_unittests"
       },
       {
-        "override_isolate_target": "sync_unit_tests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "android_devices": "4",
-              "device_type": "gce_x86"
-            }
-          ]
-        },
-        "test": "sync_unit_tests"
-      },
-      {
         "override_isolate_target": "ui_android_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
@@ -789,9 +770,6 @@
         "test": "sql_unittests"
       },
       {
-        "test": "sync_unit_tests"
-      },
-      {
         "test": "ui_android_unittests"
       },
       {
@@ -1168,12 +1146,6 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
-        "test": "sync_unit_tests"
-      },
-      {
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
         "test": "ui_base_unittests"
       },
       {
@@ -1530,12 +1502,6 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
-        "test": "sync_unit_tests"
-      },
-      {
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
         "test": "ui_base_unittests"
       },
       {
@@ -1708,9 +1674,6 @@
         "test": "sync_integration_tests"
       },
       {
-        "test": "sync_unit_tests"
-      },
-      {
         "test": "ui_base_unittests"
       },
       {
@@ -1859,9 +1822,6 @@
         "test": "sync_integration_tests"
       },
       {
-        "test": "sync_unit_tests"
-      },
-      {
         "test": "ui_base_unittests"
       },
       {
@@ -2041,9 +2001,6 @@
         "test": "sync_integration_tests"
       },
       {
-        "test": "sync_unit_tests"
-      },
-      {
         "test": "ui_base_unittests"
       },
       {
@@ -2341,12 +2298,6 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
-        "test": "sync_unit_tests"
-      },
-      {
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
         "test": "ui_base_unittests"
       },
       {
@@ -2617,12 +2568,6 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
-        "test": "sync_unit_tests"
-      },
-      {
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
         "test": "ui_base_unittests"
       },
       {
@@ -2905,12 +2850,6 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
-        "test": "sync_unit_tests"
-      },
-      {
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
         "test": "ui_base_unittests"
       },
       {
@@ -3378,12 +3317,6 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
-        "test": "sync_unit_tests"
-      },
-      {
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
         "test": "ui_base_unittests"
       },
       {
@@ -3699,12 +3632,6 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
-        "test": "sync_unit_tests"
-      },
-      {
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
         "test": "ui_base_unittests"
       },
       {
@@ -3968,12 +3895,6 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
-        "test": "sync_unit_tests"
-      },
-      {
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
         "test": "ui_base_unittests"
       },
       {
@@ -4231,12 +4152,6 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
-        "test": "sync_unit_tests"
-      },
-      {
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
         "test": "ui_base_unittests"
       },
       {
@@ -4494,12 +4409,6 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
-        "test": "sync_unit_tests"
-      },
-      {
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
         "test": "ui_base_unittests"
       },
       {
@@ -4757,12 +4666,6 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
-        "test": "sync_unit_tests"
-      },
-      {
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
         "test": "ui_base_unittests"
       },
       {
@@ -5020,12 +4923,6 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
-        "test": "sync_unit_tests"
-      },
-      {
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
         "test": "ui_base_unittests"
       },
       {
@@ -5283,12 +5180,6 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
-        "test": "sync_unit_tests"
-      },
-      {
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
         "test": "ui_base_unittests"
       },
       {
@@ -5534,12 +5425,6 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
-        "test": "sync_unit_tests"
-      },
-      {
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
         "test": "ui_base_unittests"
       },
       {
@@ -5773,12 +5658,6 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
-        "test": "sync_unit_tests"
-      },
-      {
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
         "test": "ui_base_unittests"
       },
       {
@@ -5999,12 +5878,6 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
-        "test": "sync_unit_tests"
-      },
-      {
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
         "test": "ui_base_unittests"
       },
       {
@@ -6244,12 +6117,6 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
-        "test": "sync_unit_tests"
-      },
-      {
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
         "test": "ui_base_unittests"
       },
       {
@@ -6507,12 +6374,6 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
-        "test": "sync_unit_tests"
-      },
-      {
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
         "test": "ui_base_unittests"
       },
       {
@@ -6770,12 +6631,6 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
-        "test": "sync_unit_tests"
-      },
-      {
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
         "test": "ui_base_unittests"
       },
       {
@@ -7033,12 +6888,6 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
-        "test": "sync_unit_tests"
-      },
-      {
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
         "test": "ui_base_unittests"
       },
       {
@@ -7296,12 +7145,6 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
-        "test": "sync_unit_tests"
-      },
-      {
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
         "test": "ui_base_unittests"
       },
       {
@@ -7559,12 +7402,6 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
-        "test": "sync_unit_tests"
-      },
-      {
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
         "test": "ui_base_unittests"
       },
       {
@@ -7822,12 +7659,6 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
-        "test": "sync_unit_tests"
-      },
-      {
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
         "test": "ui_base_unittests"
       },
       {
@@ -8085,12 +7916,6 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
-        "test": "sync_unit_tests"
-      },
-      {
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
         "test": "ui_base_unittests"
       },
       {
@@ -8342,12 +8167,6 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
-        "test": "sync_unit_tests"
-      },
-      {
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
         "test": "ui_base_unittests"
       },
       {
@@ -8605,12 +8424,6 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
-        "test": "sync_unit_tests"
-      },
-      {
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
         "test": "ui_base_unittests"
       },
       {
@@ -8969,12 +8782,6 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
-        "test": "sync_unit_tests"
-      },
-      {
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
         "test": "ui_base_unittests"
       },
       {
@@ -9310,12 +9117,6 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
-        "test": "sync_unit_tests"
-      },
-      {
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
         "test": "ui_base_unittests"
       },
       {
@@ -9534,9 +9335,6 @@
         "test": "sql_unittests"
       },
       {
-        "test": "sync_unit_tests"
-      },
-      {
         "test": "ui_base_unittests"
       },
       {
@@ -9860,12 +9658,6 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
-        "test": "sync_unit_tests"
-      },
-      {
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
         "test": "ui_base_unittests"
       },
       {
@@ -10078,9 +9870,6 @@
         "test": "sql_unittests"
       },
       {
-        "test": "sync_unit_tests"
-      },
-      {
         "test": "ui_base_unittests"
       },
       {
@@ -10904,12 +10693,6 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
-        "test": "sync_unit_tests"
-      },
-      {
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
         "test": "ui_base_unittests"
       },
       {
@@ -11161,12 +10944,6 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
-        "test": "sync_unit_tests"
-      },
-      {
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
         "test": "ui_base_unittests"
       },
       {
diff --git a/testing/buildbot/chromium.linux.json b/testing/buildbot/chromium.linux.json
index bba53a4..0b362e0 100644
--- a/testing/buildbot/chromium.linux.json
+++ b/testing/buildbot/chromium.linux.json
@@ -514,20 +514,6 @@
         "test": "sql_unittests"
       },
       {
-        "override_isolate_target": "sync_unit_tests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "android_devices": "4",
-              "device_os": "KTU84P",
-              "device_type": "hammerhead"
-            }
-          ]
-        },
-        "test": "sync_unit_tests"
-      },
-      {
         "override_isolate_target": "ui_android_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true,
@@ -744,9 +730,6 @@
         "test": "sql_unittests"
       },
       {
-        "test": "sync_unit_tests"
-      },
-      {
         "test": "ui_android_unittests"
       },
       {
@@ -976,12 +959,6 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
-        "test": "sync_unit_tests"
-      },
-      {
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
         "test": "ui_base_unittests"
       },
       {
@@ -1425,12 +1402,6 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
-        "test": "sync_unit_tests"
-      },
-      {
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
         "test": "test_ime_unittests"
       },
       {
@@ -1879,12 +1850,6 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
-        "test": "sync_unit_tests"
-      },
-      {
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
         "test": "test_ime_unittests"
       },
       {
@@ -2252,12 +2217,6 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
-        "test": "sync_unit_tests"
-      },
-      {
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
         "test": "ui_base_unittests"
       },
       {
diff --git a/testing/buildbot/chromium.mac.json b/testing/buildbot/chromium.mac.json
index e24c3187..05e39bf 100644
--- a/testing/buildbot/chromium.mac.json
+++ b/testing/buildbot/chromium.mac.json
@@ -13,7 +13,6 @@
       "printing_unittests",
       "skia_unittests",
       "sql_unittests",
-      "sync_unit_tests",
       "ui_base_unittests",
       "unit_tests",
       "url_unittests"
@@ -295,12 +294,6 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
-        "test": "sync_unit_tests"
-      },
-      {
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
         "test": "ui_base_unittests"
       },
       {
@@ -634,12 +627,6 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
-        "test": "sync_unit_tests"
-      },
-      {
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
         "test": "ui_base_unittests"
       },
       {
@@ -974,12 +961,6 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
-        "test": "sync_unit_tests"
-      },
-      {
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
         "test": "ui_base_unittests"
       },
       {
@@ -1302,12 +1283,6 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
-        "test": "sync_unit_tests"
-      },
-      {
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
         "test": "ui_base_unittests"
       },
       {
diff --git a/testing/buildbot/chromium.memory.full.json b/testing/buildbot/chromium.memory.full.json
index 29f26fd..cd4c928 100644
--- a/testing/buildbot/chromium.memory.full.json
+++ b/testing/buildbot/chromium.memory.full.json
@@ -363,12 +363,6 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
-        "test": "sync_unit_tests"
-      },
-      {
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
         "test": "ui_base_unittests"
       },
       {
@@ -662,12 +656,6 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
-        "test": "sync_unit_tests"
-      },
-      {
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
         "test": "ui_base_unittests"
       },
       {
@@ -919,12 +907,6 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
-        "test": "sync_unit_tests"
-      },
-      {
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
         "test": "ui_base_unittests"
       },
       {
diff --git a/testing/buildbot/chromium.memory.fyi.json b/testing/buildbot/chromium.memory.fyi.json
index 29f26fd..cd4c928 100644
--- a/testing/buildbot/chromium.memory.fyi.json
+++ b/testing/buildbot/chromium.memory.fyi.json
@@ -363,12 +363,6 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
-        "test": "sync_unit_tests"
-      },
-      {
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
         "test": "ui_base_unittests"
       },
       {
@@ -662,12 +656,6 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
-        "test": "sync_unit_tests"
-      },
-      {
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
         "test": "ui_base_unittests"
       },
       {
@@ -919,12 +907,6 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
-        "test": "sync_unit_tests"
-      },
-      {
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
         "test": "ui_base_unittests"
       },
       {
diff --git a/testing/buildbot/chromium.memory.json b/testing/buildbot/chromium.memory.json
index 6917cf03..75ec9bc 100644
--- a/testing/buildbot/chromium.memory.json
+++ b/testing/buildbot/chromium.memory.json
@@ -218,12 +218,6 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
-        "test": "sync_unit_tests"
-      },
-      {
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
         "test": "ui_base_unittests"
       },
       {
@@ -513,12 +507,6 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
-        "test": "sync_unit_tests"
-      },
-      {
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
         "test": "ui_arc_unittests"
       },
       {
@@ -731,12 +719,6 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
-        "test": "sync_unit_tests"
-      },
-      {
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
         "test": "ui_base_unittests"
       },
       {
diff --git a/testing/buildbot/chromium.win.json b/testing/buildbot/chromium.win.json
index 40dc302..9cd38f8 100644
--- a/testing/buildbot/chromium.win.json
+++ b/testing/buildbot/chromium.win.json
@@ -418,12 +418,6 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
-        "test": "sync_unit_tests"
-      },
-      {
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
         "test": "ui_base_unittests"
       },
       {
@@ -875,12 +869,6 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
-        "test": "sync_unit_tests"
-      },
-      {
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
         "test": "ui_base_unittests"
       },
       {
@@ -1363,12 +1351,6 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
-        "test": "sync_unit_tests"
-      },
-      {
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
         "test": "ui_base_unittests"
       },
       {
@@ -1765,12 +1747,6 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
-        "test": "sync_unit_tests"
-      },
-      {
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
         "test": "ui_base_unittests"
       },
       {
diff --git a/testing/buildbot/chromium_memory_trybot.json b/testing/buildbot/chromium_memory_trybot.json
index c7453442..ccc8226 100644
--- a/testing/buildbot/chromium_memory_trybot.json
+++ b/testing/buildbot/chromium_memory_trybot.json
@@ -125,7 +125,6 @@
     },
     "skia_unittests",
     "sql_unittests",
-    "sync_unit_tests",
     "ui_base_unittests",
     {
       "swarming": {
diff --git a/testing/buildbot/client.v8.fyi.json b/testing/buildbot/client.v8.fyi.json
index 7d6121c..bf13927f 100644
--- a/testing/buildbot/client.v8.fyi.json
+++ b/testing/buildbot/client.v8.fyi.json
@@ -50,7 +50,6 @@
       "skia_unittests",
       "sql_unittests",
       "sync_integration_tests",
-      "sync_unit_tests",
       "ui_base_unittests",
       "ui_touch_selection_unittests",
       "unit_tests",
diff --git a/testing/buildbot/gn_isolate_map.pyl b/testing/buildbot/gn_isolate_map.pyl
index 23a140d..c143fd6 100644
--- a/testing/buildbot/gn_isolate_map.pyl
+++ b/testing/buildbot/gn_isolate_map.pyl
@@ -539,10 +539,6 @@
     "label": "//chrome/test:sync_integration_tests",
     "type": "windowed_test_launcher",
   },
-  "sync_unit_tests": {
-    "label": "//components/sync:sync_unit_tests",
-    "type": "console_test_launcher",
-  },
   "tab_capture_end2end_tests": {
     "label": "//chrome/test:browser_tests",
     "type": "gpu_browser_test",
diff --git a/testing/buildbot/tryserver.v8.json b/testing/buildbot/tryserver.v8.json
index 09adc1a4..bdb04a0 100644
--- a/testing/buildbot/tryserver.v8.json
+++ b/testing/buildbot/tryserver.v8.json
@@ -50,7 +50,6 @@
       "skia_unittests",
       "sql_unittests",
       "sync_integration_tests",
-      "sync_unit_tests",
       "ui_base_unittests",
       "ui_touch_selection_unittests",
       "unit_tests",
diff --git a/third_party/WebKit/LayoutTests/TestExpectations b/third_party/WebKit/LayoutTests/TestExpectations
index 19fdc070..ccf99cbd 100644
--- a/third_party/WebKit/LayoutTests/TestExpectations
+++ b/third_party/WebKit/LayoutTests/TestExpectations
@@ -633,6 +633,7 @@
 # These tests fail / timeout until https://www.chromestatus.com/features/5643236399906816 ships
 crbug.com/621515 inspector/sources/debugger-async/async-await/async-callstack-async-await1.html [ Skip ]
 crbug.com/621515 inspector/sources/debugger-async/async-await/async-callstack-async-await2.html [ Skip ]
+crbug.com/621515 inspector/sources/debugger-async/async-await/async-callstack-async-await3.html [ Skip ]
 
 # These tests pass but images do not match because of position: absolute in vertical flow bug
 crbug.com/492664 imported/csswg-test/css-writing-modes-3/block-flow-direction-vrl-009.xht [ Failure ]
@@ -928,6 +929,97 @@
 crbug.com/619060 imported/wpt/pointerevents/pointerevent_pointerleave_after_pointerup_nohover-manual.html  [ Skip ]
 crbug.com/619060 imported/wpt/pointerevents/pointerevent_pointerleave_touch-manual.html  [ Skip ]
 
+crbug.com/451090 compositing/squashing/remove-squashed-layer-plus-move.html [ NeedsRebaseline ]
+crbug.com/451090 fast/repaint/abspos-shift-image-incorrect-repaint.html [ NeedsRebaseline ]
+crbug.com/451090 fast/repaint/align-content-change.html [ NeedsRebaseline ]
+crbug.com/451090 fast/repaint/align-content-distribution-change-grid.html [ NeedsRebaseline ]
+crbug.com/451090 fast/repaint/align-content-position-change-grid.html [ NeedsRebaseline ]
+crbug.com/451090 fast/repaint/align-self-change-grid.html [ NeedsRebaseline ]
+crbug.com/451090 fast/repaint/align-self-overflow-change.html [ NeedsRebaseline ]
+crbug.com/451090 fast/repaint/background-generated.html [ NeedsRebaseline ]
+crbug.com/451090 fast/repaint/background-resize-height.html [ NeedsRebaseline ]
+crbug.com/451090 fast/repaint/background-shorthand-with-gradient-and-height-changes.html [ NeedsRebaseline ]
+crbug.com/451090 fast/repaint/background-size-auto-with-gradient-and-height-changes.html [ NeedsRebaseline ]
+crbug.com/451090 fast/repaint/block-shift-repaint.html [ NeedsRebaseline ]
+crbug.com/451090 fast/repaint/border-radius-repaint-2.html [ NeedsRebaseline ]
+crbug.com/451090 fast/repaint/box-inline-resize.html [ NeedsRebaseline ]
+crbug.com/451090 fast/repaint/box-shadow-dynamic.html [ NeedsRebaseline ]
+crbug.com/451090 fast/repaint/clipped-overflow-visible-subtree.html [ NeedsRebaseline ]
+crbug.com/451090 fast/repaint/clipped-relative.html [ NeedsRebaseline ]
+crbug.com/451090 fast/repaint/content-into-overflow.html [ NeedsRebaseline ]
+crbug.com/451090 fast/repaint/crbug-371640-2.html [ NeedsRebaseline ]
+crbug.com/451090 fast/repaint/crbug-371640-3.html [ NeedsRebaseline ]
+crbug.com/451090 fast/repaint/crbug-371640-4.html [ NeedsRebaseline ]
+crbug.com/451090 fast/repaint/crbug-371640.html [ NeedsRebaseline ]
+crbug.com/451090 fast/repaint/dynamic-table-vertical-alignment-change.html [ NeedsRebaseline ]
+crbug.com/451090 fast/repaint/erase-overflow.html [ NeedsRebaseline ]
+crbug.com/451090 fast/repaint/fixed-and-absolute-position-scrolled.html [ NeedsRebaseline ]
+crbug.com/451090 fast/repaint/float-move-during-layout.html [ NeedsRebaseline ]
+crbug.com/451090 fast/repaint/float-overflow-right.html [ NeedsRebaseline ]
+crbug.com/451090 fast/repaint/float-overflow.html [ NeedsRebaseline ]
+crbug.com/451090 fast/repaint/intermediate-layout-position.html [ NeedsRebaseline ]
+crbug.com/451090 fast/repaint/justify-content-change.html [ NeedsRebaseline ]
+crbug.com/451090 fast/repaint/justify-content-distribution-change-grid.html [ NeedsRebaseline ]
+crbug.com/451090 fast/repaint/justify-content-position-change-grid.html [ NeedsRebaseline ]
+crbug.com/451090 fast/repaint/justify-content-position-change.html [ NeedsRebaseline ]
+crbug.com/451090 fast/repaint/justify-self-change.html [ NeedsRebaseline ]
+crbug.com/451090 fast/repaint/justify-self-overflow-change.html [ NeedsRebaseline ]
+crbug.com/451090 fast/repaint/layout-state-only-positioned.html [ NeedsRebaseline ]
+crbug.com/451090 fast/repaint/offset-change-wrong-invalidation-with-float.html [ NeedsRebaseline ]
+crbug.com/451090 fast/repaint/outline-child-repaint.html [ NeedsRebaseline ]
+crbug.com/451090 fast/repaint/overflow-into-content.html [ NeedsRebaseline ]
+crbug.com/451090 fast/repaint/paint-invalidation-with-reparent-across-frame-boundaries.html [ NeedsRebaseline ]
+crbug.com/451090 fast/repaint/percent-size-image-resize-container.html [ NeedsRebaseline ]
+crbug.com/451090 fast/repaint/positioned-document-element.html [ NeedsRebaseline ]
+crbug.com/451090 fast/repaint/positioned-great-grandparent-change-location.html [ NeedsRebaseline ]
+crbug.com/451090 fast/repaint/positioned-list-offset-change-repaint.html [ NeedsRebaseline ]
+crbug.com/451090 fast/repaint/reflection-repaint-test.html [ NeedsRebaseline ]
+crbug.com/451090 fast/repaint/relative-margin-change-repaint.html [ NeedsRebaseline ]
+crbug.com/451090 fast/repaint/repaint-descandant-on-ancestor-layer-move.html [ NeedsRebaseline ]
+crbug.com/451090 fast/repaint/repaint-resized-overflow.html [ NeedsRebaseline ]
+crbug.com/451090 fast/repaint/repaint-table-row-in-composited-document.html [ NeedsRebaseline ]
+crbug.com/451090 fast/repaint/replaced-clipped-positioned-not-wrong-incremental-repainting.html [ NeedsRebaseline ]
+crbug.com/451090 fast/repaint/resize-child-within-overflow.html [ NeedsRebaseline ]
+crbug.com/451090 fast/repaint/scrollbar-damage-and-full-viewport-repaint.html [ NeedsRebaseline ]
+crbug.com/451090 fast/repaint/selection-after-remove.html [ NeedsRebaseline ]
+crbug.com/451090 fast/repaint/selection-change-in-iframe-with-relative-parent.html [ NeedsRebaseline ]
+crbug.com/451090 fast/repaint/selection-clear.html [ NeedsRebaseline ]
+crbug.com/451090 fast/repaint/shift-relative-positioned-container-with-image-addition.html [ NeedsRebaseline ]
+crbug.com/451090 fast/repaint/shift-relative-positioned-container-with-image-removal.html [ NeedsRebaseline ]
+crbug.com/451090 fast/repaint/table-cell-move.html [ NeedsRebaseline ]
+crbug.com/451090 fast/repaint/table-section-overflow.html [ NeedsRebaseline ]
+crbug.com/451090 fast/repaint/table-section-repaint.html [ NeedsRebaseline ]
+crbug.com/451090 fast/repaint/table-shrink-row-repaint.html [ NeedsRebaseline ]
+crbug.com/451090 fast/repaint/text-selection-rect-in-overflow.html [ NeedsRebaseline ]
+crbug.com/451090 fast/repaint/text-selection-rect-in-overflow-2.html [ NeedsRebaseline ]
+crbug.com/451090 fast/repaint/transform-disable-layoutstate.html [ NeedsRebaseline ]
+crbug.com/451090 fast/repaint/window-resize-vertical-writing-mode.html [ NeedsRebaseline ]
+crbug.com/451090 fast/table/border-collapsing/cached-change-cell-border-width.html [ NeedsRebaseline ]
+crbug.com/451090 fast/table/border-collapsing/cached-change-col-border-width.html [ NeedsRebaseline ]
+crbug.com/451090 fast/table/border-collapsing/cached-change-row-border-width.html [ NeedsRebaseline ]
+crbug.com/451090 fast/table/border-collapsing/cached-change-tbody-border-width.html [ NeedsRebaseline ]
+crbug.com/451090 fast/table/resize-table-repaint-percent-size-cell.html [ NeedsRebaseline ]
+crbug.com/451090 fast/table/resize-table-repaint-vertical-align-cell.html [ NeedsRebaseline ]
+crbug.com/451090 fast/table/resize-table-row-repaint.html [ NeedsRebaseline ]
+crbug.com/451090 paint/selection/invalidation-rect-includes-newline-for-rtl.html [ NeedsRebaseline ]
+crbug.com/451090 paint/selection/invalidation-rect-with-br-includes-newline.html [ NeedsRebaseline ]
+crbug.com/451090 svg/as-object/deep-nested-embedded-svg-size-changes-no-layout-triggers-1.html [ NeedsRebaseline ]
+crbug.com/451090 svg/as-object/deep-nested-embedded-svg-size-changes-no-layout-triggers-2.html [ NeedsRebaseline ]
+crbug.com/451090 svg/as-object/nested-embedded-svg-size-changes-no-layout-triggers-1.html [ NeedsRebaseline ]
+crbug.com/451090 svg/as-object/nested-embedded-svg-size-changes-no-layout-triggers-2.html [ NeedsRebaseline ]
+crbug.com/451090 svg/custom/object-sizing-no-width-height-change-content-box-size.xhtml [ NeedsRebaseline ]
+crbug.com/451090 svg/custom/resource-client-removal.svg [ NeedsRebaseline ]
+crbug.com/451090 svg/filters/filter-refresh.svg [ NeedsRebaseline ]
+crbug.com/451090 svg/repaint/filter-child-repaint.svg [ NeedsRebaseline ]
+crbug.com/451090 svg/repaint/image-with-clip-path.svg [ NeedsRebaseline ]
+crbug.com/451090 svg/repaint/inner-svg-change-viewPort-relative.svg [ NeedsRebaseline ]
+crbug.com/451090 svg/repaint/paintorder-filtered.svg [ NeedsRebaseline ]
+crbug.com/451090 svg/repaint/text-pattern-update-2.html [ NeedsRebaseline ]
+crbug.com/451090 svg/repaint/text-pattern-update.html [ NeedsRebaseline ]
+crbug.com/451090 svg/repaint/tspan-pattern-update.html [ NeedsRebaseline ]
+crbug.com/451090 svg/text/text-rescale.html [ NeedsRebaseline ]
+crbug.com/451090 svg/text/text-viewbox-rescale.html [ NeedsManualRebaseline ]
+
 crbug.com/627341 imported/wpt/pointerevents/pointerevent_suppress_compat_events_on_click.html [ Skip ]
 crbug.com/627341 imported/wpt/pointerevents/pointerevent_suppress_compat_events_on_drag_mouse.html [ Skip ]
 crbug.com/627341 imported/wpt/pointerevents/pointerevent_touch-action-inherit_child-auto-child-none_touch-manual.html  [ Skip ]
@@ -1110,7 +1202,8 @@
 crbug.com/619103 paint/invalidation/animated-gif.html [ Pass Failure ]
 crbug.com/619103 paint/invalidation/animated-gif-background.html [ Pass Failure ]
 crbug.com/619103 paint/invalidation/animated-gif-background-offscreen.html [ Pass Failure ]
-crbug.com/619103 [ Win ] svg/text/text-viewbox-rescale.html [ Pass Failure ]
+# TODO(wangxianzhu): Restore the following line after manual rebaseline.
+# crbug.com/619103 [ Win ] svg/text/text-viewbox-rescale.html [ Pass Failure ]
 crbug.com/619103 paint/overflow/interest-rect-change-scroll-down.html [ Failure ]
 crbug.com/619103 paint/selection/text-selection-newline-mixed-ltr-rtl.html [ Failure ]
 crbug.com/619103 paint/selection/text-selection-newline-rtl-double-linebreak.html [ Failure ]
diff --git a/third_party/WebKit/LayoutTests/css3/flexbox/repaint-on-margin-change-expected.html b/third_party/WebKit/LayoutTests/css3/flexbox/repaint-on-margin-change-expected.html
index a951ac9..b137506 100644
--- a/third_party/WebKit/LayoutTests/css3/flexbox/repaint-on-margin-change-expected.html
+++ b/third_party/WebKit/LayoutTests/css3/flexbox/repaint-on-margin-change-expected.html
@@ -6,11 +6,12 @@
         .child {
             height: 20px;
             width: 20px;
+            background-color: green;
         }
     </style>
 </head>
 <body>
-    <div style="display: flex; flex-direction: column; height: 100%">
+    <div style="display: flex; flex-direction: column; height: 100%; background-color: blue">
         <div style="flex: 1"></div>
         <div class='nested-row-flexbox'>
             <div class="child"></div>
diff --git a/third_party/WebKit/LayoutTests/css3/flexbox/repaint-on-margin-change.html b/third_party/WebKit/LayoutTests/css3/flexbox/repaint-on-margin-change.html
index fa22c893..b42165f4 100644
--- a/third_party/WebKit/LayoutTests/css3/flexbox/repaint-on-margin-change.html
+++ b/third_party/WebKit/LayoutTests/css3/flexbox/repaint-on-margin-change.html
@@ -14,11 +14,12 @@
         .child {
             height: 20px;
             width: 20px;
+            background-color: green;
         }
     </style>
 </head>
 <body onload="runRepaintAndPixelTest()">
-    <div style="display: flex; flex-direction: column; height: 100%">
+    <div style="display: flex; flex-direction: column; height: 100%; background-color: blue">
         <div style="flex: 1"></div>
         <div class='nested-row-flexbox'>
             <div class="child"></div>
diff --git a/third_party/WebKit/LayoutTests/fast/backgrounds/background-svg-scaling-expected.png b/third_party/WebKit/LayoutTests/fast/backgrounds/background-svg-scaling-expected.png
new file mode 100644
index 0000000..037eec8
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/backgrounds/background-svg-scaling-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/fast/backgrounds/background-svg-scaling.html b/third_party/WebKit/LayoutTests/fast/backgrounds/background-svg-scaling.html
new file mode 100644
index 0000000..8e6f86c
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/backgrounds/background-svg-scaling.html
@@ -0,0 +1,32 @@
+<!DOCTYPE html>
+
+<style>
+
+div {
+  display: inline-block;
+  border-radius: 1px;
+  background-image: url('data:image/svg+xml,\
+    <svg xmlns="http://www.w3.org/2000/svg" width="100" height="100" viewBox="0 0 10 10" stroke="green" stroke-width="2">\
+      <line x1="0" y1="0" x2="10" y2="10"/>\
+      <line x1="10" y1="0" x2="0" y2="10"/>\
+    </svg>');
+}
+</style>
+
+<body>
+  <div style="width: 50px; height: 50px; background-size: 100px;"></div>
+  <div style="width: 50px; height: 50px; background-size: 50px;"></div>
+  <div style="width: 50px; height: 50px; background-size: 25px;"></div>
+  <br>
+
+  <div style="width: 100px; height: 100px; background-size: 200px;"></div>
+  <div style="width: 100px; height: 100px; background-size: 100px;"></div>
+  <div style="width: 100px; height: 100px; background-size: 50px;"></div>
+  <br>
+
+  <div style="width: 200px; height: 200px; background-size: 400px;"></div>
+  <div style="width: 200px; height: 200px; background-size: 200px;"></div>
+  <div style="width: 200px; height: 200px; background-size: 100px;"></div>
+  <br>
+
+</body>
diff --git a/third_party/WebKit/LayoutTests/fast/dom/DeviceLight/create-event-expected.txt b/third_party/WebKit/LayoutTests/fast/dom/DeviceLight/create-event-expected.txt
index 0c00425..a2b696d 100644
--- a/third_party/WebKit/LayoutTests/fast/dom/DeviceLight/create-event-expected.txt
+++ b/third_party/WebKit/LayoutTests/fast/dom/DeviceLight/create-event-expected.txt
@@ -1,15 +1,8 @@
-Tests that document.createEvent() works with DeviceLightEvent.
+Tests the DeviceLightEvent constructor.
 
 On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
 
 
-PASS typeof event == 'object' is true
-PASS event.__proto__ is DeviceLightEvent.prototype
-PASS event instanceof window.DeviceLightEvent is true
-PASS 'type' in event is true
-PASS 'bubbles' in event is true
-PASS 'cancelable' in event is true
-PASS 'value' in event is true
 PASS typeof newEvent.type == 'string' is true
 PASS newEvent.type is "devicelight"
 PASS typeof newEvent.bubbles == 'boolean' is true
@@ -20,6 +13,7 @@
 PASS newEvent.value is 10
 PASS defaultEvent.bubbles is true
 PASS defaultEvent.cancelable is false
+PASS defaultEvent.value is Infinity
 PASS successfullyParsed is true
 
 TEST COMPLETE
diff --git a/third_party/WebKit/LayoutTests/fast/dom/DeviceLight/create-event.html b/third_party/WebKit/LayoutTests/fast/dom/DeviceLight/create-event.html
index c8f934f..55c6cc8 100644
--- a/third_party/WebKit/LayoutTests/fast/dom/DeviceLight/create-event.html
+++ b/third_party/WebKit/LayoutTests/fast/dom/DeviceLight/create-event.html
@@ -3,9 +3,8 @@
 <body>
 <script src="../../../resources/js-test.js"></script>
 <script>
-description("Tests that document.createEvent() works with DeviceLightEvent.");
+description("Tests the DeviceLightEvent constructor.");
 
-var event = document.createEvent('DeviceLightEvent');
 var newEvent = new DeviceLightEvent("devicelight", {
     bubbles: true, cancelable: false,
     value: 10
@@ -13,15 +12,6 @@
 
 var defaultEvent = new DeviceLightEvent("devicelight");
 
-shouldBeTrue("typeof event == 'object'");
-shouldBe("event.__proto__", "DeviceLightEvent.prototype");
-
-shouldBeTrue("event instanceof window.DeviceLightEvent");
-shouldBeTrue("'type' in event");
-shouldBeTrue("'bubbles' in event");
-shouldBeTrue("'cancelable' in event");
-shouldBeTrue("'value' in event");
-
 shouldBeTrue("typeof newEvent.type == 'string'");
 shouldBeEqualToString("newEvent.type", "devicelight");
 shouldBeTrue("typeof newEvent.bubbles == 'boolean'");
@@ -34,6 +24,7 @@
 // FIXME: Consider making bubbles property configurable.
 shouldBeTrue("defaultEvent.bubbles");
 shouldBeFalse("defaultEvent.cancelable");
+shouldBe("defaultEvent.value", "Infinity");
 </script>
 </body>
 </html>
diff --git a/third_party/WebKit/LayoutTests/fast/events/relatedevent-expected.txt b/third_party/WebKit/LayoutTests/fast/events/relatedevent-expected.txt
index 3ea873c..2ee7a06 100644
--- a/third_party/WebKit/LayoutTests/fast/events/relatedevent-expected.txt
+++ b/third_party/WebKit/LayoutTests/fast/events/relatedevent-expected.txt
@@ -3,6 +3,7 @@
 On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
 
 
+PASS relatedEvent.type is "foo"
 PASS relatedEvent.bubbles is false
 PASS relatedEvent.cancelable is false
 PASS relatedEvent.relatedTarget is null
diff --git a/third_party/WebKit/LayoutTests/fast/events/relatedevent.html b/third_party/WebKit/LayoutTests/fast/events/relatedevent.html
index 32229d71..b746f74 100644
--- a/third_party/WebKit/LayoutTests/fast/events/relatedevent.html
+++ b/third_party/WebKit/LayoutTests/fast/events/relatedevent.html
@@ -7,13 +7,15 @@
 
 description("Tests to confirm behavior of updating IDL attributes of RelatedEvent.");
 
-var relatedEvent = document.createEvent("RelatedEvent");
+var relatedEvent = new RelatedEvent("foo");
 
-// We should not be able to update readonly attributes. 
+// We should not be able to update readonly attributes.
+relatedEvent.type = "bar";
 relatedEvent.bubbles = true;
 relatedEvent.cancelable = true;
 relatedEvent.relatedTarget = document;
 
+shouldBeEqualToString("relatedEvent.type", "foo");
 shouldBeFalse("relatedEvent.bubbles");
 shouldBeFalse("relatedEvent.cancelable");
 shouldBeNull("relatedEvent.relatedTarget");
diff --git a/third_party/WebKit/LayoutTests/fast/forms/ValidityState-valueMissing-001-expected.txt b/third_party/WebKit/LayoutTests/fast/forms/ValidityState-valueMissing-001-expected.txt
deleted file mode 100644
index 6097ca4b..0000000
--- a/third_party/WebKit/LayoutTests/fast/forms/ValidityState-valueMissing-001-expected.txt
+++ /dev/null
@@ -1,26 +0,0 @@
-This test checks validity.valueMissing with blank values, blank options selected, or nothing selected.
-
-On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
-
-
-PASS valueMissingFor("input") is true
-PASS valueMissingFor("textarea") is true
-PASS valueMissingFor("select-no-option") is true
-PASS valueMissingFor("select-placeholder-selected") is true
-PASS valueMissingFor("select-without-placeholder") is false
-PASS valueMissingFor("select-placeholder-selected-size2") is false
-PASS valueMissingFor("select-without-placeholder-size2") is false
-PASS valueMissingFor("select-none-selected-multiple") is true
-PASS valueMissingFor("select-fake-placeholder-selected-multiple") is false
-PASS valueMissingFor("select-without-fake-placeholder-multiple") is false
-PASS valueMissingFor("select-none-selected-size2-multiple") is true
-PASS valueMissingFor("select-fake-placeholder-selected-size2-multiple") is false
-PASS valueMissingFor("select-without-fake-placeholder-size2-multiple") is false
-PASS valueMissingFor("select-optgroup") is false
-PASS valueMissingFor("select-disabled-option") is true
-PASS valueMissingFor("select-disabled-option-2") is false
-PASS document.getElementById("select-disabled-option-2").selectedIndex is 1
-PASS successfullyParsed is true
-
-TEST COMPLETE
-               
diff --git a/third_party/WebKit/LayoutTests/fast/forms/ValidityState-valueMissing-001.html b/third_party/WebKit/LayoutTests/fast/forms/ValidityState-valueMissing-001.html
deleted file mode 100644
index a372347e..0000000
--- a/third_party/WebKit/LayoutTests/fast/forms/ValidityState-valueMissing-001.html
+++ /dev/null
@@ -1,96 +0,0 @@
-<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
-<html>
-<head>
-<title>required and basic valueMissing</title>
-<script src="../../resources/js-test.js"></script>
-</head>
-<body>
-<p id="description"></p>
-<div id="console"></div>
-<input id="input" name="victim" required/>
-<textarea id="textarea" name="victim" required></textarea>
-<select id="select-no-option" name="victim" required>
-</select>
-<select id="select-placeholder-selected" name="victim" required>
-  <option value="" selected />
-  <option value="X">X</option>
-</select>
-<select id="select-without-placeholder" name="victim" required>
-  <option value="X">X</option>
-  <option value="" selected />
-</select>
-<select id="select-placeholder-selected-size2" name="victim" size="2" required>
-  <option value="" selected />
-  <option value="X">X</option>
-</select>
-<select id="select-without-placeholder-size2" name="victim" size="2" required>
-  <option value="X">X</option>
-  <option value="" selected />
-</select>
-<select id="select-none-selected-multiple" name="victim" multiple required>
-  <option value="" />
-  <option value="X">X</option>
-</select>
-<select id="select-fake-placeholder-selected-multiple" name="victim" multiple required>
-  <option value="" selected />
-  <option value="X">X</option>
-</select>
-<select id="select-without-fake-placeholder-multiple" name="victim" multiple required>
-  <option value="X">X</option>
-  <option value="" selected />
-</select>
-<select id="select-none-selected-size2-multiple" name="victim" multiple size="2" required>
-  <option value="" />
-  <option value="X">X</option>
-</select>
-<select id="select-fake-placeholder-selected-size2-multiple" name="victim" multiple size="2" required>
-  <option value="" selected />
-  <option value="X">X</option>
-</select>
-<select id="select-without-fake-placeholder-size2-multiple" name="victim" multiple size="2" required>
-  <option value="X">X</option>
-  <option value="" selected />
-</select>
-<select id="select-optgroup" name="victim" required>
-  <optgroup label="1">
-    <option value="" selected />
-  </optgroup>
-  <option value="X">X</option>
-</select>
-<select id="select-disabled-option" name="victim" required>
-  <option value="" disabled selected />
-  <option value="X">X</option>
-</select>
-<select id="select-disabled-option-2" name="victim" required>
-  <option value="" disabled />
-  <option value="X">X</option>
-</select>
-<script language="JavaScript" type="text/javascript">
-    function valueMissingFor(id) {
-        return document.getElementById(id).validity.valueMissing;
-    }
-
-    description("This test checks validity.valueMissing with blank values, blank options selected, or nothing selected.");
-
-    v = document.getElementsByName("victim");
-
-    shouldBeTrue('valueMissingFor("input")');
-    shouldBeTrue('valueMissingFor("textarea")');
-    shouldBeTrue('valueMissingFor("select-no-option")');
-    shouldBeTrue('valueMissingFor("select-placeholder-selected")');
-    shouldBeFalse('valueMissingFor("select-without-placeholder")');
-    shouldBeFalse('valueMissingFor("select-placeholder-selected-size2")');
-    shouldBeFalse('valueMissingFor("select-without-placeholder-size2")');
-    shouldBeTrue('valueMissingFor("select-none-selected-multiple")');
-    shouldBeFalse('valueMissingFor("select-fake-placeholder-selected-multiple")');
-    shouldBeFalse('valueMissingFor("select-without-fake-placeholder-multiple")');
-    shouldBeTrue('valueMissingFor("select-none-selected-size2-multiple")');
-    shouldBeFalse('valueMissingFor("select-fake-placeholder-selected-size2-multiple")');
-    shouldBeFalse('valueMissingFor("select-without-fake-placeholder-size2-multiple")');
-    shouldBeFalse('valueMissingFor("select-optgroup")');
-    shouldBeTrue('valueMissingFor("select-disabled-option")');
-    shouldBeFalse('valueMissingFor("select-disabled-option-2")');
-    shouldBe('document.getElementById("select-disabled-option-2").selectedIndex', '1');
-</script>
-</body>
-</html>
diff --git a/third_party/WebKit/LayoutTests/fast/forms/ValidityState-valueMissing-002-expected.txt b/third_party/WebKit/LayoutTests/fast/forms/ValidityState-valueMissing-002-expected.txt
deleted file mode 100644
index 495faf2..0000000
--- a/third_party/WebKit/LayoutTests/fast/forms/ValidityState-valueMissing-002-expected.txt
+++ /dev/null
@@ -1,26 +0,0 @@
-This test checks validity.valueMissing with some values or options with some values selected.
-
-On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
-
-
-PASS valueMissingFor("input") is false
-PASS valueMissingFor("textarea") is false
-PASS valueMissingFor("select-with-placeholder") is false
-PASS valueMissingFor("select-without-placeholder") is false
-PASS valueMissingFor("select-with-fake-placeholder-size2") is false
-PASS valueMissingFor("select-without-fake-placeholder-size2") is false
-PASS valueMissingFor("select-with-fake-placeholder-multiple") is false
-PASS valueMissingFor("select-without-fake-placeholder-multiple") is false
-PASS valueMissingFor("select-with-fake-placeholder-size2-multiple") is false
-PASS valueMissingFor("select-without-fake-placeholder-size2-multiple") is false
-Updating valueMissing state by a key input:
-PASS valueMissingFor("select-selecting-by-key") is true
-PASS select.value is "a"
-PASS valueMissingFor("select-selecting-by-key") is false
-PASS valueMissingFor("select-selecting-by-key-2") is true
-PASS select.value is "a"
-PASS valueMissingFor("select-selecting-by-key-2") is false
-PASS successfullyParsed is true
-
-TEST COMPLETE
-
diff --git a/third_party/WebKit/LayoutTests/fast/forms/ValidityState-valueMissing-002.html b/third_party/WebKit/LayoutTests/fast/forms/ValidityState-valueMissing-002.html
deleted file mode 100644
index a793c39..0000000
--- a/third_party/WebKit/LayoutTests/fast/forms/ValidityState-valueMissing-002.html
+++ /dev/null
@@ -1,98 +0,0 @@
-<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
-<html>
-<head>
-<title>required and basic valueMissing 2</title>
-<script src="../../resources/js-test.js"></script>
-</head>
-<body>
-<p id="description"></p>
-<div id="console"></div>
-<div id=parent>
-<input id="input" name="victim" value="something" required/>
-<textarea id="textarea" name="victim" required>something</textarea>
-<select id="select-with-placeholder" name="victim" required>
-  <option value="" />
-  <option value="X" selected>X</option>
-</select>
-<select id="select-without-placeholder" name="victim" required>
-  <option value="X" selected>X</option>
-  <option value="" />
-</select>
-<select id="select-with-fake-placeholder-size2" name="victim" size="2" required>
-  <option value="" />
-  <option value="X" selected>X</option>
-</select>
-<select id="select-without-fake-placeholder-size2" name="victim" size="2" required>
-  <option value="X" selected>X</option>
-  <option value="" />
-</select>
-<select id="select-with-fake-placeholder-multiple" name="victim" multiple required>
-  <option value="" />
-  <option value="X" selected>X</option>
-</select>
-<select id="select-without-fake-placeholder-multiple" name="victim" multiple required>
-  <option value="X" selected>X</option>
-  <option value="" />
-</select>
-<select id="select-with-fake-placeholder-size2-multiple" name="victim" multiple size="2" required>
-  <option value="" />
-  <option value="X" selected>X</option>
-</select>
-<select id="select-without-fake-placeholder-size2-multiple" name="victim" multiple size="2" required>
-  <option value="X" selected>X</option>
-  <option value="" />
-</select>
-<select id=select-selecting-by-key required>
-  <option value="" selected/>
-  <option>a</option>
-</select>
-<select id=select-selecting-by-key-2 required>
-  <option value="" selected/>
-  <option accesskey="1">a</option>
-</select>
-</div>
-<script language="JavaScript" type="text/javascript">
-    function valueMissingFor(id) {
-        return document.getElementById(id).validity.valueMissing;
-    }
-
-    description("This test checks validity.valueMissing with some values or options with some values selected.");
-
-    shouldBeFalse('valueMissingFor("input")');
-    shouldBeFalse('valueMissingFor("textarea")');
-    shouldBeFalse('valueMissingFor("select-with-placeholder")');
-    shouldBeFalse('valueMissingFor("select-without-placeholder")');
-    shouldBeFalse('valueMissingFor("select-with-fake-placeholder-size2")');
-    shouldBeFalse('valueMissingFor("select-without-fake-placeholder-size2")');
-    shouldBeFalse('valueMissingFor("select-with-fake-placeholder-multiple")');
-    shouldBeFalse('valueMissingFor("select-without-fake-placeholder-multiple")');
-    shouldBeFalse('valueMissingFor("select-with-fake-placeholder-size2-multiple")');
-    shouldBeFalse('valueMissingFor("select-without-fake-placeholder-size2-multiple")');
-
-    // Need to use eventSender instead of initKeyboardEvent() because we can't
-    // make an event which returns a correct value for keyCode by initKeyboardEvent().
-    if (window.eventSender) {
-        debug("Updating valueMissing state by a key input:")
-        // Select by type-ahead.
-        var select = document.getElementById("select-selecting-by-key");
-        shouldBeTrue('valueMissingFor("select-selecting-by-key")');
-        select.focus();
-        eventSender.keyDown("a");
-        shouldBe('select.value', '"a"');
-        shouldBeFalse('valueMissingFor("select-selecting-by-key")');
-
-        // Select by accesskey.
-        select = document.getElementById("select-selecting-by-key-2");
-        shouldBeTrue('valueMissingFor("select-selecting-by-key-2")');
-        select.focus();
-        eventSender.keyDown("1", "accessKey");
-        shouldBe('select.value', '"a"');
-        shouldBeFalse('valueMissingFor("select-selecting-by-key-2")');
-    } else {
-        debug('There are tests using eventSender.');
-    }
-
-    document.body.removeChild(document.getElementById('parent'));
-</script>
-</body>
-</html>
diff --git a/third_party/WebKit/LayoutTests/fast/forms/ValidityState-valueMissing-003-expected.txt b/third_party/WebKit/LayoutTests/fast/forms/ValidityState-valueMissing-003-expected.txt
deleted file mode 100644
index 63bdcc1..0000000
--- a/third_party/WebKit/LayoutTests/fast/forms/ValidityState-valueMissing-003-expected.txt
+++ /dev/null
@@ -1,22 +0,0 @@
-This test checks validity.valueMissing of disabled form controls with blank values, blank options selected, or nothing selected.
-
-On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
-
-
-PASS valueMissingFor("input") is false
-PASS valueMissingFor("textarea") is false
-PASS valueMissingFor("select-no-option") is false
-PASS valueMissingFor("select-placeholder-selected") is false
-PASS valueMissingFor("select-without-placeholder") is false
-PASS valueMissingFor("select-placeholder-selected-size2") is false
-PASS valueMissingFor("select-without-placeholder-size2") is false
-PASS valueMissingFor("select-none-selected-multiple") is false
-PASS valueMissingFor("select-fake-placeholder-selected-multiple") is false
-PASS valueMissingFor("select-without-fake-placeholder-multiple") is false
-PASS valueMissingFor("select-none-selected-size2-multiple") is false
-PASS valueMissingFor("select-fake-placeholder-selected-size2-multiple") is false
-PASS valueMissingFor("select-without-fake-placeholder-size2-multiple") is false
-PASS successfullyParsed is true
-
-TEST COMPLETE
-            
diff --git a/third_party/WebKit/LayoutTests/fast/forms/ValidityState-valueMissing-003.html b/third_party/WebKit/LayoutTests/fast/forms/ValidityState-valueMissing-003.html
deleted file mode 100644
index 8db2df1..0000000
--- a/third_party/WebKit/LayoutTests/fast/forms/ValidityState-valueMissing-003.html
+++ /dev/null
@@ -1,78 +0,0 @@
-<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
-<html>
-<head>
-<title>required and valueMissing on disabled elements</title>
-<script src="../../resources/js-test.js"></script>
-</head>
-<body>
-<p id="description"></p>
-<div id="console"></div>
-<input id="input" name="victim" disabled required />
-<textarea id="textarea" name="victim" disabled required></textarea>
-<select id="select-no-option" name="victim" disabled required>
-</select>
-<select id="select-placeholder-selected" name="victim" disabled required>
-  <option value="" selected />
-  <option value="X">X</option>
-</select>
-<select id="select-without-placeholder" name="victim" disabled required>
-  <option value="X">X</option>
-  <option value="" selected />
-</select>
-<select id="select-placeholder-selected-size2" name="victim" size="2" disabled required>
-  <option value="" selected />
-  <option value="X">X</option>
-</select>
-<select id="select-without-placeholder-size2" name="victim" size="2" disabled required>
-  <option value="X">X</option>
-  <option value="" selected />
-</select>
-<select id="select-none-selected-multiple" name="victim" multiple disabled required>
-  <option value="" />
-  <option value="X">X</option>
-</select>
-<select id="select-fake-placeholder-selected-multiple" name="victim" multiple disabled required>
-  <option value="" selected />
-  <option value="X">X</option>
-</select>
-<select id="select-without-fake-placeholder-multiple" name="victim" multiple disabled required>
-  <option value="X">X</option>
-  <option value="" selected />
-</select>
-<select id="select-none-selected-size2-multiple" name="victim" multiple size="2" disabled required>
-  <option value="" />
-  <option value="X">X</option>
-</select>
-<select id="select-fake-placeholder-selected-size2-multiple" name="victim" multiple size="2" disabled required>
-  <option value="" selected />
-  <option value="X">X</option>
-</select>
-<select id="select-without-fake-placeholder-size2-multiple" name="victim" multiple size="2" disabled required>
-  <option value="X">X</option>
-  <option value="" selected />
-</select>
-<script language="JavaScript" type="text/javascript">
-    function valueMissingFor(id) {
-        return document.getElementById(id).validity.valueMissing;
-    }
-
-    description("This test checks validity.valueMissing of disabled form controls with blank values, blank options selected, or nothing selected.");
-
-    v = document.getElementsByName("victim");
-
-    shouldBeFalse('valueMissingFor("input")');
-    shouldBeFalse('valueMissingFor("textarea")');
-    shouldBeFalse('valueMissingFor("select-no-option")');
-    shouldBeFalse('valueMissingFor("select-placeholder-selected")');
-    shouldBeFalse('valueMissingFor("select-without-placeholder")');
-    shouldBeFalse('valueMissingFor("select-placeholder-selected-size2")');
-    shouldBeFalse('valueMissingFor("select-without-placeholder-size2")');
-    shouldBeFalse('valueMissingFor("select-none-selected-multiple")');
-    shouldBeFalse('valueMissingFor("select-fake-placeholder-selected-multiple")');
-    shouldBeFalse('valueMissingFor("select-without-fake-placeholder-multiple")');
-    shouldBeFalse('valueMissingFor("select-none-selected-size2-multiple")');
-    shouldBeFalse('valueMissingFor("select-fake-placeholder-selected-size2-multiple")');
-    shouldBeFalse('valueMissingFor("select-without-fake-placeholder-size2-multiple")');
-</script>
-</body>
-</html>
diff --git a/third_party/WebKit/LayoutTests/fast/forms/ValidityState-valueMissing-004-expected.txt b/third_party/WebKit/LayoutTests/fast/forms/ValidityState-valueMissing-004-expected.txt
deleted file mode 100644
index 3127cde..0000000
--- a/third_party/WebKit/LayoutTests/fast/forms/ValidityState-valueMissing-004-expected.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-There are two readonly form control elements below, both required and with some value: validity.valueMissing should be false in both cases.
-
- 
-SUCCESS
diff --git a/third_party/WebKit/LayoutTests/fast/forms/ValidityState-valueMissing-004.html b/third_party/WebKit/LayoutTests/fast/forms/ValidityState-valueMissing-004.html
deleted file mode 100644
index 4dad439..0000000
--- a/third_party/WebKit/LayoutTests/fast/forms/ValidityState-valueMissing-004.html
+++ /dev/null
@@ -1,27 +0,0 @@
-<html>
-<head>
-<title>required and valueMissing on readonly elements</title>
-<script language="JavaScript" type="text/javascript">
-    function log(message) {
-        document.getElementById("console").innerHTML += "<li>"+message+"</li>";
-    }
-
-    function test() {
-        if (window.testRunner)
-            testRunner.dumpAsText();
-
-        v = document.getElementsByName("victim");
-
-        log((!v[0].validity.valueMissing && !v[1].validity.valueMissing) ? "SUCCESS" : "FAILURE");
-    }
-</script>
-</head>
-<body onload="test()">
-<p>There are two readonly form control elements below, both required and with some value:
-validity.valueMissing should be false in both cases.</p>
-<input name="victim" readonly required />
-<textarea name="victim" readonly required></textarea>
-<hr>
-<ol id="console"></ol>
-</body>
-</html>
diff --git a/third_party/WebKit/LayoutTests/fast/forms/ValidityState-valueMissing-005-expected.txt b/third_party/WebKit/LayoutTests/fast/forms/ValidityState-valueMissing-005-expected.txt
deleted file mode 100644
index 888385d..0000000
--- a/third_party/WebKit/LayoutTests/fast/forms/ValidityState-valueMissing-005-expected.txt
+++ /dev/null
@@ -1,9 +0,0 @@
-There's a list of form control elements below, required attribute does not apply to them: validity.valueMissing should be false.
-
-    
-SUCCESS
-SUCCESS
-SUCCESS
-SUCCESS
-SUCCESS
-SUCCESS
diff --git a/third_party/WebKit/LayoutTests/fast/forms/ValidityState-valueMissing-005.html b/third_party/WebKit/LayoutTests/fast/forms/ValidityState-valueMissing-005.html
deleted file mode 100644
index 5dd5ce7e..0000000
--- a/third_party/WebKit/LayoutTests/fast/forms/ValidityState-valueMissing-005.html
+++ /dev/null
@@ -1,32 +0,0 @@
-<html>
-<head>
-<title>required and valueMissing on unaccepted input types</title>
-<script language="JavaScript" type="text/javascript">
-    function log(message) {
-        document.getElementById("console").innerHTML += "<li>"+message+"</li>";
-    }
-
-    function test() {
-        if (window.testRunner)
-            testRunner.dumpAsText();
-
-        v = document.getElementsByName("victim");
-
-        for (i = 0; i < v.length; i++)
-            log(!v[i].validity.valueMissing ? "SUCCESS" : "FAILURE");
-    }
-</script>
-</head>
-<body onload="test()">
-<p>There's a list of form control elements below, required attribute does not apply to them:
-validity.valueMissing should be false.</p>
-<input name="victim" type="hidden" required />
-<input name="victim" type="range" required />
-<input name="victim" type="image" required />
-<input name="victim" type="reset" required />
-<input name="victim" type="button" required />
-<input name="victim" type="submit" required />
-<hr>
-<ol id="console"></ol>
-</body>
-</html>
diff --git a/third_party/WebKit/LayoutTests/fast/forms/ValidityState-valueMissing-006-expected.txt b/third_party/WebKit/LayoutTests/fast/forms/ValidityState-valueMissing-006-expected.txt
deleted file mode 100644
index 8d5d248..0000000
--- a/third_party/WebKit/LayoutTests/fast/forms/ValidityState-valueMissing-006-expected.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-There are two checkboxes below, both are required, only one is checked.
-
- 
-SUCCESS
diff --git a/third_party/WebKit/LayoutTests/fast/forms/ValidityState-valueMissing-006.html b/third_party/WebKit/LayoutTests/fast/forms/ValidityState-valueMissing-006.html
deleted file mode 100644
index 0df4473..0000000
--- a/third_party/WebKit/LayoutTests/fast/forms/ValidityState-valueMissing-006.html
+++ /dev/null
@@ -1,26 +0,0 @@
-<html>
-<head>
-<title>required and valueMissing on checkboxes</title>
-<script language="JavaScript" type="text/javascript">
-    function log(message) {
-        document.getElementById("console").innerHTML += "<li>"+message+"</li>";
-    }
-
-    function test() {
-        if (window.testRunner)
-            testRunner.dumpAsText();
-
-        v = document.getElementsByName("victim");
-
-        log(!v[0].validity.valueMissing && v[1].validity.valueMissing ? "SUCCESS" : "FAILURE");
-    }
-</script>
-</head>
-<body onload="test()">
-<p>There are two checkboxes below, both are required, only one is checked.</p>
-<input name="victim" type="checkbox" required checked/>
-<input name="victim" type="checkbox" required />
-<hr>
-<ol id="console"></ol>
-</body>
-</html>
diff --git a/third_party/WebKit/LayoutTests/fast/forms/ValidityState-valueMissing-008-expected.txt b/third_party/WebKit/LayoutTests/fast/forms/ValidityState-valueMissing-008-expected.txt
deleted file mode 100644
index d8c490a..0000000
--- a/third_party/WebKit/LayoutTests/fast/forms/ValidityState-valueMissing-008-expected.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-There's a upload control below, with no file selected: missing value.
-
-
-SUCCESS
diff --git a/third_party/WebKit/LayoutTests/fast/forms/ValidityState-valueMissing-008.html b/third_party/WebKit/LayoutTests/fast/forms/ValidityState-valueMissing-008.html
deleted file mode 100644
index 238dacb..0000000
--- a/third_party/WebKit/LayoutTests/fast/forms/ValidityState-valueMissing-008.html
+++ /dev/null
@@ -1,25 +0,0 @@
-<html>
-<head>
-<title>required and valueMissing on file control</title>
-<script language="JavaScript" type="text/javascript">
-    function log(message) {
-        document.getElementById("console").innerHTML += "<li>"+message+"</li>";
-    }
-
-    function test() {
-        if (window.testRunner)
-            testRunner.dumpAsText();
-
-        v = document.getElementsByName("victim");
-
-        log(v[0].validity.valueMissing ? "SUCCESS" : "FAILURE");
-    }
-</script>
-</head>
-<body onload="test()">
-<p>There's a upload control below, with no file selected: missing value.</p>
-<input name="victim" type="file" required/>
-<hr>
-<ol id="console"></ol>
-</body>
-</html>
diff --git a/third_party/WebKit/LayoutTests/fast/forms/ValidityState-valueMissing-009-expected.txt b/third_party/WebKit/LayoutTests/fast/forms/ValidityState-valueMissing-009-expected.txt
deleted file mode 100644
index 1acacda..0000000
--- a/third_party/WebKit/LayoutTests/fast/forms/ValidityState-valueMissing-009-expected.txt
+++ /dev/null
@@ -1,10 +0,0 @@
-There's a list of form control elements below, required attribute applies to them but they're empty: validity.valueMissing should be true.
-
-      
-SUCCESS
-SUCCESS
-SUCCESS
-SUCCESS
-SUCCESS
-SUCCESS
-SUCCESS
diff --git a/third_party/WebKit/LayoutTests/fast/forms/ValidityState-valueMissing-009.html b/third_party/WebKit/LayoutTests/fast/forms/ValidityState-valueMissing-009.html
deleted file mode 100644
index e749efe0..0000000
--- a/third_party/WebKit/LayoutTests/fast/forms/ValidityState-valueMissing-009.html
+++ /dev/null
@@ -1,33 +0,0 @@
-<html>
-<head>
-<title>required and valueMissing on new input types</title>
-<script language="JavaScript" type="text/javascript">
-    function log(message) {
-        document.getElementById("console").innerHTML += "<li>"+message+"</li>";
-    }
-
-    function test() {
-        if (window.testRunner)
-            testRunner.dumpAsText();
-
-        v = document.getElementsByName("victim");
-
-        for (i = 0; i < v.length; i++)
-            log(v[i].validity.valueMissing ? "SUCCESS" : "FAILURE");
-    }
-</script>
-</head>
-<body onload="test()">
-<p>There's a list of form control elements below, required attribute applies to them but they're empty:
-validity.valueMissing should be true.</p>
-<input name="victim" type="text" required />
-<input name="victim" type="search" required />
-<input name="victim" type="url" required />
-<input name="victim" type="telephone" required />
-<input name="victim" type="email" required />
-<input name="victim" type="password" required />
-<input name="victim" type="number" required />
-<hr>
-<ol id="console"></ol>
-</body>
-</html>
diff --git a/third_party/WebKit/LayoutTests/fast/forms/ValidityState-valueMissing.html b/third_party/WebKit/LayoutTests/fast/forms/ValidityState-valueMissing.html
new file mode 100644
index 0000000..434e0a8
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/forms/ValidityState-valueMissing.html
@@ -0,0 +1,319 @@
+<!DOCTYPE html>
+<body>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<div id="sample"></div>
+<script>
+function valueMissingFor(html) {
+  var sample = document.getElementById('sample');
+  sample.innerHTML = html;
+  return sample.firstChild.validity.valueMissing;
+}
+
+test(() => {
+  assert_true(valueMissingFor('<input required>'));
+}, 'Empty-value INPUT[required] should be valueMissing.');
+
+test(() => {
+  assert_false(valueMissingFor('<input value="something" required>'));
+}, 'INPUT[required] with a non-empty value should not be valueMissing.');
+
+test(() => {
+  assert_true(valueMissingFor('<textarea required></textarea>'));
+}, 'Empty value TEXTAREA[required] should be valueMissing.');
+
+test(() => {
+  assert_false(valueMissingFor('<textarea required>something</textarea>'));
+}, 'TEXTAREA[required] with a non-empty value should not be valueMissing.');
+
+test(() => {
+  assert_true(valueMissingFor('<select required></select>'));
+}, 'SELECT[required] with no OPTIONS should be valueMissing.');
+
+test(() => {
+  assert_true(valueMissingFor('<select required>' +
+    '<option value="" selected />' +
+    '<option value="X">X</option>' +
+    '</select>'));
+}, 'SELECT[required] with a selected placeholder OPTION should be valueMissing.');
+
+test(() => {
+  assert_false(valueMissingFor('<select required>' +
+    '<option value="X">X</option>' +
+    '<option value="" selected />' +
+    '</select>'));
+}, 'SELECT[required] with a selected non-placeholder OPTION should not be valueMissing.');
+
+test(() => {
+  assert_false(valueMissingFor('<select size="2" required>' +
+    '<option value="" selected />' +
+    '<option value="X">X</option>' +
+    '</select>'));
+}, 'SELECT[required][size=2] with a selected placeholder OPTION should not be valueMissing.');
+
+test(() => {
+  assert_false(valueMissingFor('<select size="2" required>' +
+    '<option value="X">X</option>' +
+    '<option value="" selected />' +
+    '</select>'));
+}, 'SELECT[rquired][size=2] with a selected non-placeholder OPTION should not be valueMissing.');
+
+test(() => {
+  assert_true(valueMissingFor('<select multiple required>' +
+    '<option value="" />' +
+    '<option value="X">X</option>' +
+    '</select>'));
+}, 'SELECT[required][multiple] without selected OPTIONs should be valueMissing.');
+
+test(() => {
+  assert_false(valueMissingFor('<select multiple required>' +
+    '<option value="" selected />' +
+    '<option value="X">X</option>' +
+    '</select>'));
+}, 'SELECT[required][multiple] with a selected placeholder-like OPTION should not be valueMissing.');
+
+test(() => {
+  assert_false(valueMissingFor('<select multiple required>' +
+    '<option value="X">X</option>' +
+    '<option value="" selected />' +
+    '</select>'));
+}, 'SELECT[required][multiple] with a selected OPTION should not be valueMissing.');
+
+test(() => {
+  assert_true(valueMissingFor('<select multiple size="2" required>' +
+    '<option value="" />' +
+    '<option value="X">X</option>' +
+    '</select>'));
+}, 'SELECT[required][multiple][size=2] without selected OPTIONs should be valueMissing.');
+
+test(() => {
+  assert_false(valueMissingFor('<select multiple size="2" required>' +
+    '<option value="" selected />' +
+    '<option value="X">X</option>' +
+    '</select>'));
+}, 'SELECT[required][multiple][size=2] with a selected placeholder-liek OPTION should not be valueMissing.');
+
+test(() => {
+  assert_false(valueMissingFor('<select multiple size="2" required>' +
+    '<option value="X">X</option>' +
+    '<option value="" selected />' +
+    '</select>'));
+}, 'SELECT[required][multiple][size=2] with a selected OPTION should not be valueMissing.');
+
+test(() => {
+  assert_false(valueMissingFor('<select required>' +
+    '<optgroup label="1">' +
+    '  <option value="" selected />' +
+    '</optgroup>' +
+    '<option value="X">X</option>' +
+    '</select>'));
+}, 'SELECT[required] with a selected placeholder-like OPTION inside an OPTGROUP should not be valueMissing.');
+
+test(() => {
+  assert_true(valueMissingFor('<select required>' +
+    '<option value="" disabled selected />' +
+    '<option value="X">X</option>' +
+    '</select>'));
+}, 'SELECT[required] with a selected disabled placeholder OPTION should be valueMissing.');
+
+test(() => {
+  assert_false(valueMissingFor('<select id="select-disabled-option-2" required>' +
+    '<option value="" disabled />' +
+    '<option value="X">X</option>' +
+    '</select>'));
+  assert_equals(document.getElementById('select-disabled-option-2').selectedIndex, 1);
+}, 'SELECT[required] with a non-selected disabled placeholder OPTION should not be valueMissing.');
+
+test(() => {
+  assert_false(valueMissingFor('<select required>' +
+    '<option value="" />' +
+    '<option value="X" selected>X</option>' +
+    '</select>'));
+}, 'SELECT[required] with a unselected placeholder OPTION should not be valueMissing.');
+
+test(() => {
+  assert_false(valueMissingFor('<select size="2" required>' +
+    '<option value="" />' +
+    '<option value="X" selected>X</option>' +
+    '</select>'));
+}, 'SELECT[required][size=2] with a unselected placeholder OPTION should not be valueMissing.');
+
+test(() => {
+  assert_false(valueMissingFor('<select size="2" required>' +
+    '<option value="X" selected>X</option>' +
+    '<option value="" />' +
+    '</select>'));
+}, 'SELECT[required][size=2] with a unselected placeholder-like OPTION should not be valueMissing.');
+
+test(() => {
+  assert_false(valueMissingFor('<select multiple required>' +
+    '<option value="" />' +
+    '<option value="X" selected>X</option>' +
+    '</select>'));
+}, 'SELECT[required][multiple] with a unselected placeholder OPTION should not be valueMissing.');
+
+test(() => {
+  assert_false(valueMissingFor('<select multiple required>' +
+    '<option value="X" selected>X</option>' +
+    '<option value="" />' +
+    '</select>'));
+}, 'SELECT[required][multiple] with a unselected placeholder-like OPTION should not be valueMissing.');
+
+test(() => {
+  assert_false(valueMissingFor('<select multiple size="2" required>' +
+    '<option value="" />' +
+    '<option value="X" selected>X</option>' +
+    '</select>'));
+}, 'SELECT[required][size=2][multiple] with a unselected placeholder OPTION should not be valueMissing.');
+
+test(() => {
+  assert_false(valueMissingFor('<select multiple size="2" required>' +
+    '<option value="X" selected>X</option>' +
+    '<option value="" />' +
+    '</select>'));
+}, 'SELECT[required][size=2][multiple] with a unselected placeholder-like OPTION should not be valueMissing.');
+
+test(() => {
+  assert_true(!!window.eventSender, 'Needs eventSender.');
+  // Select by type-ahead.
+  assert_true(valueMissingFor('<select id="select-selecting-by-key" required>' +
+    '<option value="" selected/>' +
+    '<option>a</option>' +
+    '</select>'));
+  var select = document.getElementById('select-selecting-by-key');
+  select.focus();
+  eventSender.keyDown('a');
+  assert_equals(select.value, 'a');
+  assert_false(select.validity.valueMissing);
+
+  // Select by accesskey.
+  assert_true(valueMissingFor('<select id="select-selecting-by-key-2" required>' +
+    '<option value="" selected/>' +
+    '<option accesskey="1">a</option>' +
+    '</select>'));
+  select = document.getElementById('select-selecting-by-key-2');
+  select.focus();
+  eventSender.keyDown('1', 'accessKey');
+  assert_equals(select.value, 'a');
+  assert_false(select.validity.valueMissing);
+}, 'Updating valueMissing state by user input.');
+
+test(() => {
+  document.querySelector('#sample').innerHTML = '<input name="victim" disabled required />' +
+    '<textarea name="victim" disabled required></textarea>' +
+    '<select name="victim" disabled required>' +
+    '</select>' +
+    '<select name="victim" disabled required>' +
+    '  <option value="" selected />' +
+    '  <option value="X">X</option>' +
+    '</select>' +
+    '<select name="victim" disabled required>' +
+    '  <option value="X">X</option>' +
+    '  <option value="" selected />' +
+    '</select>' +
+    '<select name="victim" size="2" disabled required>' +
+    '  <option value="" selected />' +
+    '  <option value="X">X</option>' +
+    '</select>' +
+    '<select name="victim" size="2" disabled required>' +
+    '  <option value="X">X</option>' +
+    '  <option value="" selected />' +
+    '</select>' +
+    '<select name="victim" multiple disabled required>' +
+    '  <option value="" />' +
+    '  <option value="X">X</option>' +
+    '</select>' +
+    '<select name="victim" multiple disabled required>' +
+    '  <option value="" selected />' +
+    '  <option value="X">X</option>' +
+    '</select>' +
+    '<select name="victim" multiple disabled required>' +
+    '  <option value="X">X</option>' +
+    '  <option value="" selected />' +
+    '</select>' +
+    '<select name="victim" multiple size="2" disabled required>' +
+    '  <option value="" />' +
+    '  <option value="X">X</option>' +
+    '</select>' +
+    '<select name="victim" multiple size="2" disabled required>' +
+    '  <option value="" selected />' +
+    '  <option value="X">X</option>' +
+    '</select>' +
+    '<select name="victim" multiple size="2" disabled required>' +
+    '  <option value="X">X</option>' +
+    '  <option value="" selected />' +
+    '</select>';
+  var controls = document.querySelectorAll(':disabled');
+  for (var c of controls) {
+    assert_false(c.validity.valueMissing);
+  }
+}, 'Disabled controls never be valueMissing.');
+
+test(() => {
+  document.querySelector('#sample').innerHTML =
+    '<input readonly required />' +
+    '<textarea readonly required></textarea>';
+  var controls = document.querySelectorAll('[readonly]');
+  for (var c of controls) {
+    assert_false(c.validity.valueMissing);
+  }
+}, 'Read-only controls never be valueMissing.');
+
+test(() => {
+  document.querySelector('#sample').innerHTML =
+    '<fieldset id="non-supported-container">' +
+    '<input name="victim" type="hidden" required />' +
+    '<input name="victim" type="range" required />' +
+    '<input name="victim" type="image" required />' +
+    '<input name="victim" type="reset" required />' +
+    '<input name="victim" type="button" required />' +
+    '<input name="victim" type="submit" required />' +
+    '</fieldset>';
+  var fieldset = document.querySelector('#non-supported-container');
+  for (var c of fieldset.elements) {
+    assert_false(c.validity.valueMissing);
+  }
+}, 'INPUT elements of some types never be valueMissing.');
+
+test(() => {
+  document.querySelector('#sample').innerHTML =
+    '<input name="victim" type="checkbox" required checked />' +
+    '<input name="victim" type="checkbox" required />';
+  var controls = document.querySelectorAll('input[type=checkbox]');
+  assert_false(controls[0].validity.valueMissing);
+  assert_true(controls[1].validity.valueMissing);
+}, 'INPUT[type=checkbox] supports valueMissing.');
+
+test(() => {
+  assert_true(valueMissingFor('<input type="file" required />'));
+}, 'INPUT[type=file] supports valueMissing.');
+
+test(() => {
+  assert_true(valueMissingFor('<input type="text" required />'));
+}, 'INPUT[type=text] supports valueMissing.');
+
+test(() => {
+  assert_true(valueMissingFor('<input type="search" required />'));
+}, 'INPUT[type=search] supports valueMissing.');
+
+test(() => {
+  assert_true(valueMissingFor('<input type="url" required />'));
+}, 'INPUT[type=url] supports valueMissing.');
+
+test(() => {
+  assert_true(valueMissingFor('<input type="tel" required />'));
+}, 'INPUT[type=tel] supports valueMissing.');
+
+test(() => {
+  assert_true(valueMissingFor('<input type="email" required />'));
+}, 'INPUT[type=email] supports valueMissing.');
+
+test(() => {
+  assert_true(valueMissingFor('<input type="password" required />'));
+}, 'INPUT[type=password] supports valueMissing.');
+
+test(() => {
+  assert_true(valueMissingFor('<input type="number" required />'));
+}, 'INPUT[type=number] supports valueMissing.');
+</script>
+</body>
diff --git a/third_party/WebKit/LayoutTests/imported/wpt/dom/nodes/Document-createEvent-expected.txt b/third_party/WebKit/LayoutTests/imported/wpt/dom/nodes/Document-createEvent-expected.txt
index 157dd2d1..5a2c53a 100644
--- a/third_party/WebKit/LayoutTests/imported/wpt/dom/nodes/Document-createEvent-expected.txt
+++ b/third_party/WebKit/LayoutTests/imported/wpt/dom/nodes/Document-createEvent-expected.txt
@@ -230,9 +230,7 @@
 FAIL createEvent('WHEELEVENT') should be initialized correctly. Cannot read property 'type' of undefined
 PASS Should throw NOT_SUPPORTED_ERR for pluralized legacy event interface "WheelEvents" 
 PASS Should throw NOT_SUPPORTED_ERR for unrecognized arguments 
-FAIL Should throw NOT_SUPPORTED_ERR for non-legacy event interface "AnimationPlayerEvent" assert_throws: function "function () {
-        var evt = document.createEvent(eventInterface);
-      }" did not throw
+PASS Should throw NOT_SUPPORTED_ERR for non-legacy event interface "AnimationPlayerEvent" 
 PASS Should throw NOT_SUPPORTED_ERR for pluralized non-legacy event interface "AnimationPlayerEvents" 
 FAIL Should throw NOT_SUPPORTED_ERR for non-legacy event interface "ApplicationCacheErrorEvent" assert_throws: function "function () {
         var evt = document.createEvent(eventInterface);
@@ -260,9 +258,7 @@
 PASS Should throw NOT_SUPPORTED_ERR for pluralized non-legacy event interface "CommandEvents" 
 PASS Should throw NOT_SUPPORTED_ERR for non-legacy event interface "DataContainerEvent" 
 PASS Should throw NOT_SUPPORTED_ERR for pluralized non-legacy event interface "DataContainerEvents" 
-FAIL Should throw NOT_SUPPORTED_ERR for non-legacy event interface "DeviceLightEvent" assert_throws: function "function () {
-        var evt = document.createEvent(eventInterface);
-      }" did not throw
+PASS Should throw NOT_SUPPORTED_ERR for non-legacy event interface "DeviceLightEvent" 
 PASS Should throw NOT_SUPPORTED_ERR for pluralized non-legacy event interface "DeviceLightEvents" 
 FAIL Should throw NOT_SUPPORTED_ERR for non-legacy event interface "ExtendableEvent" assert_throws: function "function () {
         var evt = document.createEvent(eventInterface);
@@ -286,9 +282,7 @@
 PASS Should throw NOT_SUPPORTED_ERR for pluralized non-legacy event interface "GamepadEvents" 
 PASS Should throw NOT_SUPPORTED_ERR for non-legacy event interface "GeofencingEvent" 
 PASS Should throw NOT_SUPPORTED_ERR for pluralized non-legacy event interface "GeofencingEvents" 
-FAIL Should throw NOT_SUPPORTED_ERR for non-legacy event interface "InstallEvent" assert_throws: function "function () {
-        var evt = document.createEvent(eventInterface);
-      }" did not throw
+PASS Should throw NOT_SUPPORTED_ERR for non-legacy event interface "InstallEvent" 
 PASS Should throw NOT_SUPPORTED_ERR for pluralized non-legacy event interface "InstallEvents" 
 PASS Should throw NOT_SUPPORTED_ERR for non-legacy event interface "KeyEvent" 
 PASS Should throw NOT_SUPPORTED_ERR for pluralized non-legacy event interface "KeyEvents" 
@@ -344,9 +338,7 @@
 PASS Should throw NOT_SUPPORTED_ERR for pluralized non-legacy event interface "OrientationEvents" 
 PASS Should throw NOT_SUPPORTED_ERR for non-legacy event interface "PageTransition" 
 PASS Should throw NOT_SUPPORTED_ERR for pluralized non-legacy event interface "PageTransitions" 
-FAIL Should throw NOT_SUPPORTED_ERR for non-legacy event interface "PointerEvent" assert_throws: function "function () {
-        var evt = document.createEvent(eventInterface);
-      }" did not throw
+PASS Should throw NOT_SUPPORTED_ERR for non-legacy event interface "PointerEvent" 
 PASS Should throw NOT_SUPPORTED_ERR for pluralized non-legacy event interface "PointerEvents" 
 PASS Should throw NOT_SUPPORTED_ERR for non-legacy event interface "PopUpEvent" 
 PASS Should throw NOT_SUPPORTED_ERR for pluralized non-legacy event interface "PopUpEvents" 
@@ -378,9 +370,7 @@
         var evt = document.createEvent(eventInterface);
       }" did not throw
 PASS Should throw NOT_SUPPORTED_ERR for pluralized non-legacy event interface "RTCIceCandidateEvents" 
-FAIL Should throw NOT_SUPPORTED_ERR for non-legacy event interface "RelatedEvent" assert_throws: function "function () {
-        var evt = document.createEvent(eventInterface);
-      }" did not throw
+PASS Should throw NOT_SUPPORTED_ERR for non-legacy event interface "RelatedEvent" 
 PASS Should throw NOT_SUPPORTED_ERR for pluralized non-legacy event interface "RelatedEvents" 
 FAIL Should throw NOT_SUPPORTED_ERR for non-legacy event interface "ResourceProgressEvent" assert_throws: function "function () {
         var evt = document.createEvent(eventInterface);
diff --git a/third_party/WebKit/LayoutTests/inspector/sources/debugger-async/async-await/async-callstack-async-await1-expected.txt b/third_party/WebKit/LayoutTests/inspector/sources/debugger-async/async-await/async-callstack-async-await1-expected.txt
index a38a84f..d8120a18 100644
--- a/third_party/WebKit/LayoutTests/inspector/sources/debugger-async/async-await/async-callstack-async-await1-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector/sources/debugger-async/async-await/async-callstack-async-await1-expected.txt
@@ -3,72 +3,6 @@
 Set timer for test function.
 Captured call stacks in no particular order:
 Call stack:
-    0) doTestChainedPromises (async-callstack-async-await1.html:100)
-    [Promise.resolve]
-    0) resolvePromise (async-callstack-async-await1.html:12)
-    [setTimeout]
-    0) promiseCallback (async-callstack-async-await1.html:21)
-    1) timeoutPromise (async-callstack-async-await1.html:9)
-    2) doTestChainedPromises (async-callstack-async-await1.html:99)
-    3) testFunctionTimeout (async-callstack-async-await1.html:50)
-    [setTimeout]
-    0) testFunction (async-callstack-async-await1.html:43)
-    [setTimeout]
-    0) scheduleTestFunction (debugger-test.js:3)
-    <... skipped remaining frames ...>
-
-Call stack:
-    0) doTestChainedPromises (async-callstack-async-await1.html:102)
-    [Promise.resolve]
-    0) resolvePromise (async-callstack-async-await1.html:12)
-    [setTimeout]
-    0) promiseCallback (async-callstack-async-await1.html:21)
-    1) timeoutPromise (async-callstack-async-await1.html:9)
-    2) doTestChainedPromises (async-callstack-async-await1.html:101)
-    [Promise.resolve]
-    0) resolvePromise (async-callstack-async-await1.html:12)
-    [setTimeout]
-    0) promiseCallback (async-callstack-async-await1.html:21)
-    1) timeoutPromise (async-callstack-async-await1.html:9)
-    2) doTestChainedPromises (async-callstack-async-await1.html:99)
-    3) testFunctionTimeout (async-callstack-async-await1.html:50)
-    [setTimeout]
-    0) testFunction (async-callstack-async-await1.html:43)
-
-Call stack:
-    0) doTestChainedPromises (async-callstack-async-await1.html:104)
-    [Promise.resolve]
-    0) doTestChainedPromises (async-callstack-async-await1.html:103)
-    [Promise.resolve]
-    0) resolvePromise (async-callstack-async-await1.html:12)
-    [setTimeout]
-    0) promiseCallback (async-callstack-async-await1.html:21)
-    1) timeoutPromise (async-callstack-async-await1.html:9)
-    2) doTestChainedPromises (async-callstack-async-await1.html:101)
-    [Promise.resolve]
-    0) resolvePromise (async-callstack-async-await1.html:12)
-    [setTimeout]
-    0) promiseCallback (async-callstack-async-await1.html:21)
-    1) timeoutPromise (async-callstack-async-await1.html:9)
-    2) doTestChainedPromises (async-callstack-async-await1.html:99)
-    3) testFunctionTimeout (async-callstack-async-await1.html:50)
-
-Call stack:
-    0) doTestChainedPromises (async-callstack-async-await1.html:106)
-    [Promise.resolve]
-    0) doTestChainedPromises (async-callstack-async-await1.html:105)
-    [Promise.resolve]
-    0) doTestChainedPromises (async-callstack-async-await1.html:103)
-    [Promise.resolve]
-    0) resolvePromise (async-callstack-async-await1.html:12)
-    [setTimeout]
-    0) promiseCallback (async-callstack-async-await1.html:21)
-    1) timeoutPromise (async-callstack-async-await1.html:9)
-    2) doTestChainedPromises (async-callstack-async-await1.html:101)
-    [Promise.resolve]
-    0) resolvePromise (async-callstack-async-await1.html:12)
-
-Call stack:
     0) errorCallback (async-callstack-async-await1.html:60)
     1) doTestSettledPromisesRejected (async-callstack-async-await1.html:92)
     [Promise.reject]
@@ -92,39 +26,6 @@
 
 Call stack:
     0) thenCallback (async-callstack-async-await1.html:55)
-    1) doTestChainedPromises (async-callstack-async-await1.html:107)
-    [Promise.resolve]
-    0) resolvePromise (async-callstack-async-await1.html:12)
-    [setTimeout]
-    0) promiseCallback (async-callstack-async-await1.html:21)
-    1) timeoutPromise (async-callstack-async-await1.html:9)
-    2) doTestChainedPromises (async-callstack-async-await1.html:107)
-    [Promise.resolve]
-    0) doTestChainedPromises (async-callstack-async-await1.html:105)
-    [Promise.resolve]
-    0) doTestChainedPromises (async-callstack-async-await1.html:103)
-    [Promise.resolve]
-    0) resolvePromise (async-callstack-async-await1.html:12)
-
-Call stack:
-    0) thenCallback (async-callstack-async-await1.html:55)
-    1) doTestChainedPromisesJSON (async-callstack-async-await1.html:119)
-    [Promise.resolve]
-    0) doTestChainedPromisesJSON (async-callstack-async-await1.html:118)
-    [Promise.resolve]
-    0) doTestChainedPromisesJSON (async-callstack-async-await1.html:117)
-    [Promise.resolve]
-    0) resolvePromise (async-callstack-async-await1.html:12)
-    [setTimeout]
-    0) promiseCallback (async-callstack-async-await1.html:21)
-    1) timeoutPromise (async-callstack-async-await1.html:9)
-    2) doTestChainedPromisesJSON (async-callstack-async-await1.html:116)
-    3) testFunctionTimeout (async-callstack-async-await1.html:50)
-    [setTimeout]
-    0) testFunction (async-callstack-async-await1.html:43)
-
-Call stack:
-    0) thenCallback (async-callstack-async-await1.html:55)
     1) doTestPromiseConstructor (async-callstack-async-await1.html:70)
     [Promise.resolve]
     0) doTestPromiseConstructor (async-callstack-async-await1.html:66)
diff --git a/third_party/WebKit/LayoutTests/inspector/sources/debugger-async/async-await/async-callstack-async-await1.html b/third_party/WebKit/LayoutTests/inspector/sources/debugger-async/async-await/async-callstack-async-await1.html
index c1c4d4a4..e6b33037 100644
--- a/third_party/WebKit/LayoutTests/inspector/sources/debugger-async/async-await/async-callstack-async-await1.html
+++ b/third_party/WebKit/LayoutTests/inspector/sources/debugger-async/async-await/async-callstack-async-await1.html
@@ -45,7 +45,7 @@
 
 function testFunctionTimeout()
 {
-    var functions = [doTestPromiseConstructor, doTestSettledPromisesResolved, doTestSettledPromisesRejected, doTestChainedPromises, doTestChainedPromisesJSON];
+    var functions = [doTestPromiseConstructor, doTestSettledPromisesResolved, doTestSettledPromisesRejected];
     for (var i = 0; i < functions.length; ++i)
         functions[i]();
 }
@@ -93,38 +93,9 @@
     }
 }
 
-async function doTestChainedPromises()
-{
-    try {
-        await timeoutPromise(1);
-        debugger;
-        await timeoutPromise(2);
-        debugger;
-        await 3;
-        debugger;
-        await settledPromise(4);
-        debugger;
-        thenCallback(await timeoutPromise(5));
-    } catch (e) {
-        errorCallback(e);
-    }
-}
-
-async function doTestChainedPromisesJSON()
-{
-    try {
-        let one = await timeoutPromise(1);
-        let stringify = await JSON.stringify(one);
-        let parse = await JSON.parse(stringify);
-        thenCallback(parse);
-    } catch (e) {
-        errorCallback(e);
-    }
-}
-
 var test = function()
 {
-    var totalDebuggerStatements = 10;
+    var totalDebuggerStatements = 4;
     var maxAsyncCallStackDepth = 5;
     InspectorTest.runAsyncCallStacksTest(totalDebuggerStatements, maxAsyncCallStackDepth);
 }
diff --git a/third_party/WebKit/LayoutTests/inspector/sources/debugger-async/async-await/async-callstack-async-await2-expected.txt b/third_party/WebKit/LayoutTests/inspector/sources/debugger-async/async-await/async-callstack-async-await2-expected.txt
index 3e93c8e..abfe1c0b 100644
--- a/third_party/WebKit/LayoutTests/inspector/sources/debugger-async/async-await/async-callstack-async-await2-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector/sources/debugger-async/async-await/async-callstack-async-await2-expected.txt
@@ -3,64 +3,13 @@
 Set timer for test function.
 Captured call stacks in no particular order:
 Call stack:
-    0) errorCallback (async-callstack-async-await2.html:60)
-    1) doTestPromiseReject (async-callstack-async-await2.html:129)
-    [Promise.reject]
-    0) doTestPromiseReject (async-callstack-async-await2.html:126)
-    1) testFunctionTimeout (async-callstack-async-await2.html:50)
-    [setTimeout]
-    0) testFunction (async-callstack-async-await2.html:43)
-    [setTimeout]
-    0) scheduleTestFunction (debugger-test.js:3)
-    <... skipped remaining frames ...>
-
-Call stack:
-    0) errorCallback (async-callstack-async-await2.html:60)
-    1) doTestRejectFromChain (async-callstack-async-await2.html:109)
-    [Promise.reject]
-    0) rejectPromise (async-callstack-async-await2.html:16)
-    [setTimeout]
-    0) promiseCallback (async-callstack-async-await2.html:19)
-    1) timeoutPromise (async-callstack-async-await2.html:9)
-    2) rejectFromChain (async-callstack-async-await2.html:98)
+    0) doTestChainedPromises (async-callstack-async-await2.html:67)
     [Promise.resolve]
     0) resolvePromise (async-callstack-async-await2.html:12)
     [setTimeout]
     0) promiseCallback (async-callstack-async-await2.html:21)
     1) timeoutPromise (async-callstack-async-await2.html:9)
-    2) rejectFromChain (async-callstack-async-await2.html:97)
-    [Promise.resolve]
-    0) resolvePromise (async-callstack-async-await2.html:12)
-
-Call stack:
-    0) errorCallback (async-callstack-async-await2.html:60)
-    1) doTestThrowFromChain (async-callstack-async-await2.html:89)
-    [Promise.resolve]
-    0) resolvePromise (async-callstack-async-await2.html:12)
-    [setTimeout]
-    0) promiseCallback (async-callstack-async-await2.html:21)
-    1) timeoutPromise (async-callstack-async-await2.html:9)
-    2) throwFromChain (async-callstack-async-await2.html:76)
-    [Promise.resolve]
-    0) resolvePromise (async-callstack-async-await2.html:12)
-    [setTimeout]
-    0) promiseCallback (async-callstack-async-await2.html:21)
-    1) timeoutPromise (async-callstack-async-await2.html:9)
-    2) throwFromChain (async-callstack-async-await2.html:75)
-    3) doTestThrowFromChain (async-callstack-async-await2.html:86)
-    4) testFunctionTimeout (async-callstack-async-await2.html:50)
-    [setTimeout]
-    0) testFunction (async-callstack-async-await2.html:43)
-
-Call stack:
-    0) thenCallback (async-callstack-async-await2.html:55)
-    1) doTestPromiseAll (async-callstack-async-await2.html:67)
-    [Promise.resolve]
-    0) resolvePromise (async-callstack-async-await2.html:12)
-    [setTimeout]
-    0) promiseCallback (async-callstack-async-await2.html:21)
-    1) timeoutPromise (async-callstack-async-await2.html:9)
-    2) doTestPromiseAll (async-callstack-async-await2.html:66)
+    2) doTestChainedPromises (async-callstack-async-await2.html:66)
     3) testFunctionTimeout (async-callstack-async-await2.html:50)
     [setTimeout]
     0) testFunction (async-callstack-async-await2.html:43)
@@ -69,15 +18,87 @@
     <... skipped remaining frames ...>
 
 Call stack:
-    0) thenCallback (async-callstack-async-await2.html:55)
-    1) doTestPromiseResolve (async-callstack-async-await2.html:117)
+    0) doTestChainedPromises (async-callstack-async-await2.html:69)
     [Promise.resolve]
-    0) doTestPromiseResolve (async-callstack-async-await2.html:116)
-    1) testFunctionTimeout (async-callstack-async-await2.html:50)
+    0) resolvePromise (async-callstack-async-await2.html:12)
+    [setTimeout]
+    0) promiseCallback (async-callstack-async-await2.html:21)
+    1) timeoutPromise (async-callstack-async-await2.html:9)
+    2) doTestChainedPromises (async-callstack-async-await2.html:68)
+    [Promise.resolve]
+    0) resolvePromise (async-callstack-async-await2.html:12)
+    [setTimeout]
+    0) promiseCallback (async-callstack-async-await2.html:21)
+    1) timeoutPromise (async-callstack-async-await2.html:9)
+    2) doTestChainedPromises (async-callstack-async-await2.html:66)
+    3) testFunctionTimeout (async-callstack-async-await2.html:50)
     [setTimeout]
     0) testFunction (async-callstack-async-await2.html:43)
+
+Call stack:
+    0) doTestChainedPromises (async-callstack-async-await2.html:71)
+    [Promise.resolve]
+    0) doTestChainedPromises (async-callstack-async-await2.html:70)
+    [Promise.resolve]
+    0) resolvePromise (async-callstack-async-await2.html:12)
     [setTimeout]
-    0) scheduleTestFunction (debugger-test.js:3)
-    <... skipped remaining frames ...>
+    0) promiseCallback (async-callstack-async-await2.html:21)
+    1) timeoutPromise (async-callstack-async-await2.html:9)
+    2) doTestChainedPromises (async-callstack-async-await2.html:68)
+    [Promise.resolve]
+    0) resolvePromise (async-callstack-async-await2.html:12)
+    [setTimeout]
+    0) promiseCallback (async-callstack-async-await2.html:21)
+    1) timeoutPromise (async-callstack-async-await2.html:9)
+    2) doTestChainedPromises (async-callstack-async-await2.html:66)
+    3) testFunctionTimeout (async-callstack-async-await2.html:50)
+
+Call stack:
+    0) doTestChainedPromises (async-callstack-async-await2.html:73)
+    [Promise.resolve]
+    0) doTestChainedPromises (async-callstack-async-await2.html:72)
+    [Promise.resolve]
+    0) doTestChainedPromises (async-callstack-async-await2.html:70)
+    [Promise.resolve]
+    0) resolvePromise (async-callstack-async-await2.html:12)
+    [setTimeout]
+    0) promiseCallback (async-callstack-async-await2.html:21)
+    1) timeoutPromise (async-callstack-async-await2.html:9)
+    2) doTestChainedPromises (async-callstack-async-await2.html:68)
+    [Promise.resolve]
+    0) resolvePromise (async-callstack-async-await2.html:12)
+
+Call stack:
+    0) thenCallback (async-callstack-async-await2.html:55)
+    1) doTestChainedPromises (async-callstack-async-await2.html:74)
+    [Promise.resolve]
+    0) resolvePromise (async-callstack-async-await2.html:12)
+    [setTimeout]
+    0) promiseCallback (async-callstack-async-await2.html:21)
+    1) timeoutPromise (async-callstack-async-await2.html:9)
+    2) doTestChainedPromises (async-callstack-async-await2.html:74)
+    [Promise.resolve]
+    0) doTestChainedPromises (async-callstack-async-await2.html:72)
+    [Promise.resolve]
+    0) doTestChainedPromises (async-callstack-async-await2.html:70)
+    [Promise.resolve]
+    0) resolvePromise (async-callstack-async-await2.html:12)
+
+Call stack:
+    0) thenCallback (async-callstack-async-await2.html:55)
+    1) doTestChainedPromisesJSON (async-callstack-async-await2.html:86)
+    [Promise.resolve]
+    0) doTestChainedPromisesJSON (async-callstack-async-await2.html:85)
+    [Promise.resolve]
+    0) doTestChainedPromisesJSON (async-callstack-async-await2.html:84)
+    [Promise.resolve]
+    0) resolvePromise (async-callstack-async-await2.html:12)
+    [setTimeout]
+    0) promiseCallback (async-callstack-async-await2.html:21)
+    1) timeoutPromise (async-callstack-async-await2.html:9)
+    2) doTestChainedPromisesJSON (async-callstack-async-await2.html:83)
+    3) testFunctionTimeout (async-callstack-async-await2.html:50)
+    [setTimeout]
+    0) testFunction (async-callstack-async-await2.html:43)
 
 
diff --git a/third_party/WebKit/LayoutTests/inspector/sources/debugger-async/async-await/async-callstack-async-await2.html b/third_party/WebKit/LayoutTests/inspector/sources/debugger-async/async-await/async-callstack-async-await2.html
index 77b73e4..d87dd494 100644
--- a/third_party/WebKit/LayoutTests/inspector/sources/debugger-async/async-await/async-callstack-async-await2.html
+++ b/third_party/WebKit/LayoutTests/inspector/sources/debugger-async/async-await/async-callstack-async-await2.html
@@ -45,7 +45,7 @@
 
 function testFunctionTimeout()
 {
-    var functions = [doTestPromiseAll, doTestThrowFromChain, doTestRejectFromChain, doTestPromiseResolve, doTestPromiseReject];
+    var functions = [doTestChainedPromises, doTestChainedPromisesJSON];
     for (var i = 0; i < functions.length; ++i)
         functions[i]();
 }
@@ -60,71 +60,30 @@
     debugger;
 }
 
-async function doTestPromiseAll()
+async function doTestChainedPromises()
 {
     try {
-        let all = await Promise.all([11, 22, 33, 44, 55].map(timeoutPromise));
-        thenCallback(all);
+        await timeoutPromise(1);
+        debugger;
+        await timeoutPromise(2);
+        debugger;
+        await 3;
+        debugger;
+        await settledPromise(4);
+        debugger;
+        thenCallback(await timeoutPromise(5));
     } catch (e) {
         errorCallback(e);
     }
 }
 
-async function throwFromChain()
-{
-    await timeoutPromise(1);
-    await timeoutPromise(2);
-    await settledPromise(3);
-    throw Error("thrown from 4");
-    await timeoutPromise(5);
-    debugger;
-}
-
-async function doTestThrowFromChain()
+async function doTestChainedPromisesJSON()
 {
     try {
-        let result = await throwFromChain();
-        thencallback(result);
-    } catch (e) {
-        errorCallback(e);
-    }
-}
-
-async function rejectFromChain()
-{
-    await timeoutPromise(1);
-    await timeoutPromise(2);
-    await timeoutPromise(3);
-    await timeoutPromise(new Error(4));
-    throw new Error("thrown from rejectFromChain");
-    debugger;
-}
-
-async function doTestRejectFromChain()
-{
-    try {
-        let result = await rejectFromChain();
-        thenCallback(result);
-    } catch (e) {
-        errorCallback(e);
-    }
-}
-
-async function doTestPromiseResolve()
-{
-    try {
-        let result = await Promise.resolve(1);
-        thenCallback(result);
-    } catch (e) {
-        errorCallback(e);
-    }
-}
-
-async function doTestPromiseReject()
-{
-    try {
-        let result = await Promise.reject(new Error("2"))
-        thenCallback(result);
+        let one = await timeoutPromise(1);
+        let stringify = await JSON.stringify(one);
+        let parse = await JSON.parse(stringify);
+        thenCallback(parse);
     } catch (e) {
         errorCallback(e);
     }
@@ -132,7 +91,7 @@
 
 var test = function()
 {
-    var totalDebuggerStatements = 5;
+    var totalDebuggerStatements = 6;
     var maxAsyncCallStackDepth = 5;
     InspectorTest.runAsyncCallStacksTest(totalDebuggerStatements, maxAsyncCallStackDepth);
 }
diff --git a/third_party/WebKit/LayoutTests/inspector/sources/debugger-async/async-await/async-callstack-async-await3-expected.txt b/third_party/WebKit/LayoutTests/inspector/sources/debugger-async/async-await/async-callstack-async-await3-expected.txt
new file mode 100644
index 0000000..a283de8e3
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/inspector/sources/debugger-async/async-await/async-callstack-async-await3-expected.txt
@@ -0,0 +1,83 @@
+Tests asynchronous call stacks for async functions.
+
+Set timer for test function.
+Captured call stacks in no particular order:
+Call stack:
+    0) errorCallback (async-callstack-async-await3.html:60)
+    1) doTestPromiseReject (async-callstack-async-await3.html:129)
+    [Promise.reject]
+    0) doTestPromiseReject (async-callstack-async-await3.html:126)
+    1) testFunctionTimeout (async-callstack-async-await3.html:50)
+    [setTimeout]
+    0) testFunction (async-callstack-async-await3.html:43)
+    [setTimeout]
+    0) scheduleTestFunction (debugger-test.js:3)
+    <... skipped remaining frames ...>
+
+Call stack:
+    0) errorCallback (async-callstack-async-await3.html:60)
+    1) doTestRejectFromChain (async-callstack-async-await3.html:109)
+    [Promise.reject]
+    0) rejectPromise (async-callstack-async-await3.html:16)
+    [setTimeout]
+    0) promiseCallback (async-callstack-async-await3.html:19)
+    1) timeoutPromise (async-callstack-async-await3.html:9)
+    2) rejectFromChain (async-callstack-async-await3.html:98)
+    [Promise.resolve]
+    0) resolvePromise (async-callstack-async-await3.html:12)
+    [setTimeout]
+    0) promiseCallback (async-callstack-async-await3.html:21)
+    1) timeoutPromise (async-callstack-async-await3.html:9)
+    2) rejectFromChain (async-callstack-async-await3.html:97)
+    [Promise.resolve]
+    0) resolvePromise (async-callstack-async-await3.html:12)
+
+Call stack:
+    0) errorCallback (async-callstack-async-await3.html:60)
+    1) doTestThrowFromChain (async-callstack-async-await3.html:89)
+    [Promise.resolve]
+    0) resolvePromise (async-callstack-async-await3.html:12)
+    [setTimeout]
+    0) promiseCallback (async-callstack-async-await3.html:21)
+    1) timeoutPromise (async-callstack-async-await3.html:9)
+    2) throwFromChain (async-callstack-async-await3.html:76)
+    [Promise.resolve]
+    0) resolvePromise (async-callstack-async-await3.html:12)
+    [setTimeout]
+    0) promiseCallback (async-callstack-async-await3.html:21)
+    1) timeoutPromise (async-callstack-async-await3.html:9)
+    2) throwFromChain (async-callstack-async-await3.html:75)
+    3) doTestThrowFromChain (async-callstack-async-await3.html:86)
+    4) testFunctionTimeout (async-callstack-async-await3.html:50)
+    [setTimeout]
+    0) testFunction (async-callstack-async-await3.html:43)
+
+Call stack:
+    0) thenCallback (async-callstack-async-await3.html:55)
+    1) doTestPromiseAll (async-callstack-async-await3.html:67)
+    [Promise.resolve]
+    0) resolvePromise (async-callstack-async-await3.html:12)
+    [setTimeout]
+    0) promiseCallback (async-callstack-async-await3.html:21)
+    1) timeoutPromise (async-callstack-async-await3.html:9)
+    2) doTestPromiseAll (async-callstack-async-await3.html:66)
+    3) testFunctionTimeout (async-callstack-async-await3.html:50)
+    [setTimeout]
+    0) testFunction (async-callstack-async-await3.html:43)
+    [setTimeout]
+    0) scheduleTestFunction (debugger-test.js:3)
+    <... skipped remaining frames ...>
+
+Call stack:
+    0) thenCallback (async-callstack-async-await3.html:55)
+    1) doTestPromiseResolve (async-callstack-async-await3.html:117)
+    [Promise.resolve]
+    0) doTestPromiseResolve (async-callstack-async-await3.html:116)
+    1) testFunctionTimeout (async-callstack-async-await3.html:50)
+    [setTimeout]
+    0) testFunction (async-callstack-async-await3.html:43)
+    [setTimeout]
+    0) scheduleTestFunction (debugger-test.js:3)
+    <... skipped remaining frames ...>
+
+
diff --git a/third_party/WebKit/LayoutTests/inspector/sources/debugger-async/async-await/async-callstack-async-await3.html b/third_party/WebKit/LayoutTests/inspector/sources/debugger-async/async-await/async-callstack-async-await3.html
new file mode 100644
index 0000000..77b73e4
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/inspector/sources/debugger-async/async-await/async-callstack-async-await3.html
@@ -0,0 +1,149 @@
+<html>
+<head>
+<script src="../../../../http/tests/inspector/inspector-test.js"></script>
+<script src="../../../../http/tests/inspector/debugger-test.js"></script>
+<script>
+
+function timeoutPromise(value, ms)
+{
+    return new Promise(function promiseCallback(resolve, reject) {
+        function resolvePromise()
+        {
+            resolve(value);
+        }
+        function rejectPromise()
+        {
+            reject(value);
+        }
+        if (value instanceof Error)
+            setTimeout(rejectPromise, ms || 0);
+        else
+            setTimeout(resolvePromise, ms || 0);
+    });
+}
+
+function settledPromise(value)
+{
+    function resolveCallback(resolve, reject)
+    {
+        resolve(value);
+    }
+    function rejectCallback(resolve, reject)
+    {
+        reject(value);
+    }
+    if (value instanceof Error)
+        return new Promise(rejectCallback);
+    else
+        return new Promise(resolveCallback);
+}
+
+function testFunction()
+{
+    setTimeout(testFunctionTimeout, 0);
+}
+
+function testFunctionTimeout()
+{
+    var functions = [doTestPromiseAll, doTestThrowFromChain, doTestRejectFromChain, doTestPromiseResolve, doTestPromiseReject];
+    for (var i = 0; i < functions.length; ++i)
+        functions[i]();
+}
+
+function thenCallback(value)
+{
+    debugger;
+}
+
+function errorCallback(error)
+{
+    debugger;
+}
+
+async function doTestPromiseAll()
+{
+    try {
+        let all = await Promise.all([11, 22, 33, 44, 55].map(timeoutPromise));
+        thenCallback(all);
+    } catch (e) {
+        errorCallback(e);
+    }
+}
+
+async function throwFromChain()
+{
+    await timeoutPromise(1);
+    await timeoutPromise(2);
+    await settledPromise(3);
+    throw Error("thrown from 4");
+    await timeoutPromise(5);
+    debugger;
+}
+
+async function doTestThrowFromChain()
+{
+    try {
+        let result = await throwFromChain();
+        thencallback(result);
+    } catch (e) {
+        errorCallback(e);
+    }
+}
+
+async function rejectFromChain()
+{
+    await timeoutPromise(1);
+    await timeoutPromise(2);
+    await timeoutPromise(3);
+    await timeoutPromise(new Error(4));
+    throw new Error("thrown from rejectFromChain");
+    debugger;
+}
+
+async function doTestRejectFromChain()
+{
+    try {
+        let result = await rejectFromChain();
+        thenCallback(result);
+    } catch (e) {
+        errorCallback(e);
+    }
+}
+
+async function doTestPromiseResolve()
+{
+    try {
+        let result = await Promise.resolve(1);
+        thenCallback(result);
+    } catch (e) {
+        errorCallback(e);
+    }
+}
+
+async function doTestPromiseReject()
+{
+    try {
+        let result = await Promise.reject(new Error("2"))
+        thenCallback(result);
+    } catch (e) {
+        errorCallback(e);
+    }
+}
+
+var test = function()
+{
+    var totalDebuggerStatements = 5;
+    var maxAsyncCallStackDepth = 5;
+    InspectorTest.runAsyncCallStacksTest(totalDebuggerStatements, maxAsyncCallStackDepth);
+}
+
+</script>
+</head>
+
+<body onload="runTest()">
+<p>
+Tests asynchronous call stacks for async functions.
+</p>
+
+</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/backgrounds/background-svg-scaling-expected.png b/third_party/WebKit/LayoutTests/platform/linux/fast/backgrounds/background-svg-scaling-expected.png
new file mode 100644
index 0000000..5309f61
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/linux/fast/backgrounds/background-svg-scaling-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/backgrounds/background-svg-scaling-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/fast/backgrounds/background-svg-scaling-expected.txt
new file mode 100644
index 0000000..def0eb24
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/linux/fast/backgrounds/background-svg-scaling-expected.txt
@@ -0,0 +1,35 @@
+layer at (0,0) size 800x600
+  LayoutView at (0,0) size 800x600
+layer at (0,0) size 800x381
+  LayoutBlockFlow {HTML} at (0,0) size 800x381
+    LayoutBlockFlow {BODY} at (8,8) size 784x365
+      LayoutBlockFlow {DIV} at (0,0) size 50x50
+      LayoutText {#text} at (50,35) size 4x19
+        text run at (50,35) width 4: " "
+      LayoutBlockFlow {DIV} at (54,0) size 50x50
+      LayoutText {#text} at (104,35) size 4x19
+        text run at (104,35) width 4: " "
+      LayoutBlockFlow {DIV} at (108,0) size 50x50
+      LayoutText {#text} at (158,35) size 4x19
+        text run at (158,35) width 4: " "
+      LayoutBR {BR} at (0,0) size 0x0
+      LayoutBlockFlow {DIV} at (0,55) size 100x100
+      LayoutText {#text} at (100,140) size 4x19
+        text run at (100,140) width 4: " "
+      LayoutBlockFlow {DIV} at (104,55) size 100x100
+      LayoutText {#text} at (204,140) size 4x19
+        text run at (204,140) width 4: " "
+      LayoutBlockFlow {DIV} at (208,55) size 100x100
+      LayoutText {#text} at (308,140) size 4x19
+        text run at (308,140) width 4: " "
+      LayoutBR {BR} at (0,0) size 0x0
+      LayoutBlockFlow {DIV} at (0,160) size 200x200
+      LayoutText {#text} at (200,345) size 4x19
+        text run at (200,345) width 4: " "
+      LayoutBlockFlow {DIV} at (204,160) size 200x200
+      LayoutText {#text} at (404,345) size 4x19
+        text run at (404,345) width 4: " "
+      LayoutBlockFlow {DIV} at (408,160) size 200x200
+      LayoutText {#text} at (608,345) size 4x19
+        text run at (608,345) width 4: " "
+      LayoutBR {BR} at (0,0) size 0x0
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/backgrounds/background-svg-scaling-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/fast/backgrounds/background-svg-scaling-expected.txt
new file mode 100644
index 0000000..bf26658c
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/mac/fast/backgrounds/background-svg-scaling-expected.txt
@@ -0,0 +1,35 @@
+layer at (0,0) size 800x600
+  LayoutView at (0,0) size 800x600
+layer at (0,0) size 800x378
+  LayoutBlockFlow {HTML} at (0,0) size 800x378
+    LayoutBlockFlow {BODY} at (8,8) size 784x362
+      LayoutBlockFlow {DIV} at (0,0) size 50x50
+      LayoutText {#text} at (50,36) size 4x18
+        text run at (50,36) width 4: " "
+      LayoutBlockFlow {DIV} at (54,0) size 50x50
+      LayoutText {#text} at (104,36) size 4x18
+        text run at (104,36) width 4: " "
+      LayoutBlockFlow {DIV} at (108,0) size 50x50
+      LayoutText {#text} at (158,36) size 4x18
+        text run at (158,36) width 4: " "
+      LayoutBR {BR} at (0,0) size 0x0
+      LayoutBlockFlow {DIV} at (0,54) size 100x100
+      LayoutText {#text} at (100,140) size 4x18
+        text run at (100,140) width 4: " "
+      LayoutBlockFlow {DIV} at (104,54) size 100x100
+      LayoutText {#text} at (204,140) size 4x18
+        text run at (204,140) width 4: " "
+      LayoutBlockFlow {DIV} at (208,54) size 100x100
+      LayoutText {#text} at (308,140) size 4x18
+        text run at (308,140) width 4: " "
+      LayoutBR {BR} at (0,0) size 0x0
+      LayoutBlockFlow {DIV} at (0,158) size 200x200
+      LayoutText {#text} at (200,344) size 4x18
+        text run at (200,344) width 4: " "
+      LayoutBlockFlow {DIV} at (204,158) size 200x200
+      LayoutText {#text} at (404,344) size 4x18
+        text run at (404,344) width 4: " "
+      LayoutBlockFlow {DIV} at (408,158) size 200x200
+      LayoutText {#text} at (608,344) size 4x18
+        text run at (608,344) width 4: " "
+      LayoutBR {BR} at (0,0) size 0x0
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/backgrounds/background-svg-scaling-expected.txt b/third_party/WebKit/LayoutTests/platform/win/fast/backgrounds/background-svg-scaling-expected.txt
new file mode 100644
index 0000000..e2bfe9a
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/win/fast/backgrounds/background-svg-scaling-expected.txt
@@ -0,0 +1,35 @@
+layer at (0,0) size 800x600
+  LayoutView at (0,0) size 800x600
+layer at (0,0) size 800x378
+  LayoutBlockFlow {HTML} at (0,0) size 800x378
+    LayoutBlockFlow {BODY} at (8,8) size 784x362
+      LayoutBlockFlow {DIV} at (0,0) size 50x50
+      LayoutText {#text} at (50,36) size 4x17
+        text run at (50,36) width 4: " "
+      LayoutBlockFlow {DIV} at (54,0) size 50x50
+      LayoutText {#text} at (104,36) size 4x17
+        text run at (104,36) width 4: " "
+      LayoutBlockFlow {DIV} at (108,0) size 50x50
+      LayoutText {#text} at (158,36) size 4x17
+        text run at (158,36) width 4: " "
+      LayoutBR {BR} at (0,0) size 0x0
+      LayoutBlockFlow {DIV} at (0,54) size 100x100
+      LayoutText {#text} at (100,140) size 4x17
+        text run at (100,140) width 4: " "
+      LayoutBlockFlow {DIV} at (104,54) size 100x100
+      LayoutText {#text} at (204,140) size 4x17
+        text run at (204,140) width 4: " "
+      LayoutBlockFlow {DIV} at (208,54) size 100x100
+      LayoutText {#text} at (308,140) size 4x17
+        text run at (308,140) width 4: " "
+      LayoutBR {BR} at (0,0) size 0x0
+      LayoutBlockFlow {DIV} at (0,158) size 200x200
+      LayoutText {#text} at (200,344) size 4x17
+        text run at (200,344) width 4: " "
+      LayoutBlockFlow {DIV} at (204,158) size 200x200
+      LayoutText {#text} at (404,344) size 4x17
+        text run at (404,344) width 4: " "
+      LayoutBlockFlow {DIV} at (408,158) size 200x200
+      LayoutText {#text} at (608,344) size 4x17
+        text run at (608,344) width 4: " "
+      LayoutBR {BR} at (0,0) size 0x0
diff --git a/third_party/WebKit/LayoutTests/svg/canvas/canvas-default-object-sizing-expected.html b/third_party/WebKit/LayoutTests/svg/canvas/canvas-default-object-sizing-expected.html
index 03e0925..6a84c91 100644
--- a/third_party/WebKit/LayoutTests/svg/canvas/canvas-default-object-sizing-expected.html
+++ b/third_party/WebKit/LayoutTests/svg/canvas/canvas-default-object-sizing-expected.html
@@ -1,32 +1,37 @@
 <!DOCTYPE html>
 <title>Sizing SVG image when drawn to canvas</title>
 <script>
-function createCircle(x, y, r, sx, sy)
+function createCanvas(drawFunc)
 {
     var canvas = document.createElement('canvas');
     canvas.width = 100;
     canvas.height = 100;
     document.documentElement.appendChild(canvas);
 
-    var ctx = canvas.getContext('2d');
+    drawFunc(canvas.getContext('2d'));
+}
+
+function drawCircle(ctx, x, y, r, sx, sy)
+{
     ctx.fillStyle = "blue";
 
-    ctx.translate(50, 50);
     ctx.scale(sx || 1, sy || 1);
     ctx.beginPath();
     ctx.arc(x, y, r, 0, 2*Math.PI);
     ctx.fill();
 }
-createCircle(0, 0, 50);
-createCircle(0, -25, 25);
-createCircle(-25, 0, 25);
-createCircle(0, 0, 25, 1, 2);
-createCircle(0, 0, 25, 2, 1);
-createCircle(-25, 0, 25);
-createCircle(0, -25, 25);
-createCircle(0, -25, 25);
-createCircle(0, 0, 50);
-createCircle(0, 0, 50);
-createCircle(0, -25, 25);
-createCircle(0, 0, 50);
+
+createCanvas(function (ctx) { drawCircle(ctx, 50, 50, 50); });
+createCanvas(function (ctx) { drawCircle(ctx, 50, 25, 25); });
+createCanvas(function (ctx) { drawCircle(ctx, 25, 50, 25); });
+createCanvas(function (ctx) { drawCircle(ctx, 50, 25, 25, 1, 2); });
+createCanvas(function (ctx) { drawCircle(ctx, 25, 50, 25, 2, 1); });
+createCanvas(function (ctx) { drawCircle(ctx, 25, 50, 25); });
+createCanvas(function (ctx) { drawCircle(ctx, 50, 25, 25); });
+createCanvas(function (ctx) { drawCircle(ctx, 50, 25, 25); });
+createCanvas(function (ctx) { drawCircle(ctx, 50, 50, 50); });
+createCanvas(function (ctx) { drawCircle(ctx, 50, 50, 50); });
+createCanvas(function (ctx) { drawCircle(ctx, 50, 25, 25); drawCircle(ctx, 50, 75, 25); });
+createCanvas(function (ctx) { drawCircle(ctx, 50, 50, 50); });
+
 </script>
diff --git a/third_party/WebKit/LayoutTests/webaudio/audiobuffer-getChannelData.html b/third_party/WebKit/LayoutTests/webaudio/audiobuffer-getChannelData.html
index bb5064a3..667dbfd9 100644
--- a/third_party/WebKit/LayoutTests/webaudio/audiobuffer-getChannelData.html
+++ b/third_party/WebKit/LayoutTests/webaudio/audiobuffer-getChannelData.html
@@ -1,10 +1,10 @@
 <!doctype html>
 <html>
   <head>
+    <script src="../resources/js-test.js"></script>
     <script src="resources/compatibility.js"></script>
     <script src="resources/audio-testing.js"></script>
     <script src="resources/audioparam-testing.js"></script>
-    <script src="../resources/js-test.js"></script>
     <title>Test AudioBuffer.getChannelData() Returns the Same Object</title>
   </head>
 
diff --git a/third_party/WebKit/LayoutTests/webaudio/audiobuffer-resample.html b/third_party/WebKit/LayoutTests/webaudio/audiobuffer-resample.html
index 0a56884..85eeeb0 100644
--- a/third_party/WebKit/LayoutTests/webaudio/audiobuffer-resample.html
+++ b/third_party/WebKit/LayoutTests/webaudio/audiobuffer-resample.html
@@ -1,9 +1,9 @@
 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
 <html>
   <head>
+    <script src="../resources/js-test.js"></script>
     <script src="resources/compatibility.js"></script>
     <script src="resources/audio-testing.js"></script>
-    <script src="../resources/js-test.js"></script>
   </head>
 
   <body>
diff --git a/third_party/WebKit/LayoutTests/webaudio/audiobuffersource-grain.html b/third_party/WebKit/LayoutTests/webaudio/audiobuffersource-grain.html
index 0011e27..040c284 100644
--- a/third_party/WebKit/LayoutTests/webaudio/audiobuffersource-grain.html
+++ b/third_party/WebKit/LayoutTests/webaudio/audiobuffersource-grain.html
@@ -2,9 +2,9 @@
 <html>
   <head>
     <title>Test Start Grain with Delayed Buffer Setting </title>
+    <script src="../resources/js-test.js"></script>
     <script src="resources/compatibility.js"></script>
     <script src="resources/audio-testing.js"></script>
-    <script src="../resources/js-test.js"></script>
   </head>
 
   <body>
diff --git a/third_party/WebKit/LayoutTests/webaudio/audiobuffersource-loop-comprehensive.html b/third_party/WebKit/LayoutTests/webaudio/audiobuffersource-loop-comprehensive.html
index b012b24e..bece52e 100644
--- a/third_party/WebKit/LayoutTests/webaudio/audiobuffersource-loop-comprehensive.html
+++ b/third_party/WebKit/LayoutTests/webaudio/audiobuffersource-loop-comprehensive.html
@@ -2,10 +2,10 @@
 
 <html>
 <head>
-<script src="resources/audio-testing.js"></script>
-<script src="resources/compatibility.js"></script>
-<script src="resources/audiobuffersource-testing.js"></script>
 <script src="../resources/js-test.js"></script>
+<script src="resources/compatibility.js"></script>
+<script src="resources/audio-testing.js"></script>
+<script src="resources/audiobuffersource-testing.js"></script>
 </head>
 
 <body>
diff --git a/third_party/WebKit/LayoutTests/webaudio/audiobuffersource-one-sample-loop.html b/third_party/WebKit/LayoutTests/webaudio/audiobuffersource-one-sample-loop.html
index f15d77e..906c100 100644
--- a/third_party/WebKit/LayoutTests/webaudio/audiobuffersource-one-sample-loop.html
+++ b/third_party/WebKit/LayoutTests/webaudio/audiobuffersource-one-sample-loop.html
@@ -2,9 +2,9 @@
 <html>
   <head>
     <title>Test AudioBufferSourceNode With Looping a Single-Sample Buffer</title>
+    <script src="../resources/js-test.js"></script>
     <script src="resources/compatibility.js"></script>
     <script src="resources/audio-testing.js"></script>
-    <script src="../resources/js-test.js"></script>
   </head>
 
   <body>
diff --git a/third_party/WebKit/LayoutTests/webaudio/audiobuffersource-start.html b/third_party/WebKit/LayoutTests/webaudio/audiobuffersource-start.html
index 012c0c4..2f803873 100644
--- a/third_party/WebKit/LayoutTests/webaudio/audiobuffersource-start.html
+++ b/third_party/WebKit/LayoutTests/webaudio/audiobuffersource-start.html
@@ -2,10 +2,10 @@
 
 <html>
 <head>
+<script src="../resources/js-test.js"></script>
 <script src="resources/compatibility.js"></script>
 <script src="resources/audio-testing.js"></script>
 <script src="resources/audiobuffersource-testing.js"></script>
-<script src="../resources/js-test.js"></script>
 </head>
 
 <body>
diff --git a/third_party/WebKit/LayoutTests/webaudio/audiocontext-close-basic.html b/third_party/WebKit/LayoutTests/webaudio/audiocontext-close-basic.html
index c661916f..2785fed 100644
--- a/third_party/WebKit/LayoutTests/webaudio/audiocontext-close-basic.html
+++ b/third_party/WebKit/LayoutTests/webaudio/audiocontext-close-basic.html
@@ -2,9 +2,9 @@
 <html>
   <head>
     <title>Test AudioContext.close() closes many contexts</title>
+    <script src="../resources/js-test.js"></script>
     <script src="resources/compatibility.js"></script>
     <script src="resources/audio-testing.js"></script>
-    <script src="../resources/js-test.js"></script>
   </head>
 
   <body>
diff --git a/third_party/WebKit/LayoutTests/webaudio/audioparam-connect-audioratesignal.html b/third_party/WebKit/LayoutTests/webaudio/audioparam-connect-audioratesignal.html
index f261959..93f13cda 100644
--- a/third_party/WebKit/LayoutTests/webaudio/audioparam-connect-audioratesignal.html
+++ b/third_party/WebKit/LayoutTests/webaudio/audioparam-connect-audioratesignal.html
@@ -11,9 +11,9 @@
 
 <html>
 <head>
+<script src="../resources/js-test.js"></script>
 <script src="resources/compatibility.js"></script>
 <script src="resources/audio-testing.js"></script>
-<script src="../resources/js-test.js"></script>
 
 </head>
 <body>
diff --git a/third_party/WebKit/LayoutTests/webaudio/audioparam-exponentialRampToValueAtTime.html b/third_party/WebKit/LayoutTests/webaudio/audioparam-exponentialRampToValueAtTime.html
index 5af3ffb2..b0cfe3a 100644
--- a/third_party/WebKit/LayoutTests/webaudio/audioparam-exponentialRampToValueAtTime.html
+++ b/third_party/WebKit/LayoutTests/webaudio/audioparam-exponentialRampToValueAtTime.html
@@ -1,10 +1,10 @@
 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
 <html>
   <head>
+    <script src="../resources/js-test.js"></script>
     <script src="resources/compatibility.js"></script>
     <script src="resources/audio-testing.js"></script>
     <script src="resources/audioparam-testing.js"></script>
-    <script src="../resources/js-test.js"></script>
     <title>Test AudioParam.exponentialRampToValueAtTime</title>
   </head>
 
diff --git a/third_party/WebKit/LayoutTests/webaudio/audioparam-linearRampToValueAtTime.html b/third_party/WebKit/LayoutTests/webaudio/audioparam-linearRampToValueAtTime.html
index 6f5ade8..5862738 100644
--- a/third_party/WebKit/LayoutTests/webaudio/audioparam-linearRampToValueAtTime.html
+++ b/third_party/WebKit/LayoutTests/webaudio/audioparam-linearRampToValueAtTime.html
@@ -1,10 +1,10 @@
 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
 <html>
 <head>
+<script src="../resources/js-test.js"></script>
 <script src="resources/compatibility.js"></script>
 <script src="resources/audio-testing.js"></script>
 <script src="resources/audioparam-testing.js"></script>
-<script src="../resources/js-test.js"></script>
 <title>Test AudioParam.linearRampToValueAtTime</title>
 </head>
 
diff --git a/third_party/WebKit/LayoutTests/webaudio/audioparam-sampling.html b/third_party/WebKit/LayoutTests/webaudio/audioparam-sampling.html
index c4561788..af68c36 100644
--- a/third_party/WebKit/LayoutTests/webaudio/audioparam-sampling.html
+++ b/third_party/WebKit/LayoutTests/webaudio/audioparam-sampling.html
@@ -1,10 +1,10 @@
 <!doctype html>
 <html>
   <head>
+    <script src="../resources/js-test.js"></script>
     <script src="resources/compatibility.js"></script>
     <script src="resources/audio-testing.js"></script>
     <script src="resources/audioparam-testing.js"></script>
-    <script src="../resources/js-test.js"></script>
     <title>Test Sampling of LinearRampToValueAtTime</title>
   </head>
 
diff --git a/third_party/WebKit/LayoutTests/webaudio/audioparam-setTargetAtTime-sampling.html b/third_party/WebKit/LayoutTests/webaudio/audioparam-setTargetAtTime-sampling.html
index adbce48..e9a6651 100644
--- a/third_party/WebKit/LayoutTests/webaudio/audioparam-setTargetAtTime-sampling.html
+++ b/third_party/WebKit/LayoutTests/webaudio/audioparam-setTargetAtTime-sampling.html
@@ -1,10 +1,10 @@
 <!doctype html>
 <html>
   <head>
+    <script src="../resources/js-test.js"></script>
     <script src="resources/compatibility.js"></script>
     <script src="resources/audio-testing.js"></script>
     <script src="resources/audioparam-testing.js"></script>
-    <script src="../resources/js-test.js"></script>
     <title>Test Sampling for SetTargetAtTime</title>
   </head>
 
diff --git a/third_party/WebKit/LayoutTests/webaudio/audioparam-setTargetAtTime.html b/third_party/WebKit/LayoutTests/webaudio/audioparam-setTargetAtTime.html
index 200f02d..b10f6942 100644
--- a/third_party/WebKit/LayoutTests/webaudio/audioparam-setTargetAtTime.html
+++ b/third_party/WebKit/LayoutTests/webaudio/audioparam-setTargetAtTime.html
@@ -1,10 +1,10 @@
 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
 <html>
 <head>
+<script src="../resources/js-test.js"></script>
 <script src="resources/compatibility.js"></script>
 <script src="resources/audio-testing.js"></script>
 <script src="resources/audioparam-testing.js"></script>
-<script src="../resources/js-test.js"></script>
 <title>Test AudioParam.setTargetAtTime</title>
 </head>
 
diff --git a/third_party/WebKit/LayoutTests/webaudio/audioparam-setValueAtTime.html b/third_party/WebKit/LayoutTests/webaudio/audioparam-setValueAtTime.html
index 908c4b9..9319240 100644
--- a/third_party/WebKit/LayoutTests/webaudio/audioparam-setValueAtTime.html
+++ b/third_party/WebKit/LayoutTests/webaudio/audioparam-setValueAtTime.html
@@ -1,10 +1,10 @@
 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
 <html>
 <head>
+<script src="../resources/js-test.js"></script>
 <script src="resources/compatibility.js"></script>
 <script src="resources/audio-testing.js"></script>
 <script src="resources/audioparam-testing.js"></script>
-<script src="../resources/js-test.js"></script>
 </head>
 
 <body>
diff --git a/third_party/WebKit/LayoutTests/webaudio/audioparam-setValueCurve-duration.html b/third_party/WebKit/LayoutTests/webaudio/audioparam-setValueCurve-duration.html
index 50be73c..982af386 100644
--- a/third_party/WebKit/LayoutTests/webaudio/audioparam-setValueCurve-duration.html
+++ b/third_party/WebKit/LayoutTests/webaudio/audioparam-setValueCurve-duration.html
@@ -1,10 +1,10 @@
 <!doctype html>
 <html>
   <head>
+    <script src="../resources/js-test.js"></script>
     <script src="resources/compatibility.js"></script>
     <script src="resources/audio-testing.js"></script>
     <script src="resources/audioparam-testing.js"></script>
-    <script src="../resources/js-test.js"></script>
     <title>Test setValueCurveAtTime with Huge Duration</title>
   </head>
 
diff --git a/third_party/WebKit/LayoutTests/webaudio/audioparam-setValueCurveAtTime.html b/third_party/WebKit/LayoutTests/webaudio/audioparam-setValueCurveAtTime.html
index 09f60e9..4cc47c1d 100644
--- a/third_party/WebKit/LayoutTests/webaudio/audioparam-setValueCurveAtTime.html
+++ b/third_party/WebKit/LayoutTests/webaudio/audioparam-setValueCurveAtTime.html
@@ -1,10 +1,10 @@
 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
 <html>
 <head>
+<script src="../resources/js-test.js"></script>
 <script src="resources/compatibility.js"></script>
 <script src="resources/audio-testing.js"></script>
 <script src="resources/audioparam-testing.js"></script>
-<script src="../resources/js-test.js"></script>
 <title>Test AudioParam.setValueCurveAtTime</title>
 </head>
 
diff --git a/third_party/WebKit/LayoutTests/webaudio/audioparam-summingjunction.html b/third_party/WebKit/LayoutTests/webaudio/audioparam-summingjunction.html
index 60bf7fa..7bd5eef 100644
--- a/third_party/WebKit/LayoutTests/webaudio/audioparam-summingjunction.html
+++ b/third_party/WebKit/LayoutTests/webaudio/audioparam-summingjunction.html
@@ -7,10 +7,10 @@
 
 <html>
 <head>
+<script src="../resources/js-test.js"></script>
 <script src="resources/compatibility.js"></script>
 <script src="resources/audio-testing.js"></script>
 <script src="resources/mix-testing.js"></script>
-<script src="../resources/js-test.js"></script>
 
 </head>
 <body>
diff --git a/third_party/WebKit/LayoutTests/webaudio/audioparam-update-value-attribute.html b/third_party/WebKit/LayoutTests/webaudio/audioparam-update-value-attribute.html
index 8cb4eab2..4824971 100644
--- a/third_party/WebKit/LayoutTests/webaudio/audioparam-update-value-attribute.html
+++ b/third_party/WebKit/LayoutTests/webaudio/audioparam-update-value-attribute.html
@@ -1,10 +1,10 @@
 <!doctype html>
 <html>
   <head>
+    <script src="../resources/js-test.js"></script>
     <script src="resources/compatibility.js"></script>
     <script src="resources/audio-testing.js"></script>
     <script src="resources/audio-param.js"></script>
-    <script src="../resources/js-test.js"></script>
     <title>Updating of Value Attribute from Timeline</title>
   </head>
 
diff --git a/third_party/WebKit/LayoutTests/webaudio/audiosource-time-limits.html b/third_party/WebKit/LayoutTests/webaudio/audiosource-time-limits.html
index 59cdb7b..7a9f6c7 100644
--- a/third_party/WebKit/LayoutTests/webaudio/audiosource-time-limits.html
+++ b/third_party/WebKit/LayoutTests/webaudio/audiosource-time-limits.html
@@ -1,10 +1,10 @@
 <!doctype html>
 <html>
   <head>
+    <script src="../resources/js-test.js"></script>
     <script src="resources/compatibility.js"></script>
     <script src="resources/audio-testing.js"></script>
     <script src="resources/audioparam-testing.js"></script>
-    <script src="../resources/js-test.js"></script>
     <title>Test Scheduled Sources with Huge Time Limits</title>
   </head>
 
diff --git a/third_party/WebKit/LayoutTests/webaudio/biquad-allpass.html b/third_party/WebKit/LayoutTests/webaudio/biquad-allpass.html
index 8493418..41a07b1 100644
--- a/third_party/WebKit/LayoutTests/webaudio/biquad-allpass.html
+++ b/third_party/WebKit/LayoutTests/webaudio/biquad-allpass.html
@@ -2,9 +2,9 @@
 
 <html>
 <head>
+<script src="../resources/js-test.js"></script>
 <script src="resources/compatibility.js"></script>
 <script src="resources/audio-testing.js"></script>
-<script src="../resources/js-test.js"></script>
 <script src="resources/biquad-filters.js"></script>
 <script src="resources/biquad-testing.js"></script>
 </head>
diff --git a/third_party/WebKit/LayoutTests/webaudio/biquad-bandpass.html b/third_party/WebKit/LayoutTests/webaudio/biquad-bandpass.html
index 14885e7..69c3996 100644
--- a/third_party/WebKit/LayoutTests/webaudio/biquad-bandpass.html
+++ b/third_party/WebKit/LayoutTests/webaudio/biquad-bandpass.html
@@ -2,9 +2,9 @@
 
 <html>
 <head>
+<script src="../resources/js-test.js"></script>
 <script src="resources/compatibility.js"></script>
 <script src="resources/audio-testing.js"></script>
-<script src="../resources/js-test.js"></script>
 <script src="resources/biquad-filters.js"></script>
 <script src="resources/biquad-testing.js"></script>
 </head>
diff --git a/third_party/WebKit/LayoutTests/webaudio/biquad-getFrequencyResponse.html b/third_party/WebKit/LayoutTests/webaudio/biquad-getFrequencyResponse.html
index b517a6e..0c95af10 100644
--- a/third_party/WebKit/LayoutTests/webaudio/biquad-getFrequencyResponse.html
+++ b/third_party/WebKit/LayoutTests/webaudio/biquad-getFrequencyResponse.html
@@ -1,11 +1,11 @@
 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
 <html>
 <head>
+<script src="../resources/js-test.js"></script>
 <script src="resources/compatibility.js"></script>
 <script src="resources/audio-testing.js"></script>
 <script src="resources/biquad-filters.js"></script>
 <script src="resources/biquad-testing.js"></script>
-<script src="../resources/js-test.js"></script>
 </head>
 
 <body>
diff --git a/third_party/WebKit/LayoutTests/webaudio/biquad-highpass.html b/third_party/WebKit/LayoutTests/webaudio/biquad-highpass.html
index d12b482..ddf1819 100644
--- a/third_party/WebKit/LayoutTests/webaudio/biquad-highpass.html
+++ b/third_party/WebKit/LayoutTests/webaudio/biquad-highpass.html
@@ -2,9 +2,9 @@
 
 <html>
 <head>
+<script src="../resources/js-test.js"></script>
 <script src="resources/compatibility.js"></script>
 <script src="resources/audio-testing.js"></script>
-<script src="../resources/js-test.js"></script>
 <script src="resources/biquad-filters.js"></script>
 <script src="resources/biquad-testing.js"></script>
 </head>
diff --git a/third_party/WebKit/LayoutTests/webaudio/biquad-highshelf.html b/third_party/WebKit/LayoutTests/webaudio/biquad-highshelf.html
index 346867da..d47f654 100644
--- a/third_party/WebKit/LayoutTests/webaudio/biquad-highshelf.html
+++ b/third_party/WebKit/LayoutTests/webaudio/biquad-highshelf.html
@@ -2,9 +2,9 @@
 
 <html>
 <head>
+<script src="../resources/js-test.js"></script>
 <script src="resources/compatibility.js"></script>
 <script src="resources/audio-testing.js"></script>
-<script src="../resources/js-test.js"></script>
 <script src="resources/biquad-filters.js"></script>
 <script src="resources/biquad-testing.js"></script>
 </head>
diff --git a/third_party/WebKit/LayoutTests/webaudio/biquad-lowpass.html b/third_party/WebKit/LayoutTests/webaudio/biquad-lowpass.html
index cb8c306..daaf838 100644
--- a/third_party/WebKit/LayoutTests/webaudio/biquad-lowpass.html
+++ b/third_party/WebKit/LayoutTests/webaudio/biquad-lowpass.html
@@ -2,9 +2,9 @@
 
 <html>
 <head>
+<script src="../resources/js-test.js"></script>
 <script src="resources/compatibility.js"></script>
 <script src="resources/audio-testing.js"></script>
-<script src="../resources/js-test.js"></script>
 <script src="resources/biquad-filters.js"></script>
 <script src="resources/biquad-testing.js"></script>
 </head>
diff --git a/third_party/WebKit/LayoutTests/webaudio/biquad-lowshelf.html b/third_party/WebKit/LayoutTests/webaudio/biquad-lowshelf.html
index 27a6f3b5..92d1410 100644
--- a/third_party/WebKit/LayoutTests/webaudio/biquad-lowshelf.html
+++ b/third_party/WebKit/LayoutTests/webaudio/biquad-lowshelf.html
@@ -2,9 +2,9 @@
 
 <html>
 <head>
+<script src="../resources/js-test.js"></script>
 <script src="resources/compatibility.js"></script>
 <script src="resources/audio-testing.js"></script>
-<script src="../resources/js-test.js"></script>
 <script src="resources/biquad-filters.js"></script>
 <script src="resources/biquad-testing.js"></script>
 </head>
diff --git a/third_party/WebKit/LayoutTests/webaudio/biquad-notch.html b/third_party/WebKit/LayoutTests/webaudio/biquad-notch.html
index 177f4d0..cc99940 100644
--- a/third_party/WebKit/LayoutTests/webaudio/biquad-notch.html
+++ b/third_party/WebKit/LayoutTests/webaudio/biquad-notch.html
@@ -2,9 +2,9 @@
 
 <html>
 <head>
+<script src="../resources/js-test.js"></script>
 <script src="resources/compatibility.js"></script>
 <script src="resources/audio-testing.js"></script>
-<script src="../resources/js-test.js"></script>
 <script src="resources/biquad-filters.js"></script>
 <script src="resources/biquad-testing.js"></script>
 </head>
diff --git a/third_party/WebKit/LayoutTests/webaudio/biquad-peaking.html b/third_party/WebKit/LayoutTests/webaudio/biquad-peaking.html
index 0f09286..bd44394 100644
--- a/third_party/WebKit/LayoutTests/webaudio/biquad-peaking.html
+++ b/third_party/WebKit/LayoutTests/webaudio/biquad-peaking.html
@@ -2,9 +2,9 @@
 
 <html>
 <head>
+<script src="../resources/js-test.js"></script>
 <script src="resources/compatibility.js"></script>
 <script src="resources/audio-testing.js"></script>
-<script src="../resources/js-test.js"></script>
 <script src="resources/biquad-filters.js"></script>
 <script src="resources/biquad-testing.js"></script>
 </head>
diff --git a/third_party/WebKit/LayoutTests/webaudio/convolution-mono-mono.html b/third_party/WebKit/LayoutTests/webaudio/convolution-mono-mono.html
index 8f4cc79..57d6cb2c 100644
--- a/third_party/WebKit/LayoutTests/webaudio/convolution-mono-mono.html
+++ b/third_party/WebKit/LayoutTests/webaudio/convolution-mono-mono.html
@@ -2,9 +2,9 @@
 
 <html>
 <head>
-<script src="resources/compatibility.js"></script>
-<script type="text/javascript" src="resources/audio-testing.js"></script>
 <script src="../resources/js-test.js"></script>
+<script src="resources/compatibility.js"></script>
+<script src="resources/audio-testing.js"></script>
 <script src="resources/convolution-testing.js"></script>
 </head>
 
diff --git a/third_party/WebKit/LayoutTests/webaudio/convolver-setBuffer-null.html b/third_party/WebKit/LayoutTests/webaudio/convolver-setBuffer-null.html
index 72a46e9..403f513 100644
--- a/third_party/WebKit/LayoutTests/webaudio/convolver-setBuffer-null.html
+++ b/third_party/WebKit/LayoutTests/webaudio/convolver-setBuffer-null.html
@@ -1,9 +1,9 @@
 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
 <html>
 <head>
+<script src="../resources/js-test.js"></script>
 <script src="resources/compatibility.js"></script>
 <script src="resources/audio-testing.js"></script>
-<script src="../resources/js-test.js"></script>
 </head>
 
 <body>
diff --git a/third_party/WebKit/LayoutTests/webaudio/distance-exponential.html b/third_party/WebKit/LayoutTests/webaudio/distance-exponential.html
index 2d87447..a7c321f 100644
--- a/third_party/WebKit/LayoutTests/webaudio/distance-exponential.html
+++ b/third_party/WebKit/LayoutTests/webaudio/distance-exponential.html
@@ -1,9 +1,9 @@
 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
 <html>
   <head>
+    <script src="../resources/js-test.js"></script>
     <script src="resources/compatibility.js"></script>
     <script src="resources/audio-testing.js"></script>
-    <script src="../resources/js-test.js"></script>
     <script src="resources/distance-model-testing.js"></script>
   </head>
 
diff --git a/third_party/WebKit/LayoutTests/webaudio/distance-inverse.html b/third_party/WebKit/LayoutTests/webaudio/distance-inverse.html
index 8fe4258..37196055 100644
--- a/third_party/WebKit/LayoutTests/webaudio/distance-inverse.html
+++ b/third_party/WebKit/LayoutTests/webaudio/distance-inverse.html
@@ -1,9 +1,9 @@
 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
 <html>
   <head>
+    <script src="../resources/js-test.js"></script>
     <script src="resources/compatibility.js"></script>
     <script src="resources/audio-testing.js"></script>
-    <script src="../resources/js-test.js"></script>
     <script src="resources/distance-model-testing.js"></script>
   </head>
 
diff --git a/third_party/WebKit/LayoutTests/webaudio/distance-linear.html b/third_party/WebKit/LayoutTests/webaudio/distance-linear.html
index 57e9fda..75b1741b 100644
--- a/third_party/WebKit/LayoutTests/webaudio/distance-linear.html
+++ b/third_party/WebKit/LayoutTests/webaudio/distance-linear.html
@@ -1,9 +1,9 @@
 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
 <html>
   <head>
+    <script src="../resources/js-test.js"></script>
     <script src="resources/compatibility.js"></script>
     <script src="resources/audio-testing.js"></script>
-    <script src="../resources/js-test.js"></script>
     <script src="resources/distance-model-testing.js"></script>
   </head>
 
diff --git a/third_party/WebKit/LayoutTests/webaudio/dom-exceptions.html b/third_party/WebKit/LayoutTests/webaudio/dom-exceptions.html
index afea8f6..a8e5a97 100644
--- a/third_party/WebKit/LayoutTests/webaudio/dom-exceptions.html
+++ b/third_party/WebKit/LayoutTests/webaudio/dom-exceptions.html
@@ -1,9 +1,9 @@
 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
 <html>
 <head>
+<script src="../resources/js-test.js"></script>
 <script src="resources/compatibility.js"></script>
 <script src="resources/audio-testing.js"></script>
-<script src="../resources/js-test.js"></script>
 <script src="resources/biquad-testing.js"></script>
 </head>
 
diff --git a/third_party/WebKit/LayoutTests/webaudio/dynamicscompressor-clear-internal-state.html b/third_party/WebKit/LayoutTests/webaudio/dynamicscompressor-clear-internal-state.html
index 8867190..8c6ea19 100644
--- a/third_party/WebKit/LayoutTests/webaudio/dynamicscompressor-clear-internal-state.html
+++ b/third_party/WebKit/LayoutTests/webaudio/dynamicscompressor-clear-internal-state.html
@@ -2,9 +2,9 @@
 <html>
   <head>
     <title>Validate Reduction Value of DynamicsComporessor after Disabling</title>
+    <script src="../resources/js-test.js"></script>
     <script src="resources/compatibility.js"></script>
     <script src="resources/audio-testing.js"></script>
-    <script src="../resources/js-test.js"></script>
   </head>
 
   <body>
diff --git a/third_party/WebKit/LayoutTests/webaudio/note-grain-on-play.html b/third_party/WebKit/LayoutTests/webaudio/note-grain-on-play.html
index 6f6c3d9c..119cf52 100644
--- a/third_party/WebKit/LayoutTests/webaudio/note-grain-on-play.html
+++ b/third_party/WebKit/LayoutTests/webaudio/note-grain-on-play.html
@@ -1,10 +1,10 @@
 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
 <html>
   <head>
+    <script src="../resources/js-test.js"></script>
     <script src="resources/compatibility.js"></script>
     <script src="resources/audio-testing.js"></script>
     <script src="resources/note-grain-on-testing.js"></script>
-    <script src="../resources/js-test.js"></script>
   </head>
 
   <body>
diff --git a/third_party/WebKit/LayoutTests/webaudio/note-grain-on-timing.html b/third_party/WebKit/LayoutTests/webaudio/note-grain-on-timing.html
index 543f8b9..44625343 100644
--- a/third_party/WebKit/LayoutTests/webaudio/note-grain-on-timing.html
+++ b/third_party/WebKit/LayoutTests/webaudio/note-grain-on-timing.html
@@ -1,10 +1,10 @@
 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
 <html>
   <head>
+    <script src="../resources/js-test.js"></script>
     <script src="resources/compatibility.js"></script>
     <script src="resources/audio-testing.js"></script>
     <script src="resources/note-grain-on-testing.js"></script>
-    <script src="../resources/js-test.js"></script>
   </head>
 
   <body>
diff --git a/third_party/WebKit/LayoutTests/webaudio/offlineaudiocontext-detached-no-crash.html b/third_party/WebKit/LayoutTests/webaudio/offlineaudiocontext-detached-no-crash.html
index 378de48..b1ff8bd 100644
--- a/third_party/WebKit/LayoutTests/webaudio/offlineaudiocontext-detached-no-crash.html
+++ b/third_party/WebKit/LayoutTests/webaudio/offlineaudiocontext-detached-no-crash.html
@@ -1,9 +1,9 @@
 <!DOCTYPE HTML>
 <html>
 <head>
+<script src="../resources/js-test.js"></script>
 <script src="resources/compatibility.js"></script>
 <script src="resources/audio-testing.js"></script>
-<script src="../resources/js-test.js"></script>
 </head>
 <body>
 <script>
diff --git a/third_party/WebKit/LayoutTests/webaudio/oscillator-basic.html b/third_party/WebKit/LayoutTests/webaudio/oscillator-basic.html
index a55042b..f08b5db5 100644
--- a/third_party/WebKit/LayoutTests/webaudio/oscillator-basic.html
+++ b/third_party/WebKit/LayoutTests/webaudio/oscillator-basic.html
@@ -5,9 +5,9 @@
 -->
 <html>
 <head>
+<script src="../resources/js-test.js"></script>
 <script src="resources/compatibility.js"></script>
-<script type="text/javascript" src="resources/audio-testing.js"></script>
-<script type="text/javascript" src="../resources/js-test.js"></script>
+<script src="resources/audio-testing.js"></script>
 </head>
 
 <body>
diff --git a/third_party/WebKit/LayoutTests/webaudio/panner-automation-equalpower-stereo.html b/third_party/WebKit/LayoutTests/webaudio/panner-automation-equalpower-stereo.html
index 42e6e285..3e0683ca 100644
--- a/third_party/WebKit/LayoutTests/webaudio/panner-automation-equalpower-stereo.html
+++ b/third_party/WebKit/LayoutTests/webaudio/panner-automation-equalpower-stereo.html
@@ -1,9 +1,9 @@
 <!doctype html>
 <html>
   <head>
+    <script src="../resources/js-test.js"></script>
     <script src="resources/compatibility.js"></script>
     <script src="resources/audio-testing.js"></script>
-    <script src="../resources/js-test.js"></script>
     <script src="resources/panner-model-testing.js"></script>
   </head>
 
diff --git a/third_party/WebKit/LayoutTests/webaudio/panner-equalpower-stereo.html b/third_party/WebKit/LayoutTests/webaudio/panner-equalpower-stereo.html
index ed76004..7fb68f7 100644
--- a/third_party/WebKit/LayoutTests/webaudio/panner-equalpower-stereo.html
+++ b/third_party/WebKit/LayoutTests/webaudio/panner-equalpower-stereo.html
@@ -1,9 +1,9 @@
 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
 <html>
   <head>
+    <script src="../resources/js-test.js"></script>
     <script src="resources/compatibility.js"></script>
     <script src="resources/audio-testing.js"></script>
-    <script src="../resources/js-test.js"></script>
     <script src="resources/panner-model-testing.js"></script>
   </head>
 
diff --git a/third_party/WebKit/LayoutTests/webaudio/panner-equalpower.html b/third_party/WebKit/LayoutTests/webaudio/panner-equalpower.html
index 2ce02a9e..097aa787 100644
--- a/third_party/WebKit/LayoutTests/webaudio/panner-equalpower.html
+++ b/third_party/WebKit/LayoutTests/webaudio/panner-equalpower.html
@@ -1,9 +1,9 @@
 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
 <html>
   <head>
+    <script src="../resources/js-test.js"></script>
     <script src="resources/compatibility.js"></script>
     <script src="resources/audio-testing.js"></script>
-    <script src="../resources/js-test.js"></script>
     <script src="resources/panner-model-testing.js"></script>
   </head>
 
diff --git a/third_party/WebKit/LayoutTests/webaudio/panner-loop.html b/third_party/WebKit/LayoutTests/webaudio/panner-loop.html
index e069dfd..5b20173 100644
--- a/third_party/WebKit/LayoutTests/webaudio/panner-loop.html
+++ b/third_party/WebKit/LayoutTests/webaudio/panner-loop.html
@@ -1,9 +1,9 @@
 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
 <html>
   <head>
+    <script src="../resources/js-test.js"></script>
     <script src="resources/compatibility.js"></script>
     <script src="resources/audio-testing.js"></script>
-    <script src="../resources/js-test.js"></script>
     <script src="resources/panner-model-testing.js"></script>
   </head>
 
diff --git a/third_party/WebKit/LayoutTests/webaudio/resources/audio-testing.js b/third_party/WebKit/LayoutTests/webaudio/resources/audio-testing.js
index c248762..09f2bf7 100644
--- a/third_party/WebKit/LayoutTests/webaudio/resources/audio-testing.js
+++ b/third_party/WebKit/LayoutTests/webaudio/resources/audio-testing.js
@@ -1,3 +1,51 @@
+/* global self */
+
+// testharness.js has the higher priority.
+var TESTHARNESS = true;
+var JSTEST = false;
+
+(function () {
+    // Selected properies from testharness.js
+    var testharnessProperties = [
+        'test', 'async_test', 'promise_test', 'promise_rejects',
+        'generate_tests', 'setup', 'done', 'assert_true', 'assert_false'
+    ];
+
+    // Selected properties from js-test.js
+    var jsTestProperties = [
+        'isJsTest', 'testPassed', 'testFailed', 'gc', 'finishJSTest'
+    ];
+
+    // Check if testharness.js is properly loaded and set up a flag for it.
+    for (var name in testharnessProperties) {
+        if (!self.hasOwnProperty(testharnessProperties[name])) {
+            TESTHARNESS = false;
+            break;
+        }
+    }
+
+    // Immediately return here because testharness.js is ready.
+    if (TESTHARNESS)
+        return;
+
+    // Because testharness.js is not loaded, let us assume that js-test.js might
+    // be in use. Check if js-test.js is properly loaded and set up a flag for
+    // it.
+    JSTEST = true;
+    for (var name in jsTestProperties) {
+        if (!self.hasOwnProperty(jsTestProperties[name])) {
+            JSTEST = false;
+            break;
+        }
+    }
+
+    // If both are not loaded at all, throw here.
+    if (!JSTEST)
+        throw new Error('Cannot proceed. No test infrastructure is loaded.');
+})();
+
+
+
 function writeString(s, a, offset) {
     for (var i = 0; i < s.length; ++i) {
         a[offset + i] = s.charCodeAt(i);
@@ -301,6 +349,24 @@
         this.currentTask = 0;
     }
 
+    // This is to prime the task runner for the testharness.js async operation.
+    Tasks.prototype._initialize = function () {
+        if (TESTHARNESS) {
+            setup(new Function(), {
+                explicit_done: true
+            });
+        }
+    };
+
+    // Finalize the task runner by notifying testharness and testRunner that
+    // all the task is completed.
+    Tasks.prototype._finalize = function () {
+        if (TESTHARNESS) {
+            // From testharness.js
+            done();
+        }
+    };
+
     Tasks.prototype.defineTask = function (taskName, taskFunc) {
         // Check if there is a task defined with the same name.  If found, do
         // not add the task to the roster.
@@ -320,6 +386,8 @@
     // is no argument, run all the defined tasks.
     Tasks.prototype.runTasks = function () {
 
+        this._initialize();
+
         if (arguments.length > 0) {
 
             // Reset task queue and refill it with the with the given arguments,
@@ -341,21 +409,23 @@
             return;
         }
 
-        // done() callback from each task.  Increase the task index and call the
-        // next task.  Note that explicit signaling by done() in each task
-        // is needed because some of tests run asynchronously.
-        var done = function () {
+        // taskDone() callback from each task.  Increase the task index and call
+        // the next task.  Note that explicit signaling by taskDone() in each
+        // task is needed because some of tests run asynchronously.
+        var taskDone = function () {
             if (this.currentTask !== this.queue.length - 1) {
                 ++this.currentTask;
                 // debug('>> Audit.runTasks: ' + this.queue[this.currentTask]);
-                this.tasks[this.queue[this.currentTask]](done);
+                this.tasks[this.queue[this.currentTask]](taskDone);
+            } else {
+                this._finalize();
             }
             return;
         }.bind(this);
 
         // Start the first task.
         // debug('>> Audit.runTasks: ' + this.queue[this.currentTask]);
-        this.tasks[this.queue[this.currentTask]](done);
+        this.tasks[this.queue[this.currentTask]](taskDone);
     };
 
     return {
@@ -399,12 +469,6 @@
 
         // Check if the target contains any NaN value.
         this._checkNaN(this.target, 'ACTUAL');
-        // if (resultNaNCheck.length > 0) {
-        //     var failureMessage = 'NaN found while testing the target (' + label + ')';
-        //     testFailed(failureMessage + ': "' + this.desc + '" \n' +
-        //         resultNaNCheck);
-        //     throw failureMessage;
-        // }
 
         // |_testPassed| and |_testFailed| set this appropriately.
         this._success = false;
@@ -428,13 +492,28 @@
 
     // Internal methods starting with a underscore.
     ShouldModel.prototype._testPassed = function (msg) {
-        testPassed(this.desc + ' ' + msg + '.');
         this._success = true;
+        if (TESTHARNESS) {
+            // Using testharness.js
+            test(function () {
+                assert_true(true);
+                }, this.desc + ' ' + msg + '.');
+        } else {
+            // Using js-test.js
+            testPassed(this.desc + ' ' + msg + '.');
+        }
     };
 
     ShouldModel.prototype._testFailed = function (msg) {
-        testFailed(this.desc + ' ' + msg + '.');
         this._success = false;
+        var that = this;
+        if (TESTHARNESS) {
+            test(function () {
+                assert_true(false, that.desc + ' ' + msg + '.');
+                }, this.desc);
+        } else {
+            testFailed(this.desc + ' ' + msg + '.');
+        }
     };
 
     ShouldModel.prototype._isArray = function (arg) {
@@ -451,7 +530,15 @@
         var failureMessage = 'Assertion failed: ' + reason + ' ' + this.desc +'.';
         if (arguments.length >= 3)
             failureMessage += ": " + value;
-        testFailed(failureMessage);
+
+        if (TESTHARNESS) {
+            test(function () {
+                assert_true(false, reason + ' (' + value + ')');
+            }, this.desc)
+        } else {
+            testFailed(failureMessage);
+        }
+
         throw failureMessage;
     };
 
@@ -464,7 +551,14 @@
 
         // Checking a single variable first.
         if (Number.isNaN(value)) {
-            testFailed(failureMessage);
+            if (TESTHARNESS) {
+                test(function () {
+                    assert_true(false, failureMessage);
+                }, this.desc)
+            } else {
+                testFailed(failureMessage);
+            }
+
             throw failureMessage;
         }
 
@@ -492,7 +586,14 @@
             }
         }
 
-        testFailed(failureMessage + failureDetail);
+        if (TESTHARNESS) {
+            test(function () {
+                assert_true(false, failureMessage + failureDetail);
+            }, this.desc)
+        } else {
+            testFailed(failureMessage + failureDetail);
+        }
+
         throw failureMessage;
     };
 
diff --git a/third_party/WebKit/LayoutTests/webaudio/scriptprocessornode-detached-no-crash.html b/third_party/WebKit/LayoutTests/webaudio/scriptprocessornode-detached-no-crash.html
index 84a4da8..e2533a0 100644
--- a/third_party/WebKit/LayoutTests/webaudio/scriptprocessornode-detached-no-crash.html
+++ b/third_party/WebKit/LayoutTests/webaudio/scriptprocessornode-detached-no-crash.html
@@ -1,9 +1,9 @@
 <!DOCTYPE HTML>
 <html>
 <head>
+<script src="../resources/js-test.js"></script>
 <script src="resources/compatibility.js"></script>
 <script src="resources/audio-testing.js"></script>
-<script src="../resources/js-test.js"></script>
 </head>
 <body>
 <script>
diff --git a/third_party/WebKit/LayoutTests/webaudio/scriptprocessornode-zero-input-channels.html b/third_party/WebKit/LayoutTests/webaudio/scriptprocessornode-zero-input-channels.html
index e54a603..8491bb6 100644
--- a/third_party/WebKit/LayoutTests/webaudio/scriptprocessornode-zero-input-channels.html
+++ b/third_party/WebKit/LayoutTests/webaudio/scriptprocessornode-zero-input-channels.html
@@ -1,9 +1,9 @@
 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
 <html>
 <head>
+<script src="../resources/js-test.js"></script>
 <script src="resources/compatibility.js"></script>
 <script src="resources/audio-testing.js"></script>
-<script src="../resources/js-test.js"></script>
 </head>
 
 <body>
diff --git a/third_party/WebKit/LayoutTests/webaudio/stereopannernode-basic.html b/third_party/WebKit/LayoutTests/webaudio/stereopannernode-basic.html
index 96f7c662..cd2a73f 100644
--- a/third_party/WebKit/LayoutTests/webaudio/stereopannernode-basic.html
+++ b/third_party/WebKit/LayoutTests/webaudio/stereopannernode-basic.html
@@ -2,9 +2,9 @@
 <html>
 
 <head>
+  <script src="../resources/js-test.js"></script>
   <script src="resources/compatibility.js"></script>
   <script src="resources/audio-testing.js"></script>
-  <script src="../resources/js-test.js"></script>
 </head>
 
 <body>
diff --git a/third_party/WebKit/LayoutTests/webaudio/stereopannernode-panning.html b/third_party/WebKit/LayoutTests/webaudio/stereopannernode-panning.html
index 8fffd0b..70c62bd3 100644
--- a/third_party/WebKit/LayoutTests/webaudio/stereopannernode-panning.html
+++ b/third_party/WebKit/LayoutTests/webaudio/stereopannernode-panning.html
@@ -2,9 +2,9 @@
 <html>
 
 <head>
+  <script src="../resources/js-test.js"></script>
   <script src="resources/compatibility.js"></script>
   <script src="resources/audio-testing.js"></script>
-  <script src="../resources/js-test.js"></script>
   <script src="resources/stereopanner-testing.js"></script>
 </head>
 
diff --git a/third_party/WebKit/LayoutTests/webaudio/unit-tests/jstest-test-expected.txt b/third_party/WebKit/LayoutTests/webaudio/unit-tests/jstest-test-expected.txt
new file mode 100644
index 0000000..af4df7a3
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/webaudio/unit-tests/jstest-test-expected.txt
@@ -0,0 +1,20 @@
+A simple unit testing for audio-testing.js and js-test.js
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS Zero is equal to 0.
+PASS One is not equal to 0.
+PASS Expected SNR (110) is greater than or equal to 100.
+PASS Maximum error value (0.000001) is less than or equal to 0.00001.
+FAIL max error (0.000001) is not less than or equal to -1.
+PASS One point double zero one is 1 within a relative error of 0.1.
+FAIL Two is not 1 within a relative error of 0.1: 2 with relative error 1.
+PASS [2, 2, 2] contains only the constant 2.
+PASS [1, 2, 3] is identical to the array [1,2,3].
+PASS My array equals [0.1,0.2] with an element-wise tolerance of 0.02.
+PASS My random array contains all the expected values in the correct order: [1,3,2].
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/third_party/WebKit/LayoutTests/webaudio/unit-tests/jstest-test.html b/third_party/WebKit/LayoutTests/webaudio/unit-tests/jstest-test.html
new file mode 100644
index 0000000..5c3b694
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/webaudio/unit-tests/jstest-test.html
@@ -0,0 +1,47 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <title>A simple unit testing for audio-testing.js and js-test.js</title>
+  <script src="../../resources/js-test.js"></script>
+  <script src="../resources/audio-testing.js"></script>
+</head>
+<body>
+  <script>
+    description('A simple unit testing for audio-testing.js and js-test.js');
+    window.jsTestIsAsync = true;
+    
+    var audit = Audit.createTaskRunner();
+
+    audit.defineTask('foo', function (taskDone) {
+      Should('Zero', 0).beEqualTo(0);
+      Should('One', 1).notBeEqualTo(0);
+      Should('Expected SNR', 110).beGreaterThanOrEqualTo(100);
+      taskDone();
+    });
+
+    audit.defineTask('bar', function (taskDone) {
+      var maxError = 1e-6;
+      Should("Maximum error value", maxError).beLessThanOrEqualTo(1e-5);
+      Should("max error", maxError).beLessThanOrEqualTo(-1);
+      Should('One point double zero one', 1.001).beCloseTo(1, .1);
+      Should('Two', 2).beCloseTo(1, .1);
+      taskDone();
+    });
+
+    audit.defineTask('boo', function (taskDone) {
+      Should('[2, 2, 2]', [2, 2, 2]).beConstantValueOf(2);
+      Should('[1, 2, 3]', [1, 2, 3]).beEqualToArray([1, 2, 3]);
+      Should('My array', [0.11, 0.19]).beCloseToArray([0.1, 0.2], 0.02);
+      Should('My random array', [1, 1, 3, 3, 2]).containValues([1, 3, 2]);
+      taskDone();
+    });
+
+    audit.defineTask("finish", function (done) {
+      finishJSTest();
+      done();
+    });
+
+    audit.runTasks();
+  </script>
+</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/webaudio/unit-tests/testharness-test.html b/third_party/WebKit/LayoutTests/webaudio/unit-tests/testharness-test.html
new file mode 100644
index 0000000..c2c80da
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/webaudio/unit-tests/testharness-test.html
@@ -0,0 +1,43 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <title>A simple unit testing for audio-testing.js and testharness.js</title>
+  
+  <!-- This is the required dependency for testharness + audio-testing. Note
+    that the including order matters because audio-testing.js depends on
+    testharness.js -->
+  <script src="../../resources/testharness.js"></script>
+  <script src="../../resources/testharnessreport.js"></script>
+  <script src="../resources/audio-testing.js"></script>
+
+</head>
+<body>
+  <script>
+    var audit = Audit.createTaskRunner();
+
+    audit.defineTask('foo', function (taskDone) {
+      Should('Zero', 0).beEqualTo(0);
+      Should('One', 1).notBeEqualTo(0);
+      Should('Expected SNR', 110).beGreaterThanOrEqualTo(100);
+      taskDone();
+    });
+
+    audit.defineTask('bar', function (taskDone) {
+      var maxError = 1e-6;
+      Should("Maximum error value", maxError).beLessThanOrEqualTo(1e-5);
+      Should('One point double zero one', 1.001).beCloseTo(1, .1);
+      taskDone();
+    });
+
+    audit.defineTask('boo', function (taskDone) {
+      Should('[2, 2, 2]', [2, 2, 2]).beConstantValueOf(2);
+      Should('[1, 2, 3]', [1, 2, 3]).beEqualToArray([1, 2, 3]);
+      Should('My array', [0.11, 0.19]).beCloseToArray([0.1, 0.2], 0.02);
+      Should('My random array', [1, 1, 3, 3, 2]).containValues([1, 3, 2]);
+      taskDone();
+    });
+
+    audit.runTasks();
+  </script>
+</body>
+</html>
diff --git a/third_party/WebKit/Source/build/scripts/make_event_factory.py b/third_party/WebKit/Source/build/scripts/make_event_factory.py
index 48b9586..a6ae1858 100755
--- a/third_party/WebKit/Source/build/scripts/make_event_factory.py
+++ b/third_party/WebKit/Source/build/scripts/make_event_factory.py
@@ -71,7 +71,6 @@
 # or be deprecated/removed. https://crbug.com/569690
 def create_event_legacy_whitelist(name):
     return (name == 'AnimationEvent'
-            or name == 'AnimationPlayerEvent'
             or name == 'ApplicationCacheErrorEvent'
             or name == 'AudioProcessingEvent'
             or name == 'BeforeInstallPromptEvent'
@@ -80,7 +79,6 @@
             or name == 'ClipboardEvent'
             or name == 'CloseEvent'
             or name == 'CompositionEvent'
-            or name == 'DeviceLightEvent'
             or name == 'DeviceMotionEvent'
             or name == 'DeviceOrientationEvent'
             or name == 'DragEvent'
@@ -90,12 +88,9 @@
             or name == 'FetchEvent'
             or name == 'FocusEvent'
             or name == 'FontFaceSetLoadEvent'
-            or name == 'ForeignFetchEvent'
             or name == 'GamepadEvent'
             or name == 'HashChangeEvent'
             or name == 'IDBVersionChangeEvent'
-            or name == 'InputEvent'
-            or name == 'InstallEvent'
             or name == 'KeyboardEvents'
             or name == 'MediaEncryptedEvent'
             or name == 'MediaKeyMessageEvent'
@@ -110,22 +105,17 @@
             or name == 'OfflineAudioCompletionEvent'
             or name == 'OrientationEvent'
             or name == 'PageTransitionEvent'
-            or name == 'PaymentRequestUpdateEvent'
-            or name == 'PointerEvent'
             or name == 'PopStateEvent'
             or name == 'PresentationConnectionAvailableEvent'
             or name == 'PresentationConnectionCloseEvent'
             or name == 'ProgressEvent'
             or name == 'PromiseRejectionEvent'
             or name == 'PushEvent'
-            or name == 'RelatedEvent'
             or name == 'ResourceProgressEvent'
             or name == 'RTCDataChannelEvent'
             or name == 'RTCDTMFToneChangeEvent'
             or name == 'RTCIceCandidateEvent'
             or name == 'SecurityPolicyViolationEvent'
-            or name == 'SensorErrorEvent'
-            or name == 'SensorReadingEvent'
             or name == 'ServiceWorkerMessageEvent'
             or name == 'SpeechRecognitionError'
             or name == 'SpeechRecognitionEvent'
diff --git a/third_party/WebKit/Source/core/events/AnimationPlayerEvent.cpp b/third_party/WebKit/Source/core/events/AnimationPlayerEvent.cpp
index 55891e8..1ff3250 100644
--- a/third_party/WebKit/Source/core/events/AnimationPlayerEvent.cpp
+++ b/third_party/WebKit/Source/core/events/AnimationPlayerEvent.cpp
@@ -6,12 +6,6 @@
 
 namespace blink {
 
-AnimationPlayerEvent::AnimationPlayerEvent()
-    : m_currentTime(0.0)
-    , m_timelineTime(0.0)
-{
-}
-
 AnimationPlayerEvent::AnimationPlayerEvent(const AtomicString& type, double currentTime, double timelineTime)
     : Event(type, false, false)
     , m_currentTime(currentTime)
diff --git a/third_party/WebKit/Source/core/events/AnimationPlayerEvent.h b/third_party/WebKit/Source/core/events/AnimationPlayerEvent.h
index f5d2287..01fa2b29 100644
--- a/third_party/WebKit/Source/core/events/AnimationPlayerEvent.h
+++ b/third_party/WebKit/Source/core/events/AnimationPlayerEvent.h
@@ -13,10 +13,6 @@
 class AnimationPlayerEvent final : public Event {
     DEFINE_WRAPPERTYPEINFO();
 public:
-    static AnimationPlayerEvent* create()
-    {
-        return new AnimationPlayerEvent;
-    }
     static AnimationPlayerEvent* create(const AtomicString& type, double currentTime, double timelineTime)
     {
         return new AnimationPlayerEvent(type, currentTime, timelineTime);
@@ -37,7 +33,6 @@
     DECLARE_VIRTUAL_TRACE();
 
 private:
-    AnimationPlayerEvent();
     AnimationPlayerEvent(const AtomicString& type, double currentTime, double timelineTime);
     AnimationPlayerEvent(const AtomicString&, const AnimationPlayerEventInit&);
 
diff --git a/third_party/WebKit/Source/core/events/InputEvent.cpp b/third_party/WebKit/Source/core/events/InputEvent.cpp
index 2c99eda..395b5d9b 100644
--- a/third_party/WebKit/Source/core/events/InputEvent.cpp
+++ b/third_party/WebKit/Source/core/events/InputEvent.cpp
@@ -85,10 +85,6 @@
 
 } // anonymous namespace
 
-InputEvent::InputEvent()
-{
-}
-
 InputEvent::InputEvent(const AtomicString& type, const InputEventInit& initializer)
     : UIEvent(type, initializer)
 {
diff --git a/third_party/WebKit/Source/core/events/InputEvent.h b/third_party/WebKit/Source/core/events/InputEvent.h
index a8d6c07..2a002647 100644
--- a/third_party/WebKit/Source/core/events/InputEvent.h
+++ b/third_party/WebKit/Source/core/events/InputEvent.h
@@ -15,11 +15,6 @@
     DEFINE_WRAPPERTYPEINFO();
 
 public:
-    static InputEvent* create()
-    {
-        return new InputEvent;
-    }
-
     static InputEvent* create(const AtomicString& type, const InputEventInit& initializer)
     {
         return new InputEvent(type, initializer);
@@ -110,7 +105,6 @@
 
 private:
     friend class InputEventDispatchMediator;
-    InputEvent();
     InputEvent(const AtomicString&, const InputEventInit&);
 
     InputType m_inputType;
diff --git a/third_party/WebKit/Source/core/events/PointerEvent.cpp b/third_party/WebKit/Source/core/events/PointerEvent.cpp
index cf32bc42..9d0adc5 100644
--- a/third_party/WebKit/Source/core/events/PointerEvent.cpp
+++ b/third_party/WebKit/Source/core/events/PointerEvent.cpp
@@ -9,17 +9,6 @@
 
 namespace blink {
 
-PointerEvent::PointerEvent()
-    : m_pointerId(0)
-    , m_width(0)
-    , m_height(0)
-    , m_pressure(0)
-    , m_tiltX(0)
-    , m_tiltY(0)
-    , m_isPrimary(false)
-{
-}
-
 PointerEvent::PointerEvent(const AtomicString& type, const PointerEventInit& initializer)
     : MouseEvent(type, initializer)
     , m_pointerId(0)
diff --git a/third_party/WebKit/Source/core/events/PointerEvent.h b/third_party/WebKit/Source/core/events/PointerEvent.h
index 2ca02ba6..4f943c8a 100644
--- a/third_party/WebKit/Source/core/events/PointerEvent.h
+++ b/third_party/WebKit/Source/core/events/PointerEvent.h
@@ -15,11 +15,6 @@
     DEFINE_WRAPPERTYPEINFO();
 
 public:
-    static PointerEvent* create()
-    {
-        return new PointerEvent;
-    }
-
     static PointerEvent* create(const AtomicString& type, const PointerEventInit& initializer)
     {
         return new PointerEvent(type, initializer);
@@ -43,7 +38,6 @@
     DECLARE_VIRTUAL_TRACE();
 
 private:
-    PointerEvent();
     PointerEvent(const AtomicString&, const PointerEventInit&);
 
     int m_pointerId;
diff --git a/third_party/WebKit/Source/core/events/RelatedEvent.cpp b/third_party/WebKit/Source/core/events/RelatedEvent.cpp
index a214507..549de548 100644
--- a/third_party/WebKit/Source/core/events/RelatedEvent.cpp
+++ b/third_party/WebKit/Source/core/events/RelatedEvent.cpp
@@ -10,11 +10,6 @@
 {
 }
 
-RelatedEvent* RelatedEvent::create()
-{
-    return new RelatedEvent;
-}
-
 RelatedEvent* RelatedEvent::create(const AtomicString& type, bool canBubble, bool cancelable, EventTarget* relatedTarget)
 {
     return new RelatedEvent(type, canBubble, cancelable, relatedTarget);
@@ -25,10 +20,6 @@
     return new RelatedEvent(type, initializer);
 }
 
-RelatedEvent::RelatedEvent()
-{
-}
-
 RelatedEvent::RelatedEvent(const AtomicString& type, bool canBubble, bool cancelable, EventTarget* relatedTarget)
     : Event(type, canBubble, cancelable)
     , m_relatedTarget(relatedTarget)
diff --git a/third_party/WebKit/Source/core/events/RelatedEvent.h b/third_party/WebKit/Source/core/events/RelatedEvent.h
index f590a52..3dd3c1a 100644
--- a/third_party/WebKit/Source/core/events/RelatedEvent.h
+++ b/third_party/WebKit/Source/core/events/RelatedEvent.h
@@ -13,7 +13,6 @@
 class RelatedEvent final : public Event {
     DEFINE_WRAPPERTYPEINFO();
 public:
-    static RelatedEvent* create();
     static RelatedEvent* create(const AtomicString& type, bool canBubble, bool cancelable, EventTarget* relatedTarget);
     static RelatedEvent* create(const AtomicString& eventType, const RelatedEventInit&);
 
@@ -27,7 +26,6 @@
     DECLARE_VIRTUAL_TRACE();
 
 private:
-    RelatedEvent();
     RelatedEvent(const AtomicString& type, bool canBubble, bool cancelable, EventTarget*);
     RelatedEvent(const AtomicString& type, const RelatedEventInit&);
 
diff --git a/third_party/WebKit/Source/core/frame/UseCounter.h b/third_party/WebKit/Source/core/frame/UseCounter.h
index c1a17a1..944166c 100644
--- a/third_party/WebKit/Source/core/frame/UseCounter.h
+++ b/third_party/WebKit/Source/core/frame/UseCounter.h
@@ -954,7 +954,6 @@
         DocumentCreateEventFontFaceSetLoadEvent = 1160,
         DocumentCreateEventMediaQueryListEvent = 1161,
         DocumentCreateEventAnimationEvent = 1162,
-        DocumentCreateEventAnimationPlayerEvent = 1163,
         DocumentCreateEventApplicationCacheErrorEvent = 1164,
         DocumentCreateEventBeforeUnloadEvent = 1166,
         DocumentCreateEventClipboardEvent = 1167,
@@ -965,11 +964,9 @@
         DocumentCreateEventHashChangeEvent = 1172,
         DocumentCreateEventMutationEvent = 1173,
         DocumentCreateEventPageTransitionEvent = 1174,
-        DocumentCreateEventPointerEvent = 1175,
         DocumentCreateEventPopStateEvent = 1176,
         DocumentCreateEventProgressEvent = 1177,
         DocumentCreateEventPromiseRejectionEvent = 1178,
-        DocumentCreateEventRelatedEvent = 1179,
         DocumentCreateEventResourceProgressEvent = 1180,
         DocumentCreateEventSecurityPolicyViolationEvent = 1181,
         DocumentCreateEventTextEvent = 1182,
@@ -983,7 +980,6 @@
         DocumentCreateEventWebKitTransitionEvent = 1191,
         DocumentCreateEventBeforeInstallPromptEvent = 1192,
         DocumentCreateEventSyncEvent = 1193,
-        DocumentCreateEventDeviceLightEvent = 1194,
         DocumentCreateEventDeviceMotionEvent = 1195,
         DocumentCreateEventDeviceOrientationEvent = 1196,
         DocumentCreateEventMediaEncryptedEvent = 1197,
@@ -1003,7 +999,6 @@
         DocumentCreateEventExtendableEvent = 1213,
         DocumentCreateEventExtendableMessageEvent = 1214,
         DocumentCreateEventFetchEvent = 1215,
-        DocumentCreateEventInstallEvent = 1216,
         DocumentCreateEventServiceWorkerMessageEvent = 1217,
         DocumentCreateEventSpeechRecognitionError = 1218,
         DocumentCreateEventSpeechRecognitionEvent = 1219,
@@ -1027,7 +1022,6 @@
         V8ForInInitializer = 1238,
         V8Animation_Id_AttributeGetter = 1239,
         V8Animation_Id_AttributeSetter = 1240,
-        DocumentCreateEventInputEvent = 1242,
         WebAnimationHyphenatedProperty = 1243,
         FormControlsCollectionReturnsRadioNodeListForFieldSet = 1244,
         ApplicationCacheManifestSelectInsecureOrigin = 1245,
@@ -1066,7 +1060,6 @@
         InvalidReportUriDirectiveInMetaCSP = 1281,
         InvalidSandboxDirectiveInMetaCSP = 1282,
         InvalidFrameAncestorsDirectiveInMetaCSP = 1283,
-        DocumentCreateEventForeignFetchEvent = 1286,
         SVGCalcModeDiscrete = 1287,
         SVGCalcModeLinear = 1288,
         SVGCalcModePaced = 1289,
@@ -1121,7 +1114,6 @@
         During_Microtask_Print = 1336,
         During_Microtask_Prompt = 1337,
         During_Microtask_SyncXHR = 1338,
-        DocumentCreateEventPaymentRequestUpdateEvent = 1341,
         CredentialManagerGetReturnedCredential = 1342,
         GeolocationInsecureOriginDeprecatedNotRemoved = 1343,
         GeolocationInsecureOriginIframeDeprecatedNotRemoved = 1344,
@@ -1167,8 +1159,6 @@
         RTCPeerConnectionAddIceCandidatePromise = 1384,
         RTCPeerConnectionAddIceCandidateLegacy = 1385,
         RTCIceCandidateDefaultSdpMLineIndex = 1386,
-        DocumentCreateEventSensorErrorEvent = 1387,
-        DocumentCreateEventSensorReadingEvent = 1388,
         MediaStreamConstraintsOldAndNew = 1389,
         V8ArrayProtectorDirtied = 1390,
         V8ArraySpeciesModified = 1391,
diff --git a/third_party/WebKit/Source/core/layout/LayoutBlockFlow.h b/third_party/WebKit/Source/core/layout/LayoutBlockFlow.h
index 578b4b78..a2547141 100644
--- a/third_party/WebKit/Source/core/layout/LayoutBlockFlow.h
+++ b/third_party/WebKit/Source/core/layout/LayoutBlockFlow.h
@@ -341,6 +341,7 @@
 
     void addOutlineRects(Vector<LayoutRect>&, const LayoutPoint& additionalOffset, IncludeBlockVisualOverflowOrNot) const override;
 
+    bool paintedOutputOfObjectHasNoEffect() const override;
     PaintInvalidationReason invalidatePaintIfNeeded(const PaintInvalidationState&) override;
 
     Node* nodeForHitTest() const final;
diff --git a/third_party/WebKit/Source/core/layout/LayoutBlockFlowLine.cpp b/third_party/WebKit/Source/core/layout/LayoutBlockFlowLine.cpp
index c0e08b00..6d210be 100644
--- a/third_party/WebKit/Source/core/layout/LayoutBlockFlowLine.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutBlockFlowLine.cpp
@@ -2062,6 +2062,15 @@
         firstRootBox->setShouldDoFullPaintInvalidationRecursively();
 }
 
+bool LayoutBlockFlow::paintedOutputOfObjectHasNoEffect() const
+{
+    // LayoutBlockFlow is in charge of paint invalidation of the first line.
+    if (firstLineBox())
+        return false;
+
+    return LayoutBlock::paintedOutputOfObjectHasNoEffect();
+}
+
 PaintInvalidationReason LayoutBlockFlow::invalidatePaintIfNeeded(const PaintInvalidationState& paintInvalidationState)
 {
     if (containsFloats())
diff --git a/third_party/WebKit/Source/core/layout/LayoutBox.cpp b/third_party/WebKit/Source/core/layout/LayoutBox.cpp
index 89b23b0..7a739571 100644
--- a/third_party/WebKit/Source/core/layout/LayoutBox.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutBox.cpp
@@ -2034,6 +2034,28 @@
     return isForcedFragmentainerBreakValue(classABreakPointValue(previousBreakAfterValue));
 }
 
+bool LayoutBox::paintedOutputOfObjectHasNoEffect() const
+{
+    // In case scrollbars got repositioned (which will typically happen if the box got
+    // resized), we cannot skip invalidation.
+    if (hasNonCompositedScrollbars())
+        return false;
+
+    // Cannot skip paint invalidation if the box has real things to paint.
+    if (getSelectionState() != SelectionNone || hasBoxDecorationBackground() || styleRef().hasVisualOverflowingEffect())
+        return false;
+
+    // If the box has clip, we need issue a paint invalidation to cover the changed part of
+    // children because of change of clip when the box got resized. In theory the children
+    // should invalidate themselves when ancestor clip changes, but for now this is missing
+    // and ensuring it may hurt performance.
+    // TODO(wangxianzhu): Paint invalidation for clip change will be different in spv2.
+    if (hasClipRelatedProperty() || hasControlClip())
+        return false;
+
+    return true;
+}
+
 LayoutRect LayoutBox::localOverflowRectForPaintInvalidation() const
 {
     if (style()->visibility() != VISIBLE)
diff --git a/third_party/WebKit/Source/core/layout/LayoutBox.h b/third_party/WebKit/Source/core/layout/LayoutBox.h
index e204676..d7aab38 100644
--- a/third_party/WebKit/Source/core/layout/LayoutBox.h
+++ b/third_party/WebKit/Source/core/layout/LayoutBox.h
@@ -695,6 +695,7 @@
     // break, we also need to know the break-after value of the previous in-flow sibling.
     bool needsForcedBreakBefore(EBreak previousBreakAfterValue) const;
 
+    bool paintedOutputOfObjectHasNoEffect() const override;
     LayoutRect localOverflowRectForPaintInvalidation() const override;
     bool mapToVisualRectInAncestorSpace(const LayoutBoxModelObject* ancestor, LayoutRect&, VisualRectFlags = DefaultVisualRectFlags) const override;
     virtual void invalidatePaintForOverhangingFloats(bool paintAllDescendants);
diff --git a/third_party/WebKit/Source/core/layout/LayoutObject.cpp b/third_party/WebKit/Source/core/layout/LayoutObject.cpp
index 78d02a87..fbabc29 100644
--- a/third_party/WebKit/Source/core/layout/LayoutObject.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutObject.cpp
@@ -684,28 +684,6 @@
     return LayoutFlowThread::locateFlowThreadContainingBlockOf(*this);
 }
 
-bool LayoutObject::skipInvalidationWhenLaidOutChildren() const
-{
-    if (!m_bitfields.neededLayoutBecauseOfChildren())
-        return false;
-
-    // SVG layoutObjects need to be invalidated when their children are laid out.
-    // LayoutBlocks with line boxes are responsible to invalidate them so we can't ignore them.
-    if (isSVG() || (isLayoutBlockFlow() && toLayoutBlockFlow(this)->firstLineBox()))
-        return false;
-
-    // In case scrollbars got repositioned (which will typically happen if the layout object got
-    // resized), we cannot skip invalidation.
-    if (hasNonCompositedScrollbars())
-        return false;
-
-    // We can't detect whether a plugin has box effects, so disable this optimization for that case.
-    if (isEmbeddedObject())
-        return false;
-
-    return !hasBoxEffect();
-}
-
 static inline bool objectIsRelayoutBoundary(const LayoutObject* object)
 {
     // FIXME: In future it may be possible to broaden these conditions in order to improve performance.
@@ -1330,7 +1308,6 @@
         selectionPaintInvalidationMap->set(this, selectionRect);
 }
 
-// TODO(wangxianzhu): Remove this for slimming paint v2 because we won't care about paint invalidation rects.
 inline void LayoutObject::invalidateSelectionIfNeeded(const LayoutBoxModelObject& paintInvalidationContainer, const PaintInvalidationState& paintInvalidationState, PaintInvalidationReason invalidationReason)
 {
     // Update selection rect when we are doing full invalidation (in case that the object is moved, composite status changed, etc.)
@@ -1354,11 +1331,10 @@
 
     setPreviousSelectionRectForPaintInvalidation(newSelectionRect);
 
-    // TODO(wangxianzhu): Combine the following two conditions when removing LayoutView::doingFullPaintInvalidation().
-    if (!fullInvalidation)
+    if (!fullInvalidation) {
         fullyInvalidatePaint(paintInvalidationContainer, PaintInvalidationSelection, oldSelectionRect, newSelectionRect);
-    if (shouldInvalidateSelection())
         invalidateDisplayItemClientsWithPaintInvalidationState(paintInvalidationState, PaintInvalidationSelection);
+    }
 }
 
 PaintInvalidationReason LayoutObject::invalidatePaintIfNeeded(const PaintInvalidationState& paintInvalidationState)
@@ -1423,7 +1399,7 @@
         // invalidation is issued. See crbug.com/508383 and crbug.com/515977.
         // This is a workaround to force display items to update paint offset.
         if (!RuntimeEnabledFeatures::slimmingPaintInvalidationEnabled() && paintInvalidationState.forcedSubtreeInvalidationCheckingWithinContainer())
-            invalidateDisplayItemClientsWithPaintInvalidationState(paintInvalidationState, invalidationReason);
+            invalidateDisplayItemClientsWithPaintInvalidationState(paintInvalidationState, PaintInvalidationLocationChange);
 
         return invalidationReason;
     }
@@ -1447,6 +1423,9 @@
     if (shouldDoFullPaintInvalidation())
         return m_bitfields.fullPaintInvalidationReason();
 
+    if (paintedOutputOfObjectHasNoEffect())
+        return PaintInvalidationNone;
+
     // The outline may change shape because of position change of descendants. For simplicity,
     // just force full paint invalidation if this object is marked for checking paint invalidation
     // for any reason.
@@ -1465,13 +1444,6 @@
     if (newBounds.location() != oldBounds.location())
         return PaintInvalidationBoundsChange;
 
-    // This covers the case where we mark containing blocks for layout
-    // and they change size but don't have anything to paint. This is
-    // a pretty common case for <body> as we add / remove children
-    // (and the default background is done by FrameView).
-    if (!RuntimeEnabledFeatures::slimmingPaintV2Enabled() && skipInvalidationWhenLaidOutChildren())
-        return PaintInvalidationNone;
-
     // If the size is zero on one of our bounds then we know we're going to have
     // to do a full invalidation of either old bounds or new bounds. If we fall
     // into the incremental invalidation we'll issue two invalidations instead
@@ -3458,7 +3430,6 @@
     ASSERT(!shouldCheckForPaintInvalidationRegardlessOfPaintInvalidationState() || paintInvalidationStateIsDirty());
     clearShouldDoFullPaintInvalidation();
     m_bitfields.setChildShouldCheckForPaintInvalidation(false);
-    m_bitfields.setNeededLayoutBecauseOfChildren(false);
     m_bitfields.setMayNeedPaintInvalidation(false);
     m_bitfields.setMayNeedPaintInvalidationSubtree(false);
     m_bitfields.setShouldInvalidateSelection(false);
diff --git a/third_party/WebKit/Source/core/layout/LayoutObject.h b/third_party/WebKit/Source/core/layout/LayoutObject.h
index 7a88a69..96447e7 100644
--- a/third_party/WebKit/Source/core/layout/LayoutObject.h
+++ b/third_party/WebKit/Source/core/layout/LayoutObject.h
@@ -354,12 +354,6 @@
 
 #endif
 
-    // Correct version of !layoutObjectHasNoBoxEffectObsolete().
-    bool hasBoxEffect() const
-    {
-        return hasBoxDecorationBackground() || style()->hasVisualOverflowingEffect();
-    }
-
     // LayoutObject tree manipulation
     //////////////////////////////////////////
     virtual bool canHaveChildren() const { return virtualChildren(); }
@@ -444,8 +438,6 @@
     // or from Parent element.
     PassRefPtr<ComputedStyle> getUncachedPseudoStyleFromParentOrShadowHost() const;
 
-    bool skipInvalidationWhenLaidOutChildren() const;
-
 public:
 #ifndef NDEBUG
     void showTreeForThis() const;
@@ -694,8 +686,6 @@
     bool boxDecorationBackgroundIsKnownToBeObscured() const;
     bool hasBackground() const { return style()->hasBackground(); }
 
-    bool needsLayoutBecauseOfChildren() const { return needsLayout() && !selfNeedsLayout() && !needsPositionedMovementLayout() && !needsSimplifiedNormalFlowLayout(); }
-
     bool needsLayout() const
     {
         return m_bitfields.selfNeedsLayout() || m_bitfields.normalChildNeedsLayout() || m_bitfields.posChildNeedsLayout()
@@ -1131,6 +1121,12 @@
     void invalidatePaintIncludingNonSelfPaintingLayerDescendants(const LayoutBoxModelObject& paintInvalidationContainer);
     void setShouldDoFullPaintInvalidationIncludingNonCompositingDescendants();
 
+    // Returns true if the object will not generate any effective painted output.
+    // It's used to skip unforced paint invalidation (which is when shouldDoFullPaintInvalidation
+    // is false, but mayNeedPaintInvalidation or childShouldCheckForPaintInvalidation is true) to
+    // avoid unnecessary paint invalidations of empty areas covered by such objects.
+    virtual bool paintedOutputOfObjectHasNoEffect() const { return false; }
+
     // Returns the rect that should have paint invalidated whenever this object changes. The rect is in the view's
     // coordinate space. This method deals with outlines and overflow.
     virtual LayoutRect absoluteClippedOverflowRect() const;
@@ -1555,7 +1551,7 @@
 #if ENABLE(ASSERT)
     virtual bool paintInvalidationStateIsDirty() const
     {
-        return m_bitfields.neededLayoutBecauseOfChildren() || shouldCheckForPaintInvalidationRegardlessOfPaintInvalidationState();
+        return shouldCheckForPaintInvalidationRegardlessOfPaintInvalidationState();
     }
 #endif
 
@@ -1748,7 +1744,6 @@
             , m_mayNeedPaintInvalidation(false)
             , m_mayNeedPaintInvalidationSubtree(false)
             , m_shouldInvalidateSelection(false)
-            , m_neededLayoutBecauseOfChildren(false)
             , m_floating(false)
             , m_isAnonymous(!node)
             , m_isText(false)
@@ -1782,7 +1777,7 @@
         {
         }
 
-        // 32 bits have been used in the first word, and 17 in the second.
+        // 32 bits have been used in the first word, and 16 in the second.
 
         // Self needs layout means that this layout object is marked for a full layout.
         // This is the default layout but it is expensive as it recomputes everything.
@@ -1833,8 +1828,7 @@
         ADD_BOOLEAN_BITFIELD(childShouldCheckForPaintInvalidation, ChildShouldCheckForPaintInvalidation);
         ADD_BOOLEAN_BITFIELD(mayNeedPaintInvalidation, MayNeedPaintInvalidation);
         ADD_BOOLEAN_BITFIELD(mayNeedPaintInvalidationSubtree, MayNeedPaintInvalidationSubtree);
-        ADD_BOOLEAN_BITFIELD(shouldInvalidateSelection, ShouldInvalidateSelection); // TODO(wangxianzhu): Remove for slimming paint v2.
-        ADD_BOOLEAN_BITFIELD(neededLayoutBecauseOfChildren, NeededLayoutBecauseOfChildren); // TODO(wangxianzhu): Remove for slimming paint v2.
+        ADD_BOOLEAN_BITFIELD(shouldInvalidateSelection, ShouldInvalidateSelection);
 
         // This boolean is the cached value of 'float'
         // (see ComputedStyle::isFloating).
@@ -2051,7 +2045,6 @@
     // Set flags for later stages/cycles.
     setEverHadLayout();
     setMayNeedPaintInvalidation();
-    m_bitfields.setNeededLayoutBecauseOfChildren(needsLayoutBecauseOfChildren());
 
     // Clear needsLayout flags.
     setSelfNeedsLayout(false);
diff --git a/third_party/WebKit/Source/core/layout/LayoutReplaced.h b/third_party/WebKit/Source/core/layout/LayoutReplaced.h
index 492bf53c..190d429 100644
--- a/third_party/WebKit/Source/core/layout/LayoutReplaced.h
+++ b/third_party/WebKit/Source/core/layout/LayoutReplaced.h
@@ -72,6 +72,9 @@
 
     void paint(const PaintInfo&, const LayoutPoint&) const override;
 
+    // Replaced objects often have contents to paint.
+    bool paintedOutputOfObjectHasNoEffect() const final { return false; }
+
     struct IntrinsicSizingInfo {
         STACK_ALLOCATED();
         IntrinsicSizingInfo() : hasWidth(true), hasHeight(true) {}
diff --git a/third_party/WebKit/Source/core/layout/LayoutView.cpp b/third_party/WebKit/Source/core/layout/LayoutView.cpp
index a1f5a97..ae252ca 100644
--- a/third_party/WebKit/Source/core/layout/LayoutView.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutView.cpp
@@ -571,13 +571,6 @@
             continue;
 
         o->setShouldInvalidateSelection();
-
-        // Blocks are responsible for painting line gaps and margin gaps. They must be examined as well.
-        for (LayoutBlock* block = o->containingBlock(); block && !block->isLayoutView(); block = block->containingBlock()) {
-            if (!processedBlocks.add(block).isNewEntry)
-                break;
-            block->setShouldInvalidateSelection();
-        }
     }
 }
 
diff --git a/third_party/WebKit/Source/core/layout/svg/LayoutSVGHiddenContainer.cpp b/third_party/WebKit/Source/core/layout/svg/LayoutSVGHiddenContainer.cpp
index d7bf42b..03facf1c 100644
--- a/third_party/WebKit/Source/core/layout/svg/LayoutSVGHiddenContainer.cpp
+++ b/third_party/WebKit/Source/core/layout/svg/LayoutSVGHiddenContainer.cpp
@@ -44,16 +44,6 @@
     clearNeedsLayout();
 }
 
-void LayoutSVGHiddenContainer::paint(const PaintInfo&, const LayoutPoint&) const
-{
-    // This subtree does not paint.
-}
-
-void LayoutSVGHiddenContainer::absoluteQuads(Vector<FloatQuad>&) const
-{
-    // This subtree does not take up space or paint
-}
-
 bool LayoutSVGHiddenContainer::nodeAtFloatPoint(HitTestResult&, const FloatPoint&, HitTestAction)
 {
     return false;
diff --git a/third_party/WebKit/Source/core/layout/svg/LayoutSVGHiddenContainer.h b/third_party/WebKit/Source/core/layout/svg/LayoutSVGHiddenContainer.h
index 629f7b4..542087e 100644
--- a/third_party/WebKit/Source/core/layout/svg/LayoutSVGHiddenContainer.h
+++ b/third_party/WebKit/Source/core/layout/svg/LayoutSVGHiddenContainer.h
@@ -40,10 +40,12 @@
     bool isOfType(LayoutObjectType type) const override { return type == LayoutObjectSVGHiddenContainer || LayoutSVGContainer::isOfType(type); }
 
 private:
-    void paint(const PaintInfo&, const LayoutPoint&) const final;
+    // LayoutSVGHiddenContainer paints nothing.
+    void paint(const PaintInfo&, const LayoutPoint&) const final { }
+    bool paintedOutputOfObjectHasNoEffect() const final { return true; }
     LayoutRect absoluteClippedOverflowRect() const final { return LayoutRect(); }
     FloatRect paintInvalidationRectInLocalSVGCoordinates() const final { return FloatRect(); }
-    void absoluteQuads(Vector<FloatQuad>&) const final;
+    void absoluteQuads(Vector<FloatQuad>&) const final { }
 
     bool nodeAtFloatPoint(HitTestResult&, const FloatPoint& pointInParent, HitTestAction) final;
 };
diff --git a/third_party/WebKit/Source/core/loader/DocumentThreadableLoader.cpp b/third_party/WebKit/Source/core/loader/DocumentThreadableLoader.cpp
index 33ebc16..70543b2 100644
--- a/third_party/WebKit/Source/core/loader/DocumentThreadableLoader.cpp
+++ b/third_party/WebKit/Source/core/loader/DocumentThreadableLoader.cpp
@@ -341,7 +341,7 @@
 DocumentThreadableLoader::~DocumentThreadableLoader()
 {
     CHECK(!m_client);
-    DCHECK(!m_resource);
+    DCHECK(!resource());
 }
 
 void DocumentThreadableLoader::overrideTimeout(unsigned long timeoutMilliseconds)
@@ -971,9 +971,9 @@
 
 DEFINE_TRACE(DocumentThreadableLoader)
 {
-    visitor->trace(m_resource);
     visitor->trace(m_document);
     ThreadableLoader::trace(visitor);
+    ResourceOwner<RawResource>::trace(visitor);
 }
 
 } // namespace blink
diff --git a/third_party/WebKit/Source/core/loader/DocumentThreadableLoader.h b/third_party/WebKit/Source/core/loader/DocumentThreadableLoader.h
index 227541b..79e8336d 100644
--- a/third_party/WebKit/Source/core/loader/DocumentThreadableLoader.h
+++ b/third_party/WebKit/Source/core/loader/DocumentThreadableLoader.h
@@ -54,7 +54,8 @@
 class SecurityOrigin;
 class ThreadableLoaderClient;
 
-class CORE_EXPORT DocumentThreadableLoader final : public ThreadableLoader, private RawResourceClient {
+class CORE_EXPORT DocumentThreadableLoader final : public ThreadableLoader, private ResourceOwner<RawResource> {
+    USING_GARBAGE_COLLECTED_MIXIN(DocumentThreadableLoader);
     public:
         static void loadResourceSynchronously(Document&, const ResourceRequest&, ThreadableLoaderClient&, const ThreadableLoaderOptions&, const ResourceLoaderOptions&);
         static DocumentThreadableLoader* create(Document&, ThreadableLoaderClient*, const ThreadableLoaderOptions&, const ResourceLoaderOptions&);
@@ -150,29 +151,6 @@
         // returns allowCredentials value of m_resourceLoaderOptions.
         StoredCredentials effectiveAllowCredentials() const;
 
-        // TODO(oilpan): DocumentThreadableLoader used to be a ResourceOwner,
-        // but ResourceOwner was moved onto the oilpan heap before
-        // DocumentThreadableLoader was ready. When DocumentThreadableLoader
-        // moves onto the oilpan heap, make it a ResourceOwner again and remove
-        // this re-implementation of ResourceOwner.
-        RawResource* resource() const { return m_resource.get(); }
-        void clearResource() { setResource(nullptr); }
-        void setResource(RawResource* newResource)
-        {
-            if (newResource == m_resource)
-                return;
-
-            if (RawResource* oldResource = m_resource.release())
-                oldResource->removeClient(this);
-
-            if (newResource) {
-                m_resource = newResource;
-                m_resource->addClient(this);
-            }
-        }
-        Member<RawResource> m_resource;
-        // End of ResourceOwner re-implementation, see above.
-
         SecurityOrigin* getSecurityOrigin() const;
         Document& document() const;
 
diff --git a/third_party/WebKit/Source/core/loader/FrameFetchContext.cpp b/third_party/WebKit/Source/core/loader/FrameFetchContext.cpp
index 79e12d4d..93bda38 100644
--- a/third_party/WebKit/Source/core/loader/FrameFetchContext.cpp
+++ b/third_party/WebKit/Source/core/loader/FrameFetchContext.cpp
@@ -64,6 +64,7 @@
 #include "platform/Logging.h"
 #include "platform/TracedValue.h"
 #include "platform/mhtml/MHTMLArchive.h"
+#include "platform/network/NetworkUtils.h"
 #include "platform/network/ResourceLoadPriority.h"
 #include "platform/network/ResourceTimingInfo.h"
 #include "platform/weborigin/SchemeRegistry.h"
@@ -110,7 +111,20 @@
     // Avoid blocking same origin scripts, as they may be used to render main
     // page content, whereas cross-origin scripts inserted via document.write
     // are likely to be third party content.
-    if (request.url().host() == document.getSecurityOrigin()->domain())
+    String requestHost = request.url().host();
+    String documentHost = document.getSecurityOrigin()->domain();
+    if (requestHost == documentHost)
+        return false;
+
+    // If the hosts didn't match, then see if the domains match. For example, if
+    // a script is served from static.example.com for a document served from
+    // www.example.com, we consider that a first party script and allow it.
+    String requestDomain = NetworkUtils::getDomainAndRegistry(requestHost, NetworkUtils::IncludePrivateRegistries);
+    String documentDomain = NetworkUtils::getDomainAndRegistry(documentHost, NetworkUtils::IncludePrivateRegistries);
+    // getDomainAndRegistry will return the empty string for domains that are
+    // already top-level, such as localhost. Thus we only compare domains if we
+    // get non-empty results back from getDomainAndRegistry.
+    if (!requestDomain.isEmpty() && !documentDomain.isEmpty() && requestDomain == documentDomain)
         return false;
 
     emitWarningForDocWriteScripts(request.url().getString(), document);
diff --git a/third_party/WebKit/Source/core/loader/WorkerThreadableLoader.cpp b/third_party/WebKit/Source/core/loader/WorkerThreadableLoader.cpp
index ab02e4ff..a64cf35 100644
--- a/third_party/WebKit/Source/core/loader/WorkerThreadableLoader.cpp
+++ b/third_party/WebKit/Source/core/loader/WorkerThreadableLoader.cpp
@@ -224,7 +224,7 @@
 
 WorkerThreadableLoader::~WorkerThreadableLoader()
 {
-    DCHECK(!m_peer);
+    DCHECK(!m_mainThreadLoaderHolder);
     DCHECK(!m_client);
 }
 
@@ -240,7 +240,7 @@
         eventWithTasks = WaitableEventWithTasks::create();
 
     m_workerLoaderProxy->postTaskToLoader(BLINK_FROM_HERE, createCrossThreadTask(
-        &Peer::createAndStart,
+        &MainThreadLoaderHolder::createAndStart,
         wrapCrossThreadPersistent(this),
         m_workerLoaderProxy,
         wrapCrossThreadPersistent(m_workerGlobalScope->thread()->getWorkerThreadLifecycleContext()),
@@ -278,17 +278,17 @@
 void WorkerThreadableLoader::overrideTimeout(unsigned long timeoutMilliseconds)
 {
     DCHECK(!isMainThread());
-    if (!m_peer)
+    if (!m_mainThreadLoaderHolder)
         return;
-    m_workerLoaderProxy->postTaskToLoader(BLINK_FROM_HERE, createCrossThreadTask(&Peer::overrideTimeout, m_peer, timeoutMilliseconds));
+    m_workerLoaderProxy->postTaskToLoader(BLINK_FROM_HERE, createCrossThreadTask(&MainThreadLoaderHolder::overrideTimeout, m_mainThreadLoaderHolder, timeoutMilliseconds));
 }
 
 void WorkerThreadableLoader::cancel()
 {
     DCHECK(!isMainThread());
-    if (m_peer) {
-        m_workerLoaderProxy->postTaskToLoader(BLINK_FROM_HERE, createCrossThreadTask(&Peer::cancel, m_peer));
-        m_peer = nullptr;
+    if (m_mainThreadLoaderHolder) {
+        m_workerLoaderProxy->postTaskToLoader(BLINK_FROM_HERE, createCrossThreadTask(&MainThreadLoaderHolder::cancel, m_mainThreadLoaderHolder));
+        m_mainThreadLoaderHolder = nullptr;
     }
 
     if (!m_client)
@@ -304,17 +304,17 @@
     DCHECK(!m_client);
 }
 
-void WorkerThreadableLoader::didStart(Peer* peer)
+void WorkerThreadableLoader::didStart(MainThreadLoaderHolder* mainThreadLoaderHolder)
 {
     DCHECK(!isMainThread());
-    DCHECK(!m_peer);
-    DCHECK(peer);
+    DCHECK(!m_mainThreadLoaderHolder);
+    DCHECK(mainThreadLoaderHolder);
     if (!m_client) {
         // The loading is already cancelled.
         return;
     }
 
-    m_peer = peer;
+    m_mainThreadLoaderHolder = mainThreadLoaderHolder;
 }
 
 void WorkerThreadableLoader::didSendData(unsigned long long bytesSent, unsigned long long totalBytesToBeSent)
@@ -358,7 +358,7 @@
         return;
     auto* client = m_client;
     m_client = nullptr;
-    m_peer = nullptr;
+    m_mainThreadLoaderHolder = nullptr;
     client->didFinishLoading(identifier, finishTime);
 }
 
@@ -369,7 +369,7 @@
         return;
     auto* client = m_client;
     m_client = nullptr;
-    m_peer = nullptr;
+    m_mainThreadLoaderHolder = nullptr;
     client->didFail(error);
 }
 
@@ -380,7 +380,7 @@
         return;
     auto* client = m_client;
     m_client = nullptr;
-    m_peer = nullptr;
+    m_mainThreadLoaderHolder = nullptr;
     client->didFailAccessControlCheck(error);
 }
 
@@ -391,7 +391,7 @@
         return;
     auto* client = m_client;
     m_client = nullptr;
-    m_peer = nullptr;
+    m_mainThreadLoaderHolder = nullptr;
     client->didFailRedirectCheck();
 }
 
@@ -419,7 +419,7 @@
     ThreadableLoader::trace(visitor);
 }
 
-void WorkerThreadableLoader::Peer::createAndStart(
+void WorkerThreadableLoader::MainThreadLoaderHolder::createAndStart(
     WorkerThreadableLoader* workerLoader,
     PassRefPtr<WorkerLoaderProxy> passLoaderProxy,
     WorkerThreadLifecycleContext* workerThreadLifecycleContext,
@@ -437,25 +437,25 @@
     else
         forwarder = new AsyncTaskForwarder(loaderProxy);
 
-    Peer* peer = new Peer(forwarder, workerThreadLifecycleContext);
-    if (peer->wasContextDestroyedBeforeObserverCreation()) {
+    MainThreadLoaderHolder* mainThreadLoaderHolder = new MainThreadLoaderHolder(forwarder, workerThreadLifecycleContext);
+    if (mainThreadLoaderHolder->wasContextDestroyedBeforeObserverCreation()) {
         // The thread is already terminating.
         forwarder->abort();
-        peer->m_forwarder = nullptr;
+        mainThreadLoaderHolder->m_forwarder = nullptr;
         return;
     }
-    peer->m_workerLoader = workerLoader;
-    peer->start(*toDocument(executionContext), std::move(request), options, resourceLoaderOptions);
-    forwarder->forwardTask(BLINK_FROM_HERE, createCrossThreadTask(&WorkerThreadableLoader::didStart, wrapCrossThreadPersistent(workerLoader), wrapCrossThreadPersistent(peer)));
+    mainThreadLoaderHolder->m_workerLoader = workerLoader;
+    mainThreadLoaderHolder->start(*toDocument(executionContext), std::move(request), options, resourceLoaderOptions);
+    forwarder->forwardTask(BLINK_FROM_HERE, createCrossThreadTask(&WorkerThreadableLoader::didStart, wrapCrossThreadPersistent(workerLoader), wrapCrossThreadPersistent(mainThreadLoaderHolder)));
 }
 
-WorkerThreadableLoader::Peer::~Peer()
+WorkerThreadableLoader::MainThreadLoaderHolder::~MainThreadLoaderHolder()
 {
     DCHECK(isMainThread());
     DCHECK(!m_workerLoader);
 }
 
-void WorkerThreadableLoader::Peer::overrideTimeout(unsigned long timeoutMilliseconds)
+void WorkerThreadableLoader::MainThreadLoaderHolder::overrideTimeout(unsigned long timeoutMilliseconds)
 {
     DCHECK(isMainThread());
     if (!m_mainThreadLoader)
@@ -463,7 +463,7 @@
     m_mainThreadLoader->overrideTimeout(timeoutMilliseconds);
 }
 
-void WorkerThreadableLoader::Peer::cancel()
+void WorkerThreadableLoader::MainThreadLoaderHolder::cancel()
 {
     DCHECK(isMainThread());
     if (!m_mainThreadLoader)
@@ -472,7 +472,7 @@
     m_mainThreadLoader = nullptr;
 }
 
-void WorkerThreadableLoader::Peer::didSendData(unsigned long long bytesSent, unsigned long long totalBytesToBeSent)
+void WorkerThreadableLoader::MainThreadLoaderHolder::didSendData(unsigned long long bytesSent, unsigned long long totalBytesToBeSent)
 {
     DCHECK(isMainThread());
     CrossThreadPersistent<WorkerThreadableLoader> workerLoader = m_workerLoader.get();
@@ -481,7 +481,7 @@
     m_forwarder->forwardTask(BLINK_FROM_HERE, createCrossThreadTask(&WorkerThreadableLoader::didSendData, workerLoader, bytesSent, totalBytesToBeSent));
 }
 
-void WorkerThreadableLoader::Peer::didReceiveResponse(unsigned long identifier, const ResourceResponse& response, std::unique_ptr<WebDataConsumerHandle> handle)
+void WorkerThreadableLoader::MainThreadLoaderHolder::didReceiveResponse(unsigned long identifier, const ResourceResponse& response, std::unique_ptr<WebDataConsumerHandle> handle)
 {
     DCHECK(isMainThread());
     CrossThreadPersistent<WorkerThreadableLoader> workerLoader = m_workerLoader.get();
@@ -490,7 +490,7 @@
     m_forwarder->forwardTask(BLINK_FROM_HERE, createCrossThreadTask(&WorkerThreadableLoader::didReceiveResponse, workerLoader, identifier, response, passed(std::move(handle))));
 }
 
-void WorkerThreadableLoader::Peer::didReceiveData(const char* data, unsigned dataLength)
+void WorkerThreadableLoader::MainThreadLoaderHolder::didReceiveData(const char* data, unsigned dataLength)
 {
     DCHECK(isMainThread());
     CrossThreadPersistent<WorkerThreadableLoader> workerLoader = m_workerLoader.get();
@@ -499,7 +499,7 @@
     m_forwarder->forwardTask(BLINK_FROM_HERE, createCrossThreadTask(&WorkerThreadableLoader::didReceiveData, workerLoader, passed(createVectorFromMemoryRegion(data, dataLength))));
 }
 
-void WorkerThreadableLoader::Peer::didDownloadData(int dataLength)
+void WorkerThreadableLoader::MainThreadLoaderHolder::didDownloadData(int dataLength)
 {
     DCHECK(isMainThread());
     CrossThreadPersistent<WorkerThreadableLoader> workerLoader = m_workerLoader.get();
@@ -508,7 +508,7 @@
     m_forwarder->forwardTask(BLINK_FROM_HERE, createCrossThreadTask(&WorkerThreadableLoader::didDownloadData, workerLoader, dataLength));
 }
 
-void WorkerThreadableLoader::Peer::didReceiveCachedMetadata(const char* data, int dataLength)
+void WorkerThreadableLoader::MainThreadLoaderHolder::didReceiveCachedMetadata(const char* data, int dataLength)
 {
     DCHECK(isMainThread());
     CrossThreadPersistent<WorkerThreadableLoader> workerLoader = m_workerLoader.get();
@@ -517,7 +517,7 @@
     m_forwarder->forwardTask(BLINK_FROM_HERE, createCrossThreadTask(&WorkerThreadableLoader::didReceiveCachedMetadata, workerLoader, passed(createVectorFromMemoryRegion(data, dataLength))));
 }
 
-void WorkerThreadableLoader::Peer::didFinishLoading(unsigned long identifier, double finishTime)
+void WorkerThreadableLoader::MainThreadLoaderHolder::didFinishLoading(unsigned long identifier, double finishTime)
 {
     DCHECK(isMainThread());
     CrossThreadPersistent<WorkerThreadableLoader> workerLoader = m_workerLoader.get();
@@ -527,7 +527,7 @@
     m_forwarder = nullptr;
 }
 
-void WorkerThreadableLoader::Peer::didFail(const ResourceError& error)
+void WorkerThreadableLoader::MainThreadLoaderHolder::didFail(const ResourceError& error)
 {
     DCHECK(isMainThread());
     CrossThreadPersistent<WorkerThreadableLoader> workerLoader = m_workerLoader.get();
@@ -537,7 +537,7 @@
     m_forwarder = nullptr;
 }
 
-void WorkerThreadableLoader::Peer::didFailAccessControlCheck(const ResourceError& error)
+void WorkerThreadableLoader::MainThreadLoaderHolder::didFailAccessControlCheck(const ResourceError& error)
 {
     DCHECK(isMainThread());
     CrossThreadPersistent<WorkerThreadableLoader> workerLoader = m_workerLoader.get();
@@ -547,7 +547,7 @@
     m_forwarder = nullptr;
 }
 
-void WorkerThreadableLoader::Peer::didFailRedirectCheck()
+void WorkerThreadableLoader::MainThreadLoaderHolder::didFailRedirectCheck()
 {
     DCHECK(isMainThread());
     CrossThreadPersistent<WorkerThreadableLoader> workerLoader = m_workerLoader.get();
@@ -557,7 +557,7 @@
     m_forwarder = nullptr;
 }
 
-void WorkerThreadableLoader::Peer::didReceiveResourceTiming(const ResourceTimingInfo& info)
+void WorkerThreadableLoader::MainThreadLoaderHolder::didReceiveResourceTiming(const ResourceTimingInfo& info)
 {
     DCHECK(isMainThread());
     CrossThreadPersistent<WorkerThreadableLoader> workerLoader = m_workerLoader.get();
@@ -566,7 +566,7 @@
     m_forwarder->forwardTask(BLINK_FROM_HERE, createCrossThreadTask(&WorkerThreadableLoader::didReceiveResourceTiming, workerLoader, info));
 }
 
-void WorkerThreadableLoader::Peer::contextDestroyed()
+void WorkerThreadableLoader::MainThreadLoaderHolder::contextDestroyed()
 {
     DCHECK(isMainThread());
     if (m_forwarder) {
@@ -577,21 +577,21 @@
     cancel();
 }
 
-DEFINE_TRACE(WorkerThreadableLoader::Peer)
+DEFINE_TRACE(WorkerThreadableLoader::MainThreadLoaderHolder)
 {
     visitor->trace(m_forwarder);
     visitor->trace(m_mainThreadLoader);
     WorkerThreadLifecycleObserver::trace(visitor);
 }
 
-WorkerThreadableLoader::Peer::Peer(TaskForwarder* forwarder, WorkerThreadLifecycleContext* context)
+WorkerThreadableLoader::MainThreadLoaderHolder::MainThreadLoaderHolder(TaskForwarder* forwarder, WorkerThreadLifecycleContext* context)
     : WorkerThreadLifecycleObserver(context)
     , m_forwarder(forwarder)
 {
     DCHECK(isMainThread());
 }
 
-void WorkerThreadableLoader::Peer::start(
+void WorkerThreadableLoader::MainThreadLoaderHolder::start(
     Document& document,
     std::unique_ptr<CrossThreadResourceRequestData> request,
     const ThreadableLoaderOptions& options,
diff --git a/third_party/WebKit/Source/core/loader/WorkerThreadableLoader.h b/third_party/WebKit/Source/core/loader/WorkerThreadableLoader.h
index 02c0d8a..bcd683ee 100644
--- a/third_party/WebKit/Source/core/loader/WorkerThreadableLoader.h
+++ b/third_party/WebKit/Source/core/loader/WorkerThreadableLoader.h
@@ -56,9 +56,31 @@
 struct CrossThreadResourceRequestData;
 struct CrossThreadResourceTimingInfoData;
 
-// TODO(yhirano): Draw a diagram to illustrate the class relationship.
-// TODO(yhirano): Rename inner classes so that readers can see in which thread
-// they are living easily.
+// A WorkerThreadableLoader is a ThreadableLoader implementation intended to
+// be used in a WebWorker thread. Because Blink's ResourceFetcher and
+// ResourceLoader work only in the main thread, a WorkerThreadableLoader holds
+// a ThreadableLoader in the main thread and delegates tasks asynchronously
+// to the loader.
+//
+// CTP: CrossThreadPersistent
+// CTWP: CrossThreadWeakPersistent
+//
+// ----------------------------------------------------------------
+//                 +------------------------+
+//       raw ptr   | ThreadableLoaderClient |
+//      +--------> | worker thread          |
+//      |          +------------------------+
+//      |
+// +----+------------------+    CTP  +------------------------+
+// + WorkerThreadableLoader|<--------+ MainThreadLoaderHolder |
+// | worker thread         +-------->| main thread            |
+// +-----------------------+   CTWP  +----------------------+-+
+//                                                          |
+//                                 +------------------+     | Member
+//                                 | ThreadableLoader | <---+
+//                                 |      main thread |
+//                                 +------------------+
+//
 class WorkerThreadableLoader final : public ThreadableLoader {
 public:
     static void loadResourceSynchronously(WorkerGlobalScope&, const ResourceRequest&, ThreadableLoaderClient&, const ThreadableLoaderOptions&, const ResourceLoaderOptions&);
@@ -101,8 +123,8 @@
     // ThreadableLoaderClient for a DocumentThreadableLoader and forward
     // notifications to the associated WorkerThreadableLoader living in the
     // worker thread.
-    class Peer final : public GarbageCollectedFinalized<Peer>, public ThreadableLoaderClient, public WorkerThreadLifecycleObserver {
-        USING_GARBAGE_COLLECTED_MIXIN(Peer);
+    class MainThreadLoaderHolder final : public GarbageCollectedFinalized<MainThreadLoaderHolder>, public ThreadableLoaderClient, public WorkerThreadLifecycleObserver {
+        USING_GARBAGE_COLLECTED_MIXIN(MainThreadLoaderHolder);
     public:
         static void createAndStart(
             WorkerThreadableLoader*,
@@ -113,7 +135,7 @@
             const ResourceLoaderOptions&,
             PassRefPtr<WaitableEventWithTasks>,
             ExecutionContext*);
-        ~Peer() override;
+        ~MainThreadLoaderHolder() override;
 
         void overrideTimeout(unsigned long timeoutMillisecond);
         void cancel();
@@ -134,7 +156,7 @@
         DECLARE_TRACE();
 
     private:
-        Peer(TaskForwarder*, WorkerThreadLifecycleContext*);
+        MainThreadLoaderHolder(TaskForwarder*, WorkerThreadLifecycleContext*);
         void start(Document&, std::unique_ptr<CrossThreadResourceRequestData>, const ThreadableLoaderOptions&, const ResourceLoaderOptions&);
 
         Member<TaskForwarder> m_forwarder;
@@ -145,7 +167,7 @@
     };
 
     WorkerThreadableLoader(WorkerGlobalScope&, ThreadableLoaderClient*, const ThreadableLoaderOptions&, const ResourceLoaderOptions&, BlockingBehavior);
-    void didStart(Peer*);
+    void didStart(MainThreadLoaderHolder*);
 
     void didSendData(unsigned long long bytesSent, unsigned long long totalBytesToBeSent);
     void didReceiveResponse(unsigned long identifier, std::unique_ptr<CrossThreadResourceResponseData>, std::unique_ptr<WebDataConsumerHandle>);
@@ -166,8 +188,8 @@
     ResourceLoaderOptions m_resourceLoaderOptions;
     BlockingBehavior m_blockingBehavior;
 
-    // |*m_peer| lives in the main thread.
-    CrossThreadPersistent<Peer> m_peer;
+    // |*m_mainThreadLoaderHolder| lives in the main thread.
+    CrossThreadPersistent<MainThreadLoaderHolder> m_mainThreadLoaderHolder;
 };
 
 } // namespace blink
diff --git a/third_party/WebKit/Source/core/page/scrolling/ScrollingCoordinator.cpp b/third_party/WebKit/Source/core/page/scrolling/ScrollingCoordinator.cpp
index 9621186..031d7517 100644
--- a/third_party/WebKit/Source/core/page/scrolling/ScrollingCoordinator.cpp
+++ b/third_party/WebKit/Source/core/page/scrolling/ScrollingCoordinator.cpp
@@ -540,9 +540,12 @@
 
             if (layer->parent()) {
                 layer = layer->parent();
-            } else if (LayoutObject* parentDocLayoutObject = layer->layoutObject()->frame()->ownerLayoutObject()) {
-                layer = parentDocLayoutObject->enclosingLayer();
-                touchHandlerInChildFrame = true;
+            } else {
+                LayoutItem parentDocLayoutItem = layer->layoutObject()->frame()->ownerLayoutItem();
+                if (!parentDocLayoutItem.isNull()) {
+                    layer = parentDocLayoutItem.enclosingLayer();
+                    touchHandlerInChildFrame = true;
+                }
             }
         } while (layer);
     }
diff --git a/third_party/WebKit/Source/core/paint/PaintPropertyTreeBuilderTest.cpp b/third_party/WebKit/Source/core/paint/PaintPropertyTreeBuilderTest.cpp
index fba8378..68e572e1 100644
--- a/third_party/WebKit/Source/core/paint/PaintPropertyTreeBuilderTest.cpp
+++ b/third_party/WebKit/Source/core/paint/PaintPropertyTreeBuilderTest.cpp
@@ -99,6 +99,7 @@
     EXPECT_EQ(scrollerProperties->overflowClip(), target2Properties->overflowClip()->parent());
 
     CHECK_VISUAL_RECT(target1->layoutObject(), frameView->layoutView());
+    CHECK_VISUAL_RECT(target2->layoutObject(), frameView->layoutView());
 }
 
 TEST_F(PaintPropertyTreeBuilderTest, PositionAndScroll)
diff --git a/third_party/WebKit/Source/core/svg/graphics/SVGImage.cpp b/third_party/WebKit/Source/core/svg/graphics/SVGImage.cpp
index 821e926..6e9bfe2 100644
--- a/third_party/WebKit/Source/core/svg/graphics/SVGImage.cpp
+++ b/third_party/WebKit/Source/core/svg/graphics/SVGImage.cpp
@@ -304,12 +304,18 @@
     if (!m_page)
         return nullptr;
 
-    SkPictureRecorder recorder;
-    SkCanvas* canvas = recorder.beginRecording(width(), height());
-    drawForContainer(canvas, SkPaint(), containerSize, 1, rect(), rect(), url);
+    const FloatRect containerRect(FloatPoint(), containerSize);
 
+    SkPictureRecorder recorder;
+    SkCanvas* canvas = recorder.beginRecording(containerRect);
+    drawForContainer(canvas, SkPaint(), containerSize, 1, containerRect, containerRect, url);
+
+    const IntSize imageSize = roundedIntSize(containerSize);
+    const SkMatrix residualScale = SkMatrix::MakeScale(
+        static_cast<float>(imageSize.width()) / containerSize.width(),
+        static_cast<float>(imageSize.height()) / containerSize.height());
     return fromSkSp(SkImage::MakeFromPicture(recorder.finishRecordingAsPicture(),
-        SkISize::Make(width(), height()), nullptr, nullptr));
+        SkISize::Make(imageSize.width(), imageSize.height()), &residualScale, nullptr));
 }
 
 static bool drawNeedsLayer(const SkPaint& paint)
diff --git a/third_party/WebKit/Source/devtools/front_end/components/breakpointsList.css b/third_party/WebKit/Source/devtools/front_end/components/breakpointsList.css
index b7b3d1a..6d06233 100644
--- a/third_party/WebKit/Source/devtools/front_end/components/breakpointsList.css
+++ b/third_party/WebKit/Source/devtools/front_end/components/breakpointsList.css
@@ -98,7 +98,7 @@
 }
 
 .event-listener-breakpoints {
-    margin-top: 0;
+    margin: 0;
     padding: 2px 6px;
     list-style: none;
     min-height: 18px;
diff --git a/third_party/WebKit/Source/devtools/front_end/elements/ElementsTreeOutline.js b/third_party/WebKit/Source/devtools/front_end/elements/ElementsTreeOutline.js
index f04872af..60942ecf3 100644
--- a/third_party/WebKit/Source/devtools/front_end/elements/ElementsTreeOutline.js
+++ b/third_party/WebKit/Source/devtools/front_end/elements/ElementsTreeOutline.js
@@ -83,7 +83,8 @@
     this._treeElementsBeingUpdated = new Set();
 
     this._domModel.addEventListener(WebInspector.DOMModel.Events.MarkersChanged, this._markersChanged, this);
-    WebInspector.moduleSetting("showHTMLComments").addChangeListener(this._onShowHTMLCommentsChange.bind(this));
+    this._showHTMLCommentsSetting = WebInspector.moduleSetting("showHTMLComments");
+    this._showHTMLCommentsSetting.addChangeListener(this._onShowHTMLCommentsChange.bind(this));
 }
 
 WebInspector.ElementsTreeOutline._treeOutlineSymbol = Symbol("treeOutline");
@@ -137,7 +138,7 @@
     _onShowHTMLCommentsChange: function()
     {
         var selectedNode = this.selectedDOMNode();
-        if (selectedNode && selectedNode.nodeType() === Node.COMMENT_NODE && !WebInspector.moduleSetting("showHTMLComments").get())
+        if (selectedNode && selectedNode.nodeType() === Node.COMMENT_NODE && !this._showHTMLCommentsSetting.get())
             this.selectDOMNode(selectedNode.parentNode);
         this.update();
     },
@@ -1351,7 +1352,7 @@
 
         if (node.childNodeCount()) {
             var children = node.children();
-            if (!WebInspector.moduleSetting("showHTMLComments").get())
+            if (!this._showHTMLCommentsSetting.get())
                 children = children.filter(n => n.nodeType() !== Node.COMMENT_NODE);
             visibleChildren = visibleChildren.concat(children);
         }
diff --git a/third_party/WebKit/Source/devtools/front_end/inspector.js b/third_party/WebKit/Source/devtools/front_end/inspector.js
index 0b71b5b..322527d 100644
--- a/third_party/WebKit/Source/devtools/front_end/inspector.js
+++ b/third_party/WebKit/Source/devtools/front_end/inspector.js
@@ -2,13 +2,4 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-// Preload protocol resources for hosted mode.
-if (!/** @type {?Object} */(window.InspectorFrontendHost)) {
-    Promise.all([
-        Runtime.loadResourceIntoCache("./sdk/protocol/browser_protocol.json", false /* appendSourceURL */),
-        Runtime.loadResourceIntoCache("./sdk/protocol/js_protocol.json", false /* appendSourceURL */)
-    ]).then(() => Runtime.startApplication("inspector"));
-} else {
-    Runtime.startApplication("inspector");
-}
-
+Runtime.startApplication("inspector");
diff --git a/third_party/WebKit/Source/devtools/front_end/network/NetworkItemView.js b/third_party/WebKit/Source/devtools/front_end/network/NetworkItemView.js
index 829ecad..a385128 100644
--- a/third_party/WebKit/Source/devtools/front_end/network/NetworkItemView.js
+++ b/third_party/WebKit/Source/devtools/front_end/network/NetworkItemView.js
@@ -118,19 +118,6 @@
 }
 
 WebInspector.RequestContentView.prototype = {
-    /**
-     * @return {!WebInspector.Widget}
-     */
-    get innerView()
-    {
-        return this._innerView;
-    },
-
-    set innerView(innerView)
-    {
-        this._innerView = innerView;
-    },
-
     wasShown: function()
     {
         this._ensureInnerViewShown();
diff --git a/third_party/WebKit/Source/devtools/front_end/network/RequestPreviewView.js b/third_party/WebKit/Source/devtools/front_end/network/RequestPreviewView.js
index a316ec37..45ce5c3 100644
--- a/third_party/WebKit/Source/devtools/front_end/network/RequestPreviewView.js
+++ b/third_party/WebKit/Source/devtools/front_end/network/RequestPreviewView.js
@@ -38,6 +38,8 @@
 {
     WebInspector.RequestContentView.call(this, request);
     this._responseView = responseView;
+    /** @type {?WebInspector.Widget} */
+    this._previewView = null;
 }
 
 WebInspector.RequestPreviewView.prototype = {
@@ -47,21 +49,20 @@
             if (!this._emptyWidget) {
                 this._emptyWidget = this._createEmptyWidget();
                 this._emptyWidget.show(this.element);
-                this.innerView = this._emptyWidget;
+                this._previewView = this._emptyWidget;
             }
-        } else {
-            if (this._emptyWidget) {
-                this._emptyWidget.detach();
-                delete this._emptyWidget;
-            }
-
-            if (!this._previewView) {
-                this._createPreviewView(handlePreviewView.bind(this));
-            } else {
-                this.innerView = this._previewView;
-                handlePreviewView.call(this, this.innerView);
-            }
+            return;
         }
+        if (this._emptyWidget) {
+            this._emptyWidget.detach();
+            delete this._emptyWidget;
+            this._previewView = null;
+        }
+
+        if (!this._previewView)
+            this._createPreviewView(handlePreviewView.bind(this));
+        else
+            this._previewView.show(this.element);
 
         /**
          * @param {!WebInspector.Widget} view
@@ -70,14 +71,13 @@
         function handlePreviewView(view)
         {
             this._previewView = view;
-            this._previewView.show(this.element);
-            if (this._previewView instanceof WebInspector.View) {
+            view.show(this.element);
+            if (view instanceof WebInspector.View) {
                 var toolbar = new WebInspector.Toolbar("network-item-preview-toolbar", this.element);
-                for (var item of /** @type {!WebInspector.View} */ (this._previewView).toolbarItems())
+                for (var item of /** @type {!WebInspector.View} */ (view).toolbarItems())
                     toolbar.appendToolbarItem(item);
             }
-            this.innerView = this._previewView;
-            this._previewViewHandledForTest(this._previewView);
+            this._previewViewHandledForTest(view);
         }
     },
 
diff --git a/third_party/WebKit/Source/devtools/front_end/network/RequestResponseView.js b/third_party/WebKit/Source/devtools/front_end/network/RequestResponseView.js
index 34c35d6..44710cd1 100644
--- a/third_party/WebKit/Source/devtools/front_end/network/RequestResponseView.js
+++ b/third_party/WebKit/Source/devtools/front_end/network/RequestResponseView.js
@@ -65,7 +65,6 @@
             if (!this._emptyWidget) {
                 this._emptyWidget = this._createMessageView(WebInspector.UIString("This request has no response data available."));
                 this._emptyWidget.show(this.element);
-                this.innerView = this._emptyWidget;
             }
         } else {
             if (this._emptyWidget) {
@@ -75,12 +74,10 @@
 
             if (this.request.content && this.sourceView) {
                 this.sourceView.show(this.element);
-                this.innerView = this.sourceView;
             } else {
                 if (!this._errorView)
                     this._errorView = this._createMessageView(WebInspector.UIString("Failed to load response data"));
                 this._errorView.show(this.element);
-                this.innerView = this._errorView;
             }
         }
     },
diff --git a/third_party/WebKit/Source/devtools/front_end/sources/sourcesPanel.css b/third_party/WebKit/Source/devtools/front_end/sources/sourcesPanel.css
index 70f415e..8ee0bd29 100644
--- a/third_party/WebKit/Source/devtools/front_end/sources/sourcesPanel.css
+++ b/third_party/WebKit/Source/devtools/front_end/sources/sourcesPanel.css
@@ -112,6 +112,9 @@
     padding: 6px;
     color: #888;
     pointer-events: none;
+    display: flex;
+    align-items: center;
+    justify-content: center;
 }
 
 .callstack-info.status {
@@ -133,6 +136,7 @@
     background-repeat: no-repeat;
     border: 0 none transparent;
     position: absolute;
+    top: 4px;
     right: 3px;
     display: none;
 }
@@ -143,6 +147,7 @@
 
 .watch-expressions {
     overflow-x: hidden;
+    min-height: 26px;
 }
 
 .watch-expressions .dimmed {
@@ -153,7 +158,7 @@
     white-space: nowrap;
     text-overflow: ellipsis;
     overflow: hidden;
-    line-height: 12px;
+    line-height: 16px;
     margin-left: 11px;
 }
 
diff --git a/third_party/WebKit/Source/devtools/front_end/sources/uiList.css b/third_party/WebKit/Source/devtools/front_end/sources/uiList.css
index 88a60cf8..b7d757d 100644
--- a/third_party/WebKit/Source/devtools/front_end/sources/uiList.css
+++ b/third_party/WebKit/Source/devtools/front_end/sources/uiList.css
@@ -7,8 +7,10 @@
 .list-item {
     padding: 2px 8px 3px 8px;
     position: relative;
-    min-height: 18px;
+    min-height: 26px;
     white-space: nowrap;
+    align-items: center;
+    display: flex;
 }
 
 .list-item:nth-of-type(2n) {
diff --git a/third_party/WebKit/Source/devtools/front_end/ui/SplitWidget.js b/third_party/WebKit/Source/devtools/front_end/ui/SplitWidget.js
index 3f9e839..41d618c 100644
--- a/third_party/WebKit/Source/devtools/front_end/ui/SplitWidget.js
+++ b/third_party/WebKit/Source/devtools/front_end/ui/SplitWidget.js
@@ -477,8 +477,9 @@
         this._removeAllLayoutProperties();
 
         // this._totalSizeDIP is available below since we successfully applied constraints.
-        var sidebarSizeValue = WebInspector.zoomManager.dipToCSS(sizeDIP) + "px";
-        var mainSizeValue = (this._totalSizeCSS - WebInspector.zoomManager.dipToCSS(sizeDIP)) + "px";
+        var roundSizeCSS = Math.round(WebInspector.zoomManager.dipToCSS(sizeDIP));
+        var sidebarSizeValue = roundSizeCSS + "px";
+        var mainSizeValue = (this._totalSizeCSS - roundSizeCSS) + "px";
         this._sidebarElement.style.flexBasis = sidebarSizeValue;
 
         // Make both sides relayout boundaries.
diff --git a/third_party/WebKit/Source/devtools/front_end/ui/ViewContainers.js b/third_party/WebKit/Source/devtools/front_end/ui/ViewContainers.js
index 5f79c4c..df45b20 100644
--- a/third_party/WebKit/Source/devtools/front_end/ui/ViewContainers.js
+++ b/third_party/WebKit/Source/devtools/front_end/ui/ViewContainers.js
@@ -44,12 +44,13 @@
     this._titleElement.addEventListener("click", this._toggleExpanded.bind(this), false);
     this._titleElement.addEventListener("keydown", this._onTitleKeyDown.bind(this), false);
     this.contentElement.insertBefore(this._titleElement, this.contentElement.firstChild);
+
     var toolbarElement = this.contentElement.createChild("div");
     var toolbarItems = view.toolbarItems();
     if (toolbarItems.length) {
-        var toolbar = new WebInspector.Toolbar("", this._titleElement);
+        this._toolbar = new WebInspector.Toolbar("");
         for (var item of toolbarItems)
-            toolbar.appendToolbarItem(item);
+            this._toolbar.appendToolbarItem(item);
     }
 
     this.contentElement.createChild("content");
@@ -72,6 +73,8 @@
     {
         if (this._titleElement.classList.contains("expanded"))
             return true;
+        if (this._toolbar)
+            this._titleElement.appendChild(this._toolbar.element);
         this._titleElement.classList.add("expanded");
         this._view.showWidget(this.element);
         return true;
@@ -81,6 +84,8 @@
     {
         if (!this._titleElement.classList.contains("expanded"))
             return;
+        if (this._toolbar)
+            this._toolbar.element.remove();
         this._titleElement.classList.remove("expanded");
         this._view.hideWidget();
     },
diff --git a/third_party/WebKit/Source/devtools/front_end/ui/viewContainers.css b/third_party/WebKit/Source/devtools/front_end/ui/viewContainers.css
index 2ce52a00..dc2fe7e 100644
--- a/third_party/WebKit/Source/devtools/front_end/ui/viewContainers.css
+++ b/third_party/WebKit/Source/devtools/front_end/ui/viewContainers.css
@@ -35,12 +35,13 @@
     display: flex;
     align-items: center;
     background-color: #eee;
-    height: 20px;
+    height: 26px;
     padding: 0 5px;
     border-top: 1px solid #dadada;
     white-space: nowrap;
     overflow: hidden;
     position: relative;
+    border-bottom: 1px solid transparent;
 }
 
 .expandable-view-title.expanded,
@@ -78,7 +79,7 @@
 .expandable-view-title > .toolbar {
     position: absolute;
     right: 0;
-    top: -3px;
+    top: 0;
 }
 
 .sidebar-pane-container .toolbar {
diff --git a/third_party/WebKit/Source/devtools/scripts/hosted_mode/server.js b/third_party/WebKit/Source/devtools/scripts/hosted_mode/server.js
index 8d6dfd1e5..811bf70a 100644
--- a/third_party/WebKit/Source/devtools/scripts/hosted_mode/server.js
+++ b/third_party/WebKit/Source/devtools/scripts/hosted_mode/server.js
@@ -1,23 +1,26 @@
 // Copyright (c) 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.
-
 var fs = require("fs");
 var http = require("http");
 var https = require("https");
 var path = require("path");
 var parseURL = require("url").parse;
+var Stream = require("stream").Transform;
 
-var port = parseInt(process.env.PORT, 10) || 8090;
+var remoteDebuggingPort = parseInt(process.env.REMOTE_DEBUGGING_PORT, 10) || 9222;
+var serverPort = parseInt(process.env.PORT, 10) || 8090;
+var devtoolsFolder = path.resolve(path.join(__dirname, "../.."));
 
-http.createServer(requestHandler).listen(port);
-console.log("Started hosted mode server at http://localhost:" + port);
+http.createServer(requestHandler).listen(serverPort);
+console.log("Started hosted mode server at http://localhost:" + serverPort);
 
 function requestHandler(request, response)
 {
     var filePath = parseURL(request.url).pathname;
-    if (filePath === "/front_end/InspectorBackendCommands.js") {
-        sendResponse(200, " ");
+    if (filePath === "/") {
+        var landingURL = `http://localhost:${remoteDebuggingPort}#http://localhost:${serverPort}/front_end/inspector.html?experiments=true`;
+        sendResponse(200, `<html>Please go to <a href="${landingURL}">${landingURL}</a></html>`);
         return;
     }
 
@@ -32,10 +35,17 @@
     function handleProxyError(err)
     {
         console.log(`Error fetching over the internet file ${filePath}:`, err);
+        console.log(`Make sure you opened Chrome with the flag "--remote-debugging-port=${remoteDebuggingPort}"`);
         sendResponse(500, "500 - Internal Server Error");
     }
 
     var absoluteFilePath = path.join(process.cwd(), filePath);
+    if (!path.resolve(absoluteFilePath).startsWith(devtoolsFolder)) {
+        console.log(`File requested is outside of devtools folder: ${devtoolsFolder}`);
+        sendResponse(403, "`403 - Access denied. File requested is outside of devtools folder: ${devtoolsFolder}`");
+        return;
+    }
+
     fs.exists(absoluteFilePath, fsExistsCallback);
 
     function fsExistsCallback(fileExists)
@@ -67,25 +77,14 @@
 }
 
 var proxyFilePathToURL = {
-    "/front_end/sdk/protocol/js_protocol.json": getWebKitURL.bind(null, "platform/v8_inspector/js_protocol.json"),
-    "/front_end/sdk/protocol/browser_protocol.json": getWebKitURL.bind(null, "core/inspector/browser_protocol.json"),
-    "/front_end/SupportedCSSProperties.js": getFrontendURL.bind(null, "SupportedCSSProperties.js")
+    "/front_end/SupportedCSSProperties.js": cloudURL.bind(null, "SupportedCSSProperties.js"),
+    "/front_end/InspectorBackendCommands.js": cloudURL.bind(null, "InspectorBackendCommands.js"),
+    "/favicon.ico": () => "https://chrome-devtools-frontend.appspot.com/favicon.ico"
 };
 
-function getWebKitURL(path, commitHash)
+function cloudURL(path, commitHash)
 {
-    return {
-        url: `https://chromium.googlesource.com/chromium/src/+/${commitHash}/third_party/WebKit/Source/${path}?format=TEXT`,
-        isBase64: true
-    }
-}
-
-function getFrontendURL(path, commitHash)
-{
-    return {
-        url: `https://chrome-devtools-frontend.appspot.com/serve_file/@${commitHash}/${path}`,
-        isBase64: false
-    }
+    return `https://chrome-devtools-frontend.appspot.com/serve_file/@${commitHash}/${path}`;
 }
 
 var proxyFileCache = new Map();
@@ -94,7 +93,7 @@
 {
     if (!(filePath in proxyFilePathToURL))
         return null;
-    return fetch("http://localhost:9222/json/version")
+    return fetch(`http://localhost:${remoteDebuggingPort}/json/version`)
         .then(onBrowserMetadata);
 
     function onBrowserMetadata(metadata)
@@ -102,12 +101,10 @@
         var metadataObject = JSON.parse(metadata);
         var match = metadataObject["WebKit-Version"].match(/\s\(@(\b[0-9a-f]{5,40}\b)/);
         var commitHash = match[1];
-        var proxyFile = proxyFilePathToURL[filePath](commitHash);
-        var proxyFileURL = proxyFile.url;
+        var proxyFileURL = proxyFilePathToURL[filePath](commitHash);
         if (proxyFileCache.has(proxyFileURL))
             return proxyFileCache.get(proxyFileURL);
         return fetch(proxyFileURL)
-            .then(text => proxyFile.isBase64 ? new Buffer(text, "base64").toString("binary") : text)
             .then(cacheProxyFile.bind(null, proxyFileURL));
     }
 
@@ -122,7 +119,8 @@
 {
     return new Promise(fetchPromise);
 
-    function fetchPromise(resolve, reject) {
+    function fetchPromise(resolve, reject)
+    {
         var request;
         var protocol = parseURL(url).protocol;
         var handleResponse = getCallback.bind(null, resolve, reject);
@@ -143,9 +141,9 @@
             reject(new Error(`Request error: + ${response.statusCode}`));
             return;
         }
-        var body = "";
-        response.on("data", chunk => body += chunk);
-        response.on("end", () => resolve(body));
+        var body = new Stream();
+        response.on("data", chunk => body.push(chunk));
+        response.on("end", () => resolve(body.read()));
     }
 }
 
diff --git a/third_party/WebKit/Source/modules/canvas2d/BaseRenderingContext2D.cpp b/third_party/WebKit/Source/modules/canvas2d/BaseRenderingContext2D.cpp
index f85fa19..8f80b020 100644
--- a/third_party/WebKit/Source/modules/canvas2d/BaseRenderingContext2D.cpp
+++ b/third_party/WebKit/Source/modules/canvas2d/BaseRenderingContext2D.cpp
@@ -949,7 +949,12 @@
 
 void BaseRenderingContext2D::drawImageInternal(SkCanvas* c, CanvasImageSource* imageSource, Image* image, const FloatRect& srcRect, const FloatRect& dstRect, const SkPaint* paint)
 {
-    trackDrawCall(DrawImage, nullptr, dstRect.width(), dstRect.height());
+    if (imageSource->isSVGSource()) {
+        trackDrawCall(DrawVectorImage, nullptr, dstRect.width(), dstRect.height());
+    } else {
+        trackDrawCall(DrawBitmapImage, nullptr, dstRect.width(), dstRect.height());
+    }
+
 
     int initialSaveCount = c->getSaveCount();
     SkPaint imagePaint = *paint;
@@ -1523,12 +1528,17 @@
 
 void BaseRenderingContext2D::trackDrawCall(DrawCallType callType, Path2D* path2d, int width, int height)
 {
+    if (!RuntimeEnabledFeatures::enableCanvas2dDynamicRenderingModeSwitchingEnabled()) {
+        // Rendering mode switching is disabled so no need to track the usage
+        return;
+    }
+
     m_usageCounters.numDrawCalls[callType]++;
 
-    double boundingRectWidth = static_cast<double>(width);
-    double boundingRectHeight = static_cast<double>(height);
-    double boundingRectArea = boundingRectWidth * boundingRectHeight;
-    double boundingRectPerimeter = (2.0 * boundingRectWidth) + (2.0 * boundingRectHeight);
+    float boundingRectWidth = static_cast<float>(width);
+    float boundingRectHeight = static_cast<float>(height);
+    float boundingRectArea = boundingRectWidth * boundingRectHeight;
+    float boundingRectPerimeter = (2.0 * boundingRectWidth) + (2.0 * boundingRectHeight);
 
     if (callType == FillText
         || callType == FillPath
@@ -1544,19 +1554,21 @@
             skPath = m_path.getSkPath();
         }
 
-        if (callType == FillPath && !(skPath.getConvexity() == SkPath::kConvex_Convexity)) {
-            m_usageCounters.numNonConvexFillPathCalls++;
-        }
 
-        if (!(callType == FillRect || callType == StrokeRect || callType == DrawImage)) {
+        if (!(callType == FillRect || callType == StrokeRect || callType == DrawVectorImage || callType == DrawBitmapImage)) {
             // The correct width and height were not passed as parameters
             const SkRect& boundingRect = skPath.getBounds();
-            boundingRectWidth = static_cast<double>(std::abs(boundingRect.width()));
-            boundingRectHeight = static_cast<double>(std::abs(boundingRect.height()));
+            boundingRectWidth = static_cast<float>(std::abs(boundingRect.width()));
+            boundingRectHeight = static_cast<float>(std::abs(boundingRect.height()));
             boundingRectArea = boundingRectWidth * boundingRectHeight;
             boundingRectPerimeter = 2.0 * boundingRectWidth + 2.0 * boundingRectHeight;
         }
 
+        if (callType == FillPath && skPath.getConvexity() != SkPath::kConvex_Convexity) {
+            m_usageCounters.numNonConvexFillPathCalls++;
+            m_usageCounters.nonConvexFillPathArea += boundingRectArea;
+        }
+
         m_usageCounters.boundingBoxPerimeterDrawCalls[callType] += boundingRectPerimeter;
         m_usageCounters.boundingBoxAreaDrawCalls[callType] += boundingRectArea;
 
@@ -1569,10 +1581,12 @@
 
         CanvasGradient* gradient = canvasStyle->getCanvasGradient();
         if (gradient) {
-            m_usageCounters.numGradients++;
+
             if (gradient->getGradient()->isRadial()) {
+                m_usageCounters.numRadialGradients++;
                 m_usageCounters.boundingBoxAreaFillType[BaseRenderingContext2D::RadialGradientFillType] += boundingRectArea;
             } else {
+                m_usageCounters.numLinearGradients++;
                 m_usageCounters.boundingBoxAreaFillType[BaseRenderingContext2D::LinearGradientFillType] += boundingRectArea;
             }
         } else if (canvasStyle->getCanvasPattern()) {
@@ -1583,9 +1597,9 @@
         }
     }
 
-    if (callType == DrawImage) {
-        m_usageCounters.boundingBoxPerimeterDrawCalls[DrawImage] += boundingRectPerimeter;
-        m_usageCounters.boundingBoxAreaDrawCalls[DrawImage] += boundingRectArea;
+    if (callType == DrawVectorImage || callType == DrawBitmapImage) {
+        m_usageCounters.boundingBoxPerimeterDrawCalls[callType] += boundingRectPerimeter;
+        m_usageCounters.boundingBoxAreaDrawCalls[callType] += boundingRectArea;
     }
 
     if (callType == FillText
@@ -1594,7 +1608,8 @@
         || callType == StrokePath
         || callType == FillRect
         || callType == StrokeRect
-        || callType == DrawImage) {
+        || callType == DrawVectorImage
+        || callType == DrawBitmapImage) {
         if (state().shadowBlur() > 0.0 && SkColorGetA(state().shadowColor()) > 0) {
             m_usageCounters.numBlurredShadows++;
             m_usageCounters.boundingBoxAreaTimesShadowBlurSquared += boundingRectArea * state().shadowBlur() * state().shadowBlur();
@@ -1622,17 +1637,19 @@
 }
 
 BaseRenderingContext2D::UsageCounters::UsageCounters() :
-    numDrawCalls {0, 0, 0, 0, 0, 0},
-    boundingBoxPerimeterDrawCalls {0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
-    boundingBoxAreaDrawCalls {0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
-    boundingBoxAreaFillType {0.0, 0.0, 0.0, 0.0},
+    numDrawCalls {0, 0, 0, 0, 0, 0, 0},
+    boundingBoxPerimeterDrawCalls {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f},
+    boundingBoxAreaDrawCalls {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f},
+    boundingBoxAreaFillType {0.0f, 0.0f, 0.0f, 0.0f},
     numNonConvexFillPathCalls(0),
-    numGradients(0),
+    nonConvexFillPathArea(0.0f),
+    numRadialGradients(0),
+    numLinearGradients(0),
     numPatterns(0),
     numDrawWithComplexClips(0),
     numBlurredShadows(0),
-    boundingBoxAreaTimesShadowBlurSquared(0.0),
-    boundingBoxPerimeterTimesShadowBlurSquared(0.0),
+    boundingBoxAreaTimesShadowBlurSquared(0.0f),
+    boundingBoxPerimeterTimesShadowBlurSquared(0.0f),
     numFilters(0),
     numGetImageDataCalls(0),
     areaGetImageDataCalls(0.0),
@@ -1642,4 +1659,51 @@
     numDrawFocusCalls(0),
     numFramesSinceReset(0) {}
 
+
+float BaseRenderingContext2D::estimateRenderingCost(ExpensiveCanvasHeuristicParameters::RenderingModeCostIndex index) const
+{
+    float basicCostOfDrawCalls =
+        ExpensiveCanvasHeuristicParameters::FillRectFixedCost[index] * m_usageCounters.numDrawCalls[BaseRenderingContext2D::FillRect] +
+        ExpensiveCanvasHeuristicParameters::FillConvexPathFixedCost[index] * (m_usageCounters.numDrawCalls[BaseRenderingContext2D::FillPath] - m_usageCounters.numNonConvexFillPathCalls) +
+        ExpensiveCanvasHeuristicParameters::FillNonConvexPathFixedCost[index] * m_usageCounters.numNonConvexFillPathCalls +
+        ExpensiveCanvasHeuristicParameters::FillTextFixedCost[index] * m_usageCounters.numDrawCalls[BaseRenderingContext2D::FillText] +
+
+        ExpensiveCanvasHeuristicParameters::StrokeRectFixedCost[index] * m_usageCounters.numDrawCalls[BaseRenderingContext2D::StrokeRect] +
+        ExpensiveCanvasHeuristicParameters::StrokePathFixedCost[index] * m_usageCounters.numDrawCalls[BaseRenderingContext2D::StrokePath] +
+        ExpensiveCanvasHeuristicParameters::StrokeTextFixedCost[index] * m_usageCounters.numDrawCalls[BaseRenderingContext2D::StrokeText] +
+
+        ExpensiveCanvasHeuristicParameters::FillRectVariableCostPerArea[index] * m_usageCounters.boundingBoxAreaDrawCalls[BaseRenderingContext2D::FillRect] +
+        ExpensiveCanvasHeuristicParameters::FillConvexPathVariableCostPerArea[index] * (m_usageCounters.boundingBoxAreaDrawCalls[BaseRenderingContext2D::FillPath] - m_usageCounters.nonConvexFillPathArea) +
+        ExpensiveCanvasHeuristicParameters::FillNonConvexPathVariableCostPerArea[index] * m_usageCounters.nonConvexFillPathArea +
+        ExpensiveCanvasHeuristicParameters::FillTextVariableCostPerArea[index] * m_usageCounters.boundingBoxAreaDrawCalls[BaseRenderingContext2D::FillText] +
+
+        ExpensiveCanvasHeuristicParameters::StrokeRectVariableCostPerArea[index] * m_usageCounters.boundingBoxAreaDrawCalls[BaseRenderingContext2D::StrokeRect] +
+        ExpensiveCanvasHeuristicParameters::StrokePathVariableCostPerArea[index] * m_usageCounters.boundingBoxAreaDrawCalls[BaseRenderingContext2D::StrokePath] +
+        ExpensiveCanvasHeuristicParameters::StrokeTextVariableCostPerArea[index] * m_usageCounters.boundingBoxAreaDrawCalls[BaseRenderingContext2D::StrokeText] +
+
+        ExpensiveCanvasHeuristicParameters::PutImageDataFixedCost[index] * m_usageCounters.numPutImageDataCalls +
+        ExpensiveCanvasHeuristicParameters::PutImageDataVariableCostPerArea[index] * m_usageCounters.areaPutImageDataCalls +
+
+        ExpensiveCanvasHeuristicParameters::DrawSVGImageFixedCost[index] * m_usageCounters.numDrawCalls[BaseRenderingContext2D::DrawVectorImage] +
+        ExpensiveCanvasHeuristicParameters::DrawPNGImageFixedCost[index] * m_usageCounters.numDrawCalls[BaseRenderingContext2D::DrawBitmapImage] +
+
+        ExpensiveCanvasHeuristicParameters::DrawSVGImageVariableCostPerArea[index] * m_usageCounters.boundingBoxAreaDrawCalls[BaseRenderingContext2D::DrawVectorImage] +
+        ExpensiveCanvasHeuristicParameters::DrawPNGImageVariableCostPerArea[index] * m_usageCounters.boundingBoxAreaDrawCalls[BaseRenderingContext2D::DrawBitmapImage];
+
+    float fillTypeAdjustment =
+        ExpensiveCanvasHeuristicParameters::PatternFillTypeFixedCost[index] * m_usageCounters.numPatterns +
+        ExpensiveCanvasHeuristicParameters::LinearGradientFillTypeFixedCost[index] * m_usageCounters.numLinearGradients +
+        ExpensiveCanvasHeuristicParameters::RadialGradientFillTypeFixedCost[index] * m_usageCounters.numRadialGradients +
+
+        ExpensiveCanvasHeuristicParameters::PatternFillTypeVariableCostPerArea[index] * m_usageCounters.boundingBoxAreaFillType[BaseRenderingContext2D::PatternFillType] +
+        ExpensiveCanvasHeuristicParameters::LinearGradientFillVariableCostPerArea[index] * m_usageCounters.boundingBoxAreaFillType[BaseRenderingContext2D::LinearGradientFillType] +
+        ExpensiveCanvasHeuristicParameters::RadialGradientFillVariableCostPerArea[index] * m_usageCounters.boundingBoxAreaFillType[BaseRenderingContext2D::RadialGradientFillType];
+
+    float shadowAdjustment =
+        ExpensiveCanvasHeuristicParameters::ShadowFixedCost[index] * m_usageCounters.numBlurredShadows +
+        ExpensiveCanvasHeuristicParameters::ShadowVariableCostPerAreaTimesShadowBlurSquared[index] * m_usageCounters.boundingBoxAreaTimesShadowBlurSquared;
+
+    return basicCostOfDrawCalls + fillTypeAdjustment + shadowAdjustment;
+}
+
 } // namespace blink
diff --git a/third_party/WebKit/Source/modules/canvas2d/BaseRenderingContext2D.h b/third_party/WebKit/Source/modules/canvas2d/BaseRenderingContext2D.h
index 9638d7e..10ce134 100644
--- a/third_party/WebKit/Source/modules/canvas2d/BaseRenderingContext2D.h
+++ b/third_party/WebKit/Source/modules/canvas2d/BaseRenderingContext2D.h
@@ -13,6 +13,7 @@
 #include "modules/canvas2d/CanvasPathMethods.h"
 #include "modules/canvas2d/CanvasRenderingContext2DState.h"
 #include "modules/canvas2d/CanvasStyle.h"
+#include "platform/graphics/ExpensiveCanvasHeuristicParameters.h"
 #include "third_party/skia/include/core/SkCanvas.h"
 
 namespace blink {
@@ -165,7 +166,8 @@
     enum DrawCallType {
         StrokePath = 0,
         FillPath,
-        DrawImage,
+        DrawVectorImage,
+        DrawBitmapImage,
         FillText,
         StrokeText,
         FillRect,
@@ -183,21 +185,23 @@
 
     struct UsageCounters {
         int numDrawCalls[DrawCallTypeCount]; // use DrawCallType enum as index
-        double boundingBoxPerimeterDrawCalls[DrawCallTypeCount];
-        double boundingBoxAreaDrawCalls[DrawCallTypeCount];
-        double boundingBoxAreaFillType[PathFillTypeCount];
+        float boundingBoxPerimeterDrawCalls[DrawCallTypeCount];
+        float boundingBoxAreaDrawCalls[DrawCallTypeCount];
+        float boundingBoxAreaFillType[PathFillTypeCount];
         int numNonConvexFillPathCalls;
-        int numGradients;
+        float nonConvexFillPathArea;
+        int numRadialGradients;
+        int numLinearGradients;
         int numPatterns;
         int numDrawWithComplexClips;
         int numBlurredShadows;
-        double boundingBoxAreaTimesShadowBlurSquared;
-        double boundingBoxPerimeterTimesShadowBlurSquared;
+        float boundingBoxAreaTimesShadowBlurSquared;
+        float boundingBoxPerimeterTimesShadowBlurSquared;
         int numFilters;
         int numGetImageDataCalls;
-        double areaGetImageDataCalls;
+        float areaGetImageDataCalls;
         int numPutImageDataCalls;
-        double areaPutImageDataCalls;
+        float areaPutImageDataCalls;
         int numClearRectCalls;
         int numDrawFocusCalls;
         int numFramesSinceReset;
@@ -235,6 +239,8 @@
 
     mutable UsageCounters m_usageCounters;
 
+
+    float estimateRenderingCost(ExpensiveCanvasHeuristicParameters::RenderingModeCostIndex) const;
 private:
     void realizeSaves();
 
diff --git a/third_party/WebKit/Source/modules/canvas2d/CanvasRenderingContext2D.cpp b/third_party/WebKit/Source/modules/canvas2d/CanvasRenderingContext2D.cpp
index 65195a0..fac95df 100644
--- a/third_party/WebKit/Source/modules/canvas2d/CanvasRenderingContext2D.cpp
+++ b/third_party/WebKit/Source/modules/canvas2d/CanvasRenderingContext2D.cpp
@@ -1070,28 +1070,20 @@
 
 bool CanvasRenderingContext2D::isAccelerationOptimalForCanvasContent() const
 {
-    // Simple heuristic to determine if the GPU accelerated pipeline should be
-    // used to maximize performance of 2D canvas based on past usage.
+    // Heuristic to determine if the GPU accelerated rendering pipeline is optimal
+    // for performance based on past usage. It has a bias towards suggesting that the
+    // accelerated pipeline is optimal.
 
-    int numDrawPathCalls =
-        m_usageCounters.numDrawCalls[StrokePath] +
-        m_usageCounters.numDrawCalls[FillPath] +
-        m_usageCounters.numDrawCalls[FillText] +
-        m_usageCounters.numDrawCalls[StrokeText] +
-        m_usageCounters.numDrawCalls[FillRect] +
-        m_usageCounters.numDrawCalls[StrokeRect];
+    float acceleratedCost = estimateRenderingCost(ExpensiveCanvasHeuristicParameters::AcceleratedModeIndex);
 
-    double acceleratedCost =
-        numDrawPathCalls * ExpensiveCanvasHeuristicParameters::AcceleratedDrawPathApproximateCost +
-        m_usageCounters.numGetImageDataCalls * ExpensiveCanvasHeuristicParameters::AcceleratedGetImageDataApproximateCost+
-        m_usageCounters.numDrawCalls[DrawImage] * ExpensiveCanvasHeuristicParameters::AcceleratedDrawImageApproximateCost;
+    float recordingCost = estimateRenderingCost(ExpensiveCanvasHeuristicParameters::RecordingModeIndex);
 
-    double recordingCost =
-        numDrawPathCalls * ExpensiveCanvasHeuristicParameters::RecordingDrawPathApproximateCost +
-        m_usageCounters.numGetImageDataCalls * ExpensiveCanvasHeuristicParameters::UnacceleratedGetImageDataApproximateCost +
-        m_usageCounters.numDrawCalls[DrawImage] * ExpensiveCanvasHeuristicParameters::RecordingDrawImageApproximateCost;
+    float costDifference = acceleratedCost - recordingCost;
+    float percentCostReduction = costDifference / acceleratedCost * 100.0;
+    float costDifferencePerFrame = costDifference / m_usageCounters.numFramesSinceReset;
 
-    if (recordingCost * ExpensiveCanvasHeuristicParameters::AcceleratedHeuristicBias < acceleratedCost) {
+    if (percentCostReduction >= ExpensiveCanvasHeuristicParameters::MinPercentageImprovementToSuggestDisableAcceleration
+        && costDifferencePerFrame >= ExpensiveCanvasHeuristicParameters::MinCostPerFrameImprovementToSuggestDisableAcceleration) {
         return false;
     }
     return true;
diff --git a/third_party/WebKit/Source/modules/canvas2d/CanvasRenderingContext2DTest.cpp b/third_party/WebKit/Source/modules/canvas2d/CanvasRenderingContext2DTest.cpp
index 3f4c464..d7c01fbc 100644
--- a/third_party/WebKit/Source/modules/canvas2d/CanvasRenderingContext2DTest.cpp
+++ b/third_party/WebKit/Source/modules/canvas2d/CanvasRenderingContext2DTest.cpp
@@ -814,14 +814,21 @@
     EXPECT_TRUE(context->isAccelerationOptimalForCanvasContent());
 
     context->fillRect(10, 10, 100, 100);
-    EXPECT_FALSE(context->isAccelerationOptimalForCanvasContent());
-
-    context->drawImage(canvasElement().getExecutionContext(), &m_opaqueBitmap, 0, 0, 1, 1, 0, 0, 10, 10, exceptionState);
     EXPECT_TRUE(context->isAccelerationOptimalForCanvasContent());
 
     int numReps = 100;
     for (int i = 0; i < numReps; i++) {
-        context->fillRect(10, 10, 100, 100);
+        context->fillText("Text", 10, 10, 1); // faster with no acceleration
+    }
+    EXPECT_FALSE(context->isAccelerationOptimalForCanvasContent());
+
+    for (int i = 0; i < numReps; i++) {
+        context->fillRect(10, 10, 200, 200); // faster with acceleration
+    }
+    EXPECT_TRUE(context->isAccelerationOptimalForCanvasContent());
+
+    for (int i = 0; i < numReps * 100; i++) {
+        context->strokeText("Text", 10, 10, 1); // faster with no acceleration
     }
     EXPECT_FALSE(context->isAccelerationOptimalForCanvasContent());
 }
diff --git a/third_party/WebKit/Source/modules/canvas2d/CanvasRenderingContext2DUsageTrackingTest.cpp b/third_party/WebKit/Source/modules/canvas2d/CanvasRenderingContext2DUsageTrackingTest.cpp
index 8087727b..08934b2b 100644
--- a/third_party/WebKit/Source/modules/canvas2d/CanvasRenderingContext2DUsageTrackingTest.cpp
+++ b/third_party/WebKit/Source/modules/canvas2d/CanvasRenderingContext2DUsageTrackingTest.cpp
@@ -18,6 +18,7 @@
 #include "modules/canvas2d/CanvasPattern.h"
 #include "modules/canvas2d/HitRegionOptions.h"
 #include "modules/webgl/WebGLRenderingContext.h"
+#include "platform/RuntimeEnabledFeatures.h"
 #include "platform/graphics/StaticBitmapImage.h"
 #include "platform/graphics/UnacceleratedImageBufferSurface.h"
 #include "testing/gmock/include/gmock/gmock.h"
@@ -134,6 +135,8 @@
     m_fullImageData = ImageData::create(IntSize(10, 10));
 
     m_globalMemoryCache = replaceMemoryCacheForTesting(MemoryCache::create());
+
+    RuntimeEnabledFeatures::setEnableCanvas2dDynamicRenderingModeSwitchingEnabled(true);
 }
 
 TEST_F(CanvasRenderingContextUsageTrackingTest, FillTracking)
@@ -190,14 +193,15 @@
     gradient = context2d()->createLinearGradient(0, 0, 100, 100);
     context2d()->setFillStyle(StringOrCanvasGradientOrCanvasPattern::fromCanvasGradient(gradient));
     context2d()->fillRect(10, 10, 100, 20);
-    EXPECT_EQ(1, context2d()->getUsage().numGradients);
+    EXPECT_EQ(1, context2d()->getUsage().numLinearGradients);
     EXPECT_NEAR(100 * 20, context2d()->getUsage().boundingBoxAreaFillType[BaseRenderingContext2D::LinearGradientFillType], 1.0);
 
     NonThrowableExceptionState exceptionState;
     gradient = context2d()->createRadialGradient(0, 0, 100, 100, 200, 200, exceptionState);
     context2d()->setFillStyle(StringOrCanvasGradientOrCanvasPattern::fromCanvasGradient(gradient));
     context2d()->fillRect(10, 10, 100, 20);
-    EXPECT_EQ(2, context2d()->getUsage().numGradients);
+    EXPECT_EQ(1, context2d()->getUsage().numLinearGradients);
+    EXPECT_EQ(1, context2d()->getUsage().numRadialGradients);
     EXPECT_NEAR(100 * 20, context2d()->getUsage().boundingBoxAreaFillType[BaseRenderingContext2D::RadialGradientFillType], 1.0);
 
     // create pattern
@@ -217,7 +221,8 @@
     EXPECT_EQ(0, context2d()->getUsage().numDrawCalls[BaseRenderingContext2D::StrokePath]);
     EXPECT_EQ(0, context2d()->getUsage().numDrawCalls[BaseRenderingContext2D::StrokeText]);
     EXPECT_EQ(0, context2d()->getUsage().numPutImageDataCalls);
-    EXPECT_EQ(0, context2d()->getUsage().numDrawCalls[BaseRenderingContext2D::DrawImage]);
+    EXPECT_EQ(0, context2d()->getUsage().numDrawCalls[BaseRenderingContext2D::DrawVectorImage]);
+    EXPECT_EQ(0, context2d()->getUsage().numDrawCalls[BaseRenderingContext2D::DrawBitmapImage]);
     EXPECT_EQ(0, context2d()->getUsage().numGetImageDataCalls);
 }
 
@@ -257,7 +262,7 @@
     gradient = context2d()->createLinearGradient(0, 0, 100, 100);
     context2d()->setStrokeStyle(StringOrCanvasGradientOrCanvasPattern::fromCanvasGradient(gradient));
     context2d()->strokeRect(10, 10, 100, 100);
-    EXPECT_EQ(1, context2d()->getUsage().numGradients);
+    EXPECT_EQ(1, context2d()->getUsage().numLinearGradients);
     EXPECT_NEAR(100 * 100, context2d()->getUsage().boundingBoxAreaFillType[BaseRenderingContext2D::LinearGradientFillType], 1.0);
 
     // create pattern
@@ -277,7 +282,8 @@
     EXPECT_EQ(0, context2d()->getUsage().numNonConvexFillPathCalls);
     EXPECT_EQ(0, context2d()->getUsage().numDrawCalls[BaseRenderingContext2D::FillText]);
     EXPECT_EQ(0, context2d()->getUsage().numPutImageDataCalls);
-    EXPECT_EQ(0, context2d()->getUsage().numDrawCalls[BaseRenderingContext2D::DrawImage]);
+    EXPECT_EQ(0, context2d()->getUsage().numDrawCalls[BaseRenderingContext2D::DrawVectorImage]);
+    EXPECT_EQ(0, context2d()->getUsage().numDrawCalls[BaseRenderingContext2D::DrawBitmapImage]);
     EXPECT_EQ(0, context2d()->getUsage().numGetImageDataCalls);
 }
 
@@ -296,8 +302,11 @@
         context2d()->getImageData(0, 0, 10, 100, exceptionState);
     }
 
-    EXPECT_NEAR(numReps * imgWidth * imgHeight, context2d()->getUsage().boundingBoxAreaDrawCalls[BaseRenderingContext2D::DrawImage], 0.1);
-    EXPECT_NEAR(numReps * (2*imgWidth + 2*imgHeight), context2d()->getUsage().boundingBoxPerimeterDrawCalls[BaseRenderingContext2D::DrawImage], 0.1);
+    EXPECT_NEAR(numReps * imgWidth * imgHeight, context2d()->getUsage().boundingBoxAreaDrawCalls[BaseRenderingContext2D::DrawBitmapImage], 0.1);
+    EXPECT_NEAR(numReps * (2*imgWidth + 2*imgHeight), context2d()->getUsage().boundingBoxPerimeterDrawCalls[BaseRenderingContext2D::DrawBitmapImage], 0.1);
+
+    EXPECT_NEAR(0.0, context2d()->getUsage().boundingBoxAreaDrawCalls[BaseRenderingContext2D::DrawVectorImage], 0.1);
+    EXPECT_NEAR(0.0, context2d()->getUsage().boundingBoxPerimeterDrawCalls[BaseRenderingContext2D::DrawVectorImage], 0.1);
 
     context2d()->setFilter("blur(5px)");
     context2d()->drawImage(canvasElement().getExecutionContext(), &m_opaqueBitmap, 0, 0, 1, 1, 0, 0, 10, 10, exceptionState);
@@ -306,7 +315,7 @@
     EXPECT_NE(0, context2d()->getUsage().areaPutImageDataCalls);
     EXPECT_NEAR(numReps * m_fullImageData.get()->width() * m_fullImageData.get()->height(), context2d()->getUsage().areaPutImageDataCalls, 0.1);
 
-    EXPECT_EQ(numReps + 1, context2d()->getUsage().numDrawCalls[BaseRenderingContext2D::DrawImage]);
+    EXPECT_EQ(numReps + 1, context2d()->getUsage().numDrawCalls[BaseRenderingContext2D::DrawBitmapImage]);
     EXPECT_EQ(numReps, context2d()->getUsage().numGetImageDataCalls);
 
     EXPECT_EQ(1, context2d()->getUsage().numFilters);
diff --git a/third_party/WebKit/Source/modules/canvas2d/tools/GeneratePerformanceData.html b/third_party/WebKit/Source/modules/canvas2d/tools/GeneratePerformanceData.html
new file mode 100644
index 0000000..0d075b7
--- /dev/null
+++ b/third_party/WebKit/Source/modules/canvas2d/tools/GeneratePerformanceData.html
@@ -0,0 +1,59 @@
+<!DOCTYPE html>
+<html>
+<head></head>
+<body>
+<table>
+<tr>
+  <td>
+    <canvas id="canvas" width="1000" height="800">
+  </td>
+</tr>
+<tr>
+  <td>
+    <div id="fps_div"> </div>
+  </td>
+</tr>
+<tr>
+  <td> ------------------------------------------------------------------------------- <br>
+    CSV String: <br>
+    <textarea id="csv_string" rows="1" cols="50"></textarea>
+  </td>
+</tr>
+</table>
+
+<img src="../../../../../../tools/perf/page_sets/tough_canvas_cases/rendering_throughput/images/Chromium_11_Logo.svg" style="display: none;" id="svg_image_element"/>
+<img src="../../../../../../tools/perf/page_sets/tough_canvas_cases/many_images/images/image1_t.png" style="display: none;" id="png_image_element"/>
+
+<script type="text/javascript" src="bench.js"></script>
+<script type="text/javascript" src="GeneratePerformanceData.js"></script>
+<script type="text/javascript">
+window.onload = init;
+
+var canvas;
+var context;
+
+function init() {
+  canvas = document.getElementById('canvas');
+  context = canvas.getContext('2d');
+
+  list_of_frame_parameters = [];
+  list_of_frame_parameters = list_of_frame_parameters.concat(generatePathFrameParameters());
+  list_of_frame_parameters = list_of_frame_parameters.concat(generateImageFrameParameters());
+  list_of_frame_parameters = list_of_frame_parameters.concat(generatePutDataFrameParameters(context));
+
+  // The frames where get data is called should be measured last because rendering mode may switch automatically
+  list_of_frame_parameters = list_of_frame_parameters.concat(generateGetDataFrameParameters(context));
+
+  console.log("list_of_frame_parameters.length = " + list_of_frame_parameters.length);
+
+  bench.run(draw);
+}
+
+function draw() {
+  context.clearRect(0, 0, 1000, 800);
+
+  drawAndRecord(context);
+};
+
+</script>
+</body>
diff --git a/third_party/WebKit/Source/modules/canvas2d/tools/GeneratePerformanceData.js b/third_party/WebKit/Source/modules/canvas2d/tools/GeneratePerformanceData.js
new file mode 100644
index 0000000..7cf2a25
--- /dev/null
+++ b/third_party/WebKit/Source/modules/canvas2d/tools/GeneratePerformanceData.js
@@ -0,0 +1,647 @@
+// 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.
+
+// ==========//
+// Constants //
+// ==========//
+
+var CALL_TYPE = {
+  PATH : "PATH",
+  IMAGE : "IMAGE",
+  GET_DATA : "GET_DATA",
+  PUT_DATA : "PUT_DATA"
+}
+
+var SHAPE_TYPE = {
+  STROKE_PATH : "STROKE_PATH",
+  FILL_CONVEX_PATH : "FILL_CONVEX_PATH",
+  FILL_NON_CONVEX_PATH : "FILL_NON_CONVEX_PATH",
+  STROKE_RECT : "STROKE_RECT",
+  FILL_RECT : "FILL_RECT",
+  STROKE_TEXT : "STROKE_TEXT",
+  FILL_TEXT : "FILL_TEXT"
+}
+
+var SHAPE_STYLE = {
+    COLOR : "COLOR",
+    LINEAR_GRADIENT : "LINEAR_GRADIENT",
+    RADIAL_GRADIENT: "RADIAL_GRADIENT",
+    PATTERN : "PATTERN"
+}
+
+var IMAGE_TYPE = {
+  DRAW_SVG_IMAGE : "DRAW_SVG_IMAGE",
+  DRAW_PNG_IMAGE : "DRAW_PNG_IMAGE"
+}
+
+var NUMBER_OF_FRAME_PER_ESTIMATE = 3;
+var NUMBER_OF_BLANK_FRAMES_BETWEEN_MEASUREMENTS = 5;
+
+// The max frames per second (fps) should be less than 60 because the rendering
+// speed should be the limiting factor, not screen refresh rate.
+var MAX_FRAMES_PER_SECOND_FOR_MEASUREMENTS = 30;
+var MIN_FRAMES_PER_SECOND_FOR_MEASUREMENTS = 10;
+var TARGET_FPS = 20;
+var TARGET_TPF = 1000 / TARGET_FPS;
+
+// ================//
+// State Variables //
+// ================//
+
+var recording_helper = new RecordingHelper();
+recording_helper.restartRecordingTime();
+
+// list of list of DrawParameter's to describe the each frame to draw
+var list_of_frame_parameters = [];
+
+ // list of PerformanceMeasurement
+var performance_measurements = [];
+
+var frame_index = 0;
+var blank_counter = 0;
+
+// =============================//
+// Main rendering loop function //
+// =============================//
+
+function drawAndRecord(context) {
+  if (frame_index >= list_of_frame_parameters.length) return;
+
+  if (blank_counter > 0) {
+    recording_helper.restartRecordingTime();
+    blank_counter--;
+    return;
+  }
+
+  var newMeasurement = false;
+  if (blank_counter < 0) {
+    if (frame_index == 0
+        && recording_helper.getNumberOfFramesRecorded() == 0) {
+      newMeasurement = true;
+    } else {
+      var tpf = recording_helper.getAverageTimePerFrame();
+      var fps = recording_helper.getAverageFramesPerSecond();
+
+      if (fps > MAX_FRAMES_PER_SECOND_FOR_MEASUREMENTS) {
+        // too fast, increase quantity and try again
+        var new_quantity = quantityForTarget(
+          list_of_frame_parameters[frame_index][0].quantity,
+          tpf, TARGET_TPF);
+
+        list_of_frame_parameters[frame_index][0].quantity = new_quantity;
+
+        // reset total bounding box area values
+        for (var i = 0; i<list_of_frame_parameters[frame_index].length; i++) {
+          list_of_frame_parameters[frame_index][i].resetBoundingBoxArea();
+        }
+
+        newMeasurement = true;
+
+      } else if (fps < MIN_FRAMES_PER_SECOND_FOR_MEASUREMENTS) {
+        // too slow, move on to the next measurement
+        console.log("Too slow - moving on to next measurement.");
+        frame_index++;
+        newMeasurement = true;
+      }
+
+      if (recording_helper.getNumberOfFramesRecorded() >=
+          NUMBER_OF_FRAME_PER_ESTIMATE && newMeasurement == false) {
+        if (fps < MAX_FRAMES_PER_SECOND_FOR_MEASUREMENTS) {
+          // Redering speed, not refresh rate is the limiting factor
+          console.log("Recording: frame_index = " +
+                      frame_index + ",\n\ttfp = "+ tpf +
+                      "\n\tfps = " + fps);
+
+          performance_measurements.push(
+              new PerformanceMeasurement(
+                tpf, fps,
+                list_of_frame_parameters[frame_index]));
+
+        }
+
+        frame_index++;
+        newMeasurement = true;
+      }
+    }
+
+    if (newMeasurement) {
+      recording_helper.restartRecordingTime();
+      blank_counter = NUMBER_OF_BLANK_FRAMES_BETWEEN_MEASUREMENTS;
+      if (frame_index >= list_of_frame_parameters.length) {
+        console.log(performance_measurements);
+        drawCSVString(getCSVString(performance_measurements));
+        return;
+      }
+    }
+  }
+
+  if (blank_counter == 0) {
+    recording_helper.restartRecordingTime();
+    blank_counter--;
+  }
+
+  DrawParameters(context, list_of_frame_parameters[frame_index]);
+  recording_helper.recordFrame();
+}
+
+// =====================//
+// Data storage classes //
+// =====================//
+
+function DrawSize(width, height) {
+    this.width = Math.round(width);
+    this.height = Math.round(height);
+}
+
+function DrawParameter(
+  call_type, draw_sub_type, size, shadow_blur, quantity, fill_style) {
+    this.call_type = call_type; // path, image, put or get image data
+    this.draw_sub_type = draw_sub_type; // image type or path type
+    this.fill_style = fill_style; // for paths only
+    this.shadow_blur = shadow_blur;
+
+    // Target size of side of square bounding box. Actuall size can differ.
+    // total_bounding_box_area is returned by draw call and represents actuall
+    // area of the call.
+    this.size = size;
+
+    this.total_bounding_box_area = 0; // computed elsewhere
+    this.total_shadow_bounding_box_area = 0; // computed elsewhere
+    this.total_bounding_box_perimeter = 0; // computed elsewhere
+
+    this.resetBoundingBoxArea = function() {
+      this.total_bounding_box_area = 0;
+      this.total_shadow_bounding_box_area = 0;
+      this.total_bounding_box_perimeter = 0;
+    }
+
+    this.quantity = quantity;
+}
+
+function PerformanceMeasurement(tpf, fps, parameters) {
+    this.tpf = tpf; // time per frame
+    this.fps = fps; // frames per second
+    this.parameters = parameters; // DrawParameter object
+}
+
+// ===========================================================//
+// Utility functions for generating lists of frame parameters //
+// ===========================================================//
+
+function generatePathFrameParameters() {
+  var path_sizes = [20, 50, 200, 300, 400];
+  var quantities = [10, 20, 50, 100, 500, 1000, 2000];
+  var shadow_blurs = [0, 1, 10, 20];
+
+  // Only draw combinations that contain shadows with this probability
+  // to reduce the number of permutations.
+  var shadowedPermutationProbability = 0.1;
+
+  var list_of_frame_parameters = [];
+
+  for (shape_type in SHAPE_TYPE) {
+    for (var size_i = 0; size_i < path_sizes.length; size_i++) {
+      for (var qty_i = 0; qty_i < quantities.length; qty_i++) {
+        for (var sh_i = 0; sh_i < shadow_blurs.length; sh_i++) {
+          for (fill_style in SHAPE_STYLE) {
+            if (shadow_blurs[sh_i] == 0
+                || getTrueWithProbability(shadowedPermutationProbability)) {
+
+              list_of_frame_parameters.push([
+                new DrawParameter(CALL_TYPE.PATH, shape_type,
+                                  path_sizes[size_i], shadow_blurs[sh_i],
+                                  quantities[qty_i], fill_style)]);
+            }
+          }
+        }
+      }
+    }
+  }
+  return list_of_frame_parameters;
+}
+
+function generateImageFrameParameters() {
+  var png_image_sizes = [5, 10, 20, 50, 90];
+  var svg_image_sizes = [5, 20, 50, 90, 200, 300];
+
+  var png_quantities = [10, 50, 100, 500, 1000];
+  var svg_quantities = [10, 50, 100, 200, 500];
+  var shadow_blurs = [0, 1, 5, 10];
+
+  // Only draw combinations that contain shadows with this probability
+  // to reduce the number of permutations.
+  var shadowedPermutationProbability = 0.1;
+
+  var list_of_frame_parameters = [];
+
+  for (var size_i = 0; size_i < png_image_sizes.length; size_i++) {
+    for (var qty_i = 0; qty_i < png_quantities.length; qty_i++) {
+      for (var sh_i = 0; sh_i < shadow_blurs.length; sh_i++) {
+        if (shadow_blurs[sh_i] == 0
+            || getTrueWithProbability(shadowedPermutationProbability)) {
+
+          list_of_frame_parameters.push([
+            new DrawParameter(CALL_TYPE.IMAGE,
+                              IMAGE_TYPE.DRAW_PNG_IMAGE,
+                              png_image_sizes[size_i],
+                              shadow_blurs[sh_i],
+                              png_quantities[qty_i], "")]);
+        }
+      }
+    }
+  }
+
+  for (var size_i = 0; size_i < svg_image_sizes.length; size_i++) {
+    for (var qty_i = 0; qty_i < svg_quantities.length; qty_i++) {
+      for (var sh_i = 0; sh_i < shadow_blurs.length; sh_i++) {
+        if (shadow_blurs[sh_i] == 0
+            || getTrueWithProbability(shadowedPermutationProbability)) {
+
+          list_of_frame_parameters.push([
+            new DrawParameter(CALL_TYPE.IMAGE,
+                              IMAGE_TYPE.DRAW_SVG_IMAGE,
+                              svg_image_sizes[size_i],
+                              shadow_blurs[sh_i],
+                              svg_quantities[qty_i], "")]);
+        }
+      }
+    }
+  }
+  return list_of_frame_parameters;
+}
+
+function generatePutDataFrameParameters(context) {
+  var sizes = [20, 50, 100, 200, 300];
+  var quantities = [10, 50, 100, 500, 1000, 2000];
+
+  var list_of_frame_parameters = [];
+
+  for (var size_i = 0; size_i < sizes.length; size_i++) {
+    for (var qty_i = 0; qty_i < quantities.length; qty_i++) {
+      // Call putImageData so it aquires and caches image data of
+      // the correct dimensions
+      putImageData(context, sizes[size_i]);
+
+      list_of_frame_parameters.push([
+        new DrawParameter(CALL_TYPE.PUT_DATA,
+                          "",
+                          sizes[size_i],
+                          0,
+                          quantities[qty_i], "")]);
+    }
+  }
+
+  return list_of_frame_parameters;
+}
+
+function generateGetDataFrameParameters(context) {
+  var sizes = [20, 50, 100, 200, 300];
+  var quantities = [10, 50, 100, 500, 1000, 2000];
+
+  var list_of_frame_parameters = [];
+
+  for (var size_i = 0; size_i < sizes.length; size_i++) {
+    for (var qty_i = 0; qty_i < quantities.length; qty_i++) {
+      list_of_frame_parameters.push([
+        new DrawParameter(CALL_TYPE.GET_DATA,
+                          "",
+                          sizes[size_i],
+                          0,
+                          quantities[qty_i], "")]);
+    }
+  }
+
+  return list_of_frame_parameters;
+}
+
+// Draw each DrawParameter in the parameter_list on the canvas context,
+// updates their total_bounding_box_area, total_bounding_box_perimeter
+// and total_shadow_bounding_box_area fields.
+function DrawParameters(context, parameter_list) {
+  for (var i = 0; i < parameter_list.length; i++) {
+    var p = parameter_list[i];
+    p.resetBoundingBoxArea();
+    for (var count = 0; count < p.quantity; count++) {
+      var draw_size;
+      switch (p.call_type) {
+        case CALL_TYPE.PATH:
+          setShapeStyle(context, p.fill_style);
+          setShadeStyle(context, p.shadow_blur);
+          draw_size = drawShape(context, p.draw_sub_type, p.size);
+        break;
+        case CALL_TYPE.IMAGE:
+          setShadeStyle(context, p.shadow_blur);
+          draw_size = drawImageType(context, p.draw_sub_type, p.size);
+        break;
+        case CALL_TYPE.GET_DATA:
+          draw_size = getImageData(context, p.size);
+        break;
+        case CALL_TYPE.PUT_DATA:
+          draw_size = putImageData(context, p.size);
+        break;
+        default:
+          draw_size = new DrawSize(0, 0);
+      }
+
+      p.total_bounding_box_area +=
+        draw_size.width * draw_size.height;
+
+      p.total_bounding_box_perimeter +=
+        (2*draw_size.width) + (2*draw_size.height);
+
+      if (p.call_type == CALL_TYPE.PATH || p.call_type == CALL_TYPE.IMAGE) {
+        p.total_shadow_bounding_box_area +=
+          (draw_size.width+2*p.shadow_blur) *
+          (draw_size.height+2*p.shadow_blur);
+      }
+    }
+  }
+}
+
+// =======================================================================//
+// Utility functions to make a CSV string that encodes the generated data //
+// =======================================================================//
+
+function getDataFrame(performance_measurements) {
+  var data = {};
+
+  // shadow_blur * total bounding box area
+  data["SHADOW_BLUR_TIMES_AREA"] = [];
+
+  // shadow_blur^2 * total bounding box area
+  data["SHADOW_BLUR_SQUARED_TIMES_AREA"] = [];
+
+  // shadow_blur^2 * total shadow bounding box area
+  data["SHADOW_BLUR_SQUARED_TIMES_SHADOW_AREA"] = [];
+
+  // the number of draw calls that have a shadow
+  data["NUM_SHADOWS"] = [];
+
+  data["CALL_TYPE"] = [];
+
+  for (var i = 0; i < performance_measurements.length; i++) {
+    var performance_measurement = performance_measurements[i];
+    for (var j = 0; j < performance_measurement.parameters.length; j++) {
+      var p = performance_measurement.parameters[j];
+      var call_type = p.call_type + "_" + p.draw_sub_type;
+      var call_type_area = p.call_type + "_" + p.draw_sub_type + "_AREA";
+
+      data[call_type] = [];
+      data[call_type_area] = [];
+
+      if (p.call_type == CALL_TYPE.PATH) {
+        data[p.fill_style] = [];
+        data[p.fill_style + "_AREA"] = [];
+      }
+    }
+  }
+
+  for (var i = 0; i < performance_measurements.length; i++) {
+    var performance_measurement = performance_measurements[i];
+    for (var j = 0; j < performance_measurement.parameters.length; j++) {
+      var p = performance_measurement.parameters[j];
+      for (var key in data) {
+          data[key].push(0);
+      }
+
+      var call_type = p.call_type + "_" + p.draw_sub_type;
+      var call_type_area = p.call_type + "_" + p.draw_sub_type + "_AREA";
+
+      data[call_type][i] += p.quantity;
+
+      data[call_type_area][i] += p.total_bounding_box_area;
+
+      if (p.call_type == CALL_TYPE.PATH) {
+        data[p.fill_style][i] += p.quantity;
+        data[p.fill_style + "_AREA"][i] += p.total_bounding_box_area;
+      }
+
+      if (p.call_type == CALL_TYPE.PATH || p.call_type == CALL_TYPE.IMAGE) {
+        data["NUM_SHADOWS"][i] += (p.shadow_blur > 0.0) ? p.quantity : 0;
+
+        data["SHADOW_BLUR_TIMES_AREA"][i] +=
+          p.total_bounding_box_area * p.shadow_blur;
+
+        data["SHADOW_BLUR_SQUARED_TIMES_AREA"][i] +=
+          p.total_bounding_box_area * p.shadow_blur * p.shadow_blur;
+
+        data["SHADOW_BLUR_SQUARED_TIMES_SHADOW_AREA"][i] +=
+          p.total_shadow_bounding_box_area * p.shadow_blur * p.shadow_blur;
+      }
+
+      data["CALL_TYPE"][i] = p.call_type;
+    }
+  }
+
+  return data;
+}
+
+function getCSVString(performance_measurements) {
+  var csv_string = "";
+
+  var data_frame = getDataFrame(performance_measurements);
+
+  csv_string += "TIME_PER_FRAME, FRAMES_PER_SECOND"
+  for (var key in data_frame) {
+      csv_string += ", " + key;
+  }
+  csv_string += "\n";
+
+  for (var i = 0; i < performance_measurements.length; i++) {
+      var performance_measurement = performance_measurements[i];
+      csv_string += performance_measurement.tpf;
+      csv_string += ", " + performance_measurement.fps;
+
+      for (var key in data_frame) {
+          csv_string +=  ", " + data_frame[key][i];
+      }
+      csv_string += "\n";
+  }
+
+  return csv_string;
+}
+
+function drawCSVString(csv_string) {
+  var div = document.getElementById("csv_string");
+  div.innerHTML = csv_string;
+}
+
+// =========================================================================//
+// Utility functions to set canvas parameters and perform canvas draw calls //
+// =========================================================================//
+
+function drawShape(context, shape_type, size) {
+  context.lineWidth = 3;
+  switch (shape_type) {
+    case SHAPE_TYPE.STROKE_PATH:
+      var radius = size/2;
+      context.beginPath();
+      context.ellipse(400, 400, radius, radius, 0, 0, 2*Math.PI, false);
+      context.stroke();
+      return new DrawSize(size, size);
+
+    case SHAPE_TYPE.FILL_CONVEX_PATH:
+      var radius = size/2;
+      context.beginPath();
+      context.ellipse(400, 400, radius, radius, 0, 0, 2*Math.PI, false);
+      context.fill();
+      return new DrawSize(size, size);
+
+    case SHAPE_TYPE.FILL_NON_CONVEX_PATH:
+      var radius = size/2;
+      context.beginPath();
+      context.lineTo(400, 400);
+      context.arc(400, 400, radius, 0, Math.PI*3/2, false);
+      context.lineTo(this.x, this.y);
+      context.fill();
+      return new DrawSize(size, size);
+
+    case SHAPE_TYPE.STROKE_RECT:
+      context.beginPath();
+      context.rect(100, 100, size, size);
+      context.stroke();
+      return new DrawSize(size, size);
+
+    case SHAPE_TYPE.FILL_RECT:
+      context.beginPath();
+      context.rect(100, 100, size, size);
+      context.fill();
+      return new DrawSize(size, size);
+
+    case SHAPE_TYPE.STROKE_TEXT:
+      context.font = size + "px Georgia";
+      context.strokeText("M", 40, 500);
+      return new DrawSize(context.measureText("M").width, size);
+
+    case SHAPE_TYPE.FILL_TEXT:
+      context.font = size + "px Georgia";
+      context.fillText("M", 40, 500);
+      return new DrawSize(context.measureText("M").width, size);
+
+    default:
+      console.log("Invalid SHAPE_TYPE: " + shape_type);
+      return new DrawSize(0, 0);
+  }
+}
+
+var svg_image = document.getElementById("svg_image_element");
+var png_image = document.getElementById("png_image_element");
+function drawImageType(context, image_type, size) {
+  switch (image_type) {
+    case IMAGE_TYPE.DRAW_SVG_IMAGE:
+      context.drawImage(svg_image, 50, 50, size, size);
+    return new DrawSize(size, size);
+
+    case IMAGE_TYPE.DRAW_PNG_IMAGE:
+      if (size > png_image.width) {
+        throw "In drawImageType (png) - size too big ";
+      }
+      if (size > png_image.height) {
+        throw "In drawImageType (png) - size too big ";
+      }
+      context.drawImage(png_image, 0, 0, size, size, 50, 50, size, size);
+    return new DrawSize(size, size);
+  }
+}
+
+function setShapeStyle(context, shape_style, area) {
+  var gradient = "";
+  switch (shape_style) {
+    case SHAPE_STYLE.LINEAR_GRADIENT:
+      var gradient = context.createLinearGradient(0, 0, 800, 600);
+      gradient.addColorStop(0, "blue");
+      gradient.addColorStop(1, "white");
+      context.fillStyle = gradient;
+      context.strokeStyle = gradient;
+    break;
+    case SHAPE_STYLE.COLOR:
+      context.fillStyle = "blue";
+      context.strokeStyle = "blue";
+    break;
+    case SHAPE_STYLE.RADIAL_GRADIENT:
+      var gradient =
+        context.createRadialGradient(400, 300, 100, 400, 300, 800);
+      gradient.addColorStop(0, "blue");
+      gradient.addColorStop(1, "white");
+      context.fillStyle = gradient;
+      context.strokeStyle = gradient;
+    break;
+    case SHAPE_STYLE.PATTERN:
+      var pattern = context.createPattern(png_image,"repeat");
+      context.fillStyle = pattern;
+      context.strokeStyle = pattern;
+    break;
+    default:
+      console.log("Invalid SHAPE_STYLE: " + shape_style);
+    break;
+  }
+}
+
+function setShadeStyle(context, shadow_blur) {
+  context.shadowBlur = shadow_blur;
+  context.shadowColor= "black";
+}
+
+function getImageData(context, size) {
+  var image = context.getImageData(10,10, size, size);
+  return new DrawSize(size, size);
+}
+
+
+var image_data_cache = {};
+function putImageData(context, size) {
+  if (!(size in image_data_cache)) {
+    // Cache a data source so that subsequent calls with the same size don't
+    // need to generate a new data source of the appropriate size
+    image_data_cache[size] = context.createImageData(size, size);
+  }
+
+  context.putImageData(image_data_cache[size], 10, 10);
+  return new DrawSize(size, size);
+}
+
+// ================//
+// Other utilities //
+// ================//
+
+function RecordingHelper() {
+  this.num_frames_since_restart = 0;
+  this.recording_start_time = Date.now();
+
+  this.restartRecordingTime = function() {
+    this.num_frames_since_restart = 0;
+    this.recording_start_time = Date.now();
+  }
+
+  this.recordFrame = function() {
+    this.num_frames_since_restart += 1;
+  }
+
+  this.getAverageTimePerFrame = function() {
+    var time_interval = Date.now() - this.recording_start_time;
+    return time_interval / this.num_frames_since_restart;
+  }
+
+  this.getAverageFramesPerSecond = function() {
+    return 1000 / this.getAverageTimePerFrame();
+  }
+
+  this.getNumberOfFramesRecorded =  function() {
+    return this.num_frames_since_restart;
+  }
+}
+
+function getTrueWithProbability(probability) {
+  return Math.random() < probability;
+}
+
+// Given the current quantity of a call, the current time per frame and target
+// time per frame, return a suggested quantity that should yield a rendering
+// speed closer to the target time per frame assuming that the time per frame
+// is linearly proportional to the quantity.
+function quantityForTarget(current_quantity, current_tpf, target_tpf) {
+  if (current_quantity <= 0) return 1;
+  return Math.round(current_quantity * target_tpf / current_tpf);
+}
+
diff --git a/third_party/WebKit/Source/modules/canvas2d/tools/README.md b/third_party/WebKit/Source/modules/canvas2d/tools/README.md
new file mode 100644
index 0000000..077eb4d
--- /dev/null
+++ b/third_party/WebKit/Source/modules/canvas2d/tools/README.md
@@ -0,0 +1,17 @@
+Performance Analysis
+===
+
+This directory contains tools that support a data driven approach to improve the 2D canvas graphics rendering performance. They have 2 main purposes:
+1. Improve our understandind of the 2D canvas graphics rendering performance. This better understanding can yield new performance optimization ideas.
+2. Help design and calibrate heuristics to determine the optimal rendering strategies at run time.
+
+Performance Data Generation
+---
+
+GeneratePerformanceData.html measures the graphics rendering performance for a series of frames involving various 2D canvas operations in varying quantities, scales and shadow blur levels, including:
+ - Drawing various types of shapes with multiple different fill types.
+ - Drawing SVG and PNG images.
+ - Calling getImagedata and putImageData.
+
+After recording performance for all the frames, it generates a CSV string that includes the performance (in frames per second and time per frame) and description of every frame measured.
+
diff --git a/third_party/WebKit/Source/modules/canvas2d/tools/bench.js b/third_party/WebKit/Source/modules/canvas2d/tools/bench.js
new file mode 100644
index 0000000..82750f7
--- /dev/null
+++ b/third_party/WebKit/Source/modules/canvas2d/tools/bench.js
@@ -0,0 +1,29 @@
+// 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.
+
+var bench = (function() {
+  var rafFunc;
+  var drawFunc;
+
+  function tick() {
+    drawFunc();
+    rafFunc(tick);
+  };
+
+  function startAnimation() {
+    rafFunc = window.requestAnimationFrame ||
+              window.webkitRequestAnimationFrame ||
+              window.mozRequestAnimationFrame ||
+              window.oRequestAnimationFrame ||
+              window.msRequestAnimationFrame;
+    rafFunc(tick);
+  };
+
+  var bench = {};
+  bench.run = function(df) {
+    drawFunc = df;
+    startAnimation();
+  };
+  return bench;
+})();
diff --git a/third_party/WebKit/Source/modules/device_light/DeviceLightEvent.cpp b/third_party/WebKit/Source/modules/device_light/DeviceLightEvent.cpp
index 2d5ee691..3ec2249 100644
--- a/third_party/WebKit/Source/modules/device_light/DeviceLightEvent.cpp
+++ b/third_party/WebKit/Source/modules/device_light/DeviceLightEvent.cpp
@@ -10,11 +10,6 @@
 {
 }
 
-DeviceLightEvent::DeviceLightEvent()
-    : m_value(std::numeric_limits<double>::infinity())
-{
-}
-
 DeviceLightEvent::DeviceLightEvent(const AtomicString& eventType, double value)
     : Event(eventType, true, false) // The DeviceLightEvent bubbles but is not cancelable.
     , m_value(value)
@@ -34,7 +29,3 @@
 }
 
 } // namespace blink
-
-
-
-
diff --git a/third_party/WebKit/Source/modules/device_light/DeviceLightEvent.h b/third_party/WebKit/Source/modules/device_light/DeviceLightEvent.h
index 3713f99b..d8d1a38c 100644
--- a/third_party/WebKit/Source/modules/device_light/DeviceLightEvent.h
+++ b/third_party/WebKit/Source/modules/device_light/DeviceLightEvent.h
@@ -16,10 +16,6 @@
 public:
     ~DeviceLightEvent() override;
 
-    static DeviceLightEvent* create()
-    {
-        return new DeviceLightEvent;
-    }
     static DeviceLightEvent* create(const AtomicString& eventType, double value)
     {
         return new DeviceLightEvent(eventType, value);
@@ -34,7 +30,6 @@
     const AtomicString& interfaceName() const override;
 
 private:
-    DeviceLightEvent();
     DeviceLightEvent(const AtomicString& eventType, double value);
     DeviceLightEvent(const AtomicString& eventType, const DeviceLightEventInit& initializer);
 
diff --git a/third_party/WebKit/Source/modules/payments/PaymentRequestUpdateEvent.cpp b/third_party/WebKit/Source/modules/payments/PaymentRequestUpdateEvent.cpp
index 6aba81f..d03e5d78 100644
--- a/third_party/WebKit/Source/modules/payments/PaymentRequestUpdateEvent.cpp
+++ b/third_party/WebKit/Source/modules/payments/PaymentRequestUpdateEvent.cpp
@@ -85,11 +85,6 @@
 {
 }
 
-PaymentRequestUpdateEvent* PaymentRequestUpdateEvent::create()
-{
-    return new PaymentRequestUpdateEvent();
-}
-
 PaymentRequestUpdateEvent* PaymentRequestUpdateEvent::create(const AtomicString& type, const PaymentRequestUpdateEventInit& init)
 {
     return new PaymentRequestUpdateEvent(type, init);
@@ -139,12 +134,6 @@
     Event::trace(visitor);
 }
 
-PaymentRequestUpdateEvent::PaymentRequestUpdateEvent()
-    : m_waitForUpdate(false)
-    , m_abortTimer(this, &PaymentRequestUpdateEvent::onTimerFired)
-{
-}
-
 PaymentRequestUpdateEvent::PaymentRequestUpdateEvent(const AtomicString& type, const PaymentRequestUpdateEventInit& init)
     : Event(type, init)
     , m_waitForUpdate(false)
diff --git a/third_party/WebKit/Source/modules/payments/PaymentRequestUpdateEvent.h b/third_party/WebKit/Source/modules/payments/PaymentRequestUpdateEvent.h
index 7fa6894..69162dc 100644
--- a/third_party/WebKit/Source/modules/payments/PaymentRequestUpdateEvent.h
+++ b/third_party/WebKit/Source/modules/payments/PaymentRequestUpdateEvent.h
@@ -25,7 +25,6 @@
 public:
     ~PaymentRequestUpdateEvent() override;
 
-    static PaymentRequestUpdateEvent* create();
     static PaymentRequestUpdateEvent* create(const AtomicString& type, const PaymentRequestUpdateEventInit& = PaymentRequestUpdateEventInit());
 
     void setPaymentDetailsUpdater(PaymentUpdater*);
@@ -37,7 +36,6 @@
     DECLARE_VIRTUAL_TRACE();
 
 private:
-    PaymentRequestUpdateEvent();
     PaymentRequestUpdateEvent(const AtomicString& type, const PaymentRequestUpdateEventInit&);
 
     Member<PaymentUpdater> m_updater;
diff --git a/third_party/WebKit/Source/modules/payments/PaymentRequestUpdateEventTest.cpp b/third_party/WebKit/Source/modules/payments/PaymentRequestUpdateEventTest.cpp
index 5f883aa..fdaa7f8 100644
--- a/third_party/WebKit/Source/modules/payments/PaymentRequestUpdateEventTest.cpp
+++ b/third_party/WebKit/Source/modules/payments/PaymentRequestUpdateEventTest.cpp
@@ -36,7 +36,7 @@
 TEST(PaymentRequestUpdateEventTest, OnUpdatePaymentDetailsCalled)
 {
     V8TestingScope scope;
-    PaymentRequestUpdateEvent* event = PaymentRequestUpdateEvent::create();
+    PaymentRequestUpdateEvent* event = PaymentRequestUpdateEvent::create(EventTypeNames::shippingaddresschange);
     MockPaymentUpdater* updater = new MockPaymentUpdater;
     event->setPaymentDetailsUpdater(updater);
     event->setEventPhase(Event::kCapturingPhase);
@@ -109,7 +109,7 @@
     PaymentRequestMockFunctionScope funcs(scope.getScriptState());
     makePaymentRequestOriginSecure(scope.document());
     PaymentRequest* request = PaymentRequest::create(scope.getScriptState(), buildPaymentMethodDataForTest(), buildPaymentDetailsForTest(), scope.getExceptionState());
-    PaymentRequestUpdateEvent* event = PaymentRequestUpdateEvent::create();
+    PaymentRequestUpdateEvent* event = PaymentRequestUpdateEvent::create(EventTypeNames::shippingaddresschange);
     event->setPaymentDetailsUpdater(request);
     EXPECT_FALSE(scope.getExceptionState().hadException());
 
diff --git a/third_party/WebKit/Source/modules/sensor/SensorErrorEvent.cpp b/third_party/WebKit/Source/modules/sensor/SensorErrorEvent.cpp
index 0348945..d756af6f 100644
--- a/third_party/WebKit/Source/modules/sensor/SensorErrorEvent.cpp
+++ b/third_party/WebKit/Source/modules/sensor/SensorErrorEvent.cpp
@@ -13,11 +13,6 @@
 {
 }
 
-SensorErrorEvent::SensorErrorEvent()
-    : Event(EventTypeNames::error, false, true)
-{
-}
-
 SensorErrorEvent::SensorErrorEvent(const AtomicString& eventType)
     : Event(eventType, true, false) // let default be bubbles but is not cancelable.
 {
diff --git a/third_party/WebKit/Source/modules/sensor/SensorErrorEvent.h b/third_party/WebKit/Source/modules/sensor/SensorErrorEvent.h
index a10a333..0eedcaa 100644
--- a/third_party/WebKit/Source/modules/sensor/SensorErrorEvent.h
+++ b/third_party/WebKit/Source/modules/sensor/SensorErrorEvent.h
@@ -16,11 +16,6 @@
     DEFINE_WRAPPERTYPEINFO();
 
 public:
-    static SensorErrorEvent* create()
-    {
-        return new SensorErrorEvent;
-    }
-
     static SensorErrorEvent* create(const AtomicString& eventType)
     {
         return new SensorErrorEvent(eventType);
@@ -37,7 +32,6 @@
 
     const AtomicString& interfaceName() const override;
 
-    SensorErrorEvent();
     explicit SensorErrorEvent(const AtomicString& eventType);
     SensorErrorEvent(const AtomicString& eventType, const SensorErrorEventInit& initializer);
 
diff --git a/third_party/WebKit/Source/modules/sensor/SensorReadingEvent.cpp b/third_party/WebKit/Source/modules/sensor/SensorReadingEvent.cpp
index 1b90ea6f..911ea906 100644
--- a/third_party/WebKit/Source/modules/sensor/SensorReadingEvent.cpp
+++ b/third_party/WebKit/Source/modules/sensor/SensorReadingEvent.cpp
@@ -10,10 +10,6 @@
 {
 }
 
-SensorReadingEvent::SensorReadingEvent()
-{
-}
-
 SensorReadingEvent::SensorReadingEvent(const AtomicString& eventType)
     : Event(eventType, true, false) // let default be bubbles but is not cancelable.
     , m_reading(SensorReading::create())
diff --git a/third_party/WebKit/Source/modules/sensor/SensorReadingEvent.h b/third_party/WebKit/Source/modules/sensor/SensorReadingEvent.h
index 4616f65..d2c1b44 100644
--- a/third_party/WebKit/Source/modules/sensor/SensorReadingEvent.h
+++ b/third_party/WebKit/Source/modules/sensor/SensorReadingEvent.h
@@ -16,11 +16,6 @@
     DEFINE_WRAPPERTYPEINFO();
 
 public:
-    static SensorReadingEvent* create()
-    {
-        return new SensorReadingEvent;
-    }
-
     static SensorReadingEvent* create(const AtomicString& eventType)
     {
         return new SensorReadingEvent(eventType);
@@ -48,7 +43,6 @@
     Member<SensorReading> m_reading;
 
 private:
-    SensorReadingEvent();
     explicit SensorReadingEvent(const AtomicString& eventType);
     SensorReadingEvent(const AtomicString& eventType, SensorReading&);
     SensorReadingEvent(const AtomicString& eventType, const SensorReadingEventInit& initializer);
diff --git a/third_party/WebKit/Source/modules/serviceworkers/ForeignFetchEvent.cpp b/third_party/WebKit/Source/modules/serviceworkers/ForeignFetchEvent.cpp
index 483be1f..a9b09ef 100644
--- a/third_party/WebKit/Source/modules/serviceworkers/ForeignFetchEvent.cpp
+++ b/third_party/WebKit/Source/modules/serviceworkers/ForeignFetchEvent.cpp
@@ -11,10 +11,6 @@
 #include "wtf/RefPtr.h"
 
 namespace blink {
-ForeignFetchEvent* ForeignFetchEvent::create()
-{
-    return new ForeignFetchEvent();
-}
 
 ForeignFetchEvent* ForeignFetchEvent::create(ScriptState* scriptState, const AtomicString& type, const ForeignFetchEventInit& initializer)
 {
@@ -48,10 +44,6 @@
     return EventNames::ForeignFetchEvent;
 }
 
-ForeignFetchEvent::ForeignFetchEvent()
-{
-}
-
 ForeignFetchEvent::ForeignFetchEvent(ScriptState* scriptState, const AtomicString& type, const ForeignFetchEventInit& initializer, ForeignFetchRespondWithObserver* respondWithObserver, WaitUntilObserver* waitUntilObserver)
     : ExtendableEvent(type, initializer, waitUntilObserver)
     , m_observer(respondWithObserver)
diff --git a/third_party/WebKit/Source/modules/serviceworkers/ForeignFetchEvent.h b/third_party/WebKit/Source/modules/serviceworkers/ForeignFetchEvent.h
index 2e9a2a9..4f7579e 100644
--- a/third_party/WebKit/Source/modules/serviceworkers/ForeignFetchEvent.h
+++ b/third_party/WebKit/Source/modules/serviceworkers/ForeignFetchEvent.h
@@ -26,7 +26,6 @@
 class MODULES_EXPORT ForeignFetchEvent final : public ExtendableEvent {
     DEFINE_WRAPPERTYPEINFO();
 public:
-    static ForeignFetchEvent* create();
     static ForeignFetchEvent* create(ScriptState*, const AtomicString& type, const ForeignFetchEventInit&);
     static ForeignFetchEvent* create(ScriptState*, const AtomicString& type, const ForeignFetchEventInit&, ForeignFetchRespondWithObserver*, WaitUntilObserver*);
 
@@ -40,7 +39,6 @@
     DECLARE_VIRTUAL_TRACE();
 
 protected:
-    ForeignFetchEvent();
     ForeignFetchEvent(ScriptState*, const AtomicString& type, const ForeignFetchEventInit&, ForeignFetchRespondWithObserver*, WaitUntilObserver*);
 
 private:
diff --git a/third_party/WebKit/Source/modules/serviceworkers/InstallEvent.cpp b/third_party/WebKit/Source/modules/serviceworkers/InstallEvent.cpp
index 7c98811..30f6d7a 100644
--- a/third_party/WebKit/Source/modules/serviceworkers/InstallEvent.cpp
+++ b/third_party/WebKit/Source/modules/serviceworkers/InstallEvent.cpp
@@ -10,11 +10,6 @@
 
 namespace blink {
 
-InstallEvent* InstallEvent::create()
-{
-    return new InstallEvent();
-}
-
 InstallEvent* InstallEvent::create(const AtomicString& type, const ExtendableEventInit& eventInit)
 {
     return new InstallEvent(type, eventInit);
@@ -95,10 +90,6 @@
     return EventNames::InstallEvent;
 }
 
-InstallEvent::InstallEvent()
-{
-}
-
 InstallEvent::InstallEvent(const AtomicString& type, const ExtendableEventInit& initializer)
     : ExtendableEvent(type, initializer)
 {
diff --git a/third_party/WebKit/Source/modules/serviceworkers/InstallEvent.h b/third_party/WebKit/Source/modules/serviceworkers/InstallEvent.h
index eb075a7..46982c9 100644
--- a/third_party/WebKit/Source/modules/serviceworkers/InstallEvent.h
+++ b/third_party/WebKit/Source/modules/serviceworkers/InstallEvent.h
@@ -18,7 +18,6 @@
     DEFINE_WRAPPERTYPEINFO();
 
 public:
-    static InstallEvent* create();
     static InstallEvent* create(const AtomicString& type, const ExtendableEventInit&);
     static InstallEvent* create(const AtomicString& type, const ExtendableEventInit&, WaitUntilObserver*);
 
@@ -29,7 +28,6 @@
     const AtomicString& interfaceName() const override;
 
 protected:
-    InstallEvent();
     InstallEvent(const AtomicString& type, const ExtendableEventInit&);
     InstallEvent(const AtomicString& type, const ExtendableEventInit&, WaitUntilObserver*);
 };
diff --git a/third_party/WebKit/Source/platform/graphics/BitmapImageTest.cpp b/third_party/WebKit/Source/platform/graphics/BitmapImageTest.cpp
index 6197aec4..81180b47 100644
--- a/third_party/WebKit/Source/platform/graphics/BitmapImageTest.cpp
+++ b/third_party/WebKit/Source/platform/graphics/BitmapImageTest.cpp
@@ -218,8 +218,6 @@
     EXPECT_FALSE(m_image->hasColorProfile());
 }
 
-#if USE(QCMSLIB)
-
 TEST_F(BitmapImageTest, jpegHasColorProfile)
 {
     loadImage("/LayoutTests/fast/images/resources/icc-v2-gbr.jpg");
@@ -244,8 +242,6 @@
     EXPECT_TRUE(m_image->hasColorProfile());
 }
 
-#endif // USE(QCMSLIB)
-
 TEST_F(BitmapImageTest, icoHasWrongFrameDimensions)
 {
     loadImage("/LayoutTests/fast/images/resources/wrong-frame-dimensions.ico");
diff --git a/third_party/WebKit/Source/platform/graphics/ExpensiveCanvasHeuristicParameters.h b/third_party/WebKit/Source/platform/graphics/ExpensiveCanvasHeuristicParameters.h
index 50a022e..f32dda3d 100644
--- a/third_party/WebKit/Source/platform/graphics/ExpensiveCanvasHeuristicParameters.h
+++ b/third_party/WebKit/Source/platform/graphics/ExpensiveCanvasHeuristicParameters.h
@@ -75,34 +75,65 @@
 
 // Approximate relative costs of different types of operations for the
 // accelerated rendering pipeline and the recording rendering pipeline.
-// These costs were estimated experimentally based on the performance
-// of each pipeline in the animometer benchmark. Multiple factors influence
-// the true cost of each type of operation, including:
-// - The hardware configuration
-// - Version of the project
-// - Additional details about the operation:
-//   - Subtype of operation (png vs svg image, arc vs line...)
-//   - Scale
-//   - Associated effects (patterns, gradients...)
-// The coefficients are equal to 1/n, where n is equal to the number of calls
-// of a type that can be performed in each frame while maintaining
-// 50 frames per second. They were estimated using the animometer benchmark.
+// These costs were estimated experimentally using the tools located in the
+// third_party/WebKit/Source/modules/canvas2d/performance_analysis directory.
 
-const double AcceleratedDrawPathApproximateCost     = 0.004;
-const double AcceleratedGetImageDataApproximateCost = 0.1;
-const double AcceleratedDrawImageApproximateCost    = 0.002;
+// The RenderingModeCostIndex enum is used to access the heuristic coefficients that correspond
+// to a given rendering mode. For exmaple, FillRectFixedCost[RecordingModeIndex] is the estimated
+// fixed cost for FillRect in recording mode.
+enum RenderingModeCostIndex {
+    RecordingModeIndex = 0,
+    AcceleratedModeIndex = 1,
+    NumRederingModesCostIdexes = 2
+};
 
-const double RecordingDrawPathApproximateCost           = 0.0014;
-const double UnacceleratedGetImageDataApproximateCost   = 0.001; // This cost is for non-display-list mode after fallback.
-const double RecordingDrawImageApproximateCost          = 0.004;
+const float FillRectFixedCost[NumRederingModesCostIdexes] = {6.190e-03f, 7.715e-03f};
+const float FillConvexPathFixedCost[NumRederingModesCostIdexes] = {1.251e-02f, 1.231e-02f};
+const float FillNonConvexPathFixedCost[NumRederingModesCostIdexes] = {1.714e-02f, 4.497e-02f};
+const float FillTextFixedCost[NumRederingModesCostIdexes] = {1.119e-02f, 2.203e-02f};
 
-// Coefficient used in the isAccelerationOptimalForCanvasContent
-// heuristic to create a bias in the output.
-// If set to a value greater than 1, it creates a bias towards suggesting acceleration.
-// If set to a value smaller than 1, it creates a bias towards not suggesting acceleration
-// For example, if its value is 1.5, then disabling gpu acceleration will only be suggested if
-// recordingCost * 1.5 < acceleratedCost.
-const double AcceleratedHeuristicBias = 1.5;
+const float StrokeRectFixedCost[NumRederingModesCostIdexes] = {1.485e-02f, 7.287e-03f};
+const float StrokePathFixedCost[NumRederingModesCostIdexes] = {2.390e-02f, 5.125e-02f};
+const float StrokeTextFixedCost[NumRederingModesCostIdexes] = {1.149e-02f, 1.742e-02f};
+
+const float FillRectVariableCostPerArea[NumRederingModesCostIdexes] = {2.933e-07f, 2.188e-09f};
+const float FillConvexPathVariableCostPerArea[NumRederingModesCostIdexes] = {7.871e-07f, 1.608e-07f};
+const float FillNonConvexPathVariableCostPerArea[NumRederingModesCostIdexes] = {8.336e-07f, 1.384e-06f};
+const float FillTextVariableCostPerArea[NumRederingModesCostIdexes] = {1.411e-06f, 0.0f};
+
+const float StrokeRectVariableCostPerArea[NumRederingModesCostIdexes] = {9.882e-07f, 0.0f};
+const float StrokePathVariableCostPerArea[NumRederingModesCostIdexes] = {1.583e-06f, 2.401e-06f};
+const float StrokeTextVariableCostPerArea[NumRederingModesCostIdexes] = {1.530e-06f, 6.699e-07f};
+
+const float PatternFillTypeFixedCost[NumRederingModesCostIdexes] = {1.377e-02f, 1.035e-02f};
+const float LinearGradientFillTypeFixedCost[NumRederingModesCostIdexes] = {7.694e-03f, 6.900e-03f};
+const float RadialGradientFillTypeFixedCost[NumRederingModesCostIdexes] = {2.260e-02f, 7.193e-03f};
+
+const float PatternFillTypeVariableCostPerArea[NumRederingModesCostIdexes] = {6.080e-07f, 0.0f};
+const float LinearGradientFillVariableCostPerArea[NumRederingModesCostIdexes] = {9.635e-07f, 0.0f};
+const float RadialGradientFillVariableCostPerArea[NumRederingModesCostIdexes] = {6.662e-06f, 0.0f};
+
+const float ShadowFixedCost[NumRederingModesCostIdexes] = {2.502e-02f, 2.274e-02f};
+const float ShadowVariableCostPerAreaTimesShadowBlurSquared[NumRederingModesCostIdexes] = {6.856e-09f, 0.0f};
+
+const float PutImageDataFixedCost[NumRederingModesCostIdexes] = {1.209e-03f, 1.885e-02f};
+const float PutImageDataVariableCostPerArea[NumRederingModesCostIdexes] = {6.231e-06f, 4.116e-06f};
+
+const float DrawSVGImageFixedCost[NumRederingModesCostIdexes] = {1.431e-01f, 2.958e-01f};
+const float DrawPNGImageFixedCost[NumRederingModesCostIdexes] = {1.278e-02f, 1.306e-02f};
+
+const float DrawSVGImageVariableCostPerArea[NumRederingModesCostIdexes] = {1.030e-05f, 4.463e-06f};
+const float DrawPNGImageVariableCostPerArea[NumRederingModesCostIdexes] = {1.727e-06f, 0.0f};
+
+// Two conditions must be met before the isAccelerationOptimalForCanvasContent heuristics recommends
+// switching out of the accelerated mode.
+//   1. The difference in estimated cost per frame is larger than MinCostPerFrameImprovementToSuggestDisableAcceleration.
+//      This ensures that the overhead involved in a switch of rendering mode and the risk of making a wrong decision
+//      are justified by a large expected increased performance.
+//   2. The percent reduction in rendering cost is larger than MinPercentageImprovementToSuggestDisableAcceleration.
+//      This ensures that there is a high level of confidence that the performance would be improved in recording mode.
+const float MinCostPerFrameImprovementToSuggestDisableAcceleration = 15.0f;
+const float MinPercentageImprovementToSuggestDisableAcceleration = 30.0f;
 
 // Minimum number of frames that need to be rendered
 // before the rendering pipeline may be switched. Having this set
diff --git a/third_party/WebKit/Source/platform/graphics/paint/GeometryMapper.cpp b/third_party/WebKit/Source/platform/graphics/paint/GeometryMapper.cpp
index d6f1897..63afa759 100644
--- a/third_party/WebKit/Source/platform/graphics/paint/GeometryMapper.cpp
+++ b/third_party/WebKit/Source/platform/graphics/paint/GeometryMapper.cpp
@@ -178,7 +178,7 @@
         if ((*it) != ancestorState.transform) {
             TransformationMatrix localTransformMatrix = (*it)->matrix();
             localTransformMatrix.applyTransformOrigin((*it)->origin());
-            transformMatrix = localTransformMatrix * transformMatrix;
+            transformMatrix =  transformMatrix * localTransformMatrix;
         }
 
         precomputedData.toAncestorTransforms.set(*it, transformMatrix);
diff --git a/third_party/WebKit/Source/platform/graphics/paint/GeometryMapperTest.cpp b/third_party/WebKit/Source/platform/graphics/paint/GeometryMapperTest.cpp
index 6003d402..e78cf293 100644
--- a/third_party/WebKit/Source/platform/graphics/paint/GeometryMapperTest.cpp
+++ b/third_party/WebKit/Source/platform/graphics/paint/GeometryMapperTest.cpp
@@ -162,6 +162,31 @@
     EXPECT_EQ(rotateTransform, getPrecomputedDataForAncestor(rootPropertyTreeState()).toAncestorTransforms.get(transform1.get()));
 }
 
+TEST_F(GeometryMapperTest, NestedTransformsScaleAndTranslation)
+{
+    TransformationMatrix scaleTransform;
+    scaleTransform.scale(2);
+    RefPtr<TransformPaintPropertyNode> transform1 = TransformPaintPropertyNode::create(rootPropertyTreeState().transform, scaleTransform, FloatPoint3D());
+
+    TransformationMatrix translateTransform;
+    translateTransform.translate(100, 0);
+    RefPtr<TransformPaintPropertyNode> transform2 = TransformPaintPropertyNode::create(transform1, translateTransform, FloatPoint3D());
+
+    PropertyTreeState localState = rootPropertyTreeState();
+    localState.transform = transform2.get();
+
+    FloatRect input(0, 0, 100, 100);
+    // Note: unlike NestedTransforms, the order of these transforms matters. This tests correct order of matrix multiplication.
+    TransformationMatrix final = scaleTransform * translateTransform;
+    FloatRect output = final.mapRect(input);
+
+    CHECK_MAPPINGS(input, output, output, final, rootClipNode->clipRect().rect(), localState, rootPropertyTreeState());
+
+    // Check the cached matrix for the intermediate transform.
+    EXPECT_EQ(scaleTransform, getPrecomputedDataForAncestor(rootPropertyTreeState()).toAncestorTransforms.get(transform1.get()));
+}
+
+
 TEST_F(GeometryMapperTest, NestedTransformsIntermediateDestination)
 {
     TransformationMatrix rotateTransform;
diff --git a/third_party/WebKit/Source/platform/graphics/test/MockImageDecoder.h b/third_party/WebKit/Source/platform/graphics/test/MockImageDecoder.h
index f40291e9..99e7518 100644
--- a/third_party/WebKit/Source/platform/graphics/test/MockImageDecoder.h
+++ b/third_party/WebKit/Source/platform/graphics/test/MockImageDecoder.h
@@ -129,7 +129,7 @@
 
     void initializeNewFrame(size_t index) override
     {
-        m_frameBufferCache[index].setSize(size().width(), size().height());
+        m_frameBufferCache[index].setSizeAndColorProfile(size().width(), size().height(), colorProfile());
         m_frameBufferCache[index].setHasAlpha(false);
     }
 
diff --git a/third_party/WebKit/Source/platform/image-decoders/ImageDecoder.cpp b/third_party/WebKit/Source/platform/image-decoders/ImageDecoder.cpp
index 93d5cc8..691e9e4 100644
--- a/third_party/WebKit/Source/platform/image-decoders/ImageDecoder.cpp
+++ b/third_party/WebKit/Source/platform/image-decoders/ImageDecoder.cpp
@@ -294,9 +294,10 @@
     return m_rowBytes[i];
 }
 
-#if USE(QCMSLIB)
 namespace {
 
+#if USE(QCMSLIB)
+
 const unsigned kIccColorProfileHeaderLength = 128;
 
 bool rgbColorProfile(const char* profileData, unsigned profileLength)
@@ -317,11 +318,14 @@
 SpinLock gTargetColorProfileLock;
 qcms_profile* gTargetColorProfile = nullptr;
 
+#endif // USE(QCMSLIB)
+
 } // namespace
 
 // static
 void ImageDecoder::setTargetColorProfile(const WebVector<char>& profile)
 {
+#if USE(QCMSLIB)
     if (profile.isEmpty())
         return;
 
@@ -349,15 +353,18 @@
     }
 
     qcms_profile_precache_output_transform(gTargetColorProfile);
+#endif // USE(QCMSLIB)
 }
 
-bool ImageDecoder::hasColorProfile() const
+void ImageDecoder::setColorProfileAndComputeTransform(const char* iccData, unsigned iccLength, bool hasAlpha, bool useSRGB)
 {
-    return m_sourceToOutputDeviceColorTransform.get();
-}
+    // Sub-classes should not call this if they were instructed to ignore embedded color profiles.
+    DCHECK(!m_ignoreGammaAndColorProfile);
 
-void ImageDecoder::setColorProfileAndTransform(const char* iccData, unsigned iccLength, bool hasAlpha, bool useSRGB)
-{
+    m_colorProfile.assign(iccData, iccLength);
+    m_hasColorProfile = true;
+
+#if USE(QCMSLIB)
     m_sourceToOutputDeviceColorTransform.reset();
 
     // Create the input profile
@@ -396,19 +403,7 @@
 
     // FIXME: Don't force perceptual intent if the image profile contains an intent.
     m_sourceToOutputDeviceColorTransform.reset(qcms_transform_create(inputProfile.get(), dataFormat, gTargetColorProfile, QCMS_DATA_RGBA_8, QCMS_INTENT_PERCEPTUAL));
-}
-
-#else // USE(QCMSLIB)
-
-void ImageDecoder::setTargetColorProfile(const WebVector<char>&)
-{
-}
-
-bool ImageDecoder::hasColorProfile() const
-{
-    return false;
-}
-
 #endif // USE(QCMSLIB)
+}
 
 } // namespace blink
diff --git a/third_party/WebKit/Source/platform/image-decoders/ImageDecoder.h b/third_party/WebKit/Source/platform/image-decoders/ImageDecoder.h
index 0a73a82..a44d261 100644
--- a/third_party/WebKit/Source/platform/image-decoders/ImageDecoder.h
+++ b/third_party/WebKit/Source/platform/image-decoders/ImageDecoder.h
@@ -112,10 +112,7 @@
     ImageDecoder(AlphaOption alphaOption, GammaAndColorProfileOption colorOptions, size_t maxDecodedBytes)
         : m_premultiplyAlpha(alphaOption == AlphaPremultiplied)
         , m_ignoreGammaAndColorProfile(colorOptions == GammaAndColorProfileIgnored)
-        , m_maxDecodedBytes(maxDecodedBytes)
-        , m_sizeAvailable(false)
-        , m_isAllDataReceived(false)
-        , m_failed(false) { }
+        , m_maxDecodedBytes(maxDecodedBytes) { }
 
     virtual ~ImageDecoder() { }
 
@@ -231,14 +228,19 @@
 
     ImageOrientation orientation() const { return m_orientation; }
 
-    void setIgnoreGammaAndColorProfile(bool flag) { m_ignoreGammaAndColorProfile = flag; }
     bool ignoresGammaAndColorProfile() const { return m_ignoreGammaAndColorProfile; }
-
     static void setTargetColorProfile(const WebVector<char>&);
-    bool hasColorProfile() const;
+
+
+    // Note that hasColorProfile refers to the existence of a not-ignored
+    // embedded color profile, and is independent of whether or not that
+    // profile's transform has been baked into the pixel values.
+    bool hasColorProfile() const { return m_hasColorProfile; }
+    void setColorProfileAndComputeTransform(const char* iccData, unsigned iccLength, bool hasAlpha, bool useSRGB);
 
 #if USE(QCMSLIB)
-    void setColorProfileAndTransform(const char* iccData, unsigned iccLength, bool hasAlpha, bool useSRGB);
+    // In contrast with hasColorProfile, this refers to the transform that has
+    // been baked into the pixels.
     qcms_transform* colorTransform() { return m_sourceToOutputDeviceColorTransform.get(); }
 #endif
 
@@ -315,10 +317,13 @@
     // Decodes the requested frame.
     virtual void decode(size_t) = 0;
 
+    // Returns the embedded image color profile.
+    const ImageFrame::ICCProfile& colorProfile() const { return m_colorProfile; }
+
     RefPtr<SegmentReader> m_data; // The encoded data.
     Vector<ImageFrame, 1> m_frameBufferCache;
-    bool m_premultiplyAlpha;
-    bool m_ignoreGammaAndColorProfile;
+    const bool m_premultiplyAlpha;
+    const bool m_ignoreGammaAndColorProfile;
     ImageOrientation m_orientation;
 
     // The maximum amount of memory a decoded image should require. Ideally,
@@ -326,7 +331,7 @@
     // (and then return the downsampled size from decodedSize()). Ignoring
     // this limit can cause excessive memory use or even crashes on low-
     // memory devices.
-    size_t m_maxDecodedBytes;
+    const size_t m_maxDecodedBytes;
 
 private:
     // Some code paths compute the size of the image as "width * height * 4"
@@ -339,9 +344,12 @@
     }
 
     IntSize m_size;
-    bool m_sizeAvailable;
-    bool m_isAllDataReceived;
-    bool m_failed;
+    bool m_sizeAvailable = false;
+    bool m_isAllDataReceived = false;
+    bool m_failed = false;
+
+    bool m_hasColorProfile = false;
+    ImageFrame::ICCProfile m_colorProfile;
 
 #if USE(QCMSLIB)
     QCMSTransformUniquePtr m_sourceToOutputDeviceColorTransform;
diff --git a/third_party/WebKit/Source/platform/image-decoders/ImageFrame.cpp b/third_party/WebKit/Source/platform/image-decoders/ImageFrame.cpp
index 13904396..1803280 100644
--- a/third_party/WebKit/Source/platform/image-decoders/ImageFrame.cpp
+++ b/third_party/WebKit/Source/platform/image-decoders/ImageFrame.cpp
@@ -93,11 +93,14 @@
     return other.m_bitmap.copyTo(&m_bitmap, other.m_bitmap.colorType());
 }
 
-bool ImageFrame::setSize(int newWidth, int newHeight)
+bool ImageFrame::setSizeAndColorProfile(int newWidth, int newHeight, const ICCProfile& newIccProfile)
 {
-    // setSize() should only be called once, it leaks memory otherwise.
+    // setSizeAndColorProfile() should only be called once, it leaks memory otherwise.
     ASSERT(!width() && !height());
 
+    // TODO(ccameron): Populate the color space parameter of the SkImageInfo
+    // with newIccProfile, under a runtime flag.
+
     m_bitmap.setInfo(SkImageInfo::MakeN32(newWidth, newHeight,
         m_premultiplyAlpha ? kPremul_SkAlphaType : kUnpremul_SkAlphaType));
     if (!m_bitmap.tryAllocPixels(m_allocator, 0))
diff --git a/third_party/WebKit/Source/platform/image-decoders/ImageFrame.h b/third_party/WebKit/Source/platform/image-decoders/ImageFrame.h
index 7a51c75..f6e4e8b 100644
--- a/third_party/WebKit/Source/platform/image-decoders/ImageFrame.h
+++ b/third_party/WebKit/Source/platform/image-decoders/ImageFrame.h
@@ -29,6 +29,7 @@
 
 #include "platform/PlatformExport.h"
 #include "platform/geometry/IntRect.h"
+#include "public/platform/WebVector.h"
 #include "third_party/skia/include/core/SkBitmap.h"
 #include "wtf/Allocator.h"
 #include "wtf/Assertions.h"
@@ -70,6 +71,8 @@
     };
     typedef uint32_t PixelData;
 
+    typedef WebVector<char> ICCProfile;
+
     ImageFrame();
 
     // The assignment operator reads m_hasAlpha (inside setStatus()) before it
@@ -111,7 +114,7 @@
     // Allocates space for the pixel data.  Must be called before any pixels
     // are written.  Must only be called once.  Returns whether allocation
     // succeeded.
-    bool setSize(int newWidth, int newHeight);
+    bool setSizeAndColorProfile(int newWidth, int newHeight, const ICCProfile& newIccProfile);
 
     bool hasAlpha() const;
     const IntRect& originalFrameRect() const { return m_originalFrameRect; }
diff --git a/third_party/WebKit/Source/platform/image-decoders/bmp/BMPImageReader.cpp b/third_party/WebKit/Source/platform/image-decoders/bmp/BMPImageReader.cpp
index 3f48117..0ee27a6c 100644
--- a/third_party/WebKit/Source/platform/image-decoders/bmp/BMPImageReader.cpp
+++ b/third_party/WebKit/Source/platform/image-decoders/bmp/BMPImageReader.cpp
@@ -119,7 +119,7 @@
     // Initialize the framebuffer if needed.
     ASSERT(m_buffer);  // Parent should set this before asking us to decode!
     if (m_buffer->getStatus() == ImageFrame::FrameEmpty) {
-        if (!m_buffer->setSize(m_parent->size().width(), m_parent->size().height()))
+        if (!m_buffer->setSizeAndColorProfile(m_parent->size().width(), m_parent->size().height(), ImageFrame::ICCProfile()))
             return m_parent->setFailed(); // Unable to allocate.
         m_buffer->setStatus(ImageFrame::FramePartial);
         // setSize() calls eraseARGB(), which resets the alpha flag, so we force
diff --git a/third_party/WebKit/Source/platform/image-decoders/gif/GIFImageDecoder.cpp b/third_party/WebKit/Source/platform/image-decoders/gif/GIFImageDecoder.cpp
index 72f2c834..a769b6d0 100644
--- a/third_party/WebKit/Source/platform/image-decoders/gif/GIFImageDecoder.cpp
+++ b/third_party/WebKit/Source/platform/image-decoders/gif/GIFImageDecoder.cpp
@@ -353,7 +353,7 @@
     size_t requiredPreviousFrameIndex = buffer->requiredPreviousFrameIndex();
     if (requiredPreviousFrameIndex == kNotFound) {
         // This frame doesn't rely on any previous data.
-        if (!buffer->setSize(size().width(), size().height()))
+        if (!buffer->setSizeAndColorProfile(size().width(), size().height(), ImageFrame::ICCProfile()))
             return setFailed();
     } else {
         const ImageFrame* prevBuffer = &m_frameBufferCache[requiredPreviousFrameIndex];
diff --git a/third_party/WebKit/Source/platform/image-decoders/ico/ICOImageDecoder.cpp b/third_party/WebKit/Source/platform/image-decoders/ico/ICOImageDecoder.cpp
index da081e5..6c5c1c5 100644
--- a/third_party/WebKit/Source/platform/image-decoders/ico/ICOImageDecoder.cpp
+++ b/third_party/WebKit/Source/platform/image-decoders/ico/ICOImageDecoder.cpp
@@ -49,6 +49,7 @@
     , m_fastReader(nullptr)
     , m_decodedOffset(0)
     , m_dirEntriesCount(0)
+    , m_gammaAndColorProfileOption(colorOptions)
 {
 }
 
@@ -210,8 +211,7 @@
 
     if (!m_pngDecoders[index]) {
         AlphaOption alphaOption = m_premultiplyAlpha ? AlphaPremultiplied : AlphaNotPremultiplied;
-        GammaAndColorProfileOption colorOptions = m_ignoreGammaAndColorProfile ? GammaAndColorProfileIgnored : GammaAndColorProfileApplied;
-        m_pngDecoders[index] = wrapUnique(new PNGImageDecoder(alphaOption, colorOptions, m_maxDecodedBytes, dirEntry.m_imageOffset));
+        m_pngDecoders[index] = wrapUnique(new PNGImageDecoder(alphaOption, m_gammaAndColorProfileOption, m_maxDecodedBytes, dirEntry.m_imageOffset));
         setDataForPNGDecoderAtIndex(index);
     }
     // Fail if the size the PNGImageDecoder calculated does not match the size
diff --git a/third_party/WebKit/Source/platform/image-decoders/ico/ICOImageDecoder.h b/third_party/WebKit/Source/platform/image-decoders/ico/ICOImageDecoder.h
index c4e91b0d..b2a1fe2 100644
--- a/third_party/WebKit/Source/platform/image-decoders/ico/ICOImageDecoder.h
+++ b/third_party/WebKit/Source/platform/image-decoders/ico/ICOImageDecoder.h
@@ -174,6 +174,9 @@
     // Valid only while a BMPImageReader is decoding, this holds the size
     // for the particular entry being decoded.
     IntSize m_frameSize;
+
+    // Used to pass on to an internally created PNG decoder.
+    const GammaAndColorProfileOption m_gammaAndColorProfileOption;
 };
 
 } // namespace blink
diff --git a/third_party/WebKit/Source/platform/image-decoders/jpeg/JPEGImageDecoder.cpp b/third_party/WebKit/Source/platform/image-decoders/jpeg/JPEGImageDecoder.cpp
index 63827d4..23d6d5a 100644
--- a/third_party/WebKit/Source/platform/image-decoders/jpeg/JPEGImageDecoder.cpp
+++ b/third_party/WebKit/Source/platform/image-decoders/jpeg/JPEGImageDecoder.cpp
@@ -451,17 +451,17 @@
 
             m_decoder->setOrientation(readImageOrientation(info()));
 
-#if USE(QCMSLIB)
             // Allow color management of the decoded RGBA pixels if possible.
             if (!m_decoder->ignoresGammaAndColorProfile()) {
 #if USE(ICCJPEG)
                 JOCTET* profile = nullptr;
                 unsigned profileLength = 0;
                 if (read_icc_profile(info(), &profile, &profileLength)) {
-                    decoder()->setColorProfileAndTransform(reinterpret_cast<char*>(profile), profileLength, colorSpaceHasAlpha(info()->out_color_space), false /* useSRGB */);
+                    decoder()->setColorProfileAndComputeTransform(reinterpret_cast<char*>(profile), profileLength, colorSpaceHasAlpha(info()->out_color_space), false /* useSRGB */);
                     free(profile);
                 }
 #endif // USE(ICCJPEG)
+#if USE(QCMSLIB)
                 if (decoder()->colorTransform()) {
                     overrideColorSpace = JCS_UNKNOWN;
 #if defined(TURBO_JPEG_RGB_SWIZZLE)
@@ -470,8 +470,8 @@
                         m_info.out_color_space = JCS_EXT_RGBA;
 #endif // defined(TURBO_JPEG_RGB_SWIZZLE)
                 }
-            }
 #endif // USE(QCMSLIB)
+            }
             if (overrideColorSpace == JCS_YCbCr) {
                 m_info.out_color_space = JCS_YCbCr;
                 m_info.raw_data_out = TRUE;
@@ -927,7 +927,7 @@
         ASSERT(info->output_width == static_cast<JDIMENSION>(m_decodedSize.width()));
         ASSERT(info->output_height == static_cast<JDIMENSION>(m_decodedSize.height()));
 
-        if (!buffer.setSize(info->output_width, info->output_height))
+        if (!buffer.setSizeAndColorProfile(info->output_width, info->output_height, colorProfile()))
             return setFailed();
 
         // The buffer is transparent outside the decoded area while the image is
diff --git a/third_party/WebKit/Source/platform/image-decoders/png/PNGImageDecoder.cpp b/third_party/WebKit/Source/platform/image-decoders/png/PNGImageDecoder.cpp
index c0b8473a..dff41e3 100644
--- a/third_party/WebKit/Source/platform/image-decoders/png/PNGImageDecoder.cpp
+++ b/third_party/WebKit/Source/platform/image-decoders/png/PNGImageDecoder.cpp
@@ -216,7 +216,6 @@
     if (colorType == PNG_COLOR_TYPE_GRAY || colorType == PNG_COLOR_TYPE_GRAY_ALPHA)
         png_set_gray_to_rgb(png);
 
-#if USE(QCMSLIB)
     if ((colorType & PNG_COLOR_MASK_COLOR) && !m_ignoreGammaAndColorProfile) {
         // We only support color profiles for color PALETTE and RGB[A] PNG. Supporting
         // color profiles for gray-scale images is slightly tricky, at least using the
@@ -227,7 +226,7 @@
         bool imageHasAlpha = (colorType & PNG_COLOR_MASK_ALPHA) || trnsCount;
 #ifdef PNG_iCCP_SUPPORTED
         if (png_get_valid(png, info, PNG_INFO_sRGB)) {
-            setColorProfileAndTransform(nullptr, 0, imageHasAlpha, true /* useSRGB */);
+            setColorProfileAndComputeTransform(nullptr, 0, imageHasAlpha, true /* useSRGB */);
         } else {
             char* profileName = nullptr;
             int compressionType = 0;
@@ -238,12 +237,11 @@
 #endif
             png_uint_32 profileLength = 0;
             if (png_get_iCCP(png, info, &profileName, &compressionType, &profile, &profileLength)) {
-                setColorProfileAndTransform(reinterpret_cast<char*>(profile), profileLength, imageHasAlpha, false /* useSRGB */);
+                setColorProfileAndComputeTransform(reinterpret_cast<char*>(profile), profileLength, imageHasAlpha, false /* useSRGB */);
             }
         }
 #endif // PNG_iCCP_SUPPORTED
     }
-#endif // USE(QCMSLIB)
 
     if (!hasColorProfile()) {
         // Deal with gamma and keep it under our control.
@@ -294,7 +292,7 @@
     ImageFrame& buffer = m_frameBufferCache[0];
     if (buffer.getStatus() == ImageFrame::FrameEmpty) {
         png_structp png = m_reader->pngPtr();
-        if (!buffer.setSize(size().width(), size().height())) {
+        if (!buffer.setSizeAndColorProfile(size().width(), size().height(), colorProfile())) {
             longjmp(JMPBUF(png), 1);
             return;
         }
diff --git a/third_party/WebKit/Source/platform/image-decoders/webp/WEBPImageDecoder.cpp b/third_party/WebKit/Source/platform/image-decoders/webp/WEBPImageDecoder.cpp
index fae908a7..d5e4397 100644
--- a/third_party/WebKit/Source/platform/image-decoders/webp/WEBPImageDecoder.cpp
+++ b/third_party/WebKit/Source/platform/image-decoders/webp/WEBPImageDecoder.cpp
@@ -231,10 +231,8 @@
             m_formatFlags &= ~ICCP_FLAG;
         }
 
-#if USE(QCMSLIB)
         if ((m_formatFlags & ICCP_FLAG) && !ignoresGammaAndColorProfile())
             readColorProfile();
-#endif
     }
 
     ASSERT(isDecodedSizeAvailable());
@@ -250,7 +248,7 @@
     const size_t requiredPreviousFrameIndex = buffer.requiredPreviousFrameIndex();
     if (requiredPreviousFrameIndex == kNotFound) {
         // This frame doesn't rely on any previous data.
-        if (!buffer.setSize(size().width(), size().height()))
+        if (!buffer.setSizeAndColorProfile(size().width(), size().height(), colorProfile()))
             return setFailed();
         m_frameBackgroundHasAlpha = !buffer.originalFrameRect().contains(IntRect(IntPoint(), size()));
     } else {
@@ -300,8 +298,6 @@
     ImageDecoder::clearFrameBuffer(frameIndex);
 }
 
-#if USE(QCMSLIB)
-
 void WEBPImageDecoder::readColorProfile()
 {
     WebPChunkIterator chunkIterator;
@@ -313,13 +309,11 @@
     const char* profileData = reinterpret_cast<const char*>(chunkIterator.chunk.bytes);
     size_t profileSize = chunkIterator.chunk.size;
 
-    setColorProfileAndTransform(profileData, profileSize, true /* hasAlpha */, false /* useSRGB */);
+    setColorProfileAndComputeTransform(profileData, profileSize, true /* hasAlpha */, false /* useSRGB */);
 
     WebPDemuxReleaseChunkIterator(&chunkIterator);
 }
 
-#endif // USE(QCMSLIB)
-
 void WEBPImageDecoder::applyPostProcessing(size_t frameIndex)
 {
     ImageFrame& buffer = m_frameBufferCache[frameIndex];
@@ -462,7 +456,7 @@
     ASSERT(buffer.getStatus() != ImageFrame::FrameComplete);
 
     if (buffer.getStatus() == ImageFrame::FrameEmpty) {
-        if (!buffer.setSize(size().width(), size().height()))
+        if (!buffer.setSizeAndColorProfile(size().width(), size().height(), colorProfile()))
             return setFailed();
         buffer.setStatus(ImageFrame::FramePartial);
         // The buffer is transparent outside the decoded area while the image is loading.
diff --git a/third_party/WebKit/Source/platform/image-decoders/webp/WEBPImageDecoder.h b/third_party/WebKit/Source/platform/image-decoders/webp/WEBPImageDecoder.h
index 718ae30..969d25f2 100644
--- a/third_party/WebKit/Source/platform/image-decoders/webp/WEBPImageDecoder.h
+++ b/third_party/WebKit/Source/platform/image-decoders/webp/WEBPImageDecoder.h
@@ -65,10 +65,7 @@
     int m_formatFlags;
     bool m_frameBackgroundHasAlpha;
 
-#if USE(QCMSLIB)
     void readColorProfile();
-#endif
-
     bool updateDemuxer();
     bool initFrameBuffer(size_t frameIndex);
     void applyPostProcessing(size_t frameIndex);
diff --git a/third_party/WebKit/Source/platform/network/NetworkUtils.cpp b/third_party/WebKit/Source/platform/network/NetworkUtils.cpp
index 57c0b4c..49d0ba03 100644
--- a/third_party/WebKit/Source/platform/network/NetworkUtils.cpp
+++ b/third_party/WebKit/Source/platform/network/NetworkUtils.cpp
@@ -5,10 +5,30 @@
 #include "platform/network/NetworkUtils.h"
 
 #include "net/base/ip_address.h"
+#include "net/base/registry_controlled_domains/registry_controlled_domain.h"
 #include "net/base/url_util.h"
 #include "wtf/text/StringUTF8Adaptor.h"
 #include "wtf/text/WTFString.h"
 
+namespace {
+
+net::registry_controlled_domains::PrivateRegistryFilter getNetPrivateRegistryFilter(blink::NetworkUtils::PrivateRegistryFilter filter)
+{
+    switch (filter) {
+    case blink::NetworkUtils::IncludePrivateRegistries:
+        return net::registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES;
+    case blink::NetworkUtils::ExcludePrivateRegistries:
+        return net::registry_controlled_domains::EXCLUDE_PRIVATE_REGISTRIES;
+    }
+    // There are only two NetworkUtils::PrivateRegistryFilter enum entries, so
+    // we should never reach this point. However, we must have a default return
+    // value to avoid a compiler error.
+    NOTREACHED();
+    return net::registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES;
+}
+
+} // namespace
+
 namespace blink {
 
 namespace NetworkUtils {
@@ -28,6 +48,13 @@
     return net::IsLocalHostname(utf8.asStringPiece(), isLocal6);
 }
 
+String getDomainAndRegistry(const String& host, PrivateRegistryFilter filter)
+{
+    StringUTF8Adaptor hostUtf8(host);
+    std::string domain = net::registry_controlled_domains::GetDomainAndRegistry(hostUtf8.asStringPiece(), getNetPrivateRegistryFilter(filter));
+    return String(domain.data(), domain.length());
+}
+
 } // NetworkUtils
 
 } // namespace blink
diff --git a/third_party/WebKit/Source/platform/network/NetworkUtils.h b/third_party/WebKit/Source/platform/network/NetworkUtils.h
index 98e733a..471ebb1 100644
--- a/third_party/WebKit/Source/platform/network/NetworkUtils.h
+++ b/third_party/WebKit/Source/platform/network/NetworkUtils.h
@@ -12,10 +12,17 @@
 
 namespace NetworkUtils {
 
+enum PrivateRegistryFilter {
+    IncludePrivateRegistries,
+    ExcludePrivateRegistries,
+};
+
 PLATFORM_EXPORT bool isReservedIPAddress(const String& host);
 
 PLATFORM_EXPORT bool isLocalHostname(const String& host, bool* isLocal6);
 
+PLATFORM_EXPORT String getDomainAndRegistry(const String& host, PrivateRegistryFilter);
+
 } // NetworkUtils
 
 } // namespace blink
diff --git a/third_party/WebKit/Source/platform/network/NetworkUtilsTest.cpp b/third_party/WebKit/Source/platform/network/NetworkUtilsTest.cpp
index d5d84f93..5eac73c 100644
--- a/third_party/WebKit/Source/platform/network/NetworkUtilsTest.cpp
+++ b/third_party/WebKit/Source/platform/network/NetworkUtilsTest.cpp
@@ -61,4 +61,30 @@
     }
 }
 
+TEST(NetworkUtilsTest, GetDomainAndRegistry)
+{
+    EXPECT_EQ("", NetworkUtils::getDomainAndRegistry("", NetworkUtils::IncludePrivateRegistries));
+    EXPECT_EQ("", NetworkUtils::getDomainAndRegistry(".", NetworkUtils::IncludePrivateRegistries));
+    EXPECT_EQ("", NetworkUtils::getDomainAndRegistry("..", NetworkUtils::IncludePrivateRegistries));
+    EXPECT_EQ("", NetworkUtils::getDomainAndRegistry("com", NetworkUtils::IncludePrivateRegistries));
+    EXPECT_EQ("", NetworkUtils::getDomainAndRegistry(".com", NetworkUtils::IncludePrivateRegistries));
+    EXPECT_EQ("", NetworkUtils::getDomainAndRegistry("www.example.com:8000", NetworkUtils::IncludePrivateRegistries));
+
+    EXPECT_EQ("", NetworkUtils::getDomainAndRegistry("localhost", NetworkUtils::IncludePrivateRegistries));
+    EXPECT_EQ("", NetworkUtils::getDomainAndRegistry("127.0.0.1", NetworkUtils::IncludePrivateRegistries));
+
+    EXPECT_EQ("example.com", NetworkUtils::getDomainAndRegistry("example.com", NetworkUtils::IncludePrivateRegistries));
+    EXPECT_EQ("example.com", NetworkUtils::getDomainAndRegistry("www.example.com", NetworkUtils::IncludePrivateRegistries));
+    EXPECT_EQ("example.com", NetworkUtils::getDomainAndRegistry("static.example.com", NetworkUtils::IncludePrivateRegistries));
+    EXPECT_EQ("example.com", NetworkUtils::getDomainAndRegistry("multilevel.www.example.com", NetworkUtils::IncludePrivateRegistries));
+    EXPECT_EQ("example.co.uk", NetworkUtils::getDomainAndRegistry("www.example.co.uk", NetworkUtils::IncludePrivateRegistries));
+
+    // Verify proper handling of 'private registries'.
+    EXPECT_EQ("foo.appspot.com", NetworkUtils::getDomainAndRegistry("www.foo.appspot.com", NetworkUtils::IncludePrivateRegistries));
+    EXPECT_EQ("appspot.com", NetworkUtils::getDomainAndRegistry("www.foo.appspot.com", NetworkUtils::ExcludePrivateRegistries));
+
+    // Verify that unknown registries are included.
+    EXPECT_EQ("example.notarealregistry", NetworkUtils::getDomainAndRegistry("www.example.notarealregistry", NetworkUtils::IncludePrivateRegistries));
+}
+
 } // namespace blink
diff --git a/third_party/WebKit/Tools/Scripts/generate_w3c_directory_owner_json b/third_party/WebKit/Tools/Scripts/generate-w3c-directory-owner-json
similarity index 100%
rename from third_party/WebKit/Tools/Scripts/generate_w3c_directory_owner_json
rename to third_party/WebKit/Tools/Scripts/generate-w3c-directory-owner-json
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/common/net/buildbot.py b/third_party/WebKit/Tools/Scripts/webkitpy/common/net/buildbot.py
index f899ca2..374a8ad 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/common/net/buildbot.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/common/net/buildbot.py
@@ -87,6 +87,10 @@
     def latest_layout_test_results(self, builder_name):
         return self.fetch_layout_test_results(self.accumulated_results_url_base(builder_name))
 
+    @memoized
+    def fetch_results(self, build):
+        return self.fetch_layout_test_results(self.results_url(build.builder_name, build.build_number))
+
     def fetch_layout_test_results(self, results_url):
         """Returns a LayoutTestResults object for results fetched from a given URL."""
         # FIXME: This should cache that the result was a 404 and stop hitting the network.
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/common/net/buildbot_mock.py b/third_party/WebKit/Tools/Scripts/webkitpy/common/net/buildbot_mock.py
index 568a70d..bd4bdd8b 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/common/net/buildbot_mock.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/common/net/buildbot_mock.py
@@ -33,5 +33,18 @@
 
 class MockBuildBot(BuildBot):
 
+    def __init__(self):
+        super(MockBuildBot, self).__init__()
+        # Dict of Build to canned LayoutTestResults.
+        self._canned_results = {}
+
     def fetch_layout_test_results(self, _):
         return LayoutTestResults.results_from_string(LayoutTestResultsTest.example_full_results_json)
+
+    def set_results(self, build, results):
+        self._canned_results[build] = results
+
+    def fetch_results(self, build):
+        return self._canned_results.get(
+            build,
+            LayoutTestResults.results_from_string(LayoutTestResultsTest.example_full_results_json))
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/tool/commands/auto_rebaseline.py b/third_party/WebKit/Tools/Scripts/webkitpy/tool/commands/auto_rebaseline.py
index 3314a95..c4e35d4 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/tool/commands/auto_rebaseline.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/tool/commands/auto_rebaseline.py
@@ -64,7 +64,8 @@
 
     def bot_revision_data(self, scm):
         revisions = []
-        for result in self.build_data().values():
+        for builder_name in self._release_builders():
+            result = self._tool.buildbot.fetch_results(Build(builder_name))
             if result.run_was_interrupted():
                 _log.error("Can't rebaseline because the latest run on %s exited early.", result.builder_name())
                 return []
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/tool/commands/auto_rebaseline_unittest.py b/third_party/WebKit/Tools/Scripts/webkitpy/tool/commands/auto_rebaseline_unittest.py
index ee2ce82..d768ab9d 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/tool/commands/auto_rebaseline_unittest.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/tool/commands/auto_rebaseline_unittest.py
@@ -36,7 +36,6 @@
             "MOCK Win7": {"port_name": "test-win-win7", "specifiers": ["Win7", "Release"]},
             "MOCK Win7 (dbg)": {"port_name": "test-win-win7", "specifiers": ["Win7", "Debug"]},
         })
-
         self.command.latest_revision_processed_on_all_bots = lambda: 9000
         self.command.bot_revision_data = lambda scm: [{"builder": "MOCK Win7", "revision": "9000"}]
 
@@ -144,33 +143,50 @@
 
         test_port = self.tool.port_factory.get('test')
 
-        def build_data():
-            # Have prototype-chocolate only fail on "MOCK Mac10.11".
-            self._build_data[Build('MOCK Mac10.11')] = LayoutTestResults({
-                "tests": {
-                    "fast": {
-                        "dom": {
-                            "prototype-taco.html": {
-                                "expected": "PASS",
-                                "actual": "PASS TEXT",
-                                "is_unexpected": True
-                            },
-                            "prototype-chocolate.html": {
-                                "expected": "FAIL",
-                                "actual": "PASS"
-                            },
-                            "prototype-strawberry.html": {
-                                "expected": "PASS",
-                                "actual": "IMAGE PASS",
-                                "is_unexpected": True
-                            }
+        # Have prototype-chocolate only fail on "MOCK Mac10.11",
+        # and pass on "Mock Mac10.10".
+        self.tool.buildbot.set_results(Build('MOCK Mac10.11'), LayoutTestResults({
+            "tests": {
+                "fast": {
+                    "dom": {
+                        "prototype-taco.html": {
+                            "expected": "PASS",
+                            "actual": "PASS TEXT",
+                            "is_unexpected": True
+                        },
+                        "prototype-chocolate.html": {
+                            "expected": "FAIL",
+                            "actual": "PASS"
+                        },
+                        "prototype-strawberry.html": {
+                            "expected": "PASS",
+                            "actual": "IMAGE PASS",
+                            "is_unexpected": True
                         }
                     }
                 }
-            })
-            return self._build_data
-
-        self.command.build_data = build_data
+            }
+        }))
+        self.tool.buildbot.set_results(Build('MOCK Mac10.10'), LayoutTestResults({
+            "tests": {
+                "fast": {
+                    "dom": {
+                        "prototype-taco.html": {
+                            "expected": "PASS",
+                            "actual": "PASS",
+                        },
+                        "prototype-chocolate.html": {
+                            "expected": "FAIL",
+                            "actual": "FAIL"
+                        },
+                        "prototype-strawberry.html": {
+                            "expected": "PASS",
+                            "actual": "PASS",
+                        }
+                    }
+                }
+            }
+        }))
 
         self.tool.filesystem.write_text_file(test_port.path_to_generic_test_expectations_file(), """
 crbug.com/24182 [ Debug ] path/to/norebaseline.html [ Rebaseline ]
@@ -243,27 +259,20 @@
 
         test_port = self.tool.port_factory.get('test')
 
-        original_build_data = self.command.build_data
-
-        def build_data():
-            original_build_data()
-            # Have prototype-chocolate only fail on "MOCK Mac10.11".
-            self._build_data[Build('MOCK Mac10.11')] = LayoutTestResults({
-                "tests": {
-                    "fast": {
-                        "dom": {
-                            "prototype-taco.html": {
-                                "expected": "PASS",
-                                "actual": "PASS TEXT",
-                                "is_unexpected": True
-                            }
+        # Have prototype-chocolate only fail on "MOCK Mac10.11".
+        self.tool.buildbot.set_results(Build('MOCK Mac10.11'), LayoutTestResults({
+            "tests": {
+                "fast": {
+                    "dom": {
+                        "prototype-taco.html": {
+                            "expected": "PASS",
+                            "actual": "PASS TEXT",
+                            "is_unexpected": True
                         }
                     }
                 }
-            })
-            return self._build_data
-
-        self.command.build_data = build_data
+            }
+        }))
 
         self.tool.filesystem.write_text_file(test_port.path_to_generic_test_expectations_file(), """
 Bug(foo) fast/dom/prototype-taco.html [ NeedsRebaseline ]
@@ -282,14 +291,10 @@
         self._execute_with_mock_options()
 
         self.assertEqual(self.tool.executive.calls, [
-            [
-                ['python', 'echo', 'copy-existing-baselines-internal', '--suffixes', 'txt',
-                 '--builder', 'MOCK Mac10.11', '--test', 'fast/dom/prototype-taco.html'],
-            ],
-            [
-                ['python', 'echo', 'rebaseline-test-internal', '--suffixes', 'txt',
-                 '--builder', 'MOCK Mac10.11', '--test', 'fast/dom/prototype-taco.html'],
-            ],
+            [['python', 'echo', 'copy-existing-baselines-internal', '--suffixes', 'txt',
+              '--builder', 'MOCK Mac10.11', '--test', 'fast/dom/prototype-taco.html']],
+            [['python', 'echo', 'rebaseline-test-internal', '--suffixes', 'txt',
+              '--builder', 'MOCK Mac10.11', '--test', 'fast/dom/prototype-taco.html']],
             [['python', 'echo', 'optimize-baselines', '--no-modify-scm', '--suffixes', 'txt', 'fast/dom/prototype-taco.html']],
             ['git', 'cl', 'upload', '-f'],
         ])
@@ -303,8 +308,8 @@
 
         test_port = self.tool.port_factory.get('test')
 
-        def build_data():
-            self._build_data[Build('MOCK Mac10.10')] = self._build_data[Build('MOCK Mac10.11')] = LayoutTestResults({
+        for builder in ['MOCK Mac10.10', 'MOCK Mac10.11']:
+            self.tool.buildbot.set_results(Build(builder), LayoutTestResults({
                 "tests": {
                     "fast": {
                         "dom": {
@@ -316,10 +321,7 @@
                         }
                     }
                 }
-            })
-            return self._build_data
-
-        self.command.build_data = build_data
+            }))
 
         self.tool.filesystem.write_text_file(test_port.path_to_generic_test_expectations_file(), """
 Bug(foo) fast/dom/prototype-taco.html [ NeedsRebaseline ]
@@ -357,23 +359,19 @@
 
         test_port = self.tool.port_factory.get('test')
 
-        def build_data():
-            self._build_data[Build('MOCK Win')] = LayoutTestResults({
-                "tests": {
-                    "fast": {
-                        "dom": {
-                            "prototype-taco.html": {
-                                "expected": "FAIL",
-                                "actual": "PASS",
-                                "is_unexpected": True
-                            }
+        self.tool.buildbot.set_results(Build('MOCK Win7'), LayoutTestResults({
+            "tests": {
+                "fast": {
+                    "dom": {
+                        "prototype-taco.html": {
+                            "expected": "FAIL",
+                            "actual": "PASS",
+                            "is_unexpected": True
                         }
                     }
                 }
-            })
-            return self._build_data
-
-        self.command.build_data = build_data
+            }
+        }))
 
         self.tool.filesystem.write_text_file(test_port.path_to_generic_test_expectations_file(), """
 Bug(foo) fast/dom/prototype-taco.html [ NeedsRebaseline ]
@@ -413,23 +411,19 @@
 
         test_port = self.tool.port_factory.get('test')
 
-        def build_data():
-            self._build_data[Build('MOCK Win')] = LayoutTestResults({
-                "tests": {
-                    "fast": {
-                        "dom": {
-                            "prototype-taco.html": {
-                                "expected": "FAIL",
-                                "actual": "PASS",
-                                "is_unexpected": True
-                            }
+        self.tool.buildbot.set_results(Build('MOCK Win7'), LayoutTestResults({
+            "tests": {
+                "fast": {
+                    "dom": {
+                        "prototype-taco.html": {
+                            "expected": "FAIL",
+                            "actual": "PASS",
+                            "is_unexpected": True
                         }
                     }
                 }
-            })
-            return self._build_data
-
-        self.command.build_data = build_data
+            }
+        }))
 
         self.tool.filesystem.write_text_file(test_port.path_to_generic_test_expectations_file(), """
 Bug(foo) fast/dom/prototype-taco.html [ NeedsRebaseline ]
@@ -442,7 +436,6 @@
         self.tool.builders = BuilderList({
             "MOCK Win7": {"port_name": "test-win-win7", "specifiers": ["Win7", "Release"]},
         })
-
         old_branch_name = self.tool.scm().current_branch_or_ref
         try:
             self.command.tree_status = lambda: 'open'
@@ -470,8 +463,8 @@
 
         test_port = self.tool.port_factory.get('test')
 
-        def build_data():
-            self._build_data[Build('MOCK Mac10.10')] = self._build_data[Build('MOCK Mac10.11')] = LayoutTestResults({
+        for builder in ['MOCK Mac10.10', 'MOCK Mac10.11']:
+            self.tool.buildbot.set_results(Build(builder), LayoutTestResults({
                 "tests": {
                     "fast": {
                         "dom": {
@@ -483,10 +476,7 @@
                         }
                     }
                 }
-            })
-            return self._build_data
-
-        self.command.build_data = build_data
+            }))
 
         self.tool.filesystem.write_text_file(test_port.path_to_generic_test_expectations_file(), """
 Bug(foo) fast/dom/prototype-taco.html [ NeedsRebaseline ]
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/tool/commands/rebaseline.py b/third_party/WebKit/Tools/Scripts/webkitpy/tool/commands/rebaseline.py
index 4cbaec1d..6dc139f0 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/tool/commands/rebaseline.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/tool/commands/rebaseline.py
@@ -233,27 +233,17 @@
     def __init__(self, options=None):
         super(AbstractParallelRebaselineCommand, self).__init__(options=options)
 
-    @memoized
-    def build_data(self):
-        """Returns a map of Build objects to LayoutTestResult objects.
-
-        The Build objects are the latest builds for the release builders,
-        and LayoutTestResult objects for results fetched from archived layout
-        test results.
-        """
-        build_to_results = {}
-        for builder_name in self._release_builders():
-            builder_results = self._tool.buildbot.latest_layout_test_results(builder_name)
-            if builder_results:
-                build_to_results[Build(builder_name)] = builder_results
-            else:
-                raise Exception("No result for builder %s." % builder_name)
-        return build_to_results
-
-    # The release builders cycle much faster than the debug ones and cover all the platforms.
     def _release_builders(self):
+        """Returns a list of builder names for continuous release builders.
+
+        The release builders cycle much faster than the debug ones and cover all the platforms.
+        """
         release_builders = []
         for builder_name in self._tool.builders.all_continuous_builder_names():
+            # TODO(qyearsley): Remove this check. Explicitly excluding ASAN builders
+            # should be unnecessary, since there are no ASAN builders listed in
+            # webkitpy/common/config/builders.py. If we do want to keep this check,
+            # then we should probably also explicitly exclude MSAN builders.
             if 'ASAN' in builder_name:
                 continue
             port = self._tool.port_factory.get_from_builder_name(builder_name)
@@ -304,7 +294,7 @@
         # of some class, then this could be replaced with  a method on that class.
         return [b.builder_name for b in builds]
 
-    def _rebaseline_commands(self, test_prefix_list, options, skip_checking_actual_results=False):
+    def _rebaseline_commands(self, test_prefix_list, options):
         path_to_webkit_patch = self._tool.path()
         cwd = self._tool.scm().checkout_root
         copy_baseline_commands = []
@@ -316,14 +306,9 @@
             for test in port.tests([test_prefix]):
                 builders_to_fetch_from = self._builders_to_fetch_from(self._builder_names(test_prefix_list[test_prefix]))
                 for build in sorted(test_prefix_list[test_prefix]):
-                    # TODO(qyearsley): Remove the parameter skip_checking_actual_results
-                    # and instead refactor the existing code so that this is not necessary.
                     builder, build_number = build.builder_name, build.build_number
-
                     if builder not in builders_to_fetch_from:
                         break
-                    if skip_checking_actual_results:
-                        actual_failures_suffixes = test_prefix_list[test_prefix][build]
                     else:
                         actual_failures_suffixes = self._suffixes_for_actual_failures(
                             test, build, test_prefix_list[test_prefix][build])
@@ -466,7 +451,7 @@
             self._tool.scm().add_list(files_to_add)
         return lines_to_remove
 
-    def _rebaseline(self, options, test_prefix_list, skip_checking_actual_results=False):
+    def _rebaseline(self, options, test_prefix_list):
         """Downloads new baselines in parallel, then updates expectations files
         and optimizes baselines.
 
@@ -484,10 +469,6 @@
                 "some/other.html" but only from builder-1.
                 TODO(qyearsley): Replace test_prefix_list everywhere with some
                 sort of class that contains the same data.
-            skip_checking_actual_results: If True, then the lists of suffixes
-                to rebaseline from |test_prefix_list| will be used directly;
-                if False, then the list of suffixes will filtered to include
-                suffixes with mismatches in actual results.
         """
         for test, builds_to_check in sorted(test_prefix_list.items()):
             _log.info("Rebaselining %s", test)
@@ -495,7 +476,7 @@
                 _log.debug("  %s: %s", build, ",".join(suffixes))
 
         copy_baseline_commands, rebaseline_commands, extra_lines_to_remove = self._rebaseline_commands(
-            test_prefix_list, options, skip_checking_actual_results)
+            test_prefix_list, options)
         lines_to_remove = {}
 
         self._run_in_parallel_and_update_scm(copy_baseline_commands)
@@ -527,10 +508,13 @@
         Returns:
             A set of file suffix strings.
         """
-        if build not in self.build_data():
+        results = self._tool.buildbot.fetch_results(build)
+        if not results:
+            _log.debug('No results found for build %s', build)
             return set()
-        test_result = self.build_data()[build].result_for_test(test)
+        test_result = results.result_for_test(test)
         if not test_result:
+            _log.debug('No test result for test %s in build %s', test, build)
             return set()
         return set(existing_suffixes) & TestExpectations.suffixes_for_test_result(test_result)
 
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/tool/commands/rebaseline_from_try_jobs.py b/third_party/WebKit/Tools/Scripts/webkitpy/tool/commands/rebaseline_from_try_jobs.py
index 9719f98e..77fe0e4 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/tool/commands/rebaseline_from_try_jobs.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/tool/commands/rebaseline_from_try_jobs.py
@@ -56,7 +56,7 @@
 
         if options.dry_run:
             return
-        self._rebaseline(options, test_prefix_list, skip_checking_actual_results=True)
+        self._rebaseline(options, test_prefix_list)
 
     def _get_issue_number(self, options):
         """Gets the Rietveld CL number from either |options| or from the current local branch."""
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/tool/commands/rebaseline_from_try_jobs_unittest.py b/third_party/WebKit/Tools/Scripts/webkitpy/tool/commands/rebaseline_from_try_jobs_unittest.py
index 98f4cf1..19f17e2 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/tool/commands/rebaseline_from_try_jobs_unittest.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/tool/commands/rebaseline_from_try_jobs_unittest.py
@@ -121,14 +121,14 @@
 
         self.command._rebaseline(
             self.command_options(issue=11112222),
-            {"fast/dom/prototype-taco.html": {Build("MOCK Try Win", 5000): ["txt", "png"]}},
-            skip_checking_actual_results=True)
+            {"fast/dom/prototype-taco.html": {Build("MOCK Try Win", 5000): ["txt", "png"]}})
 
         self.assertEqual(
             self.tool.executive.calls,
             [
-                [['python', 'echo', 'copy-existing-baselines-internal', '--suffixes', 'txt,png',
+                [['python', 'echo', 'copy-existing-baselines-internal', '--suffixes', 'txt',
                   '--builder', 'MOCK Try Win', '--test', 'fast/dom/prototype-taco.html', '--build-number', '5000']],
-                [['python', 'echo', 'rebaseline-test-internal', '--suffixes', 'txt,png',
-                  '--builder', 'MOCK Try Win', '--test', 'fast/dom/prototype-taco.html', '--build-number', '5000']]
+                [['python', 'echo', 'rebaseline-test-internal', '--suffixes', 'txt',
+                  '--builder', 'MOCK Try Win', '--test', 'fast/dom/prototype-taco.html', '--build-number', '5000']],
+                [['python', 'echo', 'optimize-baselines', '--no-modify-scm', '--suffixes', 'txt', 'fast/dom/prototype-taco.html']]
             ])
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/tool/commands/rebaseline_unittest.py b/third_party/WebKit/Tools/Scripts/webkitpy/tool/commands/rebaseline_unittest.py
index a0f635e..f988172 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/tool/commands/rebaseline_unittest.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/tool/commands/rebaseline_unittest.py
@@ -60,7 +60,6 @@
         # we can make the default port also a "test" port.
         self.original_port_factory_get = self.tool.port_factory.get
         test_port = self.tool.port_factory.get('test')
-        self._build_data = {}
 
         def get_test_port(port_name=None, options=None, **kwargs):
             if not port_name:
@@ -91,28 +90,21 @@
         self.tool.filesystem.written_files = {}
 
     def _setup_mock_build_data(self):
-        data = LayoutTestResults({
-            "tests": {
-                "userscripts": {
-                    "first-test.html": {
-                        "expected": "PASS",
-                        "actual": "IMAGE+TEXT"
-                    },
-                    "second-test.html": {
-                        "expected": "FAIL",
-                        "actual": "IMAGE+TEXT"
+        for builder in ['MOCK Win7', 'MOCK Win7 (dbg)', 'MOCK Mac10.11']:
+            self.tool.buildbot.set_results(Build(builder), LayoutTestResults({
+                "tests": {
+                    "userscripts": {
+                        "first-test.html": {
+                            "expected": "PASS",
+                            "actual": "IMAGE+TEXT"
+                        },
+                        "second-test.html": {
+                            "expected": "FAIL",
+                            "actual": "IMAGE+TEXT"
+                        }
                     }
                 }
-            }
-        })
-
-        def build_data():
-            self._build_data = {}
-            for builder in ['MOCK Win7', 'MOCK Win7 (dbg)', 'MOCK Mac10.11']:
-                self._build_data[Build(builder)] = data
-            return self._build_data
-
-        self.command.build_data = build_data
+            }))
 
 class TestCopyExistingBaselinesInternal(BaseTestCase):
     command_constructor = CopyExistingBaselinesInternal
@@ -373,20 +365,16 @@
     def test_rebaseline_test_passes_on_all_builders(self):
         self._setup_mock_build_data()
 
-        def build_data():
-            self._build_data[Build('MOCK Win7')] = LayoutTestResults({
-                "tests": {
-                    "userscripts": {
-                        "first-test.html": {
-                            "expected": "NEEDSREBASELINE",
-                            "actual": "PASS"
-                        }
+        self.tool.buildbot.set_results(Build('MOCK Win7'), LayoutTestResults({
+            "tests": {
+                "userscripts": {
+                    "first-test.html": {
+                        "expected": "NEEDSREBASELINE",
+                        "actual": "PASS"
                     }
                 }
-            })
-            return self._build_data
-
-        self.command.build_data = build_data
+            }
+        }))
 
         options = MockOptions(optimize=True, verbose=True, results_directory=None)
 
@@ -405,15 +393,16 @@
         self.command._rebaseline(options, {"userscripts/first-test.html": {Build("MOCK Win7"): ["txt", "png"]}})
 
         # Note that we have one run_in_parallel() call followed by a run_command()
-        self.assertEqual(self.tool.executive.calls,
-                         [
-                             [['python', 'echo', 'copy-existing-baselines-internal', '--suffixes', 'txt,png',
-                               '--builder', 'MOCK Win7', '--test', 'userscripts/first-test.html', '--verbose']],
-                             [['python', 'echo', 'rebaseline-test-internal', '--suffixes', 'txt,png',
-                               '--builder', 'MOCK Win7', '--test', 'userscripts/first-test.html', '--verbose']],
-                             [['python', 'echo', 'optimize-baselines', '--no-modify-scm', '--suffixes', 'txt,png',
-                               'userscripts/first-test.html', '--verbose']]
-                         ])
+        self.assertEqual(
+            self.tool.executive.calls,
+            [
+                [['python', 'echo', 'copy-existing-baselines-internal', '--suffixes', 'txt,png',
+                  '--builder', 'MOCK Win7', '--test', 'userscripts/first-test.html', '--verbose']],
+                [['python', 'echo', 'rebaseline-test-internal', '--suffixes', 'txt,png',
+                  '--builder', 'MOCK Win7', '--test', 'userscripts/first-test.html', '--verbose']],
+                [['python', 'echo', 'optimize-baselines', '--no-modify-scm', '--suffixes', 'txt,png',
+                  'userscripts/first-test.html', '--verbose']]
+            ])
 
     def test_rebaseline_debug(self):
         self._setup_mock_build_data()
@@ -436,19 +425,20 @@
 
     def test_no_optimize(self):
         self._setup_mock_build_data()
+        print self.tool.buildbot._canned_results
 
         options = MockOptions(optimize=False, verbose=True, results_directory=None)
         self._write("userscripts/first-test.html", "Dummy test contents")
-        self.command._rebaseline(options, {"userscripts/first-test.html": {Build("MOCK Win7 (dbg)"): ["txt", "png"]}})
+        self.command._rebaseline(options, {"userscripts/first-test.html": {Build("MOCK Win7"): ["txt", "png"]}})
 
         # Note that we have only one run_in_parallel() call
         self.assertEqual(
             self.tool.executive.calls,
             [
                 [['python', 'echo', 'copy-existing-baselines-internal', '--suffixes', 'txt,png',
-                  '--builder', 'MOCK Win7 (dbg)', '--test', 'userscripts/first-test.html', '--verbose']],
+                  '--builder', 'MOCK Win7', '--test', 'userscripts/first-test.html', '--verbose']],
                 [['python', 'echo', 'rebaseline-test-internal', '--suffixes', 'txt,png',
-                  '--builder', 'MOCK Win7 (dbg)', '--test', 'userscripts/first-test.html', '--verbose']]
+                  '--builder', 'MOCK Win7', '--test', 'userscripts/first-test.html', '--verbose']]
             ])
 
     def test_results_directory(self):
@@ -641,8 +631,8 @@
 
         self.tool.executive = MockExecutive2()
 
-        def build_data():
-            self._build_data[Build('MOCK Mac10.11')] = self._build_data[Build('MOCK Mac10.10')] = LayoutTestResults({
+        for builder in ['MOCK Mac10.10', 'MOCK Mac10.11']:
+            self.tool.buildbot.set_results(Build(builder), LayoutTestResults({
                 "tests": {
                     "userscripts": {
                         "another-test.html": {
@@ -655,10 +645,7 @@
                         }
                     }
                 }
-            })
-            return self._build_data
-
-        self.command.build_data = build_data
+            }))
 
         self._write("userscripts/another-test.html", "Dummy test contents")
         self._write("userscripts/images.svg", "Dummy test contents")
@@ -698,8 +685,8 @@
 
         self.tool.executive = MockExecutive2()
 
-        def build_data():
-            self._build_data[Build('MOCK Mac10.10')] = self._build_data[Build('MOCK Mac10.11')] = LayoutTestResults({
+        for builder in ['MOCK Mac10.10', 'MOCK Mac10.11']:
+            self.tool.buildbot.set_results(Build(builder), LayoutTestResults({
                 "tests": {
                     "userscripts": {
                         "reftest-text.html": {
@@ -716,10 +703,7 @@
                         }
                     }
                 }
-            })
-            return self._build_data
-
-        self.command.build_data = build_data
+            }))
 
         self._write("userscripts/reftest-text.html", "Dummy test contents")
         self._write("userscripts/reftest-text-expected.html", "Dummy test contents")
@@ -785,8 +769,8 @@
     def test_rebaseline_test_passes_everywhere(self):
         test_port = self.tool.port_factory.get('test')
 
-        def build_data():
-            self._build_data[Build('MOCK Mac10.10')] = self._build_data[Build('MOCK Mac10.11')] = LayoutTestResults({
+        for builder in ['MOCK Mac10.10', 'MOCK Mac10.11']:
+            self.tool.buildbot.set_results(Build(builder), LayoutTestResults({
                 "tests": {
                     "fast": {
                         "dom": {
@@ -798,10 +782,7 @@
                         }
                     }
                 }
-            })
-            return self._build_data
-
-        self.command.build_data = build_data
+            }))
 
         self.tool.filesystem.write_text_file(test_port.path_to_generic_test_expectations_file(), """
 Bug(foo) fast/dom/prototype-taco.html [ Rebaseline ]
@@ -825,37 +806,33 @@
 """)
 
     def test_rebaseline_missing(self):
-        def build_data():
-            self._build_data[Build('MOCK Mac10.10')] = LayoutTestResults({
-                "tests": {
-                    "fast": {
-                        "dom": {
-                            "missing-text.html": {
-                                "expected": "PASS",
-                                "actual": "MISSING",
-                                "is_unexpected": True,
-                                "is_missing_text": True
-                            },
-                            "missing-text-and-image.html": {
-                                "expected": "PASS",
-                                "actual": "MISSING",
-                                "is_unexpected": True,
-                                "is_missing_text": True,
-                                "is_missing_image": True
-                            },
-                            "missing-image.html": {
-                                "expected": "PASS",
-                                "actual": "MISSING",
-                                "is_unexpected": True,
-                                "is_missing_image": True
-                            }
+        self.tool.buildbot.set_results(Build('MOCK Mac10.10'), LayoutTestResults({
+            "tests": {
+                "fast": {
+                    "dom": {
+                        "missing-text.html": {
+                            "expected": "PASS",
+                            "actual": "MISSING",
+                            "is_unexpected": True,
+                            "is_missing_text": True
+                        },
+                        "missing-text-and-image.html": {
+                            "expected": "PASS",
+                            "actual": "MISSING",
+                            "is_unexpected": True,
+                            "is_missing_text": True,
+                            "is_missing_image": True
+                        },
+                        "missing-image.html": {
+                            "expected": "PASS",
+                            "actual": "MISSING",
+                            "is_unexpected": True,
+                            "is_missing_image": True
                         }
                     }
                 }
-            })
-            return self._build_data
-
-        self.command.build_data = build_data
+            }
+        }))
 
         self._write('fast/dom/missing-text.html', "Dummy test contents")
         self._write('fast/dom/missing-text-and-image.html', "Dummy test contents")
diff --git a/third_party/libvpx/generate_gypi.sh b/third_party/libvpx/generate_gypi.sh
index 350c05ea..9dc5440 100755
--- a/third_party/libvpx/generate_gypi.sh
+++ b/third_party/libvpx/generate_gypi.sh
@@ -382,6 +382,7 @@
 # Generate *_rtcd.h files.
 # $1 - Header file directory.
 # $2 - Architecture.
+# $3 - Optional - any additional arguments to pass through.
 function gen_rtcd_header {
   echo "Generate $LIBVPX_CONFIG_DIR/$1/*_rtcd.h files."
 
@@ -397,28 +398,28 @@
 
   $BASE_DIR/$LIBVPX_SRC_DIR/build/make/rtcd.pl \
     --arch=$2 \
-    --sym=vp8_rtcd $DISABLE_AVX \
+    --sym=vp8_rtcd $DISABLE_AVX $3 \
     --config=$BASE_DIR/$TEMP_DIR/libvpx.config \
     $BASE_DIR/$LIBVPX_SRC_DIR/vp8/common/rtcd_defs.pl \
     > $BASE_DIR/$LIBVPX_CONFIG_DIR/$1/vp8_rtcd.h
 
   $BASE_DIR/$LIBVPX_SRC_DIR/build/make/rtcd.pl \
     --arch=$2 \
-    --sym=vp9_rtcd $DISABLE_AVX \
+    --sym=vp9_rtcd $DISABLE_AVX $3 \
     --config=$BASE_DIR/$TEMP_DIR/libvpx.config \
     $BASE_DIR/$LIBVPX_SRC_DIR/vp9/common/vp9_rtcd_defs.pl \
     > $BASE_DIR/$LIBVPX_CONFIG_DIR/$1/vp9_rtcd.h
 
   $BASE_DIR/$LIBVPX_SRC_DIR/build/make/rtcd.pl \
     --arch=$2 \
-    --sym=vpx_scale_rtcd $DISABLE_AVX \
+    --sym=vpx_scale_rtcd $DISABLE_AVX $3 \
     --config=$BASE_DIR/$TEMP_DIR/libvpx.config \
     $BASE_DIR/$LIBVPX_SRC_DIR/vpx_scale/vpx_scale_rtcd.pl \
     > $BASE_DIR/$LIBVPX_CONFIG_DIR/$1/vpx_scale_rtcd.h
 
   $BASE_DIR/$LIBVPX_SRC_DIR/build/make/rtcd.pl \
     --arch=$2 \
-    --sym=vpx_dsp_rtcd $DISABLE_AVX \
+    --sym=vpx_dsp_rtcd $DISABLE_AVX $3 \
     --config=$BASE_DIR/$TEMP_DIR/libvpx.config \
     $BASE_DIR/$LIBVPX_SRC_DIR/vpx_dsp/vpx_dsp_rtcd_defs.pl \
     > $BASE_DIR/$LIBVPX_CONFIG_DIR/$1/vpx_dsp_rtcd.h
@@ -463,10 +464,10 @@
 all_platforms="--enable-external-build --enable-postproc --disable-install-srcs --enable-multi-res-encoding --enable-temporal-denoising --disable-unit-tests --disable-install-docs --disable-examples --enable-vp9-temporal-denoising --enable-vp9-postproc --size-limit=16384x16384 $DISABLE_AVX --as=yasm"
 gen_config_files linux/ia32 "--target=x86-linux-gcc --disable-ccache --enable-pic --enable-realtime-only ${all_platforms}"
 gen_config_files linux/x64 "--target=x86_64-linux-gcc --disable-ccache --enable-pic --enable-realtime-only ${all_platforms}"
-gen_config_files linux/arm "--target=armv6-linux-gcc --enable-pic --enable-realtime-only --disable-install-bins --disable-install-libs --disable-edsp ${all_platforms}"
-gen_config_files linux/arm-neon "--target=armv7-linux-gcc --enable-pic --enable-realtime-only --disable-edsp ${all_platforms}"
-gen_config_files linux/arm-neon-cpu-detect "--target=armv7-linux-gcc --enable-pic --enable-realtime-only --enable-runtime-cpu-detect --disable-edsp ${all_platforms}"
-gen_config_files linux/arm64 "--force-target=armv8-linux-gcc --enable-pic --enable-realtime-only --disable-edsp ${all_platforms}"
+gen_config_files linux/arm "--target=armv7-linux-gcc --enable-pic --enable-realtime-only --disable-install-bins --disable-install-libs --disable-neon ${all_platforms}"
+gen_config_files linux/arm-neon "--target=armv7-linux-gcc --enable-pic --enable-realtime-only ${all_platforms}"
+gen_config_files linux/arm-neon-cpu-detect "--target=armv7-linux-gcc --enable-pic --enable-realtime-only --enable-runtime-cpu-detect ${all_platforms}"
+gen_config_files linux/arm64 "--force-target=armv8-linux-gcc --enable-pic --enable-realtime-only ${all_platforms}"
 gen_config_files linux/mipsel "--target=mips32-linux-gcc ${all_platforms}"
 gen_config_files linux/mips64el "--target=mips64-linux-gcc ${all_platforms}"
 gen_config_files linux/generic "--target=generic-gnu --enable-pic --enable-realtime-only ${all_platforms}"
@@ -504,7 +505,7 @@
 
 gen_rtcd_header linux/ia32 x86
 gen_rtcd_header linux/x64 x86_64
-gen_rtcd_header linux/arm armv6
+gen_rtcd_header linux/arm armv7 "--disable-neon --disable-neon_asm"
 gen_rtcd_header linux/arm-neon armv7
 gen_rtcd_header linux/arm-neon-cpu-detect armv7
 gen_rtcd_header linux/arm64 armv8
diff --git a/third_party/libvpx/source/config/linux/arm-neon-cpu-detect/vpx_config.c b/third_party/libvpx/source/config/linux/arm-neon-cpu-detect/vpx_config.c
index 135d0ef..71ea1c4 100644
--- a/third_party/libvpx/source/config/linux/arm-neon-cpu-detect/vpx_config.c
+++ b/third_party/libvpx/source/config/linux/arm-neon-cpu-detect/vpx_config.c
@@ -6,5 +6,5 @@
 /* in the file PATENTS.  All contributing project authors may */
 /* be found in the AUTHORS file in the root of the source tree. */
 #include "vpx/vpx_codec.h"
-static const char* const cfg = "--target=armv7-linux-gcc --enable-pic --enable-realtime-only --enable-runtime-cpu-detect --disable-edsp --enable-external-build --enable-postproc --disable-install-srcs --enable-multi-res-encoding --enable-temporal-denoising --disable-unit-tests --disable-install-docs --disable-examples --enable-vp9-temporal-denoising --enable-vp9-postproc --size-limit=16384x16384 --as=yasm";
+static const char* const cfg = "--target=armv7-linux-gcc --enable-pic --enable-realtime-only --enable-runtime-cpu-detect --enable-external-build --enable-postproc --disable-install-srcs --enable-multi-res-encoding --enable-temporal-denoising --disable-unit-tests --disable-install-docs --disable-examples --enable-vp9-temporal-denoising --enable-vp9-postproc --size-limit=16384x16384 --as=yasm";
 const char *vpx_codec_build_config(void) {return cfg;}
diff --git a/third_party/libvpx/source/config/linux/arm-neon/vpx_config.c b/third_party/libvpx/source/config/linux/arm-neon/vpx_config.c
index 588edd5..3f3a72bf 100644
--- a/third_party/libvpx/source/config/linux/arm-neon/vpx_config.c
+++ b/third_party/libvpx/source/config/linux/arm-neon/vpx_config.c
@@ -6,5 +6,5 @@
 /* in the file PATENTS.  All contributing project authors may */
 /* be found in the AUTHORS file in the root of the source tree. */
 #include "vpx/vpx_codec.h"
-static const char* const cfg = "--target=armv7-linux-gcc --enable-pic --enable-realtime-only --disable-edsp --enable-external-build --enable-postproc --disable-install-srcs --enable-multi-res-encoding --enable-temporal-denoising --disable-unit-tests --disable-install-docs --disable-examples --enable-vp9-temporal-denoising --enable-vp9-postproc --size-limit=16384x16384 --as=yasm";
+static const char* const cfg = "--target=armv7-linux-gcc --enable-pic --enable-realtime-only --enable-external-build --enable-postproc --disable-install-srcs --enable-multi-res-encoding --enable-temporal-denoising --disable-unit-tests --disable-install-docs --disable-examples --enable-vp9-temporal-denoising --enable-vp9-postproc --size-limit=16384x16384 --as=yasm";
 const char *vpx_codec_build_config(void) {return cfg;}
diff --git a/third_party/libvpx/source/config/linux/arm/vpx_config.c b/third_party/libvpx/source/config/linux/arm/vpx_config.c
index 9e8bc81..6361b2f8 100644
--- a/third_party/libvpx/source/config/linux/arm/vpx_config.c
+++ b/third_party/libvpx/source/config/linux/arm/vpx_config.c
@@ -6,5 +6,5 @@
 /* in the file PATENTS.  All contributing project authors may */
 /* be found in the AUTHORS file in the root of the source tree. */
 #include "vpx/vpx_codec.h"
-static const char* const cfg = "--target=armv6-linux-gcc --enable-pic --enable-realtime-only --disable-install-bins --disable-install-libs --disable-edsp --enable-external-build --enable-postproc --disable-install-srcs --enable-multi-res-encoding --enable-temporal-denoising --disable-unit-tests --disable-install-docs --disable-examples --enable-vp9-temporal-denoising --enable-vp9-postproc --size-limit=16384x16384 --as=yasm";
+static const char* const cfg = "--target=armv7-linux-gcc --enable-pic --enable-realtime-only --disable-install-bins --disable-install-libs --disable-neon --enable-external-build --enable-postproc --disable-install-srcs --enable-multi-res-encoding --enable-temporal-denoising --disable-unit-tests --disable-install-docs --disable-examples --enable-vp9-temporal-denoising --enable-vp9-postproc --size-limit=16384x16384 --as=yasm";
 const char *vpx_codec_build_config(void) {return cfg;}
diff --git a/third_party/libvpx/source/config/linux/arm64/vpx_config.c b/third_party/libvpx/source/config/linux/arm64/vpx_config.c
index 64b0c80..1b8dffc 100644
--- a/third_party/libvpx/source/config/linux/arm64/vpx_config.c
+++ b/third_party/libvpx/source/config/linux/arm64/vpx_config.c
@@ -6,5 +6,5 @@
 /* in the file PATENTS.  All contributing project authors may */
 /* be found in the AUTHORS file in the root of the source tree. */
 #include "vpx/vpx_codec.h"
-static const char* const cfg = "--force-target=armv8-linux-gcc --enable-pic --enable-realtime-only --disable-edsp --enable-external-build --enable-postproc --disable-install-srcs --enable-multi-res-encoding --enable-temporal-denoising --disable-unit-tests --disable-install-docs --disable-examples --enable-vp9-temporal-denoising --enable-vp9-postproc --size-limit=16384x16384 --as=yasm";
+static const char* const cfg = "--force-target=armv8-linux-gcc --enable-pic --enable-realtime-only --enable-external-build --enable-postproc --disable-install-srcs --enable-multi-res-encoding --enable-temporal-denoising --disable-unit-tests --disable-install-docs --disable-examples --enable-vp9-temporal-denoising --enable-vp9-postproc --size-limit=16384x16384 --as=yasm";
 const char *vpx_codec_build_config(void) {return cfg;}
diff --git a/third_party/qcms/BUILD.gn b/third_party/qcms/BUILD.gn
index b6f5f05..1183569b 100644
--- a/third_party/qcms/BUILD.gn
+++ b/third_party/qcms/BUILD.gn
@@ -6,8 +6,7 @@
   include_dirs = [ "src" ]
 }
 
-# Do not build QCMS on Android or iOS. (See http://crbug.com/577155)
-disable_qcms = is_android || is_ios
+disable_qcms = false
 
 static_library("qcms") {
   if (disable_qcms) {
diff --git a/third_party/qcms/qcms.gyp b/third_party/qcms/qcms.gyp
index 8a96979..9d52c0a 100644
--- a/third_party/qcms/qcms.gyp
+++ b/third_party/qcms/qcms.gyp
@@ -4,14 +4,7 @@
 
 {
   'variables': {
-    'conditions': [
-      # Do not build QCMS on Android or iOS. (See http://crbug.com/577155)
-      ['OS == "android" or OS == "ios"', {
-        'disable_qcms%': 1,
-      }, {
-        'disable_qcms%': 0,
-      }],
-    ],
+   'disable_qcms%': 0,
   },
   'targets': [
     {
diff --git a/tools/android/mempressure.py b/tools/android/mempressure.py
index ffa7c12..053f0a1 100755
--- a/tools/android/mempressure.py
+++ b/tools/android/mempressure.py
@@ -12,7 +12,7 @@
 _SRC_PATH = os.path.abspath(os.path.join(
     os.path.dirname(__file__), '..', '..'))
 
-sys.path.append(os.path.join(_SRC_PATH, 'third_party', 'catapult', 'devil')
+sys.path.append(os.path.join(_SRC_PATH, 'third_party', 'catapult', 'devil'))
 from devil.android import device_errors
 from devil.android import device_utils
 from devil.android import flag_changer
diff --git a/tools/clang/scripts/update.py b/tools/clang/scripts/update.py
index 279ed57..a7196497 100755
--- a/tools/clang/scripts/update.py
+++ b/tools/clang/scripts/update.py
@@ -470,6 +470,7 @@
   ldflags = []
 
   base_cmake_args = ['-GNinja',
+                     '-DCMAKE_BUILD_TYPE=Release',
                      '-DLLVM_ENABLE_ASSERTIONS=ON',
                      '-DLLVM_ENABLE_THREADS=OFF',
                      '-DLLVM_ENABLE_TIMESTAMPS=OFF',
@@ -477,13 +478,6 @@
                      '-DLLVM_USE_CRT_RELEASE=MT',
                      ]
 
-  if use_head_revision:
-    # For ToT builds, which are used to catch compiler bugs early, enable debug
-    # info for better backtraces when crashing.
-    base_cmake_args += ['-DCMAKE_BUILD_TYPE=RelWithDebInfo']
-  else:
-    base_cmake_args += ['-DCMAKE_BUILD_TYPE=Release']
-
   binutils_incdir = ''
   if sys.platform.startswith('linux'):
     binutils_incdir = os.path.join(BINUTILS_DIR, 'Linux_x64/Release/include')
@@ -658,13 +652,11 @@
     # If any Chromium tools were built, install those now.
     RunCommand(['ninja', 'cr-install'], msvc_arch='x64')
 
-  if not use_head_revision:
-    # Strip the binaries to save size, except for ToT builds.
-    if sys.platform == 'darwin':
-      # See http://crbug.com/256342
-      RunCommand(['strip', '-x', os.path.join(LLVM_BUILD_DIR, 'bin', 'clang')])
-    elif sys.platform.startswith('linux'):
-      RunCommand(['strip', os.path.join(LLVM_BUILD_DIR, 'bin', 'clang')])
+  if sys.platform == 'darwin':
+    # See http://crbug.com/256342
+    RunCommand(['strip', '-x', os.path.join(LLVM_BUILD_DIR, 'bin', 'clang')])
+  elif sys.platform.startswith('linux'):
+    RunCommand(['strip', os.path.join(LLVM_BUILD_DIR, 'bin', 'clang')])
 
   # TODO(thakis): Check that `clang --version` matches VERSION.
 
diff --git a/tools/cygprofile/profile_android_startup.py b/tools/cygprofile/profile_android_startup.py
index aadb2328..0148f9e 100644
--- a/tools/cygprofile/profile_android_startup.py
+++ b/tools/cygprofile/profile_android_startup.py
@@ -31,7 +31,7 @@
 sys.path.append(os.path.join(sys.path[0], '..', '..', 'tools', 'perf'))
 from chrome_telemetry_build import chromium_config
 sys.path.append(chromium_config.GetTelemetryDir())
-from telemetry.internal.util import webpagereplay
+from telemetry.internal.util import wpr_server
 
 sys.path.append(os.path.join(sys.path[0], '..', '..',
     'third_party', 'webpagereplay'))
@@ -143,10 +143,9 @@
     if self._is_test_ca_installed:
       args.extend(['--should_generate_certs',
                    '--https_root_ca_cert_path=' + self._wpr_ca_cert_path])
-    wpr_server = webpagereplay.ReplayServer(self._wpr_archive,
+    self._wpr_server = wpr_server.ReplayServer(self._wpr_archive,
         '127.0.0.1', 0, 0, None, args)
-    ports = wpr_server.StartServer()[:-1]
-    self._wpr_server = wpr_server
+    ports = self._wpr_server.StartServer()[:-1]
     self._host_http_port = ports[0]
     self._host_https_port = ports[1]
 
diff --git a/tools/gn/docs/reference.md b/tools/gn/docs/reference.md
index d25782f..f06b517 100644
--- a/tools/gn/docs/reference.md
+++ b/tools/gn/docs/reference.md
@@ -2022,6 +2022,7 @@
       The output file directory corresponding to the path of the
       given file, not including a trailing slash.
         "//foo/bar/baz.txt" => "//out/Default/obj/foo/bar"
+
   "gen_dir"
       The generated file directory corresponding to the path of the
       given file, not including a trailing slash.
@@ -3437,20 +3438,6 @@
     requires a lot of duplicate of rules) so should only be used when
     absolutely necessary.
 
-  concurrent_links
-    In integer expressing the number of links that Ninja will perform in
-    parallel. GN will create a pool for shared library and executable
-    link steps with this many processes. Since linking is memory- and
-    I/O-intensive, projects with many large targets may want to limit
-    the number of parallel steps to avoid overloading the computer.
-    Since creating static libraries is generally not as intensive
-    there is no limit to "alink" steps.
-
-    Defaults to 0 which Ninja interprets as "no limit".
-
-    The value used will be the one from the default toolchain of the
-    current build.
-
 ```
 
 ### **Invoking targets in toolchains**:
@@ -3481,8 +3468,6 @@
 ### **Example**:
 ```
   toolchain("plugin_toolchain") {
-    concurrent_links = 8
-
     tool("cc") {
       command = "gcc {{source}}"
       ...
diff --git a/tools/gn/function_toolchain.cc b/tools/gn/function_toolchain.cc
index 3501ec1..faa190e6 100644
--- a/tools/gn/function_toolchain.cc
+++ b/tools/gn/function_toolchain.cc
@@ -332,20 +332,6 @@
     "    requires a lot of duplicate of rules) so should only be used when\n"
     "    absolutely necessary.\n"
     "\n"
-    "  concurrent_links\n"
-    "    In integer expressing the number of links that Ninja will perform in\n"
-    "    parallel. GN will create a pool for shared library and executable\n"
-    "    link steps with this many processes. Since linking is memory- and\n"
-    "    I/O-intensive, projects with many large targets may want to limit\n"
-    "    the number of parallel steps to avoid overloading the computer.\n"
-    "    Since creating static libraries is generally not as intensive\n"
-    "    there is no limit to \"alink\" steps.\n"
-    "\n"
-    "    Defaults to 0 which Ninja interprets as \"no limit\".\n"
-    "\n"
-    "    The value used will be the one from the default toolchain of the\n"
-    "    current build.\n"
-    "\n"
     "Invoking targets in toolchains:\n"
     "\n"
     "  By default, when a target depends on another, there is an implicit\n"
@@ -370,8 +356,6 @@
     "\n"
     "Example:\n"
     "  toolchain(\"plugin_toolchain\") {\n"
-    "    concurrent_links = 8\n"
-    "\n"
     "    tool(\"cc\") {\n"
     "      command = \"gcc {{source}}\"\n"
     "      ...\n"
@@ -428,21 +412,6 @@
       return Value();
   }
 
-  // Read concurrent_links (if any).
-  const Value* concurrent_links_value =
-      block_scope.GetValue("concurrent_links", true);
-  if (concurrent_links_value) {
-    if (!concurrent_links_value->VerifyTypeIs(Value::INTEGER, err))
-      return Value();
-    if (concurrent_links_value->int_value() < 0 ||
-        concurrent_links_value->int_value() > std::numeric_limits<int>::max()) {
-      *err = Err(*concurrent_links_value, "Value out of range.");
-      return Value();
-    }
-    toolchain->set_concurrent_links(
-        static_cast<int>(concurrent_links_value->int_value()));
-  }
-
   if (!block_scope.CheckForUnusedVars(err))
     return Value();
 
diff --git a/tools/gn/ninja_build_writer.cc b/tools/gn/ninja_build_writer.cc
index a7f56f9..fba1ccb 100644
--- a/tools/gn/ninja_build_writer.cc
+++ b/tools/gn/ninja_build_writer.cc
@@ -254,10 +254,6 @@
 }
 
 void NinjaBuildWriter::WriteAllPools() {
-  out_ << "pool link_pool\n"
-       << "  depth = " << default_toolchain_->concurrent_links() << std::endl
-       << std::endl;
-
   // Compute the pools referenced by all tools of all used toolchains.
   std::set<const Pool*> used_pools;
   for (const auto& pair : used_toolchains_) {
diff --git a/tools/gn/ninja_build_writer_unittest.cc b/tools/gn/ninja_build_writer_unittest.cc
index abb54753..9fee37a 100644
--- a/tools/gn/ninja_build_writer_unittest.cc
+++ b/tools/gn/ninja_build_writer_unittest.cc
@@ -66,9 +66,6 @@
       "build build.ninja: gn\n"
       "  generator = 1\n"
       "  depfile = build.ninja.d\n";
-  const char expected_link_pool[] =
-      "pool link_pool\n"
-      "  depth = 0\n";
   const char expected_other_pool[] =
       "pool other_toolchain_other_pool\n"
       "  depth = 42\n";
@@ -91,7 +88,6 @@
         "Within: " << out_str
   EXPECT_SNIPPET(expected_rule_gn);
   EXPECT_SNIPPET(expected_build_ninja);
-  EXPECT_SNIPPET(expected_link_pool);
   EXPECT_SNIPPET(expected_other_pool);
   EXPECT_SNIPPET(expected_toolchain);
   EXPECT_SNIPPET(expected_targets);
diff --git a/tools/gn/toolchain.cc b/tools/gn/toolchain.cc
index 03c9c59..70c6ce06 100644
--- a/tools/gn/toolchain.cc
+++ b/tools/gn/toolchain.cc
@@ -29,7 +29,6 @@
 
 Toolchain::Toolchain(const Settings* settings, const Label& label)
     : Item(settings, label),
-      concurrent_links_(0),
       setup_complete_(false) {
 }
 
diff --git a/tools/gn/toolchain.h b/tools/gn/toolchain.h
index 4ccfdc8..7b61f34 100644
--- a/tools/gn/toolchain.h
+++ b/tools/gn/toolchain.h
@@ -124,16 +124,9 @@
     return substitution_bits_;
   }
 
-  void set_concurrent_links(int cl) { concurrent_links_ = cl; }
-  int concurrent_links() const { return concurrent_links_; }
-
  private:
   std::unique_ptr<Tool> tools_[TYPE_NUMTYPES];
 
-  // How many links to run in parallel. Only the default toolchain's version of
-  // this variable applies.
-  int concurrent_links_;
-
   bool setup_complete_;
 
   // Substitutions used by the tools in this toolchain.
diff --git a/tools/ipc_fuzzer/message_lib/message_names.h b/tools/ipc_fuzzer/message_lib/message_names.h
index 5a9e442..8b412d0 100644
--- a/tools/ipc_fuzzer/message_lib/message_names.h
+++ b/tools/ipc_fuzzer/message_lib/message_names.h
@@ -7,8 +7,8 @@
 
 #include <stdint.h>
 
-#include <map>
 #include <string>
+#include <unordered_map>
 #include "base/logging.h"
 #include "base/macros.h"
 
@@ -46,8 +46,8 @@
   }
 
  private:
-  typedef std::map<uint32_t, std::string> TypeToNameMap;
-  typedef std::map<std::string, uint32_t> NameToTypeMap;
+  typedef std::unordered_map<uint32_t, std::string> TypeToNameMap;
+  typedef std::unordered_map<std::string, uint32_t> NameToTypeMap;
   TypeToNameMap name_map_;
   NameToTypeMap type_map_;
 
diff --git a/tools/mb/mb_config.pyl b/tools/mb/mb_config.pyl
index bf1fc66..a905bd5f 100644
--- a/tools/mb/mb_config.pyl
+++ b/tools/mb/mb_config.pyl
@@ -1336,7 +1336,7 @@
     ],
 
     'gn_asan_edge_fuzzer_v8_heap_release_bot_x86': [
-      'gn', 'asan', 'edge', 'fuzzer', 'v8_heap', 'release_bot',
+      'gn', 'clang', 'asan', 'edge', 'fuzzer', 'v8_heap', 'release_bot',
       'x86',
     ],
 
@@ -1356,12 +1356,12 @@
     ],
 
     'gn_asan_fuzzer_v8_heap_chrome_with_codecs_release_bot_x86': [
-      'gn', 'asan', 'fuzzer', 'v8_heap', 'chrome_with_codecs', 'release_bot',
-      'x86',
+      'gn', 'clang', 'asan', 'fuzzer', 'v8_heap', 'chrome_with_codecs',
+      'release_bot', 'x86',
     ],
 
     'gn_asan_fuzzer_v8_heap_release_bot_x86': [
-      'gn', 'asan', 'fuzzer', 'v8_heap', 'release_bot', 'x86',
+      'gn', 'clang', 'asan', 'fuzzer', 'v8_heap', 'release_bot', 'x86',
     ],
 
     'gn_asan_lsan_edge_debug_bot': [
@@ -1805,17 +1805,17 @@
     ('swarming_gn_asan_clang_edge_fuzzer'
          '_static_v8_heap_x86_full_symbols_release'): [
       'swarming', 'gn', 'asan', 'clang_tot', 'edge', 'fuzzer', 'static',
-      'v8_heap', 'full_symbols', 'release',
+      'v8_heap', 'full_symbols', 'release', 'x86',
     ],
 
     'swarming_gn_asan_clang_shared_v8_heap_x86_full_symbols_release': [
       'swarming', 'gn', 'asan', 'clang_tot', 'shared', 'v8_heap',
-      'full_symbols', 'release',
+      'full_symbols', 'release', 'x86',
     ],
 
     'swarming_gn_asan_clang_fuzzer_static_v8_heap_x86_full_symbols_release': [
       'swarming', 'gn', 'asan', 'clang_tot', 'fuzzer', 'static', 'v8_heap',
-      'full_symbols', 'release',
+      'full_symbols', 'release', 'x86',
     ],
 
     'swarming_gn_asan_disable_nacl_clang_tot_full_symbols_static_release': [
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index cba61b4..16a5904 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -2755,6 +2755,15 @@
   <summary>The Autofill credit card info bar was denied.</summary>
 </histogram>
 
+<histogram name="Autofill.CreditCardFillingInfoBar"
+    enum="AutofillCreditCardInfoBar">
+  <owner>mathp@chromium.org</owner>
+  <summary>
+    The relative frequency with which users accept, deny, or ignore the Autofill
+    credit card assisted filling infobar prompt.
+  </summary>
+</histogram>
+
 <histogram name="Autofill.CreditCardInfoBar" enum="AutofillCreditCardInfoBar">
   <owner>isherman@chromium.org</owner>
   <summary>
@@ -30442,6 +30451,13 @@
   </summary>
 </histogram>
 
+<histogram name="Net.QuicSession.RejectHasProof" enum="Boolean">
+  <owner>rch@chromium.org</owner>
+  <summary>
+    True if the QUIC REJ message received from the server contains a proof.
+  </summary>
+</histogram>
+
 <histogram name="Net.QuicSession.RejectLength">
   <owner>rch@chromium.org</owner>
   <summary>
@@ -37778,6 +37794,15 @@
   </summary>
 </histogram>
 
+<histogram name="PageLoad.AbortTiming.ClientRedirect" units="ms">
+  <owner>csharrison@chromium.org</owner>
+  <summary>
+    This metric is still experimental and not yet ready to be relied upon.
+    Measures the time from navigation start to the time the page load was
+    aborted by a client side redirect (Javascript navigation).
+  </summary>
+</histogram>
+
 <histogram name="PageLoad.AbortTiming.Close" units="ms">
   <owner>csharrison@chromium.org</owner>
   <summary>
@@ -47993,6 +48018,26 @@
   </summary>
 </histogram>
 
+<histogram name="SafeBrowsing.V4DecodeAdditionsResult"
+    enum="SafeBrowsingV4DecodeResult">
+  <owner>vakh@chromium.org</owner>
+  <summary>
+    Track the result of decoding the Rice-encoded list of additions of 4-byte
+    hash prefixes. This is logged once per store, per update containing
+    Rice-encoded additions.
+  </summary>
+</histogram>
+
+<histogram name="SafeBrowsing.V4DecodeRemovalsResult"
+    enum="SafeBrowsingV4DecodeResult">
+  <owner>vakh@chromium.org</owner>
+  <summary>
+    Track the result of decoding the Rice-encoded list of indexes of hash
+    prefixes to remove since the last update. This is logged once per store, per
+    update containing Rice-encoded removals.
+  </summary>
+</histogram>
+
 <histogram name="SafeBrowsing.V4FullHashCacheResult"
     enum="SafeBrowsingV4FullHashCacheResult">
   <owner>kcarattini@chromium.org</owner>
@@ -48006,7 +48051,7 @@
 </histogram>
 
 <histogram name="SafeBrowsing.V4StoreReadResult"
-    enum="SafeBrowsingStoreReadResult">
+    enum="SafeBrowsingV4StoreReadResult">
   <owner>vakh@chromium.org</owner>
   <summary>
     Track the parsing results of reading the SafeBrowsing V4 store file from
@@ -48023,7 +48068,7 @@
 </histogram>
 
 <histogram name="SafeBrowsing.V4StoreWriteResult"
-    enum="SafeBrowsingStoreWriteResult">
+    enum="SafeBrowsingV4StoreWriteResult">
   <owner>vakh@chromium.org</owner>
   <summary>
     Track the results of writing the SafeBrowsing V4 store file to disk.
@@ -80733,6 +80778,7 @@
   <int value="62" label="WINDOWS_DESKTOP_SEARCH_INFOBAR_DELEGATE"/>
   <int value="63" label="UPDATE_PASSWORD_INFOBAR_DELEGATE"/>
   <int value="64" label="DATA_REDUCTION_PROMO_INFOBAR_DELEGATE_ANDROID"/>
+  <int value="65" label="AUTOFILL_CC_ASSIST_INFOBAR_DELEGATE"/>
 </enum>
 
 <enum name="InfoBarResponse" type="int">
@@ -82509,6 +82555,7 @@
   <int value="-1941852572" label="floating-virtual-keyboard"/>
   <int value="-1940806558" label="enable-syncfs-directory-operation"/>
   <int value="-1938263248" label="enable-extension-info-dialog"/>
+  <int value="-1934673791" label="gl-composited-texture-quad-border"/>
   <int value="-1930720286" label="nacl-debug-mask"/>
   <int value="-1928198763" label="enable-async-dns"/>
   <int value="-1925117279" label="disable-quic-https"/>
@@ -89817,25 +89864,6 @@
   <int value="4" label="NO_STATE_ERROR"/>
 </enum>
 
-<enum name="SafeBrowsingStoreReadResult" type="int">
-  <int value="0" label="READ_SUCCESS"/>
-  <int value="1" label="UNEXPECTED_READ_FAILURE"/>
-  <int value="2" label="FILE_UNREADABLE_FAILURE"/>
-  <int value="3" label="FILE_EMPTY_FAILURE"/>
-  <int value="4" label="PROTO_PARSING_FAILURE"/>
-  <int value="5" label="UNEXPECTED_MAGIC_NUMBER_FAILURE"/>
-  <int value="6" label="FILE_VERSION_TOO_LOW_FAILURE"/>
-  <int value="7" label="HASH_PREFIX_INFO_MISSING_FAILURE"/>
-</enum>
-
-<enum name="SafeBrowsingStoreWriteResult" type="int">
-  <int value="0" label="WRITE_SUCCESS"/>
-  <int value="1" label="UNEXPECTED_WRITE_FAILURE"/>
-  <int value="2" label="INVALID_RESPONSE_TYPE_FAILURE"/>
-  <int value="3" label="UNEXPECTED_BYTES_WRITTEN_FAILURE"/>
-  <int value="4" label="UNABLE_TO_RENAME_FAILURE"/>
-</enum>
-
 <enum name="SafeBrowsingV4ApplyUpdateResult" type="int">
   <int value="0" label="APPLY_UPDATE_SUCCESS"/>
   <int value="1" label="UNEXPECTED_APPLY_UPDATE_FAILURE"/>
@@ -89844,6 +89872,21 @@
   <int value="4" label="ADDITIONS_SIZE_UNEXPECTED_FAILURE"/>
   <int value="5" label="ADDITIONS_HAS_EXISTING_PREFIX_FAILURE"/>
   <int value="6" label="UNEXPECTED_RESPONSE_TYPE_FAILURE"/>
+  <int value="7" label="REMOVALS_INDEX_TOO_LARGE_FAILURE"/>
+  <int value="8" label="RICE_DECODING_FAILURE"/>
+  <int value="9" label="UNEXPECTED_COMPRESSION_TYPE_ADDITIONS_FAILURE"/>
+  <int value="10" label="UNEXPECTED_COMPRESSION_TYPE_REMOVALS_FAILURE"/>
+</enum>
+
+<enum name="SafeBrowsingV4DecodeResult" type="int">
+  <int value="0" label="DECODE_SUCCESS"/>
+  <int value="1" label="DECODE_NO_MORE_ENTRIES_FAILURE"/>
+  <int value="2" label="DECODE_REQUESTED_TOO_MANY_BITS_FAILURE"/>
+  <int value="3" label="DECODE_RAN_OUT_OF_BITS_FAILURE"/>
+  <int value="4" label="NUM_ENTRIES_NEGATIVE_FAILURE"/>
+  <int value="5" label="RICE_PARAMETER_NON_POSITIVE_FAILURE"/>
+  <int value="6" label="ENCODED_DATA_UNEXPECTED_EMPTY_FAILURE"/>
+  <int value="7" label="DECODED_INTEGER_OVERFLOW_FAILURE"/>
 </enum>
 
 <enum name="SafeBrowsingV4FullHashCacheResult" type="int">
@@ -89868,6 +89911,25 @@
   <int value="6" label="ALREADY_PENDING_ERROR"/>
 </enum>
 
+<enum name="SafeBrowsingV4StoreReadResult" type="int">
+  <int value="0" label="READ_SUCCESS"/>
+  <int value="1" label="UNEXPECTED_READ_FAILURE"/>
+  <int value="2" label="FILE_UNREADABLE_FAILURE"/>
+  <int value="3" label="FILE_EMPTY_FAILURE"/>
+  <int value="4" label="PROTO_PARSING_FAILURE"/>
+  <int value="5" label="UNEXPECTED_MAGIC_NUMBER_FAILURE"/>
+  <int value="6" label="FILE_VERSION_TOO_LOW_FAILURE"/>
+  <int value="7" label="HASH_PREFIX_INFO_MISSING_FAILURE"/>
+</enum>
+
+<enum name="SafeBrowsingV4StoreWriteResult" type="int">
+  <int value="0" label="WRITE_SUCCESS"/>
+  <int value="1" label="UNEXPECTED_WRITE_FAILURE"/>
+  <int value="2" label="INVALID_RESPONSE_TYPE_FAILURE"/>
+  <int value="3" label="UNEXPECTED_BYTES_WRITTEN_FAILURE"/>
+  <int value="4" label="UNABLE_TO_RENAME_FAILURE"/>
+</enum>
+
 <enum name="SavePasswordPromptResponseType" type="int">
   <int value="0" label="NO_RESPONSE"/>
   <int value="1" label="REMEMBER_PASSWORD"/>
@@ -99800,6 +99862,7 @@
   <suffix name="last_n" label="Offline recent pages"/>
   <suffix name="async_loading" label="Offline async loaded pages"/>
   <suffix name="custom_tabs" label="Offline custom tabs"/>
+  <suffix name="download" label="Offline downloaded pages"/>
   <affected-histogram name="OfflinePages.DeletePage.AccessCount"/>
   <affected-histogram name="OfflinePages.DeletePage.LastOpenToCreated"/>
   <affected-histogram name="OfflinePages.DeletePage.PageSize"/>
@@ -99965,6 +100028,7 @@
   <suffix name="AfterPaint.BeforeInteraction"/>
   <suffix name="AfterPaint.Before1sDelayedInteraction"/>
   <suffix name="DuringParse"/>
+  <affected-histogram name="PageLoad.AbortTiming.ClientRedirect"/>
   <affected-histogram name="PageLoad.AbortTiming.Close"/>
   <affected-histogram name="PageLoad.AbortTiming.ForwardBackNavigation"/>
   <affected-histogram name="PageLoad.AbortTiming.NewNavigation"/>
@@ -100013,6 +100077,16 @@
       name="PageLoad.AbortTiming.UnknownNavigation.BeforeCommit"/>
 </histogram_suffixes>
 
+<histogram_suffixes name="PageLoadMetricsCacheInfo" separator=".">
+  <suffix name="NoStore" label="Main resource had cache-control: no-store"/>
+  <affected-histogram
+      name="PageLoad.PaintTiming.NavigationToFirstContentfulPaint"/>
+  <affected-histogram
+      name="PageLoad.PaintTiming.NavigationToFirstContentfulPaint.LoadType.ForwardBackNavigation"/>
+  <affected-histogram
+      name="PageLoad.ParseTiming.NavigationToParseStart.LoadType.ForwardBackNavigation"/>
+</histogram_suffixes>
+
 <histogram_suffixes name="PageLoadMetricsClients" separator="."
     ordering="prefix">
   <affected-histogram
diff --git a/tools/perf/benchmarks/page_cycler.py b/tools/perf/benchmarks/page_cycler.py
index e888314..a62424f 100644
--- a/tools/perf/benchmarks/page_cycler.py
+++ b/tools/perf/benchmarks/page_cycler.py
@@ -138,13 +138,14 @@
   options = {'pageset_repeat': 3}
 
   @classmethod
-  def ShouldDisable(cls, possible_browser):  # http://crbug.com/597656
-    if (possible_browser.browser_type == 'reference' and
-        possible_browser.platform.GetDeviceTypeName() == 'Nexus 5X'):
-      return True
-    # http://crbug.com/616781
+  def ShouldDisable(cls, possible_browser):
+    if possible_browser.browser_type == 'reference':
+      if possible_browser.platform.GetDeviceTypeName() == 'Nexus 5X':
+        return True  # http://crbug.com/597656
+      if possible_browser.platform.GetOSVersionName() == 'yosemite':
+        return True  # http://crbug.com/634337
     if possible_browser.platform.GetDeviceTypeName() == 'AOSP on BullHead':
-      return True
+      return True  # http://crbug.com/616781
     return False
 
   @classmethod
diff --git a/tools/perf/benchmarks/system_health_smoke_test.py b/tools/perf/benchmarks/system_health_smoke_test.py
index c905d8c..5975313 100644
--- a/tools/perf/benchmarks/system_health_smoke_test.py
+++ b/tools/perf/benchmarks/system_health_smoke_test.py
@@ -32,7 +32,7 @@
 
 
 _DISABLED_TESTS = frozenset({
-  # crbug.com/622409
+  # crbug.com/634389
   'benchmarks.system_health_smoke_test.SystemHealthBenchmarkSmokeTest.system_health.memory_desktop.browse:news:cnn',  # pylint: disable=line-too-long
   # crbug.com/629123
   'benchmarks.system_health_smoke_test.SystemHealthBenchmarkSmokeTest.system_health.memory_mobile.browse:news:hackernews',  # pylint: disable=line-too-long
diff --git a/tools/perf/benchmarks/tab_switching.py b/tools/perf/benchmarks/tab_switching.py
index 2cd77df..689ac16 100644
--- a/tools/perf/benchmarks/tab_switching.py
+++ b/tools/perf/benchmarks/tab_switching.py
@@ -49,6 +49,7 @@
 
 
 @benchmark.Disabled('android')  # http://crbug.com/460084
+@benchmark.Disabled('mac-reference')  # http://crbug.com/634360
 @benchmark.Enabled('has tabs')
 class TabSwitchingFiveBlankTabs(perf_benchmark.PerfBenchmark):
   """This test records the MPArch.RWH_TabSwitchPaintDuration histogram.
@@ -68,8 +69,8 @@
 
 
 @benchmark.Enabled('has tabs')
-# http://crbug.com/460084, http://crbug.com/488067
-@benchmark.Disabled('android', 'linux')
+# http://crbug.com/460084, http://crbug.com/488067, http://crbug.com/634347
+@benchmark.Disabled('android', 'linux', 'mac-reference')
 class TabSwitchingToughEnergyCases(perf_benchmark.PerfBenchmark):
   """This test records the MPArch.RWH_TabSwitchPaintDuration histogram.
 
diff --git a/tools/valgrind/chrome_tests.py b/tools/valgrind/chrome_tests.py
index 458acfd2..c7f6d6c8 100755
--- a/tools/valgrind/chrome_tests.py
+++ b/tools/valgrind/chrome_tests.py
@@ -453,9 +453,6 @@
   def TestSql(self):
     return self.SimpleTest("chrome", "sql_unittests")
 
-  def TestSync(self):
-    return self.SimpleTest("chrome", "sync_unit_tests")
-
   def TestLinuxSandbox(self):
     return self.SimpleTest("sandbox", "sandbox_linux_unittests")
 
@@ -709,7 +706,6 @@
     "sandbox": TestLinuxSandbox, "sandbox_linux_unittests": TestLinuxSandbox,
     "skia": TestSkia,            "skia_unittests": TestSkia,
     "sql": TestSql,              "sql_unittests": TestSql,
-    "sync": TestSync,            "sync_unit_tests": TestSync,
     "sync_integration_tests": TestSyncIntegration,
     "sync_integration": TestSyncIntegration,
     "ui_base_unit": TestUIBaseUnit,       "ui_base_unittests": TestUIBaseUnit,
@@ -735,6 +731,8 @@
                          "as well.")
   parser.add_option("--baseline", action="store_true", default=False,
                     help="generate baseline data instead of validating")
+  parser.add_option("-f", "--force", action="store_true", default=False,
+                    help="run a broken test anyway")
   parser.add_option("--gtest_filter",
                     help="additional arguments to --gtest_filter")
   parser.add_option("--gtest_repeat", help="argument for --gtest_repeat")
@@ -793,7 +791,59 @@
   if len(options.test) != 1 and options.gtest_filter:
     parser.error("--gtest_filter and multiple tests don't make sense together")
 
+  BROKEN_TESTS = {
+    'drmemory_light': [
+      'addressinput',
+      'aura',
+      'base_unittests',
+      'cc',
+      'components', # x64 only?
+      'content',
+      'gfx',
+      'mojo_public_bindings',
+    ],
+    'drmemory_full': [
+      'addressinput',
+      'aura',
+      'base_unittests',
+      'blink_heap',
+      'blink_platform',
+      'browser_tests',
+      'cast',
+      'cc',
+      'chromedriver',
+      'compositor',
+      'content',
+      'content_browsertests',
+      'device',
+      'events',
+      'extensions',
+      'gfx',
+      'google_apis',
+      'gpu',
+      'ipc_tests',
+      'jingle',
+      'keyboard',
+      'media',
+      'midi',
+      'mojo_common',
+      'mojo_public_bindings',
+      'mojo_public_sysperf',
+      'mojo_public_system',
+      'mojo_system',
+      'net',
+      'remoting',
+      'unit',
+      'url',
+    ],
+  }
+
   for t in options.test:
+    if t in BROKEN_TESTS[options.valgrind_tool] and not options.force:
+      logging.info("Skipping broken %s test %s -- see crbug.com/633693" %
+                   (options.valgrind_tool, t))
+      return 0
+
     tests = ChromeTests(options, args, t)
     ret = tests.Run()
     if ret: return ret
diff --git a/ui/android/resources/resource_manager_impl_unittest.cc b/ui/android/resources/resource_manager_impl_unittest.cc
index e3b6974..3fca7da 100644
--- a/ui/android/resources/resource_manager_impl_unittest.cc
+++ b/ui/android/resources/resource_manager_impl_unittest.cc
@@ -52,7 +52,7 @@
     canvas.drawColor(SK_ColorWHITE);
     small_bitmap.setImmutable();
 
-    OnResourceReady(NULL, NULL, res_type, res_id,
+    OnResourceReady(nullptr, nullptr, res_type, res_id,
                     gfx::ConvertToJavaBitmap(&small_bitmap), 0, 0, 0, 0, 0, 0,
                     0, 0);
   }
@@ -103,7 +103,9 @@
     resource_manager_.Init(host_.get());
   }
 
-  ~ResourceManagerTest() override { window_android_->Destroy(NULL, NULL); }
+  ~ResourceManagerTest() override {
+    window_android_->Destroy(nullptr, nullptr);
+  }
 
   void PreloadResource(ui::SystemUIResourceType type) {
     resource_manager_.PreloadResource(ui::ANDROID_RESOURCE_TYPE_SYSTEM, type);
diff --git a/ui/compositor/compositor.cc b/ui/compositor/compositor.cc
index 846bab0..ee97043 100644
--- a/ui/compositor/compositor.cc
+++ b/ui/compositor/compositor.cc
@@ -130,6 +130,8 @@
 #elif defined(OS_MACOSX)
   settings.renderer_settings.release_overlay_resources_after_gpu_query = true;
 #endif
+  settings.renderer_settings.gl_composited_texture_quad_border =
+      command_line->HasSwitch(cc::switches::kGlCompositedTextureQuadBorder);
 
   // These flags should be mirrored by renderer versions in content/renderer/.
   settings.initial_debug_state.show_debug_borders =
diff --git a/ui/gfx/BUILD.gn b/ui/gfx/BUILD.gn
index 8657405..bf496f5 100644
--- a/ui/gfx/BUILD.gn
+++ b/ui/gfx/BUILD.gn
@@ -265,6 +265,7 @@
     "//skia",
     "//third_party/harfbuzz-ng",
     "//third_party/libpng",
+    "//third_party/qcms",
     "//third_party/zlib",
   ]
 
diff --git a/ui/gfx/DEPS b/ui/gfx/DEPS
index 27aa7392f..73c5294 100644
--- a/ui/gfx/DEPS
+++ b/ui/gfx/DEPS
@@ -3,6 +3,7 @@
   "+skia/ext",
   "+third_party/harfbuzz-ng",
   "+third_party/skia",
+  "+third_party/qcms",
   "+ui/ios",
 
   "-testing/gmock",
diff --git a/ui/gfx/color_transform.cc b/ui/gfx/color_transform.cc
index f513d4d..7e5f05a7 100644
--- a/ui/gfx/color_transform.cc
+++ b/ui/gfx/color_transform.cc
@@ -8,7 +8,15 @@
 
 #include "base/logging.h"
 #include "ui/gfx/color_space.h"
+#include "ui/gfx/icc_profile.h"
 #include "ui/gfx/transform.h"
+#include "third_party/qcms/src/qcms.h"
+
+#ifndef THIS_MUST_BE_INCLUDED_AFTER_QCMS_H
+extern "C" {
+#include "third_party/qcms/src/chain.h"
+};
+#endif
 
 namespace gfx {
 
@@ -178,7 +186,7 @@
                   dest_response.y() / source_response.y(),
                   dest_response.z() / source_response.z());
 
-  return bradford * adapter * Invert(bradford) * ret;
+  return Invert(bradford) * adapter * bradford * ret;
 }
 
 GFX_EXPORT float FromLinear(ColorSpace::TransferID id, float v) {
@@ -547,14 +555,104 @@
   Transform c_;
 };
 
+class QCMSColorTransform : public ColorTransform {
+ public:
+  // Takes ownership of the profiles
+  QCMSColorTransform(qcms_profile* from, qcms_profile* to)
+      : from_(from), to_(to) {}
+  ~QCMSColorTransform() {
+    qcms_profile_release(from_);
+    qcms_profile_release(to_);
+  }
+  void transform(TriStim* colors, size_t num) override {
+    CHECK(sizeof(TriStim) == sizeof(float[3]));
+    // QCMS doesn't like numbers outside 0..1
+    for (size_t i = 0; i < num; i++) {
+      colors[i].set_x(fmin(1.0f, fmax(0.0f, colors[i].x())));
+      colors[i].set_y(fmin(1.0f, fmax(0.0f, colors[i].y())));
+      colors[i].set_z(fmin(1.0f, fmax(0.0f, colors[i].z())));
+    }
+    qcms_chain_transform(from_, to_, reinterpret_cast<float*>(colors),
+                         reinterpret_cast<float*>(colors), num * 3);
+  }
+
+ private:
+  qcms_profile *from_, *to_;
+};
+
+class ChainColorTransform : public ColorTransform {
+ public:
+  ChainColorTransform(std::unique_ptr<ColorTransform> a,
+                      std::unique_ptr<ColorTransform> b)
+      : a_(std::move(a)), b_(std::move(b)) {}
+
+ private:
+  void transform(TriStim* colors, size_t num) override {
+    a_->transform(colors, num);
+    b_->transform(colors, num);
+  }
+  std::unique_ptr<ColorTransform> a_;
+  std::unique_ptr<ColorTransform> b_;
+};
+
+qcms_profile* GetQCMSProfileIfAvailable(const ColorSpace& color_space) {
+  ICCProfile icc_profile = ICCProfile::FromColorSpace(color_space);
+  if (icc_profile.GetData().empty())
+    return nullptr;
+  return qcms_profile_from_memory(icc_profile.GetData().data(),
+                                  icc_profile.GetData().size());
+}
+
+qcms_profile* GetXYZD50Profile() {
+  // QCMS is trixy, it has a datatype called qcms_CIE_xyY, but what it expects
+  // is in fact not xyY color coordinates, it just wants the x/y values of the
+  // primaries with Y equal to 1.0.
+  qcms_CIE_xyYTRIPLE xyz;
+  qcms_CIE_xyY w;
+  xyz.red.x = 1.0f;
+  xyz.red.y = 0.0f;
+  xyz.red.Y = 1.0f;
+  xyz.green.x = 0.0f;
+  xyz.green.y = 1.0f;
+  xyz.green.Y = 1.0f;
+  xyz.blue.x = 0.0f;
+  xyz.blue.y = 0.0f;
+  xyz.blue.Y = 1.0f;
+  w.x = 0.34567f;
+  w.y = 0.35850f;
+  w.Y = 1.0f;
+  return qcms_profile_create_rgb_with_gamma(w, xyz, 1.0f);
+}
+
 std::unique_ptr<ColorTransform> ColorTransform::NewColorTransform(
     const ColorSpace& from,
     const ColorSpace& to,
     Intent intent) {
-  // TODO(Hubbe): Check if from and/or to can be mapped to ICC profiles and
-  // provide better transforms in those cases.
-  return std::unique_ptr<ColorTransform>(
-      new ColorSpaceToColorSpaceTransform(from, to, intent));
+  qcms_profile* from_profile = GetQCMSProfileIfAvailable(from);
+  qcms_profile* to_profile = GetQCMSProfileIfAvailable(to);
+  if (from_profile) {
+    if (to_profile) {
+      return std::unique_ptr<ColorTransform>(
+          new QCMSColorTransform(from_profile, to_profile));
+    } else {
+      return std::unique_ptr<ColorTransform>(new ChainColorTransform(
+          std::unique_ptr<ColorTransform>(
+              new QCMSColorTransform(from_profile, GetXYZD50Profile())),
+          std::unique_ptr<ColorTransform>(new ColorSpaceToColorSpaceTransform(
+              ColorSpace::CreateXYZD50(), to, intent))));
+    }
+  } else {
+    if (to_profile) {
+      return std::unique_ptr<ColorTransform>(new ChainColorTransform(
+          std::unique_ptr<ColorTransform>(new ColorSpaceToColorSpaceTransform(
+              from, ColorSpace::CreateXYZD50(), intent)),
+          std::unique_ptr<ColorTransform>(
+              new QCMSColorTransform(GetXYZD50Profile(), to_profile))));
+    } else {
+      return std::unique_ptr<ColorTransform>(
+          new ColorSpaceToColorSpaceTransform(from, to, intent));
+    }
+  }
 }
 
 }  // namespace gfx
diff --git a/ui/gfx/color_transform_unittest.cc b/ui/gfx/color_transform_unittest.cc
index 0d686e0..d943c7d 100644
--- a/ui/gfx/color_transform_unittest.cc
+++ b/ui/gfx/color_transform_unittest.cc
@@ -2,9 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "base/logging.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/gfx/color_space.h"
 #include "ui/gfx/color_transform.h"
+#include "ui/gfx/icc_profile.h"
 #include "ui/gfx/transform.h"
 
 namespace gfx {
@@ -78,6 +80,290 @@
   EXPECT_GT(tmp.z(), tmp.y());
 }
 
+unsigned char srgb_icc_data[] = {
+    0x00, 0x00, 0x0b, 0xe8, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+    0x6d, 0x6e, 0x74, 0x72, 0x52, 0x47, 0x42, 0x20, 0x58, 0x59, 0x5a, 0x20,
+    0x07, 0xd9, 0x00, 0x03, 0x00, 0x1b, 0x00, 0x15, 0x00, 0x24, 0x00, 0x1f,
+    0x61, 0x63, 0x73, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf6, 0xd6,
+    0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0xd3, 0x2d, 0x00, 0x00, 0x00, 0x00,
+    0x12, 0xe2, 0xc7, 0xe9, 0xc6, 0x02, 0x6e, 0x10, 0x5e, 0xdb, 0x15, 0x15,
+    0x9c, 0x6f, 0x26, 0xed, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10,
+    0x64, 0x65, 0x73, 0x63, 0x00, 0x00, 0x01, 0x44, 0x00, 0x00, 0x00, 0x79,
+    0x62, 0x58, 0x59, 0x5a, 0x00, 0x00, 0x01, 0xc0, 0x00, 0x00, 0x00, 0x14,
+    0x62, 0x54, 0x52, 0x43, 0x00, 0x00, 0x01, 0xd4, 0x00, 0x00, 0x08, 0x0c,
+    0x67, 0x54, 0x52, 0x43, 0x00, 0x00, 0x01, 0xd4, 0x00, 0x00, 0x08, 0x0c,
+    0x72, 0x54, 0x52, 0x43, 0x00, 0x00, 0x01, 0xd4, 0x00, 0x00, 0x08, 0x0c,
+    0x64, 0x6d, 0x64, 0x64, 0x00, 0x00, 0x09, 0xe0, 0x00, 0x00, 0x00, 0x88,
+    0x67, 0x58, 0x59, 0x5a, 0x00, 0x00, 0x0a, 0x68, 0x00, 0x00, 0x00, 0x14,
+    0x6c, 0x75, 0x6d, 0x69, 0x00, 0x00, 0x0a, 0x7c, 0x00, 0x00, 0x00, 0x14,
+    0x6d, 0x65, 0x61, 0x73, 0x00, 0x00, 0x0a, 0x90, 0x00, 0x00, 0x00, 0x24,
+    0x62, 0x6b, 0x70, 0x74, 0x00, 0x00, 0x0a, 0xb4, 0x00, 0x00, 0x00, 0x14,
+    0x72, 0x58, 0x59, 0x5a, 0x00, 0x00, 0x0a, 0xc8, 0x00, 0x00, 0x00, 0x14,
+    0x74, 0x65, 0x63, 0x68, 0x00, 0x00, 0x0a, 0xdc, 0x00, 0x00, 0x00, 0x0c,
+    0x76, 0x75, 0x65, 0x64, 0x00, 0x00, 0x0a, 0xe8, 0x00, 0x00, 0x00, 0x87,
+    0x77, 0x74, 0x70, 0x74, 0x00, 0x00, 0x0b, 0x70, 0x00, 0x00, 0x00, 0x14,
+    0x63, 0x70, 0x72, 0x74, 0x00, 0x00, 0x0b, 0x84, 0x00, 0x00, 0x00, 0x37,
+    0x63, 0x68, 0x61, 0x64, 0x00, 0x00, 0x0b, 0xbc, 0x00, 0x00, 0x00, 0x2c,
+    0x64, 0x65, 0x73, 0x63, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f,
+    0x73, 0x52, 0x47, 0x42, 0x20, 0x49, 0x45, 0x43, 0x36, 0x31, 0x39, 0x36,
+    0x36, 0x2d, 0x32, 0x2d, 0x31, 0x20, 0x62, 0x6c, 0x61, 0x63, 0x6b, 0x20,
+    0x73, 0x63, 0x61, 0x6c, 0x65, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x58, 0x59, 0x5a, 0x20, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x24, 0xa0, 0x00, 0x00, 0x0f, 0x84, 0x00, 0x00, 0xb6, 0xcf,
+    0x63, 0x75, 0x72, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00,
+    0x00, 0x00, 0x00, 0x05, 0x00, 0x0a, 0x00, 0x0f, 0x00, 0x14, 0x00, 0x19,
+    0x00, 0x1e, 0x00, 0x23, 0x00, 0x28, 0x00, 0x2d, 0x00, 0x32, 0x00, 0x37,
+    0x00, 0x3b, 0x00, 0x40, 0x00, 0x45, 0x00, 0x4a, 0x00, 0x4f, 0x00, 0x54,
+    0x00, 0x59, 0x00, 0x5e, 0x00, 0x63, 0x00, 0x68, 0x00, 0x6d, 0x00, 0x72,
+    0x00, 0x77, 0x00, 0x7c, 0x00, 0x81, 0x00, 0x86, 0x00, 0x8b, 0x00, 0x90,
+    0x00, 0x95, 0x00, 0x9a, 0x00, 0x9f, 0x00, 0xa4, 0x00, 0xa9, 0x00, 0xae,
+    0x00, 0xb2, 0x00, 0xb7, 0x00, 0xbc, 0x00, 0xc1, 0x00, 0xc6, 0x00, 0xcb,
+    0x00, 0xd0, 0x00, 0xd5, 0x00, 0xdb, 0x00, 0xe0, 0x00, 0xe5, 0x00, 0xeb,
+    0x00, 0xf0, 0x00, 0xf6, 0x00, 0xfb, 0x01, 0x01, 0x01, 0x07, 0x01, 0x0d,
+    0x01, 0x13, 0x01, 0x19, 0x01, 0x1f, 0x01, 0x25, 0x01, 0x2b, 0x01, 0x32,
+    0x01, 0x38, 0x01, 0x3e, 0x01, 0x45, 0x01, 0x4c, 0x01, 0x52, 0x01, 0x59,
+    0x01, 0x60, 0x01, 0x67, 0x01, 0x6e, 0x01, 0x75, 0x01, 0x7c, 0x01, 0x83,
+    0x01, 0x8b, 0x01, 0x92, 0x01, 0x9a, 0x01, 0xa1, 0x01, 0xa9, 0x01, 0xb1,
+    0x01, 0xb9, 0x01, 0xc1, 0x01, 0xc9, 0x01, 0xd1, 0x01, 0xd9, 0x01, 0xe1,
+    0x01, 0xe9, 0x01, 0xf2, 0x01, 0xfa, 0x02, 0x03, 0x02, 0x0c, 0x02, 0x14,
+    0x02, 0x1d, 0x02, 0x26, 0x02, 0x2f, 0x02, 0x38, 0x02, 0x41, 0x02, 0x4b,
+    0x02, 0x54, 0x02, 0x5d, 0x02, 0x67, 0x02, 0x71, 0x02, 0x7a, 0x02, 0x84,
+    0x02, 0x8e, 0x02, 0x98, 0x02, 0xa2, 0x02, 0xac, 0x02, 0xb6, 0x02, 0xc1,
+    0x02, 0xcb, 0x02, 0xd5, 0x02, 0xe0, 0x02, 0xeb, 0x02, 0xf5, 0x03, 0x00,
+    0x03, 0x0b, 0x03, 0x16, 0x03, 0x21, 0x03, 0x2d, 0x03, 0x38, 0x03, 0x43,
+    0x03, 0x4f, 0x03, 0x5a, 0x03, 0x66, 0x03, 0x72, 0x03, 0x7e, 0x03, 0x8a,
+    0x03, 0x96, 0x03, 0xa2, 0x03, 0xae, 0x03, 0xba, 0x03, 0xc7, 0x03, 0xd3,
+    0x03, 0xe0, 0x03, 0xec, 0x03, 0xf9, 0x04, 0x06, 0x04, 0x13, 0x04, 0x20,
+    0x04, 0x2d, 0x04, 0x3b, 0x04, 0x48, 0x04, 0x55, 0x04, 0x63, 0x04, 0x71,
+    0x04, 0x7e, 0x04, 0x8c, 0x04, 0x9a, 0x04, 0xa8, 0x04, 0xb6, 0x04, 0xc4,
+    0x04, 0xd3, 0x04, 0xe1, 0x04, 0xf0, 0x04, 0xfe, 0x05, 0x0d, 0x05, 0x1c,
+    0x05, 0x2b, 0x05, 0x3a, 0x05, 0x49, 0x05, 0x58, 0x05, 0x67, 0x05, 0x77,
+    0x05, 0x86, 0x05, 0x96, 0x05, 0xa6, 0x05, 0xb5, 0x05, 0xc5, 0x05, 0xd5,
+    0x05, 0xe5, 0x05, 0xf6, 0x06, 0x06, 0x06, 0x16, 0x06, 0x27, 0x06, 0x37,
+    0x06, 0x48, 0x06, 0x59, 0x06, 0x6a, 0x06, 0x7b, 0x06, 0x8c, 0x06, 0x9d,
+    0x06, 0xaf, 0x06, 0xc0, 0x06, 0xd1, 0x06, 0xe3, 0x06, 0xf5, 0x07, 0x07,
+    0x07, 0x19, 0x07, 0x2b, 0x07, 0x3d, 0x07, 0x4f, 0x07, 0x61, 0x07, 0x74,
+    0x07, 0x86, 0x07, 0x99, 0x07, 0xac, 0x07, 0xbf, 0x07, 0xd2, 0x07, 0xe5,
+    0x07, 0xf8, 0x08, 0x0b, 0x08, 0x1f, 0x08, 0x32, 0x08, 0x46, 0x08, 0x5a,
+    0x08, 0x6e, 0x08, 0x82, 0x08, 0x96, 0x08, 0xaa, 0x08, 0xbe, 0x08, 0xd2,
+    0x08, 0xe7, 0x08, 0xfb, 0x09, 0x10, 0x09, 0x25, 0x09, 0x3a, 0x09, 0x4f,
+    0x09, 0x64, 0x09, 0x79, 0x09, 0x8f, 0x09, 0xa4, 0x09, 0xba, 0x09, 0xcf,
+    0x09, 0xe5, 0x09, 0xfb, 0x0a, 0x11, 0x0a, 0x27, 0x0a, 0x3d, 0x0a, 0x54,
+    0x0a, 0x6a, 0x0a, 0x81, 0x0a, 0x98, 0x0a, 0xae, 0x0a, 0xc5, 0x0a, 0xdc,
+    0x0a, 0xf3, 0x0b, 0x0b, 0x0b, 0x22, 0x0b, 0x39, 0x0b, 0x51, 0x0b, 0x69,
+    0x0b, 0x80, 0x0b, 0x98, 0x0b, 0xb0, 0x0b, 0xc8, 0x0b, 0xe1, 0x0b, 0xf9,
+    0x0c, 0x12, 0x0c, 0x2a, 0x0c, 0x43, 0x0c, 0x5c, 0x0c, 0x75, 0x0c, 0x8e,
+    0x0c, 0xa7, 0x0c, 0xc0, 0x0c, 0xd9, 0x0c, 0xf3, 0x0d, 0x0d, 0x0d, 0x26,
+    0x0d, 0x40, 0x0d, 0x5a, 0x0d, 0x74, 0x0d, 0x8e, 0x0d, 0xa9, 0x0d, 0xc3,
+    0x0d, 0xde, 0x0d, 0xf8, 0x0e, 0x13, 0x0e, 0x2e, 0x0e, 0x49, 0x0e, 0x64,
+    0x0e, 0x7f, 0x0e, 0x9b, 0x0e, 0xb6, 0x0e, 0xd2, 0x0e, 0xee, 0x0f, 0x09,
+    0x0f, 0x25, 0x0f, 0x41, 0x0f, 0x5e, 0x0f, 0x7a, 0x0f, 0x96, 0x0f, 0xb3,
+    0x0f, 0xcf, 0x0f, 0xec, 0x10, 0x09, 0x10, 0x26, 0x10, 0x43, 0x10, 0x61,
+    0x10, 0x7e, 0x10, 0x9b, 0x10, 0xb9, 0x10, 0xd7, 0x10, 0xf5, 0x11, 0x13,
+    0x11, 0x31, 0x11, 0x4f, 0x11, 0x6d, 0x11, 0x8c, 0x11, 0xaa, 0x11, 0xc9,
+    0x11, 0xe8, 0x12, 0x07, 0x12, 0x26, 0x12, 0x45, 0x12, 0x64, 0x12, 0x84,
+    0x12, 0xa3, 0x12, 0xc3, 0x12, 0xe3, 0x13, 0x03, 0x13, 0x23, 0x13, 0x43,
+    0x13, 0x63, 0x13, 0x83, 0x13, 0xa4, 0x13, 0xc5, 0x13, 0xe5, 0x14, 0x06,
+    0x14, 0x27, 0x14, 0x49, 0x14, 0x6a, 0x14, 0x8b, 0x14, 0xad, 0x14, 0xce,
+    0x14, 0xf0, 0x15, 0x12, 0x15, 0x34, 0x15, 0x56, 0x15, 0x78, 0x15, 0x9b,
+    0x15, 0xbd, 0x15, 0xe0, 0x16, 0x03, 0x16, 0x26, 0x16, 0x49, 0x16, 0x6c,
+    0x16, 0x8f, 0x16, 0xb2, 0x16, 0xd6, 0x16, 0xfa, 0x17, 0x1d, 0x17, 0x41,
+    0x17, 0x65, 0x17, 0x89, 0x17, 0xae, 0x17, 0xd2, 0x17, 0xf7, 0x18, 0x1b,
+    0x18, 0x40, 0x18, 0x65, 0x18, 0x8a, 0x18, 0xaf, 0x18, 0xd5, 0x18, 0xfa,
+    0x19, 0x20, 0x19, 0x45, 0x19, 0x6b, 0x19, 0x91, 0x19, 0xb7, 0x19, 0xdd,
+    0x1a, 0x04, 0x1a, 0x2a, 0x1a, 0x51, 0x1a, 0x77, 0x1a, 0x9e, 0x1a, 0xc5,
+    0x1a, 0xec, 0x1b, 0x14, 0x1b, 0x3b, 0x1b, 0x63, 0x1b, 0x8a, 0x1b, 0xb2,
+    0x1b, 0xda, 0x1c, 0x02, 0x1c, 0x2a, 0x1c, 0x52, 0x1c, 0x7b, 0x1c, 0xa3,
+    0x1c, 0xcc, 0x1c, 0xf5, 0x1d, 0x1e, 0x1d, 0x47, 0x1d, 0x70, 0x1d, 0x99,
+    0x1d, 0xc3, 0x1d, 0xec, 0x1e, 0x16, 0x1e, 0x40, 0x1e, 0x6a, 0x1e, 0x94,
+    0x1e, 0xbe, 0x1e, 0xe9, 0x1f, 0x13, 0x1f, 0x3e, 0x1f, 0x69, 0x1f, 0x94,
+    0x1f, 0xbf, 0x1f, 0xea, 0x20, 0x15, 0x20, 0x41, 0x20, 0x6c, 0x20, 0x98,
+    0x20, 0xc4, 0x20, 0xf0, 0x21, 0x1c, 0x21, 0x48, 0x21, 0x75, 0x21, 0xa1,
+    0x21, 0xce, 0x21, 0xfb, 0x22, 0x27, 0x22, 0x55, 0x22, 0x82, 0x22, 0xaf,
+    0x22, 0xdd, 0x23, 0x0a, 0x23, 0x38, 0x23, 0x66, 0x23, 0x94, 0x23, 0xc2,
+    0x23, 0xf0, 0x24, 0x1f, 0x24, 0x4d, 0x24, 0x7c, 0x24, 0xab, 0x24, 0xda,
+    0x25, 0x09, 0x25, 0x38, 0x25, 0x68, 0x25, 0x97, 0x25, 0xc7, 0x25, 0xf7,
+    0x26, 0x27, 0x26, 0x57, 0x26, 0x87, 0x26, 0xb7, 0x26, 0xe8, 0x27, 0x18,
+    0x27, 0x49, 0x27, 0x7a, 0x27, 0xab, 0x27, 0xdc, 0x28, 0x0d, 0x28, 0x3f,
+    0x28, 0x71, 0x28, 0xa2, 0x28, 0xd4, 0x29, 0x06, 0x29, 0x38, 0x29, 0x6b,
+    0x29, 0x9d, 0x29, 0xd0, 0x2a, 0x02, 0x2a, 0x35, 0x2a, 0x68, 0x2a, 0x9b,
+    0x2a, 0xcf, 0x2b, 0x02, 0x2b, 0x36, 0x2b, 0x69, 0x2b, 0x9d, 0x2b, 0xd1,
+    0x2c, 0x05, 0x2c, 0x39, 0x2c, 0x6e, 0x2c, 0xa2, 0x2c, 0xd7, 0x2d, 0x0c,
+    0x2d, 0x41, 0x2d, 0x76, 0x2d, 0xab, 0x2d, 0xe1, 0x2e, 0x16, 0x2e, 0x4c,
+    0x2e, 0x82, 0x2e, 0xb7, 0x2e, 0xee, 0x2f, 0x24, 0x2f, 0x5a, 0x2f, 0x91,
+    0x2f, 0xc7, 0x2f, 0xfe, 0x30, 0x35, 0x30, 0x6c, 0x30, 0xa4, 0x30, 0xdb,
+    0x31, 0x12, 0x31, 0x4a, 0x31, 0x82, 0x31, 0xba, 0x31, 0xf2, 0x32, 0x2a,
+    0x32, 0x63, 0x32, 0x9b, 0x32, 0xd4, 0x33, 0x0d, 0x33, 0x46, 0x33, 0x7f,
+    0x33, 0xb8, 0x33, 0xf1, 0x34, 0x2b, 0x34, 0x65, 0x34, 0x9e, 0x34, 0xd8,
+    0x35, 0x13, 0x35, 0x4d, 0x35, 0x87, 0x35, 0xc2, 0x35, 0xfd, 0x36, 0x37,
+    0x36, 0x72, 0x36, 0xae, 0x36, 0xe9, 0x37, 0x24, 0x37, 0x60, 0x37, 0x9c,
+    0x37, 0xd7, 0x38, 0x14, 0x38, 0x50, 0x38, 0x8c, 0x38, 0xc8, 0x39, 0x05,
+    0x39, 0x42, 0x39, 0x7f, 0x39, 0xbc, 0x39, 0xf9, 0x3a, 0x36, 0x3a, 0x74,
+    0x3a, 0xb2, 0x3a, 0xef, 0x3b, 0x2d, 0x3b, 0x6b, 0x3b, 0xaa, 0x3b, 0xe8,
+    0x3c, 0x27, 0x3c, 0x65, 0x3c, 0xa4, 0x3c, 0xe3, 0x3d, 0x22, 0x3d, 0x61,
+    0x3d, 0xa1, 0x3d, 0xe0, 0x3e, 0x20, 0x3e, 0x60, 0x3e, 0xa0, 0x3e, 0xe0,
+    0x3f, 0x21, 0x3f, 0x61, 0x3f, 0xa2, 0x3f, 0xe2, 0x40, 0x23, 0x40, 0x64,
+    0x40, 0xa6, 0x40, 0xe7, 0x41, 0x29, 0x41, 0x6a, 0x41, 0xac, 0x41, 0xee,
+    0x42, 0x30, 0x42, 0x72, 0x42, 0xb5, 0x42, 0xf7, 0x43, 0x3a, 0x43, 0x7d,
+    0x43, 0xc0, 0x44, 0x03, 0x44, 0x47, 0x44, 0x8a, 0x44, 0xce, 0x45, 0x12,
+    0x45, 0x55, 0x45, 0x9a, 0x45, 0xde, 0x46, 0x22, 0x46, 0x67, 0x46, 0xab,
+    0x46, 0xf0, 0x47, 0x35, 0x47, 0x7b, 0x47, 0xc0, 0x48, 0x05, 0x48, 0x4b,
+    0x48, 0x91, 0x48, 0xd7, 0x49, 0x1d, 0x49, 0x63, 0x49, 0xa9, 0x49, 0xf0,
+    0x4a, 0x37, 0x4a, 0x7d, 0x4a, 0xc4, 0x4b, 0x0c, 0x4b, 0x53, 0x4b, 0x9a,
+    0x4b, 0xe2, 0x4c, 0x2a, 0x4c, 0x72, 0x4c, 0xba, 0x4d, 0x02, 0x4d, 0x4a,
+    0x4d, 0x93, 0x4d, 0xdc, 0x4e, 0x25, 0x4e, 0x6e, 0x4e, 0xb7, 0x4f, 0x00,
+    0x4f, 0x49, 0x4f, 0x93, 0x4f, 0xdd, 0x50, 0x27, 0x50, 0x71, 0x50, 0xbb,
+    0x51, 0x06, 0x51, 0x50, 0x51, 0x9b, 0x51, 0xe6, 0x52, 0x31, 0x52, 0x7c,
+    0x52, 0xc7, 0x53, 0x13, 0x53, 0x5f, 0x53, 0xaa, 0x53, 0xf6, 0x54, 0x42,
+    0x54, 0x8f, 0x54, 0xdb, 0x55, 0x28, 0x55, 0x75, 0x55, 0xc2, 0x56, 0x0f,
+    0x56, 0x5c, 0x56, 0xa9, 0x56, 0xf7, 0x57, 0x44, 0x57, 0x92, 0x57, 0xe0,
+    0x58, 0x2f, 0x58, 0x7d, 0x58, 0xcb, 0x59, 0x1a, 0x59, 0x69, 0x59, 0xb8,
+    0x5a, 0x07, 0x5a, 0x56, 0x5a, 0xa6, 0x5a, 0xf5, 0x5b, 0x45, 0x5b, 0x95,
+    0x5b, 0xe5, 0x5c, 0x35, 0x5c, 0x86, 0x5c, 0xd6, 0x5d, 0x27, 0x5d, 0x78,
+    0x5d, 0xc9, 0x5e, 0x1a, 0x5e, 0x6c, 0x5e, 0xbd, 0x5f, 0x0f, 0x5f, 0x61,
+    0x5f, 0xb3, 0x60, 0x05, 0x60, 0x57, 0x60, 0xaa, 0x60, 0xfc, 0x61, 0x4f,
+    0x61, 0xa2, 0x61, 0xf5, 0x62, 0x49, 0x62, 0x9c, 0x62, 0xf0, 0x63, 0x43,
+    0x63, 0x97, 0x63, 0xeb, 0x64, 0x40, 0x64, 0x94, 0x64, 0xe9, 0x65, 0x3d,
+    0x65, 0x92, 0x65, 0xe7, 0x66, 0x3d, 0x66, 0x92, 0x66, 0xe8, 0x67, 0x3d,
+    0x67, 0x93, 0x67, 0xe9, 0x68, 0x3f, 0x68, 0x96, 0x68, 0xec, 0x69, 0x43,
+    0x69, 0x9a, 0x69, 0xf1, 0x6a, 0x48, 0x6a, 0x9f, 0x6a, 0xf7, 0x6b, 0x4f,
+    0x6b, 0xa7, 0x6b, 0xff, 0x6c, 0x57, 0x6c, 0xaf, 0x6d, 0x08, 0x6d, 0x60,
+    0x6d, 0xb9, 0x6e, 0x12, 0x6e, 0x6b, 0x6e, 0xc4, 0x6f, 0x1e, 0x6f, 0x78,
+    0x6f, 0xd1, 0x70, 0x2b, 0x70, 0x86, 0x70, 0xe0, 0x71, 0x3a, 0x71, 0x95,
+    0x71, 0xf0, 0x72, 0x4b, 0x72, 0xa6, 0x73, 0x01, 0x73, 0x5d, 0x73, 0xb8,
+    0x74, 0x14, 0x74, 0x70, 0x74, 0xcc, 0x75, 0x28, 0x75, 0x85, 0x75, 0xe1,
+    0x76, 0x3e, 0x76, 0x9b, 0x76, 0xf8, 0x77, 0x56, 0x77, 0xb3, 0x78, 0x11,
+    0x78, 0x6e, 0x78, 0xcc, 0x79, 0x2a, 0x79, 0x89, 0x79, 0xe7, 0x7a, 0x46,
+    0x7a, 0xa5, 0x7b, 0x04, 0x7b, 0x63, 0x7b, 0xc2, 0x7c, 0x21, 0x7c, 0x81,
+    0x7c, 0xe1, 0x7d, 0x41, 0x7d, 0xa1, 0x7e, 0x01, 0x7e, 0x62, 0x7e, 0xc2,
+    0x7f, 0x23, 0x7f, 0x84, 0x7f, 0xe5, 0x80, 0x47, 0x80, 0xa8, 0x81, 0x0a,
+    0x81, 0x6b, 0x81, 0xcd, 0x82, 0x30, 0x82, 0x92, 0x82, 0xf4, 0x83, 0x57,
+    0x83, 0xba, 0x84, 0x1d, 0x84, 0x80, 0x84, 0xe3, 0x85, 0x47, 0x85, 0xab,
+    0x86, 0x0e, 0x86, 0x72, 0x86, 0xd7, 0x87, 0x3b, 0x87, 0x9f, 0x88, 0x04,
+    0x88, 0x69, 0x88, 0xce, 0x89, 0x33, 0x89, 0x99, 0x89, 0xfe, 0x8a, 0x64,
+    0x8a, 0xca, 0x8b, 0x30, 0x8b, 0x96, 0x8b, 0xfc, 0x8c, 0x63, 0x8c, 0xca,
+    0x8d, 0x31, 0x8d, 0x98, 0x8d, 0xff, 0x8e, 0x66, 0x8e, 0xce, 0x8f, 0x36,
+    0x8f, 0x9e, 0x90, 0x06, 0x90, 0x6e, 0x90, 0xd6, 0x91, 0x3f, 0x91, 0xa8,
+    0x92, 0x11, 0x92, 0x7a, 0x92, 0xe3, 0x93, 0x4d, 0x93, 0xb6, 0x94, 0x20,
+    0x94, 0x8a, 0x94, 0xf4, 0x95, 0x5f, 0x95, 0xc9, 0x96, 0x34, 0x96, 0x9f,
+    0x97, 0x0a, 0x97, 0x75, 0x97, 0xe0, 0x98, 0x4c, 0x98, 0xb8, 0x99, 0x24,
+    0x99, 0x90, 0x99, 0xfc, 0x9a, 0x68, 0x9a, 0xd5, 0x9b, 0x42, 0x9b, 0xaf,
+    0x9c, 0x1c, 0x9c, 0x89, 0x9c, 0xf7, 0x9d, 0x64, 0x9d, 0xd2, 0x9e, 0x40,
+    0x9e, 0xae, 0x9f, 0x1d, 0x9f, 0x8b, 0x9f, 0xfa, 0xa0, 0x69, 0xa0, 0xd8,
+    0xa1, 0x47, 0xa1, 0xb6, 0xa2, 0x26, 0xa2, 0x96, 0xa3, 0x06, 0xa3, 0x76,
+    0xa3, 0xe6, 0xa4, 0x56, 0xa4, 0xc7, 0xa5, 0x38, 0xa5, 0xa9, 0xa6, 0x1a,
+    0xa6, 0x8b, 0xa6, 0xfd, 0xa7, 0x6e, 0xa7, 0xe0, 0xa8, 0x52, 0xa8, 0xc4,
+    0xa9, 0x37, 0xa9, 0xa9, 0xaa, 0x1c, 0xaa, 0x8f, 0xab, 0x02, 0xab, 0x75,
+    0xab, 0xe9, 0xac, 0x5c, 0xac, 0xd0, 0xad, 0x44, 0xad, 0xb8, 0xae, 0x2d,
+    0xae, 0xa1, 0xaf, 0x16, 0xaf, 0x8b, 0xb0, 0x00, 0xb0, 0x75, 0xb0, 0xea,
+    0xb1, 0x60, 0xb1, 0xd6, 0xb2, 0x4b, 0xb2, 0xc2, 0xb3, 0x38, 0xb3, 0xae,
+    0xb4, 0x25, 0xb4, 0x9c, 0xb5, 0x13, 0xb5, 0x8a, 0xb6, 0x01, 0xb6, 0x79,
+    0xb6, 0xf0, 0xb7, 0x68, 0xb7, 0xe0, 0xb8, 0x59, 0xb8, 0xd1, 0xb9, 0x4a,
+    0xb9, 0xc2, 0xba, 0x3b, 0xba, 0xb5, 0xbb, 0x2e, 0xbb, 0xa7, 0xbc, 0x21,
+    0xbc, 0x9b, 0xbd, 0x15, 0xbd, 0x8f, 0xbe, 0x0a, 0xbe, 0x84, 0xbe, 0xff,
+    0xbf, 0x7a, 0xbf, 0xf5, 0xc0, 0x70, 0xc0, 0xec, 0xc1, 0x67, 0xc1, 0xe3,
+    0xc2, 0x5f, 0xc2, 0xdb, 0xc3, 0x58, 0xc3, 0xd4, 0xc4, 0x51, 0xc4, 0xce,
+    0xc5, 0x4b, 0xc5, 0xc8, 0xc6, 0x46, 0xc6, 0xc3, 0xc7, 0x41, 0xc7, 0xbf,
+    0xc8, 0x3d, 0xc8, 0xbc, 0xc9, 0x3a, 0xc9, 0xb9, 0xca, 0x38, 0xca, 0xb7,
+    0xcb, 0x36, 0xcb, 0xb6, 0xcc, 0x35, 0xcc, 0xb5, 0xcd, 0x35, 0xcd, 0xb5,
+    0xce, 0x36, 0xce, 0xb6, 0xcf, 0x37, 0xcf, 0xb8, 0xd0, 0x39, 0xd0, 0xba,
+    0xd1, 0x3c, 0xd1, 0xbe, 0xd2, 0x3f, 0xd2, 0xc1, 0xd3, 0x44, 0xd3, 0xc6,
+    0xd4, 0x49, 0xd4, 0xcb, 0xd5, 0x4e, 0xd5, 0xd1, 0xd6, 0x55, 0xd6, 0xd8,
+    0xd7, 0x5c, 0xd7, 0xe0, 0xd8, 0x64, 0xd8, 0xe8, 0xd9, 0x6c, 0xd9, 0xf1,
+    0xda, 0x76, 0xda, 0xfb, 0xdb, 0x80, 0xdc, 0x05, 0xdc, 0x8a, 0xdd, 0x10,
+    0xdd, 0x96, 0xde, 0x1c, 0xde, 0xa2, 0xdf, 0x29, 0xdf, 0xaf, 0xe0, 0x36,
+    0xe0, 0xbd, 0xe1, 0x44, 0xe1, 0xcc, 0xe2, 0x53, 0xe2, 0xdb, 0xe3, 0x63,
+    0xe3, 0xeb, 0xe4, 0x73, 0xe4, 0xfc, 0xe5, 0x84, 0xe6, 0x0d, 0xe6, 0x96,
+    0xe7, 0x1f, 0xe7, 0xa9, 0xe8, 0x32, 0xe8, 0xbc, 0xe9, 0x46, 0xe9, 0xd0,
+    0xea, 0x5b, 0xea, 0xe5, 0xeb, 0x70, 0xeb, 0xfb, 0xec, 0x86, 0xed, 0x11,
+    0xed, 0x9c, 0xee, 0x28, 0xee, 0xb4, 0xef, 0x40, 0xef, 0xcc, 0xf0, 0x58,
+    0xf0, 0xe5, 0xf1, 0x72, 0xf1, 0xff, 0xf2, 0x8c, 0xf3, 0x19, 0xf3, 0xa7,
+    0xf4, 0x34, 0xf4, 0xc2, 0xf5, 0x50, 0xf5, 0xde, 0xf6, 0x6d, 0xf6, 0xfb,
+    0xf7, 0x8a, 0xf8, 0x19, 0xf8, 0xa8, 0xf9, 0x38, 0xf9, 0xc7, 0xfa, 0x57,
+    0xfa, 0xe7, 0xfb, 0x77, 0xfc, 0x07, 0xfc, 0x98, 0xfd, 0x29, 0xfd, 0xba,
+    0xfe, 0x4b, 0xfe, 0xdc, 0xff, 0x6d, 0xff, 0xff, 0x64, 0x65, 0x73, 0x63,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2e, 0x49, 0x45, 0x43, 0x20,
+    0x36, 0x31, 0x39, 0x36, 0x36, 0x2d, 0x32, 0x2d, 0x31, 0x20, 0x44, 0x65,
+    0x66, 0x61, 0x75, 0x6c, 0x74, 0x20, 0x52, 0x47, 0x42, 0x20, 0x43, 0x6f,
+    0x6c, 0x6f, 0x75, 0x72, 0x20, 0x53, 0x70, 0x61, 0x63, 0x65, 0x20, 0x2d,
+    0x20, 0x73, 0x52, 0x47, 0x42, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x58, 0x59, 0x5a, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x62, 0x99,
+    0x00, 0x00, 0xb7, 0x85, 0x00, 0x00, 0x18, 0xda, 0x58, 0x59, 0x5a, 0x20,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x6d, 0x65, 0x61, 0x73, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x02, 0x58, 0x59, 0x5a, 0x20, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x9e, 0x00, 0x00, 0x00, 0xa4, 0x00, 0x00, 0x00, 0x87,
+    0x58, 0x59, 0x5a, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6f, 0xa2,
+    0x00, 0x00, 0x38, 0xf5, 0x00, 0x00, 0x03, 0x90, 0x73, 0x69, 0x67, 0x20,
+    0x00, 0x00, 0x00, 0x00, 0x43, 0x52, 0x54, 0x20, 0x64, 0x65, 0x73, 0x63,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2d, 0x52, 0x65, 0x66, 0x65,
+    0x72, 0x65, 0x6e, 0x63, 0x65, 0x20, 0x56, 0x69, 0x65, 0x77, 0x69, 0x6e,
+    0x67, 0x20, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x20,
+    0x69, 0x6e, 0x20, 0x49, 0x45, 0x43, 0x20, 0x36, 0x31, 0x39, 0x36, 0x36,
+    0x2d, 0x32, 0x2d, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x58, 0x59, 0x5a, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf6, 0xd6,
+    0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0xd3, 0x2d, 0x74, 0x65, 0x78, 0x74,
+    0x00, 0x00, 0x00, 0x00, 0x43, 0x6f, 0x70, 0x79, 0x72, 0x69, 0x67, 0x68,
+    0x74, 0x20, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x74, 0x69, 0x6f,
+    0x6e, 0x61, 0x6c, 0x20, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x20, 0x43, 0x6f,
+    0x6e, 0x73, 0x6f, 0x72, 0x74, 0x69, 0x75, 0x6d, 0x2c, 0x20, 0x32, 0x30,
+    0x30, 0x39, 0x00, 0x00, 0x73, 0x66, 0x33, 0x32, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x01, 0x0c, 0x44, 0x00, 0x00, 0x05, 0xdf, 0xff, 0xff, 0xf3, 0x26,
+    0x00, 0x00, 0x07, 0x94, 0x00, 0x00, 0xfd, 0x8f, 0xff, 0xff, 0xfb, 0xa1,
+    0xff, 0xff, 0xfd, 0xa2, 0x00, 0x00, 0x03, 0xdb, 0x00, 0x00, 0xc0, 0x75};
+
+TEST(SimpleColorSpace, BT709toSRGBICC) {
+  ICCProfile srgb_icc = ICCProfile::FromData(
+      reinterpret_cast<char*>(srgb_icc_data), arraysize(srgb_icc_data));
+
+  ColorSpace bt709 = ColorSpace::CreateREC709();
+  ColorSpace sRGB = srgb_icc.GetColorSpace();
+  std::unique_ptr<ColorTransform> t(ColorTransform::NewColorTransform(
+      bt709, sRGB, ColorTransform::Intent::ABSOLUTE));
+
+  ColorTransform::TriStim tmp(16.0f / 255.0f, 0.5f, 0.5f);
+  t->transform(&tmp, 1);
+  EXPECT_NEAR(tmp.x(), 0.0f, 0.001f);
+  EXPECT_NEAR(tmp.y(), 0.0f, 0.001f);
+  EXPECT_NEAR(tmp.z(), 0.0f, 0.001f);
+
+  tmp = ColorTransform::TriStim(235.0f / 255.0f, 0.5f, 0.5f);
+  t->transform(&tmp, 1);
+  EXPECT_NEAR(tmp.x(), 1.0f, 0.001f);
+  EXPECT_NEAR(tmp.y(), 1.0f, 0.001f);
+  EXPECT_NEAR(tmp.z(), 1.0f, 0.001f);
+
+  // Test a blue color
+  tmp = ColorTransform::TriStim(128.0f / 255.0f, 240.0f / 255.0f, 0.5f);
+  t->transform(&tmp, 1);
+  EXPECT_GT(tmp.z(), tmp.x());
+  EXPECT_GT(tmp.z(), tmp.y());
+}
+
 TEST(SimpleColorSpace, UnknownToSRGB) {
   ColorSpace unknown;
   ColorSpace sRGB = ColorSpace::CreateSRGB();
diff --git a/ui/gfx/gfx.gyp b/ui/gfx/gfx.gyp
index 3df9eda..620e37a 100644
--- a/ui/gfx/gfx.gyp
+++ b/ui/gfx/gfx.gyp
@@ -82,6 +82,7 @@
         '<(DEPTH)/third_party/icu/icu.gyp:icui18n',
         '<(DEPTH)/third_party/icu/icu.gyp:icuuc',
         '<(DEPTH)/third_party/libpng/libpng.gyp:libpng',
+	'<(DEPTH)//third_party/qcms/qcms.gyp:qcms",
         '<(DEPTH)/third_party/zlib/zlib.gyp:zlib',
         'gfx_geometry',
         'gfx_range',
diff --git a/ui/gfx/icc_profile.cc b/ui/gfx/icc_profile.cc
index cd3e4e8..9fbbdd0 100644
--- a/ui/gfx/icc_profile.cc
+++ b/ui/gfx/icc_profile.cc
@@ -46,11 +46,11 @@
 }
 
 // static
-ICCProfile ICCProfile::FromData(const std::vector<char>& icc_profile_data) {
+ICCProfile ICCProfile::FromData(const char* data, size_t size) {
   ICCProfile icc_profile;
-  if (IsValidProfileLength(icc_profile_data.size())) {
+  if (IsValidProfileLength(size)) {
     icc_profile.valid_ = true;
-    icc_profile.data_ = icc_profile_data;
+    icc_profile.data_.insert(icc_profile.data_.begin(), data, data + size);
   }
   if (!icc_profile.valid_)
     return icc_profile;
diff --git a/ui/gfx/icc_profile.h b/ui/gfx/icc_profile.h
index 3b34ca2..7a2ad768 100644
--- a/ui/gfx/icc_profile.h
+++ b/ui/gfx/icc_profile.h
@@ -8,6 +8,7 @@
 #include <stdint.h>
 #include <vector>
 
+#include "base/gtest_prod_util.h"
 #include "ui/gfx/color_space.h"
 
 #if defined(OS_MACOSX)
@@ -57,7 +58,7 @@
 #endif
 
  private:
-  static ICCProfile FromData(const std::vector<char>& icc_profile);
+  static ICCProfile FromData(const char* icc_profile, size_t size);
   static bool IsValidProfileLength(size_t length);
 
   bool valid_ = false;
@@ -67,6 +68,7 @@
   // profile from a ColorSpace object created from it.
   uint64_t id_ = 0;
 
+  FRIEND_TEST_ALL_PREFIXES(SimpleColorSpace, BT709toSRGBICC);
   friend class ColorSpace;
   friend struct IPC::ParamTraits<gfx::ICCProfile>;
 };
diff --git a/ui/gfx/icc_profile_mac.mm b/ui/gfx/icc_profile_mac.mm
index 92fe8dd..ec51749 100644
--- a/ui/gfx/icc_profile_mac.mm
+++ b/ui/gfx/icc_profile_mac.mm
@@ -24,7 +24,7 @@
   const unsigned char* data = CFDataGetBytePtr(cf_icc_profile);
   std::vector<char> vector_icc_profile;
   vector_icc_profile.assign(data, data + length);
-  return FromData(vector_icc_profile);
+  return FromData(vector_icc_profile.data(), vector_icc_profile.size());
 }
 
 }  // namespace gfx
diff --git a/ui/gfx/icc_profile_win.cc b/ui/gfx/icc_profile_win.cc
index 826ecde..7e1b0ca0 100644
--- a/ui/gfx/icc_profile_win.cc
+++ b/ui/gfx/icc_profile_win.cc
@@ -57,7 +57,8 @@
 void ICCProfile::UpdateCachedProfilesOnBackgroundThread() {
   std::vector<char> icc_profile;
   ReadBestMonitorICCProfile(&icc_profile);
-  gfx::ICCProfile color_space = FromData(icc_profile);
+  gfx::ICCProfile color_space = FromData(
+      icc_profile.data(), icc_profile.size());
 
   base::AutoLock lock(g_best_monitor_color_space_lock.Get());
   g_best_monitor_color_space.Get() = color_space;
diff --git a/ui/gfx/mojo/transform.mojom b/ui/gfx/mojo/transform.mojom
index 1ce0e753..5d6103d 100644
--- a/ui/gfx/mojo/transform.mojom
+++ b/ui/gfx/mojo/transform.mojom
@@ -6,6 +6,6 @@
 
 // See ui/gfx/transform.h.
 struct Transform {
-  // Row major order.
+  // Column major order.
   array<float, 16> matrix;
 };
diff --git a/ui/gfx/mojo/transform.typemap b/ui/gfx/mojo/transform.typemap
index 848cd071..e2f6921 100644
--- a/ui/gfx/mojo/transform.typemap
+++ b/ui/gfx/mojo/transform.typemap
@@ -5,5 +5,8 @@
 mojom = "//ui/gfx/mojo/transform.mojom"
 public_headers = [ "//ui/gfx/transform.h" ]
 traits_headers = [ "//ui/gfx/mojo/transform_struct_traits.h" ]
-public_deps = [ "//ui/gfx" ]
+public_deps = [
+  "//mojo/public/cpp/bindings",
+  "//ui/gfx",
+]
 type_mappings = [ "gfx.mojom.Transform=gfx::Transform" ]
diff --git a/ui/gfx/mojo/transform_struct_traits.h b/ui/gfx/mojo/transform_struct_traits.h
index df51a6f..a55122e 100644
--- a/ui/gfx/mojo/transform_struct_traits.h
+++ b/ui/gfx/mojo/transform_struct_traits.h
@@ -5,26 +5,34 @@
 #ifndef UI_GFX_MOJO_TRANSFORM_STRUCT_TRAITS_H_
 #define UI_GFX_MOJO_TRANSFORM_STRUCT_TRAITS_H_
 
+#include "mojo/public/cpp/bindings/array_traits.h"
 #include "ui/gfx/mojo/transform.mojom.h"
 #include "ui/gfx/transform.h"
 
 namespace mojo {
 
 template <>
+struct ArrayTraits<SkMatrix44> {
+  using Element = float;
+
+  static size_t GetSize(const SkMatrix44& input) { return 16; }
+
+  static float GetAt(const SkMatrix44& input, size_t index) {
+    return input.getFloat(static_cast<int>(index % 4),
+                          static_cast<int>(index / 4));
+  }
+};
+
+template <>
 struct StructTraits<gfx::mojom::Transform, gfx::Transform> {
-  static mojo::Array<float> matrix(const gfx::Transform& transform) {
-    std::vector<float> storage(16);
-    transform.matrix().asRowMajorf(&storage[0]);
-    mojo::Array<float> matrix;
-    matrix.Swap(&storage);
-    return matrix;
+  static const SkMatrix44& matrix(const gfx::Transform& transform) {
+    return transform.matrix();
   }
 
   static bool Read(gfx::mojom::TransformDataView data, gfx::Transform* out) {
-    mojo::Array<float> matrix;
-    if (!data.ReadMatrix(&matrix))
-      return false;
-    out->matrix().setRowMajorf(&matrix.storage()[0]);
+    ArrayDataView<float> matrix;
+    data.GetMatrixDataView(&matrix);
+    out->matrix().setColMajorf(matrix.data());
     return true;
   }
 };
diff --git a/ui/gl/init/BUILD.gn b/ui/gl/init/BUILD.gn
index c7d1e67..baec674 100644
--- a/ui/gl/init/BUILD.gn
+++ b/ui/gl/init/BUILD.gn
@@ -60,8 +60,6 @@
     sources += [
       "gl_factory_ozone.cc",
       "gl_initializer_ozone.cc",
-      "gl_surface_ozone.cc",
-      "gl_surface_ozone.h",
     ]
 
     deps += [ "//ui/ozone" ]
diff --git a/ui/gl/init/gl_factory_ozone.cc b/ui/gl/init/gl_factory_ozone.cc
index 2fdcec5..ca53347 100644
--- a/ui/gl/init/gl_factory_ozone.cc
+++ b/ui/gl/init/gl_factory_ozone.cc
@@ -17,10 +17,8 @@
 #include "ui/gl/gl_surface_egl.h"
 #include "ui/gl/gl_surface_osmesa.h"
 #include "ui/gl/gl_surface_stub.h"
-#include "ui/gl/init/gl_surface_ozone.h"
 #include "ui/ozone/public/ozone_platform.h"
 #include "ui/ozone/public/surface_factory_ozone.h"
-#include "ui/ozone/public/surface_ozone_egl.h"
 
 namespace gl {
 namespace init {
@@ -62,34 +60,6 @@
   return nullptr;
 }
 
-// TODO(kylechar): Remove when all implementations are switched over.
-scoped_refptr<GLSurface> CreateViewGLSurfaceOld(gfx::AcceleratedWidget window) {
-  switch (GetGLImplementation()) {
-    case kGLImplementationEGLGLES2:
-      DCHECK_NE(window, gfx::kNullAcceleratedWidget);
-      return CreateViewGLSurfaceOzone(window);
-    default:
-      NOTREACHED();
-  }
-  return nullptr;
-}
-
-// TODO(kylechar): Remove when all implementations are switched over.
-scoped_refptr<GLSurface> CreateOffscreenGLSurfaceOld(const gfx::Size& size) {
-  switch (GetGLImplementation()) {
-    case kGLImplementationEGLGLES2:
-      if (GLSurfaceEGL::IsEGLSurfacelessContextSupported() &&
-          (size.width() == 0 && size.height() == 0)) {
-        return InitializeGLSurface(new SurfacelessEGL(size));
-      } else {
-        return InitializeGLSurface(new PbufferGLSurfaceEGL(size));
-      }
-    default:
-      NOTREACHED();
-  }
-  return nullptr;
-}
-
 }  // namespace
 
 std::vector<GLImplementation> GetAllowedGLImplementations() {
@@ -121,11 +91,10 @@
     case kGLImplementationEGLGLES2:
       return InitializeGLContext(new GLContextEGL(share_group),
                                  compatible_surface, gpu_preference);
-
     default:
       NOTREACHED();
-      return nullptr;
   }
+  return nullptr;
 }
 
 scoped_refptr<GLSurface> CreateViewGLSurface(gfx::AcceleratedWidget window) {
@@ -134,10 +103,6 @@
   if (HasDefaultImplementation(GetGLImplementation()))
     return CreateDefaultViewGLSurface(window);
 
-  // TODO(kylechar): This is deprecated, remove when possible.
-  if (!GetSurfaceFactory()->UseNewSurfaceAPI())
-    return CreateViewGLSurfaceOld(window);
-
   return GetSurfaceFactory()->CreateViewGLSurface(GetGLImplementation(),
                                                   window);
 }
@@ -156,10 +121,6 @@
   if (HasDefaultImplementation(GetGLImplementation()))
     return CreateDefaultOffscreenGLSurface(size);
 
-  // TODO(kylechar): This is deprecated, remove when possible.
-  if (!GetSurfaceFactory()->UseNewSurfaceAPI())
-    return CreateOffscreenGLSurfaceOld(size);
-
   return GetSurfaceFactory()->CreateOffscreenGLSurface(GetGLImplementation(),
                                                        size);
 }
diff --git a/ui/gl/init/gl_init.gyp b/ui/gl/init/gl_init.gyp
index 78375eb4..2eb113e9 100644
--- a/ui/gl/init/gl_init.gyp
+++ b/ui/gl/init/gl_init.gyp
@@ -38,8 +38,6 @@
         'gl_factory_win.cc',
         'gl_factory_x11.cc',
         'gl_init_export.h',
-        'gl_surface_ozone.cc',
-        'gl_surface_ozone.h',
       ],
       'conditions': [
         ['OS=="mac"', {
diff --git a/ui/gl/init/gl_surface_ozone.cc b/ui/gl/init/gl_surface_ozone.cc
deleted file mode 100644
index a7315be..0000000
--- a/ui/gl/init/gl_surface_ozone.cc
+++ /dev/null
@@ -1,194 +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 "ui/gl/init/gl_surface_ozone.h"
-
-#include <stddef.h>
-
-#include <vector>
-
-#include "base/bind.h"
-#include "base/callback.h"
-#include "base/location.h"
-#include "base/logging.h"
-#include "base/macros.h"
-#include "base/memory/scoped_vector.h"
-#include "base/memory/weak_ptr.h"
-#include "base/threading/worker_pool.h"
-#include "ui/gl/egl_util.h"
-#include "ui/gl/gl_context.h"
-#include "ui/gl/gl_image.h"
-#include "ui/gl/gl_implementation.h"
-#include "ui/gl/gl_surface_egl.h"
-#include "ui/gl/gl_surface_osmesa.h"
-#include "ui/gl/gl_surface_overlay.h"
-#include "ui/gl/gl_surface_stub.h"
-#include "ui/gl/scoped_binders.h"
-#include "ui/gl/scoped_make_current.h"
-#include "ui/ozone/gl/gl_image_ozone_native_pixmap.h"
-#include "ui/ozone/public/native_pixmap.h"
-#include "ui/ozone/public/ozone_platform.h"
-#include "ui/ozone/public/surface_factory_ozone.h"
-#include "ui/ozone/public/surface_ozone_egl.h"
-
-namespace gl {
-
-namespace {
-
-// Helper function for base::Bind to create callback to eglChooseConfig.
-bool EglChooseConfig(EGLDisplay display,
-                     const int32_t* attribs,
-                     EGLConfig* configs,
-                     int32_t config_size,
-                     int32_t* num_configs) {
-  return eglChooseConfig(display, attribs, configs, config_size, num_configs);
-}
-
-// Helper function for base::Bind to create callback to eglGetConfigAttrib.
-bool EglGetConfigAttribute(EGLDisplay display,
-                           EGLConfig config,
-                           int32_t attribute,
-                           int32_t* value) {
-  return eglGetConfigAttrib(display, config, attribute, value);
-}
-
-// Populates EglConfigCallbacks with appropriate callbacks.
-ui::EglConfigCallbacks GetEglConfigCallbacks(EGLDisplay display) {
-  ui::EglConfigCallbacks callbacks;
-  callbacks.choose_config = base::Bind(EglChooseConfig, display);
-  callbacks.get_config_attribute = base::Bind(EglGetConfigAttribute, display);
-  callbacks.get_last_error_string = base::Bind(&ui::GetLastEGLErrorString);
-  return callbacks;
-}
-
-// A thin wrapper around GLSurfaceEGL that owns the EGLNativeWindow.
-class GL_EXPORT GLSurfaceOzoneEGL : public NativeViewGLSurfaceEGL {
- public:
-  GLSurfaceOzoneEGL(std::unique_ptr<ui::SurfaceOzoneEGL> ozone_surface,
-                    gfx::AcceleratedWidget widget);
-
-  // GLSurface:
-  bool Initialize(GLSurface::Format format) override;
-  bool Resize(const gfx::Size& size,
-              float scale_factor,
-              bool has_alpha) override;
-  gfx::SwapResult SwapBuffers() override;
-  bool ScheduleOverlayPlane(int z_order,
-                            gfx::OverlayTransform transform,
-                            GLImage* image,
-                            const gfx::Rect& bounds_rect,
-                            const gfx::RectF& crop_rect) override;
-  EGLConfig GetConfig() override;
-
- private:
-  using NativeViewGLSurfaceEGL::Initialize;
-
-  ~GLSurfaceOzoneEGL() override;
-
-  bool ReinitializeNativeSurface();
-
-  // The native surface. Deleting this is allowed to free the EGLNativeWindow.
-  std::unique_ptr<ui::SurfaceOzoneEGL> ozone_surface_;
-  gfx::AcceleratedWidget widget_;
-
-  DISALLOW_COPY_AND_ASSIGN(GLSurfaceOzoneEGL);
-};
-
-GLSurfaceOzoneEGL::GLSurfaceOzoneEGL(
-    std::unique_ptr<ui::SurfaceOzoneEGL> ozone_surface,
-    gfx::AcceleratedWidget widget)
-    : NativeViewGLSurfaceEGL(ozone_surface->GetNativeWindow()),
-      ozone_surface_(std::move(ozone_surface)),
-      widget_(widget) {}
-
-bool GLSurfaceOzoneEGL::Initialize(GLSurface::Format format) {
-  format_ = format;
-  return Initialize(ozone_surface_->CreateVSyncProvider());
-}
-
-bool GLSurfaceOzoneEGL::Resize(const gfx::Size& size,
-                               float scale_factor,
-                               bool has_alpha) {
-  if (!ozone_surface_->ResizeNativeWindow(size)) {
-    if (!ReinitializeNativeSurface() ||
-        !ozone_surface_->ResizeNativeWindow(size))
-      return false;
-  }
-
-  return NativeViewGLSurfaceEGL::Resize(size, scale_factor, has_alpha);
-}
-
-gfx::SwapResult GLSurfaceOzoneEGL::SwapBuffers() {
-  gfx::SwapResult result = NativeViewGLSurfaceEGL::SwapBuffers();
-  if (result != gfx::SwapResult::SWAP_ACK)
-    return result;
-
-  return ozone_surface_->OnSwapBuffers() ? gfx::SwapResult::SWAP_ACK
-                                         : gfx::SwapResult::SWAP_FAILED;
-}
-
-bool GLSurfaceOzoneEGL::ScheduleOverlayPlane(int z_order,
-                                             gfx::OverlayTransform transform,
-                                             GLImage* image,
-                                             const gfx::Rect& bounds_rect,
-                                             const gfx::RectF& crop_rect) {
-  return image->ScheduleOverlayPlane(widget_, z_order, transform, bounds_rect,
-                                     crop_rect);
-}
-
-EGLConfig GLSurfaceOzoneEGL::GetConfig() {
-  if (!config_) {
-    ui::EglConfigCallbacks callbacks = GetEglConfigCallbacks(GetDisplay());
-    config_ = ozone_surface_->GetEGLSurfaceConfig(callbacks);
-  }
-  if (config_)
-    return config_;
-  return NativeViewGLSurfaceEGL::GetConfig();
-}
-
-GLSurfaceOzoneEGL::~GLSurfaceOzoneEGL() {
-  Destroy();  // The EGL surface must be destroyed before SurfaceOzone.
-}
-
-bool GLSurfaceOzoneEGL::ReinitializeNativeSurface() {
-  std::unique_ptr<ui::ScopedMakeCurrent> scoped_make_current;
-  GLContext* current_context = GLContext::GetCurrent();
-  bool was_current = current_context && current_context->IsCurrent(this);
-  if (was_current) {
-    scoped_make_current.reset(new ui::ScopedMakeCurrent(current_context, this));
-  }
-
-  Destroy();
-  ozone_surface_ = ui::OzonePlatform::GetInstance()
-                       ->GetSurfaceFactoryOzone()
-                       ->CreateEGLSurfaceForWidget(widget_);
-  if (!ozone_surface_) {
-    LOG(ERROR) << "Failed to create native surface.";
-    return false;
-  }
-
-  window_ = ozone_surface_->GetNativeWindow();
-  if (!Initialize(format_)) {
-    LOG(ERROR) << "Failed to initialize.";
-    return false;
-  }
-
-  return true;
-}
-
-}  // namespace
-
-scoped_refptr<GLSurface> CreateViewGLSurfaceOzone(
-    gfx::AcceleratedWidget window) {
-  std::unique_ptr<ui::SurfaceOzoneEGL> surface_ozone =
-      ui::OzonePlatform::GetInstance()
-          ->GetSurfaceFactoryOzone()
-          ->CreateEGLSurfaceForWidget(window);
-  if (!surface_ozone)
-    return nullptr;
-  return InitializeGLSurface(
-      new GLSurfaceOzoneEGL(std::move(surface_ozone), window));
-}
-
-}  // namespace gl
diff --git a/ui/gl/init/gl_surface_ozone.h b/ui/gl/init/gl_surface_ozone.h
deleted file mode 100644
index 3203f30..0000000
--- a/ui/gl/init/gl_surface_ozone.h
+++ /dev/null
@@ -1,25 +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 UI_GL_INIT_GL_SURFACE_OZONE_H_
-#define UI_GL_INIT_GL_SURFACE_OZONE_H_
-
-#include "base/memory/ref_counted.h"
-#include "ui/gfx/native_widget_types.h"
-#include "ui/gl/gl_surface.h"
-
-namespace gl {
-
-// TODO(kylechar): These functions, plus the corresponding GLSurface classes
-// have been moved into //ui/gl/init as a temporary step to break the dependency
-// from //ui/gl to //ui/ozone. Once that dependency is broken the Ozone
-// GLSurface classes should be made into base classes for each Ozone platform to
-// override and moved back to //ui/gl.
-
-scoped_refptr<GLSurface> CreateViewGLSurfaceOzone(
-    gfx::AcceleratedWidget window);
-
-}  // namespace gl
-
-#endif  // UI_GL_INIT_GL_SURFACE_OZONE_H_
diff --git a/ui/ozone/BUILD.gn b/ui/ozone/BUILD.gn
index a35e783a..5f46ca5 100644
--- a/ui/ozone/BUILD.gn
+++ b/ui/ozone/BUILD.gn
@@ -82,8 +82,7 @@
     "public/surface_factory_ozone.cc",
     "public/surface_factory_ozone.h",
     "public/surface_ozone_canvas.h",
-    "public/surface_ozone_egl.cc",
-    "public/surface_ozone_egl.h",
+    "public/swap_completion_callback.h",
     "public/system_input_injector.h",
   ]
 
diff --git a/ui/ozone/common/egl_util.cc b/ui/ozone/common/egl_util.cc
index b33407a..0dd4d332 100644
--- a/ui/ozone/common/egl_util.cc
+++ b/ui/ozone/common/egl_util.cc
@@ -86,27 +86,4 @@
   return config;
 }
 
-void* /* EGLConfig */ ChooseEGLConfig(const EglConfigCallbacks& egl,
-                                      const int32_t* attributes) {
-  void* config;
-  int32_t num_configs;
-  if (!egl.choose_config.Run(attributes, nullptr, 0, &num_configs)) {
-    LOG(ERROR) << "eglChooseConfig failed with error "
-               << egl.get_last_error_string.Run();
-    return nullptr;
-  }
-
-  if (num_configs == 0) {
-    LOG(ERROR) << "No suitable EGL configs found.";
-    return nullptr;
-  }
-
-  if (!egl.choose_config.Run(attributes, &config, 1, &num_configs)) {
-    LOG(ERROR) << "eglChooseConfig failed with error "
-               << egl.get_last_error_string.Run();
-    return nullptr;
-  }
-  return config;
-}
-
 }  // namespace ui
diff --git a/ui/ozone/common/egl_util.h b/ui/ozone/common/egl_util.h
index 64d336c8..99fee71d 100644
--- a/ui/ozone/common/egl_util.h
+++ b/ui/ozone/common/egl_util.h
@@ -6,7 +6,6 @@
 #define UI_OZONE_COMMON_EGL_UTIL_H_
 
 #include "ui/ozone/public/surface_factory_ozone.h"
-#include "ui/ozone/public/surface_ozone_egl.h"
 
 namespace ui {
 
@@ -25,10 +24,6 @@
 void* /* EGLConfig */ ChooseEGLConfig(void* /* EGLConfig */ display,
                                       const int32_t* attributes);
 
-// TODO(kylechar): This is deprecated, delete when all callers are gone.
-void* /* EGLConfig */ ChooseEGLConfig(const EglConfigCallbacks& egl,
-                                      const int32_t* attributes);
-
 }  // namespace ui
 
 #endif  // UI_OZONE_COMMON_EGL_UTIL_H_
diff --git a/ui/ozone/ozone.gyp b/ui/ozone/ozone.gyp
index 485137ae..1f09044 100644
--- a/ui/ozone/ozone.gyp
+++ b/ui/ozone/ozone.gyp
@@ -63,8 +63,7 @@
         'public/surface_factory_ozone.cc',
         'public/surface_factory_ozone.h',
         'public/surface_ozone_canvas.h',
-        'public/surface_ozone_egl.cc',
-        'public/surface_ozone_egl.h',
+        'public/swap_completion_callback.h',
         'public/system_input_injector.h',
       ],
     },
diff --git a/ui/ozone/platform/cast/surface_factory_cast.cc b/ui/ozone/platform/cast/surface_factory_cast.cc
index e6c06c14..7074271 100644
--- a/ui/ozone/platform/cast/surface_factory_cast.cc
+++ b/ui/ozone/platform/cast/surface_factory_cast.cc
@@ -167,10 +167,6 @@
   overlay_bounds_ = display_bounds;
 }
 
-bool SurfaceFactoryCast::UseNewSurfaceAPI() {
-  return true;
-}
-
 scoped_refptr<gl::GLSurface> SurfaceFactoryCast::CreateViewGLSurface(
     gl::GLImplementation implementation,
     gfx::AcceleratedWidget widget) {
diff --git a/ui/ozone/platform/cast/surface_factory_cast.h b/ui/ozone/platform/cast/surface_factory_cast.h
index 67aaad22..632367f 100644
--- a/ui/ozone/platform/cast/surface_factory_cast.h
+++ b/ui/ozone/platform/cast/surface_factory_cast.h
@@ -30,7 +30,6 @@
   ~SurfaceFactoryCast() override;
 
   // SurfaceFactoryOzone implementation:
-  bool UseNewSurfaceAPI() override;
   scoped_refptr<gl::GLSurface> CreateViewGLSurface(
       gl::GLImplementation implementation,
       gfx::AcceleratedWidget widget) override;
diff --git a/ui/ozone/platform/drm/gpu/drm_thread.h b/ui/ozone/platform/drm/gpu/drm_thread.h
index 9580c91..ca91988e 100644
--- a/ui/ozone/platform/drm/gpu/drm_thread.h
+++ b/ui/ozone/platform/drm/gpu/drm_thread.h
@@ -20,7 +20,7 @@
 #include "ui/gfx/vsync_provider.h"
 #include "ui/ozone/common/gpu/ozone_gpu_message_params.h"
 #include "ui/ozone/public/interfaces/device_cursor.mojom.h"
-#include "ui/ozone/public/surface_ozone_egl.h"
+#include "ui/ozone/public/swap_completion_callback.h"
 
 namespace base {
 struct FileDescriptor;
diff --git a/ui/ozone/platform/drm/gpu/drm_window.h b/ui/ozone/platform/drm/gpu/drm_window.h
index 84ee2554..877ff0c7 100644
--- a/ui/ozone/platform/drm/gpu/drm_window.h
+++ b/ui/ozone/platform/drm/gpu/drm_window.h
@@ -16,7 +16,7 @@
 #include "ui/gfx/vsync_provider.h"
 #include "ui/ozone/platform/drm/gpu/overlay_plane.h"
 #include "ui/ozone/platform/drm/gpu/page_flip_request.h"
-#include "ui/ozone/public/surface_ozone_egl.h"
+#include "ui/ozone/public/swap_completion_callback.h"
 
 class SkBitmap;
 
diff --git a/ui/ozone/platform/drm/gpu/drm_window_proxy.h b/ui/ozone/platform/drm/gpu/drm_window_proxy.h
index b358364..40213f4 100644
--- a/ui/ozone/platform/drm/gpu/drm_window_proxy.h
+++ b/ui/ozone/platform/drm/gpu/drm_window_proxy.h
@@ -10,7 +10,7 @@
 #include "base/macros.h"
 #include "ui/gfx/native_widget_types.h"
 #include "ui/gfx/vsync_provider.h"
-#include "ui/ozone/public/surface_ozone_egl.h"
+#include "ui/ozone/public/swap_completion_callback.h"
 
 namespace ui {
 
diff --git a/ui/ozone/platform/drm/gpu/gbm_surface_factory.cc b/ui/ozone/platform/drm/gpu/gbm_surface_factory.cc
index 1633000..df62b301 100644
--- a/ui/ozone/platform/drm/gpu/gbm_surface_factory.cc
+++ b/ui/ozone/platform/drm/gpu/gbm_surface_factory.cc
@@ -54,10 +54,6 @@
   return it->second;
 }
 
-bool GbmSurfaceFactory::UseNewSurfaceAPI() {
-  return true;
-}
-
 scoped_refptr<gl::GLSurface> GbmSurfaceFactory::CreateViewGLSurface(
     gl::GLImplementation implementation,
     gfx::AcceleratedWidget widget) {
diff --git a/ui/ozone/platform/drm/gpu/gbm_surface_factory.h b/ui/ozone/platform/drm/gpu/gbm_surface_factory.h
index f35edf1..0e6a1f7 100644
--- a/ui/ozone/platform/drm/gpu/gbm_surface_factory.h
+++ b/ui/ozone/platform/drm/gpu/gbm_surface_factory.h
@@ -33,7 +33,6 @@
   GbmSurfaceless* GetSurface(gfx::AcceleratedWidget widget) const;
 
   // SurfaceFactoryOzone:
-  bool UseNewSurfaceAPI() override;
   scoped_refptr<gl::GLSurface> CreateViewGLSurface(
       gl::GLImplementation implementation,
       gfx::AcceleratedWidget widget) override;
diff --git a/ui/ozone/platform/drm/gpu/page_flip_request.h b/ui/ozone/platform/drm/gpu/page_flip_request.h
index 5d3d8019..09eb305 100644
--- a/ui/ozone/platform/drm/gpu/page_flip_request.h
+++ b/ui/ozone/platform/drm/gpu/page_flip_request.h
@@ -11,7 +11,7 @@
 #include "base/callback.h"
 #include "base/macros.h"
 #include "ui/gfx/swap_result.h"
-#include "ui/ozone/public/surface_ozone_egl.h"
+#include "ui/ozone/public/swap_completion_callback.h"
 
 namespace ui {
 
diff --git a/ui/ozone/platform/wayland/wayland_surface_factory.cc b/ui/ozone/platform/wayland/wayland_surface_factory.cc
index 5c809ba..80acd19 100644
--- a/ui/ozone/platform/wayland/wayland_surface_factory.cc
+++ b/ui/ozone/platform/wayland/wayland_surface_factory.cc
@@ -17,7 +17,6 @@
 #include "ui/ozone/platform/wayland/wayland_object.h"
 #include "ui/ozone/platform/wayland/wayland_window.h"
 #include "ui/ozone/public/surface_ozone_canvas.h"
-#include "ui/ozone/public/surface_ozone_egl.h"
 
 #if defined(USE_WAYLAND_EGL)
 #include "ui/ozone/platform/wayland/gl_surface_wayland.h"
diff --git a/ui/ozone/platform/x11/x11_surface_factory.cc b/ui/ozone/platform/x11/x11_surface_factory.cc
index 986dda1..f061a7f 100644
--- a/ui/ozone/platform/x11/x11_surface_factory.cc
+++ b/ui/ozone/platform/x11/x11_surface_factory.cc
@@ -125,10 +125,6 @@
 
 X11SurfaceFactory::~X11SurfaceFactory() {}
 
-bool X11SurfaceFactory::UseNewSurfaceAPI() {
-  return true;
-}
-
 scoped_refptr<gl::GLSurface> X11SurfaceFactory::CreateViewGLSurface(
     gl::GLImplementation implementation,
     gfx::AcceleratedWidget widget) {
diff --git a/ui/ozone/platform/x11/x11_surface_factory.h b/ui/ozone/platform/x11/x11_surface_factory.h
index 93620ad4..0a2ffa5 100644
--- a/ui/ozone/platform/x11/x11_surface_factory.h
+++ b/ui/ozone/platform/x11/x11_surface_factory.h
@@ -20,7 +20,6 @@
   ~X11SurfaceFactory() override;
 
   // SurfaceFactoryOzone:
-  bool UseNewSurfaceAPI() override;
   scoped_refptr<gl::GLSurface> CreateViewGLSurface(
       gl::GLImplementation implementation,
       gfx::AcceleratedWidget widget) override;
diff --git a/ui/ozone/public/surface_factory_ozone.cc b/ui/ozone/public/surface_factory_ozone.cc
index 76050437..55e3be9 100644
--- a/ui/ozone/public/surface_factory_ozone.cc
+++ b/ui/ozone/public/surface_factory_ozone.cc
@@ -9,24 +9,17 @@
 #include "base/command_line.h"
 #include "ui/ozone/public/native_pixmap.h"
 #include "ui/ozone/public/surface_ozone_canvas.h"
-#include "ui/ozone/public/surface_ozone_egl.h"
 
 namespace ui {
 
-SurfaceFactoryOzone::SurfaceFactoryOzone() {
-}
+SurfaceFactoryOzone::SurfaceFactoryOzone() {}
 
-SurfaceFactoryOzone::~SurfaceFactoryOzone() {
-}
+SurfaceFactoryOzone::~SurfaceFactoryOzone() {}
 
 intptr_t SurfaceFactoryOzone::GetNativeDisplay() {
   return 0;
 }
 
-bool SurfaceFactoryOzone::UseNewSurfaceAPI() {
-  return true;
-}
-
 scoped_refptr<gl::GLSurface> SurfaceFactoryOzone::CreateViewGLSurface(
     gl::GLImplementation implementation,
     gfx::AcceleratedWidget widget) {
@@ -46,17 +39,6 @@
   return nullptr;
 }
 
-std::unique_ptr<SurfaceOzoneEGL> SurfaceFactoryOzone::CreateEGLSurfaceForWidget(
-    gfx::AcceleratedWidget widget) {
-  return nullptr;
-}
-
-std::unique_ptr<SurfaceOzoneEGL>
-SurfaceFactoryOzone::CreateSurfacelessEGLSurfaceForWidget(
-    gfx::AcceleratedWidget widget) {
-  return nullptr;
-}
-
 std::unique_ptr<SurfaceOzoneCanvas> SurfaceFactoryOzone::CreateCanvasForWidget(
     gfx::AcceleratedWidget widget) {
   return nullptr;
diff --git a/ui/ozone/public/surface_factory_ozone.h b/ui/ozone/public/surface_factory_ozone.h
index 0522b45..de8d5bd 100644
--- a/ui/ozone/public/surface_factory_ozone.h
+++ b/ui/ozone/public/surface_factory_ozone.h
@@ -27,7 +27,6 @@
 
 class NativePixmap;
 class SurfaceOzoneCanvas;
-class SurfaceOzoneEGL;
 
 // The Ozone interface allows external implementations to hook into Chromium to
 // provide a system specific implementation. The Ozone interface supports two
@@ -71,10 +70,6 @@
   // display connection for the native display.
   virtual intptr_t GetNativeDisplay();
 
-  // Checks if platform uses the new surface creation API.
-  // TODO(kylechar): Delete when using all implementations use new surface API.
-  virtual bool UseNewSurfaceAPI();
-
   // Creates a GL surface that renders directly to a view for the specified GL
   // implementation.
   virtual scoped_refptr<gl::GLSurface> CreateViewGLSurface(
@@ -82,7 +77,9 @@
       gfx::AcceleratedWidget widget);
 
   // Creates a GL surface that renders directly into a window with surfaceless
-  // semantics for the specified GL implementation.
+  // semantics for the specified GL implementation. The surface is not backed
+  // by any buffers and is used for overlay-only displays. This will return
+  // nullptr if surfaceless mode unsupported.
   virtual scoped_refptr<gl::GLSurface> CreateSurfacelessViewGLSurface(
       gl::GLImplementation implementation,
       gfx::AcceleratedWidget widget);
@@ -93,20 +90,6 @@
       gl::GLImplementation implementation,
       const gfx::Size& size);
 
-  // Create SurfaceOzoneEGL for the specified gfx::AcceleratedWidget.
-  //
-  // Note: When used from content, this is called in the GPU process. The
-  // platform must support creation of SurfaceOzoneEGL from the GPU process
-  // using only the handle contained in gfx::AcceleratedWidget.
-  virtual std::unique_ptr<SurfaceOzoneEGL> CreateEGLSurfaceForWidget(
-      gfx::AcceleratedWidget widget);
-
-  // Create an EGL surface that isn't backed by any buffers, and is used
-  // for overlay-only displays. This will return NULL if this mode is
-  // not supported.
-  virtual std::unique_ptr<SurfaceOzoneEGL> CreateSurfacelessEGLSurfaceForWidget(
-      gfx::AcceleratedWidget widget);
-
   // Create SurfaceOzoneCanvas for the specified gfx::AcceleratedWidget.
   //
   // Note: The platform must support creation of SurfaceOzoneCanvas from the
diff --git a/ui/ozone/public/surface_ozone_egl.cc b/ui/ozone/public/surface_ozone_egl.cc
deleted file mode 100644
index ba61f4f..0000000
--- a/ui/ozone/public/surface_ozone_egl.cc
+++ /dev/null
@@ -1,20 +0,0 @@
-// Copyright 2015 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 "ui/ozone/public/surface_ozone_egl.h"
-
-namespace ui {
-
-EglConfigCallbacks::EglConfigCallbacks() {}
-
-EglConfigCallbacks::EglConfigCallbacks(const EglConfigCallbacks& other) =
-    default;
-
-EglConfigCallbacks::~EglConfigCallbacks() {}
-
-bool SurfaceOzoneEGL::IsUniversalDisplayLinkDevice() {
-  return false;
-}
-
-}  // namespace ui
diff --git a/ui/ozone/public/surface_ozone_egl.h b/ui/ozone/public/surface_ozone_egl.h
deleted file mode 100644
index a8a6553..0000000
--- a/ui/ozone/public/surface_ozone_egl.h
+++ /dev/null
@@ -1,85 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_OZONE_PUBLIC_SURFACE_OZONE_EGL_H_
-#define UI_OZONE_PUBLIC_SURFACE_OZONE_EGL_H_
-
-#include <memory>
-
-#include "base/callback.h"
-#include "ui/gfx/overlay_transform.h"
-#include "ui/gfx/swap_result.h"
-#include "ui/ozone/ozone_base_export.h"
-
-namespace gfx {
-class Size;
-class VSyncProvider;
-}
-
-namespace ui {
-class NativePixmap;
-
-typedef base::Callback<void(gfx::SwapResult)> SwapCompletionCallback;
-
-// Holds callbacks to functions for configuring EGL on platform.
-struct OZONE_BASE_EXPORT EglConfigCallbacks {
-  EglConfigCallbacks();
-  EglConfigCallbacks(const EglConfigCallbacks& other);
-  ~EglConfigCallbacks();
-  base::Callback<bool(const int32_t* attribs,
-                      void** /* EGLConfig* */ configs,
-                      int32_t config_size,
-                      int32_t* num_configs)>
-      choose_config;
-  base::Callback<
-      bool(void* /* EGLConfig */ config, int32_t attribute, int32_t* value)>
-      get_config_attribute;
-  base::Callback<const char*()> get_last_error_string;
-};
-
-// The platform-specific part of an EGL surface.
-//
-// This class owns any bits that the ozone implementation needs freed when
-// the EGL surface is destroyed.
-class OZONE_BASE_EXPORT SurfaceOzoneEGL {
- public:
-  virtual ~SurfaceOzoneEGL() {}
-
-  // Returns the EGL native window for rendering onto this surface.
-  // This can be used to to create a GLSurface.
-  virtual intptr_t /* EGLNativeWindowType */ GetNativeWindow() = 0;
-
-  // Attempts to resize the EGL native window to match the viewport
-  // size.
-  virtual bool ResizeNativeWindow(const gfx::Size& viewport_size) = 0;
-
-  // Called after we swap buffers. This is usually a no-op but can
-  // be used to present the new front buffer if the platform requires this.
-  virtual bool OnSwapBuffers() = 0;
-
-  // Called after we swap buffers. This is usually a no-op but can
-  // be used to present the new front buffer if the platform requires this.
-  // The callback should be run on the calling thread
-  // (i.e. same thread SwapBuffersAsync is called).
-  virtual void OnSwapBuffersAsync(const SwapCompletionCallback& callback) = 0;
-
-  // Returns a gfx::VsyncProvider for this surface. Note that this may be
-  // called after we have entered the sandbox so if there are operations (e.g.
-  // opening a file descriptor providing vsync events) that must be done
-  // outside of the sandbox, they must have been completed in
-  // InitializeHardware. Returns an empty scoped_ptr on error.
-  virtual std::unique_ptr<gfx::VSyncProvider> CreateVSyncProvider() = 0;
-
-  // Returns true if the surface is created on a UDL device.
-  virtual bool IsUniversalDisplayLinkDevice();
-
-  // Returns the EGL configuration to use for this surface. The default EGL
-  // configuration will be used if this returns nullptr.
-  virtual void* /* EGLConfig */ GetEGLSurfaceConfig(
-      const EglConfigCallbacks& egl) = 0;
-};
-
-}  // namespace ui
-
-#endif  // UI_OZONE_PUBLIC_SURFACE_OZONE_EGL_H_
diff --git a/ui/ozone/public/swap_completion_callback.h b/ui/ozone/public/swap_completion_callback.h
new file mode 100644
index 0000000..8dfc583
--- /dev/null
+++ b/ui/ozone/public/swap_completion_callback.h
@@ -0,0 +1,17 @@
+// 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 UI_OZONE_PUBLIC_SWAP_COMPLETION_CALLBACK_H_
+#define UI_OZONE_PUBLIC_SWAP_COMPLETION_CALLBACK_H_
+
+#include "base/callback.h"
+#include "ui/gfx/swap_result.h"
+
+namespace ui {
+
+using SwapCompletionCallback = base::Callback<void(gfx::SwapResult)>;
+
+}  // namespace ui
+
+#endif  // UI_OZONE_PUBLIC_SWAP_COMPLETION_CALLBACK_H_
diff --git a/ui/views/mus/window_manager_connection.cc b/ui/views/mus/window_manager_connection.cc
index 2389915d..a16ed870 100644
--- a/ui/views/mus/window_manager_connection.cc
+++ b/ui/views/mus/window_manager_connection.cc
@@ -41,7 +41,7 @@
   // we are still valid.
   client_.reset();
   ui::Clipboard::DestroyClipboardForCurrentThread();
-  ui::GpuService::Terminate();
+  gpu_service_.reset();
   lazy_tls_ptr.Pointer()->Set(nullptr);
 
   if (ViewsDelegate::GetInstance()) {
@@ -150,8 +150,7 @@
     : connector_(connector), identity_(identity) {
   lazy_tls_ptr.Pointer()->Set(this);
 
-  ui::GpuService::Initialize(connector);
-
+  gpu_service_ = ui::GpuService::Initialize(connector);
   client_.reset(new ui::WindowTreeClient(this, nullptr, nullptr));
   client_->ConnectViaWindowTreeFactory(connector_);
 
diff --git a/ui/views/mus/window_manager_connection.h b/ui/views/mus/window_manager_connection.h
index 867e97b..69291f7 100644
--- a/ui/views/mus/window_manager_connection.h
+++ b/ui/views/mus/window_manager_connection.h
@@ -24,6 +24,10 @@
 class Connector;
 }
 
+namespace ui {
+class GpuService;
+}
+
 namespace views {
 class ClipboardMus;
 class NativeWidget;
@@ -96,6 +100,7 @@
   shell::Identity identity_;
   std::unique_ptr<ScreenMus> screen_;
   std::unique_ptr<ui::WindowTreeClient> client_;
+  std::unique_ptr<ui::GpuService> gpu_service_;
   // Must be empty on destruction.
   base::ObserverList<PointerWatcher, true> pointer_watchers_;
   base::ObserverList<TouchEventWatcher, true> touch_event_watchers_;
diff --git a/ui/webui/resources/cr_elements/policy/compiled_resources2.gyp b/ui/webui/resources/cr_elements/policy/compiled_resources2.gyp
index 7e71e2bd..b722f17e 100644
--- a/ui/webui/resources/cr_elements/policy/compiled_resources2.gyp
+++ b/ui/webui/resources/cr_elements/policy/compiled_resources2.gyp
@@ -14,6 +14,7 @@
     {
       'target_name': 'cr_policy_pref_behavior',
       'dependencies': [
+        '<(EXTERNS_GYP):settings_private',
         'cr_policy_indicator_behavior',
       ],
       'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
diff --git a/ui/webui/resources/css/roboto.css b/ui/webui/resources/css/roboto.css
index 0ff4df5..00cbd32a 100644
--- a/ui/webui/resources/css/roboto.css
+++ b/ui/webui/resources/css/roboto.css
@@ -2,6 +2,7 @@
  * Use of this source code is governed by a BSD-style license that can be
  * found in the LICENSE file. */
 
+<if expr="not chromeos">
 @font-face {
   font-family: 'Roboto';
   font-style: normal;
@@ -25,3 +26,4 @@
   src: local('Roboto Bold'), local('Roboto-Bold'),
       url(chrome://resources/roboto/roboto-bold.woff2) format('woff2');
 }
+</if>
diff --git a/ui/webui/resources/webui_resources.grd b/ui/webui/resources/webui_resources.grd
index 352b60d..34e3ba8 100644
--- a/ui/webui/resources/webui_resources.grd
+++ b/ui/webui/resources/webui_resources.grd
@@ -17,8 +17,9 @@
       <include name="IDR_WEBUI_JSTEMPLATE_JS" file="js/jstemplate_compiled.js" flattenhtml="true" type="BINDATA" />
       <include name="IDR_WEBUI_ANALYTICS_JS" file="js/analytics.js" flattenhtml="true" type="BINDATA" />
       <!-- Roboto Font. Roboto-Regular and Roboto-Light is already available on
-           Android, and Roboto-Medium is not used on Android. -->
-      <if expr="not android">
+           Android, and Roboto-Medium is not used on Android. All 6 weights of
+           Roboto are available on Chrome OS.-->
+      <if expr="not android and not chromeos">
         <include name="IDR_WEBUI_ROBOTO_ROBOTO_REGULAR_WOFF2" file="roboto/roboto-regular.woff2" type="BINDATA" />
         <include name="IDR_WEBUI_ROBOTO_ROBOTO_MEDIUM_WOFF2" file="roboto/roboto-medium.woff2" type="BINDATA" />
         <include name="IDR_WEBUI_ROBOTO_ROBOTO_BOLD_WOFF2" file="roboto/roboto-bold.woff2" type="BINDATA" />
@@ -240,7 +241,7 @@
       <structure name="IDR_WEBUI_CSS_OVERLAY"
                  file="css/overlay.css" type="chrome_html"
                  flattenhtml="true" />
-      <structure name="IDR_WEBUI_CSS_ROBOTO"
+      <structure name="IDR_WEBUI_CSS_ROBOTO" preprocess="true"
                  file="css/roboto.css" type="chrome_html" />
       <structure name="IDR_WEBUI_CSS_SPINNER"
                  file="css/spinner.css" type="chrome_html"
diff --git a/url/BUILD.gn b/url/BUILD.gn
index 764e3a9..c6020fb 100644
--- a/url/BUILD.gn
+++ b/url/BUILD.gn
@@ -73,12 +73,7 @@
   # ICU support.
   if (use_platform_icu_alternatives) {
     if (is_android) {
-      sources += [
-        "android/url_jni_registrar.cc",
-        "android/url_jni_registrar.h",
-        "url_canon_icu_alternatives_android.cc",
-        "url_canon_icu_alternatives_android.h",
-      ]
+      sources += [ "url_canon_icu_alternatives_android.cc" ]
       deps += [
         ":url_features",
         ":url_java",
diff --git a/url/android/url_jni_registrar.cc b/url/android/url_jni_registrar.cc
deleted file mode 100644
index f594d24..0000000
--- a/url/android/url_jni_registrar.cc
+++ /dev/null
@@ -1,25 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "url/android/url_jni_registrar.h"
-#include "url/url_features.h"
-
-#if BUILDFLAG(USE_PLATFORM_ICU_ALTERNATIVES)
-#include "url/url_canon_icu_alternatives_android.h"
-#endif
-
-namespace url {
-namespace android {
-
-bool RegisterJni(JNIEnv* env) {
-#if BUILDFLAG(USE_PLATFORM_ICU_ALTERNATIVES)
-  return RegisterIcuAlternativesJni(env);
-#endif
-
-  // Do nothing if USE_PLATFORM_ICU_ALTERNATIVES is false.
-  return true;
-}
-
-}  // namespace android
-}  // namespace url
diff --git a/url/android/url_jni_registrar.h b/url/android/url_jni_registrar.h
deleted file mode 100644
index 8fe7ded..0000000
--- a/url/android/url_jni_registrar.h
+++ /dev/null
@@ -1,21 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef URL_ANDROID_URL_JNI_REGISTRAR_H_
-#define URL_ANDROID_URL_JNI_REGISTRAR_H_
-
-#include <jni.h>
-
-#include "url/url_export.h"
-
-namespace url {
-namespace android {
-
-// Register all JNI bindings necessary for url.
-URL_EXPORT bool RegisterJni(JNIEnv* env);
-
-}  // namespace android
-}  // namespace url
-
-#endif  // URL_ANDROID_URL_JNI_REGISTRAR_H_
diff --git a/url/url.gyp b/url/url.gyp
index a7e5b02..12f23f5 100644
--- a/url/url.gyp
+++ b/url/url.gyp
@@ -50,7 +50,6 @@
               ],
               'sources': [
                 'url_canon_icu_alternatives_android.cc',
-                'url_canon_icu_alternatives_android.h',
               ],
             }],
             ['OS == "ios"', {
diff --git a/url/url_canon_icu_alternatives_android.cc b/url/url_canon_icu_alternatives_android.cc
index f43efce5..9536bc7 100644
--- a/url/url_canon_icu_alternatives_android.cc
+++ b/url/url_canon_icu_alternatives_android.cc
@@ -34,8 +34,4 @@
   return true;
 }
 
-bool RegisterIcuAlternativesJni(JNIEnv* env) {
-  return android::RegisterNativesImpl(env);
-}
-
 }  // namespace url
diff --git a/url/url_canon_icu_alternatives_android.h b/url/url_canon_icu_alternatives_android.h
deleted file mode 100644
index 67306db..0000000
--- a/url/url_canon_icu_alternatives_android.h
+++ /dev/null
@@ -1,18 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef URL_URL_CANON_ICU_ALTERNATIVES_ANDROID_H_
-#define URL_URL_CANON_ICU_ALTERNATIVES_ANDROID_H_
-
-#include <jni.h>
-
-namespace url {
-
-// Explicitly register static JNI functions needed when not using ICU.
-bool RegisterIcuAlternativesJni(JNIEnv* env);
-
-}  // namespace url
-
-#endif  // URL_URL_CANON_ICU_ALTERNATIVES_ANDROID_H_
-
diff --git a/url/url_srcs.gypi b/url/url_srcs.gypi
index dfa1e3f..ec1615f 100644
--- a/url/url_srcs.gypi
+++ b/url/url_srcs.gypi
@@ -5,8 +5,6 @@
 {
   'variables': {
     'gurl_sources': [
-      'android/url_jni_registrar.cc',
-      'android/url_jni_registrar.h',
       'gurl.cc',
       'gurl.h',
       'origin.cc',