diff --git a/DEPS b/DEPS
index 44ab9d73..aef1cb1 100644
--- a/DEPS
+++ b/DEPS
@@ -54,7 +54,7 @@
   'checkout_telemetry_dependencies': False,
 
   # libaom provides support for AV1 but the bitstream is not frozen.
-  'checkout_libaom': False,
+  'checkout_libaom': True,
 
   # TODO(dpranke): change to != "small" once != is supported.
   'checkout_traffic_annotation_tools': 'checkout_configuration == "default"',
@@ -130,7 +130,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': 'a12fb2d1ad961877f3fc1ca4b72965394270419d',
+  'catapult_revision': 'cb907fe1fd1b423e8395154f07dc71bab5ac08cc',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libFuzzer
   # and whatever else without interference from each other.
@@ -318,7 +318,7 @@
   },
 
   'src/third_party/depot_tools':
-    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + 'ad64abd69aedabe7da5db9ca6de6fd28fca879d2',
+    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + 'b278ddd9392390c5136079638f7fadb0d6c55f6b',
 
   # DevTools node modules. Used on Linux buildbots only.
   'src/third_party/devtools-node-modules': {
@@ -634,7 +634,7 @@
     Var('chromium_git') + '/external/khronosgroup/webgl.git' + '@' + '05591bbeae6592fd924caec8e728a4ea86cbb8c9',
 
   'src/third_party/webrtc':
-    Var('webrtc_git') + '/src.git' + '@' + '83d27683a83d8c4307ca9275779e822cb4604ccf', # commit position 20628
+    Var('webrtc_git') + '/src.git' + '@' + '31cee3a0d51eed2417dabb7d88ec19ef59444d86', # commit position 20628
 
   'src/third_party/xdg-utils': {
       'url': Var('chromium_git') + '/chromium/deps/xdg-utils.git' + '@' + 'd80274d5869b17b8c9067a1022e4416ee7ed5e0d',
diff --git a/ash/login/ui/login_auth_user_view.cc b/ash/login/ui/login_auth_user_view.cc
index 13be1c8..1abc781 100644
--- a/ash/login/ui/login_auth_user_view.cc
+++ b/ash/login/ui/login_auth_user_view.cc
@@ -115,7 +115,7 @@
   password_view_->UpdateForUser(user);
 
   pin_view_ =
-      new LoginPinView(base::BindRepeating(&LoginPasswordView::AppendNumber,
+      new LoginPinView(base::BindRepeating(&LoginPasswordView::InsertNumber,
                                            base::Unretained(password_view_)),
                        base::BindRepeating(&LoginPasswordView::Backspace,
                                            base::Unretained(password_view_)));
diff --git a/ash/login/ui/login_password_view.cc b/ash/login/ui/login_password_view.cc
index 88bd591..a123054 100644
--- a/ash/login/ui/login_password_view.cc
+++ b/ash/login/ui/login_password_view.cc
@@ -482,11 +482,8 @@
   ContentsChanged(textfield_, textfield_->text());
 }
 
-void LoginPasswordView::AppendNumber(int value) {
-  textfield_->SetText(textfield_->text() + base::IntToString16(value));
-  // |ContentsChanged| won't be called by |Textfield| if the text is changed
-  // by |Textfield::AppendText()|.
-  ContentsChanged(textfield_, textfield_->text());
+void LoginPasswordView::InsertNumber(int value) {
+  textfield_->InsertOrReplaceText(base::IntToString16(value));
 }
 
 void LoginPasswordView::Backspace() {
diff --git a/ash/login/ui/login_password_view.h b/ash/login/ui/login_password_view.h
index 315d3aa..c7f816c 100644
--- a/ash/login/ui/login_password_view.h
+++ b/ash/login/ui/login_password_view.h
@@ -89,8 +89,9 @@
   // Clear all currently entered text.
   void Clear();
 
-  // Add the given numeric value to the textfield.
-  void AppendNumber(int value);
+  // Inserts the given numeric value to the textfield at the current cursor
+  // position (most likely the end).
+  void InsertNumber(int value);
 
   // Erase the last entered value.
   void Backspace();
diff --git a/chrome/browser/chrome_browser_application_mac.mm b/chrome/browser/chrome_browser_application_mac.mm
index 1e56890..9e053af 100644
--- a/chrome/browser/chrome_browser_application_mac.mm
+++ b/chrome/browser/chrome_browser_application_mac.mm
@@ -6,7 +6,6 @@
 
 #include "base/auto_reset.h"
 #include "base/command_line.h"
-#include "base/debug/crash_logging.h"
 #include "base/logging.h"
 #include "base/mac/call_with_eh_frame.h"
 #include "base/strings/stringprintf.h"
@@ -15,7 +14,7 @@
 #import "chrome/browser/app_controller_mac.h"
 #import "chrome/browser/mac/exception_processor.h"
 #include "chrome/common/chrome_switches.h"
-#include "chrome/common/crash_keys.h"
+#include "components/crash/core/common/crash_key.h"
 #import "components/crash/core/common/objc_zombie.h"
 #include "content/public/browser/browser_accessibility_state.h"
 
@@ -224,7 +223,9 @@
       static_cast<long>(tag),
       [actionString UTF8String],
       aTarget);
-  base::debug::ScopedCrashKey key(crash_keys::mac::kSendAction, value);
+
+  static crash_reporter::CrashKeyString<256> sendActionKey("sendaction");
+  crash_reporter::ScopedCrashKeyString scopedKey(&sendActionKey, value);
 
   __block BOOL rv;
   base::mac::CallWithEHFrame(^{
@@ -243,8 +244,9 @@
 
 - (void)sendEvent:(NSEvent*)event {
   TRACE_EVENT0("toplevel", "BrowserCrApplication::sendEvent");
-  base::debug::ScopedCrashKey crash_key(
-      crash_keys::mac::kNSEvent, base::SysNSStringToUTF8([event description]));
+  static crash_reporter::CrashKeyString<256> nseventKey("nsevent");
+  crash_reporter::ScopedCrashKeyString scopedKey(
+      &nseventKey, base::SysNSStringToUTF8([event description]));
 
   base::mac::CallWithEHFrame(^{
     switch (event.type) {
diff --git a/chrome/browser/chromeos/arc/accessibility/ax_tree_source_arc.cc b/chrome/browser/chromeos/arc/accessibility/ax_tree_source_arc.cc
index 81d6ff8..e3c8a44 100644
--- a/chrome/browser/chromeos/arc/accessibility/ax_tree_source_arc.cc
+++ b/chrome/browser/chromeos/arc/accessibility/ax_tree_source_arc.cc
@@ -191,8 +191,11 @@
   }
 
   std::string class_name;
-  GetStringProperty(node, arc::mojom::AccessibilityStringProperty::CLASS_NAME,
-                    &class_name);
+  if (GetStringProperty(node,
+                        arc::mojom::AccessibilityStringProperty::CLASS_NAME,
+                        &class_name)) {
+    out_data->AddStringAttribute(ui::AX_ATTR_CLASS_NAME, class_name);
+  }
 
 #define MAP_ROLE(android_class_name, chrome_role) \
   if (class_name == android_class_name) {         \
diff --git a/chrome/browser/extensions/crx_installer.cc b/chrome/browser/extensions/crx_installer.cc
index b60a4a6..87627ce 100644
--- a/chrome/browser/extensions/crx_installer.cc
+++ b/chrome/browser/extensions/crx_installer.cc
@@ -256,6 +256,45 @@
     NOTREACHED();
 }
 
+void CrxInstaller::UpdateExtensionFromUnpackedCrx(
+    const std::string& extension_id,
+    const std::string& public_key,
+    const base::FilePath& unpacked_dir) {
+  ExtensionService* service = service_weak_.get();
+  if (!service || service->browser_terminating())
+    return;
+
+  const Extension* extension = service->GetInstalledExtension(extension_id);
+  if (!extension) {
+    LOG(WARNING) << "Will not update extension " << extension_id
+                 << " because it is not installed";
+    if (delete_source_)
+      temp_dir_ = unpacked_dir;
+    if (installer_callback_.is_null()) {
+      installer_task_runner_->PostTask(
+          FROM_HERE, base::BindOnce(&CrxInstaller::CleanupTempFiles, this));
+    } else {
+      installer_task_runner_->PostTaskAndReply(
+          FROM_HERE, base::BindOnce(&CrxInstaller::CleanupTempFiles, this),
+          base::BindOnce(
+              base::BindOnce(std::move(installer_callback_), false)));
+    }
+    return;
+  }
+
+  expected_id_ = extension_id;
+  install_source_ = extension->location();
+  install_cause_ = extension_misc::INSTALL_CAUSE_UPDATE;
+  InitializeCreationFlagsForUpdate(extension, Extension::NO_FLAGS);
+
+  const ExtensionPrefs* extension_prefs =
+      ExtensionPrefs::Get(service->GetBrowserContext());
+  DCHECK(extension_prefs);
+  set_do_not_sync(extension_prefs->DoNotSync(extension_id));
+
+  InstallUnpackedCrx(extension_id, public_key, unpacked_dir);
+}
+
 void CrxInstaller::ConvertWebAppOnFileThread(
     const WebApplicationInfo& web_app) {
   scoped_refptr<Extension> extension(ConvertWebAppToExtension(
@@ -703,6 +742,34 @@
   Release();  // balanced in ConfirmInstall() or ConfirmReEnable().
 }
 
+void CrxInstaller::InitializeCreationFlagsForUpdate(const Extension* extension,
+                                                    const int initial_flags) {
+  DCHECK(extension);
+
+  creation_flags_ = initial_flags;
+
+  // If the extension was installed from or has migrated to the webstore, or
+  // its auto-update URL is from the webstore, treat it as a webstore install.
+  // Note that we ignore some older extensions with blank auto-update URLs
+  // because we are mostly concerned with restrictions on NaCl extensions,
+  // which are newer.
+  if (extension->from_webstore() || ManifestURL::UpdatesFromGallery(extension))
+    creation_flags_ |= Extension::FROM_WEBSTORE;
+
+  // Bookmark apps being updated is kind of a contradiction, but that's because
+  // we mark the default apps as bookmark apps, and they're hosted in the web
+  // store, thus they can get updated. See http://crbug.com/101605 for more
+  // details.
+  if (extension->from_bookmark())
+    creation_flags_ |= Extension::FROM_BOOKMARK;
+
+  if (extension->was_installed_by_default())
+    creation_flags_ |= Extension::WAS_INSTALLED_BY_DEFAULT;
+
+  if (extension->was_installed_by_oem())
+    creation_flags_ |= Extension::WAS_INSTALLED_BY_OEM;
+}
+
 void CrxInstaller::UpdateCreationFlagsAndCompleteInstall() {
   creation_flags_ = extension()->creation_flags() | Extension::REQUIRE_KEY;
   // If the extension was already installed and had file access, also grant file
diff --git a/chrome/browser/extensions/crx_installer.h b/chrome/browser/extensions/crx_installer.h
index 9f807616..d14ea61 100644
--- a/chrome/browser/extensions/crx_installer.h
+++ b/chrome/browser/extensions/crx_installer.h
@@ -119,8 +119,19 @@
   // Convert the specified web app into an extension and install it.
   void InstallWebApp(const WebApplicationInfo& web_app);
 
+  // Update the extension |extension_id| with the unpacked crx in
+  // |unpacked_dir|.
+  // If |delete_source_| is true, |unpacked_dir| will be removed at the end of
+  // the update.
+  void UpdateExtensionFromUnpackedCrx(const std::string& extension_id,
+                                      const std::string& public_key,
+                                      const base::FilePath& unpacked_dir);
+
   void OnInstallPromptDone(ExtensionInstallPrompt::Result result);
 
+  void InitializeCreationFlagsForUpdate(const Extension* extension,
+                                        const int initial_flags);
+
   int creation_flags() const { return creation_flags_; }
   void set_creation_flags(int val) { creation_flags_ = val; }
 
diff --git a/chrome/browser/extensions/crx_installer_browsertest.cc b/chrome/browser/extensions/crx_installer_browsertest.cc
index badd827..f3a56e2 100644
--- a/chrome/browser/extensions/crx_installer_browsertest.cc
+++ b/chrome/browser/extensions/crx_installer_browsertest.cc
@@ -50,6 +50,7 @@
 #include "extensions/browser/management_policy.h"
 #include "extensions/browser/notification_types.h"
 #include "extensions/common/extension.h"
+#include "extensions/common/extension_builder.h"
 #include "extensions/common/feature_switch.h"
 #include "extensions/common/file_util.h"
 #include "extensions/common/permissions/api_permission.h"
@@ -160,12 +161,10 @@
   void OnInstallSuccess(const Extension* extension, SkBitmap* icon) override {
     proxy_->set_extension_id(extension->id());
     proxy_->set_confirmation_requested(did_call_show_dialog());
-    base::RunLoop::QuitCurrentWhenIdleDeprecated();
   }
   void OnInstallFailure(const CrxInstallError& error) override {
     proxy_->set_error(error.message());
     proxy_->set_confirmation_requested(did_call_show_dialog());
-    base::RunLoop::QuitCurrentWhenIdleDeprecated();
   }
 
  private:
@@ -233,19 +232,92 @@
         strict_manifest_checks);
   }
 
+  ExtensionService* extension_service() {
+    return extensions::ExtensionSystem::Get(browser()->profile())
+        ->extension_service();
+  }
+
+  const Extension* GetInstalledExtension(const std::string& extension_id) {
+    return extension_service()->GetInstalledExtension(extension_id);
+  }
+
+  std::unique_ptr<base::ScopedTempDir> UnpackedCrxTempDir() {
+    auto temp_dir = std::make_unique<base::ScopedTempDir>();
+    EXPECT_TRUE(temp_dir->CreateUniqueTempDir());
+    EXPECT_TRUE(base::PathExists(temp_dir->GetPath()));
+
+    base::FilePath unpacked_path = test_data_dir_.AppendASCII("good_unpacked");
+    EXPECT_TRUE(base::PathExists(unpacked_path));
+    EXPECT_TRUE(base::CopyDirectory(unpacked_path, temp_dir->GetPath(), false));
+
+    return temp_dir;
+  }
+
+  // Helper function that creates a file at |relative_path| within |directory|
+  // and fills it with |content|.
+  bool AddFileToDirectory(const base::FilePath& directory,
+                          const base::FilePath& relative_path,
+                          const std::string& content) const {
+    const base::FilePath full_path = directory.Append(relative_path);
+    if (!CreateDirectory(full_path.DirName()))
+      return false;
+    const int result =
+        base::WriteFile(full_path, content.data(), content.size());
+    return (static_cast<size_t>(result) == content.size());
+  }
+
+  void AddExtension(const std::string& extension_id,
+                    const std::string& version) {
+    base::ScopedTempDir temp_dir;
+    ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
+    ASSERT_TRUE(base::PathExists(temp_dir.GetPath()));
+
+    base::FilePath foo_js(FILE_PATH_LITERAL("foo.js"));
+    base::FilePath bar_html(FILE_PATH_LITERAL("bar/bar.html"));
+    ASSERT_TRUE(AddFileToDirectory(temp_dir.GetPath(), foo_js, "hello"))
+        << "Failed to write " << temp_dir.GetPath().value() << "/"
+        << foo_js.value();
+    ASSERT_TRUE(AddFileToDirectory(temp_dir.GetPath(), bar_html, "world"));
+
+    ExtensionBuilder builder;
+    builder.SetManifest(DictionaryBuilder()
+                            .Set("name", "My First Extension")
+                            .Set("version", version)
+                            .Set("manifest_version", 2)
+                            .Build());
+    builder.SetID(extension_id);
+    builder.SetPath(temp_dir.GetPath());
+    ExtensionRegistry::Get(browser()->profile())->AddEnabled(builder.Build());
+
+    const Extension* extension = GetInstalledExtension(extension_id);
+    ASSERT_NE(nullptr, extension);
+    ASSERT_EQ(version, extension->VersionString());
+  }
+
+  static void InstallerCallback(base::OnceClosure quit_closure,
+                                CrxInstaller::InstallerResultCallback callback,
+                                bool success) {
+    if (!callback.is_null())
+      std::move(callback).Run(success);
+    std::move(quit_closure).Run();
+  }
+
   void RunCrxInstaller(const WebstoreInstaller::Approval* approval,
                        std::unique_ptr<ExtensionInstallPrompt> prompt,
                        CrxInstaller::InstallerResultCallback callback,
                        const base::FilePath& crx_path) {
-    ExtensionService* service = extensions::ExtensionSystem::Get(
-        browser()->profile())->extension_service();
+    base::RunLoop run_loop;
+
     scoped_refptr<CrxInstaller> installer(
-        CrxInstaller::Create(service, std::move(prompt), approval));
+        CrxInstaller::Create(extension_service(), std::move(prompt), approval));
     installer->set_allow_silent_install(true);
     installer->set_is_gallery_install(true);
-    installer->set_installer_callback(std::move(callback));
+    installer->set_installer_callback(
+        base::BindOnce(&ExtensionCrxInstallerTest::InstallerCallback,
+                       run_loop.QuitWhenIdleClosure(), std::move(callback)));
     installer->InstallCrx(crx_path);
-    content::RunMessageLoop();
+
+    run_loop.Run();
   }
 
   void RunCrxInstallerFromUnpackedDirectory(
@@ -254,17 +326,38 @@
       const std::string& extension_id,
       const std::string& public_key,
       const base::FilePath& crx_directory) {
-    ExtensionService* service =
-        extensions::ExtensionSystem::Get(browser()->profile())
-            ->extension_service();
+    base::RunLoop run_loop;
+
     scoped_refptr<CrxInstaller> installer(
-        CrxInstaller::Create(service, std::move(prompt)));
+        CrxInstaller::Create(extension_service(), std::move(prompt)));
     installer->set_allow_silent_install(true);
     installer->set_is_gallery_install(true);
-    installer->set_installer_callback(std::move(callback));
+    installer->set_installer_callback(
+        base::BindOnce(&ExtensionCrxInstallerTest::InstallerCallback,
+                       run_loop.QuitWhenIdleClosure(), std::move(callback)));
     installer->set_delete_source(true);
     installer->InstallUnpackedCrx(extension_id, public_key, crx_directory);
-    content::RunMessageLoop();
+
+    run_loop.Run();
+  }
+
+  void RunUpdateExtension(std::unique_ptr<ExtensionInstallPrompt> prompt,
+                          const std::string& extension_id,
+                          const std::string& public_key,
+                          const base::FilePath& unpacked_dir,
+                          CrxInstaller::InstallerResultCallback callback) {
+    base::RunLoop run_loop;
+
+    scoped_refptr<CrxInstaller> installer(
+        CrxInstaller::Create(extension_service(), std::move(prompt)));
+    installer->set_delete_source(true);
+    installer->set_installer_callback(
+        base::BindOnce(&ExtensionCrxInstallerTest::InstallerCallback,
+                       run_loop.QuitWhenIdleClosure(), std::move(callback)));
+    installer->UpdateExtensionFromUnpackedCrx(extension_id, public_key,
+                                              unpacked_dir);
+
+    run_loop.Run();
   }
 
   // Installs a crx from |crx_relpath| (a path relative to the extension test
@@ -306,11 +399,8 @@
   }
 
   void InstallWebAppAndVerifyNoErrors() {
-    ExtensionService* service =
-        extensions::ExtensionSystem::Get(browser()->profile())
-            ->extension_service();
     scoped_refptr<CrxInstaller> crx_installer(
-        CrxInstaller::CreateSilent(service));
+        CrxInstaller::CreateSilent(extension_service()));
     crx_installer->set_error_on_unsupported_requirements(true);
     crx_installer->InstallWebApp(
         CreateWebAppInfo(kAppTitle, kAppDescription, kAppUrl, 64));
@@ -473,8 +563,6 @@
 }
 
 IN_PROC_BROWSER_TEST_F(ExtensionCrxInstallerTest, AllowOffStore) {
-  ExtensionService* service = extensions::ExtensionSystem::Get(
-      browser()->profile())->extension_service();
   const bool kTestData[] = {false, true};
 
   for (size_t i = 0; i < arraysize(kTestData); ++i) {
@@ -482,7 +570,7 @@
         CreateMockPromptProxyForBrowser(browser());
 
     scoped_refptr<CrxInstaller> crx_installer(
-        CrxInstaller::Create(service, mock_prompt->CreatePrompt()));
+        CrxInstaller::Create(extension_service(), mock_prompt->CreatePrompt()));
     crx_installer->set_install_cause(
         extension_misc::INSTALL_CAUSE_USER_DOWNLOAD);
 
@@ -491,10 +579,15 @@
           CrxInstaller::OffStoreInstallAllowedInTest);
     }
 
+    base::RunLoop run_loop;
+    crx_installer->set_installer_callback(
+        base::BindOnce(&ExtensionCrxInstallerTest::InstallerCallback,
+                       run_loop.QuitWhenIdleClosure(),
+                       CrxInstaller::InstallerResultCallback()));
     crx_installer->InstallCrx(test_data_dir_.AppendASCII("good.crx"));
     // The |mock_prompt| will quit running the loop once the |crx_installer|
     // is done.
-    content::RunMessageLoop();
+    run_loop.Run();
     EXPECT_EQ(kTestData[i], mock_prompt->did_succeed());
     EXPECT_EQ(kTestData[i], mock_prompt->confirmation_requested()) <<
         kTestData[i];
@@ -531,9 +624,7 @@
   const std::string extension_id("ldnnhddmnhbkjipkidpdiheffobcpfmf");
   base::FilePath base_path = test_data_dir_.AppendASCII("delayed_install");
 
-  ExtensionSystem* extension_system = extensions::ExtensionSystem::Get(
-      browser()->profile());
-  ExtensionService* service = extension_system->extension_service();
+  ExtensionService* service = extension_service();
   ASSERT_TRUE(service);
   ExtensionRegistry* registry = ExtensionRegistry::Get(
       browser()->profile());
@@ -734,6 +825,124 @@
   EXPECT_FALSE(base::PathExists(temp_dir.GetPath()));
 }
 
+IN_PROC_BROWSER_TEST_F(ExtensionCrxInstallerTest,
+                       UpdateExtensionFromUnpackedCrx_NewExtension) {
+  base::ScopedAllowBlockingForTesting allow_io;
+  std::unique_ptr<MockPromptProxy> mock_prompt =
+      CreateMockPromptProxyForBrowser(browser());
+
+  // Update won't work as the extension doesn't exist.
+  const std::string extension_id = "ldnnhddmnhbkjipkidpdiheffobcpfmf";
+  const std::string public_key =
+      "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC8c4fBSPZ6utYoZ8NiWF/"
+      "DSaimBhihjwgOsskyleFGaurhi3TDClTVSGPxNkgCzrz0wACML7M4aNjpd05qupdbR2d294j"
+      "kDuI7caxEGUucpP7GJRRHnm8Sx+"
+      "y0ury28n8jbN0PnInKKWcxpIXXmNQyC19HBuO3QIeUq9Dqc+7YFQIDAQAB";
+  ASSERT_EQ(nullptr, GetInstalledExtension(extension_id));
+  auto temp_dir = UnpackedCrxTempDir();
+  RunUpdateExtension(mock_prompt->CreatePrompt(), extension_id, public_key,
+                     temp_dir->GetPath(), base::BindOnce([](bool success) {
+                       EXPECT_FALSE(success);
+                     }));
+
+  // The unpacked folder should be deleted.
+  EXPECT_FALSE(mock_prompt->did_succeed());
+  EXPECT_FALSE(base::PathExists(temp_dir->GetPath()));
+  EXPECT_EQ(nullptr, GetInstalledExtension(extension_id));
+}
+
+IN_PROC_BROWSER_TEST_F(ExtensionCrxInstallerTest,
+                       UpdateExtensionFromUnpackedCrx_UpdateExistingExtension) {
+  base::ScopedAllowBlockingForTesting allow_io;
+  std::unique_ptr<MockPromptProxy> mock_prompt =
+      CreateMockPromptProxyForBrowser(browser());
+
+  const std::string extension_id = "ldnnhddmnhbkjipkidpdiheffobcpfmf";
+  const std::string public_key =
+      "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC8c4fBSPZ6utYoZ8NiWF/"
+      "DSaimBhihjwgOsskyleFGaurhi3TDClTVSGPxNkgCzrz0wACML7M4aNjpd05qupdbR2d294j"
+      "kDuI7caxEGUucpP7GJRRHnm8Sx+"
+      "y0ury28n8jbN0PnInKKWcxpIXXmNQyC19HBuO3QIeUq9Dqc+7YFQIDAQAB";
+
+  // Test updating an existing extension.
+  AddExtension(extension_id, "0.0");
+
+  auto temp_dir = UnpackedCrxTempDir();
+  RunUpdateExtension(mock_prompt->CreatePrompt(), extension_id, public_key,
+                     temp_dir->GetPath(), base::BindOnce([](bool success) {
+                       EXPECT_TRUE(success);
+                     }));
+
+  EXPECT_TRUE(mock_prompt->did_succeed());
+
+  // The unpacked folder should be deleted.
+  EXPECT_FALSE(base::PathExists(temp_dir->GetPath()));
+
+  const Extension* extension = GetInstalledExtension(extension_id);
+  ASSERT_NE(nullptr, extension);
+  EXPECT_EQ("1.0", extension->VersionString());
+}
+
+IN_PROC_BROWSER_TEST_F(ExtensionCrxInstallerTest,
+                       UpdateExtensionFromUnpackedCrx_InvalidPublicKey) {
+  base::ScopedAllowBlockingForTesting allow_io;
+  std::unique_ptr<MockPromptProxy> mock_prompt =
+      CreateMockPromptProxyForBrowser(browser());
+
+  const std::string extension_id = "ldnnhddmnhbkjipkidpdiheffobcpfmf";
+  const std::string public_key = "invalid public key";
+
+  // Test updating an existing extension.
+  AddExtension(extension_id, "0.0");
+
+  auto temp_dir = UnpackedCrxTempDir();
+  RunUpdateExtension(mock_prompt->CreatePrompt(), extension_id, public_key,
+                     temp_dir->GetPath(), base::BindOnce([](bool success) {
+                       EXPECT_FALSE(success);
+                     }));
+
+  EXPECT_FALSE(mock_prompt->did_succeed());
+
+  // The unpacked folder should be deleted.
+  EXPECT_FALSE(base::PathExists(temp_dir->GetPath()));
+
+  const Extension* extension = GetInstalledExtension(extension_id);
+  ASSERT_NE(nullptr, extension);
+  EXPECT_EQ("0.0", extension->VersionString());
+}
+
+IN_PROC_BROWSER_TEST_F(ExtensionCrxInstallerTest,
+                       UpdateExtensionFromUnpackedCrx_WrongPublicKey) {
+  base::ScopedAllowBlockingForTesting allow_io;
+  std::unique_ptr<MockPromptProxy> mock_prompt =
+      CreateMockPromptProxyForBrowser(browser());
+
+  const std::string extension_id = "gllekhaobjnhgeagipipnkpmmmpchacm";
+  const std::string public_key =
+      "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC8c4fBSPZ6utYoZ8NiWF/"
+      "DSaimBhihjwgOsskyleFGaurhi3TDClTVSGPxNkgCzrz0wACML7M4aNjpd05qupdbR2d294j"
+      "kDuI7caxEGUucpP7GJRRHnm8Sx+"
+      "y0ury28n8jbN0PnInKKWcxpIXXmNQyC19HBuO3QIeUq9Dqc+7YFQIDAQAB";
+
+  // Test updating an existing extension.
+  AddExtension(extension_id, "0.0");
+
+  auto temp_dir = UnpackedCrxTempDir();
+  RunUpdateExtension(mock_prompt->CreatePrompt(), extension_id, public_key,
+                     temp_dir->GetPath(), base::BindOnce([](bool success) {
+                       EXPECT_FALSE(success);
+                     }));
+
+  EXPECT_FALSE(mock_prompt->did_succeed());
+
+  // The unpacked folder should be deleted.
+  EXPECT_FALSE(base::PathExists(temp_dir->GetPath()));
+
+  const Extension* extension = GetInstalledExtension(extension_id);
+  ASSERT_NE(nullptr, extension);
+  EXPECT_EQ("0.0", extension->VersionString());
+}
+
 #if defined(OS_CHROMEOS)
 IN_PROC_BROWSER_TEST_F(ExtensionCrxInstallerTest, KioskOnlyTest) {
   // kiosk_only is whitelisted from non-chromeos.
@@ -781,10 +990,8 @@
 #endif
 
 IN_PROC_BROWSER_TEST_F(ExtensionCrxInstallerTest, DoNotSync) {
-  ExtensionService* service = extensions::ExtensionSystem::Get(
-                                  browser()->profile())->extension_service();
   scoped_refptr<CrxInstaller> crx_installer(
-      CrxInstaller::CreateSilent(service));
+      CrxInstaller::CreateSilent(extension_service()));
   crx_installer->set_do_not_sync(true);
   crx_installer->InstallCrx(test_data_dir_.AppendASCII("good.crx"));
   EXPECT_TRUE(WaitForCrxInstallerDone());
@@ -830,9 +1037,7 @@
   base::FilePath crx_with_file_permission = PackExtension(ext_source);
   ASSERT_FALSE(crx_with_file_permission.empty());
 
-  ExtensionService* service =
-      extensions::ExtensionSystem::Get(browser()->profile())
-          ->extension_service();
+  ExtensionService* service = extension_service();
 
   const std::string extension_id("bdkapipdccfifhdghmblnenbbncfcpid");
   {
diff --git a/chrome/browser/extensions/extension_service.cc b/chrome/browser/extensions/extension_service.cc
index 0e09db0..ca7fe2a 100644
--- a/chrome/browser/extensions/extension_service.cc
+++ b/chrome/browser/extensions/extension_service.cc
@@ -586,7 +586,7 @@
 
     return false;
   }
-
+  // Either |pending_extension_info| or |extension| or both must not be null.
   scoped_refptr<CrxInstaller> installer(CrxInstaller::CreateSilent(this));
   installer->set_expected_id(id);
   installer->set_expected_hash(file.expected_hash);
@@ -611,39 +611,25 @@
     creation_flags = pending_extension_info->creation_flags();
     if (pending_extension_info->mark_acknowledged())
       external_install_manager_->AcknowledgeExternalExtension(id);
-  } else if (extension) {
+    // If the extension was installed from or has migrated to the webstore, or
+    // its auto-update URL is from the webstore, treat it as a webstore install.
+    // Note that we ignore some older extensions with blank auto-update URLs
+    // because we are mostly concerned with restrictions on NaCl extensions,
+    // which are newer.
+    if (!extension && extension_urls::IsWebstoreUpdateUrl(
+                          pending_extension_info->update_url()))
+      creation_flags |= Extension::FROM_WEBSTORE;
+  } else {
+    // |extension| must not be null.
     installer->set_install_source(extension->location());
   }
-  // If the extension was installed from or has migrated to the webstore, or
-  // its auto-update URL is from the webstore, treat it as a webstore install.
-  // Note that we ignore some older extensions with blank auto-update URLs
-  // because we are mostly concerned with restrictions on NaCl extensions,
-  // which are newer.
-  if ((extension && extension->from_webstore()) ||
-      (extension && extensions::ManifestURL::UpdatesFromGallery(extension)) ||
-      (!extension && extension_urls::IsWebstoreUpdateUrl(
-           pending_extension_info->update_url()))) {
-    creation_flags |= Extension::FROM_WEBSTORE;
-  }
 
-  // Bookmark apps being updated is kind of a contradiction, but that's because
-  // we mark the default apps as bookmark apps, and they're hosted in the web
-  // store, thus they can get updated. See http://crbug.com/101605 for more
-  // details.
-  if (extension && extension->from_bookmark())
-    creation_flags |= Extension::FROM_BOOKMARK;
-
-  if (extension && extension->was_installed_by_default())
-    creation_flags |= Extension::WAS_INSTALLED_BY_DEFAULT;
-
-  if (extension && extension->was_installed_by_oem())
-    creation_flags |= Extension::WAS_INSTALLED_BY_OEM;
-
-  if (extension)
+  if (extension) {
+    installer->InitializeCreationFlagsForUpdate(extension, creation_flags);
     installer->set_do_not_sync(extension_prefs_->DoNotSync(id));
-
-  installer->set_creation_flags(creation_flags);
-
+  } else {
+    installer->set_creation_flags(creation_flags);
+  }
   installer->set_delete_source(file_ownership_passed);
   installer->set_install_cause(extension_misc::INSTALL_CAUSE_UPDATE);
   installer->InstallCrxFile(file);
diff --git a/chrome/browser/extensions/extension_system_impl.cc b/chrome/browser/extensions/extension_system_impl.cc
index 1bef781..bbe92a7d 100644
--- a/chrome/browser/extensions/extension_system_impl.cc
+++ b/chrome/browser/extensions/extension_system_impl.cc
@@ -21,6 +21,7 @@
 #include "chrome/browser/extensions/chrome_app_sorting.h"
 #include "chrome/browser/extensions/chrome_content_verifier_delegate.h"
 #include "chrome/browser/extensions/component_loader.h"
+#include "chrome/browser/extensions/crx_installer.h"
 #include "chrome/browser/extensions/extension_error_reporter.h"
 #include "chrome/browser/extensions/extension_garbage_collector.h"
 #include "chrome/browser/extensions/extension_management.h"
@@ -432,10 +433,21 @@
       extension);
 }
 
-void ExtensionSystemImpl::InstallUpdate(const std::string& extension_id,
-                                        const base::FilePath& temp_dir) {
-  NOTREACHED() << "Not yet implemented";
-  base::DeleteFile(temp_dir, true /* recursive */);
+void ExtensionSystemImpl::InstallUpdate(
+    const std::string& extension_id,
+    const std::string& public_key,
+    const base::FilePath& unpacked_dir,
+    InstallUpdateCallback install_update_callback) {
+  DCHECK(!install_update_callback.is_null());
+
+  ExtensionService* service = extension_service();
+  DCHECK(service);
+
+  scoped_refptr<CrxInstaller> installer = CrxInstaller::CreateSilent(service);
+  installer->set_delete_source(true);
+  installer->set_installer_callback(std::move(install_update_callback));
+  installer->UpdateExtensionFromUnpackedCrx(extension_id, public_key,
+                                            unpacked_dir);
 }
 
 void ExtensionSystemImpl::RegisterExtensionWithRequestContexts(
diff --git a/chrome/browser/extensions/extension_system_impl.h b/chrome/browser/extensions/extension_system_impl.h
index 68c6b64..1f1ddae1 100644
--- a/chrome/browser/extensions/extension_system_impl.h
+++ b/chrome/browser/extensions/extension_system_impl.h
@@ -40,6 +40,8 @@
 // but with a shared instance for incognito) keeps the common services.
 class ExtensionSystemImpl : public ExtensionSystem {
  public:
+  using InstallUpdateCallback = ExtensionSystem::InstallUpdateCallback;
+
   explicit ExtensionSystemImpl(Profile* profile);
   ~ExtensionSystemImpl() override;
 
@@ -73,7 +75,9 @@
   std::unique_ptr<ExtensionSet> GetDependentExtensions(
       const Extension* extension) override;
   void InstallUpdate(const std::string& extension_id,
-                     const base::FilePath& temp_dir) override;
+                     const std::string& public_key,
+                     const base::FilePath& unpacked_dir,
+                     InstallUpdateCallback install_update_callback) override;
 
  private:
   friend class ExtensionSystemSharedFactory;
diff --git a/chrome/browser/extensions/test_extension_system.cc b/chrome/browser/extensions/test_extension_system.cc
index e0453fec..beaa4f8a 100644
--- a/chrome/browser/extensions/test_extension_system.cc
+++ b/chrome/browser/extensions/test_extension_system.cc
@@ -136,8 +136,11 @@
       extension);
 }
 
-void TestExtensionSystem::InstallUpdate(const std::string& extension_id,
-                                        const base::FilePath& temp_dir) {
+void TestExtensionSystem::InstallUpdate(
+    const std::string& extension_id,
+    const std::string& public_key,
+    const base::FilePath& temp_dir,
+    InstallUpdateCallback install_update_callback) {
   NOTREACHED();
 }
 
diff --git a/chrome/browser/extensions/test_extension_system.h b/chrome/browser/extensions/test_extension_system.h
index 6b1c8008..03911a5 100644
--- a/chrome/browser/extensions/test_extension_system.h
+++ b/chrome/browser/extensions/test_extension_system.h
@@ -33,6 +33,7 @@
 // Test ExtensionSystem, for use with TestingProfile.
 class TestExtensionSystem : public ExtensionSystem {
  public:
+  using InstallUpdateCallback = ExtensionSystem::InstallUpdateCallback;
   explicit TestExtensionSystem(Profile* profile);
   ~TestExtensionSystem() override;
 
@@ -68,7 +69,9 @@
   std::unique_ptr<ExtensionSet> GetDependentExtensions(
       const Extension* extension) override;
   void InstallUpdate(const std::string& extension_id,
-                     const base::FilePath& temp_dir) override;
+                     const std::string& public_key,
+                     const base::FilePath& temp_dir,
+                     InstallUpdateCallback install_update_callback) override;
 
   // Note that you probably want to use base::RunLoop().RunUntilIdle() right
   // after this to run all the accumulated tasks.
diff --git a/chrome/browser/mac/exception_processor.mm b/chrome/browser/mac/exception_processor.mm
index a337e6f..8354415 100644
--- a/chrome/browser/mac/exception_processor.mm
+++ b/chrome/browser/mac/exception_processor.mm
@@ -18,7 +18,7 @@
 #include "base/macros.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/strings/sys_string_conversions.h"
-#include "chrome/common/crash_keys.h"
+#include "components/crash/core/common/crash_key.h"
 
 namespace chrome {
 
@@ -91,8 +91,10 @@
   NSString* exception_message_ns = [NSString
       stringWithFormat:@"%@: %@", [exception name], [exception reason]];
   std::string exception_message = base::SysNSStringToUTF8(exception_message_ns);
-  base::debug::SetCrashKeyValue(crash_keys::mac::kNSException,
-                                exception_message);
+
+  static crash_reporter::CrashKeyString<256> crash_key("nsexception");
+  crash_key.Set(exception_message);
+
   LOG(FATAL) << "Terminating from Objective-C exception: " << exception_message;
 }
 
@@ -102,20 +104,25 @@
   // Record UMA and crash keys about the exception.
   RecordExceptionWithUma(exception);
 
-  const char* const kExceptionKey =
-      seen_first_exception ? crash_keys::mac::kLastNSException
-                           : crash_keys::mac::kFirstNSException;
+  static crash_reporter::CrashKeyString<256> firstexception("firstexception");
+  static crash_reporter::CrashKeyString<256> lastexception("lastexception");
+
+  static crash_reporter::CrashKeyString<1024> firstexception_bt(
+      "firstexception_bt");
+  static crash_reporter::CrashKeyString<1024> lastexception_bt(
+      "lastexception_bt");
+
+  auto* key = seen_first_exception ? &lastexception : &firstexception;
+  auto* bt_key = seen_first_exception ? &lastexception_bt : &firstexception_bt;
+
   NSString* value = [NSString stringWithFormat:@"%@ reason %@",
       [exception name], [exception reason]];
-  base::debug::SetCrashKeyValue(kExceptionKey, base::SysNSStringToUTF8(value));
+  key->Set(base::SysNSStringToUTF8(value));
 
-  const char* const kExceptionTraceKey =
-      seen_first_exception ? crash_keys::mac::kLastNSExceptionTrace
-                           : crash_keys::mac::kFirstNSExceptionTrace;
   // This exception preprocessor runs prior to the one in libobjc, which sets
   // the -[NSException callStackReturnAddresses].
-  base::debug::SetCrashKeyToStackTrace(kExceptionTraceKey,
-                                       base::debug::StackTrace());
+  crash_reporter::SetCrashKeyStringToStackTrace(bt_key,
+                                                base::debug::StackTrace());
 
   seen_first_exception = true;
 
diff --git a/chrome/browser/resources/md_extensions/manager.js b/chrome/browser/resources/md_extensions/manager.js
index 34c9c8c..d840a3bd 100644
--- a/chrome/browser/resources/md_extensions/manager.js
+++ b/chrome/browser/resources/md_extensions/manager.js
@@ -384,7 +384,7 @@
            this.currentPage_.page == Page.ERRORS) &&
           this.currentPage_.extensionId == itemId) {
         // Leave the details page (the 'list' page is a fine choice).
-        extensions.navigation.navigateTo({page: Page.LIST});
+        extensions.navigation.replaceWith({page: Page.LIST});
       }
     },
 
@@ -428,7 +428,7 @@
         data = this.getData_(newPage.extensionId);
         if (!data) {
           // Attempting to view an invalid (removed?) app or extension ID.
-          extensions.navigation.navigateTo({page: Page.LIST});
+          extensions.navigation.replaceWith({page: Page.LIST});
           return;
         }
       }
diff --git a/chrome/browser/resources/md_extensions/navigation_helper.js b/chrome/browser/resources/md_extensions/navigation_helper.js
index 3d31509..e4efc690 100644
--- a/chrome/browser/resources/md_extensions/navigation_helper.js
+++ b/chrome/browser/resources/md_extensions/navigation_helper.js
@@ -30,6 +30,16 @@
   'use strict';
 
   /**
+   * @param {!PageState} a
+   * @param {!PageState} b
+   * @return {boolean} Whether a and b are equal.
+   */
+  function isPageStateEqual(a, b) {
+    return a.page == b.page && a.subpage == b.subpage &&
+        a.extensionId == b.extensionId;
+  }
+
+  /**
    * Regular expression that captures the leading slash, the content and the
    * trailing slash in three different groups.
    * @const {!RegExp}
@@ -51,6 +61,9 @@
       /** @private {!Map<number, function(!PageState)>} */
       this.listeners_ = new Map();
 
+      /** @private {!PageState} */
+      this.previousPage_;
+
       window.addEventListener('popstate', () => {
         this.notifyRouteChanged_(this.getCurrentPage());
       });
@@ -137,21 +150,33 @@
      */
     navigateTo(newPage) {
       let currentPage = this.getCurrentPage();
-      if (currentPage && currentPage.page == newPage.page &&
-          currentPage.subpage == newPage.subpage &&
-          currentPage.extensionId == newPage.extensionId) {
+      if (currentPage && isPageStateEqual(currentPage, newPage)) {
         return;
       }
 
-      this.updateHistory(newPage);
+      this.updateHistory(newPage, false /* replaceState */);
+      this.notifyRouteChanged_(newPage);
+    }
+
+    /**
+     * @param {!PageState} newPage the page to replace the current page with.
+     */
+    replaceWith(newPage) {
+      this.updateHistory(newPage, true /* replaceState */);
+      if (this.previousPage_ && isPageStateEqual(this.previousPage_, newPage)) {
+        // Skip the duplicate history entry.
+        history.back();
+        return;
+      }
       this.notifyRouteChanged_(newPage);
     }
 
     /**
      * Called when a page changes, and pushes state to history to reflect it.
      * @param {!PageState} entry
+     * @param {boolean} replaceState
      */
-    updateHistory(entry) {
+    updateHistory(entry, replaceState) {
       let path;
       switch (entry.page) {
         case Page.LIST:
@@ -181,10 +206,12 @@
       // a dialog. As such, we replace state rather than pushing a new state
       // on the stack so that hitting the back button doesn't just toggle the
       // dialog.
-      if (isDialogNavigation)
+      if (replaceState || isDialogNavigation) {
         history.replaceState(state, '', path);
-      else
+      } else {
+        this.previousPage_ = currentPage;
         history.pushState(state, '', path);
+      }
     }
   }
 
diff --git a/chrome/browser/signin/easy_unlock_notification_controller.cc b/chrome/browser/signin/easy_unlock_notification_controller.cc
index ed81e029..59735ef 100644
--- a/chrome/browser/signin/easy_unlock_notification_controller.cc
+++ b/chrome/browser/signin/easy_unlock_notification_controller.cc
@@ -9,7 +9,6 @@
 
 #if defined(OS_CHROMEOS)
 #include "chrome/browser/signin/easy_unlock_notification_controller_chromeos.h"
-#include "ui/message_center/message_center.h"
 #endif
 
 namespace {
@@ -38,8 +37,7 @@
 std::unique_ptr<EasyUnlockNotificationController>
 EasyUnlockNotificationController::Create(Profile* profile) {
 #if defined(OS_CHROMEOS)
-  return base::MakeUnique<EasyUnlockNotificationControllerChromeOS>(
-      profile, message_center::MessageCenter::Get());
+  return base::MakeUnique<EasyUnlockNotificationControllerChromeOS>(profile);
 #else
   return base::MakeUnique<EasyUnlockNotificationControllerStub>();
 #endif
diff --git a/chrome/browser/signin/easy_unlock_notification_controller_chromeos.cc b/chrome/browser/signin/easy_unlock_notification_controller_chromeos.cc
index a72f3c8..bfb2479 100644
--- a/chrome/browser/signin/easy_unlock_notification_controller_chromeos.cc
+++ b/chrome/browser/signin/easy_unlock_notification_controller_chromeos.cc
@@ -7,6 +7,7 @@
 #include "base/guid.h"
 #include "base/memory/ptr_util.h"
 #include "base/strings/utf_string_conversions.h"
+#include "chrome/browser/notifications/notification_display_service.h"
 #include "chrome/browser/ui/chrome_pages.h"
 #include "chrome/grit/generated_resources.h"
 #include "chrome/grit/theme_resources.h"
@@ -53,12 +54,8 @@
 }  // namespace
 
 EasyUnlockNotificationControllerChromeOS::
-    EasyUnlockNotificationControllerChromeOS(
-        Profile* profile,
-        message_center::MessageCenter* message_center)
-    : profile_(profile),
-      message_center_(message_center),
-      weak_ptr_factory_(this) {}
+    EasyUnlockNotificationControllerChromeOS(Profile* profile)
+    : profile_(profile), weak_ptr_factory_(this) {}
 
 EasyUnlockNotificationControllerChromeOS::
     ~EasyUnlockNotificationControllerChromeOS() {}
@@ -110,8 +107,8 @@
 void EasyUnlockNotificationControllerChromeOS::
     ShowPairingChangeAppliedNotification(const std::string& phone_name) {
   // Remove the pairing change notification if it is still being shown.
-  message_center_->RemoveNotification(kEasyUnlockPairingChangeNotifierId,
-                                      false /* by_user */);
+  NotificationDisplayService::GetForProfile(profile_)->Close(
+      NotificationHandler::Type::TRANSIENT, kEasyUnlockPairingChangeNotifierId);
 
   message_center::RichNotificationData rich_notification_data;
   rich_notification_data.buttons.push_back(
@@ -154,13 +151,8 @@
 void EasyUnlockNotificationControllerChromeOS::ShowNotification(
     std::unique_ptr<message_center::Notification> notification) {
   notification->SetSystemPriority();
-  std::string notification_id = notification->id();
-  if (message_center_->FindVisibleNotificationById(notification_id)) {
-    message_center_->UpdateNotification(notification_id,
-                                        std::move(notification));
-  } else {
-    message_center_->AddNotification(std::move(notification));
-  }
+  NotificationDisplayService::GetForProfile(profile_)->Display(
+      NotificationHandler::Type::TRANSIENT, *notification);
 }
 
 void EasyUnlockNotificationControllerChromeOS::LaunchEasyUnlockSettings() {
diff --git a/chrome/browser/signin/easy_unlock_notification_controller_chromeos.h b/chrome/browser/signin/easy_unlock_notification_controller_chromeos.h
index 3014e2d..4739037 100644
--- a/chrome/browser/signin/easy_unlock_notification_controller_chromeos.h
+++ b/chrome/browser/signin/easy_unlock_notification_controller_chromeos.h
@@ -12,7 +12,6 @@
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
 #include "chrome/browser/signin/easy_unlock_notification_controller.h"
-#include "ui/message_center/message_center.h"
 #include "ui/message_center/notification.h"
 #include "ui/message_center/notification_delegate.h"
 
@@ -22,9 +21,7 @@
 class EasyUnlockNotificationControllerChromeOS
     : public EasyUnlockNotificationController {
  public:
-  EasyUnlockNotificationControllerChromeOS(
-      Profile* profile,
-      message_center::MessageCenter* message_center);
+  explicit EasyUnlockNotificationControllerChromeOS(Profile* profile);
   ~EasyUnlockNotificationControllerChromeOS() override;
 
   // EasyUnlockNotificationController:
@@ -68,8 +65,6 @@
 
   Profile* profile_;
 
-  message_center::MessageCenter* message_center_;
-
   base::WeakPtrFactory<EasyUnlockNotificationControllerChromeOS>
       weak_ptr_factory_;
 
diff --git a/chrome/browser/signin/easy_unlock_notification_controller_chromeos_unittest.cc b/chrome/browser/signin/easy_unlock_notification_controller_chromeos_unittest.cc
index f1fa3ed..88e3b37 100644
--- a/chrome/browser/signin/easy_unlock_notification_controller_chromeos_unittest.cc
+++ b/chrome/browser/signin/easy_unlock_notification_controller_chromeos_unittest.cc
@@ -5,11 +5,9 @@
 #include "chrome/browser/signin/easy_unlock_notification_controller_chromeos.h"
 
 #include "base/strings/utf_string_conversions.h"
-#include "chrome/test/base/testing_profile.h"
-#include "content/public/test/test_browser_thread_bundle.h"
+#include "chrome/browser/notifications/notification_display_service_tester.h"
+#include "chrome/test/base/browser_with_test_window_test.h"
 #include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "ui/message_center/fake_message_center.h"
 #include "ui/message_center/notification.h"
 #include "ui/message_center/notification_types.h"
 
@@ -17,57 +15,11 @@
 
 const char kPhoneName[] = "Nexus 6";
 
-class TestMessageCenter : public message_center::FakeMessageCenter {
- public:
-  TestMessageCenter() : message_center::FakeMessageCenter() {}
-  ~TestMessageCenter() override {}
-
-  // message_center::FakeMessageCenter:
-  message_center::Notification* FindVisibleNotificationById(
-      const std::string& id) override {
-    auto iter = std::find_if(
-        notifications_.begin(), notifications_.end(),
-        [id](const std::shared_ptr<message_center::Notification> notification) {
-          return notification->id() == id;
-        });
-    return iter != notifications_.end() ? iter->get() : nullptr;
-  }
-
-  void AddNotification(
-      std::unique_ptr<message_center::Notification> notification) override {
-    notifications_.push_back(std::move(notification));
-  }
-
-  void UpdateNotification(
-      const std::string& old_id,
-      std::unique_ptr<message_center::Notification> new_notification) override {
-    RemoveNotification(old_id, false /* by_user */);
-    AddNotification(std::move(new_notification));
-  }
-
-  void RemoveNotification(const std::string& id, bool by_user) override {
-    if (!FindVisibleNotificationById(id))
-      return;
-
-    notifications_.erase(std::find_if(
-        notifications_.begin(), notifications_.end(),
-        [id](const std::shared_ptr<message_center::Notification> notification) {
-          return notification->id() == id;
-        }));
-  }
-
- private:
-  std::vector<std::shared_ptr<message_center::Notification>> notifications_;
-
-  DISALLOW_COPY_AND_ASSIGN(TestMessageCenter);
-};
-
 class TestableNotificationController
     : public EasyUnlockNotificationControllerChromeOS {
  public:
-  TestableNotificationController(Profile* profile,
-                                 message_center::MessageCenter* message_center)
-      : EasyUnlockNotificationControllerChromeOS(profile, message_center) {}
+  explicit TestableNotificationController(Profile* profile)
+      : EasyUnlockNotificationControllerChromeOS(profile) {}
 
   ~TestableNotificationController() override {}
 
@@ -81,17 +33,28 @@
 
 }  // namespace
 
-class EasyUnlockNotificationControllerChromeOSTest : public ::testing::Test {
+class EasyUnlockNotificationControllerChromeOSTest
+    : public BrowserWithTestWindowTest {
  protected:
-  EasyUnlockNotificationControllerChromeOSTest()
-      : notification_controller_(&profile_, &message_center_) {}
+  EasyUnlockNotificationControllerChromeOSTest() {}
 
   ~EasyUnlockNotificationControllerChromeOSTest() override {}
 
-  const content::TestBrowserThreadBundle thread_bundle_;
-  TestingProfile profile_;
-  TestMessageCenter message_center_;
-  testing::StrictMock<TestableNotificationController> notification_controller_;
+  void SetUp() override {
+    BrowserWithTestWindowTest::SetUp();
+
+    display_service_ =
+        std::make_unique<NotificationDisplayServiceTester>(profile());
+    notification_controller_ =
+        std::make_unique<testing::StrictMock<TestableNotificationController>>(
+            profile());
+  }
+
+  // const content::TestBrowserThreadBundle thread_bundle_;
+  // TestMessageCenter message_center_;
+  std::unique_ptr<testing::StrictMock<TestableNotificationController>>
+      notification_controller_;
+  std::unique_ptr<NotificationDisplayServiceTester> display_service_;
 
  private:
   DISALLOW_COPY_AND_ASSIGN(EasyUnlockNotificationControllerChromeOSTest);
@@ -101,19 +64,19 @@
        TestShowChromebookAddedNotification) {
   const char kNotificationId[] = "easyunlock_notification_ids.chromebook_added";
 
-  notification_controller_.ShowChromebookAddedNotification();
-  message_center::Notification* notification =
-      message_center_.FindVisibleNotificationById(kNotificationId);
+  notification_controller_->ShowChromebookAddedNotification();
+  base::Optional<message_center::Notification> notification =
+      display_service_->GetNotification(kNotificationId);
   ASSERT_TRUE(notification);
   ASSERT_EQ(1u, notification->buttons().size());
   EXPECT_EQ(message_center::SYSTEM_PRIORITY, notification->priority());
 
   // Clicking notification button should launch settings.
-  EXPECT_CALL(notification_controller_, LaunchEasyUnlockSettings());
+  EXPECT_CALL(*notification_controller_, LaunchEasyUnlockSettings());
   notification->ButtonClick(0);
 
   // Clicking the notification itself should also launch settings.
-  EXPECT_CALL(notification_controller_, LaunchEasyUnlockSettings());
+  EXPECT_CALL(*notification_controller_, LaunchEasyUnlockSettings());
   notification->Click();
 }
 
@@ -121,19 +84,19 @@
        TestShowPairingChangeNotification) {
   const char kNotificationId[] = "easyunlock_notification_ids.pairing_change";
 
-  notification_controller_.ShowPairingChangeNotification();
-  message_center::Notification* notification =
-      message_center_.FindVisibleNotificationById(kNotificationId);
+  notification_controller_->ShowPairingChangeNotification();
+  base::Optional<message_center::Notification> notification =
+      display_service_->GetNotification(kNotificationId);
   ASSERT_TRUE(notification);
   ASSERT_EQ(2u, notification->buttons().size());
   EXPECT_EQ(message_center::SYSTEM_PRIORITY, notification->priority());
 
   // Clicking 1st notification button should lock screen settings.
-  EXPECT_CALL(notification_controller_, LockScreen());
+  EXPECT_CALL(*notification_controller_, LockScreen());
   notification->ButtonClick(0);
 
   // Clicking 2nd notification button should launch settings.
-  EXPECT_CALL(notification_controller_, LaunchEasyUnlockSettings());
+  EXPECT_CALL(*notification_controller_, LaunchEasyUnlockSettings());
   notification->ButtonClick(1);
 
   // Clicking the notification itself should do nothing.
@@ -145,9 +108,9 @@
   const char kNotificationId[] =
       "easyunlock_notification_ids.pairing_change_applied";
 
-  notification_controller_.ShowPairingChangeAppliedNotification(kPhoneName);
-  message_center::Notification* notification =
-      message_center_.FindVisibleNotificationById(kNotificationId);
+  notification_controller_->ShowPairingChangeAppliedNotification(kPhoneName);
+  base::Optional<message_center::Notification> notification =
+      display_service_->GetNotification(kNotificationId);
   ASSERT_TRUE(notification);
   ASSERT_EQ(1u, notification->buttons().size());
   EXPECT_EQ(message_center::SYSTEM_PRIORITY, notification->priority());
@@ -157,11 +120,11 @@
             notification->message().find(base::UTF8ToUTF16(kPhoneName)));
 
   // Clicking notification button should launch settings.
-  EXPECT_CALL(notification_controller_, LaunchEasyUnlockSettings());
+  EXPECT_CALL(*notification_controller_, LaunchEasyUnlockSettings());
   notification->ButtonClick(0);
 
   // Clicking the notification itself should also launch settings.
-  EXPECT_CALL(notification_controller_, LaunchEasyUnlockSettings());
+  EXPECT_CALL(*notification_controller_, LaunchEasyUnlockSettings());
   notification->Click();
 }
 
@@ -171,30 +134,30 @@
   const char kPairingAppliedId[] =
       "easyunlock_notification_ids.pairing_change_applied";
 
-  notification_controller_.ShowPairingChangeNotification();
-  EXPECT_TRUE(message_center_.FindVisibleNotificationById(kPairingChangeId));
+  notification_controller_->ShowPairingChangeNotification();
+  EXPECT_TRUE(display_service_->GetNotification(kPairingChangeId));
 
-  notification_controller_.ShowPairingChangeAppliedNotification(kPhoneName);
-  EXPECT_FALSE(message_center_.FindVisibleNotificationById(kPairingChangeId));
-  EXPECT_TRUE(message_center_.FindVisibleNotificationById(kPairingAppliedId));
+  notification_controller_->ShowPairingChangeAppliedNotification(kPhoneName);
+  EXPECT_FALSE(display_service_->GetNotification(kPairingChangeId));
+  EXPECT_TRUE(display_service_->GetNotification(kPairingAppliedId));
 }
 
 TEST_F(EasyUnlockNotificationControllerChromeOSTest,
        TestShowPromotionNotification) {
   const char kNotificationId[] = "easyunlock_notification_ids.promotion";
 
-  notification_controller_.ShowPromotionNotification();
-  message_center::Notification* notification =
-      message_center_.FindVisibleNotificationById(kNotificationId);
+  notification_controller_->ShowPromotionNotification();
+  base::Optional<message_center::Notification> notification =
+      display_service_->GetNotification(kNotificationId);
   ASSERT_TRUE(notification);
   ASSERT_EQ(1u, notification->buttons().size());
   EXPECT_EQ(message_center::SYSTEM_PRIORITY, notification->priority());
 
   // Clicking notification button should launch settings.
-  EXPECT_CALL(notification_controller_, LaunchEasyUnlockSettings());
+  EXPECT_CALL(*notification_controller_, LaunchEasyUnlockSettings());
   notification->ButtonClick(0);
 
   // Clicking the notification itself should also launch settings.
-  EXPECT_CALL(notification_controller_, LaunchEasyUnlockSettings());
+  EXPECT_CALL(*notification_controller_, LaunchEasyUnlockSettings());
   notification->Click();
 }
diff --git a/chrome/browser/ui/ash/accessibility/ax_tree_source_aura_unittest.cc b/chrome/browser/ui/ash/accessibility/ax_tree_source_aura_unittest.cc
index bfff83c..3704424 100644
--- a/chrome/browser/ui/ash/accessibility/ax_tree_source_aura_unittest.cc
+++ b/chrome/browser/ui/ash/accessibility/ax_tree_source_aura_unittest.cc
@@ -78,6 +78,9 @@
 };
 
 TEST_F(AXTreeSourceAuraTest, Accessors) {
+  // Focus the textfield so the cursor does not disappear.
+  textfield_->RequestFocus();
+
   AXTreeSourceAura ax_tree;
   ASSERT_TRUE(ax_tree.GetRoot());
 
diff --git a/chrome/browser/ui/cocoa/toolbar/toolbar_controller.mm b/chrome/browser/ui/cocoa/toolbar/toolbar_controller.mm
index 89c59aa9..0958fe6 100644
--- a/chrome/browser/ui/cocoa/toolbar/toolbar_controller.mm
+++ b/chrome/browser/ui/cocoa/toolbar/toolbar_controller.mm
@@ -4,10 +4,8 @@
 
 #import "chrome/browser/ui/cocoa/toolbar/toolbar_controller.h"
 
-#include <sys/stat.h>
 #include <algorithm>
 
-#include "base/debug/crash_logging.h"
 #include "base/mac/bundle_locations.h"
 #include "base/mac/foundation_util.h"
 #include "base/mac/mac_util.h"
@@ -54,7 +52,6 @@
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/browser/ui/toolbar/app_menu_icon_controller.h"
 #include "chrome/browser/ui/toolbar/app_menu_model.h"
-#include "chrome/common/crash_keys.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/grit/chromium_strings.h"
 #include "chrome/grit/generated_resources.h"
@@ -256,25 +253,6 @@
 }
 
 - (void)viewDidLoadImpl {
-  // Temporary: collect information about a potentially missing or inaccessible
-  // nib (https://crbug.com/685985)
-  NSString* nibPath = [self.nibBundle pathForResource:@"Toolbar" ofType:@"nib"];
-  struct stat sb;
-  int nibErrno = 0;
-  if (stat(nibPath.fileSystemRepresentation, &sb) != 0) {
-    nibErrno = errno;
-  }
-  NSString* closestPath = nibPath;
-  while (closestPath && stat(closestPath.fileSystemRepresentation, &sb) != 0) {
-    closestPath = [closestPath stringByDeletingLastPathComponent];
-  }
-  base::debug::ScopedCrashKey nibCrashKey {
-    crash_keys::mac::kToolbarNibInfo,
-        [NSString stringWithFormat:@"errno: %d nib: %@ closest: %@", nibErrno,
-                                   nibPath, closestPath]
-            .UTF8String
-  };
-
   // When linking and running on 10.10+, both -awakeFromNib and -viewDidLoad may
   // be called, don't initialize twice.
   if (locationBarView_) {
diff --git a/chrome/browser/ui/views/frame/browser_command_handler_linux.cc b/chrome/browser/ui/views/frame/browser_command_handler_linux.cc
index 563f7f11..c03381e1 100644
--- a/chrome/browser/ui/views/frame/browser_command_handler_linux.cc
+++ b/chrome/browser/ui/views/frame/browser_command_handler_linux.cc
@@ -9,6 +9,7 @@
 #include "chrome/browser/ui/views/frame/browser_view.h"
 #include "content/public/browser/navigation_controller.h"
 #include "content/public/browser/web_contents.h"
+#include "content/public/common/content_features.h"
 #include "ui/aura/window.h"
 #include "ui/events/event.h"
 
@@ -32,6 +33,10 @@
   if (event->type() != ui::ET_MOUSE_PRESSED)
     return;
 
+  // If extended mouse buttons are supported handle them in the renderer.
+  if (base::FeatureList::IsEnabled(features::kExtendedMouseButtons))
+    return;
+
   bool back_button_pressed =
       (event->changed_button_flags() == ui::EF_BACK_MOUSE_BUTTON);
   bool forward_button_pressed =
diff --git a/chrome/common/crash_keys.cc b/chrome/common/crash_keys.cc
index 0c05948..65d5b3a 100644
--- a/chrome/common/crash_keys.cc
+++ b/chrome/common/crash_keys.cc
@@ -58,27 +58,6 @@
 const char kNumberOfUsers[] = "num-users";
 #endif
 
-#if defined(OS_MACOSX)
-namespace mac {
-
-const char kFirstNSException[] = "firstexception";
-const char kFirstNSExceptionTrace[] = "firstexception_bt";
-
-const char kLastNSException[] = "lastexception";
-const char kLastNSExceptionTrace[] = "lastexception_bt";
-
-const char kNSException[] = "nsexception";
-const char kNSExceptionTrace[] = "nsexception_bt";
-
-const char kSendAction[] = "sendaction";
-
-const char kNSEvent[] = "nsevent";
-
-const char kToolbarNibInfo[] = "toolbar-nib-info";
-
-}  // namespace mac
-#endif
-
 const char kViewCount[] = "view-count";
 
 const char kUserCloudPolicyManagerConnectTrace[] =
@@ -148,15 +127,6 @@
     {kNumberOfUsers, kSmallSize},
 #endif
 #if defined(OS_MACOSX)
-    {mac::kFirstNSException, kMediumSize},
-    {mac::kFirstNSExceptionTrace, kMediumSize},
-    {mac::kLastNSException, kMediumSize},
-    {mac::kLastNSExceptionTrace, kMediumSize},
-    {mac::kNSException, kMediumSize},
-    {mac::kNSExceptionTrace, kMediumSize},
-    {mac::kSendAction, kMediumSize},
-    {mac::kNSEvent, kMediumSize},
-    {mac::kToolbarNibInfo, kMediumSize},
     // content/:
     {"text-input-context-client", kMediumSize},
 // media/:
diff --git a/chrome/common/crash_keys.h b/chrome/common/crash_keys.h
index 38e43f2..e789e26 100644
--- a/chrome/common/crash_keys.h
+++ b/chrome/common/crash_keys.h
@@ -105,35 +105,6 @@
 extern const char kNumberOfUsers[];
 #endif
 
-#if defined(OS_MACOSX)
-namespace mac {
-
-// Used to report the first Cocoa/Mac NSException and its backtrace.
-extern const char kFirstNSException[];
-extern const char kFirstNSExceptionTrace[];
-
-// Used to report the last Cocoa/Mac NSException and its backtrace.
-extern const char kLastNSException[];
-extern const char kLastNSExceptionTrace[];
-
-// Records the current NSException as it is being created, and its backtrace.
-extern const char kNSException[];
-extern const char kNSExceptionTrace[];
-
-// In the CrApplication, records information about the current event's
-// target-action.
-extern const char kSendAction[];
-
-// In the CrApplication, records information about the current event.
-extern const char kNSEvent[];
-
-// TEMPORARY: Information about Toolbar.nib, stored right after it's supposed
-// to have loaded.  https://crbug.com/685985
-extern const char kToolbarNibInfo[];
-
-}  // namespace mac
-#endif
-
 // Numbers of active views.
 extern const char kViewCount[];
 
diff --git a/chrome/common/extensions/api/automation.idl b/chrome/common/extensions/api/automation.idl
index b738ef2..51ed85f 100644
--- a/chrome/common/extensions/api/automation.idl
+++ b/chrome/common/extensions/api/automation.idl
@@ -643,6 +643,12 @@
     // Miscellaneous attributes.
     //
 
+    // Aria auto complete.
+    DOMString? autoComplete;
+
+    // The name of the programmatic backing object.
+    DOMString? className;
+
     // A map containing all HTML attributes and their values
     // <jsexterns>@type {Object<string>}</jsexterns>
     object? htmlAttributes;
diff --git a/chrome/renderer/resources/extensions/automation/automation_node.js b/chrome/renderer/resources/extensions/automation/automation_node.js
index 07de345..f80b84c4 100644
--- a/chrome/renderer/resources/extensions/automation/automation_node.js
+++ b/chrome/renderer/resources/extensions/automation/automation_node.js
@@ -819,6 +819,8 @@
 var stringAttributes = [
     'accessKey',
     'ariaInvalidValue',
+    'autoComplete',
+    'className',
     'containerLiveRelevant',
     'containerLiveStatus',
     'description',
diff --git a/chrome/test/chromedriver/test/run_all_tests.py b/chrome/test/chromedriver/test/run_all_tests.py
index 47bcc78..ca9a248 100755
--- a/chrome/test/chromedriver/test/run_all_tests.py
+++ b/chrome/test/chromedriver/test/run_all_tests.py
@@ -199,10 +199,25 @@
 
       # TODO(samuong): speculative fix for crbug.com/611886
       os.environ['CHROME_DEVEL_SANDBOX'] = '/opt/chromium/chrome_sandbox'
-    else:
+
+    # Linux64 build numbers
+    elif util.isLinux():
       versions['63'] = '508578'
-      versions['62'] = '499119'
+      versions['62'] = '499100'
       versions['61'] = '488595'
+
+    # Mac build numbers
+    elif util.isMac():
+      versions['63'] = '508578'
+      versions['62'] = '499098'
+      versions['61'] = '488595'
+
+    # Windows build numbers
+    elif util.isWindows():
+      versions['63'] = '508578'
+      versions['62'] = '499101'
+      versions['61'] = '488595'
+
     code = 0
     for version, revision in versions.iteritems():
       if options.chrome_version and version != options.chrome_version:
diff --git a/chrome/test/data/webui/extensions/extension_manager_unit_test.js b/chrome/test/data/webui/extensions/extension_manager_unit_test.js
index 50c5f82..ebf68e0 100644
--- a/chrome/test/data/webui/extensions/extension_manager_unit_test.js
+++ b/chrome/test/data/webui/extensions/extension_manager_unit_test.js
@@ -175,7 +175,8 @@
 
       service.itemStateChangedTarget.callListeners({
         event_type: chrome.developerPrivate.EventType.UNINSTALLED,
-        // When an extension is unistalled, only the ID is passed back from C++.
+        // When an extension is uninstalled, only the ID is passed back from
+        // C++.
         item_id: extension.id,
       });
 
@@ -189,7 +190,7 @@
 
     // Test case where an extension is uninstalled from the details view. User
     // should be forwarded to the main view.
-    test(assert(TestNames.UninstallFromDetails), function() {
+    test(assert(TestNames.UninstallFromDetails), function(done) {
       const extension = extension_test_util.createExtensionInfo(
           {location: 'FROM_STORE', name: 'Alpha', id: 'a'.repeat(32)});
       simulateExtensionInstall(extension);
@@ -199,13 +200,17 @@
       Polymer.dom.flush();
       assertViewActive('extensions-detail-view');
 
-      service.itemStateChangedTarget.callListeners({
-        event_type: chrome.developerPrivate.EventType.UNINSTALLED,
-        // When an extension is unistalled, only the ID is passed back from C++.
-        item_id: extension.id,
+      window.addEventListener('popstate', () => {
+        assertViewActive('extensions-item-list');
+        done();
       });
 
-      assertViewActive('extensions-item-list');
+      service.itemStateChangedTarget.callListeners({
+        event_type: chrome.developerPrivate.EventType.UNINSTALLED,
+        // When an extension is uninstalled, only the ID is passed back from
+        // C++.
+        item_id: extension.id,
+      });
     });
 
     test(assert(TestNames.ToggleIncognitoMode), function() {
diff --git a/chrome/test/data/webui/extensions/extension_navigation_helper_test.js b/chrome/test/data/webui/extensions/extension_navigation_helper_test.js
index 7565d86..cc6efb03 100644
--- a/chrome/test/data/webui/extensions/extension_navigation_helper_test.js
+++ b/chrome/test/data/webui/extensions/extension_navigation_helper_test.js
@@ -157,6 +157,12 @@
       navigationHelper.updateHistory(
           {page: Page.DETAILS, extensionId: id2});
       expectEquals(++expectedLength, history.length);
+
+      // Using replaceWith, which passes true for replaceState should not push
+      // state.
+      navigationHelper.updateHistory(
+          {page: Page.DETAILS, extensionId: id1}, true /* replaceState */);
+      expectEquals(expectedLength, history.length);
     });
 
     test(assert(TestNames.SupportedRoutes), function() {
diff --git a/components/data_reduction_proxy/core/common/data_reduction_proxy_headers.cc b/components/data_reduction_proxy/core/common/data_reduction_proxy_headers.cc
index d1f33cf..23ec4eab 100644
--- a/components/data_reduction_proxy/core/common/data_reduction_proxy_headers.cc
+++ b/components/data_reduction_proxy/core/common/data_reduction_proxy_headers.cc
@@ -23,8 +23,6 @@
 #include "net/http/http_util.h"
 #include "net/url_request/url_request.h"
 
-using base::StringPiece;
-
 namespace {
 
 const char kChromeProxyHeader[] = "chrome-proxy";
@@ -290,7 +288,8 @@
     if (StartsWithActionPrefix(value, action_prefix)) {
       int64_t seconds;
       if (!base::StringToInt64(
-              StringPiece(value).substr(action_prefix.size() + 1), &seconds) ||
+              base::StringPiece(value).substr(action_prefix.size() + 1),
+              &seconds) ||
           seconds < 0) {
         continue;  // In case there is a well formed instruction.
       }
diff --git a/content/browser/renderer_host/clipboard_host_impl.cc b/content/browser/renderer_host/clipboard_host_impl.cc
index cadcf99b..f34527b 100644
--- a/content/browser/renderer_host/clipboard_host_impl.cc
+++ b/content/browser/renderer_host/clipboard_host_impl.cc
@@ -68,46 +68,52 @@
   clipboard_writer_->Reset();
 }
 
-void ClipboardHostImpl::GetSequenceNumber(ui::ClipboardType type,
+void ClipboardHostImpl::GetSequenceNumber(blink::mojom::ClipboardBuffer buffer,
                                           GetSequenceNumberCallback callback) {
+  ui::ClipboardType clipboard_type;
+  ConvertBufferType(buffer, &clipboard_type);
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  std::move(callback).Run(clipboard_->GetSequenceNumber(type));
+  std::move(callback).Run(clipboard_->GetSequenceNumber(clipboard_type));
 }
 
 void ClipboardHostImpl::ReadAvailableTypes(
-    ui::ClipboardType type,
+    blink::mojom::ClipboardBuffer buffer,
     ReadAvailableTypesCallback callback) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  ui::ClipboardType clipboard_type;
+  ConvertBufferType(buffer, &clipboard_type);
   std::vector<base::string16> types;
   bool contains_filenames;
-  clipboard_->ReadAvailableTypes(type, &types, &contains_filenames);
+  clipboard_->ReadAvailableTypes(clipboard_type, &types, &contains_filenames);
   std::move(callback).Run(types, contains_filenames);
 }
 
-void ClipboardHostImpl::IsFormatAvailable(content::ClipboardFormat format,
-                                          ui::ClipboardType type,
+void ClipboardHostImpl::IsFormatAvailable(blink::mojom::ClipboardFormat format,
+                                          blink::mojom::ClipboardBuffer buffer,
                                           IsFormatAvailableCallback callback) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  ui::ClipboardType clipboard_type;
+  ConvertBufferType(buffer, &clipboard_type);
   bool result = false;
   switch (format) {
-    case CLIPBOARD_FORMAT_PLAINTEXT:
+    case blink::mojom::ClipboardFormat::kPlaintext:
       result = clipboard_->IsFormatAvailable(
-                   ui::Clipboard::GetPlainTextWFormatType(), type) ||
+                   ui::Clipboard::GetPlainTextWFormatType(), clipboard_type) ||
                clipboard_->IsFormatAvailable(
-                   ui::Clipboard::GetPlainTextFormatType(), type);
+                   ui::Clipboard::GetPlainTextFormatType(), clipboard_type);
       break;
-    case CLIPBOARD_FORMAT_HTML:
+    case blink::mojom::ClipboardFormat::kHtml:
       result = clipboard_->IsFormatAvailable(ui::Clipboard::GetHtmlFormatType(),
-                                             type);
+                                             clipboard_type);
       break;
-    case CLIPBOARD_FORMAT_SMART_PASTE:
+    case blink::mojom::ClipboardFormat::kSmartPaste:
       result = clipboard_->IsFormatAvailable(
-          ui::Clipboard::GetWebKitSmartPasteFormatType(), type);
+          ui::Clipboard::GetWebKitSmartPasteFormatType(), clipboard_type);
       break;
-    case CLIPBOARD_FORMAT_BOOKMARK:
+    case blink::mojom::ClipboardFormat::kBookmark:
 #if defined(OS_WIN) || defined(OS_MACOSX)
       result = clipboard_->IsFormatAvailable(ui::Clipboard::GetUrlWFormatType(),
-                                             type);
+                                             clipboard_type);
 #else
       result = false;
 #endif
@@ -116,47 +122,59 @@
   std::move(callback).Run(result);
 }
 
-void ClipboardHostImpl::ReadText(ui::ClipboardType type,
+void ClipboardHostImpl::ReadText(blink::mojom::ClipboardBuffer buffer,
                                  ReadTextCallback callback) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  ui::ClipboardType clipboard_type;
+  ConvertBufferType(buffer, &clipboard_type);
+
   base::string16 result;
   if (clipboard_->IsFormatAvailable(ui::Clipboard::GetPlainTextWFormatType(),
-                                    type)) {
-    clipboard_->ReadText(type, &result);
+                                    clipboard_type)) {
+    clipboard_->ReadText(clipboard_type, &result);
   } else if (clipboard_->IsFormatAvailable(
-                 ui::Clipboard::GetPlainTextFormatType(), type)) {
+                 ui::Clipboard::GetPlainTextFormatType(), clipboard_type)) {
     std::string ascii;
-    clipboard_->ReadAsciiText(type, &ascii);
+    clipboard_->ReadAsciiText(clipboard_type, &ascii);
     result = base::ASCIIToUTF16(ascii);
   }
   std::move(callback).Run(result);
 }
 
-void ClipboardHostImpl::ReadHtml(ui::ClipboardType type,
+void ClipboardHostImpl::ReadHtml(blink::mojom::ClipboardBuffer buffer,
                                  ReadHtmlCallback callback) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  ui::ClipboardType clipboard_type;
+  ConvertBufferType(buffer, &clipboard_type);
+
   base::string16 markup;
   std::string src_url_str;
   uint32_t fragment_start = 0;
   uint32_t fragment_end = 0;
-  clipboard_->ReadHTML(type, &markup, &src_url_str, &fragment_start,
+  clipboard_->ReadHTML(clipboard_type, &markup, &src_url_str, &fragment_start,
                        &fragment_end);
   std::move(callback).Run(std::move(markup), GURL(src_url_str), fragment_start,
                           fragment_end);
 }
 
-void ClipboardHostImpl::ReadRtf(ui::ClipboardType type,
+void ClipboardHostImpl::ReadRtf(blink::mojom::ClipboardBuffer buffer,
                                 ReadRtfCallback callback) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
+
+  ui::ClipboardType clipboard_type;
+  ConvertBufferType(buffer, &clipboard_type);
   std::string result;
-  clipboard_->ReadRTF(type, &result);
+  clipboard_->ReadRTF(clipboard_type, &result);
   std::move(callback).Run(result);
 }
 
-void ClipboardHostImpl::ReadImage(ui::ClipboardType type,
+void ClipboardHostImpl::ReadImage(blink::mojom::ClipboardBuffer buffer,
                                   ReadImageCallback callback) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  SkBitmap bitmap = clipboard_->ReadImage(type);
+  ui::ClipboardType clipboard_type;
+  ConvertBufferType(buffer, &clipboard_type);
+
+  SkBitmap bitmap = clipboard_->ReadImage(clipboard_type);
 
   base::PostTaskWithTraits(
       FROM_HERE,
@@ -215,22 +233,25 @@
   std::move(callback).Run(std::string(), std::string(), -1);
 }
 
-void ClipboardHostImpl::ReadCustomData(ui::ClipboardType clipboard_type,
+void ClipboardHostImpl::ReadCustomData(blink::mojom::ClipboardBuffer buffer,
                                        const base::string16& type,
                                        ReadCustomDataCallback callback) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  ui::ClipboardType clipboard_type;
+  ConvertBufferType(buffer, &clipboard_type);
+
   base::string16 result;
   clipboard_->ReadCustomData(clipboard_type, type, &result);
   std::move(callback).Run(result);
 }
 
-void ClipboardHostImpl::WriteText(ui::ClipboardType clipboard_type,
+void ClipboardHostImpl::WriteText(blink::mojom::ClipboardBuffer,
                                   const base::string16& text) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   clipboard_writer_->WriteText(text);
 }
 
-void ClipboardHostImpl::WriteHtml(ui::ClipboardType clipboard_type,
+void ClipboardHostImpl::WriteHtml(blink::mojom::ClipboardBuffer,
                                   const base::string16& markup,
                                   const GURL& url) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
@@ -238,13 +259,13 @@
 }
 
 void ClipboardHostImpl::WriteSmartPasteMarker(
-    ui::ClipboardType clipboard_type) {
+    blink::mojom::ClipboardBuffer buffer) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   clipboard_writer_->WriteWebSmartPaste();
 }
 
 void ClipboardHostImpl::WriteCustomData(
-    ui::ClipboardType type,
+    blink::mojom::ClipboardBuffer,
     const std::unordered_map<base::string16, base::string16>& data) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   base::Pickle pickle;
@@ -253,7 +274,7 @@
       pickle, ui::Clipboard::GetWebCustomDataFormatType());
 }
 
-void ClipboardHostImpl::WriteBookmark(ui::ClipboardType clipboard_type,
+void ClipboardHostImpl::WriteBookmark(blink::mojom::ClipboardBuffer,
                                       const std::string& url,
                                       const base::string16& title) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
@@ -261,7 +282,7 @@
 }
 
 void ClipboardHostImpl::WriteImage(
-    ui::ClipboardType type,
+    blink::mojom::ClipboardBuffer,
     const gfx::Size& size,
     mojo::ScopedSharedBufferHandle shared_buffer_handle) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
@@ -289,7 +310,7 @@
   clipboard_writer_->WriteImage(bitmap);
 }
 
-void ClipboardHostImpl::CommitWrite(ui::ClipboardType clipboard_type) {
+void ClipboardHostImpl::CommitWrite(blink::mojom::ClipboardBuffer) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   clipboard_writer_.reset(
       new ui::ScopedClipboardWriter(ui::CLIPBOARD_TYPE_COPY_PASTE));
@@ -300,4 +321,23 @@
   mojo::ReportBadMessage("Unexpected call to WriteStringToFindPboard.");
 }
 #endif
+
+void ClipboardHostImpl::ConvertBufferType(blink::mojom::ClipboardBuffer buffer,
+                                          ui::ClipboardType* result) {
+  *result = ui::CLIPBOARD_TYPE_COPY_PASTE;
+  switch (buffer) {
+    case blink::mojom::ClipboardBuffer::kStandard:
+      break;
+    case blink::mojom::ClipboardBuffer::kSelection:
+#if defined(USE_X11)
+      *result = ui::CLIPBOARD_TYPE_SELECTION;
+      break;
+#else
+      // Chrome OS and non-X11 unix builds do not support
+      // the X selection clipboad.
+      // TODO: remove the need for this case, see http://crbug.com/361753
+      mojo::ReportBadMessage("Cannot use kSelection on non X11 platforms.");
+#endif
+  }
+}
 }  // namespace content
diff --git a/content/browser/renderer_host/clipboard_host_impl.h b/content/browser/renderer_host/clipboard_host_impl.h
index 8887586b..23e01a15 100644
--- a/content/browser/renderer_host/clipboard_host_impl.h
+++ b/content/browser/renderer_host/clipboard_host_impl.h
@@ -17,7 +17,6 @@
 #include "base/memory/shared_memory.h"
 #include "build/build_config.h"
 #include "content/common/clipboard.mojom.h"
-#include "content/common/clipboard_format.h"
 #include "content/common/content_export.h"
 #include "content/public/browser/browser_associated_interface.h"
 #include "content/public/browser/browser_message_filter.h"
@@ -57,37 +56,44 @@
                                     ReadImageCallback callback);
 
   // content::mojom::ClipboardHost
-  void GetSequenceNumber(ui::ClipboardType type,
+  void GetSequenceNumber(blink::mojom::ClipboardBuffer buffer,
                          GetSequenceNumberCallback callback) override;
-  void IsFormatAvailable(content::ClipboardFormat format,
-                         ui::ClipboardType type,
+  void IsFormatAvailable(blink::mojom::ClipboardFormat format,
+                         blink::mojom::ClipboardBuffer buffer,
                          IsFormatAvailableCallback callback) override;
-  void ReadAvailableTypes(ui::ClipboardType type,
+  void ReadAvailableTypes(blink::mojom::ClipboardBuffer buffer,
                           ReadAvailableTypesCallback callback) override;
-  void ReadText(ui::ClipboardType type, ReadTextCallback callback) override;
-  void ReadHtml(ui::ClipboardType type, ReadHtmlCallback callback) override;
-  void ReadRtf(ui::ClipboardType type, ReadRtfCallback callback) override;
-  void ReadImage(ui::ClipboardType type, ReadImageCallback callback) override;
-  void ReadCustomData(ui::ClipboardType clipboard_type,
+  void ReadText(blink::mojom::ClipboardBuffer buffer,
+                ReadTextCallback callback) override;
+  void ReadHtml(blink::mojom::ClipboardBuffer buffer,
+                ReadHtmlCallback callback) override;
+  void ReadRtf(blink::mojom::ClipboardBuffer buffer,
+               ReadRtfCallback callback) override;
+  void ReadImage(blink::mojom::ClipboardBuffer buffer,
+                 ReadImageCallback callback) override;
+  void ReadCustomData(blink::mojom::ClipboardBuffer buffer,
                       const base::string16& type,
                       ReadCustomDataCallback callback) override;
-  void WriteText(ui::ClipboardType type, const base::string16& text) override;
-  void WriteHtml(ui::ClipboardType type,
+  void WriteText(blink::mojom::ClipboardBuffer buffer,
+                 const base::string16& text) override;
+  void WriteHtml(blink::mojom::ClipboardBuffer buffer,
                  const base::string16& markup,
                  const GURL& url) override;
-  void WriteSmartPasteMarker(ui::ClipboardType type) override;
+  void WriteSmartPasteMarker(blink::mojom::ClipboardBuffer buffer) override;
   void WriteCustomData(
-      ui::ClipboardType type,
+      blink::mojom::ClipboardBuffer buffer,
       const std::unordered_map<base::string16, base::string16>& data) override;
-  void WriteBookmark(ui::ClipboardType type,
+  void WriteBookmark(blink::mojom::ClipboardBuffer buffer,
                      const std::string& url,
                      const base::string16& title) override;
-  void WriteImage(ui::ClipboardType type,
+  void WriteImage(blink::mojom::ClipboardBuffer buffer,
                   const gfx::Size& size_in_pixels,
                   mojo::ScopedSharedBufferHandle shared_buffer_handle) override;
-  void CommitWrite(ui::ClipboardType type) override;
+  void CommitWrite(blink::mojom::ClipboardBuffer buffer) override;
   void WriteStringToFindPboard(const base::string16& text) override;
 
+  void ConvertBufferType(blink::mojom::ClipboardBuffer, ui::ClipboardType*);
+
   ui::Clipboard* clipboard_;  // Not owned
   scoped_refptr<ChromeBlobStorageContext> blob_storage_context_;
   std::unique_ptr<ui::ScopedClipboardWriter> clipboard_writer_;
diff --git a/content/browser/renderer_host/clipboard_host_impl_unittest.cc b/content/browser/renderer_host/clipboard_host_impl_unittest.cc
index 618b97cf..e0e5d5e 100644
--- a/content/browser/renderer_host/clipboard_host_impl_unittest.cc
+++ b/content/browser/renderer_host/clipboard_host_impl_unittest.cc
@@ -35,12 +35,12 @@
                       mojo::ScopedSharedBufferHandle shared_memory,
                       size_t shared_memory_size) {
     host_->WriteImage(
-        ui::CLIPBOARD_TYPE_COPY_PASTE, size,
+        blink::mojom::ClipboardBuffer::kStandard, size,
         shared_memory->Clone(mojo::SharedBufferHandle::AccessMode::READ_ONLY));
   }
 
   void CallCommitWrite() {
-    host_->CommitWrite(ui::CLIPBOARD_TYPE_COPY_PASTE);
+    host_->CommitWrite(blink::mojom::ClipboardBuffer::kStandard);
     base::RunLoop().RunUntilIdle();
   }
 
diff --git a/content/browser/renderer_host/render_widget_host_view_event_handler.cc b/content/browser/renderer_host/render_widget_host_view_event_handler.cc
index 8302a85..50f0b90 100644
--- a/content/browser/renderer_host/render_widget_host_view_event_handler.cc
+++ b/content/browser/renderer_host/render_widget_host_view_event_handler.cc
@@ -18,6 +18,7 @@
 #include "content/common/site_isolation_policy.h"
 #include "content/public/browser/render_view_host.h"
 #include "content/public/browser/render_widget_host.h"
+#include "content/public/common/content_features.h"
 #include "ui/aura/client/cursor_client.h"
 #include "ui/aura/client/focus_client.h"
 #include "ui/aura/client/screen_position_client.h"
@@ -82,10 +83,11 @@
 
 // We don't mark these as handled so that they're sent back to the
 // DefWindowProc so it can generate WM_APPCOMMAND as necessary.
-bool IsXButtonUpEvent(const ui::MouseEvent* event) {
+bool ShouldGenerateAppCommand(const ui::MouseEvent* event) {
 #if defined(OS_WIN)
   switch (event->native_event().message) {
     case WM_XBUTTONUP:
+      return !base::FeatureList::IsEnabled(features::kExtendedMouseButtons);
     case WM_NCXBUTTONUP:
       return true;
   }
@@ -396,7 +398,7 @@
       break;
   }
 
-  if (!IsXButtonUpEvent(event))
+  if (!ShouldGenerateAppCommand(event))
     event->SetHandled();
 }
 
@@ -599,6 +601,7 @@
     case WM_XBUTTONDOWN:
     case WM_XBUTTONUP:
     case WM_XBUTTONDBLCLK:
+      return base::FeatureList::IsEnabled(features::kExtendedMouseButtons);
     case WM_NCMOUSELEAVE:
     case WM_NCMOUSEMOVE:
     case WM_NCLBUTTONDOWN:
@@ -618,18 +621,20 @@
       break;
   }
 #elif defined(USE_X11)
-  // Renderer only supports standard mouse buttons, so ignore programmable
-  // buttons.
-  switch (event->type()) {
-    case ui::ET_MOUSE_PRESSED:
-    case ui::ET_MOUSE_RELEASED: {
-      const int kAllowedButtons = ui::EF_LEFT_MOUSE_BUTTON |
-                                  ui::EF_MIDDLE_MOUSE_BUTTON |
-                                  ui::EF_RIGHT_MOUSE_BUTTON;
-      return (event->flags() & kAllowedButtons) != 0;
+  if (!base::FeatureList::IsEnabled(features::kExtendedMouseButtons)) {
+    // Renderer only supports standard mouse buttons, so ignore programmable
+    // buttons.
+    switch (event->type()) {
+      case ui::ET_MOUSE_PRESSED:
+      case ui::ET_MOUSE_RELEASED: {
+        const int kAllowedButtons = ui::EF_LEFT_MOUSE_BUTTON |
+                                    ui::EF_MIDDLE_MOUSE_BUTTON |
+                                    ui::EF_RIGHT_MOUSE_BUTTON;
+        return (event->flags() & kAllowedButtons) != 0;
+      }
+      default:
+        break;
     }
-    default:
-      break;
   }
 #endif
   return true;
diff --git a/content/common/BUILD.gn b/content/common/BUILD.gn
index 2556092..29cc2d2 100644
--- a/content/common/BUILD.gn
+++ b/content/common/BUILD.gn
@@ -74,7 +74,6 @@
     "cache_storage/cache_storage_types.h",
     "child_process_host_impl.cc",
     "child_process_host_impl.h",
-    "clipboard_format.h",
     "common_sandbox_support_linux.cc",
     "content_constants_internal.cc",
     "content_constants_internal.h",
@@ -634,7 +633,6 @@
     "//skia/public/interfaces",
     "//storage/common:mojo_bindings",
     "//third_party/WebKit/public:mojo_bindings",
-    "//ui/base/clipboard/mojom:mojo_bindings",
     "//ui/base/mojo:mojo_bindings",
     "//ui/gfx/geometry/mojo",
     "//ui/gfx/mojo",
diff --git a/content/common/clipboard.mojom b/content/common/clipboard.mojom
index 6e12b27..d9172a55 100644
--- a/content/common/clipboard.mojom
+++ b/content/common/clipboard.mojom
@@ -5,48 +5,43 @@
 module content.mojom;
 
 import "mojo/common/string16.mojom";
-import "ui/base/clipboard/mojom/clipboard.mojom";
+import "third_party/WebKit/common/clipboard/clipboard.mojom";
 import "ui/gfx/geometry/mojo/geometry.mojom";
 import "url/mojo/url.mojom";
 
-enum ClipboardFormat {
-  kPlaintext,
-  kHtml,
-  kSmartPaste,
-  kBookmark,
-};
-
 interface ClipboardHost {
   [Sync]
-  GetSequenceNumber(ui.mojom.ClipboardType type) => (uint64 result);
+  GetSequenceNumber(blink.mojom.ClipboardBuffer buffer) => (uint64 result);
 
   [Sync]
-  IsFormatAvailable(ClipboardFormat format,
-                    ui.mojom.ClipboardType type) => (bool result);
+  IsFormatAvailable(blink.mojom.ClipboardFormat format,
+                    blink.mojom.ClipboardBuffer buffer) => (bool result);
 
   [Sync]
-  ReadAvailableTypes(ui.mojom.ClipboardType type) =>
+  ReadAvailableTypes(blink.mojom.ClipboardBuffer buffer) =>
       (array<mojo.common.mojom.String16> types, bool result);
 
   [Sync]
-  ReadText(ui.mojom.ClipboardType type) => (mojo.common.mojom.String16 result);
+  ReadText(blink.mojom.ClipboardBuffer buffer) =>
+      (mojo.common.mojom.String16 result);
 
   [Sync]
-  ReadHtml(ui.mojom.ClipboardType type) => (mojo.common.mojom.String16 markup,
-                                            url.mojom.Url url,
-                                            uint32 fragment_start,
-                                            uint32 fragment_end);
+  ReadHtml(blink.mojom.ClipboardBuffer buffer) =>
+      (mojo.common.mojom.String16 markup,
+       url.mojom.Url url,
+       uint32 fragment_start,
+       uint32 fragment_end);
 
   [Sync]
-  ReadRtf(ui.mojom.ClipboardType type) => (string result);
+  ReadRtf(blink.mojom.ClipboardBuffer buffer) => (string result);
 
   [Sync]
-  ReadImage(ui.mojom.ClipboardType type) => (string blob_uuid,
-                                             string mime_type,
-                                             int64 size);
+  ReadImage(blink.mojom.ClipboardBuffer buffer) => (string blob_uuid,
+                                                    string mime_type,
+                                                    int64 size);
 
   [Sync]
-  ReadCustomData(ui.mojom.ClipboardType clipboard_type,
+  ReadCustomData(blink.mojom.ClipboardBuffer buffer,
                  mojo.common.mojom.String16 type) =>
                      (mojo.common.mojom.String16 result);
 
@@ -54,31 +49,32 @@
   // sender sends the different types of data it'd like to write to the
   // receiver. Then, it sends a commit message to commit the data to the system
   // clipboard.
-  WriteText(ui.mojom.ClipboardType type, mojo.common.mojom.String16 text);
+  WriteText(blink.mojom.ClipboardBuffer buffer,
+            mojo.common.mojom.String16 text);
 
-  WriteHtml(ui.mojom.ClipboardType type,
+  WriteHtml(blink.mojom.ClipboardBuffer buffer,
             mojo.common.mojom.String16 markup,
             url.mojom.Url url);
 
-  WriteSmartPasteMarker(ui.mojom.ClipboardType type);
+  WriteSmartPasteMarker(blink.mojom.ClipboardBuffer buffer);
 
   WriteCustomData(
-      ui.mojom.ClipboardType type,
+      blink.mojom.ClipboardBuffer buffer,
       map<mojo.common.mojom.String16, mojo.common.mojom.String16> data);
 
   // TODO(dcheng): The |url| parameter should really be a GURL, but <canvas>'s
   // copy as image tries to set very long data: URLs on the clipboard. Using
   // GURL causes the browser to kill the renderer for sending a bad IPC (GURLs
   // bigger than 2 megabytes are considered to be bad). https://crbug.com/459822
-  WriteBookmark(ui.mojom.ClipboardType type,
+  WriteBookmark(blink.mojom.ClipboardBuffer buffer,
                 string url,
                 mojo.common.mojom.String16 title);
 
-  WriteImage(ui.mojom.ClipboardType type,
+  WriteImage(blink.mojom.ClipboardBuffer buffer,
              gfx.mojom.Size size_in_pixels,
              handle<shared_buffer> shared_buffer_handle);
 
-  CommitWrite(ui.mojom.ClipboardType type);
+  CommitWrite(blink.mojom.ClipboardBuffer buffer);
 
   // OS_MACOSX only
   WriteStringToFindPboard(mojo.common.mojom.String16 text);
diff --git a/content/common/clipboard.typemap b/content/common/clipboard.typemap
deleted file mode 100644
index 6eda0c1..0000000
--- a/content/common/clipboard.typemap
+++ /dev/null
@@ -1,11 +0,0 @@
-# Copyright 2017 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-mojom = "//content/common/clipboard.mojom"
-public_headers = [ "//content/common/clipboard_format.h" ]
-public_deps = [
-  "//ui/base",
-]
-traits_headers = [ "//content/common/clipboard_struct_traits.h" ]
-type_mappings = [ "content.mojom.ClipboardFormat=content::ClipboardFormat" ]
diff --git a/content/common/clipboard_format.h b/content/common/clipboard_format.h
deleted file mode 100644
index debb0c03..0000000
--- a/content/common/clipboard_format.h
+++ /dev/null
@@ -1,20 +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 CONTENT_COMMON_CLIPBOARD_FORMAT_H_
-#define CONTENT_COMMON_CLIPBOARD_FORMAT_H_
-
-namespace content {
-
-enum ClipboardFormat {
-  CLIPBOARD_FORMAT_PLAINTEXT,
-  CLIPBOARD_FORMAT_HTML,
-  CLIPBOARD_FORMAT_SMART_PASTE,
-  CLIPBOARD_FORMAT_BOOKMARK,
-  CLIPBOARD_FORMAT_LAST = CLIPBOARD_FORMAT_BOOKMARK,
-};
-
-}  // namespace
-
-#endif  // CONTENT_COMMON_CLIPBOARD_FORMAT_H_
diff --git a/content/common/clipboard_struct_traits.h b/content/common/clipboard_struct_traits.h
deleted file mode 100644
index efc23b7..0000000
--- a/content/common/clipboard_struct_traits.h
+++ /dev/null
@@ -1,54 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CONTENT_COMMON_CLIPBOARD_STRUCT_TRAITS_H_
-#define CONTENT_COMMON_CLIPBOARD_STRUCT_TRAITS_H_
-
-#include "content/common/clipboard.mojom.h"
-#include "content/common/clipboard_format.h"
-#include "mojo/public/cpp/bindings/enum_traits.h"
-
-namespace mojo {
-
-template <>
-struct EnumTraits<content::mojom::ClipboardFormat, content::ClipboardFormat> {
-  static content::mojom::ClipboardFormat ToMojom(
-      content::ClipboardFormat clipboard_format) {
-    switch (clipboard_format) {
-      case content::CLIPBOARD_FORMAT_PLAINTEXT:
-        return content::mojom::ClipboardFormat::kPlaintext;
-      case content::CLIPBOARD_FORMAT_HTML:
-        return content::mojom::ClipboardFormat::kHtml;
-      case content::CLIPBOARD_FORMAT_SMART_PASTE:
-        return content::mojom::ClipboardFormat::kSmartPaste;
-      case content::CLIPBOARD_FORMAT_BOOKMARK:
-        return content::mojom::ClipboardFormat::kBookmark;
-    }
-    NOTREACHED();
-    return content::mojom::ClipboardFormat::kPlaintext;
-  }
-
-  static bool FromMojom(content::mojom::ClipboardFormat clipboard_format,
-                        content::ClipboardFormat* out) {
-    switch (clipboard_format) {
-      case content::mojom::ClipboardFormat::kPlaintext:
-        *out = content::CLIPBOARD_FORMAT_PLAINTEXT;
-        return true;
-      case content::mojom::ClipboardFormat::kHtml:
-        *out = content::CLIPBOARD_FORMAT_HTML;
-        return true;
-      case content::mojom::ClipboardFormat::kSmartPaste:
-        *out = content::CLIPBOARD_FORMAT_SMART_PASTE;
-        return true;
-      case content::mojom::ClipboardFormat::kBookmark:
-        *out = content::CLIPBOARD_FORMAT_BOOKMARK;
-        return true;
-    }
-    return false;
-  }
-};
-
-}  // namespace mojo
-
-#endif  // CONTENT_COMMON_CLIPBOARD_STRUCT_TRAITS_H_
diff --git a/content/common/typemaps.gni b/content/common/typemaps.gni
index 56b405c..0b16382 100644
--- a/content/common/typemaps.gni
+++ b/content/common/typemaps.gni
@@ -4,7 +4,6 @@
 
 typemaps = [
   "//content/common/background_fetch/background_fetch_types.typemap",
-  "//content/common/clipboard.typemap",
   "//content/common/frame.typemap",
   "//content/common/frame_messages.typemap",
   "//content/common/native_types.typemap",
diff --git a/content/public/common/content_features.cc b/content/public/common/content_features.cc
index 13e31e45..8f8e0e1 100644
--- a/content/public/common/content_features.cc
+++ b/content/public/common/content_features.cc
@@ -92,6 +92,10 @@
 const base::Feature kCompositorTouchAction{"CompositorTouchAction",
                                            base::FEATURE_DISABLED_BY_DEFAULT};
 
+// Enables exposing back/forward mouse buttons to the renderer and the web.
+const base::Feature kExtendedMouseButtons{"ExtendedMouseButtons",
+                                          base::FEATURE_DISABLED_BY_DEFAULT};
+
 // Throttle tasks in Blink background timer queues based on CPU budgets
 // for the background tab. Bug: https://crbug.com/639852.
 const base::Feature kExpensiveBackgroundTimerThrottling{
diff --git a/content/public/common/content_features.h b/content/public/common/content_features.h
index 7c4742c..d5289ad0 100644
--- a/content/public/common/content_features.h
+++ b/content/public/common/content_features.h
@@ -32,6 +32,7 @@
 CONTENT_EXPORT extern const base::Feature kCompositeOpaqueScrollers;
 CONTENT_EXPORT extern const base::Feature kCompositorImageAnimation;
 CONTENT_EXPORT extern const base::Feature kCompositorTouchAction;
+CONTENT_EXPORT extern const base::Feature kExtendedMouseButtons;
 CONTENT_EXPORT extern const base::Feature kExpensiveBackgroundTimerThrottling;
 CONTENT_EXPORT extern const base::Feature kFeaturePolicy;
 CONTENT_EXPORT extern const base::Feature kFetchKeepaliveTimeoutSetting;
diff --git a/content/renderer/pepper/event_conversion.cc b/content/renderer/pepper/event_conversion.cc
index 0bb01694..0e344f6 100644
--- a/content/renderer/pepper/event_conversion.cc
+++ b/content/renderer/pepper/event_conversion.cc
@@ -214,8 +214,17 @@
   if (mouse_event.GetType() == WebInputEvent::kMouseDown ||
       mouse_event.GetType() == WebInputEvent::kMouseMove ||
       mouse_event.GetType() == WebInputEvent::kMouseUp) {
-    result.mouse_button =
-        static_cast<PP_InputEvent_MouseButton>(mouse_event.button);
+    switch (mouse_event.button) {
+      case WebMouseEvent::Button::kNoButton:
+      case WebMouseEvent::Button::kLeft:
+      case WebMouseEvent::Button::kRight:
+      case WebMouseEvent::Button::kMiddle:
+        result.mouse_button =
+            static_cast<PP_InputEvent_MouseButton>(mouse_event.button);
+        break;
+      default:
+        return;
+    }
   }
   result.mouse_position.x = mouse_event.PositionInWidget().x;
   result.mouse_position.y = mouse_event.PositionInWidget().y;
diff --git a/content/renderer/pepper/pepper_webplugin_impl.cc b/content/renderer/pepper/pepper_webplugin_impl.cc
index bfc1965..9e125d7 100644
--- a/content/renderer/pepper/pepper_webplugin_impl.cc
+++ b/content/renderer/pepper/pepper_webplugin_impl.cc
@@ -320,7 +320,7 @@
 
     blink::WebString text =
         blink::Platform::Current()->Clipboard()->ReadPlainText(
-            blink::WebClipboard::kBufferStandard);
+            blink::mojom::ClipboardBuffer::kStandard);
 
     instance_->ReplaceSelection(text.Utf8());
     return true;
diff --git a/content/renderer/webclipboard_impl.cc b/content/renderer/webclipboard_impl.cc
index f92961c1..7b333ed6 100644
--- a/content/renderer/webclipboard_impl.cc
+++ b/content/renderer/webclipboard_impl.cc
@@ -9,7 +9,6 @@
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "build/build_config.h"
-#include "content/common/clipboard_format.h"
 #include "content/public/common/drop_data.h"
 #include "content/renderer/clipboard_utils.h"
 #include "content/renderer/drop_data_builder.h"
@@ -38,52 +37,32 @@
 
 WebClipboardImpl::~WebClipboardImpl() = default;
 
-uint64_t WebClipboardImpl::SequenceNumber(Buffer buffer) {
-  ui::ClipboardType clipboard_type;
+uint64_t WebClipboardImpl::SequenceNumber(
+    blink::mojom::ClipboardBuffer buffer) {
   uint64_t result = 0;
-  if (!ConvertBufferType(buffer, &clipboard_type))
+  if (!IsValidBufferType(buffer))
     return 0;
 
-  clipboard_.GetSequenceNumber(clipboard_type, &result);
+  clipboard_.GetSequenceNumber(buffer, &result);
   return result;
 }
 
-bool WebClipboardImpl::IsFormatAvailable(Format format, Buffer buffer) {
-  ui::ClipboardType clipboard_type = ui::CLIPBOARD_TYPE_COPY_PASTE;
-  ClipboardFormat clipboard_format = CLIPBOARD_FORMAT_PLAINTEXT;
-
-  if (!ConvertBufferType(buffer, &clipboard_type))
+bool WebClipboardImpl::IsFormatAvailable(blink::mojom::ClipboardFormat format,
+                                         blink::mojom::ClipboardBuffer buffer) {
+  if (!IsValidBufferType(buffer))
     return false;
 
-  switch (format) {
-    case kFormatPlainText:
-      clipboard_format = CLIPBOARD_FORMAT_PLAINTEXT;
-      break;
-    case kFormatHTML:
-      clipboard_format = CLIPBOARD_FORMAT_HTML;
-      break;
-    case kFormatSmartPaste:
-      clipboard_format = CLIPBOARD_FORMAT_SMART_PASTE;
-      break;
-    case kFormatBookmark:
-      clipboard_format = CLIPBOARD_FORMAT_BOOKMARK;
-      break;
-    default:
-      NOTREACHED();
-  }
-
   bool result = false;
-  clipboard_.IsFormatAvailable(clipboard_format, clipboard_type, &result);
+  clipboard_.IsFormatAvailable(format, buffer, &result);
   return result;
 }
 
 WebVector<WebString> WebClipboardImpl::ReadAvailableTypes(
-    Buffer buffer,
+    blink::mojom::ClipboardBuffer buffer,
     bool* contains_filenames) {
-  ui::ClipboardType clipboard_type;
   std::vector<base::string16> types;
-  if (ConvertBufferType(buffer, &clipboard_type)) {
-    clipboard_.ReadAvailableTypes(clipboard_type, &types, contains_filenames);
+  if (IsValidBufferType(buffer)) {
+    clipboard_.ReadAvailableTypes(buffer, &types, contains_filenames);
   }
   WebVector<WebString> web_types(types.size());
   std::transform(
@@ -92,99 +71,97 @@
   return web_types;
 }
 
-WebString WebClipboardImpl::ReadPlainText(Buffer buffer) {
-  ui::ClipboardType clipboard_type;
-  if (!ConvertBufferType(buffer, &clipboard_type))
+WebString WebClipboardImpl::ReadPlainText(
+    blink::mojom::ClipboardBuffer buffer) {
+  if (!IsValidBufferType(buffer))
     return WebString();
 
   base::string16 text;
-  clipboard_.ReadText(clipboard_type, &text);
+  clipboard_.ReadText(buffer, &text);
   return WebString::FromUTF16(text);
 }
 
-WebString WebClipboardImpl::ReadHTML(Buffer buffer,
+WebString WebClipboardImpl::ReadHTML(blink::mojom::ClipboardBuffer buffer,
                                      WebURL* source_url,
                                      unsigned* fragment_start,
                                      unsigned* fragment_end) {
-  ui::ClipboardType clipboard_type;
-  if (!ConvertBufferType(buffer, &clipboard_type))
+  if (!IsValidBufferType(buffer))
     return WebString();
 
   base::string16 html_stdstr;
   GURL gurl;
-  clipboard_.ReadHtml(clipboard_type, &html_stdstr, &gurl,
+  clipboard_.ReadHtml(buffer, &html_stdstr, &gurl,
                       static_cast<uint32_t*>(fragment_start),
                       static_cast<uint32_t*>(fragment_end));
   *source_url = gurl;
   return WebString::FromUTF16(html_stdstr);
 }
 
-WebString WebClipboardImpl::ReadRTF(Buffer buffer) {
-  ui::ClipboardType clipboard_type;
-  if (!ConvertBufferType(buffer, &clipboard_type))
+WebString WebClipboardImpl::ReadRTF(blink::mojom::ClipboardBuffer buffer) {
+  if (!IsValidBufferType(buffer))
     return WebString();
 
   std::string rtf;
-  clipboard_.ReadRtf(clipboard_type, &rtf);
+  clipboard_.ReadRtf(buffer, &rtf);
   return WebString::FromLatin1(rtf);
 }
 
-WebBlobInfo WebClipboardImpl::ReadImage(Buffer buffer) {
-  ui::ClipboardType clipboard_type;
-  if (!ConvertBufferType(buffer, &clipboard_type))
+WebBlobInfo WebClipboardImpl::ReadImage(blink::mojom::ClipboardBuffer buffer) {
+  if (!IsValidBufferType(buffer))
     return WebBlobInfo();
 
   std::string blob_uuid;
   std::string type;
   int64_t size = -1;
-  clipboard_.ReadImage(clipboard_type, &blob_uuid, &type, &size);
+  clipboard_.ReadImage(buffer, &blob_uuid, &type, &size);
   if (size < 0)
     return WebBlobInfo();
   return WebBlobInfo(WebString::FromASCII(blob_uuid), WebString::FromUTF8(type),
                      size);
 }
 
-WebString WebClipboardImpl::ReadCustomData(Buffer buffer,
+WebString WebClipboardImpl::ReadCustomData(blink::mojom::ClipboardBuffer buffer,
                                            const WebString& type) {
-  ui::ClipboardType clipboard_type;
-  if (!ConvertBufferType(buffer, &clipboard_type))
+  if (!IsValidBufferType(buffer))
     return WebString();
 
   base::string16 data;
-  clipboard_.ReadCustomData(clipboard_type, type.Utf16(), &data);
+  clipboard_.ReadCustomData(buffer, type.Utf16(), &data);
   return WebString::FromUTF16(data);
 }
 
 void WebClipboardImpl::WritePlainText(const WebString& plain_text) {
-  clipboard_.WriteText(ui::CLIPBOARD_TYPE_COPY_PASTE, plain_text.Utf16());
-  clipboard_.CommitWrite(ui::CLIPBOARD_TYPE_COPY_PASTE);
+  clipboard_.WriteText(blink::mojom::ClipboardBuffer::kStandard,
+                       plain_text.Utf16());
+  clipboard_.CommitWrite(blink::mojom::ClipboardBuffer::kStandard);
 }
 
 void WebClipboardImpl::WriteHTML(const WebString& html_text,
                                  const WebURL& source_url,
                                  const WebString& plain_text,
                                  bool write_smart_paste) {
-  clipboard_.WriteHtml(ui::CLIPBOARD_TYPE_COPY_PASTE, html_text.Utf16(),
-                       source_url);
-  clipboard_.WriteText(ui::CLIPBOARD_TYPE_COPY_PASTE, plain_text.Utf16());
+  clipboard_.WriteHtml(blink::mojom::ClipboardBuffer::kStandard,
+                       html_text.Utf16(), source_url);
+  clipboard_.WriteText(blink::mojom::ClipboardBuffer::kStandard,
+                       plain_text.Utf16());
 
   if (write_smart_paste)
-    clipboard_.WriteSmartPasteMarker(ui::CLIPBOARD_TYPE_COPY_PASTE);
-  clipboard_.CommitWrite(ui::CLIPBOARD_TYPE_COPY_PASTE);
+    clipboard_.WriteSmartPasteMarker(blink::mojom::ClipboardBuffer::kStandard);
+  clipboard_.CommitWrite(blink::mojom::ClipboardBuffer::kStandard);
 }
 
 void WebClipboardImpl::WriteImage(const WebImage& image,
                                   const WebURL& url,
                                   const WebString& title) {
   DCHECK(!image.IsNull());
-  if (!WriteImageToClipboard(ui::CLIPBOARD_TYPE_COPY_PASTE,
+  if (!WriteImageToClipboard(blink::mojom::ClipboardBuffer::kStandard,
                              image.GetSkBitmap()))
     return;
 
   if (!url.IsEmpty()) {
     GURL gurl(url);
-    clipboard_.WriteBookmark(ui::CLIPBOARD_TYPE_COPY_PASTE, gurl.spec(),
-                             title.Utf16());
+    clipboard_.WriteBookmark(blink::mojom::ClipboardBuffer::kStandard,
+                             gurl.spec(), title.Utf16());
 #if !defined(OS_MACOSX)
     // When writing the image, we also write the image markup so that pasting
     // into rich text editors, such as Gmail, reveals the image. We also don't
@@ -193,12 +170,12 @@
     // We also don't want to write HTML on a Mac, since Mail.app prefers to use
     // the image markup over attaching the actual image. See
     // http://crbug.com/33016 for details.
-    clipboard_.WriteHtml(ui::CLIPBOARD_TYPE_COPY_PASTE,
+    clipboard_.WriteHtml(blink::mojom::ClipboardBuffer::kStandard,
                          base::UTF8ToUTF16(URLToImageMarkup(url, title)),
                          GURL());
 #endif
   }
-  clipboard_.CommitWrite(ui::CLIPBOARD_TYPE_COPY_PASTE);
+  clipboard_.CommitWrite(blink::mojom::ClipboardBuffer::kStandard);
 }
 
 void WebClipboardImpl::WriteDataObject(const WebDragData& data) {
@@ -208,43 +185,38 @@
   // type. This prevents stomping on clipboard contents that might have been
   // written by extension functions such as chrome.bookmarkManagerPrivate.copy.
   if (!data_object.text.is_null())
-    clipboard_.WriteText(ui::CLIPBOARD_TYPE_COPY_PASTE,
+    clipboard_.WriteText(blink::mojom::ClipboardBuffer::kStandard,
                          data_object.text.string());
   if (!data_object.html.is_null())
-    clipboard_.WriteHtml(ui::CLIPBOARD_TYPE_COPY_PASTE,
+    clipboard_.WriteHtml(blink::mojom::ClipboardBuffer::kStandard,
                          data_object.html.string(), GURL());
   if (!data_object.custom_data.empty()) {
-    clipboard_.WriteCustomData(ui::CLIPBOARD_TYPE_COPY_PASTE,
+    clipboard_.WriteCustomData(blink::mojom::ClipboardBuffer::kStandard,
                                std::move(data_object.custom_data));
   }
-  clipboard_.CommitWrite(ui::CLIPBOARD_TYPE_COPY_PASTE);
+  clipboard_.CommitWrite(blink::mojom::ClipboardBuffer::kStandard);
 }
 
-bool WebClipboardImpl::ConvertBufferType(Buffer buffer,
-                                         ui::ClipboardType* result) {
-  *result = ui::CLIPBOARD_TYPE_COPY_PASTE;
+bool WebClipboardImpl::IsValidBufferType(blink::mojom::ClipboardBuffer buffer) {
   switch (buffer) {
-    case kBufferStandard:
-      break;
-    case kBufferSelection:
+    case blink::mojom::ClipboardBuffer::kStandard:
+      return true;
+    case blink::mojom::ClipboardBuffer::kSelection:
 #if defined(USE_X11)
-      *result = ui::CLIPBOARD_TYPE_SELECTION;
-      break;
+      return true;
 #else
       // Chrome OS and non-X11 unix builds do not support
       // the X selection clipboad.
       // TODO: remove the need for this case, see http://crbug.com/361753
       return false;
 #endif
-    default:
-      NOTREACHED();
-      return false;
   }
   return true;
 }
 
-bool WebClipboardImpl::WriteImageToClipboard(ui::ClipboardType clipboard_type,
-                                             const SkBitmap& bitmap) {
+bool WebClipboardImpl::WriteImageToClipboard(
+    blink::mojom::ClipboardBuffer buffer,
+    const SkBitmap& bitmap) {
   // Only 32-bit bitmaps are supported.
   DCHECK_EQ(bitmap.colorType(), kN32_SkColorType);
 
@@ -263,11 +235,11 @@
 
   // Allocate a shared memory buffer to hold the bitmap bits.
   uint32_t buf_size = checked_buf_size.ValueOrDie();
-  auto buffer = mojo::SharedBufferHandle::Create(buf_size);
-  auto mapping = buffer->Map(buf_size);
+  auto shared_buffer = mojo::SharedBufferHandle::Create(buf_size);
+  auto mapping = shared_buffer->Map(buf_size);
   memcpy(mapping.get(), pixels, buf_size);
 
-  clipboard_.WriteImage(clipboard_type, size, std::move(buffer));
+  clipboard_.WriteImage(buffer, size, std::move(shared_buffer));
   return true;
 }
 
diff --git a/content/renderer/webclipboard_impl.h b/content/renderer/webclipboard_impl.h
index acaf99a..758f03b 100644
--- a/content/renderer/webclipboard_impl.h
+++ b/content/renderer/webclipboard_impl.h
@@ -12,7 +12,6 @@
 #include "base/compiler_specific.h"
 #include "content/common/clipboard.mojom.h"
 #include "third_party/WebKit/public/platform/WebClipboard.h"
-#include "ui/base/clipboard/clipboard.h"
 
 namespace content {
 
@@ -23,19 +22,20 @@
   virtual ~WebClipboardImpl();
 
   // WebClipboard methods:
-  uint64_t SequenceNumber(Buffer buffer) override;
-  bool IsFormatAvailable(Format format, Buffer buffer) override;
+  uint64_t SequenceNumber(blink::mojom::ClipboardBuffer buffer) override;
+  bool IsFormatAvailable(blink::mojom::ClipboardFormat format,
+                         blink::mojom::ClipboardBuffer buffer) override;
   blink::WebVector<blink::WebString> ReadAvailableTypes(
-      Buffer buffer,
+      blink::mojom::ClipboardBuffer buffer,
       bool* contains_filenames) override;
-  blink::WebString ReadPlainText(Buffer buffer) override;
-  blink::WebString ReadHTML(Buffer buffer,
+  blink::WebString ReadPlainText(blink::mojom::ClipboardBuffer buffer) override;
+  blink::WebString ReadHTML(blink::mojom::ClipboardBuffer buffer,
                             blink::WebURL* source_url,
                             unsigned* fragment_start,
                             unsigned* fragment_end) override;
-  blink::WebString ReadRTF(Buffer buffer) override;
-  blink::WebBlobInfo ReadImage(Buffer buffer) override;
-  blink::WebString ReadCustomData(Buffer buffer,
+  blink::WebString ReadRTF(blink::mojom::ClipboardBuffer buffer) override;
+  blink::WebBlobInfo ReadImage(blink::mojom::ClipboardBuffer buffer) override;
+  blink::WebString ReadCustomData(blink::mojom::ClipboardBuffer buffer,
                                   const blink::WebString& type) override;
   void WritePlainText(const blink::WebString& plain_text) override;
   void WriteHTML(const blink::WebString& html_text,
@@ -48,8 +48,8 @@
   void WriteDataObject(const blink::WebDragData& data) override;
 
  private:
-  bool ConvertBufferType(Buffer, ui::ClipboardType*);
-  bool WriteImageToClipboard(ui::ClipboardType clipboard_type,
+  bool IsValidBufferType(blink::mojom::ClipboardBuffer buffer);
+  bool WriteImageToClipboard(blink::mojom::ClipboardBuffer buffer,
                              const SkBitmap& bitmap);
   mojom::ClipboardHost& clipboard_;
 };
diff --git a/content/shell/test_runner/pixel_dump.cc b/content/shell/test_runner/pixel_dump.cc
index c82fe2f..847aa82 100644
--- a/content/shell/test_runner/pixel_dump.cc
+++ b/content/shell/test_runner/pixel_dump.cc
@@ -183,19 +183,20 @@
   DCHECK(!callback.is_null());
   uint64_t sequence_number =
       blink::Platform::Current()->Clipboard()->SequenceNumber(
-          blink::WebClipboard::Buffer());
+          blink::mojom::ClipboardBuffer::kStandard);
   web_frame->CopyImageAt(blink::WebPoint(x, y));
   if (sequence_number ==
       blink::Platform::Current()->Clipboard()->SequenceNumber(
-          blink::WebClipboard::Buffer())) {
+          blink::mojom::ClipboardBuffer::kStandard)) {
     SkBitmap emptyBitmap;
     std::move(callback).Run(emptyBitmap);
     return;
   }
 
-  blink::WebImage image = static_cast<blink::WebMockClipboard*>(
-                              blink::Platform::Current()->Clipboard())
-                              ->ReadRawImage(blink::WebClipboard::Buffer());
+  blink::WebImage image =
+      static_cast<blink::WebMockClipboard*>(
+          blink::Platform::Current()->Clipboard())
+          ->ReadRawImage(blink::mojom::ClipboardBuffer::kStandard);
   std::move(callback).Run(image.GetSkBitmap());
 }
 
diff --git a/content/test/mock_webclipboard_impl.cc b/content/test/mock_webclipboard_impl.cc
index 26f425c..97c9b91 100644
--- a/content/test/mock_webclipboard_impl.cc
+++ b/content/test/mock_webclipboard_impl.cc
@@ -36,29 +36,31 @@
 
 MockWebClipboardImpl::~MockWebClipboardImpl() {}
 
-uint64_t MockWebClipboardImpl::SequenceNumber(Buffer) {
+uint64_t MockWebClipboardImpl::SequenceNumber(blink::mojom::ClipboardBuffer) {
   return m_sequenceNumber;
 }
 
-bool MockWebClipboardImpl::IsFormatAvailable(Format format, Buffer buffer) {
+bool MockWebClipboardImpl::IsFormatAvailable(
+    blink::mojom::ClipboardFormat format,
+    blink::mojom::ClipboardBuffer buffer) {
   switch (format) {
-    case kFormatPlainText:
+    case blink::mojom::ClipboardFormat::kPlaintext:
       return !m_plainText.is_null();
 
-    case kFormatHTML:
+    case blink::mojom::ClipboardFormat::kHtml:
       return !m_htmlText.is_null();
 
-    case kFormatSmartPaste:
+    case blink::mojom::ClipboardFormat::kSmartPaste:
       return m_writeSmartPaste;
 
-    default:
-      NOTREACHED();
+    case blink::mojom::ClipboardFormat::kBookmark:
       return false;
   }
+  return false;
 }
 
 WebVector<WebString> MockWebClipboardImpl::ReadAvailableTypes(
-    Buffer buffer,
+    blink::mojom::ClipboardBuffer buffer,
     bool* containsFilenames) {
   *containsFilenames = false;
   std::vector<WebString> results;
@@ -82,13 +84,13 @@
 }
 
 blink::WebString MockWebClipboardImpl::ReadPlainText(
-    blink::WebClipboard::Buffer buffer) {
+    blink::mojom::ClipboardBuffer buffer) {
   return WebString::FromUTF16(m_plainText);
 }
 
 // TODO(wtc): set output argument *url.
 blink::WebString MockWebClipboardImpl::ReadHTML(
-    blink::WebClipboard::Buffer buffer,
+    blink::mojom::ClipboardBuffer buffer,
     blink::WebURL* url,
     unsigned* fragmentStart,
     unsigned* fragmentEnd) {
@@ -98,7 +100,7 @@
 }
 
 blink::WebBlobInfo MockWebClipboardImpl::ReadImage(
-    blink::WebClipboard::Buffer buffer) {
+    blink::mojom::ClipboardBuffer buffer) {
   std::vector<unsigned char> output;
   const SkBitmap& bitmap = m_image.GetSkBitmap();
   if (!gfx::PNGCodec::FastEncodeBGRASkBitmap(
@@ -110,12 +112,12 @@
 }
 
 blink::WebImage MockWebClipboardImpl::ReadRawImage(
-    blink::WebClipboard::Buffer buffer) {
+    blink::mojom::ClipboardBuffer buffer) {
   return m_image;
 }
 
 blink::WebString MockWebClipboardImpl::ReadCustomData(
-    blink::WebClipboard::Buffer buffer,
+    blink::mojom::ClipboardBuffer buffer,
     const blink::WebString& type) {
   std::map<base::string16, base::string16>::const_iterator it =
       m_customData.find(type.Utf16());
diff --git a/content/test/mock_webclipboard_impl.h b/content/test/mock_webclipboard_impl.h
index a631206..a394057 100644
--- a/content/test/mock_webclipboard_impl.h
+++ b/content/test/mock_webclipboard_impl.h
@@ -27,21 +27,21 @@
   MockWebClipboardImpl();
   virtual ~MockWebClipboardImpl();
 
-  uint64_t SequenceNumber(Buffer) override;
-  bool IsFormatAvailable(blink::WebClipboard::Format format,
-                         blink::WebClipboard::Buffer buffer) override;
+  uint64_t SequenceNumber(blink::mojom::ClipboardBuffer) override;
+  bool IsFormatAvailable(blink::mojom::ClipboardFormat format,
+                         blink::mojom::ClipboardBuffer buffer) override;
   blink::WebVector<blink::WebString> ReadAvailableTypes(
-      blink::WebClipboard::Buffer buffer,
+      blink::mojom::ClipboardBuffer buffer,
       bool* containsFilenames) override;
 
-  blink::WebString ReadPlainText(blink::WebClipboard::Buffer buffer) override;
-  blink::WebString ReadHTML(blink::WebClipboard::Buffer buffer,
+  blink::WebString ReadPlainText(blink::mojom::ClipboardBuffer buffer) override;
+  blink::WebString ReadHTML(blink::mojom::ClipboardBuffer buffer,
                             blink::WebURL* url,
                             unsigned* fragmentStart,
                             unsigned* fragmentEnd) override;
-  blink::WebBlobInfo ReadImage(blink::WebClipboard::Buffer buffer) override;
-  blink::WebImage ReadRawImage(blink::WebClipboard::Buffer buffer) override;
-  blink::WebString ReadCustomData(blink::WebClipboard::Buffer buffer,
+  blink::WebBlobInfo ReadImage(blink::mojom::ClipboardBuffer buffer) override;
+  blink::WebImage ReadRawImage(blink::mojom::ClipboardBuffer buffer) override;
+  blink::WebString ReadCustomData(blink::mojom::ClipboardBuffer buffer,
                                   const blink::WebString& type) override;
 
   void WritePlainText(const blink::WebString& plain_text) override;
diff --git a/extensions/browser/BUILD.gn b/extensions/browser/BUILD.gn
index c052d184..98ec9b7 100644
--- a/extensions/browser/BUILD.gn
+++ b/extensions/browser/BUILD.gn
@@ -557,7 +557,9 @@
     "requirements_checker_unittest.cc",
     "runtime_data_unittest.cc",
     "sandboxed_unpacker_unittest.cc",
+    "updater/extension_installer_unittest.cc",
     "updater/safe_manifest_parser_unittest.cc",
+    "updater/update_data_provider_unittest.cc",
     "updater/update_service_unittest.cc",
     "value_store/leveldb_scoped_database_unittest.cc",
     "value_store/leveldb_value_store_unittest.cc",
diff --git a/extensions/browser/extension_prefs.cc b/extensions/browser/extension_prefs.cc
index c5e7911..2e117bf 100644
--- a/extensions/browser/extension_prefs.cc
+++ b/extensions/browser/extension_prefs.cc
@@ -47,147 +47,149 @@
 // during Chrome shutdown (and won't be updated on a browser crash) and so can
 // be used at startup to determine whether the extension was running when Chrome
 // was last terminated.
-const char kPrefRunning[] = "running";
+constexpr const char kPrefRunning[] = "running";
 
 // Whether this extension had windows when it was last running.
-const char kIsActive[] = "is_active";
+constexpr const char kIsActive[] = "is_active";
 
 // Where an extension was installed from. (see Manifest::Location)
-const char kPrefLocation[] = "location";
+constexpr const char kPrefLocation[] = "location";
 
 // Enabled, disabled, killed, etc. (see Extension::State)
-const char kPrefState[] = "state";
+constexpr const char kPrefState[] = "state";
 
 // The path to the current version's manifest file.
-const char kPrefPath[] = "path";
+constexpr const char kPrefPath[] = "path";
 
 // The dictionary containing the extension's manifest.
-const char kPrefManifest[] = "manifest";
+constexpr const char kPrefManifest[] = "manifest";
 
 // The version number.
-const char kPrefVersion[] = "manifest.version";
+constexpr const char kPrefVersion[] = "manifest.version";
 
 // Indicates whether an extension is blacklisted.
-const char kPrefBlacklist[] = "blacklist";
+constexpr const char kPrefBlacklist[] = "blacklist";
 
 // If extension is greylisted.
-const char kPrefBlacklistState[] = "blacklist_state";
+constexpr const char kPrefBlacklistState[] = "blacklist_state";
 
 // The count of how many times we prompted the user to acknowledge an
 // extension.
-const char kPrefAcknowledgePromptCount[] = "ack_prompt_count";
+constexpr const char kPrefAcknowledgePromptCount[] = "ack_prompt_count";
 
 // Indicates whether the user has acknowledged various types of extensions.
-const char kPrefExternalAcknowledged[] = "ack_external";
-const char kPrefBlacklistAcknowledged[] = "ack_blacklist";
+constexpr const char kPrefExternalAcknowledged[] = "ack_external";
+constexpr const char kPrefBlacklistAcknowledged[] = "ack_blacklist";
 
 // Indicates whether the external extension was installed during the first
 // run of this profile.
-const char kPrefExternalInstallFirstRun[] = "external_first_run";
+constexpr const char kPrefExternalInstallFirstRun[] = "external_first_run";
 
 // A bitmask of all the reasons an extension is disabled.
-const char kPrefDisableReasons[] = "disable_reasons";
+constexpr const char kPrefDisableReasons[] = "disable_reasons";
 
 // The key for a serialized Time value indicating the start of the day (from the
 // server's perspective) an extension last included a "ping" parameter during
 // its update check.
-const char kLastPingDay[] = "lastpingday";
+constexpr const char kLastPingDay[] = "lastpingday";
 
 // Similar to kLastPingDay, but for "active" instead of "rollcall" pings.
-const char kLastActivePingDay[] = "last_active_pingday";
+constexpr const char kLastActivePingDay[] = "last_active_pingday";
 
 // A bit we use to keep track of whether we need to do an "active" ping.
-const char kActiveBit[] = "active_bit";
+constexpr const char kActiveBit[] = "active_bit";
 
 // Path for settings specific to blacklist update.
-const char kExtensionsBlacklistUpdate[] = "extensions.blacklistupdate";
+constexpr const char kExtensionsBlacklistUpdate[] =
+    "extensions.blacklistupdate";
 
 // Path for the delayed install info dictionary preference. The actual string
 // value is a legacy artifact for when delayed installs only pertained to
 // updates that were waiting for idle.
-const char kDelayedInstallInfo[] = "idle_install_info";
+constexpr const char kDelayedInstallInfo[] = "idle_install_info";
 
 // Reason why the extension's install was delayed.
-const char kDelayedInstallReason[] = "delay_install_reason";
+constexpr const char kDelayedInstallReason[] = "delay_install_reason";
 
 // Path for the suggested page ordinal of a delayed extension install.
-const char kPrefSuggestedPageOrdinal[] = "suggested_page_ordinal";
+constexpr const char kPrefSuggestedPageOrdinal[] = "suggested_page_ordinal";
 
 // A preference that, if true, will allow this extension to run in incognito
 // mode.
-const char kPrefIncognitoEnabled[] = "incognito";
+constexpr const char kPrefIncognitoEnabled[] = "incognito";
 
 // A preference to control whether an extension is allowed to inject script in
 // pages with file URLs.
-const char kPrefAllowFileAccess[] = "newAllowFileAccess";
+constexpr const char kPrefAllowFileAccess[] = "newAllowFileAccess";
 // TODO(jstritar): As part of fixing http://crbug.com/91577, we revoked all
 // extension file access by renaming the pref. We should eventually clean up
 // the old flag and possibly go back to that name.
-// const char kPrefAllowFileAccessOld[] = "allowFileAccess";
+// constexpr const char kPrefAllowFileAccessOld[] = "allowFileAccess";
 
 // A preference specifying if the user dragged the app on the NTP.
-const char kPrefUserDraggedApp[] = "user_dragged_app_ntp";
+constexpr const char kPrefUserDraggedApp[] = "user_dragged_app_ntp";
 
 // Preferences that hold which permissions the user has granted the extension.
 // We explicitly keep track of these so that extensions can contain unknown
 // permissions, for backwards compatibility reasons, and we can still prompt
 // the user to accept them once recognized. We store the active permission
 // permissions because they may differ from those defined in the manifest.
-const char kPrefActivePermissions[] = "active_permissions";
-const char kPrefGrantedPermissions[] = "granted_permissions";
+constexpr const char kPrefActivePermissions[] = "active_permissions";
+constexpr const char kPrefGrantedPermissions[] = "granted_permissions";
 
 // The preference names for PermissionSet values.
-const char kPrefAPIs[] = "api";
-const char kPrefManifestPermissions[] = "manifest_permissions";
-const char kPrefExplicitHosts[] = "explicit_host";
-const char kPrefScriptableHosts[] = "scriptable_host";
+constexpr const char kPrefAPIs[] = "api";
+constexpr const char kPrefManifestPermissions[] = "manifest_permissions";
+constexpr const char kPrefExplicitHosts[] = "explicit_host";
+constexpr const char kPrefScriptableHosts[] = "scriptable_host";
 
 // A preference that indicates when an extension was installed.
-const char kPrefInstallTime[] = "install_time";
+constexpr const char kPrefInstallTime[] = "install_time";
 
 // A preference which saves the creation flags for extensions.
-const char kPrefCreationFlags[] = "creation_flags";
+constexpr const char kPrefCreationFlags[] = "creation_flags";
 
 // A preference that indicates whether the extension was installed from the
 // Chrome Web Store.
-const char kPrefFromWebStore[] = "from_webstore";
+constexpr const char kPrefFromWebStore[] = "from_webstore";
 
 // A preference that indicates whether the extension was installed from a
 // mock App created from a bookmark.
-const char kPrefFromBookmark[] = "from_bookmark";
+constexpr const char kPrefFromBookmark[] = "from_bookmark";
 
 // A preference that indicates whether the extension was installed as a
 // default app.
-const char kPrefWasInstalledByDefault[] = "was_installed_by_default";
+constexpr const char kPrefWasInstalledByDefault[] = "was_installed_by_default";
 
 // A preference that indicates whether the extension was installed as an
 // OEM app.
-const char kPrefWasInstalledByOem[] = "was_installed_by_oem";
+constexpr const char kPrefWasInstalledByOem[] = "was_installed_by_oem";
 
 // Key for Geometry Cache preference.
-const char kPrefGeometryCache[] = "geometry_cache";
+constexpr const char kPrefGeometryCache[] = "geometry_cache";
 
 // A preference that indicates when an extension is last launched.
-const char kPrefLastLaunchTime[] = "last_launch_time";
+constexpr const char kPrefLastLaunchTime[] = "last_launch_time";
 
 // Am installation parameter bundled with an extension.
-const char kPrefInstallParam[] = "install_parameter";
+constexpr const char kPrefInstallParam[] = "install_parameter";
 
 // A list of installed ids and a signature.
-const char kInstallSignature[] = "extensions.install_signature";
+constexpr const char kInstallSignature[] = "extensions.install_signature";
 
 // A boolean preference that indicates whether the extension should not be
 // synced. Default value is false.
-const char kPrefDoNotSync[] = "do_not_sync";
+constexpr const char kPrefDoNotSync[] = "do_not_sync";
 
-const char kCorruptedDisableCount[] = "extensions.corrupted_disable_count";
+constexpr const char kCorruptedDisableCount[] =
+    "extensions.corrupted_disable_count";
 
 // A boolean preference that indicates whether the extension has local changes
 // that need to be synced. Default value is false.
-const char kPrefNeedsSync[] = "needs_sync";
+constexpr const char kPrefNeedsSync[] = "needs_sync";
 
 // The indexed ruleset checksum for the Declarative Net Request API.
-const char kPrefDNRRulesetChecksum[] = "dnr_ruleset_checksum";
+constexpr const char kPrefDNRRulesetChecksum[] = "dnr_ruleset_checksum";
 
 // Provider of write access to a dictionary storing extension prefs.
 class ScopedExtensionPrefUpdate : public prefs::ScopedDictionaryPrefUpdate {
diff --git a/extensions/browser/extension_system.h b/extensions/browser/extension_system.h
index 36804a78..8ee7df7 100644
--- a/extensions/browser/extension_system.h
+++ b/extensions/browser/extension_system.h
@@ -132,7 +132,9 @@
   // transferred and implementors of this function are responsible for cleaning
   // it up on errors, etc.
   virtual void InstallUpdate(const std::string& extension_id,
-                             const base::FilePath& unpacked_dir) = 0;
+                             const std::string& public_key,
+                             const base::FilePath& unpacked_dir,
+                             InstallUpdateCallback install_update_callback) = 0;
 };
 
 }  // namespace extensions
diff --git a/extensions/browser/mock_extension_system.cc b/extensions/browser/mock_extension_system.cc
index 621fe93..3feaad3 100644
--- a/extensions/browser/mock_extension_system.cc
+++ b/extensions/browser/mock_extension_system.cc
@@ -76,8 +76,11 @@
   return std::unique_ptr<ExtensionSet>();
 }
 
-void MockExtensionSystem::InstallUpdate(const std::string& extension_id,
-                                        const base::FilePath& temp_dir) {
+void MockExtensionSystem::InstallUpdate(
+    const std::string& extension_id,
+    const std::string& public_key,
+    const base::FilePath& temp_dir,
+    InstallUpdateCallback install_update_callback) {
   NOTREACHED();
 }
 
diff --git a/extensions/browser/mock_extension_system.h b/extensions/browser/mock_extension_system.h
index c8748dfb..3c583d21 100644
--- a/extensions/browser/mock_extension_system.h
+++ b/extensions/browser/mock_extension_system.h
@@ -21,6 +21,8 @@
 // with the MockExtensionSystemFactory below.
 class MockExtensionSystem : public ExtensionSystem {
  public:
+  using InstallUpdateCallback = ExtensionSystem::InstallUpdateCallback;
+
   explicit MockExtensionSystem(content::BrowserContext* context);
   ~MockExtensionSystem() override;
 
@@ -44,7 +46,9 @@
   std::unique_ptr<ExtensionSet> GetDependentExtensions(
       const Extension* extension) override;
   void InstallUpdate(const std::string& extension_id,
-                     const base::FilePath& temp_dir) override;
+                     const std::string& public_key,
+                     const base::FilePath& temp_dir,
+                     InstallUpdateCallback install_update_callback) override;
 
  private:
   content::BrowserContext* browser_context_;
diff --git a/extensions/browser/updater/BUILD.gn b/extensions/browser/updater/BUILD.gn
index fb43114..6bf5e31f 100644
--- a/extensions/browser/updater/BUILD.gn
+++ b/extensions/browser/updater/BUILD.gn
@@ -15,6 +15,8 @@
     "extension_downloader_delegate.cc",
     "extension_downloader_delegate.h",
     "extension_downloader_test_delegate.h",
+    "extension_installer.cc",
+    "extension_installer.h",
     "manifest_fetch_data.cc",
     "manifest_fetch_data.h",
     "null_extension_cache.cc",
@@ -25,8 +27,6 @@
     "safe_manifest_parser.h",
     "update_data_provider.cc",
     "update_data_provider.h",
-    "update_install_shim.cc",
-    "update_install_shim.h",
     "update_service.cc",
     "update_service.h",
     "update_service_factory.cc",
diff --git a/extensions/browser/updater/extension_installer.cc b/extensions/browser/updater/extension_installer.cc
new file mode 100644
index 0000000..65b2bcdc
--- /dev/null
+++ b/extensions/browser/updater/extension_installer.cc
@@ -0,0 +1,80 @@
+// 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 "extensions/browser/updater/extension_installer.h"
+
+#include <utility>
+
+#include "base/files/file_enumerator.h"
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/files/scoped_temp_dir.h"
+#include "base/logging.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/task_scheduler/post_task.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "components/update_client/update_client_errors.h"
+#include "content/public/browser/browser_thread.h"
+
+namespace extensions {
+
+namespace {
+using InstallError = update_client::InstallError;
+using Result = update_client::CrxInstaller::Result;
+}  // namespace
+
+ExtensionInstaller::ExtensionInstaller(
+    std::string extension_id,
+    const base::FilePath& extension_root,
+    ExtensionInstallerCallback extension_installer_callback)
+    : extension_id_(extension_id),
+      extension_root_(extension_root),
+      extension_installer_callback_(std::move(extension_installer_callback)) {}
+
+void ExtensionInstaller::OnUpdateError(int error) {
+  VLOG(1) << "OnUpdateError (" << extension_id_ << ") " << error;
+}
+
+void ExtensionInstaller::Install(const base::FilePath& unpack_path,
+                                 const std::string& public_key,
+                                 UpdateClientCallback update_client_callback) {
+  auto ui_thread = content::BrowserThread::GetTaskRunnerForThread(
+      content::BrowserThread::UI);
+  DCHECK(ui_thread);
+  DCHECK(!extension_installer_callback_.is_null());
+  if (base::PathExists(unpack_path)) {
+    ui_thread->PostTask(FROM_HERE,
+                        base::BindOnce(std::move(extension_installer_callback_),
+                                       extension_id_, public_key, unpack_path,
+                                       std::move(update_client_callback)));
+    return;
+  }
+  ui_thread->PostTask(FROM_HERE,
+                      base::BindOnce(std::move(update_client_callback),
+                                     Result(InstallError::GENERIC_ERROR)));
+}
+
+bool ExtensionInstaller::GetInstalledFile(const std::string& file,
+                                          base::FilePath* installed_file) {
+  base::FilePath relative_path = base::FilePath::FromUTF8Unsafe(file);
+  if (relative_path.IsAbsolute() || relative_path.ReferencesParent())
+    return false;
+  *installed_file = extension_root_.Append(relative_path);
+  if (!extension_root_.IsParent(*installed_file) ||
+      !base::PathExists(*installed_file)) {
+    VLOG(1) << "GetInstalledFile failed to find " << installed_file->value();
+    installed_file->clear();
+    return false;
+  }
+  return true;
+}
+
+bool ExtensionInstaller::Uninstall() {
+  NOTREACHED();
+  return false;
+}
+
+ExtensionInstaller::~ExtensionInstaller() {}
+
+}  // namespace extensions
diff --git a/extensions/browser/updater/extension_installer.h b/extensions/browser/updater/extension_installer.h
new file mode 100644
index 0000000..7037808
--- /dev/null
+++ b/extensions/browser/updater/extension_installer.h
@@ -0,0 +1,68 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef EXTENSIONS_BROWSER_UPDATER_EXTENSIONS_INSTALLER_H_
+#define EXTENSIONS_BROWSER_UPDATER_EXTENSIONS_INSTALLER_H_
+
+#include <memory>
+#include <string>
+
+#include "base/callback.h"
+#include "base/files/file_path.h"
+#include "base/macros.h"
+#include "components/update_client/update_client.h"
+
+namespace extensions {
+
+// This class is used as a shim between the components::update_client and
+// extensions code, to help the generic update_client code prepare and then
+// install an updated version of an extension. Because the update_client code
+// doesn't have the notion of extension ids, we use instances of this class to
+// map an install request back to the original update check for a given
+// extension.
+class ExtensionInstaller : public update_client::CrxInstaller {
+ public:
+  using UpdateClientCallback = update_client::CrxInstaller::Callback;
+  // A callback to implement the install of a new version of the extension.
+  // Takes ownership of the directory at |unpacked_dir|.
+  using ExtensionInstallerCallback =
+      base::OnceCallback<void(const std::string& extension_id,
+                              const std::string& public_key,
+                              const base::FilePath& unpacked_dir,
+                              UpdateClientCallback update_client_callback)>;
+
+  // This method takes the id and root directory for an extension we're doing
+  // an update check for, as well as a callback to call if we get a new version
+  // of it to install.
+  ExtensionInstaller(std::string extension_id,
+                     const base::FilePath& extension_root,
+                     ExtensionInstallerCallback extension_installer_callback);
+
+  // update_client::CrxInstaller::
+  void OnUpdateError(int error) override;
+
+  // This function is executed by the component update client, which runs on a
+  // blocking thread with background priority.
+  // |update_client_callback| is expected to be called on a UI thread.
+  void Install(const base::FilePath& unpack_path,
+               const std::string& public_key,
+               UpdateClientCallback update_client_callback) override;
+  bool GetInstalledFile(const std::string& file,
+                        base::FilePath* installed_file) override;
+  bool Uninstall() override;
+
+ private:
+  friend class base::RefCountedThreadSafe<ExtensionInstaller>;
+  ~ExtensionInstaller() override;
+
+  std::string extension_id_;
+  base::FilePath extension_root_;
+  ExtensionInstallerCallback extension_installer_callback_;
+
+  DISALLOW_COPY_AND_ASSIGN(ExtensionInstaller);
+};
+
+}  // namespace extensions
+
+#endif  // EXTENSIONS_BROWSER_UPDATER_EXTENSIONS_INSTALLER_H_
diff --git a/extensions/browser/updater/extension_installer_unittest.cc b/extensions/browser/updater/extension_installer_unittest.cc
new file mode 100644
index 0000000..347ff04
--- /dev/null
+++ b/extensions/browser/updater/extension_installer_unittest.cc
@@ -0,0 +1,211 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "extensions/browser/updater/extension_installer.h"
+
+#include <memory>
+#include <string>
+
+#include "base/bind.h"
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/files/scoped_temp_dir.h"
+#include "base/memory/scoped_refptr.h"
+#include "base/run_loop.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "components/update_client/update_client.h"
+#include "components/update_client/update_client_errors.h"
+#include "content/public/test/test_browser_thread_bundle.h"
+#include "content/public/test/test_utils.h"
+#include "extensions/browser/extensions_test.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace extensions {
+
+namespace {
+
+class ExtensionInstallerTest : public ExtensionsTest {
+ public:
+  using UpdateClientCallback =
+      extensions::ExtensionInstaller::UpdateClientCallback;
+  using ExtensionInstallerCallback =
+      ExtensionInstaller::ExtensionInstallerCallback;
+  using Result = update_client::CrxInstaller::Result;
+  using InstallError = update_client::InstallError;
+
+  ExtensionInstallerTest();
+  ~ExtensionInstallerTest() override;
+
+  void InstallCompleteCallback(const Result& result);
+
+ protected:
+  void RunThreads();
+
+ protected:
+  const std::string kExtensionId = "ldnnhddmnhbkjipkidpdiheffobcpfmf";
+  const std::string kPublicKey =
+      "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC8c4fBSPZ6utYoZ8NiWF/"
+      "DSaimBhihjwgOsskyleFGaurhi3TDClTVSGPxNkgCzrz0wACML7M4aNjpd05qupdbR2d294j"
+      "kDuI7caxEGUucpP7GJRRHnm8Sx+"
+      "y0ury28n8jbN0PnInKKWcxpIXXmNQyC19HBuO3QIeUq9Dqc+7YFQIDAQAB";
+
+  base::RunLoop run_loop_;
+  Result result_;
+  bool executed_;
+
+  DISALLOW_COPY_AND_ASSIGN(ExtensionInstallerTest);
+};
+
+ExtensionInstallerTest::ExtensionInstallerTest()
+    : ExtensionsTest(std::make_unique<content::TestBrowserThreadBundle>()),
+      result_(-1),
+      executed_(false) {}
+
+ExtensionInstallerTest::~ExtensionInstallerTest() {}
+
+void ExtensionInstallerTest::InstallCompleteCallback(const Result& result) {
+  result_ = result;
+  executed_ = true;
+  run_loop_.Quit();
+}
+
+void ExtensionInstallerTest::RunThreads() {
+  run_loop_.Run();
+}
+
+TEST_F(ExtensionInstallerTest, GetInstalledFile) {
+  base::ScopedTempDir root_dir;
+  ASSERT_TRUE(root_dir.CreateUniqueTempDir());
+  ASSERT_TRUE(base::PathExists(root_dir.GetPath()));
+  scoped_refptr<ExtensionInstaller> installer =
+      base::MakeRefCounted<ExtensionInstaller>(kExtensionId, root_dir.GetPath(),
+                                               ExtensionInstallerCallback());
+
+  base::FilePath installed_file;
+
+#ifdef FILE_PATH_USES_DRIVE_LETTERS
+  const std::string absolute_path = "C:\\abc\\def";
+  const std::string relative_path = "abc\\..\\def\\ghi";
+#else
+  const std::string absolute_path = "/abc/def";
+  const std::string relative_path = "/abc/../def/ghi";
+#endif
+
+  installed_file.clear();
+  EXPECT_FALSE(installer->GetInstalledFile(absolute_path, &installed_file));
+  installed_file.clear();
+  EXPECT_FALSE(installer->GetInstalledFile(relative_path, &installed_file));
+  installed_file.clear();
+  EXPECT_FALSE(installer->GetInstalledFile("extension", &installed_file));
+
+  installed_file.clear();
+  base::FilePath temp_file;
+  ASSERT_TRUE(base::CreateTemporaryFileInDir(root_dir.GetPath(), &temp_file));
+  base::FilePath base_temp_file = temp_file.BaseName();
+  EXPECT_TRUE(installer->GetInstalledFile(
+      std::string(base_temp_file.value().begin(), base_temp_file.value().end()),
+      &installed_file));
+#ifndef FILE_PATH_USES_DRIVE_LETTERS
+  // On some Win*, this test is flaky because of the way Win* constructs path.
+  // For example,
+  // "C:\Users\chrome-bot\AppData" is the same as "C:\Users\CHROME~1\AppData"
+  EXPECT_EQ(temp_file, installed_file);
+#endif
+}
+
+TEST_F(ExtensionInstallerTest, Install_InvalidUnpackedDir) {
+  // The unpacked folder is not valid, the installer will return an error.
+  base::ScopedTempDir root_dir;
+  ASSERT_TRUE(root_dir.CreateUniqueTempDir());
+  ASSERT_TRUE(base::PathExists(root_dir.GetPath()));
+  scoped_refptr<ExtensionInstaller> installer =
+      base::MakeRefCounted<ExtensionInstaller>(
+          kExtensionId, root_dir.GetPath(),
+          base::BindOnce([](const std::string& extension_id,
+                            const std::string& public_key,
+                            const base::FilePath& unpacked_dir,
+                            UpdateClientCallback update_client_callback) {
+            // This function should never be executed.
+            EXPECT_TRUE(false);
+          }));
+
+  // Non-existing unpacked dir
+  base::ScopedTempDir unpacked_dir;
+  ASSERT_TRUE(unpacked_dir.CreateUniqueTempDir());
+  ASSERT_TRUE(base::PathExists(unpacked_dir.GetPath()));
+  ASSERT_TRUE(base::DeleteFile(unpacked_dir.GetPath(), true));
+  ASSERT_FALSE(base::PathExists(unpacked_dir.GetPath()));
+  installer->Install(
+      unpacked_dir.GetPath(), kPublicKey,
+      base::BindOnce(&ExtensionInstallerTest::InstallCompleteCallback,
+                     base::Unretained(this)));
+
+  RunThreads();
+
+  EXPECT_TRUE(executed_);
+  EXPECT_EQ(static_cast<int>(InstallError::GENERIC_ERROR), result_.error);
+}
+
+TEST_F(ExtensionInstallerTest, Install_BasicInstallOperation_Error) {
+  base::ScopedTempDir root_dir;
+  ASSERT_TRUE(root_dir.CreateUniqueTempDir());
+  ASSERT_TRUE(base::PathExists(root_dir.GetPath()));
+  scoped_refptr<ExtensionInstaller> installer =
+      base::MakeRefCounted<ExtensionInstaller>(
+          kExtensionId, root_dir.GetPath(),
+          base::BindOnce([](const std::string& extension_id,
+                            const std::string& public_key,
+                            const base::FilePath& unpacked_dir,
+                            UpdateClientCallback update_client_callback) {
+            std::move(update_client_callback)
+                .Run(Result(InstallError::GENERIC_ERROR));
+          }));
+
+  base::ScopedTempDir unpacked_dir;
+  ASSERT_TRUE(unpacked_dir.CreateUniqueTempDir());
+  ASSERT_TRUE(base::PathExists(unpacked_dir.GetPath()));
+
+  installer->Install(
+      unpacked_dir.GetPath(), kPublicKey,
+      base::BindOnce(&ExtensionInstallerTest::InstallCompleteCallback,
+                     base::Unretained(this)));
+
+  RunThreads();
+
+  EXPECT_TRUE(executed_);
+  EXPECT_EQ(static_cast<int>(InstallError::GENERIC_ERROR), result_.error);
+}
+
+TEST_F(ExtensionInstallerTest, Install_BasicInstallOperation_Success) {
+  base::ScopedTempDir root_dir;
+  ASSERT_TRUE(root_dir.CreateUniqueTempDir());
+  ASSERT_TRUE(base::PathExists(root_dir.GetPath()));
+  scoped_refptr<ExtensionInstaller> installer =
+      base::MakeRefCounted<ExtensionInstaller>(
+          kExtensionId, root_dir.GetPath(),
+          base::BindOnce([](const std::string& extension_id,
+                            const std::string& public_key,
+                            const base::FilePath& unpacked_dir,
+                            UpdateClientCallback update_client_callback) {
+            std::move(update_client_callback).Run(Result(InstallError::NONE));
+          }));
+
+  base::ScopedTempDir unpacked_dir;
+  ASSERT_TRUE(unpacked_dir.CreateUniqueTempDir());
+  ASSERT_TRUE(base::PathExists(unpacked_dir.GetPath()));
+
+  installer->Install(
+      unpacked_dir.GetPath(), kPublicKey,
+      base::BindOnce(&ExtensionInstallerTest::InstallCompleteCallback,
+                     base::Unretained(this)));
+
+  RunThreads();
+
+  EXPECT_TRUE(executed_);
+  EXPECT_EQ(static_cast<int>(InstallError::NONE), result_.error);
+}
+
+}  // namespace
+
+}  // namespace extensions
diff --git a/extensions/browser/updater/update_data_provider.cc b/extensions/browser/updater/update_data_provider.cc
index 2ee26e4..eb0e1a7 100644
--- a/extensions/browser/updater/update_data_provider.cc
+++ b/extensions/browser/updater/update_data_provider.cc
@@ -11,18 +11,20 @@
 #include "base/strings/string_util.h"
 #include "base/task_scheduler/post_task.h"
 #include "components/update_client/update_client.h"
+#include "content/public/browser/browser_thread.h"
 #include "crypto/sha2.h"
 #include "extensions/browser/content_verifier.h"
+#include "extensions/browser/extension_prefs.h"
 #include "extensions/browser/extension_registry.h"
 #include "extensions/browser/extension_system.h"
-#include "extensions/browser/updater/update_install_shim.h"
+#include "extensions/browser/extensions_browser_client.h"
 #include "extensions/common/extension.h"
 
 namespace extensions {
 
 UpdateDataProvider::UpdateDataProvider(content::BrowserContext* context,
-                                       const InstallCallback& callback)
-    : context_(context), callback_(callback) {}
+                                       InstallCallback install_callback)
+    : context_(context), install_callback_(std::move(install_callback)) {}
 
 UpdateDataProvider::~UpdateDataProvider() {}
 
@@ -36,6 +38,7 @@
   if (!context_)
     return;
   const ExtensionRegistry* registry = ExtensionRegistry::Get(context_);
+  const ExtensionPrefs* extension_prefs = ExtensionPrefs::Get(context_);
   for (const auto& id : ids) {
     const Extension* extension = registry->GetInstalledExtension(id);
     if (!extension)
@@ -50,22 +53,44 @@
     info->version = *extension->version();
     info->allows_background_download = false;
     info->requires_network_encryption = true;
-    info->installer = new UpdateInstallShim(
+    info->installer = base::MakeRefCounted<ExtensionInstaller>(
         id, extension->path(),
-        base::Bind(&UpdateDataProvider::RunInstallCallback, this));
+        base::BindOnce(&UpdateDataProvider::RunInstallCallback, this));
+    if (!ExtensionsBrowserClient::Get()->IsExtensionEnabled(id, context_)) {
+      int disabled_reasons = extension_prefs->GetDisableReasons(id);
+      if (disabled_reasons == extensions::disable_reason::DISABLE_NONE ||
+          disabled_reasons >= extensions::disable_reason::DISABLE_REASON_LAST) {
+        info->disabled_reasons.push_back(0);
+      }
+      for (int enum_value = 1;
+           enum_value < extensions::disable_reason::DISABLE_REASON_LAST;
+           enum_value <<= 1) {
+        if (disabled_reasons & enum_value)
+          info->disabled_reasons.push_back(enum_value);
+      }
+    }
   }
 }
 
-void UpdateDataProvider::RunInstallCallback(const std::string& extension_id,
-                                            const base::FilePath& temp_dir) {
+void UpdateDataProvider::RunInstallCallback(
+    const std::string& extension_id,
+    const std::string& public_key,
+    const base::FilePath& unpacked_dir,
+    UpdateClientCallback update_client_callback) {
   if (!context_) {
     base::PostTaskWithTraits(
-        FROM_HERE, {base::MayBlock(), base::TaskPriority::BACKGROUND},
-        base::Bind(base::IgnoreResult(&base::DeleteFile), temp_dir, false));
+        FROM_HERE, {base::TaskPriority::BACKGROUND, base::MayBlock()},
+        base::BindOnce(base::IgnoreResult(&base::DeleteFile), unpacked_dir,
+                       true));
     return;
-  } else {
-    callback_.Run(context_, extension_id, temp_dir);
   }
+
+  DCHECK(!install_callback_.is_null());
+  content::BrowserThread::GetTaskRunnerForThread(content::BrowserThread::UI)
+      ->PostTask(FROM_HERE,
+                 base::BindOnce(std::move(install_callback_), context_,
+                                extension_id, public_key, unpacked_dir,
+                                std::move(update_client_callback)));
 }
 
 }  // namespace extensions
diff --git a/extensions/browser/updater/update_data_provider.h b/extensions/browser/updater/update_data_provider.h
index 95cea59..85954edb 100644
--- a/extensions/browser/updater/update_data_provider.h
+++ b/extensions/browser/updater/update_data_provider.h
@@ -11,6 +11,7 @@
 #include "base/callback.h"
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
+#include "extensions/browser/updater/extension_installer.h"
 
 namespace base {
 class FilePath;
@@ -30,17 +31,20 @@
 // extensions it is doing an update check for.
 class UpdateDataProvider : public base::RefCounted<UpdateDataProvider> {
  public:
-  typedef base::Callback<void(content::BrowserContext* context,
-                              const std::string& /* extension_id */,
-                              const base::FilePath& /* temp_dir */)>
-      InstallCallback;
+  using UpdateClientCallback = ExtensionInstaller::UpdateClientCallback;
+  using InstallCallback = base::OnceCallback<void(
+      content::BrowserContext* context,
+      const std::string& /* extension_id */,
+      const std::string& /* public_key */,
+      const base::FilePath& /* unpacked_dir */,
+      UpdateClientCallback /* update_client_callback */)>;
 
   // We need a browser context to use when retrieving data for a set of
-  // extension ids, as well as a callback for proceeding with installation
-  // steps once the UpdateClient has downloaded and unpacked an update for an
-  // extension.
+  // extension ids, as well as an install callback for proceeding with
+  // installation steps once the UpdateClient has downloaded and unpacked
+  // an update for an extension.
   UpdateDataProvider(content::BrowserContext* context,
-                     const InstallCallback& callback);
+                     InstallCallback install_callback);
 
   // Notify this object that the associated browser context is being shut down
   // the pointer to the context should be dropped and no more work should be
@@ -55,11 +59,14 @@
   friend class base::RefCounted<UpdateDataProvider>;
   ~UpdateDataProvider();
 
+  // This function should be called on the browser UI thread.
   void RunInstallCallback(const std::string& extension_id,
-                          const base::FilePath& temp_dir);
+                          const std::string& public_key,
+                          const base::FilePath& unpacked_dir,
+                          UpdateClientCallback update_client_callback);
 
   content::BrowserContext* context_;
-  InstallCallback callback_;
+  InstallCallback install_callback_;
 
   DISALLOW_COPY_AND_ASSIGN(UpdateDataProvider);
 };
diff --git a/extensions/browser/updater/update_data_provider_unittest.cc b/extensions/browser/updater/update_data_provider_unittest.cc
new file mode 100644
index 0000000..821d9bf
--- /dev/null
+++ b/extensions/browser/updater/update_data_provider_unittest.cc
@@ -0,0 +1,377 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "extensions/browser/updater/update_data_provider.h"
+
+#include <memory>
+#include <set>
+#include <string>
+#include <vector>
+
+#include "base/bind.h"
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/files/scoped_temp_dir.h"
+#include "base/run_loop.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "components/update_client/update_client.h"
+#include "extensions/browser/extension_prefs.h"
+#include "extensions/browser/extension_registry.h"
+#include "extensions/browser/extension_system.h"
+#include "extensions/browser/extensions_test.h"
+#include "extensions/browser/test_extensions_browser_client.h"
+#include "extensions/browser/updater/extension_installer.h"
+#include "extensions/common/disable_reason.h"
+#include "extensions/common/extension_builder.h"
+
+namespace extensions {
+
+namespace {
+
+class UpdateDataProviderExtensionsBrowserClient
+    : public TestExtensionsBrowserClient {
+ public:
+  explicit UpdateDataProviderExtensionsBrowserClient(
+      content::BrowserContext* context)
+      : TestExtensionsBrowserClient(context) {}
+  ~UpdateDataProviderExtensionsBrowserClient() override {}
+
+  bool IsExtensionEnabled(const std::string& id,
+                          content::BrowserContext* context) const override {
+    return enabled_ids_.find(id) != enabled_ids_.end();
+  }
+
+  void AddEnabledExtension(const std::string& id) { enabled_ids_.insert(id); }
+
+ private:
+  std::set<std::string> enabled_ids_;
+
+  DISALLOW_COPY_AND_ASSIGN(UpdateDataProviderExtensionsBrowserClient);
+};
+
+class UpdateDataProviderTest : public ExtensionsTest {
+ public:
+  using UpdateClientCallback = UpdateDataProvider::UpdateClientCallback;
+
+  UpdateDataProviderTest() {}
+  ~UpdateDataProviderTest() override {}
+
+  void SetUp() override {
+    SetExtensionsBrowserClient(
+        std::make_unique<UpdateDataProviderExtensionsBrowserClient>(
+            browser_context()));
+    ExtensionsTest::SetUp();
+  }
+
+ protected:
+  ExtensionSystem* extension_system() {
+    return ExtensionSystem::Get(browser_context());
+  }
+
+  ExtensionRegistry* extension_registry() {
+    return ExtensionRegistry::Get(browser_context());
+  }
+
+  // Helper function that creates a file at |relative_path| within |directory|
+  // and fills it with |content|.
+  bool AddFileToDirectory(const base::FilePath& directory,
+                          const base::FilePath& relative_path,
+                          const std::string& content) const {
+    const base::FilePath full_path = directory.Append(relative_path);
+    if (!base::CreateDirectory(full_path.DirName()))
+      return false;
+    int result = base::WriteFile(full_path, content.data(), content.size());
+    return (static_cast<size_t>(result) == content.size());
+  }
+
+  void AddExtension(const std::string& extension_id,
+                    const std::string& version,
+                    bool enabled,
+                    int disable_reasons) {
+    base::ScopedTempDir temp_dir;
+    ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
+    ASSERT_TRUE(base::PathExists(temp_dir.GetPath()));
+
+    base::FilePath foo_js(FILE_PATH_LITERAL("foo.js"));
+    base::FilePath bar_html(FILE_PATH_LITERAL("bar/bar.html"));
+    ASSERT_TRUE(AddFileToDirectory(temp_dir.GetPath(), foo_js, "hello"))
+        << "Failed to write " << temp_dir.GetPath().value() << "/"
+        << foo_js.value();
+    ASSERT_TRUE(AddFileToDirectory(temp_dir.GetPath(), bar_html, "world"));
+
+    ExtensionBuilder builder;
+    builder.SetManifest(DictionaryBuilder()
+                            .Set("name", "My First Extension")
+                            .Set("version", version)
+                            .Set("manifest_version", 2)
+                            .Build());
+    builder.SetID(extension_id);
+    builder.SetPath(temp_dir.GetPath());
+
+    auto* test_browser_client =
+        static_cast<UpdateDataProviderExtensionsBrowserClient*>(
+            extensions_browser_client());
+    if (enabled) {
+      extension_registry()->AddEnabled(builder.Build());
+      test_browser_client->AddEnabledExtension(extension_id);
+    } else {
+      extension_registry()->AddDisabled(builder.Build());
+      ExtensionPrefs::Get(browser_context())
+          ->AddDisableReasons(extension_id, disable_reasons);
+    }
+
+    const Extension* extension =
+        extension_registry()->GetInstalledExtension(extension_id);
+    ASSERT_NE(nullptr, extension);
+    ASSERT_EQ(version, extension->VersionString());
+  }
+
+  const std::string kExtensionId1 = "adbncddmehfkgipkidpdiheffobcpfma";
+  const std::string kExtensionId2 = "ldnnhddmnhbkjipkidpdiheffobcpfmf";
+};
+
+TEST_F(UpdateDataProviderTest, GetData_NoDataAdded) {
+  scoped_refptr<UpdateDataProvider> data_provider =
+      base::MakeRefCounted<UpdateDataProvider>(
+          nullptr,
+          base::BindOnce([](content::BrowserContext*, const std::string&,
+                            const std::string&, const base::FilePath&,
+                            UpdateClientCallback update_client_callback) {}));
+
+  std::vector<std::string> ids({kExtensionId1});
+  std::vector<update_client::CrxComponent> data;
+  data_provider->GetData(ids, &data);
+  EXPECT_EQ(0UL, data.size());
+}
+
+TEST_F(UpdateDataProviderTest, GetData_EnabledExtension) {
+  scoped_refptr<UpdateDataProvider> data_provider =
+      base::MakeRefCounted<UpdateDataProvider>(
+          browser_context(),
+          base::BindOnce([](content::BrowserContext* context,
+                            const std::string& extension_id,
+                            const std::string& public_key,
+                            const base::FilePath& temp_dir,
+                            UpdateClientCallback update_client_callback) {}));
+
+  const std::string version = "0.1.2.3";
+  AddExtension(kExtensionId1, version, true,
+               disable_reason::DisableReason::DISABLE_NONE);
+
+  std::vector<std::string> ids({kExtensionId1});
+  std::vector<update_client::CrxComponent> data;
+  data_provider->GetData(ids, &data);
+
+  ASSERT_EQ(1UL, data.size());
+  EXPECT_EQ(version, data[0].version.GetString());
+  EXPECT_NE(nullptr, data[0].installer.get());
+  EXPECT_EQ(0UL, data[0].disabled_reasons.size());
+}
+
+TEST_F(UpdateDataProviderTest, GetData_DisabledExtension_WithNoReason) {
+  scoped_refptr<UpdateDataProvider> data_provider =
+      base::MakeRefCounted<UpdateDataProvider>(
+          browser_context(),
+          base::BindOnce([](content::BrowserContext* context,
+                            const std::string& extension_id,
+                            const std::string& public_key,
+                            const base::FilePath& temp_dir,
+                            UpdateClientCallback update_client_callback) {}));
+
+  const std::string version = "0.1.2.3";
+  AddExtension(kExtensionId1, version, false,
+               disable_reason::DisableReason::DISABLE_NONE);
+
+  std::vector<std::string> ids({kExtensionId1});
+  std::vector<update_client::CrxComponent> data;
+  data_provider->GetData(ids, &data);
+
+  ASSERT_EQ(1UL, data.size());
+  EXPECT_EQ(version, data[0].version.GetString());
+  EXPECT_NE(nullptr, data[0].installer.get());
+  ASSERT_EQ(1UL, data[0].disabled_reasons.size());
+  EXPECT_EQ(disable_reason::DisableReason::DISABLE_NONE,
+            data[0].disabled_reasons[0]);
+}
+
+TEST_F(UpdateDataProviderTest, GetData_DisabledExtension_UnknownReason) {
+  scoped_refptr<UpdateDataProvider> data_provider =
+      base::MakeRefCounted<UpdateDataProvider>(
+          browser_context(),
+          base::BindOnce([](content::BrowserContext* context,
+                            const std::string& extension_id,
+                            const std::string& public_key,
+                            const base::FilePath& temp_dir,
+                            UpdateClientCallback update_client_callback) {}));
+
+  const std::string version = "0.1.2.3";
+  AddExtension(kExtensionId1, version, false,
+               disable_reason::DisableReason::DISABLE_REASON_LAST);
+
+  std::vector<std::string> ids({kExtensionId1});
+  std::vector<update_client::CrxComponent> data;
+  data_provider->GetData(ids, &data);
+
+  ASSERT_EQ(1UL, data.size());
+  EXPECT_EQ(version, data[0].version.GetString());
+  EXPECT_NE(nullptr, data[0].installer.get());
+  ASSERT_EQ(1UL, data[0].disabled_reasons.size());
+  EXPECT_EQ(disable_reason::DisableReason::DISABLE_NONE,
+            data[0].disabled_reasons[0]);
+}
+
+TEST_F(UpdateDataProviderTest, GetData_DisabledExtension_WithReasons) {
+  scoped_refptr<UpdateDataProvider> data_provider =
+      base::MakeRefCounted<UpdateDataProvider>(
+          browser_context(),
+          base::BindOnce([](content::BrowserContext* context,
+                            const std::string& extension_id,
+                            const std::string& public_key,
+                            const base::FilePath& temp_dir,
+                            UpdateClientCallback update_client_callback) {}));
+
+  const std::string version = "0.1.2.3";
+  AddExtension(kExtensionId1, version, false,
+               disable_reason::DisableReason::DISABLE_USER_ACTION |
+                   disable_reason::DisableReason::DISABLE_CORRUPTED);
+
+  std::vector<std::string> ids({kExtensionId1});
+  std::vector<update_client::CrxComponent> data;
+  data_provider->GetData(ids, &data);
+
+  ASSERT_EQ(1UL, data.size());
+  EXPECT_EQ(version, data[0].version.GetString());
+  EXPECT_NE(nullptr, data[0].installer.get());
+  ASSERT_EQ(2UL, data[0].disabled_reasons.size());
+  EXPECT_EQ(disable_reason::DisableReason::DISABLE_USER_ACTION,
+            data[0].disabled_reasons[0]);
+  EXPECT_EQ(disable_reason::DisableReason::DISABLE_CORRUPTED,
+            data[0].disabled_reasons[1]);
+}
+
+TEST_F(UpdateDataProviderTest,
+       GetData_DisabledExtension_WithReasonsAndUnknownReason) {
+  scoped_refptr<UpdateDataProvider> data_provider =
+      base::MakeRefCounted<UpdateDataProvider>(
+          browser_context(),
+          base::BindOnce([](content::BrowserContext* context,
+                            const std::string& extension_id,
+                            const std::string& public_key,
+                            const base::FilePath& temp_dir,
+                            UpdateClientCallback update_client_callback) {}));
+
+  const std::string version = "0.1.2.3";
+  AddExtension(kExtensionId1, version, false,
+               disable_reason::DisableReason::DISABLE_USER_ACTION |
+                   disable_reason::DisableReason::DISABLE_CORRUPTED |
+                   disable_reason::DisableReason::DISABLE_REASON_LAST);
+
+  std::vector<std::string> ids({kExtensionId1});
+  std::vector<update_client::CrxComponent> data;
+  data_provider->GetData(ids, &data);
+
+  ASSERT_EQ(1UL, data.size());
+  EXPECT_EQ(version, data[0].version.GetString());
+  EXPECT_NE(nullptr, data[0].installer.get());
+  ASSERT_EQ(3UL, data[0].disabled_reasons.size());
+  EXPECT_EQ(disable_reason::DisableReason::DISABLE_NONE,
+            data[0].disabled_reasons[0]);
+  EXPECT_EQ(disable_reason::DisableReason::DISABLE_USER_ACTION,
+            data[0].disabled_reasons[1]);
+  EXPECT_EQ(disable_reason::DisableReason::DISABLE_CORRUPTED,
+            data[0].disabled_reasons[2]);
+}
+
+TEST_F(UpdateDataProviderTest, GetData_MultipleExtensions1) {
+  scoped_refptr<UpdateDataProvider> data_provider =
+      base::MakeRefCounted<UpdateDataProvider>(
+          browser_context(),
+          base::BindOnce([](content::BrowserContext* context,
+                            const std::string& extension_id,
+                            const std::string& public_key,
+                            const base::FilePath& temp_dir,
+                            UpdateClientCallback update_client_callback) {}));
+
+  const std::string version1 = "0.1.2.3";
+  const std::string version2 = "9.8.7.6";
+  AddExtension(kExtensionId1, version1, true,
+               disable_reason::DisableReason::DISABLE_NONE);
+  AddExtension(kExtensionId2, version2, true,
+               disable_reason::DisableReason::DISABLE_NONE);
+
+  std::vector<std::string> ids({kExtensionId1, kExtensionId2});
+  std::vector<update_client::CrxComponent> data;
+  data_provider->GetData(ids, &data);
+
+  ASSERT_EQ(2UL, data.size());
+  EXPECT_EQ(version1, data[0].version.GetString());
+  EXPECT_NE(nullptr, data[0].installer.get());
+  EXPECT_EQ(0UL, data[0].disabled_reasons.size());
+  EXPECT_EQ(version2, data[1].version.GetString());
+  EXPECT_NE(nullptr, data[1].installer.get());
+  EXPECT_EQ(0UL, data[1].disabled_reasons.size());
+}
+
+TEST_F(UpdateDataProviderTest, GetData_MultipleExtensions2) {
+  // One extension is disabled.
+  scoped_refptr<UpdateDataProvider> data_provider =
+      base::MakeRefCounted<UpdateDataProvider>(
+          browser_context(),
+          base::BindOnce([](content::BrowserContext* context,
+                            const std::string& extension_id,
+                            const std::string& public_key,
+                            const base::FilePath& temp_dir,
+                            UpdateClientCallback update_client_callback) {}));
+
+  const std::string version1 = "0.1.2.3";
+  const std::string version2 = "9.8.7.6";
+  AddExtension(kExtensionId1, version1, false,
+               disable_reason::DisableReason::DISABLE_CORRUPTED);
+  AddExtension(kExtensionId2, version2, true,
+               disable_reason::DisableReason::DISABLE_NONE);
+
+  std::vector<std::string> ids({kExtensionId1, kExtensionId2});
+  std::vector<update_client::CrxComponent> data;
+  data_provider->GetData(ids, &data);
+
+  ASSERT_EQ(2UL, data.size());
+  EXPECT_EQ(version1, data[0].version.GetString());
+  EXPECT_NE(nullptr, data[0].installer.get());
+  ASSERT_EQ(1UL, data[0].disabled_reasons.size());
+  EXPECT_EQ(disable_reason::DisableReason::DISABLE_CORRUPTED,
+            data[0].disabled_reasons[0]);
+
+  EXPECT_EQ(version2, data[1].version.GetString());
+  EXPECT_NE(nullptr, data[1].installer.get());
+  EXPECT_EQ(0UL, data[1].disabled_reasons.size());
+}
+
+TEST_F(UpdateDataProviderTest, GetData_MultipleExtensions3) {
+  // One extension is not installed.
+  scoped_refptr<UpdateDataProvider> data_provider =
+      base::MakeRefCounted<UpdateDataProvider>(
+          browser_context(),
+          base::BindOnce([](content::BrowserContext* context,
+                            const std::string& extension_id,
+                            const std::string& public_key,
+                            const base::FilePath& temp_dir,
+                            UpdateClientCallback update_client_callback) {}));
+
+  const std::string version = "0.1.2.3";
+  AddExtension(kExtensionId1, version, true,
+               disable_reason::DisableReason::DISABLE_NONE);
+
+  std::vector<std::string> ids({kExtensionId1, kExtensionId2});
+  std::vector<update_client::CrxComponent> data;
+  data_provider->GetData(ids, &data);
+
+  ASSERT_EQ(1UL, data.size());
+  EXPECT_EQ(version, data[0].version.GetString());
+  EXPECT_NE(nullptr, data[0].installer.get());
+  EXPECT_EQ(0UL, data[0].disabled_reasons.size());
+}
+
+}  // namespace
+
+}  // namespace extensions
diff --git a/extensions/browser/updater/update_install_shim.cc b/extensions/browser/updater/update_install_shim.cc
deleted file mode 100644
index 46ca4ba7..0000000
--- a/extensions/browser/updater/update_install_shim.cc
+++ /dev/null
@@ -1,105 +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 "extensions/browser/updater/update_install_shim.h"
-
-#include <utility>
-
-#include "base/files/file_enumerator.h"
-#include "base/files/file_path.h"
-#include "base/files/file_util.h"
-#include "base/files/scoped_temp_dir.h"
-#include "base/logging.h"
-#include "base/strings/string_number_conversions.h"
-#include "base/task_scheduler/post_task.h"
-#include "components/update_client/update_client_errors.h"
-#include "content/public/browser/browser_thread.h"
-
-namespace extensions {
-
-namespace {
-using InstallError = update_client::InstallError;
-using Result = update_client::CrxInstaller::Result;
-}  // namespace
-
-UpdateInstallShim::UpdateInstallShim(std::string extension_id,
-                                     const base::FilePath& extension_root,
-                                     UpdateInstallShimCallback callback)
-    : extension_id_(extension_id),
-      extension_root_(extension_root),
-      callback_(std::move(callback)) {}
-
-void UpdateInstallShim::OnUpdateError(int error) {
-  VLOG(1) << "OnUpdateError (" << extension_id_ << ") " << error;
-}
-
-void UpdateInstallShim::Install(const base::FilePath& unpack_path,
-                                const std::string& /*public_key*/,
-                                Callback callback) {
-  base::ScopedTempDir temp_dir;
-  if (!temp_dir.CreateUniqueTempDir()) {
-    content::BrowserThread::PostTask(
-        content::BrowserThread::UI, FROM_HERE,
-        base::BindOnce(std::move(callback),
-                       Result(InstallError::GENERIC_ERROR)));
-    return;
-  }
-
-  // The UpdateClient code will delete unpack_path if it still exists after
-  // this method is done, so we rename it on top of our temp dir.
-  if (!base::DeleteFile(temp_dir.GetPath(), true) ||
-      !base::Move(unpack_path, temp_dir.GetPath())) {
-    LOG(ERROR) << "Trying to install update for " << extension_id_
-               << "and failed to move " << unpack_path.value() << " to  "
-               << temp_dir.GetPath().value();
-    content::BrowserThread::PostTask(
-        content::BrowserThread::UI, FROM_HERE,
-        base::BindOnce(std::move(callback),
-                       Result(InstallError::GENERIC_ERROR)));
-    return;
-  }
-  content::BrowserThread::PostTask(
-      content::BrowserThread::UI, FROM_HERE,
-      base::BindOnce(&UpdateInstallShim::RunCallbackOnUIThread, this,
-                     temp_dir.Take()));
-
-  content::BrowserThread::PostTask(
-      content::BrowserThread::UI, FROM_HERE,
-      base::BindOnce(std::move(callback), Result(InstallError::NONE)));
-}
-
-bool UpdateInstallShim::GetInstalledFile(const std::string& file,
-                                         base::FilePath* installed_file) {
-  base::FilePath relative_path = base::FilePath::FromUTF8Unsafe(file);
-  if (relative_path.IsAbsolute() || relative_path.ReferencesParent())
-    return false;
-  *installed_file = extension_root_.Append(relative_path);
-  if (!extension_root_.IsParent(*installed_file) ||
-      !base::PathExists(*installed_file)) {
-    VLOG(1) << "GetInstalledFile failed to find " << installed_file->value();
-    installed_file->clear();
-    return false;
-  }
-  return true;
-}
-
-bool UpdateInstallShim::Uninstall() {
-  NOTREACHED();
-  return false;
-}
-
-UpdateInstallShim::~UpdateInstallShim() {}
-
-void UpdateInstallShim::RunCallbackOnUIThread(const base::FilePath& temp_dir) {
-  if (callback_.is_null()) {
-    base::PostTaskWithTraits(FROM_HERE,
-                             {base::MayBlock(), base::TaskPriority::BACKGROUND},
-                             base::Bind(base::IgnoreResult(&base::DeleteFile),
-                                        temp_dir, true /*recursive */));
-    return;
-  }
-  std::move(callback_).Run(extension_id_, temp_dir);
-}
-
-}  // namespace extensions
diff --git a/extensions/browser/updater/update_install_shim.h b/extensions/browser/updater/update_install_shim.h
deleted file mode 100644
index 5922f06..0000000
--- a/extensions/browser/updater/update_install_shim.h
+++ /dev/null
@@ -1,76 +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.
-
-#ifndef EXTENSIONS_BROWSER_UPDATER_UPDATE_INSTALL_SHIM_H_
-#define EXTENSIONS_BROWSER_UPDATER_UPDATE_INSTALL_SHIM_H_
-
-#include <memory>
-#include <string>
-
-#include "base/callback.h"
-#include "base/files/file_path.h"
-#include "base/macros.h"
-#include "components/update_client/update_client.h"
-
-namespace extensions {
-
-// A callback to implement the install of a new version of the extension.
-// Takes ownership of the directory at |temp_dir|.
-using UpdateInstallShimCallback =
-    base::OnceCallback<void(const std::string& extension_id,
-                            const base::FilePath& temp_dir)>;
-
-// This class is used as a shim between the components::update_client and
-// extensions code, to help the generic update_client code prepare and then
-// install an updated version of an extension. Because the update_client code
-// doesn't have the notion of extension ids, we use instances of this class to
-// map an install request back to the original update check for a given
-// extension.
-class UpdateInstallShim : public update_client::CrxInstaller {
- public:
-  // This method takes the id and root directory for an extension we're doing
-  // an update check for, as well as a callback to call if we get a new version
-  // of it to install.
-  UpdateInstallShim(std::string extension_id,
-                    const base::FilePath& extension_root,
-                    UpdateInstallShimCallback callback);
-
-  // Called when an update attempt failed.
-  void OnUpdateError(int error) override;
-
-  // This is called when a new version of an extension is unpacked at
-  // |unpack_path| and is ready for install. |public_key| contains the
-  // CRX public_key in PEM format, without the header and the footer.
-  void Install(const base::FilePath& unpack_path,
-               const std::string& public_key,
-               Callback callback) override;
-
-  // This is called by the generic differential update code in the
-  // update_client to provide the path to an existing file in the current
-  // version of the extension, so that it can be copied (or serve as the input
-  // to diff-patching) with output going to the directory with the new version
-  // being staged on disk for install.
-  bool GetInstalledFile(const std::string& file,
-                        base::FilePath* installed_file) override;
-
-  // This method is not relevant to extension updating.
-  bool Uninstall() override;
-
- private:
-  friend class base::RefCountedThreadSafe<UpdateInstallShim>;
-  ~UpdateInstallShim() override;
-
-  // Takes ownership of the directory at path |temp_dir|.
-  void RunCallbackOnUIThread(const base::FilePath& temp_dir);
-
-  std::string extension_id_;
-  base::FilePath extension_root_;
-  UpdateInstallShimCallback callback_;
-
-  DISALLOW_COPY_AND_ASSIGN(UpdateInstallShim);
-};
-
-}  // namespace extensions
-
-#endif  // EXTENSIONS_BROWSER_UPDATER_UPDATE_INSTALL_SHIM_H_
diff --git a/extensions/browser/updater/update_service.cc b/extensions/browser/updater/update_service.cc
index 92b5efe..8649042 100644
--- a/extensions/browser/updater/update_service.cc
+++ b/extensions/browser/updater/update_service.cc
@@ -9,6 +9,7 @@
 #include "components/update_client/update_client.h"
 #include "components/update_client/update_client_errors.h"
 #include "content/public/browser/browser_context.h"
+#include "content/public/browser/browser_thread.h"
 #include "extensions/browser/extension_system.h"
 #include "extensions/browser/extensions_browser_client.h"
 #include "extensions/browser/updater/update_data_provider.h"
@@ -16,15 +17,30 @@
 
 namespace {
 
+using UpdateClientCallback =
+    extensions::UpdateDataProvider::UpdateClientCallback;
+
 void UpdateCheckCompleteCallback(update_client::Error error) {}
 
 void SendUninstallPingCompleteCallback(update_client::Error error) {}
 
 void InstallUpdateCallback(content::BrowserContext* context,
                            const std::string& extension_id,
-                           const base::FilePath& temp_dir) {
-  extensions::ExtensionSystem::Get(context)
-      ->InstallUpdate(extension_id, temp_dir);
+                           const std::string& public_key,
+                           const base::FilePath& unpacked_dir,
+                           UpdateClientCallback update_client_callback) {
+  using InstallError = update_client::InstallError;
+  using Result = update_client::CrxInstaller::Result;
+  extensions::ExtensionSystem::Get(context)->InstallUpdate(
+      extension_id, public_key, unpacked_dir,
+      base::BindOnce(
+          [](UpdateClientCallback update_client_callback, bool success) {
+            DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+            std::move(update_client_callback)
+                .Run(Result(success ? InstallError::NONE
+                                    : InstallError::GENERIC_ERROR));
+          },
+          std::move(update_client_callback)));
 }
 
 }  // namespace
@@ -49,16 +65,17 @@
                                       const base::Version& version,
                                       int reason) {
   update_client_->SendUninstallPing(
-      id, version, reason, base::Bind(&SendUninstallPingCompleteCallback));
+      id, version, reason, base::BindOnce(&SendUninstallPingCompleteCallback));
 }
 
 void UpdateService::StartUpdateCheck(
     const std::vector<std::string>& extension_ids) {
   if (!update_client_)
     return;
-  update_client_->Update(extension_ids, base::Bind(&UpdateDataProvider::GetData,
-                                                   update_data_provider_),
-                         base::Bind(&UpdateCheckCompleteCallback));
+  update_client_->Update(
+      extension_ids,
+      base::BindOnce(&UpdateDataProvider::GetData, update_data_provider_),
+      base::BindOnce(&UpdateCheckCompleteCallback));
 }
 
 UpdateService::UpdateService(
@@ -66,8 +83,8 @@
     scoped_refptr<update_client::UpdateClient> update_client)
     : context_(context), update_client_(update_client) {
   CHECK(update_client_);
-  update_data_provider_ =
-      new UpdateDataProvider(context_, base::Bind(&InstallUpdateCallback));
+  update_data_provider_ = base::MakeRefCounted<UpdateDataProvider>(
+      context_, base::BindOnce(&InstallUpdateCallback));
 }
 
 UpdateService::~UpdateService() {}
diff --git a/extensions/browser/updater/update_service_unittest.cc b/extensions/browser/updater/update_service_unittest.cc
index 069680af..ede45cc 100644
--- a/extensions/browser/updater/update_service_unittest.cc
+++ b/extensions/browser/updater/update_service_unittest.cc
@@ -112,6 +112,7 @@
 // versions of an extension.
 class FakeExtensionSystem : public MockExtensionSystem {
  public:
+  using InstallUpdateCallback = MockExtensionSystem::InstallUpdateCallback;
   explicit FakeExtensionSystem(content::BrowserContext* context)
       : MockExtensionSystem(context) {}
   ~FakeExtensionSystem() override {}
@@ -131,14 +132,18 @@
 
   // ExtensionSystem override
   void InstallUpdate(const std::string& extension_id,
-                     const base::FilePath& temp_dir) override {
+                     const std::string& public_key,
+                     const base::FilePath& temp_dir,
+                     InstallUpdateCallback install_update_callback) override {
     base::DeleteFile(temp_dir, true /*recursive*/);
     InstallUpdateRequest request;
     request.extension_id = extension_id;
     request.temp_dir = temp_dir;
     install_requests_.push_back(request);
-    if (!next_install_callback_.is_null())
+    if (!next_install_callback_.is_null()) {
       std::move(next_install_callback_).Run();
+    }
+    std::move(install_update_callback).Run(true);
   }
 
  private:
@@ -261,12 +266,16 @@
   base::ScopedTempDir new_version_dir;
   ASSERT_TRUE(new_version_dir.CreateUniqueTempDir());
 
+  bool done = false;
   installer->Install(
       new_version_dir.GetPath(), std::string(),
-      base::Bind([](const update_client::CrxInstaller::Result& result) {
-        EXPECT_EQ(0, result.error);
-        EXPECT_EQ(0, result.extended_error);
-      }));
+      base::BindOnce(
+          [](bool* done, const update_client::CrxInstaller::Result& result) {
+            *done = true;
+            EXPECT_EQ(0, result.error);
+            EXPECT_EQ(0, result.extended_error);
+          },
+          &done));
 
   scoped_refptr<content::MessageLoopRunner> loop_runner =
       base::MakeRefCounted<content::MessageLoopRunner>();
@@ -277,8 +286,9 @@
       extension_system()->install_requests();
   ASSERT_EQ(1u, requests->size());
   EXPECT_EQ(requests->at(0).extension_id, extension1->id());
-  EXPECT_NE(requests->at(0).temp_dir.value(),
+  EXPECT_EQ(requests->at(0).temp_dir.value(),
             new_version_dir.GetPath().value());
+  EXPECT_TRUE(done);
 }
 
 TEST_F(UpdateServiceTest, UninstallPings) {
diff --git a/extensions/shell/browser/shell_extension_system.cc b/extensions/shell/browser/shell_extension_system.cc
index 176952a..56a5a81 100644
--- a/extensions/shell/browser/shell_extension_system.cc
+++ b/extensions/shell/browser/shell_extension_system.cc
@@ -198,8 +198,11 @@
   return std::make_unique<ExtensionSet>();
 }
 
-void ShellExtensionSystem::InstallUpdate(const std::string& extension_id,
-                                         const base::FilePath& temp_dir) {
+void ShellExtensionSystem::InstallUpdate(
+    const std::string& extension_id,
+    const std::string& public_key,
+    const base::FilePath& temp_dir,
+    InstallUpdateCallback install_update_callback) {
   NOTREACHED();
   base::DeleteFile(temp_dir, true /* recursive */);
 }
diff --git a/extensions/shell/browser/shell_extension_system.h b/extensions/shell/browser/shell_extension_system.h
index 15e8482..d13eed1a 100644
--- a/extensions/shell/browser/shell_extension_system.h
+++ b/extensions/shell/browser/shell_extension_system.h
@@ -29,6 +29,7 @@
 // app_shell to skip initialization of services it doesn't need.
 class ShellExtensionSystem : public ExtensionSystem {
  public:
+  using InstallUpdateCallback = ExtensionSystem::InstallUpdateCallback;
   explicit ShellExtensionSystem(content::BrowserContext* browser_context);
   ~ShellExtensionSystem() override;
 
@@ -75,7 +76,9 @@
   std::unique_ptr<ExtensionSet> GetDependentExtensions(
       const Extension* extension) override;
   void InstallUpdate(const std::string& extension_id,
-                     const base::FilePath& temp_dir) override;
+                     const std::string& public_key,
+                     const base::FilePath& temp_dir,
+                     InstallUpdateCallback install_update_callback) override;
 
  private:
   void OnExtensionRegisteredWithRequestContexts(
diff --git a/media/capture/mojo/video_capture_types.typemap b/media/capture/mojo/video_capture_types.typemap
index 9b7ae3d..70e9a398 100644
--- a/media/capture/mojo/video_capture_types.typemap
+++ b/media/capture/mojo/video_capture_types.typemap
@@ -13,11 +13,11 @@
 traits_headers = [
   "//media/capture/ipc/capture_param_traits_macros.h",
   "//media/capture/ipc/capture_param_traits.h",
-  "//media/capture/mojo/video_capture_types_typemap_traits.h",
+  "//media/capture/mojo/video_capture_types_struct_traits.h",
 ]
 
 sources = [
-  "//media/capture/mojo/video_capture_types_typemap_traits.cc",
+  "//media/capture/mojo/video_capture_types_struct_traits.cc",
 ]
 
 deps = [
diff --git a/media/capture/mojo/video_capture_types_typemap_traits.cc b/media/capture/mojo/video_capture_types_struct_traits.cc
similarity index 99%
rename from media/capture/mojo/video_capture_types_typemap_traits.cc
rename to media/capture/mojo/video_capture_types_struct_traits.cc
index 1f24be4..998cea8 100644
--- a/media/capture/mojo/video_capture_types_typemap_traits.cc
+++ b/media/capture/mojo/video_capture_types_struct_traits.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 "media/capture/mojo/video_capture_types_typemap_traits.h"
+#include "media/capture/mojo/video_capture_types_struct_traits.h"
 
 #include "media/base/ipc/media_param_traits_macros.h"
 #include "ui/gfx/geometry/mojo/geometry.mojom.h"
diff --git a/media/capture/mojo/video_capture_types_typemap_traits.h b/media/capture/mojo/video_capture_types_struct_traits.h
similarity index 96%
rename from media/capture/mojo/video_capture_types_typemap_traits.h
rename to media/capture/mojo/video_capture_types_struct_traits.h
index 811e678..e78fb29 100644
--- a/media/capture/mojo/video_capture_types_typemap_traits.h
+++ b/media/capture/mojo/video_capture_types_struct_traits.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef MEDIA_CAPTURE_MOJO_VIDEO_CAPTURE_TYPES_TYPEMAP_TRAITS_H_
-#define MEDIA_CAPTURE_MOJO_VIDEO_CAPTURE_TYPES_TYPEMAP_TRAITS_H_
+#ifndef MEDIA_CAPTURE_MOJO_VIDEO_CAPTURE_TYPES_STRUCT_TRAITS_H_
+#define MEDIA_CAPTURE_MOJO_VIDEO_CAPTURE_TYPES_STRUCT_TRAITS_H_
 
 #include "media/capture/mojo/video_capture_types.mojom.h"
 #include "media/capture/video/video_capture_device_descriptor.h"
@@ -187,4 +187,4 @@
 };
 }  // namespace mojo
 
-#endif  // MEDIA_CAPTURE_MOJO_VIDEO_CAPTURE_TYPES_TYPEMAP_TRAITS_H_
+#endif  // MEDIA_CAPTURE_MOJO_VIDEO_CAPTURE_TYPES_STRUCT_TRAITS_H_
diff --git a/mojo/public/tools/bindings/chromium_bindings_configuration.gni b/mojo/public/tools/bindings/chromium_bindings_configuration.gni
index 0ff3764..cf9bc92 100644
--- a/mojo/public/tools/bindings/chromium_bindings_configuration.gni
+++ b/mojo/public/tools/bindings/chromium_bindings_configuration.gni
@@ -44,7 +44,6 @@
   "//storage/common/typemaps.gni",
   "//third_party/WebKit/common/typemaps.gni",
   "//third_party/WebKit/public/public_typemaps.gni",
-  "//ui/base/clipboard/mojom/typemaps.gni",
   "//ui/base/mojo/typemaps.gni",
   "//ui/display/mojo/typemaps.gni",
   "//ui/events/devices/mojo/typemaps.gni",
diff --git a/net/nqe/network_quality_estimator.cc b/net/nqe/network_quality_estimator.cc
index 84ef525..b7c34fe 100644
--- a/net/nqe/network_quality_estimator.cc
+++ b/net/nqe/network_quality_estimator.cc
@@ -1739,7 +1739,8 @@
       std::string("NQE.RTT.RawObservation.") +
           nqe::internal::GetNameForObservationSource(observation.source()),
       1, 10 * 1000, 50, base::HistogramBase::kUmaTargetedHistogramFlag);
-  raw_observation_histogram->Add(observation.value());
+  if (raw_observation_histogram)
+    raw_observation_histogram->Add(observation.value());
 
   // Maybe recompute the effective connection type since a new RTT observation
   // is available.
@@ -1773,7 +1774,8 @@
       std::string("NQE.Kbps.RawObservation.") +
           nqe::internal::GetNameForObservationSource(observation.source()),
       1, 10 * 1000, 50, base::HistogramBase::kUmaTargetedHistogramFlag);
-  raw_observation_histogram->Add(observation.value());
+  if (raw_observation_histogram)
+    raw_observation_histogram->Add(observation.value());
 
   // Maybe recompute the effective connection type since a new throughput
   // observation is available.
diff --git a/net/url_request/url_request_quic_unittest.cc b/net/url_request/url_request_quic_unittest.cc
index 6820bd9a..580f652 100644
--- a/net/url_request/url_request_quic_unittest.cc
+++ b/net/url_request/url_request_quic_unittest.cc
@@ -248,7 +248,7 @@
   EXPECT_EQ(kHelloBodyValue, delegate.data_received());
 }
 
-TEST_F(URLRequestQuicTest, CancelPushIfCached) {
+TEST_F(URLRequestQuicTest, CancelPushIfCached_SomeCached) {
   base::RunLoop run_loop;
   Init();
 
@@ -292,7 +292,7 @@
   net::TestNetLogEntry::List entries;
   ExtractNetLog(NetLogEventType::SERVER_PUSH_LOOKUP_TRANSACTION, &entries);
 
-  EXPECT_EQ(4u, entries.size());
+  ASSERT_EQ(4u, entries.size());
 
   std::string value;
   int net_error;
@@ -301,14 +301,43 @@
   std::string push_url_2 =
       base::StringPrintf("https://%s%s", kTestServerHost, "/favicon.ico");
 
+  ASSERT_EQ(entries[0].type,
+            net::NetLogEventType::SERVER_PUSH_LOOKUP_TRANSACTION);
+  EXPECT_EQ(entries[0].phase, net::NetLogEventPhase::BEGIN);
+  EXPECT_EQ(entries[0].source.type,
+            net::NetLogSourceType::SERVER_PUSH_LOOKUP_TRANSACTION);
+  EXPECT_TRUE(entries[0].params);
   EXPECT_TRUE(entries[0].GetStringValue("push_url", &value));
   EXPECT_EQ(value, push_url_1);
+
+  ASSERT_EQ(entries[1].type,
+            net::NetLogEventType::SERVER_PUSH_LOOKUP_TRANSACTION);
+  EXPECT_EQ(entries[1].phase, net::NetLogEventPhase::BEGIN);
+  EXPECT_EQ(entries[1].source.type,
+            net::NetLogSourceType::SERVER_PUSH_LOOKUP_TRANSACTION);
+  EXPECT_TRUE(entries[1].params);
   EXPECT_TRUE(entries[1].GetStringValue("push_url", &value));
   EXPECT_EQ(value, push_url_2);
+
+  ASSERT_EQ(entries[2].type,
+            net::NetLogEventType::SERVER_PUSH_LOOKUP_TRANSACTION);
+  EXPECT_EQ(entries[2].phase, net::NetLogEventPhase::END);
+  EXPECT_EQ(entries[2].source.type,
+            net::NetLogSourceType::SERVER_PUSH_LOOKUP_TRANSACTION);
+  EXPECT_EQ(entries[2].source.id, entries[1].source.id);
+  EXPECT_TRUE(entries[2].params);
   // Net error code -400 is found for this lookup transaction, the push is not
   // found in the cache.
   EXPECT_TRUE(entries[2].GetIntegerValue("net_error", &net_error));
   EXPECT_EQ(net_error, -400);
+
+  ASSERT_EQ(entries[3].type,
+            net::NetLogEventType::SERVER_PUSH_LOOKUP_TRANSACTION);
+  EXPECT_EQ(entries[3].phase, net::NetLogEventPhase::END);
+  EXPECT_EQ(entries[3].source.type,
+            net::NetLogSourceType::SERVER_PUSH_LOOKUP_TRANSACTION);
+  EXPECT_EQ(entries[3].source.id, entries[0].source.id);
+  EXPECT_FALSE(entries[3].params);
   // No net error code for this lookup transaction, the push is found.
   EXPECT_FALSE(entries[3].GetIntegerValue("net_error", &net_error));
 
@@ -316,7 +345,7 @@
   EXPECT_LE(1u, GetRstErrorCountReceivedByServer(QUIC_STREAM_CANCELLED));
 }
 
-TEST_F(URLRequestQuicTest, CancelPushIfCached2) {
+TEST_F(URLRequestQuicTest, CancelPushIfCached_AllCached) {
   base::RunLoop run_loop;
   Init();
 
@@ -357,7 +386,7 @@
   EXPECT_TRUE(request_1->status().is_success());
 
   // Send a request to /index2.html which pushes /kitten-1.jpg and /favicon.ico.
-  // Should cancel push for /kitten-1.jpg.
+  // Should cancel push for both pushed resources, since they're already cached.
   CheckLoadTimingDelegate delegate(true);
   std::string url =
       base::StringPrintf("https://%s%s", kTestServerHost, "/index2.html");
@@ -387,15 +416,39 @@
   std::string push_url_2 =
       base::StringPrintf("https://%s%s", kTestServerHost, "/favicon.ico");
 
+  ASSERT_EQ(entries[0].type,
+            net::NetLogEventType::SERVER_PUSH_LOOKUP_TRANSACTION);
+  EXPECT_EQ(entries[0].phase, net::NetLogEventPhase::BEGIN);
+  EXPECT_EQ(entries[0].source.type,
+            net::NetLogSourceType::SERVER_PUSH_LOOKUP_TRANSACTION);
+  EXPECT_TRUE(entries[0].params);
   EXPECT_TRUE(entries[0].GetStringValue("push_url", &value));
   EXPECT_EQ(value, push_url_1);
 
+  ASSERT_EQ(entries[1].type,
+            net::NetLogEventType::SERVER_PUSH_LOOKUP_TRANSACTION);
+  EXPECT_EQ(entries[1].phase, net::NetLogEventPhase::BEGIN);
+  EXPECT_EQ(entries[1].source.type,
+            net::NetLogSourceType::SERVER_PUSH_LOOKUP_TRANSACTION);
+  EXPECT_TRUE(entries[1].params);
   EXPECT_TRUE(entries[1].GetStringValue("push_url", &value));
   EXPECT_EQ(value, push_url_2);
 
+  ASSERT_EQ(entries[2].type,
+            net::NetLogEventType::SERVER_PUSH_LOOKUP_TRANSACTION);
+  EXPECT_EQ(entries[2].phase, net::NetLogEventPhase::END);
+  EXPECT_EQ(entries[2].source.type,
+            net::NetLogSourceType::SERVER_PUSH_LOOKUP_TRANSACTION);
+  EXPECT_FALSE(entries[2].params);
   // No net error code for this lookup transaction, the push is found.
   EXPECT_FALSE(entries[2].GetIntegerValue("net_error", &net_error));
 
+  ASSERT_EQ(entries[3].type,
+            net::NetLogEventType::SERVER_PUSH_LOOKUP_TRANSACTION);
+  EXPECT_EQ(entries[3].phase, net::NetLogEventPhase::END);
+  EXPECT_EQ(entries[3].source.type,
+            net::NetLogSourceType::SERVER_PUSH_LOOKUP_TRANSACTION);
+  EXPECT_FALSE(entries[3].params);
   // No net error code for this lookup transaction, the push is found.
   EXPECT_FALSE(entries[3].GetIntegerValue("net_error", &net_error));
 
diff --git a/remoting/ios/app/remoting_theme.h b/remoting/ios/app/remoting_theme.h
index f21abd63..8f9c722 100644
--- a/remoting/ios/app/remoting_theme.h
+++ b/remoting/ios/app/remoting_theme.h
@@ -31,6 +31,7 @@
 @property(class, nonatomic, readonly) UIColor* hostWarningColor;
 @property(class, nonatomic, readonly) UIColor* menuBlueColor;
 @property(class, nonatomic, readonly) UIColor* menuTextColor;
+@property(class, nonatomic, readonly) UIColor* menuSeparatorColor;
 @property(class, nonatomic, readonly) UIColor* refreshIndicatorColor;
 @property(class, nonatomic, readonly) UIColor* pinEntryPairingColor;
 @property(class, nonatomic, readonly) UIColor* pinEntryPlaceholderColor;
diff --git a/remoting/ios/app/remoting_theme.mm b/remoting/ios/app/remoting_theme.mm
index 78a343e3..18e8a366 100644
--- a/remoting/ios/app/remoting_theme.mm
+++ b/remoting/ios/app/remoting_theme.mm
@@ -74,6 +74,15 @@
   return UIColor.whiteColor;
 }
 
++ (UIColor*)menuSeparatorColor {
+  static UIColor* color;
+  static dispatch_once_t onceToken;
+  dispatch_once(&onceToken, ^{
+    color = [UIColor colorWithWhite:1.f alpha:0.4f];
+  });
+  return color;
+}
+
 + (UIColor*)pinEntryPairingColor {
   return UIColor.whiteColor;
 }
diff --git a/remoting/ios/app/settings/remoting_settings_view_controller.mm b/remoting/ios/app/settings/remoting_settings_view_controller.mm
index f2627ea..cbee659 100644
--- a/remoting/ios/app/settings/remoting_settings_view_controller.mm
+++ b/remoting/ios/app/settings/remoting_settings_view_controller.mm
@@ -22,6 +22,8 @@
 static NSString* const kReusableIdentifierItem = @"remotingSettingsVCItem";
 static NSString* const kFeedbackContext = @"InSessionFeedbackContext";
 
+static const CGFloat kSectionSeparatorHeight = 1.f;
+
 @interface RemotingSettingsViewController () {
   MDCAppBar* _appBar;
   NSArray* _sections;
@@ -72,6 +74,13 @@
           forSupplementaryViewOfKind:UICollectionElementKindSectionHeader
                  withReuseIdentifier:UICollectionElementKindSectionHeader];
 
+  // A 1px height cell acting as the separator. Not being shown on the last
+  // section. See also:
+  // -collectionView:layout:referenceSizeForFooterInSection:
+  [self.collectionView registerClass:[UICollectionViewCell class]
+          forSupplementaryViewOfKind:UICollectionElementKindSectionFooter
+                 withReuseIdentifier:UICollectionElementKindSectionFooter];
+
   _sections = @[
     l10n_util::GetNSString(IDS_DISPLAY_OPTIONS),
     l10n_util::GetNSString(IDS_MOUSE_OPTIONS),
@@ -79,6 +88,7 @@
     l10n_util::GetNSString(IDS_SUPPORT_MENU),
   ];
   self.styler.cellStyle = MDCCollectionViewCellStyleCard;
+  self.styler.shouldHideSeparators = YES;
 }
 
 - (void)viewWillAppear:(BOOL)animated {
@@ -106,9 +116,6 @@
 - (UICollectionViewCell*)collectionView:(UICollectionView*)collectionView
                  cellForItemAtIndexPath:(NSIndexPath*)indexPath {
   SettingOption* setting = _content[indexPath.section][indexPath.item];
-  // TODO(nicholss): There is a bug in MDCCollectionViewTextCell, it has a
-  // wrapping UIView that leaves behind a one pixel edge. Filed a bug:
-  // https://github.com/material-components/material-components-ios/issues/1519
   MDCCollectionViewTextCell* cell = [collectionView
       dequeueReusableCellWithReuseIdentifier:kReusableIdentifierItem
                                 forIndexPath:indexPath];
@@ -198,18 +205,25 @@
 - (UICollectionReusableView*)collectionView:(UICollectionView*)collectionView
           viewForSupplementaryElementOfKind:(NSString*)kind
                                 atIndexPath:(NSIndexPath*)indexPath {
-  MDCCollectionViewTextCell* supplementaryView =
-      [collectionView dequeueReusableSupplementaryViewOfKind:kind
-                                         withReuseIdentifier:kind
-                                                forIndexPath:indexPath];
   if ([kind isEqualToString:UICollectionElementKindSectionHeader]) {
+    MDCCollectionViewTextCell* supplementaryView =
+        [collectionView dequeueReusableSupplementaryViewOfKind:kind
+                                           withReuseIdentifier:kind
+                                                  forIndexPath:indexPath];
     supplementaryView.contentView.backgroundColor = RemotingTheme.menuBlueColor;
     supplementaryView.textLabel.text = _sections[(NSUInteger)indexPath.section];
     supplementaryView.textLabel.textColor = RemotingTheme.menuTextColor;
     supplementaryView.isAccessibilityElement = YES;
     supplementaryView.accessibilityLabel = supplementaryView.textLabel.text;
+    return supplementaryView;
   }
-  return supplementaryView;
+  DCHECK([kind isEqualToString:UICollectionElementKindSectionFooter]);
+  UICollectionViewCell* view =
+      [collectionView dequeueReusableSupplementaryViewOfKind:kind
+                                         withReuseIdentifier:kind
+                                                forIndexPath:indexPath];
+  view.contentView.backgroundColor = RemotingTheme.menuSeparatorColor;
+  return view;
 }
 
 #pragma mark - <UICollectionViewDelegateFlowLayout>
@@ -222,6 +236,18 @@
                     MDCCellDefaultOneLineHeight);
 }
 
+- (CGSize)collectionView:(UICollectionView*)collectionView
+                             layout:
+                                 (UICollectionViewLayout*)collectionViewLayout
+    referenceSizeForFooterInSection:(NSInteger)section {
+  if (section == (NSInteger)(_sections.count - 1)) {
+    // No separator for last section. Note that the footer cell will not be
+    // created if 0 is returned.
+    return CGSizeZero;
+  }
+  return CGSizeMake(collectionView.bounds.size.width, kSectionSeparatorHeight);
+}
+
 #pragma mark - Private
 
 - (void)didTapClose:(id)button {
diff --git a/sandbox/linux/seccomp-bpf/sandbox_bpf.cc b/sandbox/linux/seccomp-bpf/sandbox_bpf.cc
index 9ff79d7..72a79670 100644
--- a/sandbox/linux/seccomp-bpf/sandbox_bpf.cc
+++ b/sandbox/linux/seccomp-bpf/sandbox_bpf.cc
@@ -15,8 +15,6 @@
 #include "base/logging.h"
 #include "base/macros.h"
 #include "base/posix/eintr_wrapper.h"
-#include "base/third_party/dynamic_annotations/dynamic_annotations.h"
-#include "base/third_party/valgrind/valgrind.h"
 #include "sandbox/linux/bpf_dsl/bpf_dsl.h"
 #include "sandbox/linux/bpf_dsl/codegen.h"
 #include "sandbox/linux/bpf_dsl/policy.h"
@@ -122,12 +120,6 @@
 
 // static
 bool SandboxBPF::SupportsSeccompSandbox(SeccompLevel level) {
-  // Never pretend to support seccomp with Valgrind, as it
-  // throws the tool off.
-  if (RunningOnValgrind()) {
-    return false;
-  }
-
   switch (level) {
     case SeccompLevel::SINGLE_THREADED:
       return KernelSupportsSeccompBPF();
diff --git a/sandbox/linux/seccomp-bpf/sandbox_bpf_test_runner.cc b/sandbox/linux/seccomp-bpf/sandbox_bpf_test_runner.cc
index 5f59cbb..36f3744 100644
--- a/sandbox/linux/seccomp-bpf/sandbox_bpf_test_runner.cc
+++ b/sandbox/linux/seccomp-bpf/sandbox_bpf_test_runner.cc
@@ -9,7 +9,6 @@
 #include <memory>
 
 #include "base/logging.h"
-#include "base/third_party/dynamic_annotations/dynamic_annotations.h"
 #include "sandbox/linux/bpf_dsl/policy.h"
 #include "sandbox/linux/seccomp-bpf/die.h"
 #include "sandbox/linux/seccomp-bpf/sandbox_bpf.h"
@@ -44,9 +43,9 @@
     bpf_tester_delegate_->RunTestFunction();
   } else {
     printf("This BPF test is not fully running in this configuration!\n");
-    // Android and Valgrind are the only configurations where we accept not
-    // having kernel BPF support.
-    if (!IsAndroid() && !RunningOnValgrind()) {
+    // Android is the only configuration where we accept not having kernel
+    // BPF support.
+    if (!IsAndroid()) {
       const bool seccomp_bpf_is_supported = false;
       SANDBOX_ASSERT(seccomp_bpf_is_supported);
     }
diff --git a/sandbox/linux/seccomp-bpf/sandbox_bpf_test_runner.h b/sandbox/linux/seccomp-bpf/sandbox_bpf_test_runner.h
index 1cf1c2f..4fc3c5d1 100644
--- a/sandbox/linux/seccomp-bpf/sandbox_bpf_test_runner.h
+++ b/sandbox/linux/seccomp-bpf/sandbox_bpf_test_runner.h
@@ -40,7 +40,7 @@
 // run a test function (via |bpf_tester_delegate|) if the current kernel
 // configuration allows it. If it can not run the test under seccomp-bpf,
 // Run() will still compile the policy which should allow to get some coverage
-// under tools such as Valgrind.
+// under tools that behave like Valgrind.
 class SandboxBPFTestRunner : public SandboxTestRunner {
  public:
   // This constructor takes ownership of the |bpf_tester_delegate| object.
diff --git a/sandbox/linux/seccomp-bpf/syscall.h b/sandbox/linux/seccomp-bpf/syscall.h
index ccfc88d..3b02a67 100644
--- a/sandbox/linux/seccomp-bpf/syscall.h
+++ b/sandbox/linux/seccomp-bpf/syscall.h
@@ -28,7 +28,7 @@
   // System calls can take up to six parameters (up to eight on some
   // architectures). Traditionally, glibc
   // implements this property by using variadic argument lists. This works, but
-  // confuses modern tools such as valgrind, because we are nominally passing
+  // confuses tools that behave like Valgrind, because we are nominally passing
   // uninitialized data whenever we call through this function and pass less
   // than the full six arguments.
   // So, instead, we use C++'s template system to achieve a very similar
diff --git a/sandbox/linux/services/credentials.cc b/sandbox/linux/services/credentials.cc
index d97f094..65b63ad 100644
--- a/sandbox/linux/services/credentials.cc
+++ b/sandbox/linux/services/credentials.cc
@@ -23,8 +23,6 @@
 #include "base/macros.h"
 #include "base/posix/eintr_wrapper.h"
 #include "base/process/launch.h"
-#include "base/third_party/dynamic_annotations/dynamic_annotations.h"
-#include "base/third_party/valgrind/valgrind.h"
 #include "build/build_config.h"
 #include "sandbox/linux/services/namespace_utils.h"
 #include "sandbox/linux/services/proc_util.h"
@@ -115,10 +113,10 @@
 void CheckCloneNewUserErrno(int error) {
   // EPERM can happen if already in a chroot. EUSERS if too many nested
   // namespaces are used. EINVAL for kernels that don't support the feature.
-  // Valgrind will ENOSYS unshare().  ENOSPC can occur when the system has
-  // reached its maximum configured number of user namespaces.
+  // ENOSPC can occur when the system has reached its maximum configured
+  // number of user namespaces.
   PCHECK(error == EPERM || error == EUSERS || error == EINVAL ||
-         error == ENOSYS || error == ENOSPC);
+         error == ENOSPC);
 }
 
 // Converts a Capability to the corresponding Linux CAP_XXX value.
@@ -256,12 +254,6 @@
 
 // static
 bool Credentials::CanCreateProcessInNewUserNS() {
-  // Valgrind will let clone(2) pass-through, but doesn't support unshare(),
-  // so always consider UserNS unsupported there.
-  if (RunningOnValgrind()) {
-    return false;
-  }
-
 #if defined(THREAD_SANITIZER)
   // With TSAN, processes will always have threads running and can never
   // enter a new user namespace with MoveToNewUserNS().
diff --git a/sandbox/linux/services/namespace_utils.cc b/sandbox/linux/services/namespace_utils.cc
index 83749adf..376b179 100644
--- a/sandbox/linux/services/namespace_utils.cc
+++ b/sandbox/linux/services/namespace_utils.cc
@@ -20,8 +20,6 @@
 #include "base/posix/eintr_wrapper.h"
 #include "base/process/launch.h"
 #include "base/strings/safe_sprintf.h"
-#include "base/third_party/dynamic_annotations/dynamic_annotations.h"
-#include "base/third_party/valgrind/valgrind.h"
 
 namespace sandbox {
 
@@ -52,12 +50,6 @@
 
 // static
 bool NamespaceUtils::KernelSupportsUnprivilegedNamespace(int type) {
-  // Valgrind will let clone(2) pass-through, but doesn't support unshare(),
-  // so always consider namespaces unsupported there.
-  if (RunningOnValgrind()) {
-    return false;
-  }
-
   // As of Linux 3.8, /proc/self/ns/* files exist for all namespace types. Since
   // user namespaces were added in 3.8, it is OK to rely on the existence of
   // /proc/self/ns/*.
diff --git a/sandbox/linux/services/syscall_wrappers.cc b/sandbox/linux/services/syscall_wrappers.cc
index 9c7727ce..fcfd2aa 100644
--- a/sandbox/linux/services/syscall_wrappers.cc
+++ b/sandbox/linux/services/syscall_wrappers.cc
@@ -16,7 +16,6 @@
 
 #include "base/compiler_specific.h"
 #include "base/logging.h"
-#include "base/third_party/valgrind/valgrind.h"
 #include "build/build_config.h"
 #include "sandbox/linux/system_headers/capability.h"
 #include "sandbox/linux/system_headers/linux_signal.h"
diff --git a/sandbox/linux/services/syscall_wrappers_unittest.cc b/sandbox/linux/services/syscall_wrappers_unittest.cc
index 34ac7409..b28e6381 100644
--- a/sandbox/linux/services/syscall_wrappers_unittest.cc
+++ b/sandbox/linux/services/syscall_wrappers_unittest.cc
@@ -13,7 +13,6 @@
 
 #include "base/logging.h"
 #include "base/posix/eintr_wrapper.h"
-#include "base/third_party/valgrind/valgrind.h"
 #include "build/build_config.h"
 #include "sandbox/linux/system_headers/linux_signal.h"
 #include "sandbox/linux/tests/test_utils.h"
diff --git a/sandbox/linux/services/thread_helpers_unittests.cc b/sandbox/linux/services/thread_helpers_unittests.cc
index 78e6d83..5e57459 100644
--- a/sandbox/linux/services/thread_helpers_unittests.cc
+++ b/sandbox/linux/services/thread_helpers_unittests.cc
@@ -14,7 +14,6 @@
 #include "base/macros.h"
 #include "base/posix/eintr_wrapper.h"
 #include "base/process/process_metrics.h"
-#include "base/third_party/dynamic_annotations/dynamic_annotations.h"
 #include "base/threading/platform_thread.h"
 #include "base/threading/thread.h"
 #include "build/build_config.h"
@@ -30,13 +29,7 @@
 // These tests fail under ThreadSanitizer, see http://crbug.com/342305
 #if !defined(THREAD_SANITIZER)
 
-int GetRaceTestIterations() {
-  if (RunningOnValgrind()) {
-    return 2;
-  } else {
-    return 1000;
-  }
-}
+const int kRaceTestIterations = 1000;
 
 class ScopedProc {
  public:
@@ -81,7 +74,7 @@
   ASSERT_TRUE(ThreadHelpers::IsSingleThreaded(proc_fd.fd()));
 
   // Iterate to check for race conditions.
-  for (int i = 0; i < GetRaceTestIterations(); ++i) {
+  for (int i = 0; i < kRaceTestIterations; ++i) {
     base::Thread thread("sandbox_tests");
     ASSERT_TRUE(
         ThreadHelpers::StartThreadAndWatchProcFS(proc_fd.fd(), &thread));
@@ -98,7 +91,7 @@
   base::Thread thread("sandbox_tests");
   // This is testing for a race condition, so iterate.
   // Manually, this has been tested with more that 1M iterations.
-  for (int i = 0; i < GetRaceTestIterations(); ++i) {
+  for (int i = 0; i < kRaceTestIterations; ++i) {
     ASSERT_TRUE(
         ThreadHelpers::StartThreadAndWatchProcFS(proc_fd.fd(), &thread));
     ASSERT_FALSE(ThreadHelpers::IsSingleThreaded(proc_fd.fd()));
@@ -116,7 +109,7 @@
   base::Thread thread1("sandbox_tests");
   base::Thread thread2("sandbox_tests");
 
-  for (int i = 0; i < GetRaceTestIterations(); ++i) {
+  for (int i = 0; i < kRaceTestIterations; ++i) {
     SANDBOX_ASSERT(
         ThreadHelpers::StartThreadAndWatchProcFS(proc_fd.fd(), &thread1));
     SANDBOX_ASSERT(
diff --git a/sandbox/linux/syscall_broker/broker_host.cc b/sandbox/linux/syscall_broker/broker_host.cc
index 68a5260..7d2a7ca 100644
--- a/sandbox/linux/syscall_broker/broker_host.cc
+++ b/sandbox/linux/syscall_broker/broker_host.cc
@@ -23,8 +23,6 @@
 #include "base/pickle.h"
 #include "base/posix/eintr_wrapper.h"
 #include "base/posix/unix_domain_socket.h"
-#include "base/third_party/dynamic_annotations/dynamic_annotations.h"
-#include "base/third_party/valgrind/valgrind.h"
 #include "sandbox/linux/syscall_broker/broker_common.h"
 #include "sandbox/linux/syscall_broker/broker_policy.h"
 #include "sandbox/linux/system_headers/linux_syscalls.h"
@@ -41,10 +39,6 @@
 int sys_open(const char* pathname, int flags) {
   // Hardcode mode to rw------- when creating files.
   int mode = (flags & O_CREAT) ? 0600 : 0;
-  if (RunningOnValgrind()) {
-    // Valgrind does not support AT_FDCWD, just use libc's open() in this case.
-    return open(pathname, flags, mode);
-  }
   return syscall(__NR_openat, AT_FDCWD, pathname, flags, mode);
 }
 
diff --git a/sandbox/linux/syscall_broker/broker_process_unittest.cc b/sandbox/linux/syscall_broker/broker_process_unittest.cc
index ff7ff2b..e17aba3f 100644
--- a/sandbox/linux/syscall_broker/broker_process_unittest.cc
+++ b/sandbox/linux/syscall_broker/broker_process_unittest.cc
@@ -525,8 +525,6 @@
       *std::max_element(available_fds,
                         available_fds + arraysize(available_fds));
 
-  // Valgrind doesn't allow changing the hard descriptor limit, so we only
-  // change the soft descriptor limit here.
   struct rlimit rlim;
   SANDBOX_ASSERT(0 == getrlimit(RLIMIT_NOFILE, &rlim));
   SANDBOX_ASSERT(fd_limit <= rlim.rlim_cur);
diff --git a/sandbox/linux/tests/unit_tests.cc b/sandbox/linux/tests/unit_tests.cc
index 6df7730..1b28aa2 100644
--- a/sandbox/linux/tests/unit_tests.cc
+++ b/sandbox/linux/tests/unit_tests.cc
@@ -17,8 +17,6 @@
 #include "base/debug/leak_annotations.h"
 #include "base/files/file_util.h"
 #include "base/posix/eintr_wrapper.h"
-#include "base/third_party/dynamic_annotations/dynamic_annotations.h"
-#include "base/third_party/valgrind/valgrind.h"
 #include "build/build_config.h"
 #include "sandbox/linux/tests/unit_tests.h"
 
@@ -179,13 +177,9 @@
     SANDBOX_ASSERT(!close(fds[0]));
     SANDBOX_ASSERT(!close(fds[1]));
 
-    // Don't set a timeout if running on Valgrind, since it's generally much
-    // slower.
-    if (!RunningOnValgrind()) {
 #if !defined(OS_NACL_NONSFI)
-      SetProcessTimeout(GetSubProcessTimeoutTimeInSeconds());
+    SetProcessTimeout(GetSubProcessTimeoutTimeInSeconds());
 #endif
-    }
 
     // Disable core files. They are not very useful for our individual test
     // cases.
diff --git a/testing/buildbot/filters/mojo.fyi.network_browser_tests.filter b/testing/buildbot/filters/mojo.fyi.network_browser_tests.filter
index bdaae62f0..15e418d 100644
--- a/testing/buildbot/filters/mojo.fyi.network_browser_tests.filter
+++ b/testing/buildbot/filters/mojo.fyi.network_browser_tests.filter
@@ -130,9 +130,6 @@
 -NewlibPackagedAppTest.NoSocketPermissions
 -NewlibPackagedAppTest.SocketPermissions
 -NewlibPackagedAppTest.SuccessfulLoad
--OutOfProcessPPAPITest.FileRef1
--OutOfProcessPPAPITest.FileRef2
--OutOfProcessPPAPITest.URLLoader1
 -OutOfProcessProxyResolverBrowserTest.Verify
 -PageInfoBubbleViewBrowserTest.SiteSettingsLinkWithNonDefaultPort
 -PageInfoBubbleViewBrowserTest.SiteSettingsLinkWithSiteDetailsEnabledAndNonDefaultPort
@@ -153,13 +150,6 @@
 -PolicyTest.BookmarkBarEnabled
 -PolicyTest.DefaultCookiesSetting
 -PolicyTest.HomepageLocation
--PPAPINaClNewlibTest.FileRef1
--PPAPINaClNewlibTest.FileRef2
--PPAPINaClNewlibTest.URLLoader1
-# Note: the next 3 tests pass locally but fail on bot.
--PPAPINaClPNaClNonSfiTest.FileRef1
--PPAPINaClPNaClNonSfiTest.FileRef2
--PPAPINaClPNaClNonSfiTest.URLLoader1
 -PrefetchBrowserTestPredictionDisabled.ExperimentDisabled
 -PreviewsOptimizationGuideBrowserTest.NoScriptPreviewsEnabledByWhitelist
 -ProcessManagementTest.ProcessOverflow
@@ -900,3 +890,16 @@
 # TODO(jam): switch the tests to hook in via URLLoaderFactory to check load flags.
 -NoStatePrefetchBrowserTest/NoStatePrefetchBrowserTest.IssuesIdlePriorityRequests/0
 -NoStatePrefetchBrowserTest/NoStatePrefetchBrowserTest.IssuesIdlePriorityRequests/1
+
+# Add support of download_to_file for URLLoader.
+# http://crbug.com/791702
+-OutOfProcessPPAPITest.FileRef1
+-OutOfProcessPPAPITest.FileRef2
+-OutOfProcessPPAPITest.URLLoader1
+-PPAPINaClNewlibTest.FileRef1
+-PPAPINaClNewlibTest.FileRef2
+-PPAPINaClNewlibTest.URLLoader1
+# Note: the next 3 tests pass locally but fail on bot.
+-PPAPINaClPNaClNonSfiTest.FileRef1
+-PPAPINaClPNaClNonSfiTest.FileRef2
+-PPAPINaClPNaClNonSfiTest.URLLoader1
diff --git a/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST.json b/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST.json
index e818a19b..4fe65ae 100644
--- a/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST.json
+++ b/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST.json
@@ -5277,6 +5277,18 @@
      {}
     ]
    ],
+   "FileAPI/url/url_xmlhttprequest_img.html": [
+    [
+     "/FileAPI/url/url_xmlhttprequest_img.html",
+     [
+      [
+       "/FileAPI/url/url_xmlhttprequest_img-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
    "acid/acid2/reftest.html": [
     [
      "/acid/acid2/reftest.html",
@@ -42509,30 +42521,6 @@
      {}
     ]
    ],
-   "css/css-multicol/multicol-count-computed-001.xht": [
-    [
-     "/css/css-multicol/multicol-count-computed-001.xht",
-     [
-      [
-       "/css/css-multicol/multicol-count-computed-ref.xht",
-       "=="
-      ]
-     ],
-     {}
-    ]
-   ],
-   "css/css-multicol/multicol-count-computed-002.xht": [
-    [
-     "/css/css-multicol/multicol-count-computed-002.xht",
-     [
-      [
-       "/css/css-multicol/multicol-count-computed-2-ref.xht",
-       "=="
-      ]
-     ],
-     {}
-    ]
-   ],
    "css/css-multicol/multicol-count-computed-003.xht": [
     [
      "/css/css-multicol/multicol-count-computed-003.xht",
@@ -109060,16 +109048,6 @@
      {}
     ]
    ],
-   "css/css-multicol/multicol-count-computed-2-ref.xht": [
-    [
-     {}
-    ]
-   ],
-   "css/css-multicol/multicol-count-computed-ref.xht": [
-    [
-     {}
-    ]
-   ],
    "css/css-multicol/multicol-count-large-2-ref.xht": [
     [
      {}
@@ -110710,6 +110688,116 @@
      {}
     ]
    ],
+   "css/css-syntax/OWNERS": [
+    [
+     {}
+    ]
+   ],
+   "css/css-syntax/charset/MANIFEST": [
+    [
+     {}
+    ]
+   ],
+   "css/css-syntax/charset/page-windows-1251-charset-attribute-bogus-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "css/css-syntax/charset/support/MANIFEST": [
+    [
+     {}
+    ]
+   ],
+   "css/css-syntax/charset/support/at-charset-bogus.css": [
+    [
+     {}
+    ]
+   ],
+   "css/css-syntax/charset/support/at-charset-utf16-ascii-only.css": [
+    [
+     {}
+    ]
+   ],
+   "css/css-syntax/charset/support/at-charset-utf16.css": [
+    [
+     {}
+    ]
+   ],
+   "css/css-syntax/charset/support/at-charset-utf16be.css": [
+    [
+     {}
+    ]
+   ],
+   "css/css-syntax/charset/support/at-charset-windows-1250-in-utf16.css": [
+    [
+     {}
+    ]
+   ],
+   "css/css-syntax/charset/support/at-charset-windows-1250-in-utf16be.css": [
+    [
+     {}
+    ]
+   ],
+   "css/css-syntax/charset/support/at-charset-windows-1250.css": [
+    [
+     {}
+    ]
+   ],
+   "css/css-syntax/charset/support/bomless-utf16.css": [
+    [
+     {}
+    ]
+   ],
+   "css/css-syntax/charset/support/bomless-utf16be.css": [
+    [
+     {}
+    ]
+   ],
+   "css/css-syntax/charset/support/http-bogus-at-charset-windows-1250.bogus.css": [
+    [
+     {}
+    ]
+   ],
+   "css/css-syntax/charset/support/http-bogus-at-charset-windows-1250.bogus.css.headers": [
+    [
+     {}
+    ]
+   ],
+   "css/css-syntax/charset/support/http-bogus.bogus.css": [
+    [
+     {}
+    ]
+   ],
+   "css/css-syntax/charset/support/http-bogus.bogus.css.headers": [
+    [
+     {}
+    ]
+   ],
+   "css/css-syntax/charset/support/http-windows-1250-at-charset-windows-1253.windows1250.css": [
+    [
+     {}
+    ]
+   ],
+   "css/css-syntax/charset/support/http-windows-1250-at-charset-windows-1253.windows1250.css.headers": [
+    [
+     {}
+    ]
+   ],
+   "css/css-syntax/charset/support/no-decl-ascii-only.css": [
+    [
+     {}
+    ]
+   ],
+   "css/css-syntax/charset/support/no-decl.css": [
+    [
+     {}
+    ]
+   ],
+   "css/css-syntax/charset/support/utf8-bom.css": [
+    [
+     {}
+    ]
+   ],
    "css/css-tables/OWNERS": [
     [
      {}
@@ -163976,6 +164064,12 @@
      }
     ]
    ],
+   "cookies/meta-blocked.html": [
+    [
+     "/cookies/meta-blocked.html",
+     {}
+    ]
+   ],
    "cookies/path/match.html": [
     [
      "/cookies/path/match.html",
@@ -166738,6 +166832,126 @@
      {}
     ]
    ],
+   "css/css-syntax/charset/page-utf16-css-bomless-utf16.html": [
+    [
+     "/css/css-syntax/charset/page-utf16-css-bomless-utf16.html",
+     {}
+    ]
+   ],
+   "css/css-syntax/charset/page-utf16-css-bomless-utf16be.html": [
+    [
+     "/css/css-syntax/charset/page-utf16-css-bomless-utf16be.html",
+     {}
+    ]
+   ],
+   "css/css-syntax/charset/page-utf16-css-no-decl-ascii-only.html": [
+    [
+     "/css/css-syntax/charset/page-utf16-css-no-decl-ascii-only.html",
+     {}
+    ]
+   ],
+   "css/css-syntax/charset/page-utf16-css-no-decl.html": [
+    [
+     "/css/css-syntax/charset/page-utf16-css-no-decl.html",
+     {}
+    ]
+   ],
+   "css/css-syntax/charset/page-windows-1251-charset-attribute-bogus.html": [
+    [
+     "/css/css-syntax/charset/page-windows-1251-charset-attribute-bogus.html",
+     {}
+    ]
+   ],
+   "css/css-syntax/charset/page-windows-1251-css-at-charset-1250-charset-attribute-windows-1253.html": [
+    [
+     "/css/css-syntax/charset/page-windows-1251-css-at-charset-1250-charset-attribute-windows-1253.html",
+     {}
+    ]
+   ],
+   "css/css-syntax/charset/page-windows-1251-css-at-charset-bogus-charset-attribute-windows-1250.html": [
+    [
+     "/css/css-syntax/charset/page-windows-1251-css-at-charset-bogus-charset-attribute-windows-1250.html",
+     {}
+    ]
+   ],
+   "css/css-syntax/charset/page-windows-1251-css-at-charset-bogus.html": [
+    [
+     "/css/css-syntax/charset/page-windows-1251-css-at-charset-bogus.html",
+     {}
+    ]
+   ],
+   "css/css-syntax/charset/page-windows-1251-css-at-charset-utf16-ascii-only.html": [
+    [
+     "/css/css-syntax/charset/page-windows-1251-css-at-charset-utf16-ascii-only.html",
+     {}
+    ]
+   ],
+   "css/css-syntax/charset/page-windows-1251-css-at-charset-utf16.html": [
+    [
+     "/css/css-syntax/charset/page-windows-1251-css-at-charset-utf16.html",
+     {}
+    ]
+   ],
+   "css/css-syntax/charset/page-windows-1251-css-at-charset-utf16be.html": [
+    [
+     "/css/css-syntax/charset/page-windows-1251-css-at-charset-utf16be.html",
+     {}
+    ]
+   ],
+   "css/css-syntax/charset/page-windows-1251-css-at-charset-windows-1250-in-utf16.html": [
+    [
+     "/css/css-syntax/charset/page-windows-1251-css-at-charset-windows-1250-in-utf16.html",
+     {}
+    ]
+   ],
+   "css/css-syntax/charset/page-windows-1251-css-at-charset-windows-1250-in-utf16be.html": [
+    [
+     "/css/css-syntax/charset/page-windows-1251-css-at-charset-windows-1250-in-utf16be.html",
+     {}
+    ]
+   ],
+   "css/css-syntax/charset/page-windows-1251-css-http-bogus-at-charset-windows-1250.html": [
+    [
+     "/css/css-syntax/charset/page-windows-1251-css-http-bogus-at-charset-windows-1250.html",
+     {}
+    ]
+   ],
+   "css/css-syntax/charset/page-windows-1251-css-http-bogus.html": [
+    [
+     "/css/css-syntax/charset/page-windows-1251-css-http-bogus.html",
+     {}
+    ]
+   ],
+   "css/css-syntax/charset/page-windows-1251-css-http-windows-1250-at-charset-windows-1253.html": [
+    [
+     "/css/css-syntax/charset/page-windows-1251-css-http-windows-1250-at-charset-windows-1253.html",
+     {}
+    ]
+   ],
+   "css/css-syntax/charset/page-windows-1251-css-no-decl.html": [
+    [
+     "/css/css-syntax/charset/page-windows-1251-css-no-decl.html",
+     {}
+    ]
+   ],
+   "css/css-syntax/charset/page-windows-1251-css-utf8-bom.html": [
+    [
+     "/css/css-syntax/charset/page-windows-1251-css-utf8-bom.html",
+     {}
+    ]
+   ],
+   "css/css-syntax/charset/xml-stylesheet-page-windows-1251-charset-attribute-windows-1250.xhtml": [
+    [
+     "/css/css-syntax/charset/xml-stylesheet-page-windows-1251-charset-attribute-windows-1250.xhtml",
+     {}
+    ]
+   ],
+   "css/css-syntax/ident-three-code-points.html": [
+    [
+     "/css/css-syntax/ident-three-code-points.html",
+     {}
+    ]
+   ],
    "css/css-tables/bounding-box-computation-1.html": [
     [
      "/css/css-tables/bounding-box-computation-1.html",
@@ -227031,6 +227245,10 @@
    "3003064bfdf750dc93d84cd4333fd5df6a125320",
    "support"
   ],
+  "FileAPI/url/url_xmlhttprequest_img.html": [
+   "33c65ffbbe2ab33fa1d5ce946d0be536dd7d0a69",
+   "reftest"
+  ],
   "IndexedDB/OWNERS": [
    "625de99f3cd80a20a21a12e48aab4f48608ee0cb",
    "support"
@@ -233887,6 +234105,10 @@
    "1949878db1be4093ec8d9595710f9fd8887434ba",
    "support"
   ],
+  "cookies/meta-blocked.html": [
+   "1ece2f38a340ff4ff4713ada5568281d0e1c5be2",
+   "testharness"
+  ],
   "cookies/path/echo-cookie.html": [
    "cbb91823a75f6e5c5ae435c5bc4c3b15a09c483e",
    "support"
@@ -264803,14 +265025,6 @@
    "6703b66b9696faa2d9efb86c93a5127952d52484",
    "reftest"
   ],
-  "css/css-multicol/multicol-count-computed-001.xht": [
-   "0b899eed278c7427523cdabd0b4f73d1f70f4c8a",
-   "reftest"
-  ],
-  "css/css-multicol/multicol-count-computed-002.xht": [
-   "76581613fb9ec4c0cf786361cb9f5b3d2977537b",
-   "reftest"
-  ],
   "css/css-multicol/multicol-count-computed-003-ref.xht": [
    "80e54fbeedd11f39d9041d45d266cf87a69d28b1",
    "support"
@@ -264831,14 +265045,6 @@
    "fdc0811616680d44203af48c16fcbd91f5e2d9ea",
    "reftest"
   ],
-  "css/css-multicol/multicol-count-computed-2-ref.xht": [
-   "c56592171fc03c060391ed79cdc07504e3331110",
-   "support"
-  ],
-  "css/css-multicol/multicol-count-computed-ref.xht": [
-   "6709a84fd18a48dfb086fc16f9c5c88e428ba19d",
-   "support"
-  ],
   "css/css-multicol/multicol-count-large-001.xht": [
    "c2a6c85790cc1bb26a55ac35ce7c180540bcf303",
    "reftest"
@@ -268055,6 +268261,174 @@
    "5bb192165bcb7d9a619d86dbff61831fc8de71cb",
    "support"
   ],
+  "css/css-syntax/OWNERS": [
+   "495f99b874611fd8f82f2e33bc4b7d930cc60fde",
+   "support"
+  ],
+  "css/css-syntax/charset/MANIFEST": [
+   "d77d6bd640f8c586ad2e82d2a527c368fbfc7be5",
+   "support"
+  ],
+  "css/css-syntax/charset/page-utf16-css-bomless-utf16.html": [
+   "71e0fbbf27aa36242db447dca103db0ea5d710ef",
+   "testharness"
+  ],
+  "css/css-syntax/charset/page-utf16-css-bomless-utf16be.html": [
+   "2bd93f230a222a761c1a350acede04956ee94bc1",
+   "testharness"
+  ],
+  "css/css-syntax/charset/page-utf16-css-no-decl-ascii-only.html": [
+   "9f29dbb08c5cb8f228e3aa49bac45d48f3e319d7",
+   "testharness"
+  ],
+  "css/css-syntax/charset/page-utf16-css-no-decl.html": [
+   "e6fd148365fcf41aa162b7de5e0f3af4eb8e7df9",
+   "testharness"
+  ],
+  "css/css-syntax/charset/page-windows-1251-charset-attribute-bogus-expected.txt": [
+   "6924d5356c7e1d498d1642194cc2db97d33cf9b4",
+   "support"
+  ],
+  "css/css-syntax/charset/page-windows-1251-charset-attribute-bogus.html": [
+   "f91ac261b40d32103b75032aaaed95f8c0617374",
+   "testharness"
+  ],
+  "css/css-syntax/charset/page-windows-1251-css-at-charset-1250-charset-attribute-windows-1253.html": [
+   "9b9ab5a691be7964bff5b081d3bd01133f588e98",
+   "testharness"
+  ],
+  "css/css-syntax/charset/page-windows-1251-css-at-charset-bogus-charset-attribute-windows-1250.html": [
+   "5f70e5b166ebd2f8626007e55aa651192674b641",
+   "testharness"
+  ],
+  "css/css-syntax/charset/page-windows-1251-css-at-charset-bogus.html": [
+   "b927d2630dceb67aa9692ecfb22b37f399705d28",
+   "testharness"
+  ],
+  "css/css-syntax/charset/page-windows-1251-css-at-charset-utf16-ascii-only.html": [
+   "5efe33ccb01d04b029b297dd95b0c2eb084a70c4",
+   "testharness"
+  ],
+  "css/css-syntax/charset/page-windows-1251-css-at-charset-utf16.html": [
+   "d149bf8baa5e763541f5d8cf1c0ce86c91be2fa8",
+   "testharness"
+  ],
+  "css/css-syntax/charset/page-windows-1251-css-at-charset-utf16be.html": [
+   "1f8b097c3e2cfa8c94fcb14376c2856af69bddc6",
+   "testharness"
+  ],
+  "css/css-syntax/charset/page-windows-1251-css-at-charset-windows-1250-in-utf16.html": [
+   "59d4d455344f9b29428f82031451d072fa0f449e",
+   "testharness"
+  ],
+  "css/css-syntax/charset/page-windows-1251-css-at-charset-windows-1250-in-utf16be.html": [
+   "3be9a938865c20a707ee3ada8b00e6ca8acbc804",
+   "testharness"
+  ],
+  "css/css-syntax/charset/page-windows-1251-css-http-bogus-at-charset-windows-1250.html": [
+   "4d16e1c31928f71e5e7dfa77351c9c029b876611",
+   "testharness"
+  ],
+  "css/css-syntax/charset/page-windows-1251-css-http-bogus.html": [
+   "c6bfbcef66dca5a7f04e2667368e43d62ada6f25",
+   "testharness"
+  ],
+  "css/css-syntax/charset/page-windows-1251-css-http-windows-1250-at-charset-windows-1253.html": [
+   "bb795995f4ca4a703737eb23403c10b2d24fbe6e",
+   "testharness"
+  ],
+  "css/css-syntax/charset/page-windows-1251-css-no-decl.html": [
+   "6335315279817cd27d315bc9489cdd33e518363b",
+   "testharness"
+  ],
+  "css/css-syntax/charset/page-windows-1251-css-utf8-bom.html": [
+   "0f5342eb0c5624773636a6cdff27b3bf43162e44",
+   "testharness"
+  ],
+  "css/css-syntax/charset/support/MANIFEST": [
+   "adfd5e61bd3ec75ecdb5e3aeeef3be7fe3e6e94d",
+   "support"
+  ],
+  "css/css-syntax/charset/support/at-charset-bogus.css": [
+   "ae24bd8577db59e32b423a973d3b55028a6b60a2",
+   "support"
+  ],
+  "css/css-syntax/charset/support/at-charset-utf16-ascii-only.css": [
+   "6cccd39376b0b7569c83c2fb6900ae0edee022e9",
+   "support"
+  ],
+  "css/css-syntax/charset/support/at-charset-utf16.css": [
+   "c85b98e0fc46ccceecdab1d4023a7ca3fe73e320",
+   "support"
+  ],
+  "css/css-syntax/charset/support/at-charset-utf16be.css": [
+   "45d04f18dcb0a463578e3dc6a516c376e040a3d7",
+   "support"
+  ],
+  "css/css-syntax/charset/support/at-charset-windows-1250-in-utf16.css": [
+   "98c63a9973f670a802df0aba7940edc9642d878e",
+   "support"
+  ],
+  "css/css-syntax/charset/support/at-charset-windows-1250-in-utf16be.css": [
+   "55cf587d0907b6b5d62ed76827165f8bf0a916e8",
+   "support"
+  ],
+  "css/css-syntax/charset/support/at-charset-windows-1250.css": [
+   "0aee1dbedd53e2797108b0863524815b1c519448",
+   "support"
+  ],
+  "css/css-syntax/charset/support/bomless-utf16.css": [
+   "1ee6c1ccd46740b77c18fa1c86c82724d9b11258",
+   "support"
+  ],
+  "css/css-syntax/charset/support/bomless-utf16be.css": [
+   "8e5e4cc4818408cac8770a3215adfa73deb905ee",
+   "support"
+  ],
+  "css/css-syntax/charset/support/http-bogus-at-charset-windows-1250.bogus.css": [
+   "0aee1dbedd53e2797108b0863524815b1c519448",
+   "support"
+  ],
+  "css/css-syntax/charset/support/http-bogus-at-charset-windows-1250.bogus.css.headers": [
+   "7a1fb90f753b36ac12724c04f9e6c8fafd12926a",
+   "support"
+  ],
+  "css/css-syntax/charset/support/http-bogus.bogus.css": [
+   "b66e99da86e8c2f3b445dd1571583a6ca8eb0c44",
+   "support"
+  ],
+  "css/css-syntax/charset/support/http-bogus.bogus.css.headers": [
+   "7a1fb90f753b36ac12724c04f9e6c8fafd12926a",
+   "support"
+  ],
+  "css/css-syntax/charset/support/http-windows-1250-at-charset-windows-1253.windows1250.css": [
+   "7508ebde599e1e2cc97ce134a9426c2960fff7a8",
+   "support"
+  ],
+  "css/css-syntax/charset/support/http-windows-1250-at-charset-windows-1253.windows1250.css.headers": [
+   "cc35f80c1538e56deb8bdd0465b9e7be6562ea6e",
+   "support"
+  ],
+  "css/css-syntax/charset/support/no-decl-ascii-only.css": [
+   "83fb3f71f2b2e633c60c4296761fbb555ac6ee1a",
+   "support"
+  ],
+  "css/css-syntax/charset/support/no-decl.css": [
+   "b66e99da86e8c2f3b445dd1571583a6ca8eb0c44",
+   "support"
+  ],
+  "css/css-syntax/charset/support/utf8-bom.css": [
+   "8e639df06cc88c8b36f4f62d58a5a5f019eb7e4b",
+   "support"
+  ],
+  "css/css-syntax/charset/xml-stylesheet-page-windows-1251-charset-attribute-windows-1250.xhtml": [
+   "abadfe4da5dc6adc4e40700e84674ec84fc6d744",
+   "testharness"
+  ],
+  "css/css-syntax/ident-three-code-points.html": [
+   "7ce37259edc09da4e36f40c026ac76f33d829720",
+   "testharness"
+  ],
   "css/css-tables/OWNERS": [
    "2b1ea903cb673cb3de2a105e04b25f49b14edb4a",
    "support"
@@ -318960,11 +319334,11 @@
    "testharness"
   ],
   "mediacapture-streams/MediaStreamTrack-MediaElement-disabled-video-is-black.https-expected.txt": [
-   "9991fcb8d0ab935449cc3075a448c2c9b7b9a75b",
+   "4034d28ea06d606101c2f0be58bcc312075da025",
    "support"
   ],
   "mediacapture-streams/MediaStreamTrack-MediaElement-disabled-video-is-black.https.html": [
-   "9f8b4811f67bd0c9ed67327e9589db68432e3117",
+   "e3358344a76f874b68bdba743f113caa3b61ec88",
    "testharness"
   ],
   "mediacapture-streams/MediaStreamTrack-end-manual.https.html": [
diff --git a/third_party/WebKit/LayoutTests/external/wpt/FileAPI/url/url_xmlhttprequest_img.html b/third_party/WebKit/LayoutTests/external/wpt/FileAPI/url/url_xmlhttprequest_img.html
new file mode 100644
index 0000000..468dcb0
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/FileAPI/url/url_xmlhttprequest_img.html
@@ -0,0 +1,27 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<meta charset="utf-8">
+<title>FileAPI Test: Creating Blob URL via XMLHttpRequest as image source</title>
+<link rel="author" title="Intel" href="http://www.intel.com">
+<link rel="author" title="JunChen Xia" href="mailto:xjconlyme@gmail.com">
+<link rel="match" href="url_xmlhttprequest_img-ref.html">
+
+<p>Test passes if there is a filled blue square.</p>
+
+<p>
+  <img id="fileDisplay">
+</p>
+
+<script src="/common/reftest-wait.js"></script>
+<script>
+  var http = new XMLHttpRequest();
+  http.open("GET", "/images/blue96x96.png", true);
+  http.responseType = "blob";
+  http.onloadend = function() {
+    var fileDisplay = document.querySelector("#fileDisplay");
+    fileDisplay.src = window.URL.createObjectURL(http.response);
+    fileDisplay.onload = takeScreenshot;
+  };
+  http.send();
+</script>
+</html>
diff --git a/third_party/WebKit/Source/core/clipboard/DataObject.cpp b/third_party/WebKit/Source/core/clipboard/DataObject.cpp
index e608946..33fd7f5 100644
--- a/third_party/WebKit/Source/core/clipboard/DataObject.cpp
+++ b/third_party/WebKit/Source/core/clipboard/DataObject.cpp
@@ -46,7 +46,7 @@
 #if DCHECK_IS_ON()
   HashSet<String> types_seen;
 #endif
-  WebClipboard::Buffer buffer = Pasteboard::GeneralPasteboard()->GetBuffer();
+  mojom::ClipboardBuffer buffer = Pasteboard::GeneralPasteboard()->GetBuffer();
   uint64_t sequence_number =
       Platform::Current()->Clipboard()->SequenceNumber(buffer);
   bool ignored;
diff --git a/third_party/WebKit/Source/core/clipboard/DataObjectItem.cpp b/third_party/WebKit/Source/core/clipboard/DataObjectItem.cpp
index b03f204..2c988d8 100644
--- a/third_party/WebKit/Source/core/clipboard/DataObjectItem.cpp
+++ b/third_party/WebKit/Source/core/clipboard/DataObjectItem.cpp
@@ -128,7 +128,7 @@
   DCHECK_EQ(source_, kPasteboardSource);
   if (GetType() == kMimeTypeImagePng) {
     WebBlobInfo blob_info = Platform::Current()->Clipboard()->ReadImage(
-        WebClipboard::kBufferStandard);
+        mojom::ClipboardBuffer::kStandard);
     if (blob_info.size() < 0)
       return nullptr;
     return File::Create(
@@ -148,7 +148,7 @@
 
   DCHECK_EQ(source_, kPasteboardSource);
 
-  WebClipboard::Buffer buffer = Pasteboard::GeneralPasteboard()->GetBuffer();
+  mojom::ClipboardBuffer buffer = Pasteboard::GeneralPasteboard()->GetBuffer();
   String data;
   // This is ugly but there's no real alternative.
   if (type_ == kMimeTypeTextPlain) {
diff --git a/third_party/WebKit/Source/core/clipboard/Pasteboard.cpp b/third_party/WebKit/Source/core/clipboard/Pasteboard.cpp
index bbbfaa5..041af5b 100644
--- a/third_party/WebKit/Source/core/clipboard/Pasteboard.cpp
+++ b/third_party/WebKit/Source/core/clipboard/Pasteboard.cpp
@@ -48,15 +48,15 @@
   return pasteboard;
 }
 
-Pasteboard::Pasteboard() : buffer_(WebClipboard::kBufferStandard) {}
+Pasteboard::Pasteboard() : buffer_(mojom::ClipboardBuffer::kStandard) {}
 
 bool Pasteboard::IsSelectionMode() const {
-  return buffer_ == WebClipboard::kBufferSelection;
+  return buffer_ == mojom::ClipboardBuffer::kSelection;
 }
 
 void Pasteboard::SetSelectionMode(bool selection_mode) {
-  buffer_ = selection_mode ? WebClipboard::kBufferSelection
-                           : WebClipboard::kBufferStandard;
+  buffer_ = selection_mode ? mojom::ClipboardBuffer::kSelection
+                           : mojom::ClipboardBuffer::kStandard;
 }
 
 void Pasteboard::WritePlainText(const String& text, SmartReplaceOption) {
@@ -90,12 +90,12 @@
 
 bool Pasteboard::CanSmartReplace() {
   return Platform::Current()->Clipboard()->IsFormatAvailable(
-      WebClipboard::kFormatSmartPaste, buffer_);
+      mojom::ClipboardFormat::kSmartPaste, buffer_);
 }
 
 bool Pasteboard::IsHTMLAvailable() {
   return Platform::Current()->Clipboard()->IsFormatAvailable(
-      WebClipboard::kFormatHTML, buffer_);
+      mojom::ClipboardFormat::kHtml, buffer_);
 }
 
 String Pasteboard::PlainText() {
diff --git a/third_party/WebKit/Source/core/clipboard/Pasteboard.h b/third_party/WebKit/Source/core/clipboard/Pasteboard.h
index 0336c6f..b606f432 100644
--- a/third_party/WebKit/Source/core/clipboard/Pasteboard.h
+++ b/third_party/WebKit/Source/core/clipboard/Pasteboard.h
@@ -70,12 +70,12 @@
   bool IsSelectionMode() const;
   void SetSelectionMode(bool);
 
-  WebClipboard::Buffer GetBuffer() const { return buffer_; }
+  mojom::ClipboardBuffer GetBuffer() const { return buffer_; }
 
  private:
   Pasteboard();
 
-  WebClipboard::Buffer buffer_;
+  mojom::ClipboardBuffer buffer_;
 };
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/css/ComputedStyleCSSValueMapping.cpp b/third_party/WebKit/Source/core/css/ComputedStyleCSSValueMapping.cpp
index 8a143df..2cd78225 100644
--- a/third_party/WebKit/Source/core/css/ComputedStyleCSSValueMapping.cpp
+++ b/third_party/WebKit/Source/core/css/ComputedStyleCSSValueMapping.cpp
@@ -189,27 +189,28 @@
 static CSSValue* ValueForPositionOffset(const ComputedStyle& style,
                                         const CSSProperty& property,
                                         const LayoutObject* layout_object) {
-  Length offset, opposite;
+  std::pair<const Length*, const Length*> positions;
   switch (property.PropertyID()) {
     case CSSPropertyLeft:
-      offset = style.Left();
-      opposite = style.Right();
+      positions = std::make_pair(&style.Left(), &style.Right());
       break;
     case CSSPropertyRight:
-      offset = style.Right();
-      opposite = style.Left();
+      positions = std::make_pair(&style.Right(), &style.Left());
       break;
     case CSSPropertyTop:
-      offset = style.Top();
-      opposite = style.Bottom();
+      positions = std::make_pair(&style.Top(), &style.Bottom());
       break;
     case CSSPropertyBottom:
-      offset = style.Bottom();
-      opposite = style.Top();
+      positions = std::make_pair(&style.Bottom(), &style.Top());
       break;
     default:
+      NOTREACHED();
       return nullptr;
   }
+  DCHECK(positions.first && positions.second);
+
+  const Length& offset = *positions.first;
+  const Length& opposite = *positions.second;
 
   if (offset.IsPercentOrCalc() && layout_object && layout_object->IsBox() &&
       layout_object->IsPositioned()) {
@@ -255,8 +256,9 @@
       }
 
       // Length doesn't provide operator -, so multiply by -1.
-      opposite *= -1.f;
-      return ZoomAdjustedPixelValueForLength(opposite, style);
+      Length negated_opposite = opposite;
+      negated_opposite *= -1.f;
+      return ZoomAdjustedPixelValueForLength(negated_opposite, style);
     }
 
     if (layout_object->IsOutOfFlowPositioned() && layout_object->IsBox()) {
@@ -699,7 +701,7 @@
 }
 
 static CSSValue* ValueForLineHeight(const ComputedStyle& style) {
-  Length length = style.LineHeight();
+  const Length& length = style.LineHeight();
   if (length.IsNegative())
     return CSSIdentifierValue::Create(CSSValueNormal);
 
@@ -1464,7 +1466,7 @@
   return list;
 }
 
-static CSSValueList* ValuesForBorderRadiusCorner(LengthSize radius,
+static CSSValueList* ValuesForBorderRadiusCorner(const LengthSize& radius,
                                                  const ComputedStyle& style) {
   CSSValueList* list = CSSValueList::CreateSpaceSeparated();
   if (radius.Width().GetType() == kPercent)
@@ -1480,7 +1482,7 @@
   return list;
 }
 
-static const CSSValue& ValueForBorderRadiusCorner(LengthSize radius,
+static const CSSValue& ValueForBorderRadiusCorner(const LengthSize& radius,
                                                   const ComputedStyle& style) {
   CSSValueList& list = *ValuesForBorderRadiusCorner(radius, style);
   if (list.Item(0) == list.Item(1))
@@ -2802,14 +2804,14 @@
         return CSSIdentifierValue::Create(CSSValueAuto);
       return CSSStringValue::Create(style.Locale());
     case CSSPropertyMarginTop: {
-      Length margin_top = style.MarginTop();
+      const Length& margin_top = style.MarginTop();
       if (margin_top.IsFixed() || !layout_object || !layout_object->IsBox())
         return ZoomAdjustedPixelValueForLength(margin_top, style);
       return ZoomAdjustedPixelValue(ToLayoutBox(layout_object)->MarginTop(),
                                     style);
     }
     case CSSPropertyMarginRight: {
-      Length margin_right = style.MarginRight();
+      const Length& margin_right = style.MarginRight();
       if (margin_right.IsFixed() || !layout_object || !layout_object->IsBox())
         return ZoomAdjustedPixelValueForLength(margin_right, style);
       float value;
@@ -2829,14 +2831,14 @@
       return ZoomAdjustedPixelValue(value, style);
     }
     case CSSPropertyMarginBottom: {
-      Length margin_bottom = style.MarginBottom();
+      const Length& margin_bottom = style.MarginBottom();
       if (margin_bottom.IsFixed() || !layout_object || !layout_object->IsBox())
         return ZoomAdjustedPixelValueForLength(margin_bottom, style);
       return ZoomAdjustedPixelValue(ToLayoutBox(layout_object)->MarginBottom(),
                                     style);
     }
     case CSSPropertyMarginLeft: {
-      Length margin_left = style.MarginLeft();
+      const Length& margin_left = style.MarginLeft();
       if (margin_left.IsFixed() || !layout_object || !layout_object->IsBox())
         return ZoomAdjustedPixelValueForLength(margin_left, style);
       return ZoomAdjustedPixelValue(ToLayoutBox(layout_object)->MarginLeft(),
@@ -2912,28 +2914,28 @@
     case CSSPropertyOverflowY:
       return CSSIdentifierValue::Create(style.OverflowY());
     case CSSPropertyPaddingTop: {
-      Length padding_top = style.PaddingTop();
+      const Length& padding_top = style.PaddingTop();
       if (padding_top.IsFixed() || !layout_object || !layout_object->IsBox())
         return ZoomAdjustedPixelValueForLength(padding_top, style);
       return ZoomAdjustedPixelValue(
           ToLayoutBox(layout_object)->ComputedCSSPaddingTop(), style);
     }
     case CSSPropertyPaddingRight: {
-      Length padding_right = style.PaddingRight();
+      const Length& padding_right = style.PaddingRight();
       if (padding_right.IsFixed() || !layout_object || !layout_object->IsBox())
         return ZoomAdjustedPixelValueForLength(padding_right, style);
       return ZoomAdjustedPixelValue(
           ToLayoutBox(layout_object)->ComputedCSSPaddingRight(), style);
     }
     case CSSPropertyPaddingBottom: {
-      Length padding_bottom = style.PaddingBottom();
+      const Length& padding_bottom = style.PaddingBottom();
       if (padding_bottom.IsFixed() || !layout_object || !layout_object->IsBox())
         return ZoomAdjustedPixelValueForLength(padding_bottom, style);
       return ZoomAdjustedPixelValue(
           ToLayoutBox(layout_object)->ComputedCSSPaddingBottom(), style);
     }
     case CSSPropertyPaddingLeft: {
-      Length padding_left = style.PaddingLeft();
+      const Length& padding_left = style.PaddingLeft();
       if (padding_left.IsFixed() || !layout_object || !layout_object->IsBox())
         return ZoomAdjustedPixelValueForLength(padding_left, style);
       return ZoomAdjustedPixelValue(
diff --git a/third_party/WebKit/Source/core/dom/Node.cpp b/third_party/WebKit/Source/core/dom/Node.cpp
index 8150288..5791b6a 100644
--- a/third_party/WebKit/Source/core/dom/Node.cpp
+++ b/third_party/WebKit/Source/core/dom/Node.cpp
@@ -79,6 +79,7 @@
 #include "core/frame/EventHandlerRegistry.h"
 #include "core/frame/LocalDOMWindow.h"
 #include "core/frame/LocalFrame.h"
+#include "core/frame/LocalFrameClient.h"
 #include "core/frame/LocalFrameView.h"
 #include "core/frame/UseCounter.h"
 #include "core/html/HTMLDialogElement.h"
@@ -2408,6 +2409,21 @@
           frame->GetEventHandler().StartMiddleClickAutoscroll(layout_object);
       }
     }
+  } else if (event_type == EventTypeNames::mouseup && event->IsMouseEvent()) {
+    MouseEvent* mouse_event = ToMouseEvent(event);
+    if (mouse_event->button() ==
+        static_cast<short>(WebPointerProperties::Button::kBack)) {
+      if (LocalFrame* frame = GetDocument().GetFrame()) {
+        if (frame->Client()->NavigateBackForward(-1))
+          event->SetDefaultHandled();
+      }
+    } else if (mouse_event->button() ==
+               static_cast<short>(WebPointerProperties::Button::kForward)) {
+      if (LocalFrame* frame = GetDocument().GetFrame()) {
+        if (frame->Client()->NavigateBackForward(1))
+          event->SetDefaultHandled();
+      }
+    }
   }
 }
 
diff --git a/third_party/WebKit/Source/core/exported/WebFrameTest.cpp b/third_party/WebKit/Source/core/exported/WebFrameTest.cpp
index 318b935..6a8eb68 100644
--- a/third_party/WebKit/Source/core/exported/WebFrameTest.cpp
+++ b/third_party/WebKit/Source/core/exported/WebFrameTest.cpp
@@ -10859,17 +10859,17 @@
   web_view->Resize(WebSize(400, 400));
 
   uint64_t sequence = Platform::Current()->Clipboard()->SequenceNumber(
-      WebClipboard::kBufferStandard);
+      mojom::ClipboardBuffer::kStandard);
 
   WebLocalFrame* local_frame = web_view->MainFrameImpl();
   local_frame->CopyImageAt(WebPoint(50, 50));
 
   EXPECT_NE(sequence, Platform::Current()->Clipboard()->SequenceNumber(
-                          WebClipboard::kBufferStandard));
+                          mojom::ClipboardBuffer::kStandard));
 
   WebImage image =
       static_cast<WebMockClipboard*>(Platform::Current()->Clipboard())
-          ->ReadRawImage(WebClipboard::Buffer());
+          ->ReadRawImage(mojom::ClipboardBuffer::kStandard);
 
   EXPECT_EQ(SkColorSetARGB(255, 255, 0, 0), image.GetSkBitmap().getColor(0, 0));
 }
@@ -10886,17 +10886,17 @@
   web_view->SetVisualViewportOffset(WebFloatPoint(200, 200));
 
   uint64_t sequence = Platform::Current()->Clipboard()->SequenceNumber(
-      WebClipboard::kBufferStandard);
+      mojom::ClipboardBuffer::kStandard);
 
   WebLocalFrame* local_frame = web_view->MainFrameImpl();
   local_frame->CopyImageAt(WebPoint(0, 0));
 
   EXPECT_NE(sequence, Platform::Current()->Clipboard()->SequenceNumber(
-                          WebClipboard::kBufferStandard));
+                          mojom::ClipboardBuffer::kStandard));
 
   WebImage image =
       static_cast<WebMockClipboard*>(Platform::Current()->Clipboard())
-          ->ReadRawImage(WebClipboard::Buffer());
+          ->ReadRawImage(mojom::ClipboardBuffer::kStandard);
 
   EXPECT_EQ(SkColorSetARGB(255, 255, 0, 0), image.GetSkBitmap().getColor(0, 0));
 }
diff --git a/third_party/WebKit/Source/core/exported/WebPluginContainerTest.cpp b/third_party/WebKit/Source/core/exported/WebPluginContainerTest.cpp
index c6f2088..b7507cb 100644
--- a/third_party/WebKit/Source/core/exported/WebPluginContainerTest.cpp
+++ b/third_party/WebKit/Source/core/exported/WebPluginContainerTest.cpp
@@ -247,7 +247,7 @@
 
 WebString ReadClipboard() {
   return Platform::Current()->Clipboard()->ReadPlainText(
-      WebClipboard::Buffer());
+      mojom::ClipboardBuffer::kStandard);
 }
 
 void ClearClipboardBuffer() {
diff --git a/third_party/WebKit/Source/core/html/HTMLAnchorElement.cpp b/third_party/WebKit/Source/core/html/HTMLAnchorElement.cpp
index 6b17acc..5708793 100644
--- a/third_party/WebKit/Source/core/html/HTMLAnchorElement.cpp
+++ b/third_party/WebKit/Source/core/html/HTMLAnchorElement.cpp
@@ -412,12 +412,15 @@
 }
 
 bool IsLinkClick(Event* event) {
-  // Allow detail <= 1 so that synthetic clicks work. They may have detail == 0.
-  return (event->type() == EventTypeNames::click ||
-          event->type() == EventTypeNames::auxclick) &&
-         (!event->IsMouseEvent() ||
-          ToMouseEvent(event)->button() !=
-              static_cast<short>(WebPointerProperties::Button::kRight));
+  if ((event->type() != EventTypeNames::click &&
+       event->type() != EventTypeNames::auxclick) ||
+      !event->IsMouseEvent()) {
+    return false;
+  }
+  MouseEvent* mouse_event = ToMouseEvent(event);
+  short button = mouse_event->button();
+  return (button == static_cast<short>(WebPointerProperties::Button::kLeft) ||
+          button == static_cast<short>(WebPointerProperties::Button::kMiddle));
 }
 
 bool HTMLAnchorElement::WillRespondToMouseClickEvents() {
diff --git a/third_party/WebKit/Source/core/html/ImageData.cpp b/third_party/WebKit/Source/core/html/ImageData.cpp
index 82d2bb2e..75222d6c 100644
--- a/third_party/WebKit/Source/core/html/ImageData.cpp
+++ b/third_party/WebKit/Source/core/html/ImageData.cpp
@@ -746,7 +746,8 @@
     CanvasPixelFormat canvas_pixel_format,
     unsigned char* converted_pixels,
     DataU8ColorType u8_color_type,
-    const IntRect* src_rect) {
+    const IntRect* src_rect,
+    const AlphaDisposition alpha_disposition) {
   if (!data_ && !data_u16_ && !data_f32_)
     return false;
 
@@ -764,6 +765,7 @@
 
   // if color conversion is not needed, copy data into pixel buffer.
   if (!src_color_space.get() && !dst_color_space.get() && data_) {
+    int num_pixels = width() * height();
     SwizzleIfNeeded(u8_color_type, crop_rect);
     if (crop_rect) {
       unsigned char* src_data =
@@ -778,11 +780,23 @@
         src_index += src_row_stride;
         dst_index += dst_row_stride;
       }
+      num_pixels = crop_rect->Width() * crop_rect->Height();
     } else {
       memcpy(converted_pixels, data_->Data(), data_->length());
     }
+    bool conversion_result = true;
+    if (alpha_disposition == kPremultiplyAlpha) {
+      std::unique_ptr<SkColorSpaceXform> xform =
+          SkColorSpaceXform::New(SkColorSpace::MakeSRGBLinear().get(),
+                                 SkColorSpace::MakeSRGBLinear().get());
+      SkColorSpaceXform::ColorFormat color_format =
+          SkColorSpaceXform::ColorFormat::kRGBA_8888_ColorFormat;
+      conversion_result =
+          xform->apply(color_format, converted_pixels, color_format,
+                       converted_pixels, num_pixels, kPremul_SkAlphaType);
+    }
     SwizzleIfNeeded(u8_color_type, crop_rect);
-    return true;
+    return conversion_result;
   }
 
   bool conversion_result = false;
@@ -806,6 +820,9 @@
           : SkColorSpaceXform::ColorFormat::kBGRA_8888_ColorFormat;
   if (canvas_pixel_format == kF16CanvasPixelFormat)
     dst_color_format = SkColorSpaceXform::ColorFormat::kRGBA_F16_ColorFormat;
+  SkAlphaType alpha_type = (alpha_disposition == kPremultiplyAlpha)
+                               ? kPremul_SkAlphaType
+                               : kUnpremul_SkAlphaType;
 
   // SkColorSpaceXform only accepts big-endian integers when source data is
   // uint16. Since ImageData is always little-endian, we need to convert back
@@ -827,17 +844,16 @@
     for (int i = 0; i < crop_rect->Height(); i++) {
       conversion_result &=
           xform->apply(dst_color_format, dst_data + dst_index, src_color_format,
-                       src_data + src_index, crop_rect->Width(),
-                       SkAlphaType::kUnpremul_SkAlphaType);
+                       src_data + src_index, crop_rect->Width(), alpha_type);
       if (!conversion_result)
         break;
       src_index += src_row_stride;
       dst_index += dst_row_stride;
     }
   } else {
-    conversion_result = xform->apply(dst_color_format, converted_pixels,
-                                     src_color_format, src_data, size_.Area(),
-                                     SkAlphaType::kUnpremul_SkAlphaType);
+    conversion_result =
+        xform->apply(dst_color_format, converted_pixels, src_color_format,
+                     src_data, size_.Area(), alpha_type);
   }
 
   SwapU16EndiannessForSkColorSpaceXform(crop_rect);
diff --git a/third_party/WebKit/Source/core/html/ImageData.h b/third_party/WebKit/Source/core/html/ImageData.h
index 7585b751..e3e2400 100644
--- a/third_party/WebKit/Source/core/html/ImageData.h
+++ b/third_party/WebKit/Source/core/html/ImageData.h
@@ -138,11 +138,13 @@
   // For example, if ImageDataInCanvasColorSettings() is called to fill an
   // ImageBuffer, kRGBAColorType should be used. If the converted pixels are
   // used to create an ImageBitmap, kN32ColorType should be used.
-  bool ImageDataInCanvasColorSettings(CanvasColorSpace,
-                                      CanvasPixelFormat,
-                                      unsigned char* converted_pixels,
-                                      DataU8ColorType,
-                                      const IntRect* = nullptr);
+  bool ImageDataInCanvasColorSettings(
+      CanvasColorSpace,
+      CanvasPixelFormat,
+      unsigned char* converted_pixels,
+      DataU8ColorType,
+      const IntRect* = nullptr,
+      const AlphaDisposition = kDontPremultiplyAlpha);
 
   // ImageBitmapSource implementation
   IntSize BitmapSourceSize() const override { return size_; }
diff --git a/third_party/WebKit/Source/core/imagebitmap/ImageBitmap.cpp b/third_party/WebKit/Source/core/imagebitmap/ImageBitmap.cpp
index 018cf7c..577e999c 100644
--- a/third_party/WebKit/Source/core/imagebitmap/ImageBitmap.cpp
+++ b/third_party/WebKit/Source/core/imagebitmap/ImageBitmap.cpp
@@ -284,6 +284,11 @@
   info = info.makeAlphaType(alpha_type);
 
   // For premul to unpremul, we have to readback the pixels.
+  // For unpremul to premul, we can either readback the pixels or draw onto a
+  // surface. As shown  in
+  // https://fiddle.skia.org/c/1ec3c61ed08f7863d43b9f49ab120a0a, drawing on a
+  // surface and getting a snapshot is slower if the image is small. Therefore,
+  // for small images (< 128x128 pixels), we still do read back.
   if (alpha_type == kUnpremul_SkAlphaType ||
       (image->width() * image->height() < 16384)) {
     // Set the color space of the ImageInfo to nullptr to unpremul in gamma
@@ -295,12 +300,6 @@
     return NewImageFromRaster(info, std::move(dst_pixels));
   }
 
-  // For unpremul to premul, we can either readback the pixels or draw onto a
-  // surface. As shown  in
-  // https://fiddle.skia.org/c/1ec3c61ed08f7863d43b9f49ab120a0a, drawing on a
-  // surface and getting a snapshot is slower if the image is small. Therefore,
-  // for small images (< 128x128 pixels), we still do read back.
-
   // Draw on a surface. Avoid sRGB gamma transfer curve.
   if (SkColorSpace::Equals(info.colorSpace(), SkColorSpace::MakeSRGB().get()))
     info = info.makeColorSpace(nullptr);
@@ -766,13 +765,17 @@
   if (!data->ImageDataInCanvasColorSettings(
           parsed_options.color_params.ColorSpace(),
           parsed_options.color_params.PixelFormat(), image_pixels->Data(),
-          kN32ColorType, &src_rect))
+          kN32ColorType, &src_rect,
+          parsed_options.premultiply_alpha ? kPremultiplyAlpha
+                                           : kDontPremultiplyAlpha))
     return;
 
   // Create Image object
   SkImageInfo info = SkImageInfo::Make(
       src_rect.Width(), src_rect.Height(),
-      parsed_options.color_params.GetSkColorType(), kUnpremul_SkAlphaType,
+      parsed_options.color_params.GetSkColorType(),
+      parsed_options.premultiply_alpha ? kPremul_SkAlphaType
+                                       : kUnpremul_SkAlphaType,
       parsed_options.color_params.GetSkColorSpaceForSkSurfaces());
   image_ = NewImageFromRaster(info, std::move(image_pixels));
   if (!image_)
@@ -791,12 +794,6 @@
   if (!image_)
     return;
 
-  // premultiply if needed
-  if (parsed_options.premultiply_alpha)
-    image_ = GetImageWithAlphaDisposition(std::move(image_), kPremultiplyAlpha);
-  if (!image_)
-    return;
-
   // flip if needed
   if (parsed_options.flip_y)
     image_ = FlipImageVertically(std::move(image_), parsed_options);
diff --git a/third_party/WebKit/Source/core/imagebitmap/ImageBitmap.h b/third_party/WebKit/Source/core/imagebitmap/ImageBitmap.h
index c13637b..92aa676 100644
--- a/third_party/WebKit/Source/core/imagebitmap/ImageBitmap.h
+++ b/third_party/WebKit/Source/core/imagebitmap/ImageBitmap.h
@@ -28,11 +28,6 @@
 class ImageDecoder;
 class OffscreenCanvas;
 
-enum AlphaDisposition {
-  kPremultiplyAlpha,
-  kDontPremultiplyAlpha,
-};
-
 enum ColorSpaceInfoUpdate {
   kUpdateColorSpaceInformation,
   kDontUpdateColorSpaceInformation,
diff --git a/third_party/WebKit/Source/core/input/EventHandlerTest.cpp b/third_party/WebKit/Source/core/input/EventHandlerTest.cpp
index 3c7049f..6d3951a5 100644
--- a/third_party/WebKit/Source/core/input/EventHandlerTest.cpp
+++ b/third_party/WebKit/Source/core/input/EventHandlerTest.cpp
@@ -887,4 +887,94 @@
   ASSERT_FALSE(chrome_client_->ReceivedRequestForUnbufferedInput());
 }
 
+class NavigationCapturingFrameClient : public EmptyLocalFrameClient {
+ public:
+  NavigationCapturingFrameClient() {}
+
+  bool NavigateBackForward(int offset) const override {
+    offset_ = offset;
+    return true;
+  }
+
+  int Offset() const { return offset_; }
+
+ private:
+  mutable int offset_ = 0;
+};
+
+class EventHandlerNavigationTest : public EventHandlerTest {
+ public:
+  EventHandlerNavigationTest() {}
+
+  void SetUp() override {
+    frame_client_ = new NavigationCapturingFrameClient();
+    Page::PageClients clients;
+    FillWithEmptyClients(clients);
+    SetupPageWithClients(&clients, frame_client_);
+  }
+
+  int Offset() { return frame_client_->Offset(); }
+
+ private:
+  Persistent<NavigationCapturingFrameClient> frame_client_;
+};
+
+TEST_F(EventHandlerNavigationTest, MouseButtonsNavigate) {
+  SetHtmlInnerHTML("<div>");
+
+  EXPECT_EQ(0, Offset());
+
+  WebMouseEvent mouse_back_event(
+      WebInputEvent::kMouseUp, WebFloatPoint(51, 50), WebFloatPoint(51, 50),
+      WebPointerProperties::Button::kBack, 0, WebInputEvent::kNoModifiers,
+      TimeTicks::Now().InSeconds());
+  mouse_back_event.SetFrameScale(1);
+  GetDocument().GetFrame()->GetEventHandler().HandleMouseReleaseEvent(
+      mouse_back_event);
+
+  EXPECT_EQ(-1, Offset());
+
+  WebMouseEvent mouse_forward_event(
+      WebInputEvent::kMouseUp, WebFloatPoint(51, 50), WebFloatPoint(51, 50),
+      WebPointerProperties::Button::kForward, 0, WebInputEvent::kNoModifiers,
+      TimeTicks::Now().InSeconds());
+  mouse_forward_event.SetFrameScale(1);
+  GetDocument().GetFrame()->GetEventHandler().HandleMouseReleaseEvent(
+      mouse_forward_event);
+
+  EXPECT_EQ(1, Offset());
+}
+
+TEST_F(EventHandlerNavigationTest, MouseButtonsDontNavigate) {
+  SetHtmlInnerHTML("<div>");
+  GetDocument().GetSettings()->SetScriptEnabled(true);
+  Element* script = GetDocument().createElement("script");
+  script->SetInnerHTMLFromString(
+      "document.addEventListener('mouseup', event => "
+      "event.preventDefault());");
+  GetDocument().body()->AppendChild(script);
+
+  EXPECT_EQ(0, Offset());
+
+  WebMouseEvent mouse_back_event(
+      WebInputEvent::kMouseUp, WebFloatPoint(51, 50), WebFloatPoint(51, 50),
+      WebPointerProperties::Button::kBack, 0, WebInputEvent::kNoModifiers,
+      TimeTicks::Now().InSeconds());
+  mouse_back_event.SetFrameScale(1);
+  GetDocument().GetFrame()->GetEventHandler().HandleMouseReleaseEvent(
+      mouse_back_event);
+
+  EXPECT_EQ(0, Offset());
+
+  WebMouseEvent mouse_forward_event(
+      WebInputEvent::kMouseUp, WebFloatPoint(51, 50), WebFloatPoint(51, 50),
+      WebPointerProperties::Button::kForward, 0, WebInputEvent::kNoModifiers,
+      TimeTicks::Now().InSeconds());
+  mouse_forward_event.SetFrameScale(1);
+  GetDocument().GetFrame()->GetEventHandler().HandleMouseReleaseEvent(
+      mouse_forward_event);
+
+  EXPECT_EQ(0, Offset());
+}
+
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/loader/DocumentThreadableLoader.cpp b/third_party/WebKit/Source/core/loader/DocumentThreadableLoader.cpp
index cb20338..5dfaec9b 100644
--- a/third_party/WebKit/Source/core/loader/DocumentThreadableLoader.cpp
+++ b/third_party/WebKit/Source/core/loader/DocumentThreadableLoader.cpp
@@ -53,6 +53,7 @@
 #include "platform/loader/fetch/FetchUtils.h"
 #include "platform/loader/fetch/Resource.h"
 #include "platform/loader/fetch/ResourceFetcher.h"
+#include "platform/loader/fetch/ResourceLoader.h"
 #include "platform/loader/fetch/ResourceLoaderOptions.h"
 #include "platform/loader/fetch/ResourceRequest.h"
 #include "platform/weborigin/SchemeRegistry.h"
@@ -536,7 +537,7 @@
 
 DocumentThreadableLoader::~DocumentThreadableLoader() {
   CHECK(!client_);
-  DCHECK(!resource_);
+  DCHECK(!GetResource());
 }
 
 void DocumentThreadableLoader::OverrideTimeout(
@@ -585,14 +586,16 @@
 }
 
 void DocumentThreadableLoader::SetDefersLoading(bool value) {
-  if (GetResource())
-    GetResource()->SetDefersLoading(value);
+  if (GetResource() && GetResource()->Loader())
+    GetResource()->Loader()->SetDefersLoading(value);
 }
 
 void DocumentThreadableLoader::Clear() {
   client_ = nullptr;
   timeout_timer_.Stop();
   request_started_seconds_ = 0.0;
+  if (GetResource())
+    checker_.WillRemoveClient();
   ClearResource();
 }
 
@@ -734,6 +737,8 @@
 
   // FIXME: consider combining this with CORS redirect handling performed by
   // CrossOriginAccessControl::handleRedirect().
+  if (GetResource())
+    checker_.WillRemoveClient();
   ClearResource();
 
   // If
@@ -1101,6 +1106,8 @@
 }
 
 void DocumentThreadableLoader::LoadFallbackRequestForServiceWorker() {
+  if (GetResource())
+    checker_.WillRemoveClient();
   ClearResource();
   ResourceRequest fallback_request(fallback_request_for_service_worker_);
   fallback_request_for_service_worker_ = ResourceRequest();
@@ -1116,6 +1123,8 @@
   actual_request_ = ResourceRequest();
   actual_options_ = ResourceLoaderOptions();
 
+  if (GetResource())
+    checker_.WillRemoveClient();
   ClearResource();
 
   PrepareCrossOriginRequest(actual_request);
@@ -1200,6 +1209,8 @@
   } else {
     SetResource(RawResource::Fetch(new_params, fetcher));
   }
+  if (GetResource())
+    checker_.WillAddClient();
 
   if (!GetResource()) {
     probe::documentThreadableLoaderFailedToStartLoadingForClient(
@@ -1365,10 +1376,9 @@
 }
 
 void DocumentThreadableLoader::Trace(blink::Visitor* visitor) {
-  visitor->Trace(resource_);
   visitor->Trace(loading_context_);
   ThreadableLoader::Trace(visitor);
-  RawResourceClient::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 89b55c0..73cadb9 100644
--- a/third_party/WebKit/Source/core/loader/DocumentThreadableLoader.h
+++ b/third_party/WebKit/Source/core/loader/DocumentThreadableLoader.h
@@ -57,8 +57,9 @@
 
 // TODO(horo): We are using this class not only in documents, but also in
 // workers. We should change the name to ThreadableLoaderImpl.
-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:
@@ -203,32 +204,6 @@
   void LoadRequest(ResourceRequest&, ResourceLoaderOptions);
   bool IsAllowedRedirect(network::mojom::FetchRequestMode, const KURL&) const;
 
-  // TODO(hiroshige): After crbug.com/633696 is fixed,
-  // - Remove RawResourceClientStateChecker logic,
-  // - Make DocumentThreadableLoader to be a ResourceOwner and remove this
-  //   re-implementation of ResourceOwner, and
-  // - Consider re-applying RawResourceClientStateChecker in a more
-  //   general fashion (crbug.com/640291).
-  RawResource* GetResource() const { return resource_.Get(); }
-  void ClearResource() { SetResource(nullptr); }
-  void SetResource(RawResource* new_resource) {
-    if (new_resource == resource_)
-      return;
-
-    if (RawResource* old_resource = resource_.Release()) {
-      checker_.WillRemoveClient();
-      old_resource->RemoveClient(this);
-    }
-
-    if (new_resource) {
-      resource_ = new_resource;
-      checker_.WillAddClient();
-      resource_->AddClient(this);
-    }
-  }
-  Member<RawResource> resource_;
-  // End of ResourceOwner re-implementation, see above.
-
   SecurityOrigin* GetSecurityOrigin() const;
 
   // Returns null if the loader is not associated with Document.
diff --git a/third_party/WebKit/Source/modules/clipboard/BUILD.gn b/third_party/WebKit/Source/modules/clipboard/BUILD.gn
index 04dd610..9fbd54d 100644
--- a/third_party/WebKit/Source/modules/clipboard/BUILD.gn
+++ b/third_party/WebKit/Source/modules/clipboard/BUILD.gn
@@ -13,4 +13,7 @@
     "NavigatorClipboard.cpp",
     "NavigatorClipboard.h",
   ]
+  deps = [
+    "//third_party/WebKit/public:blink_headers",
+  ]
 }
diff --git a/third_party/WebKit/Source/modules/clipboard/ClipboardPromise.cpp b/third_party/WebKit/Source/modules/clipboard/ClipboardPromise.cpp
index 00ff09e..740f42d 100644
--- a/third_party/WebKit/Source/modules/clipboard/ClipboardPromise.cpp
+++ b/third_party/WebKit/Source/modules/clipboard/ClipboardPromise.cpp
@@ -13,6 +13,7 @@
 #include "platform/clipboard/ClipboardMimeTypes.h"
 #include "public/platform/Platform.h"
 #include "public/platform/TaskType.h"
+#include "third_party/WebKit/public/platform/WebClipboard.h"
 
 namespace blink {
 
@@ -54,7 +55,7 @@
 ClipboardPromise::ClipboardPromise(ScriptState* script_state)
     : ContextLifecycleObserver(blink::ExecutionContext::From(script_state)),
       script_promise_resolver_(ScriptPromiseResolver::Create(script_state)),
-      buffer_(WebClipboard::kBufferStandard) {}
+      buffer_(mojom::ClipboardBuffer::kStandard) {}
 
 scoped_refptr<WebTaskRunner> ClipboardPromise::GetTaskRunner() {
   // TODO(garykac): Replace MiscPlatformAPI with TaskType specific to clipboard.
diff --git a/third_party/WebKit/Source/modules/clipboard/ClipboardPromise.h b/third_party/WebKit/Source/modules/clipboard/ClipboardPromise.h
index 5218501..8b0c254 100644
--- a/third_party/WebKit/Source/modules/clipboard/ClipboardPromise.h
+++ b/third_party/WebKit/Source/modules/clipboard/ClipboardPromise.h
@@ -8,7 +8,7 @@
 #include "bindings/core/v8/ScriptPromise.h"
 #include "core/CoreExport.h"
 #include "core/dom/ContextLifecycleObserver.h"
-#include "public/platform/WebClipboard.h"
+#include "third_party/WebKit/common/clipboard/clipboard.mojom-blink.h"
 
 namespace blink {
 
@@ -44,7 +44,7 @@
 
   Member<ScriptPromiseResolver> script_promise_resolver_;
 
-  WebClipboard::Buffer buffer_;
+  mojom::ClipboardBuffer buffer_;
 };
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/platform/graphics/GraphicsTypes.h b/third_party/WebKit/Source/platform/graphics/GraphicsTypes.h
index dd26fbb..1a0aa305 100644
--- a/third_party/WebKit/Source/platform/graphics/GraphicsTypes.h
+++ b/third_party/WebKit/Source/platform/graphics/GraphicsTypes.h
@@ -35,6 +35,11 @@
 
 namespace blink {
 
+enum AlphaDisposition {
+  kPremultiplyAlpha,
+  kDontPremultiplyAlpha,
+};
+
 enum DataU8ColorType {
   kRGBAColorType,
   kN32ColorType,
diff --git a/third_party/WebKit/Source/platform/loader/fetch/RawResource.cpp b/third_party/WebKit/Source/platform/loader/fetch/RawResource.cpp
index 7b63439..f06f0904 100644
--- a/third_party/WebKit/Source/platform/loader/fetch/RawResource.cpp
+++ b/third_party/WebKit/Source/platform/loader/fetch/RawResource.cpp
@@ -31,7 +31,6 @@
 #include "platform/loader/fetch/MemoryCache.h"
 #include "platform/loader/fetch/ResourceClientWalker.h"
 #include "platform/loader/fetch/ResourceFetcher.h"
-#include "platform/loader/fetch/ResourceLoader.h"
 #include "platform/network/http_names.h"
 #include "platform/scheduler/child/web_scheduler.h"
 #include "public/platform/Platform.h"
@@ -296,11 +295,6 @@
   Resource::NotifyFinished();
 }
 
-void RawResource::SetDefersLoading(bool defers) {
-  if (Loader())
-    Loader()->SetDefersLoading(defers);
-}
-
 static bool ShouldIgnoreHeaderForCacheReuse(AtomicString header_name) {
   // FIXME: This list of headers that don't affect cache policy almost certainly
   // isn't complete.
diff --git a/third_party/WebKit/Source/platform/loader/fetch/RawResource.h b/third_party/WebKit/Source/platform/loader/fetch/RawResource.h
index 8d59b043..b81d484 100644
--- a/third_party/WebKit/Source/platform/loader/fetch/RawResource.h
+++ b/third_party/WebKit/Source/platform/loader/fetch/RawResource.h
@@ -66,12 +66,6 @@
     return CreateForTest(KURL(url), type);
   }
 
-  // FIXME: AssociatedURLLoader shouldn't be a DocumentThreadableLoader and
-  // therefore shouldn't use RawResource. However, it is, and it needs to be
-  // able to defer loading. This can be fixed by splitting CORS preflighting out
-  // of DocumentThreadableLoader.
-  void SetDefersLoading(bool);
-
   // Resource implementation
   bool CanReuse(const FetchParameters&) const override;
   bool WillFollowRedirect(const ResourceRequest&,
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/common/checkout/baseline_optimizer_unittest.py b/third_party/WebKit/Tools/Scripts/webkitpy/common/checkout/baseline_optimizer_unittest.py
index 24b6926..cc7ba469 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/common/checkout/baseline_optimizer_unittest.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/common/checkout/baseline_optimizer_unittest.py
@@ -27,7 +27,6 @@
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 import unittest
-import logging
 import sys
 
 from webkitpy.common.checkout.baseline_optimizer import BaselineOptimizer
@@ -36,11 +35,6 @@
 from webkitpy.common.path_finder import PathFinder
 from webkitpy.layout_tests.builder_list import BuilderList
 
-# Print out useful debug logs in very verbose (-vv) mode.
-_log = logging.getLogger()
-_log.level = logging.DEBUG
-_log.addHandler(logging.StreamHandler(sys.stderr))
-
 ALL_PASS_TESTHARNESS_RESULT = """This is a testharness.js-based test.
 PASS woohoo
 Harness: the test ran to completion.
diff --git a/third_party/WebKit/common/BUILD.gn b/third_party/WebKit/common/BUILD.gn
index 949d9b9..900946fc 100644
--- a/third_party/WebKit/common/BUILD.gn
+++ b/third_party/WebKit/common/BUILD.gn
@@ -110,6 +110,7 @@
   sources = [
     "blob/blob.mojom",
     "blob/blob_registry.mojom",
+    "clipboard/clipboard.mojom",
     "page/page_visibility_state.mojom",
     "service_worker/service_worker_client.mojom",
     "service_worker/service_worker_provider_type.mojom",
diff --git a/third_party/WebKit/common/clipboard/OWNERS b/third_party/WebKit/common/clipboard/OWNERS
new file mode 100644
index 0000000..08850f4
--- /dev/null
+++ b/third_party/WebKit/common/clipboard/OWNERS
@@ -0,0 +1,2 @@
+per-file *.mojom=set noparent
+per-file *.mojom=file://ipc/SECURITY_OWNERS
diff --git a/third_party/WebKit/common/clipboard/clipboard.mojom b/third_party/WebKit/common/clipboard/clipboard.mojom
new file mode 100644
index 0000000..96d3078e
--- /dev/null
+++ b/third_party/WebKit/common/clipboard/clipboard.mojom
@@ -0,0 +1,21 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+module blink.mojom;
+
+enum ClipboardFormat {
+  kPlaintext,
+  kHtml,
+  kSmartPaste,
+  kBookmark,
+};
+
+enum ClipboardBuffer {
+  kStandard,
+  // Used on platforms like the X Window System that treat selection
+  // as a type of clipboard.
+  // TODO(crbug.com/676224): When preprocessing of mojom is available only
+  // define this value for USE_X11.
+  kSelection,
+};
diff --git a/third_party/WebKit/public/platform/WebClipboard.h b/third_party/WebKit/public/platform/WebClipboard.h
index 63633904..02f8b58a 100644
--- a/third_party/WebKit/public/platform/WebClipboard.h
+++ b/third_party/WebKit/public/platform/WebClipboard.h
@@ -37,6 +37,7 @@
 #include "public/platform/WebString.h"
 #include "public/platform/WebURL.h"
 #include "public/platform/WebVector.h"
+#include "third_party/WebKit/common/clipboard/clipboard.mojom-shared.h"
 
 namespace blink {
 
@@ -46,45 +47,39 @@
 
 class WebClipboard {
  public:
-  enum Format {
-    kFormatPlainText,
-    kFormatHTML,
-    kFormatBookmark,
-    kFormatSmartPaste
-  };
-
-  enum Buffer {
-    kBufferStandard,
-    // Used on platforms like the X Window System that treat selection
-    // as a type of clipboard.
-    kBufferSelection,
-  };
-
   // Returns an identifier which can be used to determine whether the data
   // contained within the clipboard has changed.
-  virtual uint64_t SequenceNumber(Buffer) { return 0; }
+  virtual uint64_t SequenceNumber(mojom::ClipboardBuffer) { return 0; }
 
-  virtual bool IsFormatAvailable(Format, Buffer) { return false; }
+  virtual bool IsFormatAvailable(mojom::ClipboardFormat,
+                                 mojom::ClipboardBuffer) {
+    return false;
+  }
 
-  virtual WebVector<WebString> ReadAvailableTypes(Buffer,
+  virtual WebVector<WebString> ReadAvailableTypes(blink::mojom::ClipboardBuffer,
                                                   bool* contains_filenames) {
     return WebVector<WebString>();
   }
-  virtual WebString ReadPlainText(Buffer) { return WebString(); }
+  virtual WebString ReadPlainText(blink::mojom::ClipboardBuffer) {
+    return WebString();
+  }
   // |fragment_start| and |fragment_end| are indexes into the returned markup
   // that indicate the start and end of the fragment if the returned markup
   // contains additional context. If there is no additional context,
   // |fragment_start| will be zero and |fragment_end| will be the same as the
   // length of the returned markup.
-  virtual WebString ReadHTML(Buffer buffer,
+  virtual WebString ReadHTML(blink::mojom::ClipboardBuffer buffer,
                              WebURL* page_url,
                              unsigned* fragment_start,
                              unsigned* fragment_end) {
     return WebString();
   }
-  virtual WebString ReadRTF(Buffer) { return WebString(); }
-  virtual WebBlobInfo ReadImage(Buffer) { return WebBlobInfo(); }
-  virtual WebString ReadCustomData(Buffer, const WebString& type) {
+  virtual WebString ReadRTF(mojom::ClipboardBuffer) { return WebString(); }
+  virtual WebBlobInfo ReadImage(mojom::ClipboardBuffer) {
+    return WebBlobInfo();
+  }
+  virtual WebString ReadCustomData(mojom::ClipboardBuffer,
+                                   const WebString& type) {
     return WebString();
   }
 
diff --git a/third_party/WebKit/public/platform/WebMockClipboard.h b/third_party/WebKit/public/platform/WebMockClipboard.h
index dc4b29a..9026ccce 100644
--- a/third_party/WebKit/public/platform/WebMockClipboard.h
+++ b/third_party/WebKit/public/platform/WebMockClipboard.h
@@ -16,7 +16,7 @@
 // used in layout and unit tests.
 class BLINK_PLATFORM_EXPORT WebMockClipboard : public WebClipboard {
  public:
-  virtual WebImage ReadRawImage(Buffer) { return WebImage(); }
+  virtual WebImage ReadRawImage(mojom::ClipboardBuffer) { return WebImage(); }
 
  protected:
   // Convenience method for WebMockClipoard implementations to create a blob
diff --git a/third_party/closure_compiler/externs/automation.js b/third_party/closure_compiler/externs/automation.js
index 9c580aa..5d8a092b 100644
--- a/third_party/closure_compiler/externs/automation.js
+++ b/third_party/closure_compiler/externs/automation.js
@@ -431,8 +431,7 @@
 chrome.automation.AutomationNode.prototype.boundsForRange = function(startIndex, endIndex) {};
 
 /**
- * The location (as a bounding box) of this node in global screen coordinates.
- * This is the same as location but not clipped by ancestors.
+ * The location (as a bounding box) of this node in global screen coordinates without applying any clipping from ancestors.
  * @type {(!chrome.automation.Rect|undefined)}
  * @see https://developer.chrome.com/extensions/automation#type-unclippedLocation
  */
@@ -895,6 +894,20 @@
 chrome.automation.AutomationNode.prototype.containerLiveBusy;
 
 /**
+ * Aria auto complete.
+ * @type {(string|undefined)}
+ * @see https://developer.chrome.com/extensions/automation#type-autoComplete
+ */
+chrome.automation.AutomationNode.prototype.autoComplete;
+
+/**
+ * The name of the programmatic backing object.
+ * @type {(string|undefined)}
+ * @see https://developer.chrome.com/extensions/automation#type-className
+ */
+chrome.automation.AutomationNode.prototype.className;
+
+/**
  * A map containing all HTML attributes and their values
  * @type {Object<string>}
  * @see https://developer.chrome.com/extensions/automation#type-htmlAttributes
diff --git a/ui/accessibility/ax_enums.idl b/ui/accessibility/ax_enums.idl
index 5036668..0bd3f8f 100644
--- a/ui/accessibility/ax_enums.idl
+++ b/ui/accessibility/ax_enums.idl
@@ -340,6 +340,7 @@
     aria_invalid_value,
     auto_complete,
     chrome_channel,  // Automation only.
+    class_name, // views and Android
     container_live_relevant,
     container_live_status,
     description,
diff --git a/ui/accessibility/ax_node_data.cc b/ui/accessibility/ax_node_data.cc
index 729b692..f60b1d0 100644
--- a/ui/accessibility/ax_node_data.cc
+++ b/ui/accessibility/ax_node_data.cc
@@ -831,6 +831,9 @@
       case AX_ATTR_CHROME_CHANNEL:
         result += " chrome_channel=" + value;
         break;
+      case AX_ATTR_CLASS_NAME:
+        result += " class_name=" + value;
+        break;
       case AX_ATTR_DESCRIPTION:
         result += " description=" + value;
         break;
diff --git a/ui/base/clipboard/mojom/BUILD.gn b/ui/base/clipboard/mojom/BUILD.gn
deleted file mode 100644
index 77cea73..0000000
--- a/ui/base/clipboard/mojom/BUILD.gn
+++ /dev/null
@@ -1,11 +0,0 @@
-# Copyright 2017 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-import("//mojo/public/tools/bindings/mojom.gni")
-
-mojom("mojo_bindings") {
-  sources = [
-    "clipboard.mojom",
-  ]
-}
diff --git a/ui/base/clipboard/mojom/OWNERS b/ui/base/clipboard/mojom/OWNERS
deleted file mode 100644
index 253d946..0000000
--- a/ui/base/clipboard/mojom/OWNERS
+++ /dev/null
@@ -1,8 +0,0 @@
-per-file *.mojom=set noparent
-per-file *.mojom=file://ipc/SECURITY_OWNERS
-
-per-file *.typemap=set noparent
-per-file *.typemap=file://ipc/SECURITY_OWNERS
-
-per-file *_struct_traits*.*=set noparent
-per-file *_struct_traits*.*=file://ipc/SECURITY_OWNERS
diff --git a/ui/base/clipboard/mojom/clipboard.mojom b/ui/base/clipboard/mojom/clipboard.mojom
deleted file mode 100644
index 84f0d28..0000000
--- a/ui/base/clipboard/mojom/clipboard.mojom
+++ /dev/null
@@ -1,11 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-module ui.mojom;
-
-enum ClipboardType {
-  kCopyPaste,
-  kSelection,
-  kDrag,
-};
diff --git a/ui/base/clipboard/mojom/clipboard.typemap b/ui/base/clipboard/mojom/clipboard.typemap
deleted file mode 100644
index 6d3c890..0000000
--- a/ui/base/clipboard/mojom/clipboard.typemap
+++ /dev/null
@@ -1,11 +0,0 @@
-# Copyright 2017 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-mojom = "//ui/base/clipboard/mojom/clipboard.mojom"
-public_headers = [ "//ui/base/clipboard/clipboard_types.h" ]
-traits_headers = [ "//ui/base/clipboard/mojom/clipboard_struct_traits.h" ]
-deps = [
-  "//ui/base",
-]
-type_mappings = [ "ui.mojom.ClipboardType=ui::ClipboardType" ]
diff --git a/ui/base/clipboard/mojom/clipboard_struct_traits.h b/ui/base/clipboard/mojom/clipboard_struct_traits.h
deleted file mode 100644
index a5f7b733..0000000
--- a/ui/base/clipboard/mojom/clipboard_struct_traits.h
+++ /dev/null
@@ -1,47 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_BASE_CLIPBOARD_MOJOM_CLIPBOARD_STRUCT_TRAITS_H_
-#define UI_BASE_CLIPBOARD_MOJOM_CLIPBOARD_STRUCT_TRAITS_H_
-
-#include "ui/base/clipboard/clipboard_types.h"
-#include "ui/base/clipboard/mojom/clipboard.mojom-shared.h"
-
-namespace mojo {
-
-template <>
-struct EnumTraits<ui::mojom::ClipboardType, ui::ClipboardType> {
-  static ui::mojom::ClipboardType ToMojom(ui::ClipboardType clipboard_type) {
-    switch (clipboard_type) {
-      case ui::CLIPBOARD_TYPE_COPY_PASTE:
-        return ui::mojom::ClipboardType::kCopyPaste;
-      case ui::CLIPBOARD_TYPE_SELECTION:
-        return ui::mojom::ClipboardType::kSelection;
-      case ui::CLIPBOARD_TYPE_DRAG:
-        return ui::mojom::ClipboardType::kDrag;
-    }
-    NOTREACHED();
-    return ui::mojom::ClipboardType::kCopyPaste;
-  }
-
-  static bool FromMojom(ui::mojom::ClipboardType clipboard_type,
-                        ui::ClipboardType* out) {
-    switch (clipboard_type) {
-      case ui::mojom::ClipboardType::kCopyPaste:
-        *out = ui::CLIPBOARD_TYPE_COPY_PASTE;
-        return true;
-      case ui::mojom::ClipboardType::kSelection:
-        *out = ui::CLIPBOARD_TYPE_SELECTION;
-        return true;
-      case ui::mojom::ClipboardType::kDrag:
-        *out = ui::CLIPBOARD_TYPE_DRAG;
-        return true;
-    }
-    return false;
-  }
-};
-
-}  // namespace mojo
-
-#endif  // UI_BASE_CLIPBOARD_MOJOM_CLIPBOARD_STRUCT_TRAITS_H_
diff --git a/ui/base/clipboard/mojom/typemaps.gni b/ui/base/clipboard/mojom/typemaps.gni
deleted file mode 100644
index a206af2..0000000
--- a/ui/base/clipboard/mojom/typemaps.gni
+++ /dev/null
@@ -1,5 +0,0 @@
-# Copyright 2017 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-typemaps = [ "//ui/base/clipboard/mojom/clipboard.typemap" ]
diff --git a/ui/events/blink/web_input_event_builders_win.cc b/ui/events/blink/web_input_event_builders_win.cc
index 3e38895..f90aeef 100644
--- a/ui/events/blink/web_input_event_builders_win.cc
+++ b/ui/events/blink/web_input_event_builders_win.cc
@@ -78,6 +78,14 @@
       type = WebInputEvent::kMouseDown;
       button = WebMouseEvent::Button::kRight;
       break;
+    case WM_XBUTTONDOWN:
+    case WM_XBUTTONDBLCLK:
+      type = WebInputEvent::kMouseDown;
+      if ((HIWORD(wparam) & XBUTTON1))
+        button = WebMouseEvent::Button::kBack;
+      else if ((HIWORD(wparam) & XBUTTON2))
+        button = WebMouseEvent::Button::kForward;
+      break;
     case WM_LBUTTONUP:
       type = WebInputEvent::kMouseUp;
       button = WebMouseEvent::Button::kLeft;
@@ -90,6 +98,13 @@
       type = WebInputEvent::kMouseUp;
       button = WebMouseEvent::Button::kRight;
       break;
+    case WM_XBUTTONUP:
+      type = WebInputEvent::kMouseUp;
+      if ((HIWORD(wparam) & XBUTTON1))
+        button = WebMouseEvent::Button::kBack;
+      else if ((HIWORD(wparam) & XBUTTON2))
+        button = WebMouseEvent::Button::kForward;
+      break;
     default:
       NOTREACHED();
   }
@@ -107,6 +122,10 @@
     modifiers |= WebInputEvent::kMiddleButtonDown;
   if (wparam & MK_RBUTTON)
     modifiers |= WebInputEvent::kRightButtonDown;
+  if (wparam & MK_XBUTTON1)
+    modifiers |= WebInputEvent::kBackButtonDown;
+  if (wparam & MK_XBUTTON2)
+    modifiers |= WebInputEvent::kForwardButtonDown;
 
   WebMouseEvent result(type, modifiers, time_stamp);
   result.pointer_type = pointer_type;
diff --git a/ui/views/accessibility/ax_view_obj_wrapper.cc b/ui/views/accessibility/ax_view_obj_wrapper.cc
index 974f2a5..f4ff851 100644
--- a/ui/views/accessibility/ax_view_obj_wrapper.cc
+++ b/ui/views/accessibility/ax_view_obj_wrapper.cc
@@ -62,6 +62,9 @@
                                       base::UTF16ToUTF8(description));
   }
 
+  out_node_data->AddStringAttribute(ui::AX_ATTR_CLASS_NAME,
+                                    view_->GetClassName());
+
   out_node_data->location = gfx::RectF(view_->GetBoundsInScreen());
 }
 
diff --git a/ui/views/controls/textfield/textfield.cc b/ui/views/controls/textfield/textfield.cc
index 412f559..7be7cbfa 100644
--- a/ui/views/controls/textfield/textfield.cc
+++ b/ui/views/controls/textfield/textfield.cc
@@ -342,6 +342,8 @@
 void Textfield::SetText(const base::string16& new_text) {
   model_->SetText(new_text);
   OnCaretBoundsChanged();
+  UpdateCursorViewPosition();
+  UpdateCursorVisibility();
   SchedulePaint();
   NotifyAccessibilityEvent(ui::AX_EVENT_VALUE_CHANGED, true);
 }