diff --git a/DEPS b/DEPS
index 19c2241..60d6487 100644
--- a/DEPS
+++ b/DEPS
@@ -78,7 +78,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling Skia
   # and whatever else without interference from each other.
-  'skia_revision': 'd23d8d1d980bfd7afac9ec4bae7607bd65866fe6',
+  'skia_revision': 'c5980d0aa3e97f07a4f5bc413a2c5bc5ed3bc973',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling V8
   # and whatever else without interference from each other.
@@ -90,7 +90,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling ANGLE
   # and whatever else without interference from each other.
-  'angle_revision': 'eeda03b624b9faa369d085dd3fe73bdf94fdc2c5',
+  'angle_revision': '949b4f07fd1ef5b208136fe38327c28c95f18928',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling build tools
   # and whatever else without interference from each other.
@@ -102,7 +102,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling PDFium
   # and whatever else without interference from each other.
-  'pdfium_revision': '5183e8679844eeff2c5dda2a2e02762487429a1f',
+  'pdfium_revision': '0c53b008b4f2f7a790f756d706a00e8de98dfedd',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling openmax_dl
   # and whatever else without interference from each other.
@@ -134,7 +134,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': 'd14d29762cc0d6fd8c4738a8be98a91b965258ec',
+  'catapult_revision': '34323dc0a2a96eab02fc28f64499c8473c473395',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libFuzzer
   # and whatever else without interference from each other.
@@ -475,13 +475,13 @@
   },
 
   'src/third_party/libvpx/source/libvpx':
-    Var('chromium_git') + '/webm/libvpx.git' + '@' +  '8a4336ed2edea09b67f49828df1f8c526a85a7a6',
+    Var('chromium_git') + '/webm/libvpx.git' + '@' +  'bed28a55f593efd3a71a3a9d05cf8bb25d15fa44',
 
   'src/third_party/libwebm/source':
     Var('chromium_git') + '/webm/libwebm.git' + '@' + 'b03c65468b06d097f27235d93d76bfc45f490ede',
 
   'src/third_party/libyuv':
-    Var('chromium_git') + '/libyuv/libyuv.git' + '@' + '263243aadc3c30d548ffc36e6fdb0cc987511cc6',  # from r1687
+    Var('chromium_git') + '/libyuv/libyuv.git' + '@' + '50f9e618fa4bcb0561622fd709bee5da922b0fd4',  # from r1688
 
   'src/third_party/lighttpd': {
       'url': Var('chromium_git') + '/chromium/deps/lighttpd.git' + '@' + Var('lighttpd_revision'),
@@ -640,7 +640,7 @@
     Var('chromium_git') + '/external/khronosgroup/webgl.git' + '@' + 'd458ada06171a85af00367251a4ed55db7fe2018',
 
   'src/third_party/webrtc':
-    Var('webrtc_git') + '/src.git' + '@' + 'f641687a8070f646f6e073020a59bc288ec1b319', # commit position 20628
+    Var('webrtc_git') + '/src.git' + '@' + 'a9329dbae21cabd4b860e729ecd7769f5bec9ac7', # commit position 20628
 
   'src/third_party/xdg-utils': {
       'url': Var('chromium_git') + '/chromium/deps/xdg-utils.git' + '@' + 'd80274d5869b17b8c9067a1022e4416ee7ed5e0d',
diff --git a/android_webview/browser/aw_safe_browsing_resource_throttle.cc b/android_webview/browser/aw_safe_browsing_resource_throttle.cc
index 26f0c282..28dfc8f2 100644
--- a/android_webview/browser/aw_safe_browsing_resource_throttle.cc
+++ b/android_webview/browser/aw_safe_browsing_resource_throttle.cc
@@ -8,8 +8,8 @@
 
 #include "android_webview/browser/aw_contents_client_bridge.h"
 #include "android_webview/browser/aw_safe_browsing_whitelist_manager.h"
+#include "android_webview/browser/aw_url_checker_delegate_impl.h"
 #include "components/safe_browsing/db/v4_protocol_manager_util.h"
-#include "components/safe_browsing/features.h"
 #include "net/url_request/url_request.h"
 
 namespace android_webview {
@@ -38,13 +38,7 @@
   if (!database_manager->IsSupported())
     return nullptr;
 
-  if (base::FeatureList::IsEnabled(safe_browsing::kParallelUrlCheck)) {
-    return new AwSafeBrowsingParallelResourceThrottle(
-        request, resource_type, std::move(database_manager),
-        std::move(ui_manager), whitelist_manager);
-  }
-
-  return new AwSafeBrowsingResourceThrottle(
+  return new AwSafeBrowsingParallelResourceThrottle(
       request, resource_type, std::move(database_manager),
       std::move(ui_manager), whitelist_manager);
 }
@@ -53,56 +47,6 @@
   return request->GetUserData(kCancelledBySafeBrowsingUserDataKey) != nullptr;
 }
 
-AwSafeBrowsingResourceThrottle::AwSafeBrowsingResourceThrottle(
-    net::URLRequest* request,
-    content::ResourceType resource_type,
-    scoped_refptr<safe_browsing::SafeBrowsingDatabaseManager> database_manager,
-    scoped_refptr<AwSafeBrowsingUIManager> ui_manager,
-    AwSafeBrowsingWhitelistManager* whitelist_manager)
-    : safe_browsing::BaseResourceThrottle(
-          request,
-          resource_type,
-          safe_browsing::CreateSBThreatTypeSet(
-              {safe_browsing::SB_THREAT_TYPE_URL_MALWARE,
-               safe_browsing::SB_THREAT_TYPE_URL_PHISHING}),
-          database_manager,
-          ui_manager),
-      request_(request),
-      url_checker_delegate_(
-          new AwUrlCheckerDelegateImpl(std::move(database_manager),
-                                       std::move(ui_manager),
-                                       whitelist_manager)) {}
-
-AwSafeBrowsingResourceThrottle::~AwSafeBrowsingResourceThrottle() = default;
-
-bool AwSafeBrowsingResourceThrottle::CheckUrl(const GURL& gurl) {
-  if (url_checker_delegate_->IsUrlWhitelisted(gurl)) {
-    return true;
-  }
-  return BaseResourceThrottle::CheckUrl(gurl);
-}
-
-void AwSafeBrowsingResourceThrottle::StartDisplayingBlockingPageHelper(
-    security_interstitials::UnsafeResource resource) {
-  const content::ResourceRequestInfo* info =
-      content::ResourceRequestInfo::ForRequest(request_);
-  bool is_main_frame =
-      info && info->GetResourceType() == content::RESOURCE_TYPE_MAIN_FRAME;
-  bool has_user_gesture = info && info->HasUserGesture();
-
-  net::HttpRequestHeaders headers;
-  if (!request_->GetFullRequestHeaders(&headers))
-    headers = request_->extra_request_headers();
-
-  url_checker_delegate_->StartDisplayingBlockingPageHelper(
-      resource, request_->method(), headers, is_main_frame, has_user_gesture);
-}
-
-void AwSafeBrowsingResourceThrottle::CancelResourceLoad() {
-  SetCancelledBySafeBrowsing(request_);
-  BaseResourceThrottle::CancelResourceLoad();
-}
-
 AwSafeBrowsingParallelResourceThrottle::AwSafeBrowsingParallelResourceThrottle(
     net::URLRequest* request,
     content::ResourceType resource_type,
diff --git a/android_webview/browser/aw_safe_browsing_resource_throttle.h b/android_webview/browser/aw_safe_browsing_resource_throttle.h
index 1316072..1be37cf 100644
--- a/android_webview/browser/aw_safe_browsing_resource_throttle.h
+++ b/android_webview/browser/aw_safe_browsing_resource_throttle.h
@@ -6,31 +6,20 @@
 #define ANDROID_WEBVIEW_BROWSER_AW_SAFE_BROWSING_RESOURCE_THROTTLE_H_
 
 #include "android_webview/browser/aw_safe_browsing_ui_manager.h"
-#include "android_webview/browser/aw_url_checker_delegate_impl.h"
-#include "android_webview/browser/net/aw_web_resource_request.h"
 #include "base/macros.h"
-#include "components/safe_browsing/base_resource_throttle.h"
 #include "components/safe_browsing/browser/base_parallel_resource_throttle.h"
 #include "components/safe_browsing/db/database_manager.h"
-#include "components/security_interstitials/content/unsafe_resource.h"
 #include "content/public/common/resource_type.h"
 
 namespace net {
 class URLRequest;
 }
 
-using safe_browsing::ThreatMetadata;
-using safe_browsing::SBThreatType;
-
 namespace android_webview {
 
 class AwSafeBrowsingWhitelistManager;
 
-// Contructs a resource throttle for SafeBrowsing. It returns an
-// AwSafeBrowsingParallelResourceThrottle instance if
-// --enable-features=S13nSafeBrowsingParallelUrlCheck is specified; returns
-// an AwSafeBrowsingResourceThrottle otherwise.
-//
+// Contructs a resource throttle for SafeBrowsing.
 // It returns nullptr if GMS doesn't exist on device or support SafeBrowsing.
 content::ResourceThrottle* MaybeCreateAwSafeBrowsingResourceThrottle(
     net::URLRequest* request,
@@ -41,47 +30,9 @@
 
 bool IsCancelledBySafeBrowsing(const net::URLRequest* request);
 
-class AwSafeBrowsingResourceThrottle
-    : public safe_browsing::BaseResourceThrottle {
- protected:
-  bool CheckUrl(const GURL& url) override;
-
- private:
-  friend content::ResourceThrottle* MaybeCreateAwSafeBrowsingResourceThrottle(
-      net::URLRequest* request,
-      content::ResourceType resource_type,
-      scoped_refptr<safe_browsing::SafeBrowsingDatabaseManager>
-          database_manager,
-      scoped_refptr<AwSafeBrowsingUIManager> ui_manager,
-      AwSafeBrowsingWhitelistManager* whitelist_manager);
-
-  AwSafeBrowsingResourceThrottle(
-      net::URLRequest* request,
-      content::ResourceType resource_type,
-      scoped_refptr<safe_browsing::SafeBrowsingDatabaseManager>
-          database_manager,
-      scoped_refptr<AwSafeBrowsingUIManager> ui_manager,
-      AwSafeBrowsingWhitelistManager* whitelist_manager);
-
-  ~AwSafeBrowsingResourceThrottle() override;
-
-  void StartDisplayingBlockingPageHelper(
-      security_interstitials::UnsafeResource resource) override;
-
-  // safe_browsing::BaseResourceThrottle overrides:
-  void CancelResourceLoad() override;
-
-  net::URLRequest* request_;
-
-  scoped_refptr<safe_browsing::UrlCheckerDelegate> url_checker_delegate_;
-
-  DISALLOW_COPY_AND_ASSIGN(AwSafeBrowsingResourceThrottle);
-};
-
-// Unlike AwSafeBrowsingResourceThrottle, this class never defers starting the
-// URL request or following redirects. If any of the checks for the original URL
-// and redirect chain are not complete by the time the response headers are
-// available, the request is deferred until all the checks are done.
+// AwSafeBrowsingPrallelResourceThrottle uses a WebView-specific
+// safe_browsing::UrlCheckerDelegate implementation with its base class
+// safe_browsing::BaseParallelResourceThrottle.
 class AwSafeBrowsingParallelResourceThrottle
     : public safe_browsing::BaseParallelResourceThrottle {
  private:
diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/AwZoomTest.java b/android_webview/javatests/src/org/chromium/android_webview/test/AwZoomTest.java
index b62ea86..44be493 100644
--- a/android_webview/javatests/src/org/chromium/android_webview/test/AwZoomTest.java
+++ b/android_webview/javatests/src/org/chromium/android_webview/test/AwZoomTest.java
@@ -19,6 +19,7 @@
 import org.chromium.android_webview.AwContents;
 import org.chromium.android_webview.AwSettings;
 import org.chromium.base.ThreadUtils;
+import org.chromium.base.test.util.DisabledTest;
 import org.chromium.base.test.util.Feature;
 import org.chromium.base.test.util.RetryOnFailure;
 
@@ -153,6 +154,7 @@
     }
 
     @Test
+    @DisabledTest(message = "crbug.com/800015")
     @SmallTest
     @Feature({"AndroidWebView"})
     @RetryOnFailure // Flaky (times out). See http://crbug.com/661879.
@@ -164,6 +166,7 @@
     // According to Android CTS test, zoomIn/Out must work
     // even if supportZoom is turned off.
     @Test
+    @DisabledTest(message = "crbug.com/800015")
     @SmallTest
     @Feature({"AndroidWebView"})
     @RetryOnFailure
diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/LoadUrlTest.java b/android_webview/javatests/src/org/chromium/android_webview/test/LoadUrlTest.java
index b54a36f..85651e1 100644
--- a/android_webview/javatests/src/org/chromium/android_webview/test/LoadUrlTest.java
+++ b/android_webview/javatests/src/org/chromium/android_webview/test/LoadUrlTest.java
@@ -8,6 +8,7 @@
 
 import android.support.test.InstrumentationRegistry;
 import android.support.test.filters.SmallTest;
+import android.util.Base64;
 import android.util.Pair;
 
 import org.json.JSONArray;
@@ -78,8 +79,9 @@
     @Feature({"AndroidWebView"})
     public void testDataUrlBase64() throws Throwable {
         final String expectedTitle = "dataUrlTestBase64";
-        final String data = "PGh0bWw+PGhlYWQ+PHRpdGxlPmRhdGFVcmxUZXN0QmFzZTY0PC90aXRsZT48"
-                + "L2hlYWQ+PC9odG1sPg==";
+        final String unencodedData =
+                "<html><head><title>" + expectedTitle + "</title></head><body>foo</body></html>";
+        final String data = Base64.encodeToString(unencodedData.getBytes(), Base64.NO_PADDING);
 
         final TestAwContentsClient contentsClient = new TestAwContentsClient();
         final AwTestContainerView testContainerView =
@@ -93,6 +95,31 @@
     @Test
     @SmallTest
     @Feature({"AndroidWebView"})
+    public void testDataUrlBase64WithTrickyCharacters() throws Throwable {
+        // We want all of these characters to be treated literally (e.g. "%3f" should be "%3f")
+        final String expectedTextContent =
+                "This text\nhas tricky characters: %3f!#$&'()*+,\\/:;=?@[]";
+        final String unencodedData =
+                "<html><body><pre>" + expectedTextContent + "</pre></body></html>";
+        final String data = Base64.encodeToString(unencodedData.getBytes(), Base64.NO_PADDING);
+
+        final TestAwContentsClient contentsClient = new TestAwContentsClient();
+        final AwTestContainerView testContainerView =
+                mActivityTestRule.createAwTestContainerViewOnMainSync(contentsClient);
+        final AwContents awContents = testContainerView.getAwContents();
+        mActivityTestRule.enableJavaScriptOnUiThread(awContents);
+        mActivityTestRule.loadDataSync(
+                awContents, contentsClient.getOnPageFinishedHelper(), data, "text/html", true);
+        String textContent =
+                mActivityTestRule.getJavaScriptResultBodyTextContent(awContents, contentsClient);
+        // The JavaScript result escapes special characters - we need to unescape them.
+        textContent = textContent.replace("\\n", "\n").replace("\\\\", "\\");
+        Assert.assertEquals(expectedTextContent, textContent);
+    }
+
+    @Test
+    @SmallTest
+    @Feature({"AndroidWebView"})
     public void testDataUrlCharset() throws Throwable {
         // Note that the \u00a3 (pound sterling) is the important character in the following
         // string as it's not in the US_ASCII character set.
diff --git a/ash/BUILD.gn b/ash/BUILD.gn
index 1f844d78..25fa7898 100644
--- a/ash/BUILD.gn
+++ b/ash/BUILD.gn
@@ -108,6 +108,8 @@
     "display/display_error_observer_chromeos.h",
     "display/display_move_window_util.cc",
     "display/display_move_window_util.h",
+    "display/display_prefs.cc",
+    "display/display_prefs.h",
     "display/display_shutdown_observer.cc",
     "display/display_shutdown_observer.h",
     "display/display_synchronizer.cc",
diff --git a/ash/app_list/model/app_list_folder_item.cc b/ash/app_list/model/app_list_folder_item.cc
index 9378311..14c622c 100644
--- a/ash/app_list/model/app_list_folder_item.cc
+++ b/ash/app_list/model/app_list_folder_item.cc
@@ -36,10 +36,6 @@
                                                         folder_icon_bounds);
 }
 
-void AppListFolderItem::Activate(int event_flags) {
-  // Folder handling is implemented by the View, so do nothing.
-}
-
 // static
 const char AppListFolderItem::kItemType[] = "FolderItem";
 
@@ -47,11 +43,6 @@
   return AppListFolderItem::kItemType;
 }
 
-ui::MenuModel* AppListFolderItem::GetContextMenuModel() {
-  // TODO(stevenjb/jennyz): Implement.
-  return NULL;
-}
-
 AppListItem* AppListFolderItem::FindChildItem(const std::string& id) {
   return item_list_->FindItem(id);
 }
diff --git a/ash/app_list/model/app_list_folder_item.h b/ash/app_list/model/app_list_folder_item.h
index d138775c..5bc3a29 100644
--- a/ash/app_list/model/app_list_folder_item.h
+++ b/ash/app_list/model/app_list_folder_item.h
@@ -7,6 +7,7 @@
 
 #include <stddef.h>
 
+#include <memory>
 #include <string>
 #include <vector>
 
@@ -65,9 +66,7 @@
   FolderType folder_type() const { return folder_type_; }
 
   // AppListItem overrides:
-  void Activate(int event_flags) override;
   const char* GetItemType() const override;
-  ui::MenuModel* GetContextMenuModel() override;
   AppListItem* FindChildItem(const std::string& id) override;
   size_t ChildItemCount() const override;
   bool CompareForTest(const AppListItem* other) const override;
diff --git a/ash/app_list/model/app_list_item.cc b/ash/app_list/model/app_list_item.cc
index d3a428b..50aed61 100644
--- a/ash/app_list/model/app_list_item.cc
+++ b/ash/app_list/model/app_list_item.cc
@@ -57,17 +57,11 @@
   observers_.RemoveObserver(observer);
 }
 
-void AppListItem::Activate(int event_flags) {}
-
 const char* AppListItem::GetItemType() const {
   static const char* app_type = "";
   return app_type;
 }
 
-ui::MenuModel* AppListItem::GetContextMenuModel() {
-  return NULL;
-}
-
 AppListItem* AppListItem::FindChildItem(const std::string& id) {
   return NULL;
 }
diff --git a/ash/app_list/model/app_list_item.h b/ash/app_list/model/app_list_item.h
index 3091adef..4fe28eb 100644
--- a/ash/app_list/model/app_list_item.h
+++ b/ash/app_list/model/app_list_item.h
@@ -20,10 +20,6 @@
 class FastShowPickler;
 class ChromeAppListModelUpdater;
 
-namespace ui {
-class MenuModel;
-}
-
 namespace app_list {
 
 class AppListItemList;
@@ -77,18 +73,10 @@
   void AddObserver(AppListItemObserver* observer);
   void RemoveObserver(AppListItemObserver* observer);
 
-  // Activates (opens) the item. Does nothing by default.
-  virtual void Activate(int event_flags);
-
   // Returns a static const char* identifier for the subclass (defaults to "").
   // Pointers can be compared for quick type checking.
   virtual const char* GetItemType() const;
 
-  // Returns the context menu model for this item, or NULL if there is currently
-  // no menu for the item (e.g. during install).
-  // Note the returned menu model is owned by this item.
-  virtual ui::MenuModel* GetContextMenuModel();
-
   // Returns the item matching |id| contained in this item (e.g. if the item is
   // a folder), or NULL if the item was not found or this is not a container.
   virtual AppListItem* FindChildItem(const std::string& id);
diff --git a/chrome/browser/chromeos/display/display_prefs.cc b/ash/display/display_prefs.cc
similarity index 93%
rename from chrome/browser/chromeos/display/display_prefs.cc
rename to ash/display/display_prefs.cc
index 1b70215..85808ade 100644
--- a/chrome/browser/chromeos/display/display_prefs.cc
+++ b/ash/display/display_prefs.cc
@@ -2,11 +2,14 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/chromeos/display/display_prefs.h"
+#include "ash/display/display_prefs.h"
 
 #include <stddef.h>
 
+#include "ash/public/cpp/ash_pref_names.h"
+#include "ash/session/session_controller.h"
 #include "ash/shell.h"
+#include "base/command_line.h"
 #include "base/stl_util.h"
 #include "base/strings/string16.h"
 #include "base/strings/string_number_conversions.h"
@@ -14,11 +17,10 @@
 #include "base/strings/string_util.h"
 #include "base/sys_info.h"
 #include "base/values.h"
-#include "chrome/common/pref_names.h"
+#include "chromeos/chromeos_switches.h"
 #include "components/prefs/pref_registry_simple.h"
 #include "components/prefs/pref_service.h"
 #include "components/prefs/scoped_user_pref_update.h"
-#include "components/user_manager/user_manager.h"
 #include "third_party/cros_system_api/dbus/service_constants.h"
 #include "ui/display/manager/display_layout_store.h"
 #include "ui/display/manager/display_manager.h"
@@ -30,7 +32,9 @@
 #include "url/url_canon.h"
 #include "url/url_util.h"
 
-namespace chromeos {
+using chromeos::DisplayPowerState;
+
+namespace ash {
 
 namespace {
 
@@ -162,11 +166,14 @@
 // Returns true id the current user can write display preferences to
 // Local State.
 bool UserCanSaveDisplayPreference() {
-  user_manager::UserManager* user_manager = user_manager::UserManager::Get();
-  return user_manager->IsUserLoggedIn() &&
-         (user_manager->IsLoggedInAsUserWithGaiaAccount() ||
-          user_manager->IsLoggedInAsSupervisedUser() ||
-          user_manager->IsLoggedInAsKioskApp());
+  SessionController* controller = ash::Shell::Get()->session_controller();
+  auto user_type = controller->GetUserType();
+  if (!user_type)
+    return false;
+  return *user_type == user_manager::USER_TYPE_REGULAR ||
+         *user_type == user_manager::USER_TYPE_CHILD ||
+         *user_type == user_manager::USER_TYPE_SUPERVISED ||
+         *user_type == user_manager::USER_TYPE_KIOSK_APP;
 }
 
 void LoadDisplayLayouts(PrefService* local_state) {
@@ -573,8 +580,6 @@
     pref_data->GetList().emplace_back(base::Value(base::Int64ToString(id)));
 }
 
-DisplayPrefs* g_display_prefs = nullptr;
-
 }  // namespace
 
 // static
@@ -590,20 +595,35 @@
   registry->RegisterListPref(prefs::kExternalDisplayMirrorInfo);
 }
 
-// static
-DisplayPrefs* DisplayPrefs::Get() {
-  CHECK(g_display_prefs);
-  return g_display_prefs;
+DisplayPrefs::DisplayPrefs() {
+  ash::Shell::Get()->AddShellObserver(this);
 }
 
-DisplayPrefs::DisplayPrefs(PrefService* local_state)
-    : local_state_(local_state) {
-  g_display_prefs = this;
+DisplayPrefs::~DisplayPrefs() {
+  ash::Shell::Get()->RemoveShellObserver(this);
 }
 
-DisplayPrefs::~DisplayPrefs() = default;
+void DisplayPrefs::OnLocalStatePrefServiceInitialized(
+    PrefService* pref_service) {
+  if (local_state_)
+    return;
+
+  bool first_run_after_boot = base::CommandLine::ForCurrentProcess()->HasSwitch(
+      chromeos::switches::kFirstExecAfterBoot);
+  LoadDisplayPreferences(first_run_after_boot, pref_service);
+
+  if (store_requested_) {
+    StoreDisplayPrefs();
+    store_requested_ = false;
+  }
+}
 
 void DisplayPrefs::StoreDisplayPrefs() {
+  if (!local_state_) {
+    store_requested_ = true;
+    return;
+  }
+
   // Stores the power state regardless of the login status, because the power
   // state respects to the current status (close/open) of the lid which can be
   // changed in any situation. See http://crbug.com/285360
@@ -622,15 +642,17 @@
   StoreExternalDisplayMirrorInfo(local_state_);
 }
 
-void DisplayPrefs::LoadDisplayPreferences(bool first_run_after_boot) {
-  LoadDisplayLayouts(local_state_);
-  LoadDisplayProperties(local_state_);
-  LoadExternalDisplayMirrorInfo(local_state_);
-  LoadDisplayRotationState(local_state_);
-  LoadDisplayTouchAssociations(local_state_);
+void DisplayPrefs::LoadDisplayPreferences(bool first_run_after_boot,
+                                          PrefService* local_state) {
+  local_state_ = local_state;
+  LoadDisplayLayouts(local_state);
+  LoadDisplayProperties(local_state);
+  LoadExternalDisplayMirrorInfo(local_state);
+  LoadDisplayRotationState(local_state);
+  LoadDisplayTouchAssociations(local_state);
   if (!first_run_after_boot) {
     // Restore DisplayPowerState:
-    std::string value = local_state_->GetString(prefs::kDisplayPowerState);
+    std::string value = local_state->GetString(prefs::kDisplayPowerState);
     chromeos::DisplayPowerState power_state;
     if (GetDisplayPowerStateFromString(value, &power_state)) {
       ash::Shell::Get()->display_configurator()->SetInitialDisplayPower(
@@ -677,4 +699,4 @@
   return ParseTouchCalibrationStringValue(str, point_pair_quad);
 }
 
-}  // namespace chromeos
+}  // namespace ash
diff --git a/ash/display/display_prefs.h b/ash/display/display_prefs.h
new file mode 100644
index 0000000..8fea18f
--- /dev/null
+++ b/ash/display/display_prefs.h
@@ -0,0 +1,86 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef ASH_DISPLAY_DISPLAY_PREFS_H_
+#define ASH_DISPLAY_DISPLAY_PREFS_H_
+
+#include <stdint.h>
+#include <array>
+
+#include "ash/ash_export.h"
+#include "ash/shell_observer.h"
+#include "third_party/cros_system_api/dbus/service_constants.h"
+#include "ui/display/display.h"
+#include "ui/display/display_layout.h"
+
+class PrefRegistrySimple;
+class PrefService;
+
+namespace gfx {
+class Point;
+}
+
+namespace display {
+struct TouchCalibrationData;
+}
+
+namespace ash {
+
+class DisplayPrefsTest;
+
+// Manages display preference settings. Settings are stored in the local state
+// for the session.
+class ASH_EXPORT DisplayPrefs : public ShellObserver {
+ public:
+  // Registers the prefs associated with display settings.
+  static void RegisterLocalStatePrefs(PrefRegistrySimple* registry);
+
+  DisplayPrefs();
+  ~DisplayPrefs() override;
+
+  // ShellObserver
+  void OnLocalStatePrefServiceInitialized(PrefService* pref_service) override;
+
+  // Stores all current displays preferences or queues a request until
+  // LoadDisplayPreferences is called..
+  void StoreDisplayPrefs();
+
+  // Test helper methods.
+
+  void StoreDisplayRotationPrefsForTest(display::Display::Rotation rotation,
+                                        bool rotation_lock);
+  void StoreDisplayLayoutPrefForTest(const display::DisplayIdList& list,
+                                     const display::DisplayLayout& layout);
+  void StoreDisplayPowerStateForTest(chromeos::DisplayPowerState power_state);
+  void LoadTouchAssociationPreferenceForTest();
+  void StoreLegacyTouchDataForTest(int64_t display_id,
+                                   const display::TouchCalibrationData& data);
+  // Parses the marshalled string data stored in local preferences for
+  // calibration points and populates |point_pair_quad| using the unmarshalled
+  // data. See TouchCalibrationData in Managed display info.
+  bool ParseTouchCalibrationStringForTest(
+      const std::string& str,
+      std::array<std::pair<gfx::Point, gfx::Point>, 4>* point_pair_quad);
+
+ protected:
+  friend class DisplayPrefsTest;
+
+  // Loads display preferences from |local_state| and sets |local_state_|.
+  // |first_run_after_boot| is used to determine whether power state preferences
+  // should be applied.
+  void LoadDisplayPreferences(bool first_run_after_boot,
+                              PrefService* local_state);
+
+ private:
+  // Set in LoadDisplayPreferencse. If null, StoreDisplayPrefs just sets
+  // store_requested_.
+  PrefService* local_state_ = nullptr;
+  bool store_requested_ = false;
+
+  DISALLOW_COPY_AND_ASSIGN(DisplayPrefs);
+};
+
+}  // namespace ash
+
+#endif  // ASH_DISPLAY_DISPLAY_PREFS_H_
diff --git a/ash/display/resolution_notification_controller.h b/ash/display/resolution_notification_controller.h
index 130105b..aa18794 100644
--- a/ash/display/resolution_notification_controller.h
+++ b/ash/display/resolution_notification_controller.h
@@ -76,7 +76,7 @@
  private:
   friend class ResolutionNotificationControllerTest;
   FRIEND_TEST_ALL_PREFIXES(ResolutionNotificationControllerTest, Timeout);
-  FRIEND_TEST_ALL_PREFIXES(chromeos::DisplayPrefsTest, PreventStore);
+  FRIEND_TEST_ALL_PREFIXES(DisplayPrefsTest, PreventStore);
 
   // A struct to bundle the data for a single resolution change.
   struct ResolutionChangeInfo;
diff --git a/ash/public/cpp/ash_pref_names.cc b/ash/public/cpp/ash_pref_names.cc
index f5e57e5..0846a5b9 100644
--- a/ash/public/cpp/ash_pref_names.cc
+++ b/ash/public/cpp/ash_pref_names.cc
@@ -67,6 +67,23 @@
 // regardless of the state of a11y features.
 const char kShouldAlwaysShowAccessibilityMenu[] = "settings.a11y.enable_menu";
 
+// Power state of the current displays from the last run.
+const char kDisplayPowerState[] = "settings.display.power_state";
+// A dictionary pref that stores per display preferences.
+const char kDisplayProperties[] = "settings.display.properties";
+// A dictionary pref that specifies the state of the rotation lock, and the
+// display orientation, for the internal display.
+const char kDisplayRotationLock[] = "settings.display.rotation_lock";
+// A dictionary pref that stores the touch associations for the device.
+const char kDisplayTouchAssociations[] = "settings.display.touch_associations";
+// A list pref that stores the mirror info for each external display.
+const char kExternalDisplayMirrorInfo[] =
+    "settings.display.external_display_mirror_info";
+// A dictionary pref that specifies per-display layout/offset information.
+// Its key is the ID of the display and its value is a dictionary for the
+// layout/offset information.
+const char kSecondaryDisplays[] = "settings.display.secondary_displays";
+
 // A boolean pref which stores whether a stylus has been seen before.
 const char kHasSeenStylus[] = "ash.has_seen_stylus";
 // A boolean pref which stores whether a the palette warm welcome bubble
diff --git a/ash/public/cpp/ash_pref_names.h b/ash/public/cpp/ash_pref_names.h
index 72106378..3dca6c1 100644
--- a/ash/public/cpp/ash_pref_names.h
+++ b/ash/public/cpp/ash_pref_names.h
@@ -30,6 +30,13 @@
 ASH_PUBLIC_EXPORT extern const char kAccessibilitySwitchAccessEnabled[];
 ASH_PUBLIC_EXPORT extern const char kShouldAlwaysShowAccessibilityMenu[];
 
+ASH_PUBLIC_EXPORT extern const char kDisplayPowerState[];
+ASH_PUBLIC_EXPORT extern const char kDisplayProperties[];
+ASH_PUBLIC_EXPORT extern const char kDisplayRotationLock[];
+ASH_PUBLIC_EXPORT extern const char kDisplayTouchAssociations[];
+ASH_PUBLIC_EXPORT extern const char kExternalDisplayMirrorInfo[];
+ASH_PUBLIC_EXPORT extern const char kSecondaryDisplays[];
+
 ASH_PUBLIC_EXPORT extern const char kHasSeenStylus[];
 ASH_PUBLIC_EXPORT extern const char kShownPaletteWelcomeBubble[];
 ASH_PUBLIC_EXPORT extern const char kEnableStylusTools[];
diff --git a/ash/shell.cc b/ash/shell.cc
index 07ee6a6f..a09ca38 100644
--- a/ash/shell.cc
+++ b/ash/shell.cc
@@ -25,6 +25,7 @@
 #include "ash/display/display_color_manager_chromeos.h"
 #include "ash/display/display_configuration_controller.h"
 #include "ash/display/display_error_observer_chromeos.h"
+#include "ash/display/display_prefs.h"
 #include "ash/display/display_shutdown_observer.h"
 #include "ash/display/event_transformation_handler.h"
 #include "ash/display/mouse_cursor_event_filter.h"
@@ -373,6 +374,7 @@
 
 // static
 void Shell::RegisterLocalStatePrefs(PrefRegistrySimple* registry) {
+  DisplayPrefs::RegisterLocalStatePrefs(registry);
   PaletteTray::RegisterLocalStatePrefs(registry);
   WallpaperController::RegisterLocalStatePrefs(registry);
   BluetoothPowerController::RegisterLocalStatePrefs(registry);
@@ -661,6 +663,7 @@
   user_metrics_recorder_->OnShellShuttingDown();
 
   shell_delegate_->PreShutdown();
+  display_prefs_.reset();
 
   // Remove the focus from any window. This will prevent overhead and side
   // effects (e.g. crashes) from changing focus during shutdown.
@@ -908,12 +911,12 @@
         base::WrapUnique(native_cursor_manager_));
   }
 
-  // TODO(stevenjb): ChromeShellDelegate::PreInit currently handles
-  // DisplayPreference initialization, required for InitializeDisplayManager.
-  // Before we can move that code into ash/display where it belongs, we need to
-  // wait for |lcoal_state_| to be set in OnLocalStatePrefServiceInitialized
-  // before initializing DisplayPreferences (and therefore DisplayManager).
-  // http://crbug.com/678949.
+  // Construct DisplayPrefs here so that display_prefs()->StoreDisplayPrefs()
+  // can safely be called. DisplayPrefs will be loaded once |local_state_|
+  // is available and store requests will be queued in the meanwhile.
+  display_prefs_ = std::make_unique<DisplayPrefs>();
+
+  // TODO(stevenjb): Move DisplayConfigurationObserver to Ash also.
   shell_delegate_->PreInit();
 
   InitializeDisplayManager();
@@ -1283,18 +1286,30 @@
       shelf_window_watcher_ =
           std::make_unique<ShelfWindowWatcher>(shelf_model());
   }
-  // Recreates keyboard on user profile change, to refresh keyboard
-  // extensions with the new profile and the extensions call proper IME.
-  // |LOGGED_IN_NOT_ACTIVE| is needed so that the virtual keyboard works on
-  // supervised user creation. crbug.com/712873
-  // |ACTIVE| is also needed for guest user workflow.
+
   // NOTE: keyboard::IsKeyboardEnabled() is false in mash, but may not be in
   // unit tests. crbug.com/646565.
-  if ((state == session_manager::SessionState::LOGGED_IN_NOT_ACTIVE ||
-       state == session_manager::SessionState::ACTIVE) &&
-      keyboard::IsKeyboardEnabled()) {
-    // Recreate the keyboard after initial login and after multiprofile login.
-    CreateKeyboard();
+  if (keyboard::IsKeyboardEnabled()) {
+    switch (state) {
+      case session_manager::SessionState::OOBE:
+      case session_manager::SessionState::LOGIN_PRIMARY:
+        // Ensure that the keyboard controller is activated for the primary
+        // window.
+        GetPrimaryRootWindowController()->ActivateKeyboard(
+            keyboard::KeyboardController::GetInstance());
+        break;
+      case session_manager::SessionState::LOGGED_IN_NOT_ACTIVE:
+      case session_manager::SessionState::ACTIVE:
+        // Recreate the keyboard on user profile change, to refresh keyboard
+        // extensions with the new profile and ensure the extensions call the
+        // proper IME. |LOGGED_IN_NOT_ACTIVE| is needed so that the virtual
+        // keyboard works on supervised user creation, http://crbug.com/712873.
+        // |ACTIVE| is also needed for guest user workflow.
+        CreateKeyboard();
+        break;
+      default:
+        break;
+    }
   }
 
   shell_port_->UpdateSystemModalAndBlockingContainers();
diff --git a/ash/shell.h b/ash/shell.h
index b8e87b6b..b4dad85 100644
--- a/ash/shell.h
+++ b/ash/shell.h
@@ -94,6 +94,7 @@
 class DisplayColorManager;
 class DisplayConfigurationController;
 class DisplayErrorObserver;
+class DisplayPrefs;
 class DisplayShutdownObserver;
 class DragDropController;
 class EventClientImpl;
@@ -330,6 +331,7 @@
   ::wm::CursorManager* cursor_manager() { return cursor_manager_.get(); }
 
   display::DisplayManager* display_manager() { return display_manager_.get(); }
+  DisplayPrefs* display_prefs() { return display_prefs_.get(); }
   DisplayConfigurationController* display_configuration_controller() {
     return display_configuration_controller_.get();
   }
@@ -725,6 +727,7 @@
   std::unique_ptr<::wm::AcceleratorFilter> accelerator_filter_;
 
   std::unique_ptr<display::DisplayManager> display_manager_;
+  std::unique_ptr<DisplayPrefs> display_prefs_;
   std::unique_ptr<DisplayConfigurationController>
       display_configuration_controller_;
 
diff --git a/ash/shell/app_list.cc b/ash/shell/app_list.cc
index ac786b1..472dc07 100644
--- a/ash/shell/app_list.cc
+++ b/ash/shell/app_list.cc
@@ -129,8 +129,7 @@
     }
   }
 
-  // AppListItem
-  void Activate(int event_flags) override { ActivateItem(type_, event_flags); }
+  void Activate(int event_flags) { ActivateItem(type_, event_flags); }
 
  private:
   Type type_;
@@ -293,6 +292,18 @@
     NOTIMPLEMENTED();
   }
 
+  void ActivateItem(const std::string& id, int event_flags) override {
+    WindowTypeShelfItem* item =
+        static_cast<WindowTypeShelfItem*>(model_->FindItem(id));
+    if (!item)
+      return;
+    item->Activate(event_flags);
+  }
+
+  ui::MenuModel* GetContextMenuModel(const std::string& id) override {
+    return nullptr;
+  }
+
   void AddObserver(app_list::AppListViewDelegateObserver* observer) override {
     NOTIMPLEMENTED();
   }
diff --git a/base/allocator/partition_allocator/page_allocator.cc b/base/allocator/partition_allocator/page_allocator.cc
index 8fc4c6d..61cd43b 100644
--- a/base/allocator/partition_allocator/page_allocator.cc
+++ b/base/allocator/partition_allocator/page_allocator.cc
@@ -208,38 +208,43 @@
   DCHECK(!(reinterpret_cast<uintptr_t>(address) & align_offset_mask));
 
   // If the client passed null as the address, choose a good one.
-  if (!address) {
+  if (address == nullptr) {
     address = GetRandomPageBase();
     address = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(address) &
                                       align_base_mask);
   }
 
   // First try to force an exact-size, aligned allocation from our random base.
-  for (int count = 0; count < 3; ++count) {
+#if defined(ARCH_CPU_32_BITS)
+  // On 32 bit systems, first try one random aligned address, and then try an
+  // aligned address derived from the value of |ret|.
+  constexpr int kExactSizeTries = 2;
+#else
+  // On 64 bit systems, try 3 random aligned addresses.
+  constexpr int kExactSizeTries = 3;
+#endif
+  for (int i = 0; i < kExactSizeTries; ++i) {
     void* ret = AllocPagesIncludingReserved(address, length, page_accessibility,
                                             commit);
-    if (ret) {
+    if (ret != nullptr) {
       // If the alignment is to our liking, we're done.
       if (!(reinterpret_cast<uintptr_t>(ret) & align_offset_mask))
         return ret;
       // Free the memory and try again.
       FreePages(ret, length);
-#if defined(ARCH_CPU_32_BITS)
-      // For small address spaces, try an aligned hint in the free range.
-      address = reinterpret_cast<void*>(
-          (reinterpret_cast<uintptr_t>(ret) + align) & align_base_mask);
-#endif
     } else {
-      // |ret| is null; we're OOM when an unhinted allocation fails.
+      // |ret| is null; if this try was unhinted, we're OOM.
       if (kHintIsAdvisory || address == nullptr)
         return nullptr;
-#if defined(ARCH_CPU_32_BITS)
-      // On 32-bit systems, let the OS choose the base.
-      address = nullptr;
-#endif
     }
 
-#if !defined(ARCH_CPU_32_BITS)
+#if defined(ARCH_CPU_32_BITS)
+    // For small address spaces, try the first aligned address >= |ret|. Note
+    // |ret| may be null, in which case |address| becomes null.
+    address = reinterpret_cast<void*>(
+        (reinterpret_cast<uintptr_t>(ret) + align_offset_mask) &
+        align_base_mask);
+#else  // defined(ARCH_CPU_64_BITS)
     // Keep trying random addresses on systems that have a large address space.
     address = GetRandomPageBase();
     address = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(address) &
@@ -259,8 +264,9 @@
                                       commit);
     // The retries are for Windows, where a race can steal our mapping on
     // resize.
-  } while (ret && (ret = TrimMapping(ret, try_length, length, align,
-                                     page_accessibility, commit)) == nullptr);
+  } while (ret != nullptr &&
+           (ret = TrimMapping(ret, try_length, length, align,
+                              page_accessibility, commit)) == nullptr);
 
   return ret;
 }
diff --git a/base/files/file_unittest.cc b/base/files/file_unittest.cc
index c1027f7c..1bc09fa 100644
--- a/base/files/file_unittest.cc
+++ b/base/files/file_unittest.cc
@@ -39,6 +39,7 @@
     File file(file_path, base::File::FLAG_OPEN | base::File::FLAG_READ);
     EXPECT_FALSE(file.IsValid());
     EXPECT_EQ(base::File::FILE_ERROR_NOT_FOUND, file.error_details());
+    EXPECT_EQ(base::File::FILE_ERROR_NOT_FOUND, base::File::GetLastFileError());
   }
 
   {
@@ -80,6 +81,7 @@
     EXPECT_FALSE(file.IsValid());
     EXPECT_FALSE(file.created());
     EXPECT_EQ(base::File::FILE_ERROR_EXISTS, file.error_details());
+    EXPECT_EQ(base::File::FILE_ERROR_EXISTS, base::File::GetLastFileError());
   }
 
   {
diff --git a/base/files/file_win.cc b/base/files/file_win.cc
index a9d322f..d7bffc3b 100644
--- a/base/files/file_win.cc
+++ b/base/files/file_win.cc
@@ -286,6 +286,7 @@
   switch (last_error) {
     case ERROR_SHARING_VIOLATION:
       return FILE_ERROR_IN_USE;
+    case ERROR_ALREADY_EXISTS:
     case ERROR_FILE_EXISTS:
       return FILE_ERROR_EXISTS;
     case ERROR_FILE_NOT_FOUND:
diff --git a/base/optional.h b/base/optional.h
index 7e039c6f..f6619a5 100644
--- a/base/optional.h
+++ b/base/optional.h
@@ -33,22 +33,29 @@
 namespace internal {
 
 template <typename T, bool = std::is_trivially_destructible<T>::value>
-struct OptionalStorage {
+struct OptionalStorageBase {
   // Initializing |empty_| here instead of using default member initializing
   // to avoid errors in g++ 4.8.
-  constexpr OptionalStorage() : empty_('\0') {}
+  constexpr OptionalStorageBase() : empty_('\0') {}
 
   template <class... Args>
-  constexpr explicit OptionalStorage(in_place_t, Args&&... args)
+  constexpr explicit OptionalStorageBase(in_place_t, Args&&... args)
       : is_null_(false), value_(std::forward<Args>(args)...) {}
 
   // When T is not trivially destructible we must call its
   // destructor before deallocating its memory.
-  ~OptionalStorage() {
+  ~OptionalStorageBase() {
     if (!is_null_)
       value_.~T();
   }
 
+  template <class... Args>
+  void Init(Args&&... args) {
+    DCHECK(is_null_);
+    ::new (&value_) T(std::forward<Args>(args)...);
+    is_null_ = false;
+  }
+
   bool is_null_ = true;
   union {
     // |empty_| exists so that the union will always be initialized, even when
@@ -60,19 +67,26 @@
 };
 
 template <typename T>
-struct OptionalStorage<T, true> {
+struct OptionalStorageBase<T, true /* trivially destructible */> {
   // Initializing |empty_| here instead of using default member initializing
   // to avoid errors in g++ 4.8.
-  constexpr OptionalStorage() : empty_('\0') {}
+  constexpr OptionalStorageBase() : empty_('\0') {}
 
   template <class... Args>
-  constexpr explicit OptionalStorage(in_place_t, Args&&... args)
+  constexpr explicit OptionalStorageBase(in_place_t, Args&&... args)
       : is_null_(false), value_(std::forward<Args>(args)...) {}
 
   // When T is trivially destructible (i.e. its destructor does nothing) there
   // is no need to call it. Explicitly defaulting the destructor means it's not
   // user-provided. Those two together make this destructor trivial.
-  ~OptionalStorage() = default;
+  ~OptionalStorageBase() = default;
+
+  template <class... Args>
+  void Init(Args&&... args) {
+    DCHECK(is_null_);
+    ::new (&value_) T(std::forward<Args>(args)...);
+    is_null_ = false;
+  }
 
   bool is_null_ = true;
   union {
@@ -84,6 +98,93 @@
   };
 };
 
+// Implement conditional constexpr copy and move constructors. These are
+// constexpr if is_trivially_{copy,move}_constructible<T>::value is true
+// respectively. If each is true, the corresponding constructor is defined as
+// "= default;", which generates a constexpr constructor (In this case,
+// the condition of constexpr-ness is satisfied because the base class also has
+// compiler generated constexpr {copy,move} constructors). Note that
+// placement-new is prohibited in constexpr.
+template <typename T,
+          bool = std::is_trivially_copy_constructible<T>::value,
+          bool = std::is_trivially_move_constructible<T>::value>
+struct OptionalStorage : OptionalStorageBase<T> {
+  // This is no trivially {copy,move} constructible case. Other cases are
+  // defined below as specializations.
+
+  // Accessing the members of template base class requires explicit
+  // declaration.
+  using OptionalStorageBase<T>::is_null_;
+  using OptionalStorageBase<T>::value_;
+  using OptionalStorageBase<T>::Init;
+
+  // Inherit constructors (specifically, the in_place constructor).
+  using OptionalStorageBase<T>::OptionalStorageBase;
+
+  // User defined constructor deletes the default constructor.
+  // Define it explicitly.
+  OptionalStorage() = default;
+
+  OptionalStorage(const OptionalStorage& other) {
+    if (!other.is_null_)
+      Init(other.value_);
+  }
+
+  OptionalStorage(OptionalStorage&& other) {
+    if (!other.is_null_)
+      Init(std::move(other.value_));
+  }
+};
+
+template <typename T>
+struct OptionalStorage<T,
+                       true /* trivially copy constructible */,
+                       false /* trivially move constructible */>
+    : OptionalStorageBase<T> {
+  using OptionalStorageBase<T>::is_null_;
+  using OptionalStorageBase<T>::value_;
+  using OptionalStorageBase<T>::Init;
+  using OptionalStorageBase<T>::OptionalStorageBase;
+
+  OptionalStorage() = default;
+  OptionalStorage(const OptionalStorage& other) = default;
+
+  OptionalStorage(OptionalStorage&& other) {
+    if (!other.is_null_)
+      Init(std::move(other.value_));
+  }
+};
+
+template <typename T>
+struct OptionalStorage<T,
+                       false /* trivially copy constructible */,
+                       true /* trivially move constructible */>
+    : OptionalStorageBase<T> {
+  using OptionalStorageBase<T>::is_null_;
+  using OptionalStorageBase<T>::value_;
+  using OptionalStorageBase<T>::Init;
+  using OptionalStorageBase<T>::OptionalStorageBase;
+
+  OptionalStorage() = default;
+  OptionalStorage(OptionalStorage&& other) = default;
+
+  OptionalStorage(const OptionalStorage& other) {
+    if (!other.is_null_)
+      Init(other.value_);
+  }
+};
+
+template <typename T>
+struct OptionalStorage<T,
+                       true /* trivially copy constructible */,
+                       true /* trivially move constructible */>
+    : OptionalStorageBase<T> {
+  // If both trivially {copy,move} constructible are true, it is not necessary
+  // to use user-defined constructors. So, just inheriting constructors
+  // from the base class works.
+  using OptionalStorageBase<T>::OptionalStorageBase;
+};
+
 // Base class to support conditionally usable copy-/move- constructors
 // and assign operators.
 template <typename T>
@@ -93,17 +194,8 @@
   // because of C++ language restriction.
  protected:
   constexpr OptionalBase() = default;
-
-  // TODO(dcheng): Make these constexpr iff T is trivially constructible.
-  OptionalBase(const OptionalBase& other) {
-    if (!other.storage_.is_null_)
-      Init(other.storage_.value_);
-  }
-
-  OptionalBase(OptionalBase&& other) {
-    if (!other.storage_.is_null_)
-      Init(std::move(other.storage_.value_));
-  }
+  constexpr OptionalBase(const OptionalBase& other) = default;
+  constexpr OptionalBase(OptionalBase&& other) = default;
 
   template <class... Args>
   constexpr explicit OptionalBase(in_place_t, Args&&... args)
@@ -131,23 +223,16 @@
     return *this;
   }
 
-  template <class... Args>
-  void Init(Args&&... args) {
-    DCHECK(storage_.is_null_);
-    ::new (&storage_.value_) T(std::forward<Args>(args)...);
-    storage_.is_null_ = false;
-  }
-
   void InitOrAssign(const T& value) {
     if (storage_.is_null_)
-      Init(value);
+      storage_.Init(value);
     else
       storage_.value_ = value;
   }
 
   void InitOrAssign(T&& value) {
     if (storage_.is_null_)
-      Init(std::move(value));
+      storage_.Init(std::move(value));
     else
       storage_.value_ = std::move(value);
   }
@@ -183,8 +268,8 @@
   // Defer default/copy/move constructor implementation to OptionalBase.
   // TODO(hidehiko): Implement conditional enabling.
   constexpr Optional() = default;
-  Optional(const Optional& other) = default;
-  Optional(Optional&& other) = default;
+  constexpr Optional(const Optional& other) = default;
+  constexpr Optional(Optional&& other) = default;
 
   constexpr Optional(nullopt_t) {}
 
@@ -299,10 +384,10 @@
 
     if (storage_.is_null_ != other.storage_.is_null_) {
       if (storage_.is_null_) {
-        Init(std::move(other.storage_.value_));
+        storage_.Init(std::move(other.storage_.value_));
         other.FreeIfNeeded();
       } else {
-        other.Init(std::move(storage_.value_));
+        other.storage_.Init(std::move(storage_.value_));
         FreeIfNeeded();
       }
       return;
@@ -320,7 +405,7 @@
   template <class... Args>
   void emplace(Args&&... args) {
     FreeIfNeeded();
-    Init(std::forward<Args>(args)...);
+    storage_.Init(std::forward<Args>(args)...);
   }
 
   template <
@@ -331,7 +416,7 @@
                                                      Args...>::value>>
   T& emplace(std::initializer_list<U> il, Args&&... args) {
     FreeIfNeeded();
-    Init(il, std::forward<Args>(args)...);
+    storage_.Init(il, std::forward<Args>(args)...);
     return storage_.value_;
   }
 
@@ -339,7 +424,6 @@
   // Accessing template base class's protected member needs explicit
   // declaration to do so.
   using internal::OptionalBase<T>::FreeIfNeeded;
-  using internal::OptionalBase<T>::Init;
   using internal::OptionalBase<T>::InitOrAssign;
   using internal::OptionalBase<T>::storage_;
 };
diff --git a/base/optional_unittest.cc b/base/optional_unittest.cc
index 60347d5e..91e63e7 100644
--- a/base/optional_unittest.cc
+++ b/base/optional_unittest.cc
@@ -151,8 +151,8 @@
 
 TEST(OptionalTest, CopyConstructor) {
   {
-    Optional<float> first(0.1f);
-    Optional<float> other(first);
+    constexpr Optional<float> first(0.1f);
+    constexpr Optional<float> other(first);
 
     EXPECT_TRUE(other);
     EXPECT_EQ(other.value(), 0.1f);
@@ -207,8 +207,8 @@
 
 TEST(OptionalTest, MoveConstructor) {
   {
-    Optional<float> first(0.1f);
-    Optional<float> second(std::move(first));
+    constexpr Optional<float> first(0.1f);
+    constexpr Optional<float> second(std::move(first));
 
     EXPECT_TRUE(second);
     EXPECT_EQ(second.value(), 0.1f);
diff --git a/base/test/BUILD.gn b/base/test/BUILD.gn
index 12b34f4..dc92513 100644
--- a/base/test/BUILD.gn
+++ b/base/test/BUILD.gn
@@ -28,6 +28,8 @@
     "../trace_event/trace_config_memory_test_util.h",
     "android/java_handler_thread_helpers.cc",
     "android/java_handler_thread_helpers.h",
+    "android/url_utils.cc",
+    "android/url_utils.h",
     "bind_test_util.h",
     "copy_only_int.h",
     "fuzzed_data_provider.cc",
@@ -343,6 +345,7 @@
     sources = [
       "android/java/src/org/chromium/base/MainReturnCodeResult.java",
       "android/java/src/org/chromium/base/MultiprocessTestClientLauncher.java",
+      "android/javatests/src/org/chromium/base/test/util/UrlUtils.java",
     ]
     jni_package = "base"
   }
diff --git a/base/test/android/javatests/src/org/chromium/base/test/util/UrlUtils.java b/base/test/android/javatests/src/org/chromium/base/test/util/UrlUtils.java
index 4b7b36c..9ca3fcc 100644
--- a/base/test/android/javatests/src/org/chromium/base/test/util/UrlUtils.java
+++ b/base/test/android/javatests/src/org/chromium/base/test/util/UrlUtils.java
@@ -7,10 +7,13 @@
 import org.junit.Assert;
 
 import org.chromium.base.PathUtils;
+import org.chromium.base.annotations.CalledByNative;
+import org.chromium.base.annotations.MainDex;
 
 /**
  * Collection of URL utilities.
  */
+@MainDex
 public class UrlUtils {
     private static final String DATA_DIR = "/chrome/test/data/";
 
@@ -36,6 +39,7 @@
     /**
      * Returns the root of the test data directory.
      */
+    @CalledByNative
     public static String getIsolatedTestRoot() {
         return PathUtils.getExternalStorageDirectory() + "/chromium_tests_root";
     }
diff --git a/base/test/android/url_utils.cc b/base/test/android/url_utils.cc
new file mode 100644
index 0000000..7d2a8ed
--- /dev/null
+++ b/base/test/android/url_utils.cc
@@ -0,0 +1,24 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/test/android/url_utils.h"
+
+#include "base/android/jni_string.h"
+#include "base/android/scoped_java_ref.h"
+#include "jni/UrlUtils_jni.h"
+
+namespace base {
+namespace android {
+
+FilePath GetIsolatedTestRoot() {
+  JNIEnv* env = base::android::AttachCurrentThread();
+  ScopedJavaLocalRef<jstring> jtest_data_dir =
+      Java_UrlUtils_getIsolatedTestRoot(env);
+  base::FilePath test_data_dir(
+      base::android::ConvertJavaStringToUTF8(env, jtest_data_dir));
+  return test_data_dir;
+}
+
+}  // namespace android
+}  // namespace base
diff --git a/base/test/android/url_utils.h b/base/test/android/url_utils.h
new file mode 100644
index 0000000..3769bd2
--- /dev/null
+++ b/base/test/android/url_utils.h
@@ -0,0 +1,23 @@
+// 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 BASE_TEST_ANDROID_URL_UTILS_H_
+#define BASE_TEST_ANDROID_URL_UTILS_H_
+
+#include <jni.h>
+
+#include "base/base_export.h"
+#include "base/files/file_path.h"
+
+namespace base {
+namespace android {
+
+// Returns the root of the test data directory. This function will call into
+// Java class UrlUtils through JNI bridge.
+BASE_EXPORT FilePath GetIsolatedTestRoot();
+
+}  // namespace android
+}  // namespace base
+
+#endif  // BASE_TEST_ANDROID_URL_UTILS_H_
diff --git a/base/trace_event/memory_dump_manager.cc b/base/trace_event/memory_dump_manager.cc
index efe7be6b..1eb41e4e 100644
--- a/base/trace_event/memory_dump_manager.cc
+++ b/base/trace_event/memory_dump_manager.cc
@@ -595,18 +595,32 @@
   // If we are in background tracing, we should invoke only the whitelisted
   // providers. Ignore other providers and continue.
   if (pmd_async_state->req_args.level_of_detail ==
-          MemoryDumpLevelOfDetail::BACKGROUND &&
-      !mdpinfo->whitelisted_for_background_mode) {
-    pmd_async_state->pending_dump_providers.pop_back();
-    return SetupNextMemoryDump(std::move(pmd_async_state));
+      MemoryDumpLevelOfDetail::BACKGROUND) {
+    // TODO(ssid): This is a temporary hack to fix crashes
+    // https://crbug.com/797784. We could still cause stack overflow in a
+    // detailed mode dump or when there are lot of providers whitelisted.
+    while (!mdpinfo->whitelisted_for_background_mode) {
+      pmd_async_state->pending_dump_providers.pop_back();
+      if (pmd_async_state->pending_dump_providers.empty())
+        return FinishAsyncProcessDump(std::move(pmd_async_state));
+      mdpinfo = pmd_async_state->pending_dump_providers.back().get();
+    }
   }
 
   // If we are in summary mode, we only need to invoke the providers
   // whitelisted for summary mode.
-  if (pmd_async_state->req_args.dump_type == MemoryDumpType::SUMMARY_ONLY &&
-      !mdpinfo->whitelisted_for_summary_mode) {
-    pmd_async_state->pending_dump_providers.pop_back();
-    return SetupNextMemoryDump(std::move(pmd_async_state));
+  if (pmd_async_state->req_args.dump_type == MemoryDumpType::SUMMARY_ONLY) {
+    // TODO(ssid): This is a temporary hack to fix crashes
+    // https://crbug.com/797784. We could still cause stack overflow in a
+    // detailed mode dump or when there are lot of providers whitelisted. It is
+    // assumed here that a provider whitelisted for summary mode is also
+    // whitelisted for background mode and skip the check.
+    while (!mdpinfo->whitelisted_for_summary_mode) {
+      pmd_async_state->pending_dump_providers.pop_back();
+      if (pmd_async_state->pending_dump_providers.empty())
+        return FinishAsyncProcessDump(std::move(pmd_async_state));
+      mdpinfo = pmd_async_state->pending_dump_providers.back().get();
+    }
   }
 
   // If the dump provider did not specify a task runner affinity, dump on
diff --git a/base/trace_event/memory_infra_background_whitelist.cc b/base/trace_event/memory_infra_background_whitelist.cc
index 38a5846..f2cf4cd 100644
--- a/base/trace_event/memory_infra_background_whitelist.cc
+++ b/base/trace_event/memory_infra_background_whitelist.cc
@@ -24,7 +24,6 @@
     "ClientDiscardableSharedMemoryManager",
     "DOMStorage",
     "DiscardableSharedMemoryManager",
-    "DnsConfigServicePosix::HostsReader",
     "gpu::BufferManager",
     "gpu::RenderbufferManager",
     "gpu::TextureManager",
@@ -101,7 +100,6 @@
     "mojo/shared_buffer",
     "mojo/unknown",
     "mojo/watcher",
-    "net/dns_config_service_posix_hosts_reader",
     "net/http_network_session_0x?",
     "net/http_network_session_0x?/quic_stream_factory",
     "net/http_network_session_0x?/socket_pool",
diff --git a/build/android/pylib/gtest/gtest_test_instance.py b/build/android/pylib/gtest/gtest_test_instance.py
index 7961722..c3e7fb6 100644
--- a/build/android/pylib/gtest/gtest_test_instance.py
+++ b/build/android/pylib/gtest/gtest_test_instance.py
@@ -194,6 +194,9 @@
         log.append(l)
 
     if result_type and test_name:
+      # Don't bother symbolizing output if the test passed.
+      if result_type == base_test_result.ResultType.PASS:
+        stack = []
       results.append(base_test_result.BaseTestResult(
           TestNameWithoutDisabledPrefix(test_name), result_type, duration,
           log=symbolize_stack_and_merge_with_log()))
diff --git a/build/config/compiler/BUILD.gn b/build/config/compiler/BUILD.gn
index c31d2d0..84730e8 100644
--- a/build/config/compiler/BUILD.gn
+++ b/build/config/compiler/BUILD.gn
@@ -682,18 +682,20 @@
       }
 
       if (mips_arch_variant == "r6") {
+        cflags += [ "-mno-odd-spreg" ]
+        ldflags += [ "-mips32r6" ]
         if (is_clang) {
-          cflags += [ "-march=mips32r6" ]
+          cflags += [
+            "-march=mipsel",
+            "-mcpu=mips32r6",
+          ]
         } else {
           cflags += [
             "-mips32r6",
             "-Wa,-mips32r6",
           ]
           if (is_android) {
-            ldflags += [
-              "-mips32r6",
-              "-Wl,-melf32ltsmip",
-            ]
+            ldflags += [ "-Wl,-melf32ltsmip" ]
           }
         }
         if (mips_use_msa == true) {
@@ -703,18 +705,12 @@
           ]
         }
       } else if (mips_arch_variant == "r2") {
+        ldflags += [ "-mips32r2" ]
         if (is_clang) {
-          if (is_android) {
-            cflags += [
-              "-march=mipsel",
-              "-mcpu=mips32r2",
-            ]
-          } else {
-            cflags += [
-              "-march=mipsel",
-              "-mcpu=mips32r2",
-            ]
-          }
+          cflags += [
+            "-march=mipsel",
+            "-mcpu=mips32r2",
+          ]
         } else {
           cflags += [
             "-mips32r2",
@@ -725,18 +721,12 @@
           }
         }
       } else if (mips_arch_variant == "r1") {
+        ldflags += [ "-mips32" ]
         if (is_clang) {
-          if (is_android) {
-            cflags += [
-              "-march=mipsel",
-              "-mcpu=mips32",
-            ]
-          } else {
-            cflags += [
-              "-march=mipsel",
-              "-mcpu=mips32",
-            ]
-          }
+          cflags += [
+            "-march=mipsel",
+            "-mcpu=mips32",
+          ]
         } else {
           cflags += [
             "-mips32",
diff --git a/cc/layers/video_frame_provider_client_impl_unittest.cc b/cc/layers/video_frame_provider_client_impl_unittest.cc
index c34150a..19481d3 100644
--- a/cc/layers/video_frame_provider_client_impl_unittest.cc
+++ b/cc/layers/video_frame_provider_client_impl_unittest.cc
@@ -33,7 +33,7 @@
   VideoFrameProviderClientImplTest()
       : client_impl_(VideoFrameProviderClientImpl::Create(&provider_, this)),
         video_layer_impl_(nullptr),
-        test_frame_(media::VideoFrame::CreateFrame(media::PIXEL_FORMAT_YV12,
+        test_frame_(media::VideoFrame::CreateFrame(media::PIXEL_FORMAT_I420,
                                                    gfx::Size(10, 10),
                                                    gfx::Rect(10, 10),
                                                    gfx::Size(10, 10),
diff --git a/cc/layers/video_layer_impl_unittest.cc b/cc/layers/video_layer_impl_unittest.cc
index 9a933eb0..fc67628 100644
--- a/cc/layers/video_layer_impl_unittest.cc
+++ b/cc/layers/video_layer_impl_unittest.cc
@@ -41,7 +41,7 @@
   DebugSetImplThreadAndMainThreadBlocked(impl.task_runner_provider());
 
   scoped_refptr<media::VideoFrame> video_frame = media::VideoFrame::CreateFrame(
-      media::PIXEL_FORMAT_YV12, gfx::Size(10, 10), gfx::Rect(10, 10),
+      media::PIXEL_FORMAT_I420, gfx::Size(10, 10), gfx::Rect(10, 10),
       gfx::Size(10, 10), base::TimeDelta());
   FakeVideoFrameProvider provider;
   provider.set_frame(video_frame);
@@ -120,7 +120,7 @@
   EXPECT_FALSE(draw_properties.occlusion_in_content_space.IsOccluded(visible));
 
   scoped_refptr<media::VideoFrame> video_frame = media::VideoFrame::CreateFrame(
-      media::PIXEL_FORMAT_YV12, gfx::Size(10, 10), gfx::Rect(10, 10),
+      media::PIXEL_FORMAT_I420, gfx::Size(10, 10), gfx::Rect(10, 10),
       gfx::Size(10, 10), base::TimeDelta());
   provider.set_frame(video_frame);
   active_tree->set_needs_update_draw_properties();
@@ -155,7 +155,7 @@
   DebugSetImplThreadAndMainThreadBlocked(impl.task_runner_provider());
 
   scoped_refptr<media::VideoFrame> video_frame = media::VideoFrame::CreateFrame(
-      media::PIXEL_FORMAT_YV12, gfx::Size(20, 10), gfx::Rect(20, 10),
+      media::PIXEL_FORMAT_I420, gfx::Size(20, 10), gfx::Rect(20, 10),
       gfx::Size(20, 10), base::TimeDelta());
   FakeVideoFrameProvider provider;
   provider.set_frame(video_frame);
@@ -191,7 +191,7 @@
   DebugSetImplThreadAndMainThreadBlocked(impl.task_runner_provider());
 
   scoped_refptr<media::VideoFrame> video_frame = media::VideoFrame::CreateFrame(
-      media::PIXEL_FORMAT_YV12, gfx::Size(20, 10), gfx::Rect(20, 10),
+      media::PIXEL_FORMAT_I420, gfx::Size(20, 10), gfx::Rect(20, 10),
       gfx::Size(20, 10), base::TimeDelta());
   FakeVideoFrameProvider provider;
   provider.set_frame(video_frame);
@@ -227,7 +227,7 @@
   DebugSetImplThreadAndMainThreadBlocked(impl.task_runner_provider());
 
   scoped_refptr<media::VideoFrame> video_frame = media::VideoFrame::CreateFrame(
-      media::PIXEL_FORMAT_YV12, gfx::Size(20, 10), gfx::Rect(20, 10),
+      media::PIXEL_FORMAT_I420, gfx::Size(20, 10), gfx::Rect(20, 10),
       gfx::Size(20, 10), base::TimeDelta());
   FakeVideoFrameProvider provider;
   provider.set_frame(video_frame);
@@ -263,7 +263,7 @@
   DebugSetImplThreadAndMainThreadBlocked(impl.task_runner_provider());
 
   scoped_refptr<media::VideoFrame> video_frame = media::VideoFrame::CreateFrame(
-      media::PIXEL_FORMAT_YV12, gfx::Size(20, 10), gfx::Rect(20, 10),
+      media::PIXEL_FORMAT_I420, gfx::Size(20, 10), gfx::Rect(20, 10),
       gfx::Size(20, 10), base::TimeDelta());
   FakeVideoFrameProvider provider;
   provider.set_frame(video_frame);
@@ -303,7 +303,7 @@
   mailbox_holder.mailbox.name[0] = 1;
 
   scoped_refptr<media::VideoFrame> video_frame = media::VideoFrame::CreateFrame(
-      media::PIXEL_FORMAT_YV12, gfx::Size(20, 10), gfx::Rect(20, 10),
+      media::PIXEL_FORMAT_I420, gfx::Size(20, 10), gfx::Rect(20, 10),
       gfx::Size(20, 10), base::TimeDelta());
 
   FakeVideoFrameProvider provider;
diff --git a/cc/paint/paint_op_buffer_eq_fuzzer.cc b/cc/paint/paint_op_buffer_eq_fuzzer.cc
index e2e9f2a..8dd616e 100644
--- a/cc/paint/paint_op_buffer_eq_fuzzer.cc
+++ b/cc/paint/paint_op_buffer_eq_fuzzer.cc
@@ -39,7 +39,7 @@
   cc::PaintOp::SerializeOptions serialize_options;
   serialize_options.transfer_cache = &transfer_cache_helper;
   cc::PaintOp::DeserializeOptions deserialize_options;
-  serialize_options.transfer_cache = &transfer_cache_helper;
+  deserialize_options.transfer_cache = &transfer_cache_helper;
 
   // Need 4 bytes to be able to read the type/skip.
   if (size < 4)
diff --git a/cc/paint/paint_op_reader.cc b/cc/paint/paint_op_reader.cc
index f2ec7be..b2e1bec 100644
--- a/cc/paint/paint_op_reader.cc
+++ b/cc/paint/paint_op_reader.cc
@@ -243,6 +243,8 @@
 void PaintOpReader::Read(PaintImage* image) {
   uint32_t transfer_cache_entry_id;
   ReadSimple(&transfer_cache_entry_id);
+  if (!valid_)
+    return;
 
   // If we encountered a decode failure, we may write an invalid id for the
   // image. In these cases, just return, leaving the image as nullptr.
diff --git a/cc/trees/proxy_impl.cc b/cc/trees/proxy_impl.cc
index dafbc8f3..fddb06a 100644
--- a/cc/trees/proxy_impl.cc
+++ b/cc/trees/proxy_impl.cc
@@ -101,8 +101,12 @@
   // Take away the LayerTreeFrameSink before destroying things so it doesn't
   // try to call into its client mid-shutdown.
   host_impl_->ReleaseLayerTreeFrameSink();
-  scheduler_ = nullptr;
+
+  // It is important to destroy LTHI before the Scheduler since it can make
+  // callbacks that access it during destruction cleanup.
   host_impl_ = nullptr;
+  scheduler_ = nullptr;
+
   // We need to explicitly shutdown the notifier to destroy any weakptrs it is
   // holding while still on the compositor thread. This also ensures any
   // callbacks holding a ProxyImpl pointer are cancelled.
diff --git a/cc/trees/single_thread_proxy.cc b/cc/trees/single_thread_proxy.cc
index ebbe994d..4574948 100644
--- a/cc/trees/single_thread_proxy.cc
+++ b/cc/trees/single_thread_proxy.cc
@@ -292,8 +292,11 @@
     // Take away the LayerTreeFrameSink before destroying things so it doesn't
     // try to call into its client mid-shutdown.
     host_impl_->ReleaseLayerTreeFrameSink();
-    scheduler_on_impl_thread_ = nullptr;
+
+    // It is important to destroy LTHI before the Scheduler since it can make
+    // callbacks that access it during destruction cleanup.
     host_impl_ = nullptr;
+    scheduler_on_impl_thread_ = nullptr;
   }
   layer_tree_host_ = nullptr;
 }
diff --git a/chrome/android/java/res/layout/data_reduction_old_stats_layout.xml b/chrome/android/java/res/layout/data_reduction_old_stats_layout.xml
deleted file mode 100644
index 99a2a5e..0000000
--- a/chrome/android/java/res/layout/data_reduction_old_stats_layout.xml
+++ /dev/null
@@ -1,127 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- 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. -->
-
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:tools="http://schemas.android.com/tools"
-    android:id="@+id/data_reduction_stats_container"
-    android:layout_width="match_parent"
-    android:layout_height="wrap_content"
-    android:clipChildren="false"
-    android:clipToPadding="false"
-    android:orientation="vertical" >
-
-    <TextView
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:fadingEdge="horizontal"
-        android:text="@string/data_reduction_stats_title"
-        android:textAppearance="@style/PreferenceCategoryTextStyle" />
-
-    <include layout="@layout/data_usage_chart" />
-
-    <FrameLayout
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content" >
-
-        <TextView
-            android:id="@+id/data_reduction_start_date"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:textAppearance="@style/PreferenceSummary"
-            android:textSize="14sp" />
-
-        <TextView
-            android:id="@+id/data_reduction_end_date"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:textAppearance="@style/PreferenceSummary"
-            android:textSize="14sp" />
-
-    </FrameLayout>
-
-    <LinearLayout
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:orientation="horizontal" >
-
-        <TextView
-            android:id="@+id/data_reduction_percent"
-            android:layout_height="wrap_content"
-            android:layout_width="wrap_content"
-            android:layout_marginTop="0dp"
-            android:textColor="?android:attr/textColorPrimary"
-            android:textSize="50sp" />
-
-        <FrameLayout
-            android:layout_height="wrap_content"
-            android:layout_width="0dp"
-            android:layout_weight="1"
-            android:paddingEnd="6dp"
-            android:paddingStart="20dp" >
-
-            <LinearLayout
-                android:layout_height="wrap_content"
-                android:layout_width="wrap_content"
-                android:layout_gravity="end"
-                android:orientation="vertical"
-                tools:ignore="UselessParent" >
-
-                <TextView
-                    android:layout_width="match_parent"
-                    android:layout_height="wrap_content"
-                    android:layout_marginTop="14dp"
-                    android:singleLine="true"
-                    android:text="@string/data_reduction_original_size_label"
-                    android:textColor="?android:attr/textColorPrimary"
-                    android:textSize="14sp" />
-
-                <TextView
-                    android:layout_width="match_parent"
-                    android:layout_height="wrap_content"
-                    android:layout_marginTop="4dp"
-                    android:singleLine="true"
-                    android:text="@string/data_reduction_compressed_size_label"
-                    android:textColor="?android:attr/textColorPrimary"
-                    android:textSize="14sp" />
-            </LinearLayout>
-
-        </FrameLayout>
-
-        <LinearLayout
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:orientation="vertical"
-            android:paddingStart="10dp" >
-
-            <TextView
-                android:id="@+id/data_reduction_original_size"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:layout_marginTop="14dp"
-                android:textAppearance="@style/BlackTitle2" />
-
-            <TextView
-                android:id="@+id/data_reduction_compressed_size"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:layout_marginTop="4dp"
-                android:textAppearance="@style/BlackTitle2" />
-        </LinearLayout>
-
-    </LinearLayout>
-
-    <TextView
-        android:id="@+id/data_reduction_proxy_unreachable"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:layout_marginBottom="20dp"
-        android:layout_marginTop="20dp"
-        android:drawableStart="@drawable/exclamation_triangle"
-        android:drawablePadding="6dp"
-        android:text="@string/data_reduction_proxy_unreachable_warn"
-        android:textColor="?android:attr/textColorPrimary"
-        android:textSize="14sp" />
-
-</LinearLayout>
\ No newline at end of file
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeFeatureList.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeFeatureList.java
index 5e12b3dd..56dae20 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeFeatureList.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeFeatureList.java
@@ -203,7 +203,6 @@
     // Enables the Data Reduction Proxy menu item in the main menu rather than under Settings on
     // Android.
     public static final String DATA_REDUCTION_MAIN_MENU = "DataReductionProxyMainMenu";
-    public static final String DATA_REDUCTION_SITE_BREAKDOWN = "DataReductionProxySiteBreakdown";
     public static final String DONT_PREFETCH_LIBRARIES = "DontPrefetchLibraries";
     public static final String DOWNLOAD_HOME_SHOW_STORAGE_INFO = "DownloadHomeShowStorageInfo";
     public static final String DOWNLOADS_FOREGROUND = "DownloadsForeground";
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/DeferredStartupHandler.java b/chrome/android/java/src/org/chromium/chrome/browser/DeferredStartupHandler.java
index b1d7290..cff00682 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/DeferredStartupHandler.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/DeferredStartupHandler.java
@@ -94,7 +94,7 @@
         if (UmaUtils.hasComeToForeground()) {
             RecordHistogram.recordLongTimesHistogram(
                     "UMA.Debug.EnableCrashUpload.DeferredStartUpCompleteTime",
-                    SystemClock.uptimeMillis() - UmaUtils.getForegroundStartTime(),
+                    SystemClock.uptimeMillis() - UmaUtils.getForegroundStartTicks(),
                     TimeUnit.MILLISECONDS);
         }
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/LaunchIntentDispatcher.java b/chrome/android/java/src/org/chromium/chrome/browser/LaunchIntentDispatcher.java
index 7008962..a699892 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/LaunchIntentDispatcher.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/LaunchIntentDispatcher.java
@@ -23,6 +23,7 @@
 
 import org.chromium.base.ContextUtils;
 import org.chromium.base.Log;
+import org.chromium.base.StrictModeContext;
 import org.chromium.base.metrics.CachedMetrics;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.IntentHandler.ExternalAppId;
@@ -452,9 +453,13 @@
         maybePrefetchDnsInBackground();
 
         // Create and fire a launch intent.
-        mActivity.startActivity(createCustomTabActivityIntent(mActivity, mIntent,
-                                        !isCustomTabIntent(mIntent) && mIsHerbIntent),
-                getStartActivityIntentOptions());
+        Intent launchIntent = createCustomTabActivityIntent(
+                mActivity, mIntent, !isCustomTabIntent(mIntent) && mIsHerbIntent);
+        // Allow disk writes during startActivity() to avoid strict mode violations on some
+        // Samsung devices, see https://crbug.com/796548.
+        try (StrictModeContext smc = StrictModeContext.allowDiskWrites()) {
+            mActivity.startActivity(launchIntent, getStartActivityIntentOptions());
+        }
         if (mIsHerbIntent) {
             mActivity.overridePendingTransition(R.anim.activity_open_enter, R.anim.no_anim);
         }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkBridge.java b/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkBridge.java
index 8455dd4..eaa78bf5 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkBridge.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkBridge.java
@@ -498,6 +498,16 @@
     }
 
     /**
+     * Get the total number of bookmarks in the sub tree of the specified folder.
+     * @param id The {@link BookmarkId} of the folder to be queried.
+     * @return The total number of bookmarks in the folder.
+     */
+    public int getTotalBookmarkCount(BookmarkId id) {
+        assert mIsNativeBookmarkModelLoaded;
+        return nativeGetTotalBookmarkCount(mNativeBookmarkBridge, id.getId(), id.getType());
+    }
+
+    /**
      * Synchronously gets a list of bookmarks that match the specified search query.
      * @param query Keyword used for searching bookmarks.
      * @param maxNumberOfResult Maximum number of result to fetch.
@@ -896,6 +906,7 @@
             boolean getFolders, boolean getBookmarks, List<BookmarkId> bookmarksList);
     private native BookmarkId nativeGetChildAt(long nativeBookmarkBridge, long id, int type,
             int index);
+    private native int nativeGetTotalBookmarkCount(long nativeBookmarkBridge, long id, int type);
     private native void nativeSetBookmarkTitle(long nativeBookmarkBridge, long id, int type,
             String title);
     private native void nativeSetBookmarkUrl(long nativeBookmarkBridge, long id, int type,
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkFolderRow.java b/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkFolderRow.java
index 82d49e9..957caa20 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkFolderRow.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkFolderRow.java
@@ -42,7 +42,7 @@
     BookmarkItem setBookmarkId(BookmarkId bookmarkId) {
         BookmarkItem item = super.setBookmarkId(bookmarkId);
         mTitleView.setText(item.getTitle());
-        int childCount = mDelegate.getModel().getChildCount(bookmarkId);
+        int childCount = mDelegate.getModel().getTotalBookmarkCount(bookmarkId);
         mDescriptionView.setText((childCount > 0)
                         ? getResources().getQuantityString(
                                   R.plurals.bookmarks_count, childCount, childCount)
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadManagerService.java b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadManagerService.java
index cba164d0..26a03536 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadManagerService.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadManagerService.java
@@ -769,7 +769,8 @@
             // the real file path to the user instead of a content:// download ID.
             Uri fileUri = contentUri;
             if (filePath != null) fileUri = Uri.fromFile(new File(filePath));
-            return MediaViewerUtils.getMediaViewerIntent(fileUri, contentUri, mimeType);
+            return MediaViewerUtils.getMediaViewerIntent(
+                    fileUri, contentUri, mimeType, true /* allowExternalAppHandlers */);
         }
         return MediaViewerUtils.createViewIntentForUri(contentUri, mimeType, originalUrl, referrer);
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadUtils.java b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadUtils.java
index f8a80e7c..55eccf3 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadUtils.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadUtils.java
@@ -479,8 +479,8 @@
             Uri contentUri = getUriForItem(file);
             String normalizedMimeType = Intent.normalizeMimeType(mimeType);
 
-            Intent intent =
-                    MediaViewerUtils.getMediaViewerIntent(fileUri, contentUri, normalizedMimeType);
+            Intent intent = MediaViewerUtils.getMediaViewerIntent(
+                    fileUri, contentUri, normalizedMimeType, true /* allowExternalAppHandlers */);
             IntentHandler.startActivityForTrustedIntent(intent);
             service.updateLastAccessTime(downloadGuid, isOffTheRecord);
             return true;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/ui/DownloadItemView.java b/chrome/android/java/src/org/chromium/chrome/browser/download/ui/DownloadItemView.java
index 3d3f39d..c0f0bb0 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/download/ui/DownloadItemView.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/download/ui/DownloadItemView.java
@@ -31,6 +31,7 @@
 import org.chromium.chrome.browser.widget.TintedImageButton;
 import org.chromium.chrome.browser.widget.selection.SelectableItemView;
 import org.chromium.components.offline_items_collection.OfflineItem.Progress;
+import org.chromium.components.variations.VariationsAssociatedData;
 import org.chromium.ui.UiUtils;
 
 import java.util.List;
@@ -41,6 +42,10 @@
  */
 public class DownloadItemView extends SelectableItemView<DownloadHistoryItemWrapper>
         implements ThumbnailProvider.ThumbnailRequest, ListMenuButton.Delegate {
+    private static final String VARIATION_TRIAL_DOWNLOAD_HOME_MORE_BUTTON =
+            "DownloadHomeMoreButton";
+    private static final String VARIATION_PARAM_SHOW_MORE_BUTTON = "show_more_button";
+
     // Please treat this list as append only and keep it in sync with
     // Android.DownloadManager.List.View.Actions in enums.xml.
     @IntDef({VIEW_ACTION_OPEN, VIEW_ACTION_RESUME, VIEW_ACTION_PAUSE, VIEW_ACTION_CANCEL,
@@ -55,6 +60,14 @@
     private static final int VIEW_ACTION_MENU_DELETE = 5;
     private static final int VIEW_ACTION_BOUNDARY = 6;
 
+    /**
+     * Set based on Chrome Variations to determine whether or not to show the "more" menu button on
+     * this item.  This will be set only once the first time it is queried through
+     * {@link #isMoreButtonEnabled()} and will not be set again for the current process lifetime to
+     * avoid hitting the Chrome Variations system for each list item.
+     */
+    private static Boolean sMoreButtonEnabled;
+
     private final int mMargin;
     private final int mMarginSubsection;
     private final int mIconBackgroundColor;
@@ -236,7 +249,6 @@
 
         if (item.isComplete()) {
             showLayout(mLayoutCompleted);
-            mMoreButton.setVisibility(View.VISIBLE);
         } else {
             showLayout(mLayoutInProgress);
             mDownloadStatusView.setText(item.getStatusString());
@@ -273,9 +285,11 @@
                 ApiCompatibilityUtils.setMarginEnd(
                         (MarginLayoutParams) mDownloadPercentageView.getLayoutParams(), mMargin);
             }
-            mMoreButton.setVisibility(View.GONE);
         }
 
+        boolean canShowMore = item.isComplete() && isMoreButtonEnabled();
+        mMoreButton.setVisibility(canShowMore ? View.VISIBLE : View.GONE);
+
         setLongClickable(item.isComplete());
     }
 
@@ -369,4 +383,26 @@
         RecordHistogram.recordEnumeratedHistogram(
                 "Android.DownloadManager.List.View.Action", action, VIEW_ACTION_BOUNDARY);
     }
+
+    /**
+     * Uses Chrome Variations to determine whether or not to show the "more" menu button.  This
+     * value will be queried the first time this method is run and cached for future calls.  The
+     * default value will be {@code true} if no Chrome Variation is found for this value.
+     * @return Whether or not the "more" menu button should be shown.
+     */
+    private static boolean isMoreButtonEnabled() {
+        if (sMoreButtonEnabled == null) {
+            // Default the more button to true.  Any invalid non-empty value will set the result to
+            // false though.
+            sMoreButtonEnabled = true;
+
+            String variationResult = VariationsAssociatedData.getVariationParamValue(
+                    VARIATION_TRIAL_DOWNLOAD_HOME_MORE_BUTTON, VARIATION_PARAM_SHOW_MORE_BUTTON);
+            if (!TextUtils.isEmpty(variationResult)) {
+                sMoreButtonEnabled = Boolean.parseBoolean(variationResult);
+            }
+        }
+
+        return sMoreButtonEnabled;
+    }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/firstrun/FirstRunActivityBase.java b/chrome/android/java/src/org/chromium/chrome/browser/firstrun/FirstRunActivityBase.java
index f46c487..63f7af0 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/firstrun/FirstRunActivityBase.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/firstrun/FirstRunActivityBase.java
@@ -64,7 +64,7 @@
         super.onStart();
         // Since the FRE may be shown before any tab is shown, mark that this is the point at
         // which Chrome went to foreground. This is needed as otherwise an assert will be hit
-        // in UmaUtils.getForegroundStartTime() when recording the time taken to load the first
+        // in UmaUtils.getForegroundStartTicks() when recording the time taken to load the first
         // page (which happens after native has been initialized possibly while FRE is still
         // active).
         UmaUtils.recordForegroundStartTime();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/media/MediaViewerUtils.java b/chrome/android/java/src/org/chromium/chrome/browser/media/MediaViewerUtils.java
index 6752208e..1f3292d 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/media/MediaViewerUtils.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/media/MediaViewerUtils.java
@@ -34,14 +34,16 @@
 
     /**
      * Creates an Intent that allows viewing the given file in an internal media viewer.
-     * @param displayUri URI to display to the user, ideally in file:// form.
-     * @param contentUri content:// URI pointing at the file.
-     * @param mimeType   MIME type of the file.
+     * @param displayUri               URI to display to the user, ideally in file:// form.
+     * @param contentUri               content:// URI pointing at the file.
+     * @param mimeType                 MIME type of the file.
+     * @param allowExternalAppHandlers Whether the viewer should allow the user to open with another
+     *                                 app.
      * @return Intent that can be fired to open the file.
      */
-    public static Intent getMediaViewerIntent(Uri displayUri, Uri contentUri, String mimeType) {
+    public static Intent getMediaViewerIntent(
+            Uri displayUri, Uri contentUri, String mimeType, boolean allowExternalAppHandlers) {
         Context context = ContextUtils.getApplicationContext();
-        Intent viewIntent = createViewIntentForUri(contentUri, mimeType, null, null);
 
         Bitmap closeIcon = BitmapFactory.decodeResource(
                 context.getResources(), R.drawable.ic_arrow_back_white_24dp);
@@ -53,16 +55,19 @@
         builder.setCloseButtonIcon(closeIcon);
         builder.setShowTitle(true);
 
-        // Create a PendingIntent that can be used to view the file externally.
-        // TODO(https://crbug.com/795968): Check if this is problematic in multi-window mode,
-        //                                 where two different viewers could be visible at the
-        //                                 same time.
-        Intent chooserIntent = Intent.createChooser(viewIntent, null);
-        chooserIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-        String openWithStr = context.getString(R.string.download_manager_open_with);
-        PendingIntent pendingViewIntent = PendingIntent.getActivity(
-                context, 0, chooserIntent, PendingIntent.FLAG_CANCEL_CURRENT);
-        builder.addMenuItem(openWithStr, pendingViewIntent);
+        if (allowExternalAppHandlers) {
+            // Create a PendingIntent that can be used to view the file externally.
+            // TODO(https://crbug.com/795968): Check if this is problematic in multi-window mode,
+            //                                 where two different viewers could be visible at the
+            //                                 same time.
+            Intent viewIntent = createViewIntentForUri(contentUri, mimeType, null, null);
+            Intent chooserIntent = Intent.createChooser(viewIntent, null);
+            chooserIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+            String openWithStr = context.getString(R.string.download_manager_open_with);
+            PendingIntent pendingViewIntent = PendingIntent.getActivity(
+                    context, 0, chooserIntent, PendingIntent.FLAG_CANCEL_CURRENT);
+            builder.addMenuItem(openWithStr, pendingViewIntent);
+        }
 
         // Create a PendingIntent that shares the file with external apps.
         PendingIntent pendingShareIntent = PendingIntent.getActivity(context, 0,
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/metrics/UmaUtils.java b/chrome/android/java/src/org/chromium/chrome/browser/metrics/UmaUtils.java
index bed12cbb..3c1a1dc 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/metrics/UmaUtils.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/metrics/UmaUtils.java
@@ -137,7 +137,12 @@
         return sApplicationStartWallClockMs;
     }
 
-    public static long getForegroundStartTime() {
+    @CalledByNative
+    public static long getMainEntryPointTicks() {
+        return sApplicationStartTimeMs;
+    }
+
+    public static long getForegroundStartTicks() {
         assert sForegroundStartTimeMs != 0;
         return sForegroundStartTimeMs;
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/payments/AutofillPaymentApp.java b/chrome/android/java/src/org/chromium/chrome/browser/payments/AutofillPaymentApp.java
index 66fb992..484d578 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/payments/AutofillPaymentApp.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/payments/AutofillPaymentApp.java
@@ -22,12 +22,16 @@
 import java.util.Map;
 import java.util.Set;
 
+import javax.annotation.Nullable;
+
 /**
  * Provides access to locally stored user credit cards.
  */
 public class AutofillPaymentApp implements PaymentApp {
     private final WebContents mWebContents;
     private Set<Integer> mBasicCardTypes;
+    private Set<String> mBasicCardSupportedNetworks;
+    private Set<String> mSupportedMethods;
 
     /**
      * Builds a payment app backed by autofill cards.
@@ -46,9 +50,8 @@
         List<CreditCard> cards = pdm.getCreditCardsToSuggest();
         final List<PaymentInstrument> instruments = new ArrayList<>(cards.size());
 
-        Set<String> basicCardSupportedNetworks = null;
         if (methodDataMap.containsKey(BasicCardUtils.BASIC_CARD_METHOD_NAME)) {
-            basicCardSupportedNetworks = BasicCardUtils.convertBasicCardToNetworks(
+            mBasicCardSupportedNetworks = BasicCardUtils.convertBasicCardToNetworks(
                     methodDataMap.get(BasicCardUtils.BASIC_CARD_METHOD_NAME));
             mBasicCardTypes = BasicCardUtils.convertBasicCardToTypes(
                     methodDataMap.get(BasicCardUtils.BASIC_CARD_METHOD_NAME));
@@ -56,48 +59,65 @@
             mBasicCardTypes = new HashSet<>(BasicCardUtils.getCardTypes().values());
             mBasicCardTypes.add(CardType.UNKNOWN);
         }
+        mSupportedMethods = new HashSet<>(methodDataMap.keySet());
 
         for (int i = 0; i < cards.size(); i++) {
-            CreditCard card = cards.get(i);
-            AutofillProfile billingAddress = TextUtils.isEmpty(card.getBillingAddressId())
-                    ? null
-                    : pdm.getProfile(card.getBillingAddressId());
-
-            if (billingAddress != null
-                    && AutofillAddress.checkAddressCompletionStatus(
-                               billingAddress, AutofillAddress.IGNORE_PHONE_COMPLETENESS_CHECK)
-                            != AutofillAddress.COMPLETE) {
-                billingAddress = null;
-            }
-
-            if (billingAddress == null) card.setBillingAddressId(null);
-
-            String methodName = null;
-            if (basicCardSupportedNetworks != null
-                    && basicCardSupportedNetworks.contains(card.getBasicCardIssuerNetwork())) {
-                methodName = BasicCardUtils.BASIC_CARD_METHOD_NAME;
-            } else if (methodDataMap.containsKey(card.getBasicCardIssuerNetwork())) {
-                methodName = card.getBasicCardIssuerNetwork();
-            }
-
-            if (methodName != null && mBasicCardTypes.contains(card.getCardType())) {
-                // Whether this card matches the card type (credit, debit, prepaid) exactly. If the
-                // merchant requests all card types, then this is always true. If the merchant
-                // requests only a subset of card types, then this is false for "unknown" card
-                // types. The "unknown" card types is where Chrome is unable to determine the type
-                // of card. Cards that don't match the card type exactly cannot be pre-selected in
-                // the UI.
-                boolean matchesMerchantCardTypeExactly = card.getCardType() != CardType.UNKNOWN
-                        || mBasicCardTypes.size() == BasicCardUtils.TOTAL_NUMBER_OF_CARD_TYPES;
-
-                instruments.add(new AutofillPaymentInstrument(mWebContents, card, billingAddress,
-                        methodName, matchesMerchantCardTypeExactly));
-            }
+            PaymentInstrument instrument = getInstrumentForCard(cards.get(i));
+            if (instrument != null) instruments.add(instrument);
         }
 
         new Handler().post(() -> callback.onInstrumentsReady(AutofillPaymentApp.this, instruments));
     }
 
+    /**
+     * Creates a payment instrument object for the given card if it is usable for the
+     * payment request. This interface must be called after getInstruments.
+     *
+     * @param card The given card.
+     */
+    @Nullable
+    public PaymentInstrument getInstrumentForCard(CreditCard card) {
+        if (mSupportedMethods == null) return null;
+
+        PersonalDataManager pdm = PersonalDataManager.getInstance();
+        AutofillProfile billingAddress = TextUtils.isEmpty(card.getBillingAddressId())
+                ? null
+                : pdm.getProfile(card.getBillingAddressId());
+
+        if (billingAddress != null
+                && AutofillAddress.checkAddressCompletionStatus(
+                           billingAddress, AutofillAddress.IGNORE_PHONE_COMPLETENESS_CHECK)
+                        != AutofillAddress.COMPLETE) {
+            billingAddress = null;
+        }
+
+        if (billingAddress == null) card.setBillingAddressId(null);
+
+        String methodName = null;
+        if (mBasicCardSupportedNetworks != null
+                && mBasicCardSupportedNetworks.contains(card.getBasicCardIssuerNetwork())) {
+            methodName = BasicCardUtils.BASIC_CARD_METHOD_NAME;
+        } else if (mSupportedMethods.contains(card.getBasicCardIssuerNetwork())) {
+            methodName = card.getBasicCardIssuerNetwork();
+        }
+
+        if (methodName != null && mBasicCardTypes.contains(card.getCardType())) {
+            // Whether this card matches the card type (credit, debit, prepaid) exactly. If the
+            // merchant requests all card types, then this is always true. If the merchant
+            // requests only a subset of card types, then this is false for "unknown" card
+            // types. The "unknown" card types is where Chrome is unable to determine the type
+            // of card. Cards that don't match the card type exactly cannot be pre-selected in
+            // the UI.
+            boolean matchesMerchantCardTypeExactly = card.getCardType() != CardType.UNKNOWN
+                    || mBasicCardTypes.size() == BasicCardUtils.TOTAL_NUMBER_OF_CARD_TYPES;
+
+            return new AutofillPaymentInstrument(
+                    mWebContents, card, billingAddress, methodName, matchesMerchantCardTypeExactly);
+        }
+
+        return null;
+    }
+
     @Override
     public Set<String> getAppMethodNames() {
         Set<String> methods = new HashSet<>(BasicCardUtils.getNetworks().values());
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentRequestImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentRequestImpl.java
index 5f593af..f352537c 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentRequestImpl.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentRequestImpl.java
@@ -20,6 +20,7 @@
 import org.chromium.chrome.browser.UrlConstants;
 import org.chromium.chrome.browser.autofill.PersonalDataManager;
 import org.chromium.chrome.browser.autofill.PersonalDataManager.AutofillProfile;
+import org.chromium.chrome.browser.autofill.PersonalDataManager.CreditCard;
 import org.chromium.chrome.browser.autofill.PersonalDataManager.NormalizedAddressRequestDelegate;
 import org.chromium.chrome.browser.favicon.FaviconHelper;
 import org.chromium.chrome.browser.page_info.CertificateChainHelper;
@@ -91,7 +92,7 @@
                    PaymentInstrument.AbortCallback, PaymentInstrument.InstrumentDetailsCallback,
                    PaymentAppFactory.PaymentAppCreatedCallback,
                    PaymentResponseHelper.PaymentResponseRequesterDelegate, FocusChangedObserver,
-                   NormalizedAddressRequestDelegate {
+                   NormalizedAddressRequestDelegate, SettingsAutofillAndPaymentsObserver.Observer {
     /**
      * A test-only observer for the PaymentRequest service implementation.
      */
@@ -1475,8 +1476,64 @@
         Intent intent = PreferencesLauncher.createIntentForSettingsPage(
                 context, AutofillAndPaymentsPreferences.class.getName());
         context.startActivity(intent);
-        mJourneyLogger.setAborted(AbortReason.ABORTED_BY_USER);
-        disconnectFromClientWithDebugMessage("Card and address settings clicked");
+    }
+
+    @Override
+    public void onAddressUpdated(AutofillAddress address) {
+        if (mClient == null) return;
+
+        address.setShippingAddressLabelWithCountry();
+        mCardEditor.updateBillingAddressIfComplete(address);
+
+        if (mShippingAddressesSection != null) {
+            mShippingAddressesSection.addAndSelectOrUpdateItem(address);
+            mUI.updateSection(PaymentRequestUI.TYPE_SHIPPING_ADDRESSES, mShippingAddressesSection);
+        }
+
+        if (mContactSection != null) {
+            mContactSection.addOrUpdateWithAutofillAddress(address);
+            mUI.updateSection(PaymentRequestUI.TYPE_CONTACT_DETAILS, mContactSection);
+        }
+    }
+
+    @Override
+    public void onAddressDeleted(String guid) {
+        if (mClient == null) return;
+
+        // TODO: Delete the address from mShippingAddressesSection and mContactSection. Note that we
+        // only displayed SUGGESTIONS_LIMIT addresses, so we may want to add back previously
+        // ignored addresses.
+    }
+
+    @Override
+    public void onCreditCardUpdated(CreditCard card) {
+        if (mClient == null) return;
+        if (!mMerchantSupportsAutofillPaymentInstruments || mPaymentMethodsSection == null) return;
+
+        PaymentInstrument updatedAutofillPaymentInstruments = null;
+        for (PaymentApp app : mApps) {
+            if (app instanceof AutofillPaymentApp) {
+                updatedAutofillPaymentInstruments =
+                        ((AutofillPaymentApp) app).getInstrumentForCard(card);
+            }
+        }
+        if (updatedAutofillPaymentInstruments == null) return;
+
+        mPaymentMethodsSection.addAndSelectOrUpdateItem(updatedAutofillPaymentInstruments);
+
+        updateInstrumentModifiedTotals();
+        mUI.updateSection(PaymentRequestUI.TYPE_PAYMENT_METHODS, mPaymentMethodsSection);
+    }
+
+    @Override
+    public void onCreditCardDeleted(String guid) {
+        if (mClient == null) return;
+        if (!mMerchantSupportsAutofillPaymentInstruments || mPaymentMethodsSection == null) return;
+
+        mPaymentMethodsSection.removeAndUnselectItem(guid);
+
+        updateInstrumentModifiedTotals();
+        mUI.updateSection(PaymentRequestUI.TYPE_PAYMENT_METHODS, mPaymentMethodsSection);
     }
 
     /**
@@ -1672,6 +1729,8 @@
         // UI has requested the full list of payment instruments. Provide it now.
         if (mPaymentInformationCallback != null) providePaymentInformation();
 
+        SettingsAutofillAndPaymentsObserver.getInstance().registerObserver(this);
+
         triggerPaymentAppUiSkipIfApplicable();
     }
 
@@ -1858,6 +1917,8 @@
             mObservedTabModel = null;
         }
 
+        SettingsAutofillAndPaymentsObserver.getInstance().unregisterObserver(this);
+
         // Destroy native objects.
         for (CurrencyFormatter formatter : mCurrencyFormatterMap.values()) {
             assert formatter != null;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/payments/SettingsAutofillAndPaymentsObserver.java b/chrome/android/java/src/org/chromium/chrome/browser/payments/SettingsAutofillAndPaymentsObserver.java
new file mode 100644
index 0000000..fdff69d
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/payments/SettingsAutofillAndPaymentsObserver.java
@@ -0,0 +1,143 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.payments;
+
+import org.chromium.base.ThreadUtils;
+import org.chromium.chrome.browser.autofill.PersonalDataManager.CreditCard;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/** The class to observe address and card changes in 'settings/Autofill and payment'. */
+public class SettingsAutofillAndPaymentsObserver {
+    private static final List<Observer> sObservers = new ArrayList<>();
+    private static SettingsAutofillAndPaymentsObserver sSettingsAutofillAndPaymentsObserver;
+
+    /** The interface to observe address and card changes in 'settings/Autofill and payment'. */
+    public interface Observer {
+        /**
+         * Called when user updates or adds an address.
+         *
+         * @param address The updated or added address.
+         */
+        void onAddressUpdated(AutofillAddress address);
+
+        /**
+         * Called when user deletes an address.
+         *
+         * @param guid The guid of the address.
+         */
+        void onAddressDeleted(String guid);
+
+        /**
+         * Called when user updates or addes a credit card.
+         *
+         * @param card The updated or added card.
+         */
+        void onCreditCardUpdated(CreditCard card);
+
+        /**
+         * Called when user deletes a credit card.
+         *
+         * @param guid The guid of the card.
+         */
+        void onCreditCardDeleted(String guid);
+    }
+
+    /** Gets an instance of this class. */
+    public static SettingsAutofillAndPaymentsObserver getInstance() {
+        ThreadUtils.assertOnUiThread();
+
+        if (sSettingsAutofillAndPaymentsObserver == null) {
+            sSettingsAutofillAndPaymentsObserver = new SettingsAutofillAndPaymentsObserver();
+        }
+        return sSettingsAutofillAndPaymentsObserver;
+    }
+
+    // Avoid accident instantiation.
+    private SettingsAutofillAndPaymentsObserver() {}
+
+    /**
+     * Registers the given observer.
+     *
+     * @param observer The observer to register.
+     */
+    public void registerObserver(Observer observer) {
+        sObservers.add(observer);
+    }
+
+    /**
+     * Unregisters the given observer.
+     *
+     * @param observer The observer to remove.
+     */
+    public void unregisterObserver(Observer observer) {
+        sObservers.remove(observer);
+    }
+
+    /**
+     * Notify the given address has been updated.
+     *
+     * @param address The given address.
+     */
+    public void notifyOnAddressUpdated(AutofillAddress address) {
+        for (Observer observer : sObservers) {
+            ThreadUtils.postOnUiThread(new Runnable() {
+                @Override
+                public void run() {
+                    observer.onAddressUpdated(address);
+                }
+            });
+        }
+    }
+
+    /**
+     * Notify the given address has been deleted.
+     *
+     * @param guid The given address guid.
+     */
+    public void notifyOnAddressDeleted(String guid) {
+        for (Observer observer : sObservers) {
+            ThreadUtils.postOnUiThread(new Runnable() {
+                @Override
+                public void run() {
+                    observer.onAddressDeleted(guid);
+                }
+            });
+        }
+    }
+
+    /**
+     * Notify the given card has been updated.
+     *
+     * @param card The given card.
+     */
+    public void notifyOnCreditCardUpdated(CreditCard card) {
+        for (Observer observer : sObservers) {
+            ThreadUtils.postOnUiThread(new Runnable() {
+                @Override
+                public void run() {
+                    observer.onCreditCardUpdated(card);
+                }
+            });
+        }
+    }
+
+    /**
+     * Notify the given card has been deleted.
+     *
+     * @param guid The given card guid.
+     */
+    public void notifyOnCreditCardDeleted(String guid) {
+        for (Observer observer : sObservers) {
+            ThreadUtils.postOnUiThread(new Runnable() {
+                @Override
+                public void run() {
+                    observer.onCreditCardDeleted(guid);
+                }
+            });
+        }
+    }
+}
\ No newline at end of file
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/payments/ui/SectionInformation.java b/chrome/android/java/src/org/chromium/chrome/browser/payments/ui/SectionInformation.java
index 6e3e93a..04a5356 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/payments/ui/SectionInformation.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/payments/ui/SectionInformation.java
@@ -4,6 +4,8 @@
 
 package org.chromium.chrome.browser.payments.ui;
 
+import android.text.TextUtils;
+
 import org.chromium.base.VisibleForTesting;
 import org.chromium.chrome.R;
 
@@ -165,6 +167,56 @@
     }
 
     /**
+     * Adds the given item at the head of the list if it doesn't exist and selects it if it is
+     * complete, otherwise updates the corresponding item and unselect it if it is incomplete.
+     *
+     * @param item The item to add or update.
+     */
+    public void addAndSelectOrUpdateItem(PaymentOption item) {
+        if (mItems == null) mItems = new ArrayList<>();
+        int i = 0;
+        for (; i < mItems.size(); i++) {
+            if (TextUtils.equals(mItems.get(i).getIdentifier(), item.getIdentifier())) {
+                break;
+            }
+        }
+        if (i < mItems.size()) {
+            mItems.set(i, item);
+            if (mSelectedItem == i && !item.isComplete()) mSelectedItem = NO_SELECTION;
+            return;
+        }
+
+        mItems.add(0, item);
+        if (item.isComplete()) {
+            mSelectedItem = 0;
+        } else {
+            mSelectedItem = NO_SELECTION;
+        }
+    }
+
+    /**
+     * Remove the given item and unselect it if it is the selected item. Sets selected item to
+     * INVALID_SELECTION if there is no item in this section.
+     *
+     * @param identifier The identifier of the removed item.
+     */
+    public void removeAndUnselectItem(String identifier) {
+        for (int i = 0; i < mItems.size(); i++) {
+            if (TextUtils.equals(mItems.get(i).getIdentifier(), identifier)) {
+                if (mSelectedItem == i) {
+                    mSelectedItem = NO_SELECTION;
+                } else if (mSelectedItem > 0) {
+                    // Update the selected item index.
+                    mSelectedItem -= mSelectedItem > i ? 1 : 0;
+                }
+                mItems.remove(i);
+                if (mItems.size() == 0) mSelectedItem = INVALID_SELECTION;
+                break;
+            }
+        }
+    }
+
+    /**
      * Returns the resource ID for the string telling users that they can add a new option.
      *
      * @return ID if the user can add a new option, or 0 if they can't.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/autofill/AutofillLocalCardEditor.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/autofill/AutofillLocalCardEditor.java
index a9385c8..9df84375 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/autofill/AutofillLocalCardEditor.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/autofill/AutofillLocalCardEditor.java
@@ -19,10 +19,10 @@
 
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.ChromeVersionInfo;
-import org.chromium.chrome.browser.autofill.CardType;
 import org.chromium.chrome.browser.autofill.PersonalDataManager;
 import org.chromium.chrome.browser.autofill.PersonalDataManager.AutofillProfile;
 import org.chromium.chrome.browser.autofill.PersonalDataManager.CreditCard;
+import org.chromium.chrome.browser.payments.SettingsAutofillAndPaymentsObserver;
 import org.chromium.chrome.browser.widget.CompatibilityTextInputLayout;
 
 import java.text.SimpleDateFormat;
@@ -180,15 +180,16 @@
                     R.string.payments_card_number_invalid_validation_message));
             return false;
         }
-        CreditCard card = new CreditCard(mGUID, AutofillAndPaymentsPreferences.SETTINGS_ORIGIN,
-                true /* isLocal */, false /* isCached */, mNameText.getText().toString().trim(),
-                cardNumber, "" /* obfuscatedNumber */,
-                String.valueOf(mExpirationMonth.getSelectedItemPosition() + 1),
-                (String) mExpirationYear.getSelectedItem(), "" /* basicCardPaymentType */,
-                0 /* issuerIconDrawableId */, CardType.UNKNOWN,
-                ((AutofillProfile) mBillingAddress.getSelectedItem()).getGUID() /* billing */,
-                "" /* serverId */);
-        personalDataManager.setCreditCard(card);
+        CreditCard card = personalDataManager.getCreditCardForNumber(cardNumber);
+        card.setGUID(mGUID);
+        card.setOrigin(AutofillAndPaymentsPreferences.SETTINGS_ORIGIN);
+        card.setName(mNameText.getText().toString().trim());
+        card.setMonth(String.valueOf(mExpirationMonth.getSelectedItemPosition() + 1));
+        card.setYear((String) mExpirationYear.getSelectedItem());
+        card.setBillingAddressId(((AutofillProfile) mBillingAddress.getSelectedItem()).getGUID());
+        // Set GUID for adding a new card.
+        card.setGUID(personalDataManager.setCreditCard(card));
+        SettingsAutofillAndPaymentsObserver.getInstance().notifyOnCreditCardUpdated(card);
         return true;
     }
 
@@ -196,6 +197,7 @@
     protected void deleteEntry() {
         if (mGUID != null) {
             PersonalDataManager.getInstance().deleteCreditCard(mGUID);
+            SettingsAutofillAndPaymentsObserver.getInstance().notifyOnCreditCardDeleted(mGUID);
         }
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/autofill/AutofillProfileEditorPreference.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/autofill/AutofillProfileEditorPreference.java
index 408c6ee..8e6db67 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/autofill/AutofillProfileEditorPreference.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/autofill/AutofillProfileEditorPreference.java
@@ -12,6 +12,7 @@
 import org.chromium.chrome.browser.autofill.PersonalDataManager;
 import org.chromium.chrome.browser.payments.AddressEditor;
 import org.chromium.chrome.browser.payments.AutofillAddress;
+import org.chromium.chrome.browser.payments.SettingsAutofillAndPaymentsObserver;
 import org.chromium.chrome.browser.payments.ui.EditorDialog;
 import org.chromium.chrome.browser.payments.ui.EditorObserverForTest;
 
@@ -64,6 +65,8 @@
             public void onResult(AutofillAddress address) {
                 if (address != null) {
                     PersonalDataManager.getInstance().setProfile(address.getProfile());
+                    SettingsAutofillAndPaymentsObserver.getInstance().notifyOnAddressUpdated(
+                            address);
                 }
                 if (mObserverForTest != null) {
                     mObserverForTest.onEditorReadyToEdit();
@@ -83,6 +86,8 @@
                 public void run() {
                     if (mGUID != null) {
                         PersonalDataManager.getInstance().deleteProfile(mGUID);
+                        SettingsAutofillAndPaymentsObserver.getInstance().notifyOnAddressDeleted(
+                                mGUID);
                     }
                     if (mObserverForTest != null) {
                         mObserverForTest.onEditorReadyToEdit();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/autofill/AutofillServerCardEditor.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/autofill/AutofillServerCardEditor.java
index 7ad0351..bd74cda 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/autofill/AutofillServerCardEditor.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/autofill/AutofillServerCardEditor.java
@@ -17,6 +17,7 @@
 import org.chromium.chrome.browser.autofill.PersonalDataManager;
 import org.chromium.chrome.browser.autofill.PersonalDataManager.AutofillProfile;
 import org.chromium.chrome.browser.customtabs.CustomTabActivity;
+import org.chromium.chrome.browser.payments.SettingsAutofillAndPaymentsObserver;
 
 /**
  * Server credit card settings.
@@ -97,6 +98,7 @@
             mCard.setBillingAddressId(
                     ((AutofillProfile) mBillingAddress.getSelectedItem()).getGUID());
             PersonalDataManager.getInstance().updateServerCardBillingAddress(mCard);
+            SettingsAutofillAndPaymentsObserver.getInstance().notifyOnCreditCardUpdated(mCard);
         }
         return true;
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/datareduction/DataReductionStatsPreference.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/datareduction/DataReductionStatsPreference.java
index fbc2cac..691992b 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/datareduction/DataReductionStatsPreference.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/datareduction/DataReductionStatsPreference.java
@@ -26,7 +26,6 @@
 import org.chromium.base.Callback;
 import org.chromium.base.ContextUtils;
 import org.chromium.chrome.R;
-import org.chromium.chrome.browser.ChromeFeatureList;
 import org.chromium.chrome.browser.net.spdyproxy.DataReductionProxySettings;
 import org.chromium.chrome.browser.util.FileSizeUtil;
 import org.chromium.third_party.android.datausagechart.ChartDataUsageView;
@@ -76,11 +75,9 @@
      * the breakdown can be shown.
      */
     public static void initializeDataReductionSiteBreakdownPref() {
-        // If the site breakdown feature isn't enabled or the pref has already been set, don't set
-        // it.
-        if (!ChromeFeatureList.isEnabled(ChromeFeatureList.DATA_REDUCTION_SITE_BREAKDOWN)
-                || ContextUtils.getAppSharedPreferences().contains(
-                           PREF_DATA_REDUCTION_SITE_BREAKDOWN_ALLOWED_DATE)) {
+        // If the site breakdown pref has already been set, don't set it.
+        if (ContextUtils.getAppSharedPreferences().contains(
+                    PREF_DATA_REDUCTION_SITE_BREAKDOWN_ALLOWED_DATE)) {
             return;
         }
 
@@ -101,12 +98,7 @@
 
     public DataReductionStatsPreference(Context context, AttributeSet attrs) {
         super(context, attrs);
-
-        if (ChromeFeatureList.isEnabled(ChromeFeatureList.DATA_REDUCTION_SITE_BREAKDOWN)) {
-            setWidgetLayoutResource(R.layout.data_reduction_stats_layout);
-        } else {
-            setWidgetLayoutResource(R.layout.data_reduction_old_stats_layout);
-        }
+        setWidgetLayoutResource(R.layout.data_reduction_stats_layout);
     }
 
     @Override
@@ -191,8 +183,6 @@
         super.onBindView(view);
         mDataUsageTextView = (TextView) view.findViewById(R.id.data_reduction_usage);
         mDataSavingsTextView = (TextView) view.findViewById(R.id.data_reduction_savings);
-        mOriginalSizeTextView = (TextView) view.findViewById(R.id.data_reduction_original_size);
-        mReceivedSizeTextView = (TextView) view.findViewById(R.id.data_reduction_compressed_size);
         mPercentReductionTextView = (TextView) view.findViewById(R.id.data_reduction_percent);
         mStartDateTextView = (TextView) view.findViewById(R.id.data_reduction_start_date);
         mEndDateTextView = (TextView) view.findViewById(R.id.data_reduction_end_date);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrShellImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrShellImpl.java
index 37b1479..85c7d58 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrShellImpl.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrShellImpl.java
@@ -492,11 +492,12 @@
         mLastContentHeight = height;
         mLastContentDpr = dpr;
 
+        // Native pages don't listen to our DPR changes, so to get them to render at the correct
+        // size we need to make them larger.
+        DisplayAndroid primaryDisplay = DisplayAndroid.getNonMultiDisplay(mActivity);
+        float dip = primaryDisplay.getDipScale();
+
         if (mNativePage != null) {
-            // Native pages don't listen to our DPR changes, so to get them to render at the correct
-            // size we need to make them larger.
-            DisplayAndroid primaryDisplay = DisplayAndroid.getNonMultiDisplay(mActivity);
-            float dip = primaryDisplay.getDipScale();
             width *= (dip / dpr);
             height *= (dip / dpr);
         }
@@ -505,7 +506,7 @@
         int surfaceHeight = (int) Math.ceil(height * dpr);
 
         Point size = new Point(surfaceWidth, surfaceHeight);
-        mContentVirtualDisplay.update(size, dpr, null, null, null, null, null);
+        mContentVirtualDisplay.update(size, dpr, dip / dpr, null, null, null, null, null);
         assert mTab != null;
         if (mTab.getContentViewCore() != null) {
             nativeOnPhysicalBackingSizeChanged(
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheetContentController.java b/chrome/android/java/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheetContentController.java
index 4730657..937e493 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheetContentController.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheetContentController.java
@@ -242,6 +242,7 @@
 
     @Override
     public void onFinishInflate() {
+        super.onFinishInflate();
         BrowserStartupController.get(LibraryProcessType.PROCESS_BROWSER)
                 .addStartupCompletedObserver(new BrowserStartupController.StartupCallback() {
                     @Override
diff --git a/chrome/android/java_sources.gni b/chrome/android/java_sources.gni
index 32ea33d..ea43e92 100644
--- a/chrome/android/java_sources.gni
+++ b/chrome/android/java_sources.gni
@@ -846,6 +846,7 @@
   "java/src/org/chromium/chrome/browser/payments/PaymentResponseHelper.java",
   "java/src/org/chromium/chrome/browser/payments/ServiceWorkerPaymentApp.java",
   "java/src/org/chromium/chrome/browser/payments/ServiceWorkerPaymentAppBridge.java",
+  "java/src/org/chromium/chrome/browser/payments/SettingsAutofillAndPaymentsObserver.java",
   "java/src/org/chromium/chrome/browser/payments/ShippingStrings.java",
   "java/src/org/chromium/chrome/browser/payments/SslValidityChecker.java",
   "java/src/org/chromium/chrome/browser/payments/UriUtils.java",
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/PopularUrlsTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/PopularUrlsTest.java
index 3383b311..d9c9c83 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/PopularUrlsTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/PopularUrlsTest.java
@@ -30,13 +30,17 @@
 
 import java.io.BufferedReader;
 import java.io.File;
+import java.io.FileInputStream;
 import java.io.FileNotFoundException;
-import java.io.FileReader;
-import java.io.FileWriter;
+import java.io.FileOutputStream;
 import java.io.IOException;
+import java.io.InputStreamReader;
 import java.io.OutputStreamWriter;
+import java.io.Reader;
+import java.io.UnsupportedEncodingException;
+import java.io.Writer;
+import java.util.ArrayList;
 import java.util.Iterator;
-import java.util.LinkedList;
 import java.util.List;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.TimeoutException;
@@ -91,14 +95,17 @@
     }
 
     private BufferedReader getInputStream(File inputFile) throws FileNotFoundException {
-        FileReader fileReader = new FileReader(inputFile);
-        BufferedReader bufferedReader = new BufferedReader(fileReader);
-
-        return bufferedReader;
+        try {
+            Reader fileReader = new InputStreamReader(new FileInputStream(inputFile), "UTF-8");
+            return new BufferedReader(fileReader);
+        } catch (UnsupportedEncodingException ex) {
+            throw new RuntimeException("UTF-8 not present...time to give up on this charade.", ex);
+        }
     }
 
     private OutputStreamWriter getOutputStream(File outputFile) throws IOException {
-        return new FileWriter(outputFile, mStatus.getIsRecovery());
+        return new OutputStreamWriter(
+                new FileOutputStream(outputFile, mStatus.getIsRecovery()), "UTF-8");
     }
 
     private void logToStream(String str, OutputStreamWriter writer) throws IOException {
@@ -122,14 +129,14 @@
 
         public RunStatus(File file) throws IOException {
             mFile = file;
-            FileReader input = null;
+            Reader input = null;
             BufferedReader reader = null;
             mIsRecovery = false;
             mAllClear = false;
             mIteration = 0;
             mPage = 0;
             try {
-                input = new FileReader(mFile);
+                input = new InputStreamReader(new FileInputStream(mFile), "UTF-8");
                 mIsRecovery = true;
                 reader = new BufferedReader(input);
                 String line = reader.readLine();
@@ -161,12 +168,12 @@
         }
 
         public void write() throws IOException {
-            FileWriter output = null;
+            Writer output = null;
             if (mFile.exists()) {
                 mFile.delete();
             }
             try {
-                output = new FileWriter(mFile);
+                output = new OutputStreamWriter(new FileOutputStream(mFile), "UTF-8");
                 output.write(mIteration + NEW_LINE);
                 output.write(mPage + NEW_LINE);
                 output.write(mUrl + NEW_LINE);
@@ -322,7 +329,7 @@
     private void loopUrls(BufferedReader input, OutputStreamWriter outputWriter,
             OutputStreamWriter failureWriter, boolean clearCache, int loopCount)
             throws IOException, InterruptedException {
-        List<String> pages = new LinkedList<String>();
+        List<String> pages = new ArrayList<>();
 
         String page;
         while (null != (page = input.readLine())) {
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/VideoFullscreenOrientationLockChromeTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/VideoFullscreenOrientationLockChromeTest.java
index fabed21f..d476b8b1 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/VideoFullscreenOrientationLockChromeTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/VideoFullscreenOrientationLockChromeTest.java
@@ -130,7 +130,8 @@
         // Orientation lock should be disabled when download viewer activity is started.
         Uri fileUri = Uri.parse(UrlUtils.getIsolatedTestFileUrl(VIDEO_URL));
         String mimeType = "video/mp4";
-        Intent intent = MediaViewerUtils.getMediaViewerIntent(fileUri, fileUri, mimeType);
+        Intent intent = MediaViewerUtils.getMediaViewerIntent(
+                fileUri, fileUri, mimeType, true /* allowExternalAppHandlers */);
         IntentHandler.startActivityForTrustedIntent(intent);
         waitUntilUnlocked();
 
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/preferences/datareduction/DataReductionStatsPreferenceTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/preferences/datareduction/DataReductionStatsPreferenceTest.java
index 397b336..b8610dd 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/preferences/datareduction/DataReductionStatsPreferenceTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/preferences/datareduction/DataReductionStatsPreferenceTest.java
@@ -22,13 +22,9 @@
 import org.chromium.base.test.BaseJUnit4ClassRunner;
 import org.chromium.base.test.util.AdvancedMockContext;
 import org.chromium.base.test.util.Feature;
-import org.chromium.chrome.browser.ChromeFeatureList;
 import org.chromium.chrome.browser.net.spdyproxy.DataReductionProxySettings;
 import org.chromium.chrome.browser.test.ChromeBrowserTestRule;
 
-import java.util.HashMap;
-import java.util.Map;
-
 /**
  * Unit test suite for DataReductionStatsPreference.
  */
@@ -80,28 +76,6 @@
         ContextUtils.initApplicationContextForTests(mContext);
         mSettings = new TestDataReductionProxySettings();
         DataReductionProxySettings.setInstanceForTesting(mSettings);
-
-        Map<String, Boolean> features = new HashMap<>();
-        features.put(ChromeFeatureList.DATA_REDUCTION_SITE_BREAKDOWN, true);
-        ChromeFeatureList.setTestFeatures(features);
-    }
-
-    /**
-     * Tests that the site breakdown pref isn't initialized if the feature isn't enabled.
-     */
-    @Test
-    @SmallTest
-    @UiThreadTest
-    @Feature({"DataReduction"})
-    public void testDontInitializeSiteBreakdownPref() throws Throwable {
-        // Disable the feature
-        Map<String, Boolean> features = new HashMap<>();
-        features.put(ChromeFeatureList.DATA_REDUCTION_SITE_BREAKDOWN, false);
-        ChromeFeatureList.setTestFeatures(features);
-
-        DataReductionStatsPreference.initializeDataReductionSiteBreakdownPref();
-        Assert.assertFalse(ContextUtils.getAppSharedPreferences().contains(
-                PREF_DATA_REDUCTION_SITE_BREAKDOWN_ALLOWED_DATE));
     }
 
     /**
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/sync/ui/PassphraseActivityTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/sync/ui/PassphraseActivityTest.java
index 70b3ca8..e7e769c 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/sync/ui/PassphraseActivityTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/sync/ui/PassphraseActivityTest.java
@@ -10,7 +10,6 @@
 import android.content.Intent;
 import android.os.Bundle;
 import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
 
 import org.junit.After;
 import org.junit.Assert;
@@ -22,7 +21,7 @@
 
 import org.chromium.base.ThreadUtils;
 import org.chromium.base.test.BaseJUnit4ClassRunner;
-import org.chromium.base.test.util.Feature;
+import org.chromium.base.test.util.DisabledTest;
 import org.chromium.base.test.util.RetryOnFailure;
 import org.chromium.chrome.browser.sync.FakeProfileSyncService;
 import org.chromium.chrome.browser.sync.ProfileSyncService;
@@ -57,9 +56,10 @@
      * This is a regression test for http://crbug.com/469890.
      */
     @Test
-    @SmallTest
-    @Feature({"Sync"})
+    // @SmallTest
+    // @Feature({"Sync"})
     @RetryOnFailure
+    @DisabledTest
     public void testCallbackAfterBackgrounded() throws Exception {
         InstrumentationRegistry.getInstrumentation().waitForIdleSync();
         SigninTestUtil.addAndSignInTestAccount();
@@ -114,4 +114,4 @@
             }
         });
     }
-}
\ No newline at end of file
+}
diff --git a/chrome/app/android/chrome_main_delegate_android.cc b/chrome/app/android/chrome_main_delegate_android.cc
index 54a2761..27a8342 100644
--- a/chrome/app/android/chrome_main_delegate_android.cc
+++ b/chrome/app/android/chrome_main_delegate_android.cc
@@ -92,8 +92,9 @@
     // Also only record the start time the first time round, since this is the
     // start time of the application, and will be same for all requests.
     if (!browser_runner_.get()) {
-      base::Time time = chrome::android::GetMainEntryPointTime();
-      startup_metric_utils::RecordMainEntryPointTime(time);
+      startup_metric_utils::RecordMainEntryPointTime(
+          chrome::android::GetMainEntryPointTimeWallClock(),
+          chrome::android::GetMainEntryPointTimeTicks());
       browser_runner_.reset(content::BrowserMainRunner::Create());
     }
     return browser_runner_->Initialize(main_function_params);
diff --git a/chrome/app/chrome_main_delegate.cc b/chrome/app/chrome_main_delegate.cc
index ba47751..934cee1 100644
--- a/chrome/app/chrome_main_delegate.cc
+++ b/chrome/app/chrome_main_delegate.cc
@@ -487,7 +487,8 @@
 // from the Java side until it has initialized the JNI. See
 // ChromeMainDelegateAndroid.
 #if !defined(OS_ANDROID)
-  startup_metric_utils::RecordMainEntryPointTime(base::Time::Now());
+  startup_metric_utils::RecordMainEntryPointTime(base::Time::Now(),
+                                                 base::TimeTicks::Now());
 #endif
 }
 #endif  // !defined(CHROME_MULTIPLE_DLL_CHILD)
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index 6ca1cd3..65d1c90 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -2080,12 +2080,6 @@
          data_reduction_proxy::features::kDataReductionMainMenu,
          kDataReductionMainMenuFeatureVariations,
          "DataReductionProxyMainMenu")},
-    {"enable-data-reduction-proxy-site-breakdown",
-     flag_descriptions::kEnableDataReductionProxySiteBreakdownName,
-     flag_descriptions::kEnableDataReductionProxySiteBreakdownDescription,
-     kOsAndroid,
-     FEATURE_VALUE_TYPE(
-         data_reduction_proxy::features::kDataReductionSiteBreakdown)},
     {"enable-offline-previews", flag_descriptions::kEnableOfflinePreviewsName,
      flag_descriptions::kEnableOfflinePreviewsDescription, kOsAndroid,
      FEATURE_VALUE_TYPE(previews::features::kOfflinePreviews)},
@@ -3071,11 +3065,6 @@
      SINGLE_VALUE_TYPE(chromeos::switches::kEnableChromeVoxArcSupport)},
 #endif  // defined(OS_CHROMEOS)
 
-    {"enable-fetch-keepalive-timeout-setting",
-     flag_descriptions::kFetchKeepaliveTimeoutSettingName,
-     flag_descriptions::kFetchKeepaliveTimeoutSettingDescription, kOsAll,
-     FEATURE_VALUE_TYPE(features::kFetchKeepaliveTimeoutSetting)},
-
     {"enable-renderer-side-resource-scheduler",
      flag_descriptions::kRendererSideResourceSchedulerName,
      flag_descriptions::kRendererSideResourceSchedulerDescription, kOsAll,
diff --git a/chrome/browser/android/bookmarks/bookmark_bridge.cc b/chrome/browser/android/bookmarks/bookmark_bridge.cc
index 7dd6dcb..7fc8308 100644
--- a/chrome/browser/android/bookmarks/bookmark_bridge.cc
+++ b/chrome/browser/android/bookmarks/bookmark_bridge.cc
@@ -439,6 +439,36 @@
       env, child->id(), GetBookmarkType(child));
 }
 
+jint BookmarkBridge::GetTotalBookmarkCount(
+    JNIEnv* env,
+    const base::android::JavaParamRef<jobject>& obj,
+    jlong id,
+    jint type) {
+  DCHECK(IsLoaded());
+
+  std::queue<const BookmarkNode*> nodes;
+  const BookmarkNode* parent = GetNodeByID(id, type);
+  DCHECK(parent->is_folder());
+
+  int count = 0;
+  nodes.push(parent);
+  while (!nodes.empty()) {
+    const BookmarkNode* node = nodes.front();
+    nodes.pop();
+
+    for (int i = 0; i < node->child_count(); ++i) {
+      const BookmarkNode* child = node->GetChild(i);
+      if (child->is_folder()) {
+        nodes.push(child);
+      } else {
+        count += 1;
+      }
+    }
+  }
+
+  return count;
+}
+
 void BookmarkBridge::SetBookmarkTitle(JNIEnv* env,
                                        const JavaParamRef<jobject>& obj,
                                        jlong id,
diff --git a/chrome/browser/android/bookmarks/bookmark_bridge.h b/chrome/browser/android/bookmarks/bookmark_bridge.h
index 9b486326..4222738 100644
--- a/chrome/browser/android/bookmarks/bookmark_bridge.h
+++ b/chrome/browser/android/bookmarks/bookmark_bridge.h
@@ -109,6 +109,13 @@
       jint type,
       jint index);
 
+  // Get the number of bookmarks in the sub tree of the specified bookmark node.
+  // The specified node must be of folder type.
+  jint GetTotalBookmarkCount(JNIEnv* env,
+                             const base::android::JavaParamRef<jobject>& obj,
+                             jlong id,
+                             jint type);
+
   void SetBookmarkTitle(JNIEnv* env,
                         const base::android::JavaParamRef<jobject>& obj,
                         jlong id,
diff --git a/chrome/browser/android/chrome_feature_list.cc b/chrome/browser/android/chrome_feature_list.cc
index 58b8b70..0d05955 100644
--- a/chrome/browser/android/chrome_feature_list.cc
+++ b/chrome/browser/android/chrome_feature_list.cc
@@ -93,7 +93,6 @@
     &kDontPrefetchLibraries,
     &kDownloadHomeShowStorageInfo,
     &data_reduction_proxy::features::kDataReductionMainMenu,
-    &data_reduction_proxy::features::kDataReductionSiteBreakdown,
     &kFullscreenActivity,
     &kImprovedA2HS,
     &kLanguagesPreference,
diff --git a/chrome/browser/android/compositor/scene_layer/contextual_search_scene_layer.cc b/chrome/browser/android/compositor/scene_layer/contextual_search_scene_layer.cc
index 4d9aee5..5e14561 100644
--- a/chrome/browser/android/compositor/scene_layer/contextual_search_scene_layer.cc
+++ b/chrome/browser/android/compositor/scene_layer/contextual_search_scene_layer.cc
@@ -201,7 +201,7 @@
       base::MakeUnique<BitmapFetcher>(gurl, this, NO_TRAFFIC_ANNOTATION_YET);
   fetcher_->Init(
       std::string(),
-      blink::kWebReferrerPolicyNoReferrerWhenDowngradeOriginWhenCrossOrigin,
+      net::URLRequest::REDUCE_REFERRER_GRANULARITY_ON_TRANSITION_CROSS_ORIGIN,
       net::LOAD_NORMAL);
   fetcher_->Start(loader_factory);
 }
diff --git a/chrome/browser/android/metrics/uma_utils.cc b/chrome/browser/android/metrics/uma_utils.cc
index 32c6b90..85effc8 100644
--- a/chrome/browser/android/metrics/uma_utils.cc
+++ b/chrome/browser/android/metrics/uma_utils.cc
@@ -18,13 +18,33 @@
 namespace chrome {
 namespace android {
 
-base::Time GetMainEntryPointTime() {
+base::Time GetMainEntryPointTimeWallClock() {
   JNIEnv* env = base::android::AttachCurrentThread();
   int64_t startTimeUnixMs = Java_UmaUtils_getMainEntryPointWallTime(env);
   return base::Time::UnixEpoch() +
          base::TimeDelta::FromMilliseconds(startTimeUnixMs);
 }
 
+base::TimeTicks GetMainEntryPointTimeTicks() {
+  JNIEnv* env = base::android::AttachCurrentThread();
+  // Generally the use of base::TimeTicks::FromInternalValue() is discouraged.
+  //
+  // The implementation of the SystemClock.uptimeMillis() in AOSP uses the same
+  // clock as base::TimeTicks::Now(): clock_gettime(CLOCK_MONOTONIC), see in
+  // platform/system/code:
+  // 1. libutils/SystemClock.cpp
+  // 2. libutils/Timers.cpp
+  //
+  // We are not aware of any motivations for Android OEMs to modify the AOSP
+  // implementation of either uptimeMillis() or clock_gettime(CLOCK_MONOTONIC),
+  // so we assume that there are no such customizations.
+  //
+  // Under these assumptions the conversion is as safe as copying the value of
+  // base::TimeTicks::Now() with a loss of sub-millisecond precision.
+  return base::TimeTicks::FromInternalValue(
+      Java_UmaUtils_getMainEntryPointTicks(env) * 1000);
+}
+
 static jboolean JNI_UmaUtils_IsClientInMetricsReportingSample(
     JNIEnv* env,
     const JavaParamRef<jclass>& obj) {
diff --git a/chrome/browser/android/metrics/uma_utils.h b/chrome/browser/android/metrics/uma_utils.h
index 9d03494c..2360305 100644
--- a/chrome/browser/android/metrics/uma_utils.h
+++ b/chrome/browser/android/metrics/uma_utils.h
@@ -12,7 +12,8 @@
 namespace chrome {
 namespace android {
 
-base::Time GetMainEntryPointTime();
+base::Time GetMainEntryPointTimeWallClock();
+base::TimeTicks GetMainEntryPointTimeTicks();
 
 }  // namespace android
 }  // namespace chrome
diff --git a/chrome/browser/apps/guest_view/web_view_interactive_browsertest.cc b/chrome/browser/apps/guest_view/web_view_interactive_browsertest.cc
index 404fa6e..a6fe7f7 100644
--- a/chrome/browser/apps/guest_view/web_view_interactive_browsertest.cc
+++ b/chrome/browser/apps/guest_view/web_view_interactive_browsertest.cc
@@ -55,6 +55,7 @@
 #include "ui/events/keycodes/keyboard_codes.h"
 #include "ui/gfx/geometry/rect.h"
 #include "ui/gfx/range/range.h"
+#include "ui/touch_selection/touch_selection_menu_runner.h"
 
 using extensions::AppWindow;
 using extensions::ExtensionsAPIClient;
@@ -1586,6 +1587,60 @@
 }
 #endif
 
+#if !defined(OS_MACOSX)
+IN_PROC_BROWSER_TEST_P(WebViewInteractiveTest, LongPressSelection) {
+  if (!base::FeatureList::IsEnabled(::features::kGuestViewCrossProcessFrames))
+    return;
+
+  SetupTest("web_view/text_selection",
+            "/extensions/platform_apps/web_view/text_selection/guest.html");
+  ASSERT_TRUE(guest_web_contents());
+  ASSERT_TRUE(embedder_web_contents());
+  ASSERT_TRUE(ui_test_utils::ShowAndFocusNativeWindow(GetPlatformAppWindow()));
+
+  auto filter = std::make_unique<content::InputMsgWatcher>(
+      guest_web_contents()->GetRenderWidgetHostView()->GetRenderWidgetHost(),
+      blink::WebInputEvent::kGestureLongPress);
+
+  // Wait for guest to load (without this the events never reach the guest).
+  scoped_refptr<content::MessageLoopRunner> message_loop_runner =
+      new content::MessageLoopRunner;
+  base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+      FROM_HERE, message_loop_runner->QuitClosure(),
+      base::TimeDelta::FromMilliseconds(200));
+  message_loop_runner->Run();
+
+  gfx::Rect guest_rect = guest_web_contents()->GetContainerBounds();
+  gfx::Point embedder_origin =
+      embedder_web_contents()->GetContainerBounds().origin();
+  guest_rect.Offset(-embedder_origin.x(), -embedder_origin.y());
+
+  // Mouse click is necessary for focus.
+  content::SimulateMouseClickAt(embedder_web_contents(), 0,
+                                blink::WebMouseEvent::Button::kLeft,
+                                guest_rect.CenterPoint());
+
+  content::SimulateLongPressAt(embedder_web_contents(),
+                               guest_rect.CenterPoint());
+  EXPECT_EQ(content::INPUT_EVENT_ACK_STATE_CONSUMED,
+            filter->GetAckStateWaitIfNecessary());
+
+  // Give enough time for the quick menu to fire.
+  message_loop_runner = new content::MessageLoopRunner;
+  base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+      FROM_HERE, message_loop_runner->QuitClosure(),
+      base::TimeDelta::FromMilliseconds(200));
+  message_loop_runner->Run();
+
+// TODO: Fix quick menu opening on Windows.
+#if !defined(OS_WIN)
+  EXPECT_TRUE(ui::TouchSelectionMenuRunner::GetInstance()->IsRunning());
+#endif
+
+  EXPECT_FALSE(guest_web_contents()->IsShowingContextMenu());
+}
+#endif
+
 #if defined(OS_MACOSX)
 IN_PROC_BROWSER_TEST_P(WebViewInteractiveTest, TextSelection) {
   SetupTest("web_view/text_selection",
diff --git a/chrome/browser/bitmap_fetcher/bitmap_fetcher.cc b/chrome/browser/bitmap_fetcher/bitmap_fetcher.cc
index b12ecc0..6e423ee 100644
--- a/chrome/browser/bitmap_fetcher/bitmap_fetcher.cc
+++ b/chrome/browser/bitmap_fetcher/bitmap_fetcher.cc
@@ -7,7 +7,6 @@
 #include "content/public/browser/browser_context.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/storage_partition.h"
-#include "content/public/common/referrer.h"
 #include "net/url_request/url_fetcher.h"
 #include "net/url_request/url_request_context_getter.h"
 #include "net/url_request/url_request_status.h"
@@ -22,7 +21,7 @@
 }
 
 void BitmapFetcher::Init(const std::string& referrer,
-                         blink::WebReferrerPolicy referrer_policy,
+                         net::URLRequest::ReferrerPolicy referrer_policy,
                          int load_flags) {
   if (simple_loader_ != NULL)
     return;
@@ -30,8 +29,7 @@
   auto resource_request = std::make_unique<content::ResourceRequest>();
   resource_request->url = url_;
   resource_request->referrer = GURL(referrer);
-  resource_request->referrer_policy =
-      content::Referrer::ReferrerPolicyForUrlRequest(referrer_policy);
+  resource_request->referrer_policy = referrer_policy;
   resource_request->load_flags = load_flags;
   simple_loader_ = content::SimpleURLLoader::Create(std::move(resource_request),
                                                     traffic_annotation_);
diff --git a/chrome/browser/bitmap_fetcher/bitmap_fetcher.h b/chrome/browser/bitmap_fetcher/bitmap_fetcher.h
index 0e459e44..0083b3135 100644
--- a/chrome/browser/bitmap_fetcher/bitmap_fetcher.h
+++ b/chrome/browser/bitmap_fetcher/bitmap_fetcher.h
@@ -15,6 +15,7 @@
 #include "content/public/common/simple_url_loader.h"
 #include "content/public/common/url_loader_factory.mojom.h"
 #include "net/traffic_annotation/network_traffic_annotation.h"
+#include "net/url_request/url_request.h"
 #include "url/gurl.h"
 
 class SkBitmap;
@@ -37,7 +38,7 @@
   // |net::LOAD_NORMAL| is appropriate.  Init may be called more than once in
   // some cases.  If so, subsequent starts will be ignored.
   void Init(const std::string& referrer,
-            blink::WebReferrerPolicy referrer_policy,
+            net::URLRequest::ReferrerPolicy referrer_policy,
             int load_flags);
 
   // Start fetching the URL with the fetcher. The delegate is notified
diff --git a/chrome/browser/bitmap_fetcher/bitmap_fetcher_browsertest.cc b/chrome/browser/bitmap_fetcher/bitmap_fetcher_browsertest.cc
index 8c17e644..ea1cc0e 100644
--- a/chrome/browser/bitmap_fetcher/bitmap_fetcher_browsertest.cc
+++ b/chrome/browser/bitmap_fetcher/bitmap_fetcher_browsertest.cc
@@ -149,7 +149,7 @@
   // an image in a callback to OnImageDecoded().
   fetcher.Init(
       std::string(),
-      blink::kWebReferrerPolicyNoReferrerWhenDowngradeOriginWhenCrossOrigin,
+      net::URLRequest::REDUCE_REFERRER_GRANULARITY_ON_TRANSITION_CROSS_ORIGIN,
       net::LOAD_NORMAL);
   fetcher.Start(
       content::BrowserContext::GetDefaultStoragePartition(browser()->profile())
@@ -198,7 +198,7 @@
 
   fetcher.Init(
       std::string(),
-      blink::kWebReferrerPolicyNoReferrerWhenDowngradeOriginWhenCrossOrigin,
+      net::URLRequest::REDUCE_REFERRER_GRANULARITY_ON_TRANSITION_CROSS_ORIGIN,
       net::LOAD_NORMAL);
   fetcher.Start(
       content::BrowserContext::GetDefaultStoragePartition(browser()->profile())
@@ -217,7 +217,7 @@
 
   fetcher.Init(
       std::string(),
-      blink::kWebReferrerPolicyNoReferrerWhenDowngradeOriginWhenCrossOrigin,
+      net::URLRequest::REDUCE_REFERRER_GRANULARITY_ON_TRANSITION_CROSS_ORIGIN,
       net::LOAD_NORMAL);
   fetcher.Start(
       content::BrowserContext::GetDefaultStoragePartition(browser()->profile())
diff --git a/chrome/browser/bitmap_fetcher/bitmap_fetcher_service.cc b/chrome/browser/bitmap_fetcher/bitmap_fetcher_service.cc
index d6b8b62..56fbf3c 100644
--- a/chrome/browser/bitmap_fetcher/bitmap_fetcher_service.cc
+++ b/chrome/browser/bitmap_fetcher/bitmap_fetcher_service.cc
@@ -132,7 +132,7 @@
 
   new_fetcher->Init(
       std::string(),
-      blink::kWebReferrerPolicyNoReferrerWhenDowngradeOriginWhenCrossOrigin,
+      net::URLRequest::REDUCE_REFERRER_GRANULARITY_ON_TRANSITION_CROSS_ORIGIN,
       net::LOAD_NORMAL);
   new_fetcher->Start(
       content::BrowserContext::GetDefaultStoragePartition(context_)
diff --git a/chrome/browser/browsing_data/OWNERS b/chrome/browser/browsing_data/OWNERS
index 1f8f137..9ab8416 100644
--- a/chrome/browser/browsing_data/OWNERS
+++ b/chrome/browser/browsing_data/OWNERS
@@ -1,7 +1,3 @@
-bauerb@chromium.org
-markusheintz@chromium.org
-michaeln@chromium.org
-mkwst@chromium.org
-msramek@chromium.org
+file://content/browser/browsing_data/OWNERS
 
 # COMPONENT: Privacy
diff --git a/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate.cc b/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate.cc
index 1da88bf22..85e3085e 100644
--- a/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate.cc
+++ b/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate.cc
@@ -84,6 +84,7 @@
 #include "net/http/http_transaction_factory.h"
 #include "net/reporting/reporting_browsing_data_remover.h"
 #include "net/reporting/reporting_service.h"
+#include "net/url_request/network_error_logging_delegate.h"
 #include "net/url_request/url_request_context.h"
 #include "net/url_request/url_request_context_getter.h"
 #include "url/url_util.h"
@@ -260,6 +261,17 @@
     service->RemoveBrowsingData(data_type_mask, origin_filter);
 }
 
+void ClearNetworkErrorLoggingOnIOThread(
+    net::URLRequestContextGetter* context,
+    const base::RepeatingCallback<bool(const GURL&)>& origin_filter) {
+  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+  net::NetworkErrorLoggingDelegate* delegate =
+      context->GetURLRequestContext()->network_error_logging_delegate();
+  if (delegate)
+    delegate->RemoveBrowsingData(origin_filter);
+}
+
 #if defined(OS_ANDROID)
 void ClearPrecacheInBackground(content::BrowserContext* browser_context) {
   // Precache code was removed in M61 but the sqlite database file could be
@@ -361,6 +373,7 @@
 #endif
       clear_auto_sign_in_(sub_task_forward_callback_),
       clear_reporting_cache_(sub_task_forward_callback_),
+      clear_network_error_logging_(sub_task_forward_callback_),
       clear_video_perf_history_(sub_task_forward_callback_),
 #if BUILDFLAG(ENABLE_PLUGINS)
       flash_lso_helper_(BrowsingDataFlashLSOHelper::Create(browser_context)),
@@ -1109,6 +1122,19 @@
         UIThreadTrampoline(clear_reporting_cache_.GetCompletionCallback()));
   }
 
+  if ((remove_mask & content::BrowsingDataRemover::DATA_TYPE_COOKIES) ||
+      (remove_mask & DATA_TYPE_HISTORY)) {
+    scoped_refptr<net::URLRequestContextGetter> context =
+        profile_->GetRequestContext();
+
+    clear_network_error_logging_.Start();
+    BrowserThread::PostTaskAndReply(
+        BrowserThread::IO, FROM_HERE,
+        base::BindOnce(&ClearNetworkErrorLoggingOnIOThread,
+                       base::RetainedRef(std::move(context)), filter),
+        UIThreadTrampoline(
+            clear_network_error_logging_.GetCompletionCallback()));
+  }
 //////////////////////////////////////////////////////////////////////////////
 // DATA_TYPE_WEB_APP_DATA
 #if defined(OS_ANDROID)
@@ -1159,6 +1185,7 @@
 #endif
          !clear_auto_sign_in_.is_pending() &&
          !clear_reporting_cache_.is_pending() &&
+         !clear_network_error_logging_.is_pending() &&
          !clear_video_perf_history_.is_pending() && !clear_plugin_data_count_;
 }
 
diff --git a/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate.h b/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate.h
index 09c34a15..a9aedf5 100644
--- a/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate.h
+++ b/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate.h
@@ -281,6 +281,7 @@
 #endif
   SubTask clear_auto_sign_in_;
   SubTask clear_reporting_cache_;
+  SubTask clear_network_error_logging_;
   SubTask clear_video_perf_history_;
   // Counts the number of plugin data tasks. Should be the number of LSO cookies
   // to be deleted, or 1 while we're fetching LSO cookies or deleting in bulk.
diff --git a/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate_unittest.cc b/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate_unittest.cc
index 6a5b083..048d4438 100644
--- a/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate_unittest.cc
+++ b/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate_unittest.cc
@@ -82,6 +82,7 @@
 #include "net/http/http_transaction_factory.h"
 #include "net/reporting/reporting_browsing_data_remover.h"
 #include "net/reporting/reporting_service.h"
+#include "net/url_request/network_error_logging_delegate.h"
 #include "net/url_request/url_request_context.h"
 #include "net/url_request/url_request_context_getter.h"
 #include "third_party/skia/include/core/SkBitmap.h"
@@ -916,11 +917,11 @@
 
 class MockReportingService : public net::ReportingService {
  public:
-  MockReportingService() {}
+  MockReportingService() = default;
 
   // net::ReportingService implementation:
 
-  ~MockReportingService() override {}
+  ~MockReportingService() override = default;
 
   void QueueReport(const GURL& url,
                    const std::string& group,
@@ -949,14 +950,14 @@
 
   int remove_calls() const { return remove_calls_; }
   int last_data_type_mask() const { return last_data_type_mask_; }
-  base::Callback<bool(const GURL&)> last_origin_filter() const {
+  const base::RepeatingCallback<bool(const GURL&)>& last_origin_filter() const {
     return last_origin_filter_;
   }
 
  private:
   int remove_calls_ = 0;
   int last_data_type_mask_ = 0;
-  base::Callback<bool(const GURL&)> last_origin_filter_;
+  base::RepeatingCallback<bool(const GURL&)> last_origin_filter_;
 
   DISALLOW_COPY_AND_ASSIGN(MockReportingService);
 };
@@ -966,7 +967,7 @@
   ClearReportingCacheTester(TestingProfile* profile, bool create_service)
       : profile_(profile) {
     if (create_service)
-      service_ = base::MakeUnique<MockReportingService>();
+      service_ = std::make_unique<MockReportingService>();
 
     net::URLRequestContext* request_context =
         profile_->GetRequestContext()->GetURLRequestContext();
@@ -981,9 +982,10 @@
     request_context->set_reporting_service(old_service_);
   }
 
-  void GetMockInfo(int* remove_calls_out,
-                   int* last_data_type_mask_out,
-                   base::Callback<bool(const GURL&)>* last_origin_filter_out) {
+  void GetMockInfo(
+      int* remove_calls_out,
+      int* last_data_type_mask_out,
+      base::RepeatingCallback<bool(const GURL&)>* last_origin_filter_out) {
     DCHECK_NE(nullptr, service_.get());
 
     *remove_calls_out = service_->remove_calls();
@@ -997,6 +999,78 @@
   net::ReportingService* old_service_;
 };
 
+class MockNetworkErrorLoggingDelegate
+    : public net::NetworkErrorLoggingDelegate {
+ public:
+  MockNetworkErrorLoggingDelegate() = default;
+
+  // net::NetworkErrorLoggingDelegate implementation:
+
+  ~MockNetworkErrorLoggingDelegate() override = default;
+
+  void OnHeader(const url::Origin& origin, const std::string& value) override {
+    NOTREACHED();
+  }
+
+  void OnNetworkError(const ErrorDetails& details) override { NOTREACHED(); }
+
+  void RemoveBrowsingData(const base::RepeatingCallback<bool(const GURL&)>&
+                              origin_filter) override {
+    ++remove_calls_;
+    last_origin_filter_ = origin_filter;
+  }
+
+  void SetReportingService(net::ReportingService* reporting_service) override {}
+
+  int remove_calls() const { return remove_calls_; }
+  const base::RepeatingCallback<bool(const GURL&)>& last_origin_filter() const {
+    return last_origin_filter_;
+  }
+
+ private:
+  int remove_calls_ = 0;
+  base::RepeatingCallback<bool(const GURL&)> last_origin_filter_;
+
+  DISALLOW_COPY_AND_ASSIGN(MockNetworkErrorLoggingDelegate);
+};
+
+class ClearNetworkErrorLoggingTester {
+ public:
+  ClearNetworkErrorLoggingTester(TestingProfile* profile, bool create_service)
+      : profile_(profile) {
+    if (create_service)
+      delegate_ = std::make_unique<MockNetworkErrorLoggingDelegate>();
+
+    net::URLRequestContext* request_context =
+        profile_->GetRequestContext()->GetURLRequestContext();
+
+    request_context->set_network_error_logging_delegate(delegate_.get());
+  }
+
+  ~ClearNetworkErrorLoggingTester() {
+    net::URLRequestContext* request_context =
+        profile_->GetRequestContext()->GetURLRequestContext();
+    DCHECK_EQ(delegate_.get(),
+              request_context->network_error_logging_delegate());
+    request_context->set_network_error_logging_delegate(nullptr);
+  }
+
+  void GetMockInfo(
+      int* remove_calls_out,
+      base::RepeatingCallback<bool(const GURL&)>* last_origin_filter_out) {
+    DCHECK_NE(nullptr, delegate_.get());
+
+    *remove_calls_out = delegate_->remove_calls();
+    *last_origin_filter_out = delegate_->last_origin_filter();
+  }
+
+ private:
+  TestingProfile* profile_;
+  std::unique_ptr<MockNetworkErrorLoggingDelegate> delegate_;
+
+  DISALLOW_COPY_AND_ASSIGN(ClearNetworkErrorLoggingTester);
+};
+
 // Implementation of the TestingProfile that provides an SSLHostStateDelegate
 // which is required for the tests.
 class BrowsingDataRemoverTestingProfile : public TestingProfile {
@@ -2483,7 +2557,7 @@
 
   int remove_count;
   int data_type_mask;
-  base::Callback<bool(const GURL&)> origin_filter;
+  base::RepeatingCallback<bool(const GURL&)> origin_filter;
   tester.GetMockInfo(&remove_count, &data_type_mask, &origin_filter);
 
   EXPECT_EQ(1, remove_count);
@@ -2507,7 +2581,7 @@
 
   int remove_count;
   int data_type_mask;
-  base::Callback<bool(const GURL&)> origin_filter;
+  base::RepeatingCallback<bool(const GURL&)> origin_filter;
   tester.GetMockInfo(&remove_count, &data_type_mask, &origin_filter);
 
   EXPECT_EQ(1, remove_count);
@@ -2526,7 +2600,7 @@
 
   int remove_count;
   int data_type_mask;
-  base::Callback<bool(const GURL&)> origin_filter;
+  base::RepeatingCallback<bool(const GURL&)> origin_filter;
   tester.GetMockInfo(&remove_count, &data_type_mask, &origin_filter);
 
   EXPECT_EQ(1, remove_count);
@@ -2552,7 +2626,7 @@
 
   int remove_count;
   int data_type_mask;
-  base::Callback<bool(const GURL&)> origin_filter;
+  base::RepeatingCallback<bool(const GURL&)> origin_filter;
   tester.GetMockInfo(&remove_count, &data_type_mask, &origin_filter);
 
   EXPECT_EQ(1, remove_count);
@@ -2574,7 +2648,7 @@
 
   int remove_count;
   int data_type_mask;
-  base::Callback<bool(const GURL&)> origin_filter;
+  base::RepeatingCallback<bool(const GURL&)> origin_filter;
   tester.GetMockInfo(&remove_count, &data_type_mask, &origin_filter);
 
   EXPECT_EQ(1, remove_count);
@@ -2603,7 +2677,7 @@
 
   int remove_count;
   int data_type_mask;
-  base::Callback<bool(const GURL&)> origin_filter;
+  base::RepeatingCallback<bool(const GURL&)> origin_filter;
   tester.GetMockInfo(&remove_count, &data_type_mask, &origin_filter);
 
   EXPECT_EQ(1, remove_count);
@@ -2614,6 +2688,56 @@
       ProbablySameFilters(builder->BuildGeneralFilter(), origin_filter));
 }
 
+TEST_F(ChromeBrowsingDataRemoverDelegateTest, NetworkErrorLogging_NoDelegate) {
+  ClearNetworkErrorLoggingTester tester(GetProfile(), false);
+
+  BlockUntilBrowsingDataRemoved(
+      base::Time(), base::Time::Max(),
+      content::BrowsingDataRemover::DATA_TYPE_COOKIES |
+          ChromeBrowsingDataRemoverDelegate::DATA_TYPE_HISTORY,
+      true);
+
+  // Nothing to check, since there's no mock service; we're just making sure
+  // nothing crashes without a service.
+}
+
+TEST_F(ChromeBrowsingDataRemoverDelegateTest, NetworkErrorLogging_Cookies) {
+  ClearNetworkErrorLoggingTester tester(GetProfile(), true);
+
+  std::unique_ptr<BrowsingDataFilterBuilder> builder(
+      BrowsingDataFilterBuilder::Create(BrowsingDataFilterBuilder::WHITELIST));
+  builder->AddRegisterableDomain(kTestRegisterableDomain1);
+
+  BlockUntilOriginDataRemoved(base::Time(), base::Time::Max(),
+                              content::BrowsingDataRemover::DATA_TYPE_COOKIES,
+                              builder->Copy());
+
+  int remove_count;
+  base::RepeatingCallback<bool(const GURL&)> origin_filter;
+  tester.GetMockInfo(&remove_count, &origin_filter);
+
+  EXPECT_EQ(1, remove_count);
+  EXPECT_TRUE(
+      ProbablySameFilters(builder->BuildGeneralFilter(), origin_filter));
+}
+
+// This would use an origin filter, but history isn't yet filterable.
+TEST_F(ChromeBrowsingDataRemoverDelegateTest, NetworkErrorLogging_History) {
+  ClearNetworkErrorLoggingTester tester(GetProfile(), true);
+
+  BlockUntilBrowsingDataRemoved(
+      base::Time(), base::Time::Max(),
+      ChromeBrowsingDataRemoverDelegate::DATA_TYPE_HISTORY, true);
+
+  int remove_count;
+  base::RepeatingCallback<bool(const GURL&)> origin_filter;
+  tester.GetMockInfo(&remove_count, &origin_filter);
+
+  EXPECT_EQ(1, remove_count);
+  EXPECT_TRUE(ProbablySameFilters(BrowsingDataFilterBuilder::BuildNoopFilter(),
+                                  origin_filter));
+}
+
 // Test that all WebsiteSettings are getting deleted by creating a
 // value for each of them and removing data.
 TEST_F(ChromeBrowsingDataRemoverDelegateTest, AllTypesAreGettingDeleted) {
diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc
index 0edf5f0..7fdb479c 100644
--- a/chrome/browser/chrome_content_browser_client.cc
+++ b/chrome/browser/chrome_content_browser_client.cc
@@ -275,9 +275,9 @@
 #include "chrome/browser/chromeos/system/input_device_settings.h"
 #include "chrome/browser/mash_service_registry.h"
 #include "chrome/browser/metrics/leak_detector/leak_detector_remote_controller.h"
+#include "chrome/browser/ui/ash/chrome_browser_main_extra_parts_ash.h"
 #include "chrome/browser/ui/browser_dialogs.h"
 #include "chrome/browser/ui/browser_finder.h"
-#include "chrome/browser/ui/views/ash/chrome_browser_main_extra_parts_ash.h"
 #include "chromeos/chromeos_constants.h"
 #include "chromeos/chromeos_switches.h"
 #include "components/user_manager/user_manager.h"
diff --git a/chrome/browser/chromeos/BUILD.gn b/chrome/browser/chromeos/BUILD.gn
index abd1c42..418ebe55 100644
--- a/chrome/browser/chromeos/BUILD.gn
+++ b/chrome/browser/chromeos/BUILD.gn
@@ -510,8 +510,6 @@
     "dbus/screen_lock_service_provider.h",
     "display/display_configuration_observer.cc",
     "display/display_configuration_observer.h",
-    "display/display_prefs.cc",
-    "display/display_prefs.h",
     "display/output_protection_controller_ash.cc",
     "display/output_protection_controller_ash.h",
     "display/output_protection_controller_mus.cc",
diff --git a/chrome/browser/chromeos/accessibility/select_to_speak_event_rewriter.cc b/chrome/browser/chromeos/accessibility/select_to_speak_event_rewriter.cc
index 3226c66..0759b35 100644
--- a/chrome/browser/chromeos/accessibility/select_to_speak_event_rewriter.cc
+++ b/chrome/browser/chromeos/accessibility/select_to_speak_event_rewriter.cc
@@ -44,6 +44,8 @@
 }
 }  // namespace
 
+const ui::KeyboardCode kSpeakSelectionKey = ui::VKEY_S;
+
 SelectToSpeakEventRewriter::SelectToSpeakEventRewriter(
     aura::Window* root_window)
     : root_window_(root_window) {
@@ -78,12 +80,18 @@
     if (event->type() == ui::ET_KEY_PRESSED && state_ == INACTIVE) {
       state_ = SEARCH_DOWN;
     } else if (event->type() == ui::ET_KEY_RELEASED) {
-      if (state_ == CAPTURING) {
+      if (state_ == CAPTURING_MOUSE) {
         cancel_event = true;
         state_ = WAIT_FOR_MOUSE_RELEASE;
       } else if (state_ == MOUSE_RELEASED) {
         cancel_event = true;
         state_ = INACTIVE;
+      } else if (state_ == CAPTURING_SPEAK_SELECTION_KEY) {
+        cancel_event = true;
+        state_ = WAIT_FOR_SPEAK_SELECTION_KEY_RELEASE;
+      } else if (state_ == SPEAK_SELECTION_KEY_RELEASED) {
+        cancel_event = true;
+        state_ = INACTIVE;
       } else if (state_ == SEARCH_DOWN) {
         // They just tapped the search key without clicking the mouse.
         // Don't cancel this event -- the search key may still be used
@@ -91,6 +99,26 @@
         state_ = INACTIVE;
       }
     }
+  } else if (key_code == kSpeakSelectionKey) {
+    if (event->type() == ui::ET_KEY_PRESSED &&
+        (state_ == SEARCH_DOWN || state_ == SPEAK_SELECTION_KEY_RELEASED)) {
+      // They pressed the S key while search was down.
+      // It's possible to press the selection key multiple times to read
+      // the same region over and over, so state S_RELEASED can become state
+      // CAPTURING_SPEAK_SELECTION_KEY if the search key is not lifted.
+      cancel_event = true;
+      state_ = CAPTURING_SPEAK_SELECTION_KEY;
+    } else if (event->type() == ui::ET_KEY_RELEASED) {
+      if (state_ == CAPTURING_SPEAK_SELECTION_KEY) {
+        // They released the speak selection key while it was being captured.
+        cancel_event = true;
+        state_ = SPEAK_SELECTION_KEY_RELEASED;
+      } else if (state_ == WAIT_FOR_SPEAK_SELECTION_KEY_RELEASE) {
+        // They have already released the search key
+        cancel_event = true;
+        state_ = INACTIVE;
+      }
+    }
   } else if (state_ == SEARCH_DOWN) {
     state_ = INACTIVE;
   }
@@ -111,7 +139,7 @@
 
   if ((state_ == SEARCH_DOWN || state_ == MOUSE_RELEASED) &&
       event->type() == ui::ET_MOUSE_PRESSED) {
-    state_ = CAPTURING;
+    state_ = CAPTURING_MOUSE;
   }
 
   if (state_ == WAIT_FOR_MOUSE_RELEASE &&
@@ -120,7 +148,7 @@
     return false;
   }
 
-  if (state_ != CAPTURING)
+  if (state_ != CAPTURING_MOUSE)
     return false;
 
   if (event->type() == ui::ET_MOUSE_RELEASED)
@@ -129,7 +157,7 @@
   ui::MouseEvent mutable_event(*event);
   ConvertMouseEventToDIPs(&mutable_event);
 
-  // If we're in the capturing state, forward the mouse event to
+  // If we're in the capturing mouse state, forward the mouse event to
   // select-to-speak.
   if (event_delegate_for_testing_) {
     event_delegate_for_testing_->OnForwardEventToSelectToSpeakExtension(
diff --git a/chrome/browser/chromeos/accessibility/select_to_speak_event_rewriter.h b/chrome/browser/chromeos/accessibility/select_to_speak_event_rewriter.h
index 3c0f98f..dcc386e 100644
--- a/chrome/browser/chromeos/accessibility/select_to_speak_event_rewriter.h
+++ b/chrome/browser/chromeos/accessibility/select_to_speak_event_rewriter.h
@@ -54,16 +54,16 @@
       std::unique_ptr<ui::Event>* new_event) override;
 
   enum State {
-    // Neither the Search key nor the mouse button are down.
+    // The search key is not down. No other keys or mouse events are captured.
     INACTIVE,
 
-    // The Search key is down but the mouse button is not.
+    // The Search key is down but the mouse button and 'S' key are not.
     SEARCH_DOWN,
 
     // The user held down Search and clicked the mouse button. We're capturing
-    // all events from now on until either Search or the mouse button is
+    // all mouse events from now on until either Search or the mouse button is
     // released.
-    CAPTURING,
+    CAPTURING_MOUSE,
 
     // The mouse was released, but Search is still held down. If the user
     // clicks again, we'll go back to the state CAPTURING. This is different
@@ -75,7 +75,23 @@
     // The Search key was released while the mouse was still down, cancelling
     // the Select-to-Speak event. Stay in this mode until the mouse button
     // is released, too.
-    WAIT_FOR_MOUSE_RELEASE
+    WAIT_FOR_MOUSE_RELEASE,
+
+    // The user held down Search and clicked the speak selection key. We're
+    // waiting for the event where the speak selection key is released or the
+    // search key is released.
+    CAPTURING_SPEAK_SELECTION_KEY,
+
+    // The user held down Search and clicked and released the speak selection
+    // key. We will wait for the Search key to be released too. This is
+    // different than SEARCH_DOWN because we know the user used the speak
+    // selection key, so when Search is released we will capture that event to
+    // not trigger opening the Search UI.
+    SPEAK_SELECTION_KEY_RELEASED,
+
+    // The Search key was released while the selection key was still down. Stay
+    // in this mode until the speak selection key is released too.
+    WAIT_FOR_SPEAK_SELECTION_KEY_RELEASE
   };
 
   State state_ = INACTIVE;
diff --git a/chrome/browser/chromeos/accessibility/select_to_speak_event_rewriter_unittest.cc b/chrome/browser/chromeos/accessibility/select_to_speak_event_rewriter_unittest.cc
index 6fd94b18e..1dbe4786 100644
--- a/chrome/browser/chromeos/accessibility/select_to_speak_event_rewriter_unittest.cc
+++ b/chrome/browser/chromeos/accessibility/select_to_speak_event_rewriter_unittest.cc
@@ -328,3 +328,76 @@
   ASSERT_TRUE(event_capturer_.last_key_event());
   EXPECT_FALSE(event_capturer_.last_key_event()->handled());
 }
+
+TEST_F(SelectToSpeakEventRewriterTest, SearchPlusSIsCaptured) {
+  generator_->PressKey(ui::VKEY_LWIN, ui::EF_COMMAND_DOWN);
+
+  // Press and release S, key presses should be captured.
+  event_capturer_.Reset();
+  generator_->PressKey(ui::VKEY_S, ui::EF_COMMAND_DOWN);
+  ASSERT_FALSE(event_capturer_.last_key_event());
+
+  generator_->ReleaseKey(ui::VKEY_S, ui::EF_COMMAND_DOWN);
+  ASSERT_FALSE(event_capturer_.last_key_event());
+
+  // Press and release again while still holding down search.
+  // The events should continue to be captured.
+  generator_->PressKey(ui::VKEY_S, ui::EF_COMMAND_DOWN);
+  ASSERT_FALSE(event_capturer_.last_key_event());
+
+  generator_->ReleaseKey(ui::VKEY_S, ui::EF_COMMAND_DOWN);
+  ASSERT_FALSE(event_capturer_.last_key_event());
+
+  generator_->ReleaseKey(ui::VKEY_LWIN, ui::EF_COMMAND_DOWN);
+  ASSERT_FALSE(event_capturer_.last_key_event());
+
+  // S alone is not captured
+  generator_->PressKey(ui::VKEY_S, ui::EF_COMMAND_DOWN);
+  ASSERT_TRUE(event_capturer_.last_key_event());
+  ASSERT_FALSE(event_capturer_.last_key_event()->handled());
+}
+
+TEST_F(SelectToSpeakEventRewriterTest, SearchPlusSIgnoresMouse) {
+  generator_->PressKey(ui::VKEY_LWIN, ui::EF_COMMAND_DOWN);
+
+  // Press S
+  event_capturer_.Reset();
+  generator_->PressKey(ui::VKEY_S, ui::EF_COMMAND_DOWN);
+  ASSERT_FALSE(event_capturer_.last_key_event());
+
+  // Mouse events are passed through like normal.
+  generator_->PressLeftButton();
+  EXPECT_TRUE(event_capturer_.last_mouse_event());
+  event_capturer_.Reset();
+  generator_->ReleaseLeftButton();
+  EXPECT_TRUE(event_capturer_.last_mouse_event());
+
+  generator_->ReleaseKey(ui::VKEY_S, ui::EF_COMMAND_DOWN);
+  ASSERT_FALSE(event_capturer_.last_key_event());
+
+  generator_->ReleaseKey(ui::VKEY_LWIN, ui::EF_COMMAND_DOWN);
+  ASSERT_FALSE(event_capturer_.last_key_event());
+}
+
+TEST_F(SelectToSpeakEventRewriterTest, SearchPlusMouseIgnoresS) {
+  generator_->PressKey(ui::VKEY_LWIN, ui::EF_COMMAND_DOWN);
+
+  // Press the mouse
+  event_capturer_.Reset();
+  generator_->PressLeftButton();
+  EXPECT_FALSE(event_capturer_.last_mouse_event());
+
+  // S key events are passed through like normal.
+  generator_->PressKey(ui::VKEY_S, ui::EF_COMMAND_DOWN);
+  ASSERT_TRUE(event_capturer_.last_key_event());
+  event_capturer_.Reset();
+  generator_->ReleaseKey(ui::VKEY_S, ui::EF_COMMAND_DOWN);
+  ASSERT_TRUE(event_capturer_.last_key_event());
+
+  generator_->ReleaseLeftButton();
+  EXPECT_FALSE(event_capturer_.last_mouse_event());
+
+  event_capturer_.Reset();
+  generator_->ReleaseKey(ui::VKEY_LWIN, ui::EF_COMMAND_DOWN);
+  ASSERT_FALSE(event_capturer_.last_key_event());
+}
diff --git a/chrome/browser/chromeos/arc/arc_session_manager.cc b/chrome/browser/chromeos/arc/arc_session_manager.cc
index 9521ec9..00fb6cd6 100644
--- a/chrome/browser/chromeos/arc/arc_session_manager.cc
+++ b/chrome/browser/chromeos/arc/arc_session_manager.cc
@@ -77,6 +77,16 @@
   UpdateOptInCancelUMA(OptInCancelReason::USER_CANCEL);
 }
 
+chromeos::SessionManagerClient* GetSessionManagerClient() {
+  // If the DBusThreadManager or the SessionManagerClient aren't available,
+  // there isn't much we can do. This should only happen when running tests.
+  if (!chromeos::DBusThreadManager::IsInitialized() ||
+      !chromeos::DBusThreadManager::Get() ||
+      !chromeos::DBusThreadManager::Get()->GetSessionManagerClient())
+    return nullptr;
+  return chromeos::DBusThreadManager::Get()->GetSessionManagerClient();
+}
+
 }  // namespace
 
 // This class is used to track statuses on OptIn flow. It is created in case ARC
@@ -144,11 +154,18 @@
   DCHECK(!g_arc_session_manager);
   g_arc_session_manager = this;
   arc_session_runner_->AddObserver(this);
+  chromeos::SessionManagerClient* client = GetSessionManagerClient();
+  if (client)
+    client->AddObserver(this);
 }
 
 ArcSessionManager::~ArcSessionManager() {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
 
+  chromeos::SessionManagerClient* client = GetSessionManagerClient();
+  if (client)
+    client->RemoveObserver(this);
+
   Shutdown();
   arc_session_runner_->RemoveObserver(this);
 
@@ -1030,6 +1047,10 @@
   arc_session_runner_->AddObserver(this);
 }
 
+ArcSessionRunner* ArcSessionManager::GetArcSessionRunnerForTesting() {
+  return arc_session_runner_.get();
+}
+
 void ArcSessionManager::SetAttemptUserExitCallbackForTesting(
     const base::Closure& callback) {
   DCHECK(!callback.is_null());
@@ -1045,6 +1066,16 @@
     observer.OnArcErrorShowRequested(error);
 }
 
+void ArcSessionManager::EmitLoginPromptVisibleCalled() {
+  // Since 'login-prompt-visible' Upstart signal starts all Upstart jobs the
+  // instance may depend on such as cras, EmitLoginPromptVisibleCalled() is the
+  // safe place to start a mini instance.
+  if (!IsArcAvailable())
+    return;
+
+  arc_session_runner_->RequestStart(ArcInstanceMode::MINI_INSTANCE);
+}
+
 std::ostream& operator<<(std::ostream& os,
                          const ArcSessionManager::State& state) {
 #define MAP_STATE(name)                \
diff --git a/chrome/browser/chromeos/arc/arc_session_manager.h b/chrome/browser/chromeos/arc/arc_session_manager.h
index 647b830b..e6c3e2e 100644
--- a/chrome/browser/chromeos/arc/arc_session_manager.h
+++ b/chrome/browser/chromeos/arc/arc_session_manager.h
@@ -15,6 +15,7 @@
 #include "base/timer/timer.h"
 #include "chrome/browser/chromeos/arc/arc_support_host.h"
 #include "chrome/browser/chromeos/policy/android_management_client.h"
+#include "chromeos/dbus/session_manager_client.h"
 #include "components/arc/arc_session_runner.h"
 #include "components/arc/arc_stop_reason.h"
 
@@ -32,7 +33,8 @@
 
 // This class is responsible for handing stages of ARC life-cycle.
 class ArcSessionManager : public ArcSessionRunner::Observer,
-                          public ArcSupportHost::ErrorDelegate {
+                          public ArcSupportHost::ErrorDelegate,
+                          public chromeos::SessionManagerClient::Observer {
  public:
   // Represents each State of ARC session.
   // NOT_INITIALIZED: represents the state that the Profile is not yet ready
@@ -248,6 +250,7 @@
   // Injectors for testing.
   void SetArcSessionRunnerForTesting(
       std::unique_ptr<ArcSessionRunner> arc_session_runner);
+  ArcSessionRunner* GetArcSessionRunnerForTesting();
   void SetAttemptUserExitCallbackForTesting(const base::Closure& callback);
 
   // Returns whether the Play Store app is requested to be launched by this
@@ -343,6 +346,9 @@
   void ShowArcSupportHostError(ArcSupportHost::Error error,
                                bool should_show_send_feedback);
 
+  // chromeos::SessionManagerClient::Observer:
+  void EmitLoginPromptVisibleCalled() override;
+
   std::unique_ptr<ArcSessionRunner> arc_session_runner_;
 
   // Unowned pointer. Keeps current profile.
diff --git a/chrome/browser/chromeos/arc/arc_session_manager_unittest.cc b/chrome/browser/chromeos/arc/arc_session_manager_unittest.cc
index b6397db4..402adf68 100644
--- a/chrome/browser/chromeos/arc/arc_session_manager_unittest.cc
+++ b/chrome/browser/chromeos/arc/arc_session_manager_unittest.cc
@@ -145,7 +145,80 @@
   DISALLOW_COPY_AND_ASSIGN(FakeLoginDisplayHost);
 };
 
-}  // namespace
+class ArcSessionManagerInLoginScreenTest : public testing::Test {
+ public:
+  ArcSessionManagerInLoginScreenTest()
+      : user_manager_enabler_(
+            std::make_unique<chromeos::FakeChromeUserManager>()) {
+    chromeos::DBusThreadManager::GetSetterForTesting()->SetSessionManagerClient(
+        std::make_unique<chromeos::FakeSessionManagerClient>());
+
+    chromeos::DBusThreadManager::Initialize();
+
+    ArcSessionManager::DisableUIForTesting();
+    SetArcBlockedDueToIncompatibleFileSystemForTesting(false);
+
+    arc_service_manager_ = std::make_unique<ArcServiceManager>();
+    arc_session_manager_ =
+        std::make_unique<ArcSessionManager>(std::make_unique<ArcSessionRunner>(
+            base::BindRepeating(FakeArcSession::Create)));
+  }
+
+  ~ArcSessionManagerInLoginScreenTest() override {
+    arc_session_manager_->Shutdown();
+    arc_session_manager_.reset();
+    arc_service_manager_.reset();
+    chromeos::DBusThreadManager::Shutdown();
+  }
+
+ protected:
+  ArcSessionManager* arc_session_manager() {
+    return arc_session_manager_.get();
+  }
+
+  FakeArcSession* arc_session() {
+    return static_cast<FakeArcSession*>(
+        arc_session_manager_->GetArcSessionRunnerForTesting()
+            ->GetArcSessionForTesting());
+  }
+
+ private:
+  content::TestBrowserThreadBundle thread_bundle_;
+  std::unique_ptr<ArcServiceManager> arc_service_manager_;
+  std::unique_ptr<ArcSessionManager> arc_session_manager_;
+  user_manager::ScopedUserManager user_manager_enabler_;
+
+  DISALLOW_COPY_AND_ASSIGN(ArcSessionManagerInLoginScreenTest);
+};
+
+// We expect mini instance starts to run if EmitLoginPromptVisible signal is
+// emitted.
+TEST_F(ArcSessionManagerInLoginScreenTest, EmitLoginPromptVisible) {
+  EXPECT_FALSE(arc_session());
+
+  SetArcAvailableCommandLineForTesting(base::CommandLine::ForCurrentProcess());
+
+  chromeos::DBusThreadManager::Get()
+      ->GetSessionManagerClient()
+      ->EmitLoginPromptVisible();
+  ASSERT_TRUE(arc_session());
+  EXPECT_FALSE(arc_session()->is_running());
+  EXPECT_EQ(ArcSessionManager::State::NOT_INITIALIZED,
+            arc_session_manager()->state());
+}
+
+// We expect mini instance does not start on EmitLoginPromptVisible when ARC
+// is not available.
+TEST_F(ArcSessionManagerInLoginScreenTest, EmitLoginPromptVisible_NoOp) {
+  EXPECT_FALSE(arc_session());
+
+  chromeos::DBusThreadManager::Get()
+      ->GetSessionManagerClient()
+      ->EmitLoginPromptVisible();
+  EXPECT_FALSE(arc_session());
+  EXPECT_EQ(ArcSessionManager::State::NOT_INITIALIZED,
+            arc_session_manager()->state());
+}
 
 class ArcSessionManagerTestBase : public testing::Test {
  public:
@@ -167,8 +240,9 @@
     SetArcBlockedDueToIncompatibleFileSystemForTesting(false);
 
     arc_service_manager_ = std::make_unique<ArcServiceManager>();
-    arc_session_manager_ = std::make_unique<ArcSessionManager>(
-        std::make_unique<ArcSessionRunner>(base::Bind(FakeArcSession::Create)));
+    arc_session_manager_ =
+        std::make_unique<ArcSessionManager>(std::make_unique<ArcSessionRunner>(
+            base::BindRepeating(FakeArcSession::Create)));
 
     EXPECT_TRUE(temp_dir_.CreateUniqueTempDir());
     TestingProfile::Builder profile_builder;
@@ -1016,4 +1090,6 @@
   }
 }
 
+}  // namespace
+
 }  // namespace arc
diff --git a/chrome/browser/chromeos/chrome_browser_main_chromeos.cc b/chrome/browser/chromeos/chrome_browser_main_chromeos.cc
index 89d126a..2e56ea5 100644
--- a/chrome/browser/chromeos/chrome_browser_main_chromeos.cc
+++ b/chrome/browser/chromeos/chrome_browser_main_chromeos.cc
@@ -194,6 +194,7 @@
 #include "ui/chromeos/events/event_rewriter_chromeos.h"
 #include "ui/chromeos/events/pref_names.h"
 #include "ui/events/event_utils.h"
+#include "ui/keyboard/content/keyboard.h"
 #include "ui/message_center/message_center.h"
 
 #if BUILDFLAG(ENABLE_RLZ)
@@ -855,9 +856,15 @@
 
   arc_kiosk_app_manager_.reset(new ArcKioskAppManager());
 
-  // NOTE: Initializes ash::Shell.
+  // NOTE: Calls ChromeBrowserMainParts::PreProfileInit() which calls
+  // ChromeBrowserMainExtraPartsAsh::PreProfileInit() which initializes
+  // ash::Shell.
   ChromeBrowserMainPartsLinux::PreProfileInit();
 
+  // Initialize the keyboard before any session state changes (i.e. before
+  // loading the default profile).
+  keyboard::InitializeKeyboard();
+
   PushProcessCreationTimeToAsh();
 
   // Makes mojo request to TabletModeController in ash.
diff --git a/chrome/browser/chromeos/display/display_configuration_observer.cc b/chrome/browser/chromeos/display/display_configuration_observer.cc
index 3ad1920..d3271912 100644
--- a/chrome/browser/chromeos/display/display_configuration_observer.cc
+++ b/chrome/browser/chromeos/display/display_configuration_observer.cc
@@ -4,11 +4,11 @@
 
 #include "chrome/browser/chromeos/display/display_configuration_observer.h"
 
+#include "ash/display/display_prefs.h"
 #include "ash/display/window_tree_host_manager.h"
 #include "ash/shell.h"
 #include "ash/wm/tablet_mode/tablet_mode_controller.h"
 #include "base/command_line.h"
-#include "chrome/browser/chromeos/display/display_prefs.h"
 #include "chromeos/chromeos_switches.h"
 #include "ui/display/manager/display_layout_store.h"
 #include "ui/display/manager/display_manager.h"
@@ -30,21 +30,21 @@
   base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
   if (command_line->HasSwitch(chromeos::switches::kFirstExecAfterBoot) &&
       save_preference_) {
-    DisplayPrefs::Get()->StoreDisplayPrefs();
+    ash::Shell::Get()->display_prefs()->StoreDisplayPrefs();
   }
 }
 
 void DisplayConfigurationObserver::OnDisplayConfigurationChanged() {
   if (save_preference_)
-    DisplayPrefs::Get()->StoreDisplayPrefs();
+    ash::Shell::Get()->display_prefs()->StoreDisplayPrefs();
 }
 
 void DisplayConfigurationObserver::OnTabletModeStarted() {
   // TODO(oshima): Tablet mode defaults to mirror mode until we figure out
   // how to handle this scenario, and we shouldn't save this state.
-  // crbug.com/733092.
+  // http://crbug.com/733092.
   save_preference_ = false;
-  // TODO(oshima): Mirroring won't work with 3 displays. crbug.com/737667.
+  // TODO(oshima): Mirroring won't work with 3 displays http://crbug.com/737667.
   display::DisplayManager* display_manager =
       ash::Shell::Get()->display_manager();
   was_in_mirror_mode_ = display_manager->IsInMirrorMode();
diff --git a/chrome/browser/chromeos/display/display_prefs.h b/chrome/browser/chromeos/display/display_prefs.h
deleted file mode 100644
index b9474802..0000000
--- a/chrome/browser/chromeos/display/display_prefs.h
+++ /dev/null
@@ -1,72 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_CHROMEOS_DISPLAY_DISPLAY_PREFS_H_
-#define CHROME_BROWSER_CHROMEOS_DISPLAY_DISPLAY_PREFS_H_
-
-#include <stdint.h>
-#include <array>
-
-#include "third_party/cros_system_api/dbus/service_constants.h"
-#include "ui/display/display.h"
-#include "ui/display/display_layout.h"
-
-class PrefRegistrySimple;
-class PrefService;
-
-namespace gfx {
-class Point;
-}
-
-namespace display {
-struct TouchCalibrationData;
-}
-
-namespace chromeos {
-
-// Manages display preference settings. Settings are stored in the local state
-// for the session.
-class DisplayPrefs {
- public:
-  // Registers the prefs associated with display settings.
-  static void RegisterLocalStatePrefs(PrefRegistrySimple* registry);
-
-  // TODO(stevenjb): Move to ash::Shell::display_prefs().
-  static DisplayPrefs* Get();
-
-  explicit DisplayPrefs(PrefService* local_state);
-
-  ~DisplayPrefs();
-
-  // Stores all current displays preferences.
-  void StoreDisplayPrefs();
-
-  // Loads display preferences from |local_state_|. |first_run_after_boot| is
-  // used to determine whether power state preferences should be applied.
-  void LoadDisplayPreferences(bool first_run_after_boot);
-
-  // Test helper methods.
-
-  void StoreDisplayRotationPrefsForTest(display::Display::Rotation rotation,
-                                        bool rotation_lock);
-  void StoreDisplayLayoutPrefForTest(const display::DisplayIdList& list,
-                                     const display::DisplayLayout& layout);
-  void StoreDisplayPowerStateForTest(DisplayPowerState power_state);
-  void LoadTouchAssociationPreferenceForTest();
-  void StoreLegacyTouchDataForTest(int64_t display_id,
-                                   const display::TouchCalibrationData& data);
-  // Parses the marshalled string data stored in local preferences for
-  // calibration points and populates |point_pair_quad| using the unmarshalled
-  // data. See TouchCalibrationData in Managed display info.
-  bool ParseTouchCalibrationStringForTest(
-      const std::string& str,
-      std::array<std::pair<gfx::Point, gfx::Point>, 4>* point_pair_quad);
-
- private:
-  PrefService* local_state_;
-};
-
-}  // namespace chromeos
-
-#endif  // CHROME_BROWSER_CHROMEOS_DISPLAY_DISPLAY_PREFS_H_
diff --git a/chrome/browser/chromeos/display/display_prefs_unittest.cc b/chrome/browser/chromeos/display/display_prefs_unittest.cc
index 0eb2003..24b1afcc 100644
--- a/chrome/browser/chromeos/display/display_prefs_unittest.cc
+++ b/chrome/browser/chromeos/display/display_prefs_unittest.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/chromeos/display/display_prefs.h"
+#include "ash/display/display_prefs.h"
 
 #include <stdint.h>
 
@@ -14,6 +14,8 @@
 #include "ash/display/resolution_notification_controller.h"
 #include "ash/display/screen_orientation_controller_chromeos.h"
 #include "ash/display/window_tree_host_manager.h"
+#include "ash/public/cpp/ash_pref_names.h"
+#include "ash/session/test_session_controller_client.h"
 #include "ash/shell.h"
 #include "ash/test/ash_test_base.h"
 #include "ash/wm/tablet_mode/tablet_mode_controller.h"
@@ -24,11 +26,10 @@
 #include "base/strings/string_number_conversions.h"
 #include "base/values.h"
 #include "chrome/browser/chromeos/display/display_configuration_observer.h"
-#include "chrome/browser/chromeos/login/users/mock_user_manager.h"
-#include "chrome/common/pref_names.h"
 #include "components/prefs/scoped_user_pref_update.h"
 #include "components/prefs/testing_pref_service.h"
-#include "components/user_manager/scoped_user_manager.h"
+#include "components/user_manager/user_type.h"
+#include "testing/gtest/include/gtest/gtest.h"
 #include "ui/display/display_layout_builder.h"
 #include "ui/display/display_switches.h"
 #include "ui/display/manager/chromeos/display_configurator.h"
@@ -42,9 +43,7 @@
 #include "ui/gfx/geometry/vector3d_f.h"
 #include "ui/message_center/message_center.h"
 
-using ash::ResolutionNotificationController;
-
-namespace chromeos {
+namespace ash {
 
 namespace {
 const char kPrimaryIdKey[] = "primary-id";
@@ -93,48 +92,37 @@
   return true;
 }
 
-class DisplayPrefsTest : public ash::AshTestBase {
+}  // namespace
+
+class DisplayPrefsTest : public NoSessionAshTestBase {
  protected:
-  DisplayPrefsTest()
-      : mock_user_manager_(new MockUserManager),
-        user_manager_enabler_(base::WrapUnique(mock_user_manager_)) {}
+  DisplayPrefsTest() {}
 
   ~DisplayPrefsTest() override {}
 
   void SetUp() override {
-    EXPECT_CALL(*mock_user_manager_, IsUserLoggedIn())
-        .WillRepeatedly(testing::Return(false));
-    EXPECT_CALL(*mock_user_manager_, Shutdown());
-    ash::AshTestBase::SetUp();
-    DisplayPrefs::RegisterLocalStatePrefs(local_state_.registry());
-    display_prefs_ = std::make_unique<DisplayPrefs>(&local_state_);
-    observer_ = std::make_unique<DisplayConfigurationObserver>();
+    AshTestBase::SetUp();
+    // AshTestBase::SetUp() initializes local state.
+    ASSERT_TRUE(local_state());
+    observer_ = std::make_unique<chromeos::DisplayConfigurationObserver>();
     observer_->OnDisplaysInitialized();
   }
 
   void TearDown() override {
     observer_.reset();
-    display_prefs_.reset();
-    ash::AshTestBase::TearDown();
+    AshTestBase::TearDown();
   }
 
-  void LoggedInAsUser() {
-    EXPECT_CALL(*mock_user_manager_, IsUserLoggedIn())
-        .WillRepeatedly(testing::Return(true));
-    EXPECT_CALL(*mock_user_manager_, IsLoggedInAsUserWithGaiaAccount())
-        .WillRepeatedly(testing::Return(true));
+  void LoggedInAsUser() { SimulateUserLogin("user1@test.com"); }
+
+  void LoggedInAsGuest() { SimulateGuestLogin(); }
+
+  void LoadDisplayPreferences(bool first_run_after_boot) {
+    display_prefs()->LoadDisplayPreferences(first_run_after_boot,
+                                            local_state());
   }
 
-  void LoggedInAsGuest() {
-    EXPECT_CALL(*mock_user_manager_, IsUserLoggedIn())
-        .WillRepeatedly(testing::Return(true));
-    EXPECT_CALL(*mock_user_manager_, IsLoggedInAsUserWithGaiaAccount())
-        .WillRepeatedly(testing::Return(false));
-    EXPECT_CALL(*mock_user_manager_, IsLoggedInAsSupervisedUser())
-        .WillRepeatedly(testing::Return(false));
-  }
-
-  // Do not use the implementation of display_preferences.cc directly to avoid
+  // Do not use the implementation of display_prefs.cc directly to avoid
   // notifying the update to the system.
   void StoreDisplayLayoutPrefForList(
       const display::DisplayIdList& list,
@@ -142,7 +130,7 @@
       int offset,
       int64_t primary_id) {
     std::string name = display::DisplayIdListToString(list);
-    DictionaryPrefUpdate update(&local_state_, prefs::kSecondaryDisplays);
+    DictionaryPrefUpdate update(local_state(), prefs::kSecondaryDisplays);
     display::DisplayLayout display_layout;
     display_layout.placement_list.emplace_back(position, offset);
     display_layout.primary_id = primary_id;
@@ -163,7 +151,7 @@
                                    std::unique_ptr<base::Value> value) {
     std::string name = display::DisplayIdListToString(list);
 
-    DictionaryPrefUpdate update(&local_state_, prefs::kSecondaryDisplays);
+    DictionaryPrefUpdate update(local_state(), prefs::kSecondaryDisplays);
     base::DictionaryValue* pref_data = update.Get();
 
     base::Value* layout_value = pref_data->FindKey(name);
@@ -192,7 +180,7 @@
   }
 
   void StoreDisplayOverscan(int64_t id, const gfx::Insets& insets) {
-    DictionaryPrefUpdate update(&local_state_, prefs::kDisplayProperties);
+    DictionaryPrefUpdate update(local_state(), prefs::kDisplayProperties);
     const std::string name = base::Int64ToString(id);
 
     base::DictionaryValue* pref_data = update.Get();
@@ -230,21 +218,17 @@
         .ToString();
   }
 
-  PrefService* local_state() { return &local_state_; }
-  DisplayPrefs* display_prefs() { return display_prefs_.get(); }
+  PrefService* local_state() {
+    return ash::Shell::Get()->GetLocalStatePrefService();
+  }
+  DisplayPrefs* display_prefs() { return ash::Shell::Get()->display_prefs(); }
 
  private:
-  MockUserManager* mock_user_manager_;  // Not owned.
-  user_manager::ScopedUserManager user_manager_enabler_;
-  TestingPrefServiceSimple local_state_;
-  std::unique_ptr<DisplayPrefs> display_prefs_;
-  std::unique_ptr<ash::WindowTreeHostManager::Observer> observer_;
+  std::unique_ptr<WindowTreeHostManager::Observer> observer_;
 
   DISALLOW_COPY_AND_ASSIGN(DisplayPrefsTest);
 };
 
-}  // namespace
-
 TEST_F(DisplayPrefsTest, ListedLayoutOverrides) {
   UpdateDisplay("100x100,200x200");
 
@@ -261,7 +245,7 @@
 
   ash::Shell* shell = ash::Shell::Get();
 
-  display_prefs()->LoadDisplayPreferences(true);
+  LoadDisplayPreferences(true);
   // DisplayPowerState should be ignored at boot.
   EXPECT_EQ(chromeos::DISPLAY_POWER_ALL_ON,
             shell->display_configurator()->requested_power_state());
@@ -767,7 +751,7 @@
 TEST_F(DisplayPrefsTest, DisplayPowerStateAfterRestart) {
   display_prefs()->StoreDisplayPowerStateForTest(
       chromeos::DISPLAY_POWER_INTERNAL_OFF_EXTERNAL_ON);
-  display_prefs()->LoadDisplayPreferences(false);
+  LoadDisplayPreferences(false);
   EXPECT_EQ(chromeos::DISPLAY_POWER_INTERNAL_OFF_EXTERNAL_ON,
             ash::Shell::Get()->display_configurator()->requested_power_state());
 }
@@ -776,7 +760,7 @@
   ash::Shell* shell = ash::Shell::Get();
   display_prefs()->StoreDisplayPowerStateForTest(
       chromeos::DISPLAY_POWER_INTERNAL_OFF_EXTERNAL_ON);
-  display_prefs()->LoadDisplayPreferences(false);
+  LoadDisplayPreferences(false);
   // DisplayPowerState should be ignored at boot.
   EXPECT_EQ(chromeos::DISPLAY_POWER_INTERNAL_OFF_EXTERNAL_ON,
             shell->display_configurator()->requested_power_state());
@@ -790,7 +774,7 @@
 
   // Don't try to load
   local_state()->SetString(prefs::kDisplayPowerState, "all_off");
-  display_prefs()->LoadDisplayPreferences(false);
+  LoadDisplayPreferences(false);
   EXPECT_EQ(chromeos::DISPLAY_POWER_INTERNAL_OFF_EXTERNAL_ON,
             shell->display_configurator()->requested_power_state());
 }
@@ -944,7 +928,7 @@
 
   display_prefs()->StoreDisplayRotationPrefsForTest(display::Display::ROTATE_90,
                                                     true);
-  display_prefs()->LoadDisplayPreferences(false);
+  LoadDisplayPreferences(false);
 
   bool display_rotation_lock =
       display_manager()->registered_internal_display_rotation_lock();
@@ -1071,7 +1055,7 @@
   StoreDisplayPropertyForList(
       list, "primary-id",
       base::MakeUnique<base::Value>(base::Int64ToString(first_display_id)));
-  display_prefs()->LoadDisplayPreferences(false);
+  LoadDisplayPreferences(false);
 
   // Should not restore to unified unless unified desktop is enabled.
   display_info_list.emplace_back(second_display_info);
@@ -1081,7 +1065,7 @@
   // Restored to unified.
   display_manager()->SetUnifiedDesktopEnabled(true);
   StoreDisplayBoolPropertyForList(list, "default_unified", true);
-  display_prefs()->LoadDisplayPreferences(false);
+  LoadDisplayPreferences(false);
   display_manager()->OnNativeDisplaysChanged(display_info_list);
   EXPECT_TRUE(display_manager()->IsInUnifiedMode());
 
@@ -1096,7 +1080,7 @@
       display::GetDisplayIdWithoutOutputIndex(second_display_id));
   StoreExternalDisplayMirrorInfo(external_display_mirror_info);
   StoreDisplayBoolPropertyForList(list, "default_unified", true);
-  display_prefs()->LoadDisplayPreferences(false);
+  LoadDisplayPreferences(false);
   display_info_list.emplace_back(second_display_info);
   display_manager()->OnNativeDisplaysChanged(display_info_list);
   EXPECT_TRUE(display_manager()->IsInMirrorMode());
@@ -1113,7 +1097,7 @@
   external_display_mirror_info.clear();
   StoreExternalDisplayMirrorInfo(external_display_mirror_info);
   StoreDisplayBoolPropertyForList(list, "default_unified", false);
-  display_prefs()->LoadDisplayPreferences(false);
+  LoadDisplayPreferences(false);
   display_info_list.emplace_back(second_display_info);
   display_manager()->OnNativeDisplaysChanged(display_info_list);
   EXPECT_FALSE(display_manager()->IsInMirrorMode());
@@ -1153,7 +1137,7 @@
   builder.AddDisplayPlacement(list[2], list[1],
                               display::DisplayPlacement::BOTTOM, 100);
   display_prefs()->StoreDisplayLayoutPrefForTest(list, *builder.Build());
-  display_prefs()->LoadDisplayPreferences(false);
+  LoadDisplayPreferences(false);
 
   UpdateDisplay("200x200,200x200,300x300");
   display::DisplayIdList new_list =
@@ -1258,7 +1242,7 @@
   std::set<int64_t> external_display_mirror_info;
   external_display_mirror_info.emplace(first_display_masked_id);
   StoreExternalDisplayMirrorInfo(external_display_mirror_info);
-  display_prefs()->LoadDisplayPreferences(true);
+  LoadDisplayPreferences(true);
   const base::ListValue* pref_external_display_mirror_info =
       local_state()->GetList(prefs::kExternalDisplayMirrorInfo);
   EXPECT_EQ(1U, pref_external_display_mirror_info->GetSize());
@@ -1298,7 +1282,7 @@
   external_display_mirror_info.clear();
   external_display_mirror_info.emplace(second_display_masked_id);
   StoreExternalDisplayMirrorInfo(external_display_mirror_info);
-  display_prefs()->LoadDisplayPreferences(false);
+  LoadDisplayPreferences(false);
   pref_external_display_mirror_info =
       local_state()->GetList(prefs::kExternalDisplayMirrorInfo);
   EXPECT_EQ(1U, pref_external_display_mirror_info->GetSize());
@@ -1326,4 +1310,4 @@
   EXPECT_EQ(0U, pref_external_display_mirror_info->GetSize());
 }
 
-}  // namespace chromeos
+}  // namespace ash
diff --git a/chrome/browser/chromeos/login/users/chrome_user_manager_impl.cc b/chrome/browser/chromeos/login/users/chrome_user_manager_impl.cc
index a83ded0..c6e38c7 100644
--- a/chrome/browser/chromeos/login/users/chrome_user_manager_impl.cc
+++ b/chrome/browser/chromeos/login/users/chrome_user_manager_impl.cc
@@ -17,6 +17,7 @@
 #include "base/bind_helpers.h"
 #include "base/command_line.h"
 #include "base/compiler_specific.h"
+#include "base/feature_list.h"
 #include "base/format_macros.h"
 #include "base/location.h"
 #include "base/logging.h"
@@ -50,6 +51,8 @@
 #include "chrome/browser/chromeos/login/users/supervised_user_manager_impl.h"
 #include "chrome/browser/chromeos/login/users/wallpaper/wallpaper_manager.h"
 #include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h"
+#include "chrome/browser/chromeos/printing/external_printers.h"
+#include "chrome/browser/chromeos/printing/external_printers_factory.h"
 #include "chrome/browser/chromeos/profiles/profile_helper.h"
 #include "chrome/browser/chromeos/session_length_limiter.h"
 #include "chrome/browser/chromeos/settings/cros_settings.h"
@@ -64,6 +67,7 @@
 #include "chrome/browser/ui/ash/wallpaper_controller_client.h"
 #include "chrome/browser/ui/browser_dialogs.h"
 #include "chrome/common/chrome_constants.h"
+#include "chrome/common/chrome_features.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/pref_names.h"
 #include "chromeos/chromeos_switches.h"
@@ -179,6 +183,10 @@
       ->GetMinimumVersionPolicyHandler();
 }
 
+ExternalPrinters* GetExternalPrinters(const AccountId& account_id) {
+  return ExternalPrintersFactory::Get()->GetForAccountId(account_id);
+}
+
 }  // namespace
 
 // static
@@ -275,6 +283,11 @@
           cros_settings_, device_local_account_policy_service,
           policy::key::kWallpaperImage, this);
   wallpaper_policy_observer_->Init();
+  printers_policy_observer_ =
+      std::make_unique<policy::CloudExternalDataPolicyObserver>(
+          cros_settings_, device_local_account_policy_service,
+          policy::key::kNativePrintersBulkConfiguration, this);
+  printers_policy_observer_->Init();
 
   // Record the stored session length for enrolled device.
   if (IsEnterpriseManaged())
@@ -321,6 +334,9 @@
   multi_profile_user_controller_.reset();
   avatar_policy_observer_.reset();
   wallpaper_policy_observer_.reset();
+  // Remove the observer before shutting down the printer policy objects.
+  printers_policy_observer_.reset();
+  ExternalPrintersFactory::Get()->Shutdown();
   registrar_.RemoveAll();
 }
 
@@ -488,6 +504,7 @@
 void ChromeUserManagerImpl::StopPolicyObserverForTesting() {
   avatar_policy_observer_.reset();
   wallpaper_policy_observer_.reset();
+  printers_policy_observer_.reset();
 }
 
 void ChromeUserManagerImpl::Observe(
@@ -567,6 +584,8 @@
     GetUserImageManager(account_id)->OnExternalDataSet(policy);
   else if (policy == policy::key::kWallpaperImage)
     WallpaperManager::Get()->OnPolicySet(policy, account_id);
+  else if (policy == policy::key::kNativePrintersBulkConfiguration)
+    GetExternalPrinters(account_id)->ClearData();
   else
     NOTREACHED();
 }
@@ -579,6 +598,8 @@
     GetUserImageManager(account_id)->OnExternalDataCleared(policy);
   else if (policy == policy::key::kWallpaperImage)
     WallpaperManager::Get()->OnPolicyCleared(policy, account_id);
+  else if (policy == policy::key::kNativePrintersBulkConfiguration)
+    GetExternalPrinters(account_id)->ClearData();
   else
     NOTREACHED();
 }
@@ -595,6 +616,8 @@
   else if (policy == policy::key::kWallpaperImage)
     WallpaperManager::Get()->OnPolicyFetched(policy, account_id,
                                              std::move(data));
+  else if (policy == policy::key::kNativePrintersBulkConfiguration)
+    GetExternalPrinters(account_id)->SetData(std::move(data));
   else
     NOTREACHED();
 }
@@ -1006,6 +1029,7 @@
 
   WallpaperControllerClient::Get()->RemoveUserWallpaper(account_id);
   GetUserImageManager(account_id)->DeleteUserImage();
+  ExternalPrintersFactory::Get()->RemoveForUserId(account_id);
 
   supervised_user_manager_->RemoveNonCryptohomeData(account_id.GetUserEmail());
 
diff --git a/chrome/browser/chromeos/login/users/chrome_user_manager_impl.h b/chrome/browser/chromeos/login/users/chrome_user_manager_impl.h
index 6b7d1be..7728498 100644
--- a/chrome/browser/chromeos/login/users/chrome_user_manager_impl.h
+++ b/chrome/browser/chromeos/login/users/chrome_user_manager_impl.h
@@ -7,6 +7,7 @@
 
 #include <map>
 #include <memory>
+#include <set>
 #include <string>
 #include <vector>
 
@@ -25,6 +26,7 @@
 #include "chrome/browser/chromeos/policy/device_local_account.h"
 #include "chrome/browser/chromeos/policy/device_local_account_policy_service.h"
 #include "chrome/browser/chromeos/policy/minimum_version_policy_handler.h"
+#include "chrome/browser/chromeos/printing/external_printers.h"
 #include "chrome/browser/chromeos/settings/cros_settings.h"
 #include "chrome/browser/chromeos/settings/device_settings_service.h"
 #include "components/signin/core/account_id/account_id.h"
@@ -295,6 +297,10 @@
   std::unique_ptr<policy::CloudExternalDataPolicyObserver>
       wallpaper_policy_observer_;
 
+  // Observer for the policy that provides policy printers.
+  std::unique_ptr<policy::CloudExternalDataPolicyObserver>
+      printers_policy_observer_;
+
   base::WeakPtrFactory<ChromeUserManagerImpl> weak_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(ChromeUserManagerImpl);
diff --git a/chrome/browser/chromeos/login/users/wallpaper/OWNERS b/chrome/browser/chromeos/login/users/wallpaper/OWNERS
index a9af8c9..0643f65 100644
--- a/chrome/browser/chromeos/login/users/wallpaper/OWNERS
+++ b/chrome/browser/chromeos/login/users/wallpaper/OWNERS
@@ -1,4 +1,7 @@
+set noparent
+
 bshe@chromium.org
+wzang@chromium.org
 xdai@chromium.org
 
 # COMPONENT: UI>Shell>Wallpaper
diff --git a/chrome/browser/chromeos/printing/cups_printers_manager.cc b/chrome/browser/chromeos/printing/cups_printers_manager.cc
index 69e87a47..dca0313 100644
--- a/chrome/browser/chromeos/printing/cups_printers_manager.cc
+++ b/chrome/browser/chromeos/printing/cups_printers_manager.cc
@@ -312,7 +312,7 @@
     const auto* detected = FindDetectedPrinter(printer.id());
 
     // For compatibility with the previous implementation, record USB printers
-    // seperately from other IPP printers.  Eventually we may want to shift
+    // separately from other IPP printers.  Eventually we may want to shift
     // this to be split by autodetected/not autodetected instead of USB/other
     // IPP.
     if (IsUsbPrinter(printer)) {
diff --git a/chrome/browser/chromeos/printing/synced_printers_manager.cc b/chrome/browser/chromeos/printing/synced_printers_manager.cc
index 992932e..8d0f628f 100644
--- a/chrome/browser/chromeos/printing/synced_printers_manager.cc
+++ b/chrome/browser/chromeos/printing/synced_printers_manager.cc
@@ -10,6 +10,7 @@
 #include <utility>
 #include <vector>
 
+#include "base/feature_list.h"
 #include "base/guid.h"
 #include "base/json/json_reader.h"
 #include "base/md5.h"
@@ -18,13 +19,20 @@
 #include "base/optional.h"
 #include "base/synchronization/lock.h"
 #include "base/values.h"
+#include "chrome/browser/browser_process.h"
+#include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h"
+#include "chrome/browser/chromeos/printing/external_printers.h"
+#include "chrome/browser/chromeos/printing/external_printers_factory.h"
+#include "chrome/browser/chromeos/printing/external_printers_pref_bridge.h"
 #include "chrome/browser/chromeos/printing/printer_configurer.h"
 #include "chrome/browser/chromeos/printing/printers_sync_bridge.h"
 #include "chrome/browser/chromeos/printing/specifics_translation.h"
 #include "chrome/browser/profiles/profile.h"
+#include "chrome/common/chrome_features.h"
 #include "chrome/common/pref_names.h"
 #include "chromeos/printing/printer_configuration.h"
 #include "chromeos/printing/printer_translator.h"
+#include "components/policy/policy_constants.h"
 #include "components/pref_registry/pref_registry_syncable.h"
 #include "components/prefs/pref_service.h"
 
@@ -32,11 +40,23 @@
 
 namespace {
 
-// Enumeration values for NativePrintersBulkAccessMode.
-constexpr int kBlacklistAccess = 0;
-// TODO(crbug.com/758680): Parse the access policy.
-// constexpr int kWhitelistAccess = 1;
-// constexpr int kAllAccess = 2;
+// Returns the collection policies for user printers.
+ExternalPrinterPolicies UserPolicyNames() {
+  ExternalPrinterPolicies user_policy_names;
+  user_policy_names.access_mode = prefs::kRecommendedNativePrintersAccessMode;
+  user_policy_names.blacklist = prefs::kRecommendedNativePrintersBlacklist;
+  user_policy_names.whitelist = prefs::kRecommendedNativePrintersWhitelist;
+  return user_policy_names;
+}
+
+// Inserts |printer| into |new_printers| if the id does not already exist.
+// Returns true if the insert was successful, false if there was a conflict.
+bool InsertIfNotPresent(std::unordered_map<std::string, Printer>* new_printers,
+                        const Printer& printer) {
+  std::pair<std::unordered_map<std::string, Printer>::iterator, bool> ret =
+      new_printers->insert({printer.id(), printer});
+  return ret.second;
+}
 
 class SyncedPrintersManagerImpl : public SyncedPrintersManager,
                                   public PrintersSyncBridge::Observer {
@@ -53,6 +73,11 @@
         prefs::kRecommendedNativePrinters,
         base::Bind(&SyncedPrintersManagerImpl::UpdateRecommendedPrinters,
                    base::Unretained(this)));
+    if (base::FeatureList::IsEnabled(features::kBulkPrinters)) {
+      printers_observer_ = std::make_unique<ExternalPrintersPrefBridge>(
+          UserPolicyNames(), profile_);
+    }
+
     UpdateRecommendedPrinters();
     sync_bridge_->AddObserver(this);
   }
@@ -137,7 +162,7 @@
     auto found = enterprise_printers_.find(printer_id);
     if (found != enterprise_printers_.end()) {
       // Copy a printer.
-      return base::MakeUnique<Printer>(found->second);
+      return std::make_unique<Printer>(found->second);
     }
 
     base::Optional<sync_pb::PrinterSpecifics> printer =
@@ -158,18 +183,15 @@
     sync_bridge_->UpdatePrinter(PrinterToSpecifics(printer));
   }
 
-  void UpdateRecommendedPrinters() {
+  // Reads printers provided by NativePrinters policy.  Appends ids to |new_ids|
+  // in the order they were received. Appends printers to |new_printers| indexed
+  // by id.  Discards printers with duplicate ids.
+  void PolicyNativePrinters(
+      std::vector<std::string>* new_ids,
+      std::unordered_map<std::string, Printer>* new_printers) {
     const PrefService* prefs = profile_->GetPrefs();
-
     const base::ListValue* values =
         prefs->GetList(prefs::kRecommendedNativePrinters);
-
-    // Parse the policy JSON into new structures outside the lock.
-    std::vector<std::string> new_ids;
-    std::unordered_map<std::string, Printer> new_printers;
-
-    new_ids.reserve(values->GetList().size());
-    new_printers.reserve(values->GetList().size());
     for (const auto& value : *values) {
       std::string printer_json;
       if (!value.GetAsString(&printer_json)) {
@@ -193,20 +215,60 @@
       std::string id = base::MD5String(printer_json);
       printer_dictionary->SetString(kPrinterId, id);
 
-      if (base::ContainsKey(new_printers, id)) {
-        // Skip duplicated entries.
-        LOG(WARNING) << "Duplicate printer ignored.";
-        continue;
-      }
-
       auto new_printer = RecommendedPrinterToPrinter(*printer_dictionary);
       if (!new_printer) {
         LOG(WARNING) << "Recommended printer is malformed.";
         continue;
       }
 
-      new_ids.push_back(id);
-      new_printers.insert({id, *new_printer});
+      if (!InsertIfNotPresent(new_printers, *new_printer)) {
+        // Printer is already in the list.
+        LOG(WARNING) << "Duplicate printer ignored: " << id;
+        continue;
+      }
+
+      new_ids->push_back(id);
+    }
+  }
+
+  // Reads printers provided by NativePrintersBulkConfigurations policy.
+  // Appends ids to |new_ids| in the order they were received. Appends printers
+  // to |new_printers| indexed by id.  Discards printers with duplicate ids.
+  void BulkPolicyPrinters(
+      std::vector<std::string>* new_ids,
+      std::unordered_map<std::string, Printer>* new_printers) {
+    DCHECK(new_ids);
+    DCHECK(new_printers);
+
+    ExternalPrinters* external_printers =
+        ExternalPrintersFactory::Get()->GetForProfile(profile_);
+    if (!external_printers || !external_printers->IsPolicySet())
+      return;
+
+    const std::map<const std::string, const Printer>& printers =
+        external_printers->GetPrinters();
+    for (const auto& entry : printers) {
+      Printer printer(entry.second);
+      printer.set_source(Printer::SRC_POLICY);
+
+      if (!InsertIfNotPresent(new_printers, printer)) {
+        // Printer is already in the list.
+        LOG(WARNING) << "Duplicate printer ignored: " << printer.id();
+        continue;
+      }
+
+      new_ids->push_back(printer.id());
+    }
+  }
+
+  void UpdateRecommendedPrinters() {
+    // Parse the policy JSON into new structures outside the lock.
+    std::vector<std::string> new_ids;
+    std::unordered_map<std::string, Printer> new_printers;
+
+    PolicyNativePrinters(&new_ids, &new_printers);
+    if (base::FeatureList::IsEnabled(features::kBulkPrinters)) {
+      BulkPolicyPrinters(&new_ids, &new_printers);
     }
 
     // Objects not in the most recent update get deallocated after method
@@ -238,6 +300,9 @@
   // The backend for profile printers.
   std::unique_ptr<PrintersSyncBridge> sync_bridge_;
 
+  // Connects external printers preferences with the tracking object.
+  std::unique_ptr<ExternalPrintersPrefBridge> printers_observer_;
+
   // Enterprise printers as of the last time we got a policy update.  The ids
   // vector is used to preserve the received ordering.
   std::vector<std::string> enterprise_printer_ids_;
@@ -261,18 +326,15 @@
   registry->RegisterListPref(prefs::kPrintingDevices,
                              user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
   registry->RegisterListPref(prefs::kRecommendedNativePrinters);
-  // Default value is blacklist.
-  registry->RegisterIntegerPref(prefs::kRecommendedNativePrintersAccessMode,
-                                kBlacklistAccess);
-  registry->RegisterListPref(prefs::kRecommendedNativePrintersBlacklist);
-  registry->RegisterListPref(prefs::kRecommendedNativePrintersWhitelist);
+
+  ExternalPrintersPrefBridge::RegisterProfilePrefs(registry, UserPolicyNames());
 }
 
 // static
 std::unique_ptr<SyncedPrintersManager> SyncedPrintersManager::Create(
     Profile* profile,
     std::unique_ptr<PrintersSyncBridge> sync_bridge) {
-  return base::MakeUnique<SyncedPrintersManagerImpl>(profile,
+  return std::make_unique<SyncedPrintersManagerImpl>(profile,
                                                      std::move(sync_bridge));
 }
 
diff --git a/chrome/browser/conflicts/installed_programs_win.cc b/chrome/browser/conflicts/installed_programs_win.cc
index 6763476..27b1b04 100644
--- a/chrome/browser/conflicts/installed_programs_win.cc
+++ b/chrome/browser/conflicts/installed_programs_win.cc
@@ -49,7 +49,7 @@
 // Returns true if the |component_path| points to a registry key. Registry key
 // paths are characterized by a number instead of a drive letter.
 // See the documentation for ::MsiGetComponentPath():
-// https://msdn.microsoft.com/en-us/library/windows/desktop/aa370112(v=vs.85).aspx
+// https://msdn.microsoft.com/library/windows/desktop/aa370112.aspx
 bool IsRegistryComponentPath(const base::string16& component_path) {
   base::string16 drive_letter =
       component_path.substr(0, component_path.find(':'));
@@ -93,15 +93,15 @@
 void CheckRegistryKeyForInstalledProgram(
     HKEY hkey,
     const base::string16& key_path,
+    REGSAM wow64access,
     const base::string16& key_name,
     const MsiUtil& msi_util,
     InstalledPrograms::ProgramsData* programs_data,
     int* size_in_bytes) {
-  base::win::RegKey candidate(
-      hkey,
-      base::StringPrintf(L"%ls\\%ls", key_path.c_str(), key_name.c_str())
-          .c_str(),
-      KEY_READ);
+  base::string16 candidate_key_path =
+      base::StringPrintf(L"%ls\\%ls", key_path.c_str(), key_name.c_str());
+  base::win::RegKey candidate(hkey, candidate_key_path.c_str(),
+                              KEY_QUERY_VALUE | wow64access);
 
   if (!candidate.Valid())
     return;
@@ -177,20 +177,25 @@
   auto programs_data = base::MakeUnique<InstalledPrograms::ProgramsData>();
 
   // Iterate over all the variants of the uninstall registry key.
-  const wchar_t* kUninstallKeyPaths[] = {
-      L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall",
-      L"SOFTWARE\\WOW6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall",
-  };
+  const wchar_t kUninstallKeyPath[] =
+      L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall";
 
+  // The "HKCU\SOFTWARE\" registry subtree is shared between both 32-bits and
+  // 64-bits views. Accessing both would create duplicate entries.
+  // https://msdn.microsoft.com/library/windows/desktop/aa384253.aspx
+  static const std::pair<HKEY, REGSAM> kCombinations[] = {
+      {HKEY_CURRENT_USER, 0},
+      {HKEY_LOCAL_MACHINE, KEY_WOW64_32KEY},
+      {HKEY_LOCAL_MACHINE, KEY_WOW64_64KEY},
+  };
   int size_in_bytes = 0;
-  for (const wchar_t* uninstall_key_path : kUninstallKeyPaths) {
-    for (HKEY hkey : {HKEY_LOCAL_MACHINE, HKEY_CURRENT_USER}) {
-      for (base::win::RegistryKeyIterator i(hkey, uninstall_key_path);
-           i.Valid(); ++i) {
-        CheckRegistryKeyForInstalledProgram(hkey, uninstall_key_path, i.Name(),
-                                            *msi_util, programs_data.get(),
-                                            &size_in_bytes);
-      }
+  for (const auto& combination : kCombinations) {
+    for (base::win::RegistryKeyIterator i(combination.first, kUninstallKeyPath,
+                                          combination.second);
+         i.Valid(); ++i) {
+      CheckRegistryKeyForInstalledProgram(
+          combination.first, kUninstallKeyPath, combination.second, i.Name(),
+          *msi_util, programs_data.get(), &size_in_bytes);
     }
   }
 
diff --git a/chrome/browser/extensions/display_info_provider_chromeos.cc b/chrome/browser/extensions/display_info_provider_chromeos.cc
index 3cd0a43..8876f11e 100644
--- a/chrome/browser/extensions/display_info_provider_chromeos.cc
+++ b/chrome/browser/extensions/display_info_provider_chromeos.cc
@@ -7,6 +7,7 @@
 #include <stdint.h>
 
 #include "ash/display/display_configuration_controller.h"
+#include "ash/display/display_prefs.h"
 #include "ash/display/overscan_calibrator.h"
 #include "ash/display/resolution_notification_controller.h"
 #include "ash/display/screen_orientation_controller_chromeos.h"
@@ -15,7 +16,6 @@
 #include "ash/touch/ash_touch_transform_controller.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/stringprintf.h"
-#include "chrome/browser/chromeos/display/display_prefs.h"
 #include "chrome/browser/ui/ash/ash_util.h"
 #include "chrome/browser/ui/ash/tablet_mode_client.h"
 #include "extensions/common/api/system_display.h"
@@ -416,7 +416,7 @@
              ->resolution_notification_controller()
              ->PrepareNotificationAndSetDisplayMode(
                  id, current_mode, new_mode, base::BindRepeating([]() {
-                   chromeos::DisplayPrefs::Get()->StoreDisplayPrefs();
+                   ash::Shell::Get()->display_prefs()->StoreDisplayPrefs();
                  }))) {
       *error = "Unable to set the display mode.";
       return false;
diff --git a/chrome/browser/extensions/webstore_install_helper.cc b/chrome/browser/extensions/webstore_install_helper.cc
index 4a49f7f..d3fea6f 100644
--- a/chrome/browser/extensions/webstore_install_helper.cc
+++ b/chrome/browser/extensions/webstore_install_helper.cc
@@ -84,7 +84,7 @@
     icon_fetcher_.reset(new BitmapFetcher(icon_url_, this, traffic_annotation));
     icon_fetcher_->Init(
         std::string(),
-        blink::kWebReferrerPolicyNoReferrerWhenDowngradeOriginWhenCrossOrigin,
+        net::URLRequest::REDUCE_REFERRER_GRANULARITY_ON_TRANSITION_CROSS_ORIGIN,
         net::LOAD_DO_NOT_SAVE_COOKIES | net::LOAD_DO_NOT_SEND_COOKIES);
     icon_fetcher_->Start(loader_factory);
   }
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc
index 03206c3..a47423b 100644
--- a/chrome/browser/flag_descriptions.cc
+++ b/chrome/browser/flag_descriptions.cc
@@ -653,12 +653,6 @@
     "Enables granting and removing access to features through the "
     "Feature-Policy HTTP header.";
 
-const char kFetchKeepaliveTimeoutSettingName[] =
-    "Fetch API keepalive timeout setting";
-const char kFetchKeepaliveTimeoutSettingDescription[] =
-    "This is for setting the timeout value for Fetch API with keepalive option "
-    "and SendBeacon";
-
 const char kFontCacheScalingName[] = "FontCache scaling";
 const char kFontCacheScalingDescription[] =
     "Reuse a cached font in the renderer to serve different sizes of font for "
@@ -1860,11 +1854,6 @@
 const char kEnableDataReductionProxyMainMenuDescription[] =
     "Enables the Data Saver menu item in the main menu";
 
-const char kEnableDataReductionProxySiteBreakdownName[] =
-    "Data Saver Site Breakdown";
-const char kEnableDataReductionProxySiteBreakdownDescription[] =
-    "Enable the site breakdown on the Data Saver settings page.";
-
 const char kEnableOmniboxClipboardProviderName[] =
     "Omnibox clipboard URL suggestions";
 const char kEnableOmniboxClipboardProviderDescription[] =
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h
index fa49d7e..e4d6ae2 100644
--- a/chrome/browser/flag_descriptions.h
+++ b/chrome/browser/flag_descriptions.h
@@ -413,9 +413,6 @@
 extern const char kFeaturePolicyName[];
 extern const char kFeaturePolicyDescription[];
 
-extern const char kFetchKeepaliveTimeoutSettingName[];
-extern const char kFetchKeepaliveTimeoutSettingDescription[];
-
 extern const char kFontCacheScalingName[];
 extern const char kFontCacheScalingDescription[];
 
@@ -1144,9 +1141,6 @@
 extern const char kEnableDataReductionProxyMainMenuName[];
 extern const char kEnableDataReductionProxyMainMenuDescription[];
 
-extern const char kEnableDataReductionProxySiteBreakdownName[];
-extern const char kEnableDataReductionProxySiteBreakdownDescription[];
-
 extern const char kEnableOmniboxClipboardProviderName[];
 extern const char kEnableOmniboxClipboardProviderDescription[];
 
diff --git a/chrome/browser/guest_view/web_view/chrome_web_view_guest_delegate.cc b/chrome/browser/guest_view/web_view/chrome_web_view_guest_delegate.cc
index 5417eca..bd85f3b 100644
--- a/chrome/browser/guest_view/web_view/chrome_web_view_guest_delegate.cc
+++ b/chrome/browser/guest_view/web_view/chrome_web_view_guest_delegate.cc
@@ -19,6 +19,7 @@
 #include "components/guest_view/browser/guest_view_event.h"
 #include "components/renderer_context_menu/context_menu_delegate.h"
 #include "content/public/browser/render_process_host.h"
+#include "content/public/browser/render_widget_host_view.h"
 #include "extensions/browser/api/web_request/web_request_api.h"
 #include "extensions/browser/guest_view/web_view/web_view_constants.h"
 
@@ -38,6 +39,20 @@
 
 bool ChromeWebViewGuestDelegate::HandleContextMenu(
     const content::ContextMenuParams& params) {
+  if ((params.source_type == ui::MENU_SOURCE_LONG_PRESS ||
+       params.source_type == ui::MENU_SOURCE_TOUCH) &&
+      !params.selection_text.empty() &&
+      (guest_web_contents()->GetRenderWidgetHostView() &&
+       guest_web_contents()
+           ->GetRenderWidgetHostView()
+           ->GetTouchSelectionControllerClientManager())) {
+    // This context menu request should be handled by the
+    // TouchSelectionController. If the user selects the full context menu from
+    // the QuickMenu, the request will come back here (with different source
+    // parameters) to complete.
+    return true;
+  }
+
   ContextMenuDelegate* menu_delegate =
       ContextMenuDelegate::FromWebContents(guest_web_contents());
   DCHECK(menu_delegate);
diff --git a/chrome/browser/history/history_tab_helper.cc b/chrome/browser/history/history_tab_helper.cc
index a05c0f2..e5778af 100644
--- a/chrome/browser/history/history_tab_helper.cc
+++ b/chrome/browser/history/history_tab_helper.cc
@@ -13,9 +13,11 @@
 #include "chrome/browser/prerender/prerender_manager_factory.h"
 #include "chrome/browser/profiles/profile.h"
 #include "components/history/content/browser/history_context_helper.h"
+#include "components/history/core/browser/history_constants.h"
 #include "components/history/core/browser/history_service.h"
 #include "content/public/browser/navigation_entry.h"
 #include "content/public/browser/navigation_handle.h"
+#include "content/public/browser/render_frame_host.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/browser/web_contents_delegate.h"
 #include "content/public/common/frame_navigate_params.h"
@@ -46,9 +48,7 @@
 }  // namespace
 
 HistoryTabHelper::HistoryTabHelper(WebContents* web_contents)
-    : content::WebContentsObserver(web_contents),
-      received_page_title_(false) {
-}
+    : content::WebContentsObserver(web_contents) {}
 
 HistoryTabHelper::~HistoryTabHelper() {
 }
@@ -60,12 +60,6 @@
     GetHistoryService()->AddPage(add_page_args);
 }
 
-void HistoryTabHelper::UpdateHistoryPageTitle(const NavigationEntry& entry) {
-  history::HistoryService* hs = GetHistoryService();
-  if (hs)
-    hs->SetPageTitle(entry.GetVirtualURL(), entry.GetTitleForDisplay());
-}
-
 history::HistoryAddPageArgs
 HistoryTabHelper::CreateHistoryAddPageArgs(
     const GURL& virtual_url,
@@ -118,8 +112,7 @@
     return;
 
   if (navigation_handle->IsInMainFrame()) {
-    // Allow the new page to set the title again.
-    received_page_title_ = false;
+    is_loading_ = true;
   } else if (!navigation_handle->HasSubframeNavigationEntryCommitted()) {
     // Filter out unwanted URLs. We don't add auto-subframe URLs that don't
     // change which NavigationEntry is current. They are a large part of history
@@ -166,7 +159,7 @@
     return;
   }
 #else
-  // Don't update history if this web contents isn't associatd with a tab.
+  // Don't update history if this web contents isn't associated with a tab.
   Browser* browser = chrome::FindBrowserWithWebContents(web_contents());
   if (!browser || browser->is_app())
     return;
@@ -175,19 +168,29 @@
   UpdateHistoryForNavigation(add_page_args);
 }
 
-void HistoryTabHelper::TitleWasSet(NavigationEntry* entry) {
-  if (received_page_title_)
+void HistoryTabHelper::DidFinishLoad(
+    content::RenderFrameHost* render_frame_host,
+    const GURL& validated_url) {
+  if (render_frame_host->GetParent())
     return;
 
-  if (entry) {
-    UpdateHistoryPageTitle(*entry);
+  is_loading_ = false;
+  last_load_completion_ = base::TimeTicks::Now();
+}
 
-    // For file URLs without a title, the title is synthesized. In that case, we
-    // don't want the update to count toward the "one set per page of the title
-    // to history."
-    bool title_is_synthesized =
-        entry->GetURL().SchemeIsFile() && entry->GetTitle().empty();
-    received_page_title_ = !title_is_synthesized;
+void HistoryTabHelper::TitleWasSet(NavigationEntry* entry) {
+  if (!entry)
+    return;
+
+  // Only store page titles into history if they were set while the page was
+  // loading or during a brief span after load is complete. This fixes the case
+  // where a page uses a title change to alert a user of a situation but that
+  // title change ends up saved in history.
+  if (is_loading_ || (base::TimeTicks::Now() - last_load_completion_ <
+                      history::GetTitleSettingWindow())) {
+    history::HistoryService* hs = GetHistoryService();
+    if (hs)
+      hs->SetPageTitle(entry->GetVirtualURL(), entry->GetTitleForDisplay());
   }
 }
 
diff --git a/chrome/browser/history/history_tab_helper.h b/chrome/browser/history/history_tab_helper.h
index 4007a00..9dcf0c97 100644
--- a/chrome/browser/history/history_tab_helper.h
+++ b/chrome/browser/history/history_tab_helper.h
@@ -26,10 +26,6 @@
   void UpdateHistoryForNavigation(
       const history::HistoryAddPageArgs& add_page_args);
 
-  // Sends the page title to the history service. This is called when we receive
-  // the page title and we know we want to update history.
-  void UpdateHistoryPageTitle(const content::NavigationEntry& entry);
-
   // Returns the history::HistoryAddPageArgs to use for adding a page to
   // history.
   history::HistoryAddPageArgs CreateHistoryAddPageArgs(
@@ -45,17 +41,22 @@
   // content::WebContentsObserver implementation.
   void DidFinishNavigation(
       content::NavigationHandle* navigation_handle) override;
+  void DidFinishLoad(content::RenderFrameHost* render_frame_host,
+                     const GURL& validated_url) override;
   void TitleWasSet(content::NavigationEntry* entry) override;
   void WebContentsDestroyed() override;
 
-  // Helper function to return the history service.  May return NULL.
+  // Helper function to return the history service.  May return null.
   history::HistoryService* GetHistoryService();
 
-  // Whether we have a (non-empty) title for the current page.
-  // Used to prevent subsequent title updates from affecting history. This
-  // prevents some weirdness because some AJAXy apps use titles for status
-  // messages.
-  bool received_page_title_;
+  // True after navigation to a page is complete and the page is currently
+  // loading. Only applies to the main frame of the page.
+  bool is_loading_ = false;
+
+  // The time that the current page finished loading. Only title changes within
+  // a certain time period after the page load is complete will be saved to the
+  // history system. Only applies to the main frame of the page.
+  base::TimeTicks last_load_completion_;
 
   DISALLOW_COPY_AND_ASSIGN(HistoryTabHelper);
 };
diff --git a/chrome/browser/infobars/infobars_browsertest.cc b/chrome/browser/infobars/infobars_browsertest.cc
index b1d2d68..d7542118 100644
--- a/chrome/browser/infobars/infobars_browsertest.cc
+++ b/chrome/browser/infobars/infobars_browsertest.cc
@@ -27,6 +27,7 @@
 #include "chrome/browser/ui/omnibox/alternate_nav_infobar_delegate.h"
 #include "chrome/browser/ui/page_info/page_info_infobar_delegate.h"
 #include "chrome/browser/ui/startup/automation_infobar_delegate.h"
+#include "chrome/browser/ui/startup/obsolete_system_infobar_delegate.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/browser/ui/test/test_browser_ui.h"
 #include "chrome/common/chrome_switches.h"
@@ -48,6 +49,7 @@
 #endif
 
 #if defined(OS_MACOSX)
+#include "chrome/browser/ui/cocoa/keystone_infobar_delegate.h"
 #include "chrome/browser/ui/startup/session_crashed_infobar_delegate.h"
 #endif
 
@@ -93,40 +95,49 @@
 
   ui_test_utils::NavigateToURL(
       browser(), embedded_test_server()->GetURL("/simple.html"));
+  InfoBarService* infobar_service = InfoBarService::FromWebContents(
+      browser()->tab_strip_model()->GetActiveWebContents());
 
-  content::WindowedNotificationObserver infobar_added_1(
+  // Adding a theme should create an infobar.
+  {
+    content::WindowedNotificationObserver infobar_added(
         chrome::NOTIFICATION_TAB_CONTENTS_INFOBAR_ADDED,
         content::NotificationService::AllSources());
-  InstallExtension("theme.crx");
-  infobar_added_1.Wait();
+    InstallExtension("theme.crx");
+    infobar_added.Wait();
+    EXPECT_EQ(1u, infobar_service->infobar_count());
+  }
 
-  ui_test_utils::NavigateToURLWithDisposition(
-      browser(), embedded_test_server()->GetURL("/simple.html"),
-      WindowOpenDisposition::NEW_FOREGROUND_TAB,
-      ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
-  content::WindowedNotificationObserver infobar_added_2(
+  // Adding a theme in a new tab should close the old tab's infobar.
+  {
+    ui_test_utils::NavigateToURLWithDisposition(
+        browser(), embedded_test_server()->GetURL("/simple.html"),
+        WindowOpenDisposition::NEW_FOREGROUND_TAB,
+        ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
+    content::WindowedNotificationObserver infobar_added(
         chrome::NOTIFICATION_TAB_CONTENTS_INFOBAR_ADDED,
         content::NotificationService::AllSources());
-  content::WindowedNotificationObserver infobar_removed_1(
-      chrome::NOTIFICATION_TAB_CONTENTS_INFOBAR_REMOVED,
+    content::WindowedNotificationObserver infobar_removed(
+        chrome::NOTIFICATION_TAB_CONTENTS_INFOBAR_REMOVED,
         content::NotificationService::AllSources());
-  InstallExtension("theme2.crx");
-  infobar_removed_1.Wait();
-  infobar_added_2.Wait();
-  EXPECT_EQ(
-      0u,
-      InfoBarService::FromWebContents(
-          browser()->tab_strip_model()->GetWebContentsAt(0))->infobar_count());
+    InstallExtension("theme2.crx");
+    infobar_removed.Wait();
+    infobar_added.Wait();
+    EXPECT_EQ(0u, infobar_service->infobar_count());
+    infobar_service = InfoBarService::FromWebContents(
+        browser()->tab_strip_model()->GetActiveWebContents());
+    EXPECT_EQ(1u, infobar_service->infobar_count());
+  }
 
-  content::WindowedNotificationObserver infobar_removed_2(
-      chrome::NOTIFICATION_TAB_CONTENTS_INFOBAR_REMOVED,
+  // Switching back to the default theme should close the infobar.
+  {
+    content::WindowedNotificationObserver infobar_removed(
+        chrome::NOTIFICATION_TAB_CONTENTS_INFOBAR_REMOVED,
         content::NotificationService::AllSources());
-  ThemeServiceFactory::GetForProfile(browser()->profile())->UseDefaultTheme();
-  infobar_removed_2.Wait();
-  EXPECT_EQ(0u,
-            InfoBarService::FromWebContents(
-                browser()->tab_strip_model()->GetActiveWebContents())->
-                infobar_count());
+    ThemeServiceFactory::GetForProfile(browser()->profile())->UseDefaultTheme();
+    infobar_removed.Wait();
+    EXPECT_EQ(0u, infobar_service->infobar_count());
+  }
 }
 
 namespace {
@@ -203,9 +214,11 @@
       {"reload_plugin", IBD::RELOAD_PLUGIN_INFOBAR_DELEGATE},
       {"plugin_observer", IBD::PLUGIN_OBSERVER_INFOBAR_DELEGATE},
       {"file_access_disabled", IBD::FILE_ACCESS_DISABLED_INFOBAR_DELEGATE},
+      {"keystone_promotion", IBD::KEYSTONE_PROMOTION_INFOBAR_DELEGATE_MAC},
       {"collected_cookies", IBD::COLLECTED_COOKIES_INFOBAR_DELEGATE},
       {"alternate_nav", IBD::ALTERNATE_NAV_INFOBAR_DELEGATE},
       {"default_browser", IBD::DEFAULT_BROWSER_INFOBAR_DELEGATE},
+      {"obsolete_system", IBD::OBSOLETE_SYSTEM_INFOBAR_DELEGATE},
       {"session_crashed", IBD::SESSION_CRASHED_INFOBAR_DELEGATE_MAC_IOS},
       {"page_info", IBD::PAGE_INFO_INFOBAR_DELEGATE},
       {"translate", IBD::TRANSLATE_INFOBAR_DELEGATE_NON_AURA},
@@ -245,6 +258,13 @@
     case IBD::FILE_ACCESS_DISABLED_INFOBAR_DELEGATE:
       ChromeSelectFilePolicy(GetWebContents()).SelectFileDenied();
       break;
+    case IBD::KEYSTONE_PROMOTION_INFOBAR_DELEGATE_MAC:
+#if defined(OS_MACOSX)
+      KeystonePromotionInfoBarDelegate::Create(GetWebContents());
+#else
+      ADD_FAILURE() << "This infobar is not supported on this OS.";
+#endif
+      break;
     case IBD::COLLECTED_COOKIES_INFOBAR_DELEGATE:
       CollectedCookiesInfoBarDelegate::Create(GetInfoBarService());
       break;
@@ -263,6 +283,9 @@
                                                     browser()->profile());
 #endif
       break;
+    case IBD::OBSOLETE_SYSTEM_INFOBAR_DELEGATE:
+      ObsoleteSystemInfoBarDelegate::Create(GetInfoBarService());
+      break;
     case IBD::SESSION_CRASHED_INFOBAR_DELEGATE_MAC_IOS:
 #if defined(OS_MACOSX)
       SessionCrashedInfoBarDelegate::Create(browser());
@@ -355,6 +378,12 @@
   ShowAndVerifyUi();
 }
 
+#if defined(OS_MACOSX)
+IN_PROC_BROWSER_TEST_F(InfoBarUiTest, InvokeUi_keystone_promotion) {
+  ShowAndVerifyUi();
+}
+#endif
+
 IN_PROC_BROWSER_TEST_F(InfoBarUiTest, InvokeUi_collected_cookies) {
   ShowAndVerifyUi();
 }
@@ -369,6 +398,10 @@
 }
 #endif
 
+IN_PROC_BROWSER_TEST_F(InfoBarUiTest, InvokeUi_obsolete_system) {
+  ShowAndVerifyUi();
+}
+
 #if defined(OS_MACOSX)
 IN_PROC_BROWSER_TEST_F(InfoBarUiTest, InvokeUi_session_crashed) {
   ShowAndVerifyUi();
diff --git a/chrome/browser/io_thread.cc b/chrome/browser/io_thread.cc
index 42e44e4..7227741 100644
--- a/chrome/browser/io_thread.cc
+++ b/chrome/browser/io_thread.cc
@@ -531,15 +531,14 @@
                         CRYPTO_needs_hwcap2_workaround());
 #endif
 
+  std::vector<scoped_refptr<const net::CTLogVerifier>> ct_logs(
+      net::ct::CreateLogVerifiersForKnownLogs());
+  globals_->ct_logs.assign(ct_logs.begin(), ct_logs.end());
+
   ConstructSystemRequestContext();
 
   UpdateDnsClientEnabled();
 
-  std::vector<scoped_refptr<const net::CTLogVerifier>> ct_logs(
-      net::ct::CreateLogVerifiersForKnownLogs());
-
-  globals_->ct_logs.assign(ct_logs.begin(), ct_logs.end());
-
   ct_tree_tracker_ =
       std::make_unique<certificate_transparency::TreeStateTracker>(
           globals_->ct_logs, globals_->system_request_context->host_resolver(),
diff --git a/chrome/browser/loader/safe_browsing_resource_throttle.cc b/chrome/browser/loader/safe_browsing_resource_throttle.cc
index 0a37234..60514c4 100644
--- a/chrome/browser/loader/safe_browsing_resource_throttle.cc
+++ b/chrome/browser/loader/safe_browsing_resource_throttle.cc
@@ -6,11 +6,9 @@
 
 #include "chrome/browser/safe_browsing/safe_browsing_service.h"
 #include "chrome/browser/safe_browsing/ui_manager.h"
-#include "components/safe_browsing/base_ui_manager.h"
+#include "chrome/browser/safe_browsing/url_checker_delegate_impl.h"
+#include "components/safe_browsing/db/database_manager.h"
 #include "components/safe_browsing/db/v4_protocol_manager_util.h"
-#include "components/safe_browsing/features.h"
-#include "content/public/browser/resource_request_info.h"
-#include "net/http/http_request_headers.h"
 
 content::ResourceThrottle* MaybeCreateSafeBrowsingResourceThrottle(
     net::URLRequest* request,
@@ -19,48 +17,8 @@
   if (!sb_service->database_manager()->IsSupported())
     return nullptr;
 
-  if (base::FeatureList::IsEnabled(safe_browsing::kParallelUrlCheck)) {
-    return new SafeBrowsingParallelResourceThrottle(request, resource_type,
-                                                    sb_service);
-  }
-  return new SafeBrowsingResourceThrottle(request, resource_type, sb_service);
-}
-
-SafeBrowsingResourceThrottle::SafeBrowsingResourceThrottle(
-    const net::URLRequest* request,
-    content::ResourceType resource_type,
-    safe_browsing::SafeBrowsingService* sb_service)
-    : safe_browsing::BaseResourceThrottle(
-          request,
-          resource_type,
-          safe_browsing::CreateSBThreatTypeSet(
-              {safe_browsing::SB_THREAT_TYPE_URL_MALWARE,
-               safe_browsing::SB_THREAT_TYPE_URL_PHISHING,
-               safe_browsing::SB_THREAT_TYPE_URL_UNWANTED}),
-          sb_service->database_manager(),
-          sb_service->ui_manager()),
-      url_checker_delegate_(new safe_browsing::UrlCheckerDelegateImpl(
-          sb_service->database_manager(),
-          sb_service->ui_manager())) {}
-
-SafeBrowsingResourceThrottle::~SafeBrowsingResourceThrottle() = default;
-
-const char* SafeBrowsingResourceThrottle::GetNameForLogging() const {
-  return "SafeBrowsingResourceThrottle";
-}
-
-void SafeBrowsingResourceThrottle::MaybeDestroyPrerenderContents(
-    const content::ResourceRequestInfo* info) {
-  url_checker_delegate_->MaybeDestroyPrerenderContents(
-      info->GetWebContentsGetterForRequest());
-}
-
-void SafeBrowsingResourceThrottle::StartDisplayingBlockingPageHelper(
-    security_interstitials::UnsafeResource resource) {
-  // On Chrome only the first argument is used.
-  url_checker_delegate_->StartDisplayingBlockingPageHelper(
-      resource, std::string(), net::HttpRequestHeaders(),
-      false /* is_main_frame */, false /* has_user_gesture */);
+  return new SafeBrowsingParallelResourceThrottle(request, resource_type,
+                                                  sb_service);
 }
 
 SafeBrowsingParallelResourceThrottle::SafeBrowsingParallelResourceThrottle(
diff --git a/chrome/browser/loader/safe_browsing_resource_throttle.h b/chrome/browser/loader/safe_browsing_resource_throttle.h
index ee9889ed..38d3161 100644
--- a/chrome/browser/loader/safe_browsing_resource_throttle.h
+++ b/chrome/browser/loader/safe_browsing_resource_throttle.h
@@ -7,8 +7,6 @@
 
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
-#include "chrome/browser/safe_browsing/url_checker_delegate_impl.h"
-#include "components/safe_browsing/base_resource_throttle.h"
 #include "components/safe_browsing/browser/base_parallel_resource_throttle.h"
 #include "content/public/browser/resource_throttle.h"
 #include "content/public/common/resource_type.h"
@@ -21,11 +19,7 @@
 class SafeBrowsingService;
 }
 
-// Contructs a resource throttle for SafeBrowsing. It returns a
-// SafeBrowsingParallelResourceThrottle instance if
-// --enable-features=S13nSafeBrowsingParallelUrlCheck is specified; returns
-// a SafeBrowsingResourceThrottle otherwise.
-//
+// Contructs a resource throttle for SafeBrowsing.
 // It could return nullptr if URL checking is not supported on this
 // build+device.
 content::ResourceThrottle* MaybeCreateSafeBrowsingResourceThrottle(
@@ -33,67 +27,9 @@
     content::ResourceType resource_type,
     safe_browsing::SafeBrowsingService* sb_service);
 
-// SafeBrowsingResourceThrottle functions as its base class
-// safe_browsing::BaseResourceThrottle, but dispatches to either the local or
-// remote SafeBrowsingDatabaseManager, depending on if running on desktop or
-// mobile. It also has its own chrome-specific prerender check of redirect URLs
-// inside StartDisplayingBlockingPage().
-//
-// See also safe_browsing::BaseResourceThrottle for details on how the safe
-// browsing check occurs.
-//
-// On desktop (ifdef SAFE_BROWSING_DB_LOCAL)
-// -----------------------------------------
-// This check is done before requesting the original URL, and additionally
-// before following any subsequent redirect.  In the common case the check
-// completes synchronously (no match in the in-memory DB), so the request's
-// flow is un-interrupted.  However if the URL fails this quick check, it
-// has the possibility of being on the blacklist. Now the request is
-// deferred (prevented from starting), and a more expensive safe browsing
-// check is begun (fetches the full hashes).
-//
-// On mobile (ifdef SAFE_BROWSING_DB_REMOTE):
-// -----------------------------------------
-// The check is started and runs in parallel with the resource load.  If the
-// check is not complete by the time the headers are loaded, the request is
-// suspended until the URL is classified.  We let the headers load on mobile
-// since the RemoteSafeBrowsingDatabase checks always have some non-zero
-// latency -- there no synchronous pass.  This parallelism helps
-// performance.  Redirects are handled the same way as desktop so they
-// always defer.
-class SafeBrowsingResourceThrottle
-    : public safe_browsing::BaseResourceThrottle {
- private:
-  friend content::ResourceThrottle* MaybeCreateSafeBrowsingResourceThrottle(
-      net::URLRequest* request,
-      content::ResourceType resource_type,
-      safe_browsing::SafeBrowsingService* sb_service);
-
-  SafeBrowsingResourceThrottle(const net::URLRequest* request,
-                               content::ResourceType resource_type,
-                               safe_browsing::SafeBrowsingService* sb_service);
-
-  ~SafeBrowsingResourceThrottle() override;
-
-  const char* GetNameForLogging() const override;
-
-  // This posts a task to destroy prerender contents
-  void MaybeDestroyPrerenderContents(
-      const content::ResourceRequestInfo* info) override;
-
-  void StartDisplayingBlockingPageHelper(
-      security_interstitials::UnsafeResource resource) override;
-
-  scoped_refptr<safe_browsing::UrlCheckerDelegate> url_checker_delegate_;
-
-  DISALLOW_COPY_AND_ASSIGN(SafeBrowsingResourceThrottle);
-};
-
-// Unlike SafeBrowsingResourceThrottle, this class never defers starting the URL
-// request or following redirects, no matter on mobile or desktop. If any of the
-// checks for the original URL and redirect chain are not complete by the time
-// the response headers are available, the request is deferred until all the
-// checks are done.
+// SafeBrowsingParallelResourceThrottle uses a Chrome-specific
+// safe_browsing::UrlCheckerDelegate implementation with its base class
+// safe_browsing::BaseParallelResourceThrottle.
 class SafeBrowsingParallelResourceThrottle
     : public safe_browsing::BaseParallelResourceThrottle {
  private:
diff --git a/chrome/browser/media/encrypted_media_browsertest.cc b/chrome/browser/media/encrypted_media_browsertest.cc
index 02fd2274..c03ace8 100644
--- a/chrome/browser/media/encrypted_media_browsertest.cc
+++ b/chrome/browser/media/encrypted_media_browsertest.cc
@@ -309,17 +309,11 @@
 
 #if BUILDFLAG(ENABLE_LIBRARY_CDMS)
     if (IsExternalClearKey(key_system)) {
-      // TODO(crbug.com/764143): Only RegisterPepperCdm() when we use pepper CDM
-      // after we update key system support query to use CdmRegistry.
-      RegisterPepperCdm(command_line, media::kClearKeyCdmBaseDirectory,
-                        media::kClearKeyCdmAdapterFileName,
-                        media::kClearKeyCdmDisplayName,
-                        media::kClearKeyCdmPepperMimeType);
+      RegisterExternalClearKey(command_line);
 
       // TODO(xhwang): Update ScopedFeatureList::InitWithFeatures() to accept
       // vectors so that we can simplify this block.
       if (cdm_host_type == CdmHostType::kMojo) {
-        RegisterExternalClearKey(command_line);
         if (support_experimental_cdm_interface) {
           scoped_feature_list_.InitWithFeatures(
               {media::kExternalClearKeyForTesting,
diff --git a/chrome/browser/media/encrypted_media_supported_types_browsertest.cc b/chrome/browser/media/encrypted_media_supported_types_browsertest.cc
index d922316e..6fbac66 100644
--- a/chrome/browser/media/encrypted_media_supported_types_browsertest.cc
+++ b/chrome/browser/media/encrypted_media_supported_types_browsertest.cc
@@ -311,13 +311,7 @@
 
   void SetUpCommandLine(base::CommandLine* command_line) override {
     EncryptedMediaSupportedTypesTest::SetUpCommandLine(command_line);
-    // TODO(crbug.com/764143): Replace RegisterPepperCdm() with
-    // RegisterExternalClearKey() after we migrate key system support query to
-    // use CdmRegistry.
-    RegisterPepperCdm(command_line, media::kClearKeyCdmBaseDirectory,
-                      media::kClearKeyCdmAdapterFileName,
-                      media::kClearKeyCdmDisplayName,
-                      media::kClearKeyCdmPepperMimeType);
+    RegisterExternalClearKey(command_line);
   }
 
  private:
diff --git a/chrome/browser/media/library_cdm_test_helper.cc b/chrome/browser/media/library_cdm_test_helper.cc
index 284a7723..bac3a4c 100644
--- a/chrome/browser/media/library_cdm_test_helper.cc
+++ b/chrome/browser/media/library_cdm_test_helper.cc
@@ -33,6 +33,13 @@
   // Append the switch to register the Clear Key CDM path.
   command_line->AppendSwitchNative(switches::kClearKeyCdmPathForTesting,
                                    cdm_path.value());
+
+  // Also register the pepper plugin.
+  // TODO(crbug.com/772160) Remove this when pepper CDM support removed.
+  RegisterPepperCdm(command_line, media::kClearKeyCdmBaseDirectory,
+                    media::kClearKeyCdmAdapterFileName,
+                    media::kClearKeyCdmDisplayName,
+                    media::kClearKeyCdmPepperMimeType);
 }
 
 bool IsLibraryCdmRegistered(const std::string& cdm_guid) {
diff --git a/chrome/browser/metrics/startup_metrics_browsertest.cc b/chrome/browser/metrics/startup_metrics_browsertest.cc
index ab9258f..1e5e999 100644
--- a/chrome/browser/metrics/startup_metrics_browsertest.cc
+++ b/chrome/browser/metrics/startup_metrics_browsertest.cc
@@ -30,6 +30,7 @@
     // "Startup.BrowserMessageLoopStartHardFaultCount",
     // "Startup.BrowserMessageLoopStartTime",
     // "Startup.BrowserMessageLoopStartTimeFromMainEntry2",
+    // "Startup.BrowserMessageLoopStartTimeFromMainEntry3",
     // "Startup.LoadTime.ExeMainToDllMain2",
     // "Startup.LoadTime.ProcessCreateToDllMain2",
     // "Startup.LoadTime.ProcessCreateToExeMain2",
diff --git a/chrome/browser/password_manager/credential_manager_browsertest.cc b/chrome/browser/password_manager/credential_manager_browsertest.cc
index b1b3026b..f2b6c13 100644
--- a/chrome/browser/password_manager/credential_manager_browsertest.cc
+++ b/chrome/browser/password_manager/credential_manager_browsertest.cc
@@ -1004,9 +1004,9 @@
 
   // Reload the page and make sure it's autofilled.
   NavigateToFile("/password/password_form.html");
+  WaitForElementValue("username_field", "user");
   content::SimulateMouseClickAt(
       WebContents(), 0, blink::WebMouseEvent::Button::kLeft, gfx::Point(1, 1));
-  WaitForElementValue("username_field", "user");
   WaitForElementValue("password_field", "12345");
 }
 
diff --git a/chrome/browser/password_manager/password_manager_browsertest.cc b/chrome/browser/password_manager/password_manager_browsertest.cc
index 4a7f903c..3f77775 100644
--- a/chrome/browser/password_manager/password_manager_browsertest.cc
+++ b/chrome/browser/password_manager/password_manager_browsertest.cc
@@ -968,11 +968,13 @@
   // Now navigate to a login form that has similar HTML markup.
   NavigateToFile("/password/password_form.html");
 
+  // The form should be filled with the previously submitted username.
+  CheckElementValue("username_field", "my_username");
+
   // Simulate a user click to force an autofill of the form's DOM value, not
   // just the suggested value.
   content::SimulateMouseClick(WebContents(), 0,
                               blink::WebMouseEvent::Button::kLeft);
-  WaitForElementValue("username_field", "my_username");
   WaitForElementValue("password_field", "password");
 
   // Submit the form and verify that there is no infobar (as the password
@@ -1151,7 +1153,7 @@
 }
 
 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTestBase,
-                       UsernameAndPasswordValueAccessible) {
+                       PasswordValueAccessible) {
   // At first let us save a credential to the password store.
   scoped_refptr<password_manager::TestPasswordStore> password_store =
       static_cast<password_manager::TestPasswordStore*>(
@@ -1184,16 +1186,18 @@
   NavigateToFile("/password/form_and_link.html");
   reload_observer.Wait();
 
-  // Now check that the username and the password are not accessible yet.
-  CheckElementValue("username_field", "");
+  // Wait until the username is filled, to make sure autofill kicked in.
+  WaitForElementValue("username_field", "admin");
+  // Now check that the password is not accessible yet.
   CheckElementValue("password_field", "");
   // Let the user interact with the page.
   content::SimulateMouseClickAt(
       WebContents(), 0, blink::WebMouseEvent::Button::kLeft, gfx::Point(1, 1));
-  // Wait until that interaction causes the username and the password value to
-  // be revealed.
-  WaitForElementValue("username_field", "admin");
+  // Wait until that interaction causes the password value to be revealed.
   WaitForElementValue("password_field", "12345");
+  // And check that after the side-effects of the interaction took place, the
+  // username value stays the same.
+  CheckElementValue("username_field", "admin");
 }
 
 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTestBase,
@@ -2295,8 +2299,10 @@
   NavigateToFile("/password/password_form_in_same_origin_iframe.html");
   reload_observer.Wait();
 
-  // Verify password and username are not accessible yet.
-  CheckElementValue("iframe", "username_field", "");
+  // Verify username is autofilled
+  CheckElementValue("iframe", "username_field", "temp");
+
+  // Verify password is not autofilled
   CheckElementValue("iframe", "password_field", "");
 
   // Simulate the user interaction in the iframe which should trigger autofill.
@@ -2320,9 +2326,11 @@
 
   content::SimulateMouseClickAt(
       WebContents(), 0, blink::WebMouseEvent::Button::kLeft, gfx::Point(x, y));
-  // Verify username and password have been autofilled
-  WaitForElementValue("iframe", "username_field", "temp");
+  // Verify password has been autofilled
   WaitForElementValue("iframe", "password_field", "pa55w0rd");
+
+  // Verify username has been autofilled
+  CheckElementValue("iframe", "username_field", "temp");
 }
 
 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTestBase, NoFormElementTest) {
@@ -2957,12 +2965,13 @@
   // password is autofilled.
   NavigateToFile("/password/password_form.html");
 
+  CheckElementValue("hidden_password_form_username", "myusername");
+
   // Let the user interact with the page, so that DOM gets modification events,
   // needed for autofilling the password.
   content::SimulateMouseClickAt(
       WebContents(), 0, blink::WebMouseEvent::Button::kLeft, gfx::Point(1, 1));
 
-  WaitForElementValue("hidden_password_form_username", "myusername");
   WaitForElementValue("hidden_password_form_password", "mypassword");
 }
 
@@ -2985,12 +2994,13 @@
   // whether username and password is autofilled.
   NavigateToFile("/password/password_form.html");
 
+  CheckElementValue("form_with_hidden_password_username", "myusername");
+
   // Let the user interact with the page, so that DOM gets modification events,
   // needed for autofilling the password.
   content::SimulateMouseClickAt(
       WebContents(), 0, blink::WebMouseEvent::Button::kLeft, gfx::Point(1, 1));
 
-  WaitForElementValue("form_with_hidden_password_username", "myusername");
   WaitForElementValue("form_with_hidden_password_password", "mypassword");
 }
 
diff --git a/chrome/browser/prefs/browser_prefs.cc b/chrome/browser/prefs/browser_prefs.cc
index 8f4ea3d..64a468b 100644
--- a/chrome/browser/prefs/browser_prefs.cc
+++ b/chrome/browser/prefs/browser_prefs.cc
@@ -202,7 +202,6 @@
 #include "chrome/browser/chromeos/arc/arc_session_manager.h"
 #include "chrome/browser/chromeos/arc/policy/arc_policy_bridge.h"
 #include "chrome/browser/chromeos/customization/customization_document.h"
-#include "chrome/browser/chromeos/display/display_prefs.h"
 #include "chrome/browser/chromeos/extensions/echo_private_api.h"
 #include "chrome/browser/chromeos/file_system_provider/registry.h"
 #include "chrome/browser/chromeos/first_run/first_run.h"
@@ -424,7 +423,6 @@
   chromeos::NetworkThrottlingObserver::RegisterPrefs(registry);
   chromeos::PowerMetricsReporter::RegisterLocalStatePrefs(registry);
   chromeos::Preferences::RegisterPrefs(registry);
-  chromeos::DisplayPrefs::RegisterLocalStatePrefs(registry);
   chromeos::ResetScreen::RegisterPrefs(registry);
   chromeos::ResourceReporter::RegisterPrefs(registry);
   chromeos::ServicesCustomizationDocument::RegisterPrefs(registry);
diff --git a/chrome/browser/profiles/off_the_record_profile_impl.cc b/chrome/browser/profiles/off_the_record_profile_impl.cc
index abd3151..152cb90 100644
--- a/chrome/browser/profiles/off_the_record_profile_impl.cc
+++ b/chrome/browser/profiles/off_the_record_profile_impl.cc
@@ -127,17 +127,6 @@
 }  // namespace
 #endif
 
-PrefStore* CreateExtensionPrefStore(Profile* profile,
-                                    bool incognito_pref_store) {
-#if BUILDFLAG(ENABLE_EXTENSIONS)
-  return new ExtensionPrefStore(
-      ExtensionPrefValueMapFactory::GetForBrowserContext(profile),
-      incognito_pref_store);
-#else
-  return NULL;
-#endif
-}
-
 OffTheRecordProfileImpl::OffTheRecordProfileImpl(Profile* real_profile)
     : profile_(real_profile), start_time_(Time::Now()) {
   // Must happen before we ask for prefs as prefs needs the connection to the
diff --git a/chrome/browser/profiles/profile.cc b/chrome/browser/profiles/profile.cc
index b8cdce2..89468b9 100644
--- a/chrome/browser/profiles/profile.cc
+++ b/chrome/browser/profiles/profile.cc
@@ -40,6 +40,8 @@
 #endif
 
 #if BUILDFLAG(ENABLE_EXTENSIONS)
+#include "extensions/browser/extension_pref_store.h"
+#include "extensions/browser/extension_pref_value_map_factory.h"
 #include "extensions/browser/pref_names.h"
 #endif
 
@@ -290,6 +292,17 @@
   }
 }
 
+PrefStore* Profile::CreateExtensionPrefStore(Profile* profile,
+                                             bool incognito_pref_store) {
+#if BUILDFLAG(ENABLE_EXTENSIONS)
+  return new ExtensionPrefStore(
+      ExtensionPrefValueMapFactory::GetForBrowserContext(profile),
+      incognito_pref_store);
+#else
+  return nullptr;
+#endif
+}
+
 bool ProfileCompare::operator()(Profile* a, Profile* b) const {
   DCHECK(a && b);
   if (a->IsSameProfile(b))
diff --git a/chrome/browser/profiles/profile.h b/chrome/browser/profiles/profile.h
index 5826d8b9..aac8aa0 100644
--- a/chrome/browser/profiles/profile.h
+++ b/chrome/browser/profiles/profile.h
@@ -24,6 +24,7 @@
 
 class ExtensionSpecialStoragePolicy;
 class PrefService;
+class PrefStore;
 class TestingProfile;
 
 namespace base {
@@ -345,6 +346,11 @@
     is_system_profile_ = is_system_profile;
   }
 
+  // Returns a newly created ExtensionPrefStore suitable for the supplied
+  // Profile.
+  static PrefStore* CreateExtensionPrefStore(Profile*,
+                                             bool incognito_pref_store);
+
  private:
   bool restored_last_session_;
 
diff --git a/chrome/browser/profiles/profile_avatar_downloader.cc b/chrome/browser/profiles/profile_avatar_downloader.cc
index e3b6bfb..c1980027 100644
--- a/chrome/browser/profiles/profile_avatar_downloader.cc
+++ b/chrome/browser/profiles/profile_avatar_downloader.cc
@@ -68,7 +68,7 @@
   if (loader_factory) {
     fetcher_->Init(
         std::string(),
-        blink::kWebReferrerPolicyNoReferrerWhenDowngradeOriginWhenCrossOrigin,
+        net::URLRequest::REDUCE_REFERRER_GRANULARITY_ON_TRANSITION_CROSS_ORIGIN,
         net::LOAD_NORMAL);
     fetcher_->Start(loader_factory);
   }
diff --git a/chrome/browser/profiles/profile_impl.cc b/chrome/browser/profiles/profile_impl.cc
index e533e435..be977dfe 100644
--- a/chrome/browser/profiles/profile_impl.cc
+++ b/chrome/browser/profiles/profile_impl.cc
@@ -270,17 +270,6 @@
   return std::string();
 }
 
-PrefStore* CreateExtensionPrefStore(Profile* profile,
-                                    bool incognito_pref_store) {
-#if BUILDFLAG(ENABLE_EXTENSIONS)
-  return new ExtensionPrefStore(
-      ExtensionPrefValueMapFactory::GetForBrowserContext(profile),
-      incognito_pref_store);
-#else
-  return NULL;
-#endif
-}
-
 }  // namespace
 
 // static
diff --git a/chrome/browser/repost_form_warning_browsertest.cc b/chrome/browser/repost_form_warning_browsertest.cc
index b6c7468..d7566ad 100644
--- a/chrome/browser/repost_form_warning_browsertest.cc
+++ b/chrome/browser/repost_form_warning_browsertest.cc
@@ -2,10 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "build/build_config.h"
 #include "chrome/app/chrome_command_ids.h"
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
+#include "chrome/browser/ui/test/test_browser_dialog.h"
 #include "chrome/common/url_constants.h"
 #include "chrome/test/base/in_process_browser_test.h"
 #include "chrome/test/base/ui_test_utils.h"
@@ -17,10 +19,26 @@
 
 using web_modal::WebContentsModalDialogManager;
 
-typedef InProcessBrowserTest RepostFormWarningTest;
+class RepostFormWarningTest : public DialogBrowserTest {
+ public:
+  RepostFormWarningTest() {}
+  ~RepostFormWarningTest() override {}
 
-// If becomes flaky, disable on Windows and use http://crbug.com/47228
-IN_PROC_BROWSER_TEST_F(RepostFormWarningTest, TestDoubleReload) {
+  // BrowserTestBase:
+  void SetUpOnMainThread() override;
+
+  // DialogBrowserTest:
+  void ShowUi(const std::string& name) override;
+
+ protected:
+  content::WebContents* TryReload();
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(RepostFormWarningTest);
+};
+
+void RepostFormWarningTest::SetUpOnMainThread() {
+  DialogBrowserTest::SetUpOnMainThread();
   ASSERT_TRUE(embedded_test_server()->Start());
 
   // Load a form.
@@ -28,14 +46,26 @@
                                embedded_test_server()->GetURL("/form.html"));
   // Submit it.
   ui_test_utils::NavigateToURL(
-      browser(),
-      GURL("javascript:document.getElementById('form').submit()"));
+      browser(), GURL("javascript:document.getElementById('form').submit()"));
+}
 
-  // Try to reload it twice, checking for repost.
+void RepostFormWarningTest::ShowUi(const std::string& name) {
+  TryReload();
+}
+
+content::WebContents* RepostFormWarningTest::TryReload() {
+  // Try to reload it, checking for repost.
   content::WebContents* web_contents =
       browser()->tab_strip_model()->GetActiveWebContents();
   web_contents->GetController().Reload(content::ReloadType::NORMAL, true);
-  web_contents->GetController().Reload(content::ReloadType::NORMAL, true);
+  return web_contents;
+}
+
+// If becomes flaky, disable on Windows and use http://crbug.com/47228
+IN_PROC_BROWSER_TEST_F(RepostFormWarningTest, TestDoubleReload) {
+  // Try to reload it twice, checking for repost.
+  content::WebContents* web_contents = TryReload();
+  TryReload();
 
   // There should only be one dialog open.
   WebContentsModalDialogManager* web_contents_modal_dialog_manager =
@@ -52,20 +82,8 @@
 
 // If becomes flaky, disable on Windows and use http://crbug.com/47228
 IN_PROC_BROWSER_TEST_F(RepostFormWarningTest, TestLoginAfterRepost) {
-  ASSERT_TRUE(embedded_test_server()->Start());
-
-  // Load a form.
-  ui_test_utils::NavigateToURL(browser(),
-                               embedded_test_server()->GetURL("/form.html"));
-  // Submit it.
-  ui_test_utils::NavigateToURL(
-      browser(),
-      GURL("javascript:document.getElementById('form').submit()"));
-
   // Try to reload it, checking for repost.
-  content::WebContents* web_contents =
-      browser()->tab_strip_model()->GetActiveWebContents();
-  web_contents->GetController().Reload(content::ReloadType::NORMAL, true);
+  content::WebContents* web_contents = TryReload();
 
   // Navigate to a page that requires authentication, bringing up another
   // tab-modal sheet.
@@ -90,3 +108,11 @@
       WindowOpenDisposition::CURRENT_TAB, ui::PAGE_TRANSITION_TYPED, false));
   navigation_observer.Wait();
 }
+
+// Disable on Mac OS until dialogs are using toolkit-views for MacViews project.
+// https://crbug.com/683356
+#if !defined(OS_MACOSX)
+IN_PROC_BROWSER_TEST_F(RepostFormWarningTest, InvokeUi_TestRepostWarning) {
+  ShowAndVerifyUi();
+}
+#endif
diff --git a/chrome/browser/resource_coordinator/tab_lifecycle_unit.cc b/chrome/browser/resource_coordinator/tab_lifecycle_unit.cc
index 2551f9e7..b0ece8b 100644
--- a/chrome/browser/resource_coordinator/tab_lifecycle_unit.cc
+++ b/chrome/browser/resource_coordinator/tab_lifecycle_unit.cc
@@ -251,6 +251,28 @@
   return web_contents();
 }
 
+bool TabLifecycleUnitSource::TabLifecycleUnit::IsMediaTab() const {
+  // TODO(fdoray): Consider being notified of audible, capturing and mirrored
+  // state changes via WebContentsDelegate::NavigationStateChanged().
+  // https://crbug.com/775644
+
+  if (recently_audible_time_ == base::TimeTicks::Max() ||
+      (!recently_audible_time_.is_null() &&
+       NowTicks() - recently_audible_time_ < kTabAudioProtectionTime)) {
+    return true;
+  }
+
+  scoped_refptr<MediaStreamCaptureIndicator> media_indicator =
+      MediaCaptureDevicesDispatcher::GetInstance()
+          ->GetMediaStreamCaptureIndicator();
+  if (media_indicator->IsCapturingUserMedia(GetWebContents()) ||
+      media_indicator->IsBeingMirrored(GetWebContents())) {
+    return true;
+  }
+
+  return false;
+}
+
 bool TabLifecycleUnitSource::TabLifecycleUnit::IsAutoDiscardable() const {
   return auto_discardable_;
 }
@@ -272,33 +294,15 @@
   return GetState() == State::DISCARDED;
 }
 
+int TabLifecycleUnitSource::TabLifecycleUnit::GetDiscardCount() const {
+  return discard_count_;
+}
+
 void TabLifecycleUnitSource::TabLifecycleUnit::OnDiscardedStateChange() {
   for (auto& observer : *observers_)
     observer.OnDiscardedStateChange(GetWebContents(), IsDiscarded());
 }
 
-bool TabLifecycleUnitSource::TabLifecycleUnit::IsMediaTab() const {
-  // TODO(fdoray): Consider being notified of audible, capturing and mirrored
-  // state changes via WebContentsDelegate::NavigationStateChanged().
-  // https://crbug.com/775644
-
-  if (recently_audible_time_ == base::TimeTicks::Max() ||
-      (!recently_audible_time_.is_null() &&
-       NowTicks() - recently_audible_time_ < kTabAudioProtectionTime)) {
-    return true;
-  }
-
-  scoped_refptr<MediaStreamCaptureIndicator> media_indicator =
-      MediaCaptureDevicesDispatcher::GetInstance()
-          ->GetMediaStreamCaptureIndicator();
-  if (media_indicator->IsCapturingUserMedia(GetWebContents()) ||
-      media_indicator->IsBeingMirrored(GetWebContents())) {
-    return true;
-  }
-
-  return false;
-}
-
 content::RenderProcessHost*
 TabLifecycleUnitSource::TabLifecycleUnit::GetRenderProcessHost() const {
   return GetWebContents()->GetMainFrame()->GetProcess();
diff --git a/chrome/browser/resource_coordinator/tab_lifecycle_unit.h b/chrome/browser/resource_coordinator/tab_lifecycle_unit.h
index b708962..77aca15 100644
--- a/chrome/browser/resource_coordinator/tab_lifecycle_unit.h
+++ b/chrome/browser/resource_coordinator/tab_lifecycle_unit.h
@@ -79,19 +79,17 @@
 
   // TabLifecycleUnitExternal:
   content::WebContents* GetWebContents() const override;
+  bool IsMediaTab() const override;
   bool IsAutoDiscardable() const override;
   void SetAutoDiscardable(bool auto_discardable) override;
   void DiscardTab() override;
   bool IsDiscarded() const override;
+  int GetDiscardCount() const override;
 
  private:
   // Invoked when the state goes from DISCARDED to non-DISCARDED and vice-versa.
   void OnDiscardedStateChange();
 
-  // Whether the tab is playing audio, has played audio recently, is accessing
-  // the microphone, is accessing the camera or is being mirrored.
-  bool IsMediaTab() const;
-
   // Returns the RenderProcessHost associated with this tab.
   content::RenderProcessHost* GetRenderProcessHost() const;
 
diff --git a/chrome/browser/resource_coordinator/tab_lifecycle_unit_external.h b/chrome/browser/resource_coordinator/tab_lifecycle_unit_external.h
index 7a7144a..ae1bc47 100644
--- a/chrome/browser/resource_coordinator/tab_lifecycle_unit_external.h
+++ b/chrome/browser/resource_coordinator/tab_lifecycle_unit_external.h
@@ -25,6 +25,10 @@
   // Returns the WebContents associated with this tab.
   virtual content::WebContents* GetWebContents() const = 0;
 
+  // Whether the tab is playing audio, has played audio recently, is accessing
+  // the microphone, is accessing the camera or is being mirrored.
+  virtual bool IsMediaTab() const = 0;
+
   // Returns true if this tab can be automatically discarded.
   virtual bool IsAutoDiscardable() const = 0;
 
@@ -36,6 +40,9 @@
 
   // Returns true if the tab is discarded.
   virtual bool IsDiscarded() const = 0;
+
+  // Returns the number of times that the tab was discarded.
+  virtual int GetDiscardCount() const = 0;
 };
 
 }  // namespace resource_coordinator
diff --git a/chrome/browser/resources/chromeos/quick_unlock/md_pin_keyboard.html b/chrome/browser/resources/chromeos/quick_unlock/md_pin_keyboard.html
index 592d5ef3..f2df6c145 100644
--- a/chrome/browser/resources/chromeos/quick_unlock/md_pin_keyboard.html
+++ b/chrome/browser/resources/chromeos/quick_unlock/md_pin_keyboard.html
@@ -113,7 +113,7 @@
         top: 0;
       }
 
-      .digit-button.backspace-button:not([has-content]) {
+      .digit-button.backspace-button[disabled] {
         opacity: 0.34;
       }
 
@@ -261,7 +261,7 @@
           </paper-button>
           <div class="backspace-button-container">
             <paper-icon-button class="digit-button backspace-button"
-                has-content$="[[hasInput_(value)]]"
+                disabled$="[[!hasInput_(value)]]"
                 icon="pin-keyboard:backspace"
                 on-pointerdown="onBackspacePointerDown_"
                 on-pointerout="clearAndReset_"
diff --git a/chrome/browser/resources/chromeos/quick_unlock/pin_keyboard.html b/chrome/browser/resources/chromeos/quick_unlock/pin_keyboard.html
index 464e965..92db182 100644
--- a/chrome/browser/resources/chromeos/quick_unlock/pin_keyboard.html
+++ b/chrome/browser/resources/chromeos/quick_unlock/pin_keyboard.html
@@ -118,7 +118,7 @@
         top: 0;
       }
 
-      .digit-button.backspace-button:not([has-content]) {
+      .digit-button.backspace-button[disabled] {
         color: #000;
         opacity: 0.26;
       }
@@ -249,7 +249,7 @@
           </paper-button>
           <div class="backspace-button-container">
             <paper-icon-button class="digit-button backspace-button"
-                has-content$="[[hasInput_(value)]]"
+                disabled$="[[!hasInput_(value)]]"
                 icon="pin-keyboard:backspace"
                 on-pointerdown="onBackspacePointerDown_"
                 on-pointerout="clearAndReset_"
diff --git a/chrome/browser/resources/chromeos/select_to_speak/select_to_speak.js b/chrome/browser/resources/chromeos/select_to_speak/select_to_speak.js
index d4e8f7cd..22e8d4a 100644
--- a/chrome/browser/resources/chromeos/select_to_speak/select_to_speak.js
+++ b/chrome/browser/resources/chromeos/select_to_speak/select_to_speak.js
@@ -6,6 +6,9 @@
 var EventType = chrome.automation.EventType;
 var RoleType = chrome.automation.RoleType;
 
+// Whether reading selected text is enabled.
+const READ_SELECTION_ENABLED = false;
+
 /**
  * Return the rect that encloses two points.
  * @param {number} x1 The first x coordinate.
@@ -170,7 +173,8 @@
     if (nodeGroupItem.node.wordEnds[i] + nodeGroupItem.startChar < indexAfter) {
       continue;
     }
-    return nodeGroupItem.node.wordEnds[i] + nodeGroupItem.startChar;
+    let result = nodeGroupItem.node.wordEnds[i] + nodeGroupItem.startChar;
+    return text.length > result ? result : text.length;
   }
   // Default.
   return text.length;
@@ -200,6 +204,17 @@
 }
 
 /**
+ * Returns true if a node should be ignored by Select-to-Speak.
+ * @param {AutomationNode} node The node to test
+ * @return {boolean} whether this node should be ignored.
+ */
+function shouldIgnoreNode(node) {
+  return (
+      !node.name || !node.location || node.state.offscreen ||
+      node.state.invisible);
+}
+
+/**
  * Finds all nodes within the subtree rooted at |node| that overlap
  * a given rectangle.
  * @param {AutomationNode} node The starting node.
@@ -219,8 +234,9 @@
   if (found)
     return true;
 
-  if (!node.name || !node.location || node.state.offscreen ||
-      node.state.invisible)
+  // Closure needs node.location check here to allow the next few
+  // lines to compile.
+  if (shouldIgnoreNode(node) || node.location === undefined)
     return false;
 
   if (overlaps(node.location, rect)) {
@@ -237,6 +253,48 @@
   return false;
 }
 
+/**
+ * Class representing a position on the accessibility, made of a
+ * selected node and the offset of that selection.
+ * @typedef {{node: (!AutomationNode),
+ *            offset: (number)}}
+ */
+var Position;
+
+/**
+ * Finds the deep equivalent node where a selection starts given a node
+ * object and selection offset. This is meant to be used in conjunction with
+ * the anchorObject/anchorOffset and focusObject/focusOffset of the
+ * automation API.
+ * @param {AutomationNode} parent The parent node of the selection,
+ * similar to chrome.automation.focusObject.
+ * @param {number} offset The integer offset of the selection. This is
+ * similar to chrome.automation.focusOffset.
+ * @return {!Position} The node matching the selected offset.
+ */
+function getDeepEquivalentForSelection(parent, offset) {
+  if (parent.children.length == 0)
+    return {node: parent, offset: offset};
+  // Create a stack of children nodes to search through.
+  let nodesToCheck = parent.children.slice().reverse();
+  let index = 0;
+  var node;
+  // Delve down into the children recursively to find the
+  // one at this offset.
+  while (nodesToCheck.length > 0) {
+    node = nodesToCheck.pop();
+    if (node.children.length > 0) {
+      nodesToCheck = nodesToCheck.concat(node.children.slice().reverse());
+    } else {
+      index += node.name ? node.name.length : 0;
+      if (index > offset) {
+        return {node: node, offset: offset - index + node.name.length};
+      }
+    }
+  }
+  // We are off the end of the last node.
+  return {node: node, offset: node.name.length};
+}
 
 
 /**
@@ -255,6 +313,9 @@
   /** @private {boolean} */
   this.isSearchKeyDown_ = false;
 
+  /** @private {boolean} */
+  this.isSelectionKeyDown_ = false;
+
   /** @private {!Set<number>} */
   this.keysCurrentlyDown_ = new Set();
 
@@ -339,6 +400,9 @@
 SelectToSpeak.CONTROL_KEY_CODE = 17;
 
 /** @const {number} */
+SelectToSpeak.READ_SELECTION_KEY_CODE = 83;
+
+/** @const {number} */
 SelectToSpeak.NODE_STATE_TEST_INTERVAL_MS = 1000;
 
 SelectToSpeak.prototype = {
@@ -353,7 +417,9 @@
    *    handlers to run.
    */
   onMouseDown_: function(evt) {
-    if (!this.isSearchKeyDown_)
+    // If the user hasn't clicked 'search', or if they are currently
+    // trying to highlight a selection, don't track the mouse.
+    if (!this.isSearchKeyDown_ || this.isSelectionKeyDown_)
       return false;
 
     this.trackingMouse_ = true;
@@ -428,6 +494,7 @@
     // container. In the future we might include other container-like
     // roles here.
     var root = evt.target;
+    // TODO: Use AutomationPredicate.root instead?
     while (root.parent && root.role != RoleType.WINDOW &&
            root.role != RoleType.ROOT_WEB_AREA &&
            root.role != RoleType.DESKTOP && root.role != RoleType.DIALOG &&
@@ -448,6 +515,7 @@
       if (!findAllMatching(root, rect, nodes) && focusedNode)
         findAllMatching(focusedNode.root, rect, nodes);
       this.startSpeechQueue_(nodes);
+      // TODO: Include a metric to say this was started using search+mouse.
       this.recordStartEvent_();
     }.bind(this));
   },
@@ -459,6 +527,12 @@
     if (this.keysPressedTogether_.size == 0 &&
         evt.keyCode == SelectToSpeak.SEARCH_KEY_CODE) {
       this.isSearchKeyDown_ = true;
+    } else if (
+        READ_SELECTION_ENABLED && this.keysCurrentlyDown_.size == 1 &&
+        evt.keyCode == SelectToSpeak.READ_SELECTION_KEY_CODE &&
+        !this.trackingMouse_) {
+      // Only go into selection mode if we aren't already tracking the mouse.
+      this.isSelectionKeyDown_ = true;
     } else if (!this.trackingMouse_) {
       this.isSearchKeyDown_ = false;
     }
@@ -471,7 +545,14 @@
    * @param {!Event} evt
    */
   onKeyUp_: function(evt) {
-    if (evt.keyCode == SelectToSpeak.SEARCH_KEY_CODE) {
+    if (evt.keyCode == SelectToSpeak.READ_SELECTION_KEY_CODE &&
+        this.isSelectionKeyDown_ && this.keysPressedTogether_.size == 2 &&
+        this.keysPressedTogether_.has(evt.keyCode) &&
+        this.keysPressedTogether_.has(SelectToSpeak.SEARCH_KEY_CODE)) {
+      this.isSelectionKeyDown_ = false;
+      chrome.tts.isSpeaking(this.cancelIfSpeaking_.bind(this));
+      chrome.automation.getFocus(this.requestSpeakSelectedText_.bind(this));
+    } else if (evt.keyCode == SelectToSpeak.SEARCH_KEY_CODE) {
       this.isSearchKeyDown_ = false;
 
       // If we were in the middle of tracking the mouse, cancel it.
@@ -500,6 +581,80 @@
   },
 
   /**
+   * Queues up selected text for reading.
+   */
+  requestSpeakSelectedText_: function(focusedNode) {
+    // If nothing is selected, return early.
+    // TODO: Consider playing a tone to let the user know they did the correct
+    // keystroke but nothing was selected.
+    if (!focusedNode || !focusedNode.root || !focusedNode.root.anchorObject ||
+        !focusedNode.root.focusObject)
+      return;
+    let anchorObject = focusedNode.root.anchorObject;
+    let anchorOffset = focusedNode.root.anchorOffset || 0;
+    let focusObject = focusedNode.root.focusObject;
+    let focusOffset = focusedNode.root.focusOffset || 0;
+    if (anchorObject === focusObject && anchorOffset == focusOffset)
+      return;
+    let firstPosition;
+    let lastPosition;
+    let dir = AutomationUtil.getDirection(anchorObject, focusObject);
+    // Highlighting may be forwards or backwards. Make sure we start at the
+    // first node.
+    if (dir == constants.Dir.FORWARD) {
+      firstPosition = getDeepEquivalentForSelection(anchorObject, anchorOffset);
+      lastPosition = getDeepEquivalentForSelection(focusObject, focusOffset);
+    } else {
+      lastPosition = getDeepEquivalentForSelection(anchorObject, anchorOffset);
+      firstPosition = getDeepEquivalentForSelection(focusObject, focusOffset);
+    }
+
+    // Adjust such that non-text types don't have offsets into their names.
+    if (firstPosition.node.role != 'staticText' &&
+        firstPosition.node.role != 'inlineTextBox') {
+      firstPosition.offset = 0;
+    }
+    if (lastPosition.node.role != 'staticText' &&
+        lastPosition.node.role != 'inlineTextBox') {
+      lastPosition.offset = lastPosition.node.name.length;
+    }
+
+    let nodes = [];
+    let selectedNode = firstPosition.node;
+    if (firstPosition.offset < selectedNode.name.length) {
+      // Initialize to the first node in the list.
+      nodes.push(selectedNode);
+    } else {
+      // The selectedNode actually has no content selected. Let the list
+      // initialize itself to the next node in the loop below.
+      // This can happen if you click-and-drag starting after the text in
+      // a first line to highlight text in a second line.
+      firstPosition.offset = 0;
+    }
+    while (selectedNode && selectedNode != lastPosition.node &&
+           AutomationUtil.getDirection(selectedNode, lastPosition.node) ===
+               constants.Dir.FORWARD) {
+      // TODO: Is there a way to optimize the directionality checking of
+      // AutomationUtil.getDirection(selectedNode, finalNode)?
+      // For example, by making a helper and storing partial computation?
+      selectedNode = AutomationUtil.findNextNode(
+          selectedNode, constants.Dir.FORWARD,
+          AutomationPredicate.leafWithText);
+      if (selectedNode) {
+        if (!shouldIgnoreNode(selectedNode))
+          nodes.push(selectedNode);
+      } else {
+        break;
+      }
+    }
+
+    this.startSpeechQueue_(nodes, firstPosition.offset, lastPosition.offset);
+
+    // TODO: Include a metric to say this was started using search+mouse.
+    this.recordStartEvent_();
+  },
+
+  /**
    * Stop speech. If speech was in-progress, the interruption
    * event will be caught and clearFocusRingAndNode_ will be
    * called, stopping visual feedback as well.
@@ -552,8 +707,12 @@
   /**
    * Enqueue speech commands for all of the given nodes.
    * @param {Array<AutomationNode>} nodes The nodes to speak.
+   * @param {number=} opt_startIndex The index into the first node's text
+   * at which to start speaking. If this is not passed, will start at 0.
+   * @param {number=} opt_endIndex The index into the last node's text
+   * at which to end speech. If this is not passed, will stop at the end.
    */
-  startSpeechQueue_: function(nodes) {
+  startSpeechQueue_: function(nodes, opt_startIndex, opt_endIndex) {
     chrome.tts.stop();
     if (this.intervalRef_ !== undefined) {
       clearInterval(this.intervalRef_);
@@ -563,12 +722,31 @@
         SelectToSpeak.NODE_STATE_TEST_INTERVAL_MS);
     for (var i = 0; i < nodes.length; i++) {
       let node = nodes[i];
-      let textToSpeak = '';
       let nodeGroup = buildNodeGroup(nodes, i);
+      if (i == 0) {
+        // We need to start in the middle of a node. Remove all text before
+        // the start index so that it is not spoken.
+        // Backfill with spaces so that index counting functions don't get
+        // confused.
+        // Must check opt_startIndex in its own if statement to make the
+        // Closure compiler happy.
+        if (opt_startIndex !== undefined) {
+          nodeGroup.text = ' '.repeat(opt_startIndex) +
+              nodeGroup.text.substr(opt_startIndex);
+        }
+      }
+      let isFirst = i == 0;
       // Advance i to the end of this group, to skip all nodes it contains.
       i = nodeGroup.endIndex;
-      textToSpeak = nodeGroup.text;
       let isLast = (i == nodes.length - 1);
+      if (isLast && opt_endIndex !== undefined) {
+        // We need to stop in the middle of a node. Remove all text after
+        // the end index so it is not spoken. Backfill with spaces so that
+        // index counting functions don't get confused.
+        nodeGroup.text = nodeGroup.text.substr(
+            0,
+            nodeGroup.text.length - (nodes[i].name.length - opt_endIndex) - 1);
+      }
       if (nodeGroup.nodes.length == 0 && !isLast) {
         continue;
       }
@@ -578,7 +756,7 @@
         pitch: this.speechPitch_,
         'enqueue': true,
         onEvent:
-            (function(nodeGroup, isLast, event) {
+            (function(nodeGroup, isFirst, isLast, event) {
               if (event.type == 'start' && nodeGroup.nodes.length > 0) {
                 if (nodeGroup.endIndex != nodeGroup.startIndex) {
                   // The block parent only matters if the block has more
@@ -587,14 +765,31 @@
                 } else {
                   this.currentBlockParent_ = null;
                 }
+                // The node group index may not be 0 if we are using
+                // opt_startIndex. For example, if the user highlighted
+                // partway through the second inlineTextBox in a
+                // paragraph.
                 this.currentNodeGroupIndex_ = 0;
+                if (opt_startIndex !== undefined && isFirst) {
+                  for (let i = 0; i < nodeGroup.nodes.length; i++) {
+                    if (opt_startIndex < nodeGroup.nodes[i].startChar +
+                            nodeGroup.nodes[i].node.name.length) {
+                      this.currentNodeGroupIndex_ = i;
+                      break;
+                    }
+                  }
+                }
                 this.currentNode_ =
                     nodeGroup.nodes[this.currentNodeGroupIndex_];
                 if (this.wordHighlight_) {
                   // At 'start', find the first word and highlight that.
                   // Clear the previous word in the node.
                   this.currentNodeWord_ = null;
-                  this.updateNodeHighlight_(nodeGroup.text, 0);
+                  // If this is the first nodeGroup, pass the opt_startIndex.
+                  // If this is the last nodeGroup, pass the opt_endIndex.
+                  this.updateNodeHighlight_(
+                      nodeGroup.text, 0, isFirst ? opt_startIndex : undefined,
+                      isLast ? opt_endIndex : undefined);
                 } else {
                   this.testCurrentNode_();
                 }
@@ -619,8 +814,6 @@
                     // Move to the next node.
                     this.currentNodeGroupIndex_ += 1;
                     this.currentNode_ = next;
-                    // TODO: If the next node is a non-word character, like an
-                    // open or closed paren, we should keep moving.
                     this.currentNodeWord_ = null;
                     if (!this.wordHighlight_) {
                       // If we are doing a per-word highlight, we will test the
@@ -631,12 +824,14 @@
                   }
                 }
                 if (this.wordHighlight_) {
-                  this.updateNodeHighlight_(nodeGroup.text, event.charIndex);
+                  this.updateNodeHighlight_(
+                      nodeGroup.text, event.charIndex, undefined,
+                      isLast ? opt_endIndex : undefined);
                 } else {
                   this.currentNodeWord_ = null;
                 }
               }
-            }).bind(this, nodeGroup, isLast)
+            }).bind(this, nodeGroup, isFirst, isLast)
       };
 
       // Pick the voice name from prefs first, or the one that matches
@@ -662,7 +857,7 @@
         options['voiceName'] = this.voiceNameFromLocale_;
       }
 
-      chrome.tts.speak(textToSpeak || '', options);
+      chrome.tts.speak(nodeGroup.text || '', options);
     }
   },
 
@@ -896,17 +1091,26 @@
    * and the character index of an event.
    * @param {string} text The current text
    * @param {number} charIndex The index of a current event in the text.
+   * @param {number=} opt_startIndex The index at which to start the highlight.
+   * This takes precedence over the charIndex.
+   * @param {number=} opt_endIndex The index at which to end the highlight. This
+   * takes precedence over the next word end.
    */
-  updateNodeHighlight_: function(text, charIndex) {
-    if (charIndex >= text.length - 1) {
+  updateNodeHighlight_: function(
+      text, charIndex, opt_startIndex, opt_endIndex) {
+    if (charIndex >= text.length) {
       // No need to do work if we are at the end of the paragraph.
       return;
     }
     // Get the next word based on the event's charIndex.
     let nextWordStart = getNextWordStart(text, charIndex, this.currentNode_);
-    let nextWordEnd = getNextWordEnd(text, nextWordStart, this.currentNode_);
+    let nextWordEnd = getNextWordEnd(
+        text, opt_startIndex === undefined ? nextWordStart : opt_startIndex,
+        this.currentNode_);
     // Map the next word into the node's index from the text.
-    let nodeStart = nextWordStart - this.currentNode_.startChar;
+    let nodeStart = opt_startIndex === undefined ?
+        nextWordStart - this.currentNode_.startChar :
+        opt_startIndex - this.currentNode_.startChar;
     let nodeEnd = Math.min(
         nextWordEnd - this.currentNode_.startChar,
         this.currentNode_.node.name.length);
diff --git a/chrome/browser/resources/chromeos/select_to_speak/select_to_speak_unittest.gtestjs b/chrome/browser/resources/chromeos/select_to_speak/select_to_speak_unittest.gtestjs
index 9839006..eb733941 100644
--- a/chrome/browser/resources/chromeos/select_to_speak/select_to_speak_unittest.gtestjs
+++ b/chrome/browser/resources/chromeos/select_to_speak/select_to_speak_unittest.gtestjs
@@ -237,4 +237,68 @@
   assertTrue(findAllMatching(rootNode, rect, result));
   assertEquals(1, result.length);
   assertEquals(container2, result[0]);
+});
+
+TEST_F('SelectToSpeakUnitTest', 'getDeepEquivalentForSelectionNoChildren',
+    function() {
+  let node = {name: 'Hello, world', children: []};
+  let result = getDeepEquivalentForSelection(node, 0);
+  assertEquals(node, result.node);
+  assertEquals(0, result.offset);
+
+  result = getDeepEquivalentForSelection(node, 6);
+  assertEquals(node, result.node);
+  assertEquals(6, result.offset);
+});
+
+TEST_F('SelectToSpeakUnitTest', 'getDeepEquivalentForSelectionSimpleChildren',
+    function() {
+  let child1 = {name: 'Hello,', children: []};
+  let child2 = {name: ' world', children: []};
+  let root = {name: 'Hello, world', children: [child1, child2]};
+  let result = getDeepEquivalentForSelection(root, 0);
+  assertEquals(child1, result.node);
+  assertEquals(0, result.offset);
+
+  result = getDeepEquivalentForSelection(root, 5);
+  assertEquals(child1, result.node);
+  assertEquals(5, result.offset);
+
+  result = getDeepEquivalentForSelection(root, 6);
+  assertEquals(child2, result.node);
+  assertEquals(0, result.offset);
+
+  result = getDeepEquivalentForSelection(root, 9);
+  assertEquals(child2, result.node);
+  assertEquals(3, result.offset);
+});
+
+TEST_F('SelectToSpeakUnitTest', 'getDeepEquivalentForSelectionComplexChildren',
+    function() {
+  let child1 = {name: 'Hello', children: []};
+  let child2 = {name: undefined, children: []};  // Empty name
+  let child3 = {name: ',', children: []};
+  let child4 = {name: 'Hello,', children: [child1, child2, child3]};
+
+  let child5 = {name: ' ', children: []};
+  let child6 = {name: 'world', children: []};
+  let child7 = {name: ' world', children: [child5, child6]};
+
+  let root = {name: 'Hello, world', children: [child4, child7]};
+
+  let result = getDeepEquivalentForSelection(root, 0);
+  assertEquals(child1, result.node);
+  assertEquals(0, result.offset);
+
+  result = getDeepEquivalentForSelection(root, 5);
+  assertEquals(child3, result.node);
+  assertEquals(0, result.offset);
+
+  result = getDeepEquivalentForSelection(root, 6);
+  assertEquals(child5, result.node);
+  assertEquals(0, result.offset);
+
+  result = getDeepEquivalentForSelection(root, 9);
+  assertEquals(child6, result.node);
+  assertEquals(2, result.offset);
 });
\ No newline at end of file
diff --git a/chrome/browser/resources/cryptotoken/manifest.json b/chrome/browser/resources/cryptotoken/manifest.json
index 9dd756d..fecac54 100644
--- a/chrome/browser/resources/cryptotoken/manifest.json
+++ b/chrome/browser/resources/cryptotoken/manifest.json
@@ -1,7 +1,7 @@
 {
   "name": "CryptoTokenExtension",
   "description": "CryptoToken Component Extension",
-  "version": "0.9.71",
+  "version": "0.9.73",
   "key": "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAq7zRobvA+AVlvNqkHSSVhh1sEWsHSqz4oR/XptkDe/Cz3+gW9ZGumZ20NCHjaac8j1iiesdigp8B1LJsd/2WWv2Dbnto4f8GrQ5MVphKyQ9WJHwejEHN2K4vzrTcwaXqv5BSTXwxlxS/mXCmXskTfryKTLuYrcHEWK8fCHb+0gvr8b/kvsi75A1aMmb6nUnFJvETmCkOCPNX5CHTdy634Ts/x0fLhRuPlahk63rdf7agxQv5viVjQFk+tbgv6aa9kdSd11Js/RZ9yZjrFgHOBWgP4jTBqud4+HUglrzu8qynFipyNRLCZsaxhm+NItTyNgesxLdxZcwOz56KD1Q4IQIDAQAB",
   "manifest_version": 2,
   "permissions": [
diff --git a/chrome/browser/resources/cryptotoken/singlesigner.js b/chrome/browser/resources/cryptotoken/singlesigner.js
index e39e4008..3982b3f 100644
--- a/chrome/browser/resources/cryptotoken/singlesigner.js
+++ b/chrome/browser/resources/cryptotoken/singlesigner.js
@@ -354,10 +354,12 @@
  *     for this gnubby.
  */
 SingleGnubbySigner.signErrorIndicatesInvalidKeyHandle = function(code) {
-  return (
-      code == DeviceStatusCodes.WRONG_DATA_STATUS ||
-      code == DeviceStatusCodes.WRONG_LENGTH_STATUS ||
-      code == DeviceStatusCodes.INVALID_DATA_STATUS);
+  // Negative errors are synthetic, device-level errors, rather than APDU-layer
+  // things. Wait for touch is the only error code defined to be a transient
+  // situation. Unfortunately the spec is ambiguous, and some devices behave
+  // oddly, so we treat all APDU-layer errors as idempotent rather than
+  // transient.
+  return code > 0 && code != DeviceStatusCodes.WAIT_TOUCH_STATUS;
 };
 
 /**
@@ -391,10 +393,6 @@
 
   var self = this;
   switch (code) {
-    case DeviceStatusCodes.GONE_STATUS:
-      this.goToError_(code);
-      break;
-
     case DeviceStatusCodes.TIMEOUT_STATUS:
       this.gnubby_.sync(this.synced_.bind(this));
       break;
@@ -404,13 +402,6 @@
       break;
 
     case DeviceStatusCodes.OK_STATUS:
-      // Lower bound on the minimum length, signature length can vary.
-      var MIN_SIGNATURE_LENGTH = 7;
-      if (!opt_info || opt_info.byteLength < MIN_SIGNATURE_LENGTH) {
-        console.error(UTIL_fmt(
-            'Got short response to sign request (' +
-            (opt_info ? opt_info.byteLength : 0) + ' bytes), WTF?'));
-      }
       if (this.forEnroll_) {
         this.goToError_(code);
       } else {
@@ -424,9 +415,16 @@
       }, SingleGnubbySigner.SIGN_DELAY_MILLIS);
       break;
 
-    case DeviceStatusCodes.WRONG_DATA_STATUS:
-    case DeviceStatusCodes.WRONG_LENGTH_STATUS:
-    case DeviceStatusCodes.INVALID_DATA_STATUS:
+    default:
+      if (code < 0) {
+        // Negative errors are synthetic, device-level errors, rather than
+        // APDU-layer things. Other than the ones explicitly handled above,
+        // these are indicative of unhappy devices, so return them immediately
+        // to the caller.
+        this.goToError_(code);
+        return;
+      }
+
       if (this.challengeIndex_ < this.challenges_.length - 1) {
         this.doSign_(++this.challengeIndex_);
       } else if (this.forEnroll_) {
@@ -434,16 +432,6 @@
       } else {
         this.goToError_(code);
       }
-      break;
-
-    default:
-      if (this.forEnroll_) {
-        this.goToError_(code, true);
-      } else if (this.challengeIndex_ < this.challenges_.length - 1) {
-        this.doSign_(++this.challengeIndex_);
-      } else {
-        this.goToError_(code, true);
-      }
   }
 };
 
diff --git a/chrome/browser/resources/discards/discards.html b/chrome/browser/resources/discards/discards.html
index aaa29306..4d5828f 100644
--- a/chrome/browser/resources/discards/discards.html
+++ b/chrome/browser/resources/discards/discards.html
@@ -34,10 +34,7 @@
           <th data-sort-key="utilityRank" class="sort-column">Utility Rank</th>
           <th data-sort-key="title">Tab Title</th>
           <th data-sort-key="tabUrl">Tab URL</th>
-          <th data-sort-key="isApp">App</th>
-          <th data-sort-key="isInternal">Internal</th>
           <th data-sort-key="isMedia">Media</th>
-          <th data-sort-key="isPinned">Pinned</th>
           <th data-sort-key="isDiscarded">Discarded</th>
           <th data-sort-key="discardCount">Discard Count</th>
           <th data-sort-key="isAutoDiscardable">Auto Discardable</th>
@@ -59,10 +56,7 @@
           </div>
         </td>
         <td class="tab-url-cell"></td>
-        <td class="is-app-cell boolean-cell"></td>
-        <td class="is-internal-cell boolean-cell"></td>
         <td class="is-media-cell boolean-cell"></td>
-        <td class="is-pinned-cell boolean-cell"></td>
         <td class="is-discarded-cell boolean-cell"></td>
         <td class="discard-count-cell"></td>
         <td class="is-auto-discardable-cell boolean-cell">
diff --git a/chrome/browser/resources/discards/discards.js b/chrome/browser/resources/discards/discards.js
index 210abe9..b09684e 100644
--- a/chrome/browser/resources/discards/discards.js
+++ b/chrome/browser/resources/discards/discards.js
@@ -64,10 +64,7 @@
     }
 
     // Compares boolean fields.
-    if ([
-          'isApp', 'isInternal', 'isMedia', 'isPinned', 'isDiscarded',
-          'isAutoDiscardable'
-        ].includes(sortKey)) {
+    if (['isMedia', 'isDiscarded', 'isAutoDiscardable'].includes(sortKey)) {
       if (val1 == val2)
         return 0;
       return val1 ? 1 : -1;
@@ -247,13 +244,8 @@
         info.faviconUrl ? info.faviconUrl : 'chrome://favicon';
     row.querySelector('.title-div').textContent = info.title;
     row.querySelector('.tab-url-cell').textContent = info.tabUrl;
-    row.querySelector('.is-app-cell').textContent = boolToString(info.isApp);
-    row.querySelector('.is-internal-cell').textContent =
-        boolToString(info.isInternal);
     row.querySelector('.is-media-cell').textContent =
         boolToString(info.isMedia);
-    row.querySelector('.is-pinned-cell').textContent =
-        boolToString(info.isPinned);
     row.querySelector('.is-discarded-cell').textContent =
         boolToString(info.isDiscarded);
     row.querySelector('.discard-count-cell').textContent =
diff --git a/chrome/browser/resources/md_bookmarks/toolbar.html b/chrome/browser/resources/md_bookmarks/toolbar.html
index 55fff095..94a2776 100644
--- a/chrome/browser/resources/md_bookmarks/toolbar.html
+++ b/chrome/browser/resources/md_bookmarks/toolbar.html
@@ -7,7 +7,6 @@
 <link rel="import" href="chrome://resources/polymer/v1_0/paper-icon-button/paper-icon-button-light.html">
 <link rel="import" href="chrome://bookmarks/edit_dialog.html">
 <link rel="import" href="chrome://bookmarks/shared_style.html">
-<link rel="stylesheet" href="chrome://resources/css/md_colors.css">
 
 <dom-module id="bookmarks-toolbar">
   <template>
diff --git a/chrome/browser/resources/md_extensions/extensions.html b/chrome/browser/resources/md_extensions/extensions.html
index 97ddab4..5b728b9 100644
--- a/chrome/browser/resources/md_extensions/extensions.html
+++ b/chrome/browser/resources/md_extensions/extensions.html
@@ -36,6 +36,7 @@
 </head>
 <body>
   <extensions-manager></extensions-manager>
+  <link rel="stylesheet" href="chrome://resources/css/md_colors.css">
   <link rel="stylesheet" href="chrome://resources/css/text_defaults_md.css">
   <link rel="import" href="manager.html">
 </body>
diff --git a/chrome/browser/resources/md_extensions/manager.html b/chrome/browser/resources/md_extensions/manager.html
index becb5669..a556faa 100644
--- a/chrome/browser/resources/md_extensions/manager.html
+++ b/chrome/browser/resources/md_extensions/manager.html
@@ -21,7 +21,6 @@
 <link rel="import" href="sidebar.html">
 <link rel="import" href="toolbar.html">
 <link rel="import" href="view_manager.html">
-<link rel="stylesheet" href="chrome://resources/css/md_colors.css">
 
 <if expr="chromeos">
 <link rel="import" href="kiosk_browser_proxy.html">
@@ -52,7 +51,7 @@
       }
 
       extensions-toolbar {
-        background: var(--md-toolbar-color);
+        background-color: var(--md-toolbar-color);
       }
     </style>
     <extensions-drop-overlay></extensions-drop-overlay>
diff --git a/chrome/browser/resources/md_extensions/toolbar.html b/chrome/browser/resources/md_extensions/toolbar.html
index a72c956..371c0db 100644
--- a/chrome/browser/resources/md_extensions/toolbar.html
+++ b/chrome/browser/resources/md_extensions/toolbar.html
@@ -10,7 +10,6 @@
 <link rel="import" href="chrome://resources/polymer/v1_0/iron-a11y-announcer/iron-a11y-announcer.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/paper-styles/color.html">
 <link rel="import" href="icons.html">
-<link rel="stylesheet" href="chrome://resources/css/md_colors.css">
 
 <dom-module id="extensions-toolbar">
   <template>
diff --git a/chrome/browser/resources/md_history/.eslintrc.js b/chrome/browser/resources/md_history/.eslintrc.js
new file mode 100644
index 0000000..25e21f9
--- /dev/null
+++ b/chrome/browser/resources/md_history/.eslintrc.js
@@ -0,0 +1,13 @@
+// Copyright 2018 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.exports = {
+  'env': {
+    'browser': true,
+    'es6': true,
+  },
+  'rules': {
+    'no-var': 'error',
+  },
+};
diff --git a/chrome/browser/resources/md_history/app.html b/chrome/browser/resources/md_history/app.html
index 1d5e648..5afaa5d 100644
--- a/chrome/browser/resources/md_history/app.html
+++ b/chrome/browser/resources/md_history/app.html
@@ -10,7 +10,6 @@
 <link rel="import" href="chrome://history/router.html">
 <link rel="import" href="chrome://history/shared_style.html">
 <link rel="import" href="chrome://history/side_bar.html">
-<link rel="stylesheet" href="chrome://resources/css/md_colors.css">
 
 <!-- Lazy loaded: history-synced-device-manager, cr-drawer. -->
 
diff --git a/chrome/browser/resources/md_history/app.js b/chrome/browser/resources/md_history/app.js
index 0c25e14..c187aca 100644
--- a/chrome/browser/resources/md_history/app.js
+++ b/chrome/browser/resources/md_history/app.js
@@ -3,7 +3,7 @@
 // found in the LICENSE file.
 
 cr.define('md_history', function() {
-  var lazyLoadPromise = null;
+  let lazyLoadPromise = null;
   function ensureLazyLoaded() {
     if (!lazyLoadPromise) {
       lazyLoadPromise = new Promise(function(resolve, reject) {
@@ -120,7 +120,7 @@
 
     // Focus the search field on load. Done here to ensure the history page
     // is rendered before we try to take focus.
-    var searchField =
+    const searchField =
         /** @type {HistoryToolbarElement} */ (this.$.toolbar).searchField;
     if (!searchField.narrow) {
       searchField.getSearchInput().focus();
@@ -152,7 +152,7 @@
 
   /** @private */
   onCrToolbarMenuTap_: function() {
-    var drawer = /** @type {!CrDrawerElement} */ (this.$.drawer.get());
+    const drawer = /** @type {!CrDrawerElement} */ (this.$.drawer.get());
     drawer.toggle();
     this.showMenuPromo_ = false;
   },
@@ -163,7 +163,7 @@
    * @param {{detail: {countAddition: number}}} e
    */
   checkboxSelected: function(e) {
-    var toolbar = /** @type {HistoryToolbarElement} */ (this.$.toolbar);
+    const toolbar = /** @type {HistoryToolbarElement} */ (this.$.toolbar);
     toolbar.count = /** @type {HistoryListElement} */ (this.$.history)
                         .getSelectedItemCount();
   },
@@ -174,8 +174,8 @@
    * @private
    */
   unselectAll: function() {
-    var list = /** @type {HistoryListElement} */ (this.$.history);
-    var toolbar = /** @type {HistoryToolbarElement} */ (this.$.toolbar);
+    const list = /** @type {HistoryListElement} */ (this.$.history);
+    const toolbar = /** @type {HistoryToolbarElement} */ (this.$.toolbar);
     list.unselectAllItems();
     toolbar.count = 0;
   },
@@ -193,7 +193,7 @@
     this.set('queryState_.querying', false);
     this.set('queryResult_.info', info);
     this.set('queryResult_.results', results);
-    var list = /** @type {HistoryListElement} */ (this.$['history']);
+    const list = /** @type {HistoryListElement} */ (this.$['history']);
     list.historyResult(info, results);
   },
 
@@ -294,7 +294,8 @@
 
   /** @private */
   hasDrawerChanged_: function() {
-    var drawer = /** @type {?CrDrawerElement} */ (this.$.drawer.getIfExists());
+    const drawer =
+        /** @type {?CrDrawerElement} */ (this.$.drawer.getIfExists());
     if (!this.hasDrawer_ && drawer && drawer.open)
       drawer.closeDrawer();
   },
@@ -315,14 +316,14 @@
 
   /** @private */
   closeDrawer_: function() {
-    var drawer = this.$.drawer.get();
+    const drawer = this.$.drawer.get();
     if (drawer && drawer.open)
       drawer.closeDrawer();
   },
 
   /** @private */
   recordHistoryPageView_: function() {
-    var histogramValue = HistoryPageViewHistogram.END;
+    let histogramValue = HistoryPageViewHistogram.END;
     switch (this.selectedPage_) {
       case 'syncedTabs':
         histogramValue = this.isUserSignedIn_ ?
diff --git a/chrome/browser/resources/md_history/browser_service.js b/chrome/browser/resources/md_history/browser_service.js
index 2757ff2..c26d343 100644
--- a/chrome/browser/resources/md_history/browser_service.js
+++ b/chrome/browser/resources/md_history/browser_service.js
@@ -29,7 +29,7 @@
         });
       }
 
-      var removalList = items.map(function(item) {
+      const removalList = items.map(function(item) {
         return {
           url: item.url,
           timestamps: item.allTimestamps,
diff --git a/chrome/browser/resources/md_history/constants.js b/chrome/browser/resources/md_history/constants.js
index 550f0ce..768c52c4 100644
--- a/chrome/browser/resources/md_history/constants.js
+++ b/chrome/browser/resources/md_history/constants.js
@@ -3,27 +3,27 @@
 // found in the LICENSE file.
 
 // Globals:
-/** @const */ var RESULTS_PER_PAGE = 150;
+/** @type {number} */ const RESULTS_PER_PAGE = 150;
 
 /**
  * Amount of time between pageviews that we consider a 'break' in browsing,
  * measured in milliseconds.
- * @const
+ * @type {number}
  */
-var BROWSING_GAP_TIME = 15 * 60 * 1000;
+const BROWSING_GAP_TIME = 15 * 60 * 1000;
 
 /**
  * The largest bucket value for UMA histogram, based on entry ID. All entries
  * with IDs greater than this will be included in this bucket.
- * @const
+ * @type {number}
  */
-var UMA_MAX_BUCKET_VALUE = 1000;
+const UMA_MAX_BUCKET_VALUE = 1000;
 
 /**
  * The largest bucket value for a UMA histogram that is a subset of above.
- * @const
+ * @type {number}
  */
-var UMA_MAX_SUBSET_BUCKET_VALUE = 100;
+const UMA_MAX_SUBSET_BUCKET_VALUE = 100;
 
 /**
  * Histogram buckets for UMA tracking of which view is being shown to the user.
@@ -31,7 +31,7 @@
  * This enum is append-only.
  * @enum {number}
  */
-var HistoryPageViewHistogram = {
+const HistoryPageViewHistogram = {
   HISTORY: 0,
   DEPRECATED_GROUPED_WEEK: 1,
   DEPRECATED_GROUPED_MONTH: 2,
@@ -40,16 +40,14 @@
   END: 5,  // Should always be last.
 };
 
-/**
- * @const
- */
-var SYNCED_TABS_HISTOGRAM_NAME = 'HistoryPage.OtherDevicesMenu';
+/** @type {string} */
+const SYNCED_TABS_HISTOGRAM_NAME = 'HistoryPage.OtherDevicesMenu';
 
 /**
  * Histogram buckets for UMA tracking of synced tabs.
- * @const
+ * @enum {number}
  */
-var SyncedTabsHistogram = {
+const SyncedTabsHistogram = {
   INITIALIZED: 0,
   SHOW_MENU_DEPRECATED: 1,
   LINK_CLICKED: 2,
diff --git a/chrome/browser/resources/md_history/externs.js b/chrome/browser/resources/md_history/externs.js
index 8f7d7c2..5fd8abbb 100644
--- a/chrome/browser/resources/md_history/externs.js
+++ b/chrome/browser/resources/md_history/externs.js
@@ -27,7 +27,7 @@
  *            title: string,
  *            url: string}}
  */
-var HistoryEntry;
+let HistoryEntry;
 
 /**
  * The type of the history results info object. The definition is based on
@@ -36,7 +36,7 @@
  * @typedef {{finished: boolean,
  *            term: string}}
  */
-var HistoryQuery;
+let HistoryQuery;
 
 /**
  * The type of the foreign session tab object. This definition is based on
@@ -48,7 +48,7 @@
  *            type: string,
  *            url: string}}
  */
-var ForeignSessionTab;
+let ForeignSessionTab;
 
 /**
  * The type of the foreign session tab object. This definition is based on
@@ -58,7 +58,7 @@
  *            sessionId: number,
  *            tabs: Array<ForeignSessionTab>}}
  */
-var ForeignSessionWindow;
+let ForeignSessionWindow;
 
 /**
  * The type of the foreign session info object. This definition is based on
@@ -71,27 +71,27 @@
  *            timestamp: number,
  *            windows: Array<ForeignSessionWindow>}}
  */
-var ForeignSession;
+let ForeignSession;
 
 /**
  * @typedef {{incremental: boolean,
  *            querying: boolean,
  *            searchTerm: string}}
  */
-var QueryState;
+let QueryState;
 
 /**
  * @typedef {{info: ?HistoryQuery,
  *            results: ?Array<!HistoryEntry>,
  *            sessionList: ?Array<!ForeignSession>}}
  */
-var QueryResult;
+let QueryResult;
 
 /**
  * @constructor
  * @extends {MouseEvent}
  */
-var DomRepeatClickEvent = function() {};
+const DomRepeatClickEvent = function() {};
 
 /** @type {Object} */
 DomRepeatClickEvent.prototype.model;
diff --git a/chrome/browser/resources/md_history/history.js b/chrome/browser/resources/md_history/history.js
index c9571285..961ec8f 100644
--- a/chrome/browser/resources/md_history/history.js
+++ b/chrome/browser/resources/md_history/history.js
@@ -8,9 +8,13 @@
 chrome.send('getForeignSessions');
 
 /** @type {Promise} */
-var upgradePromise = null;
-/** @type {boolean} */
-var resultsRendered = false;
+let upgradePromise = null;
+
+/**
+ * Adding this on |window| since it is accessed by tests.
+ * @type {boolean}
+ */
+window.resultsRendered = false;
 
 /**
  * @return {!Promise} Resolves once the history-app has been fully upgraded.
@@ -38,12 +42,12 @@
  */
 function historyResult(info, results) {
   waitForAppUpgrade().then(function() {
-    var app = /** @type {HistoryAppElement} */ ($('history-app'));
+    const app = /** @type {HistoryAppElement} */ ($('history-app'));
     app.historyResult(info, results);
     document.body.classList.remove('loading');
 
-    if (!resultsRendered) {
-      resultsRendered = true;
+    if (!window.resultsRendered) {
+      window.resultsRendered = true;
       app.onFirstRender();
     }
   });
@@ -57,7 +61,7 @@
  */
 function showNotification(includeOtherFormsOfBrowsingHistory) {
   waitForAppUpgrade().then(function() {
-    var app = /** @type {HistoryAppElement} */ ($('history-app'));
+    const app = /** @type {HistoryAppElement} */ ($('history-app'));
     app.showSidebarFooter = includeOtherFormsOfBrowsingHistory;
   });
 }
diff --git a/chrome/browser/resources/md_history/history_item.js b/chrome/browser/resources/md_history/history_item.js
index 4aea6ae..fa0dd0ec 100644
--- a/chrome/browser/resources/md_history/history_item.js
+++ b/chrome/browser/resources/md_history/history_item.js
@@ -19,7 +19,7 @@
 
   /** @override */
   getCustomEquivalent: function(sampleElement) {
-    var equivalent;
+    let equivalent;
 
     if (this.getTypeForElement(sampleElement) == 'star')
       equivalent = this.getFirstFocusable('title');
@@ -78,7 +78,7 @@
     },
   };
 
-  var HistoryItem = Polymer({
+  const HistoryItem = Polymer({
     is: 'history-item',
 
     properties: {
@@ -196,8 +196,8 @@
      * @private
      */
     onItemClick_: function(e) {
-      for (var i = 0; i < e.path.length; i++) {
-        var elem = e.path[i];
+      for (let i = 0; i < e.path.length; i++) {
+        const elem = e.path[i];
         if (elem.id != 'checkbox' &&
             (elem.nodeName == 'A' || elem.nodeName == 'BUTTON')) {
           return;
@@ -233,7 +233,7 @@
      * @return {string}
      */
     getEntrySummary_: function() {
-      var item = this.item;
+      const item = this.item;
       return loadTimeData.getStringF(
           'entrySummary', item.dateTimeOfDay,
           item.starred ? loadTimeData.getString('bookmarked') : '', item.title,
@@ -260,7 +260,7 @@
       if (this.$$('#bookmark-star') == this.root.activeElement)
         this.$['menu-button'].focus();
 
-      var browserService = md_history.BrowserService.getInstance();
+      const browserService = md_history.BrowserService.getInstance();
       browserService.removeBookmark(this.item.url);
       browserService.recordAction('BookmarkStarClicked');
 
@@ -287,7 +287,7 @@
      * on-click rather than on-tap, as on-click triggers from middle clicks.
      */
     onLinkClick_: function() {
-      var browserService = md_history.BrowserService.getInstance();
+      const browserService = md_history.BrowserService.getInstance();
       browserService.recordAction('EntryLinkClick');
 
       if (this.searchTerm)
@@ -336,7 +336,7 @@
 
     /** @private */
     addTimeTitle_: function() {
-      var el = this.$['time-accessed'];
+      const el = this.$['time-accessed'];
       el.setAttribute('title', new Date(this.item.time).toString());
       this.unlisten(el, 'mouseover', 'addTimeTitle_');
     },
@@ -348,7 +348,7 @@
    * @return {string} The title for a page of search results.
    */
   HistoryItem.searchResultsTitle = function(numberOfResults, searchTerm) {
-    var resultId = numberOfResults == 1 ? 'searchResult' : 'searchResults';
+    const resultId = numberOfResults == 1 ? 'searchResult' : 'searchResults';
     return loadTimeData.getStringF(
         'foundSearchResults', numberOfResults, loadTimeData.getString(resultId),
         searchTerm);
diff --git a/chrome/browser/resources/md_history/history_list.js b/chrome/browser/resources/md_history/history_list.js
index 748e50e..8b94ed48 100644
--- a/chrome/browser/resources/md_history/history_list.js
+++ b/chrome/browser/resources/md_history/history_list.js
@@ -103,7 +103,7 @@
    * result loading should be disabled.
    */
   addNewResults: function(historyResults, incremental, finished) {
-    var results = historyResults.slice();
+    const results = historyResults.slice();
     /** @type {IronScrollThresholdElement} */ (this.$['scroll-threshold'])
         .clearTriggers();
 
@@ -162,7 +162,7 @@
     if (!this.canDeleteHistory_)
       return;
 
-    var browserService = md_history.BrowserService.getInstance();
+    const browserService = md_history.BrowserService.getInstance();
     browserService.recordAction('RemoveSelected');
     if (this.queryState.searchTerm != '')
       browserService.recordAction('SearchResultRemove');
@@ -197,8 +197,8 @@
    * @private
    */
   deleteSelected_: function() {
-    var toBeRemoved = Array.from(this.selectedItems.values())
-                          .map((index) => this.get(`historyData_.${index}`));
+    const toBeRemoved = Array.from(this.selectedItems.values())
+                            .map((index) => this.get(`historyData_.${index}`));
 
     md_history.BrowserService.getInstance()
         .deleteItems(toBeRemoved)
@@ -216,13 +216,13 @@
    * @private
    */
   removeItemsByIndex_: function(indices) {
-    var splices = [];
+    const splices = [];
     indices.sort(function(a, b) {
       // Sort in reverse numerical order.
       return b - a;
     });
     indices.forEach((index) => {
-      var item = this.historyData_.splice(index, 1);
+      const item = this.historyData_.splice(index, 1);
       splices.push({
         index: index,
         removed: [item],
@@ -239,7 +239,7 @@
    * @private
    */
   closeMenu_: function() {
-    var menu = this.$.sharedMenu.getIfExists();
+    const menu = this.$.sharedMenu.getIfExists();
     if (menu && menu.open) {
       this.actionMenuModel_ = null;
       menu.close();
@@ -255,7 +255,7 @@
         'ConfirmRemoveSelected');
 
     this.deleteSelected_();
-    var dialog = assert(this.$.dialog.getIfExists());
+    const dialog = assert(this.$.dialog.getIfExists());
     dialog.close();
   },
 
@@ -264,7 +264,7 @@
     md_history.BrowserService.getInstance().recordAction(
         'CancelRemoveSelected');
 
-    var dialog = assert(this.$.dialog.getIfExists());
+    const dialog = assert(this.$.dialog.getIfExists());
     dialog.close();
   },
 
@@ -274,12 +274,12 @@
    * @private
    */
   onRemoveBookmarkStars_: function(e) {
-    var url = e.detail;
+    const url = e.detail;
 
     if (this.historyData_ === undefined)
       return;
 
-    for (var i = 0; i < this.historyData_.length; i++) {
+    for (let i = 0; i < this.historyData_.length; i++) {
       if (this.historyData_[i].url == url)
         this.set(`historyData_.${i}.starred`, false);
     }
@@ -307,14 +307,14 @@
    * @private
    */
   onOpenMenu_: function(e) {
-    var index = e.detail.index;
-    var list = /** @type {IronListElement} */ (this.$['infinite-list']);
+    const index = e.detail.index;
+    const list = /** @type {IronListElement} */ (this.$['infinite-list']);
     if (index < list.firstVisibleIndex || index > list.lastVisibleIndex)
       list.scrollToIndex(index);
 
-    var target = e.detail.target;
+    const target = e.detail.target;
     this.actionMenuModel_ = e.detail;
-    var menu = /** @type {CrActionMenuElement} */ (this.$.sharedMenu.get());
+    const menu = /** @type {CrActionMenuElement} */ (this.$.sharedMenu.get());
     menu.showAt(target);
   },
 
@@ -323,7 +323,7 @@
     md_history.BrowserService.getInstance().recordAction(
         'EntryMenuShowMoreFromSite');
 
-    var menu = assert(this.$.sharedMenu.getIfExists());
+    const menu = assert(this.$.sharedMenu.getIfExists());
     this.fire('change-query', {search: this.actionMenuModel_.item.domain});
     this.actionMenuModel_ = null;
     this.closeMenu_();
@@ -331,10 +331,10 @@
 
   /** @private */
   onRemoveFromHistoryTap_: function() {
-    var browserService = md_history.BrowserService.getInstance();
+    const browserService = md_history.BrowserService.getInstance();
     browserService.recordAction('EntryMenuRemoveFromHistory');
-    var menu = assert(this.$.sharedMenu.getIfExists());
-    var itemData = this.actionMenuModel_;
+    const menu = assert(this.$.sharedMenu.getIfExists());
+    const itemData = this.actionMenuModel_;
     browserService.deleteItems([itemData.item]).then((items) => {
       // This unselect-all resets the toolbar when deleting a selected item
       // and clears selection state which can be invalid if items move
@@ -344,11 +344,11 @@
       this.fire('unselect-all');
       this.removeItemsByIndex_([itemData.index]);
 
-      var index = itemData.index;
+      const index = itemData.index;
       if (index == undefined)
         return;
 
-      var browserService = md_history.BrowserService.getInstance();
+      const browserService = md_history.BrowserService.getInstance();
       browserService.recordHistogram(
           'HistoryPage.RemoveEntryPosition',
           Math.min(index, UMA_MAX_BUCKET_VALUE), UMA_MAX_BUCKET_VALUE);
@@ -366,13 +366,13 @@
    * @private
    */
   onItemSelected_: function(e) {
-    var index = e.detail.index;
-    var indices = [];
+    const index = e.detail.index;
+    const indices = [];
 
     // Handle shift selection. Change the selection state of all items between
     // |path| and |lastSelected| to the selection state of |item|.
     if (e.detail.shiftKey && this.lastSelectedIndex != undefined) {
-      for (var i = Math.min(index, this.lastSelectedIndex);
+      for (let i = Math.min(index, this.lastSelectedIndex);
            i <= Math.max(index, this.lastSelectedIndex); i++) {
         indices.push(i);
       }
@@ -381,7 +381,7 @@
     if (indices.length == 0)
       indices.push(index);
 
-    var selected = !this.selectedItems.has(index);
+    const selected = !this.selectedItems.has(index);
 
     indices.forEach((index) => {
       this.changeSelection_(index, selected);
@@ -406,8 +406,8 @@
     if (index >= length - 1 || length == 0)
       return false;
 
-    var currentItem = this.historyData_[index];
-    var nextItem = this.historyData_[index + 1];
+    const currentItem = this.historyData_[index];
+    const nextItem = this.historyData_[index + 1];
 
     if (this.searchedTerm)
       return currentItem.dateShort != nextItem.dateShort;
@@ -463,7 +463,7 @@
    * @private
    */
   noResultsMessage_: function(searchedTerm) {
-    var messageId = searchedTerm !== '' ? 'noSearchResults' : 'noResults';
+    const messageId = searchedTerm !== '' ? 'noSearchResults' : 'noResults';
     return loadTimeData.getString(messageId);
   },
 
@@ -486,9 +486,9 @@
     if (results.length == 0)
       return;
 
-    var currentDate = results[0].dateRelativeDay;
+    let currentDate = results[0].dateRelativeDay;
 
-    for (var i = 0; i < results.length; i++) {
+    for (let i = 0; i < results.length; i++) {
       // Sets the default values for these fields to prevent undefined types.
       results[i].selected = false;
       results[i].readableTimestamp =
diff --git a/chrome/browser/resources/md_history/query_manager.js b/chrome/browser/resources/md_history/query_manager.js
index de55e2b3..5d34fbde 100644
--- a/chrome/browser/resources/md_history/query_manager.js
+++ b/chrome/browser/resources/md_history/query_manager.js
@@ -41,13 +41,13 @@
     this.documentListeners_['change-query'] = this.onChangeQuery_.bind(this);
     this.documentListeners_['query-history'] = this.onQueryHistory_.bind(this);
 
-    for (var e in this.documentListeners_)
+    for (const e in this.documentListeners_)
       document.addEventListener(e, this.documentListeners_[e]);
   },
 
   /** @override */
   detached: function() {
-    for (var e in this.documentListeners_)
+    for (const e in this.documentListeners_)
       document.removeEventListener(e, this.documentListeners_[e]);
   },
 
@@ -56,7 +56,7 @@
    * @private
    */
   queryHistory_: function(incremental) {
-    var queryState = this.queryState;
+    const queryState = this.queryState;
 
     if (queryState.queryingDisabled)
       return;
@@ -79,8 +79,8 @@
    * @private
    */
   onChangeQuery_: function(e) {
-    var changes = /** @type {{search: ?string}} */ (e.detail);
-    var needsUpdate = false;
+    const changes = /** @type {{search: ?string}} */ (e.detail);
+    let needsUpdate = false;
 
     if (changes.search != null &&
         changes.search != this.queryState.searchTerm) {
diff --git a/chrome/browser/resources/md_history/router.js b/chrome/browser/resources/md_history/router.js
index 29f7512..56689ff 100644
--- a/chrome/browser/resources/md_history/router.js
+++ b/chrome/browser/resources/md_history/router.js
@@ -40,7 +40,7 @@
    * Write all relevant page state to the URL.
    */
   serializeUrl: function() {
-    var path = this.selectedPage;
+    let path = this.selectedPage;
 
     if (path == 'history')
       path = '';
@@ -62,9 +62,9 @@
   /** @private */
   parseUrl_: function() {
     this.parsing_ = true;
-    var changes = {};
-    var sections = this.path_.substr(1).split('/');
-    var page = sections[0] || 'history';
+    const changes = {};
+    const sections = this.path_.substr(1).split('/');
+    const page = sections[0] || 'history';
 
     changes.search = this.queryParams_.q || '';
 
diff --git a/chrome/browser/resources/md_history/searched_label.js b/chrome/browser/resources/md_history/searched_label.js
index bef60f6..08ff7c44 100644
--- a/chrome/browser/resources/md_history/searched_label.js
+++ b/chrome/browser/resources/md_history/searched_label.js
@@ -21,16 +21,16 @@
    * @private
    */
   setSearchedTextToBold_: function() {
-    var i = 0;
-    var titleText = this.title;
+    let i = 0;
+    const titleText = this.title;
 
     if (this.searchTerm == '' || this.searchTerm == null) {
       this.textContent = titleText;
       return;
     }
 
-    var re = new RegExp(quoteString(this.searchTerm), 'gim');
-    var match;
+    const re = new RegExp(quoteString(this.searchTerm), 'gim');
+    let match;
     this.textContent = '';
     while (match = re.exec(titleText)) {
       if (match.index > i)
@@ -38,7 +38,7 @@
             document.createTextNode(titleText.slice(i, match.index)));
       i = re.lastIndex;
       // Mark the highlighted text in bold.
-      var b = document.createElement('b');
+      const b = document.createElement('b');
       b.textContent = titleText.substring(match.index, i);
       this.appendChild(b);
     }
diff --git a/chrome/browser/resources/md_history/side_bar.js b/chrome/browser/resources/md_history/side_bar.js
index 34697cf..f5b04af9 100644
--- a/chrome/browser/resources/md_history/side_bar.js
+++ b/chrome/browser/resources/md_history/side_bar.js
@@ -47,7 +47,7 @@
    * @private
    */
   onClearBrowsingDataTap_: function(e) {
-    var browserService = md_history.BrowserService.getInstance();
+    const browserService = md_history.BrowserService.getInstance();
     browserService.recordAction('InitClearBrowsingData');
     browserService.openClearBrowsingData();
     /** @type {PaperRippleElement} */ (this.$['cbd-ripple']).upAction();
diff --git a/chrome/browser/resources/md_history/synced_device_card.js b/chrome/browser/resources/md_history/synced_device_card.js
index 7d37148..3206eb2 100644
--- a/chrome/browser/resources/md_history/synced_device_card.js
+++ b/chrome/browser/resources/md_history/synced_device_card.js
@@ -51,15 +51,15 @@
    * @return {!Array<!cr.ui.FocusRow>}
    */
   createFocusRows: function() {
-    var titleRow = new cr.ui.FocusRow(this.$['card-heading'], null);
+    const titleRow = new cr.ui.FocusRow(this.$['card-heading'], null);
     titleRow.addItem('menu', '#menu-button');
     titleRow.addItem('collapse', '#collapse-button');
-    var rows = [titleRow];
+    const rows = [titleRow];
     if (this.opened) {
       Polymer.dom(this.root)
           .querySelectorAll('.item-container')
           .forEach(function(el) {
-            var row = new cr.ui.FocusRow(el, null);
+            const row = new cr.ui.FocusRow(el, null);
             row.addItem('title', '.website-title');
             rows.push(row);
           });
@@ -74,8 +74,8 @@
    * @private
    */
   openTab_: function(e) {
-    var tab = /** @type {ForeignSessionTab} */ (e.model.tab);
-    var browserService = md_history.BrowserService.getInstance();
+    const tab = /** @type {ForeignSessionTab} */ (e.model.tab);
+    const browserService = md_history.BrowserService.getInstance();
     browserService.recordHistogram(
         SYNCED_TABS_HISTOGRAM_NAME, SyncedTabsHistogram.LINK_CLICKED,
         SyncedTabsHistogram.LIMIT);
@@ -88,7 +88,7 @@
    * Toggles the dropdown display of synced tabs for each device card.
    */
   toggleTabCard: function() {
-    var histogramValue = this.$.collapse.opened ?
+    const histogramValue = this.$.collapse.opened ?
         SyncedTabsHistogram.COLLAPSE_SESSION :
         SyncedTabsHistogram.EXPAND_SESSION;
 
@@ -115,9 +115,9 @@
    */
   updateIcons_: function() {
     this.async(function() {
-      var icons = Polymer.dom(this.root).querySelectorAll('.website-icon');
+      const icons = Polymer.dom(this.root).querySelectorAll('.website-icon');
 
-      for (var i = 0; i < this.tabs.length; i++) {
+      for (let i = 0; i < this.tabs.length; i++) {
         icons[i].style.backgroundImage = cr.icon.getFavicon(this.tabs[i].url);
       }
     });
diff --git a/chrome/browser/resources/md_history/synced_device_manager.js b/chrome/browser/resources/md_history/synced_device_manager.js
index 8ea2b78..ef84de1f 100644
--- a/chrome/browser/resources/md_history/synced_device_manager.js
+++ b/chrome/browser/resources/md_history/synced_device_manager.js
@@ -11,7 +11,7 @@
  *           tabs: !Array<!ForeignSessionTab>,
  *           tag: string}}
  */
-var ForeignDeviceInternal;
+let ForeignDeviceInternal;
 
 Polymer({
   is: 'history-synced-device-manager',
@@ -104,11 +104,11 @@
    * @private
    */
   createInternalDevice_: function(session) {
-    var tabs = [];
-    var separatorIndexes = [];
-    for (var i = 0; i < session.windows.length; i++) {
-      var windowId = session.windows[i].sessionId;
-      var newTabs = session.windows[i].tabs;
+    let tabs = [];
+    const separatorIndexes = [];
+    for (let i = 0; i < session.windows.length; i++) {
+      const windowId = session.windows[i].sessionId;
+      const newTabs = session.windows[i].tabs;
       if (newTabs.length == 0)
         continue;
 
@@ -116,15 +116,15 @@
         tab.windowId = windowId;
       });
 
-      var windowAdded = false;
+      let windowAdded = false;
       if (!this.searchTerm) {
         // Add all the tabs if there is no search term.
         tabs = tabs.concat(newTabs);
         windowAdded = true;
       } else {
-        var searchText = this.searchTerm.toLowerCase();
-        for (var j = 0; j < newTabs.length; j++) {
-          var tab = newTabs[j];
+        const searchText = this.searchTerm.toLowerCase();
+        for (let j = 0; j < newTabs.length; j++) {
+          const tab = newTabs[j];
           if (tab.title.toLowerCase().indexOf(searchText) != -1) {
             tabs.push(tab);
             windowAdded = true;
@@ -152,7 +152,7 @@
 
   /** @private */
   onOpenMenu_: function(e) {
-    var menu = /** @type {CrActionMenuElement} */ (this.$.menu.get());
+    const menu = /** @type {CrActionMenuElement} */ (this.$.menu.get());
     this.actionMenuModel_ = e.detail.tag;
     menu.showAt(e.detail.target);
     md_history.BrowserService.getInstance().recordHistogram(
@@ -162,8 +162,8 @@
 
   /** @private */
   onOpenAllTap_: function() {
-    var menu = assert(this.$.menu.getIfExists());
-    var browserService = md_history.BrowserService.getInstance();
+    const menu = assert(this.$.menu.getIfExists());
+    const browserService = md_history.BrowserService.getInstance();
     browserService.recordHistogram(
         SYNCED_TABS_HISTOGRAM_NAME, SyncedTabsHistogram.OPEN_ALL,
         SyncedTabsHistogram.LIMIT);
@@ -196,8 +196,8 @@
 
   /** @private */
   onDeleteSessionTap_: function() {
-    var menu = assert(this.$.menu.getIfExists());
-    var browserService = md_history.BrowserService.getInstance();
+    const menu = assert(this.$.menu.getIfExists());
+    const browserService = md_history.BrowserService.getInstance();
     browserService.recordHistogram(
         SYNCED_TABS_HISTOGRAM_NAME, SyncedTabsHistogram.HIDE_FOR_NOW,
         SyncedTabsHistogram.LIMIT);
@@ -234,7 +234,7 @@
    * @return {boolean}
    */
   showSignInGuide: function(signInState, guestSession) {
-    var show = !signInState && !guestSession;
+    const show = !signInState && !guestSession;
     if (show) {
       md_history.BrowserService.getInstance().recordAction(
           'Signin_Impression_FromRecentTabs');
@@ -249,7 +249,7 @@
    * @return {string}
    */
   noSyncedTabsMessage: function() {
-    var stringName = this.fetchingSyncedTabs_ ? 'loading' : 'noSyncedResults';
+    let stringName = this.fetchingSyncedTabs_ ? 'loading' : 'noSyncedResults';
     if (this.searchTerm !== '')
       stringName = 'noSearchResults';
     return loadTimeData.getString(stringName);
@@ -276,9 +276,9 @@
           SyncedTabsHistogram.LIMIT);
     }
 
-    var devices = [];
+    const devices = [];
     sessionList.forEach((session) => {
-      var device = this.createInternalDevice_(session);
+      const device = this.createInternalDevice_(session);
       if (device.tabs.length != 0)
         devices.push(device);
     });
diff --git a/chrome/browser/resources/print_preview/new/other_options_settings.html b/chrome/browser/resources/print_preview/new/other_options_settings.html
index f6397776..b816a327 100644
--- a/chrome/browser/resources/print_preview/new/other_options_settings.html
+++ b/chrome/browser/resources/print_preview/new/other_options_settings.html
@@ -1,50 +1,53 @@
 <link rel="import" href="chrome://resources/html/polymer.html">
 
+<link rel="import" href="chrome://resources/cr_elements/hidden_style_css.html">
 <link rel="import" href="checkbox_radio_css.html">
 <link rel="import" href="print_preview_shared_css.html">
+<link rel="import" href="settings_behavior.html">
 <link rel="import" href="settings_section.html">
 
 <dom-module id="print-preview-other-options-settings">
   <template>
-    <style include="print-preview-shared checkbox-radio">
+    <style include="print-preview-shared checkbox-radio cr-hidden-style">
+      label {
+        display: block;
+      }
     </style>
     <print-preview-settings-section class="multirow-controls">
       <span slot="title" id="options-label">$i18n{optionsLabel}</span>
       <div slot="controls" class="checkbox">
-        <div id="header-footer-container"
+        <label aria-live="polite"
             hidden$="[[!settings.headerFooter.available]]">
-          <label aria-live="polite">
-            <input type="checkbox">
-            <span>$i18n{optionHeaderFooter}</span>
-          </label>
-        </div>
-        <div id="duplex-container" hidden$="[[!settings.duplex.available]]">
-          <label aria-live="polite">
-            <input type="checkbox" checked="{{duplexValue_::change}}">
-            <span>$i18n{optionTwoSided}</span>
-          </label>
-        </div>
-        <div id="css-background-container"
+          <input type="checkbox" id="header-footer"
+              on-change="onHeaderFooterChange_"
+              checked$="[[settings.headerFooter.value]]">
+          <span>$i18n{optionHeaderFooter}</span>
+        </label>
+        <label aria-live="polite" hidden$="[[!settings.duplex.available]]">
+          <input type="checkbox" id="duplex" on-change="onDuplexChange_"
+              checked$="[[settings.duplex.value]]">
+          <span>$i18n{optionTwoSided}</span>
+        </label>
+        <label aria-live="polite"
             hidden$="[[!settings.cssBackground.available]]">
-          <label aria-live="polite">
-            <input type="checkbox">
-            <span>$i18n{optionBackgroundColorsAndImages}</span>
-          </label>
-        </div>
-        <div id="rasterize-container"
-            hidden$="[[!settings.rasterize.available]]">
-          <label aria-live="polite">
-            <input type="checkbox">
-            <span>$i18n{optionRasterize}</span>
-          </label>
-        </div>
-        <div id="selection-only-container"
+          <input type="checkbox" id="css-background"
+              on-change="onCssBackgroundChange_"
+              checked$="[[settings.cssBackground.value]]">
+          <span>$i18n{optionBackgroundColorsAndImages}</span>
+        </label>
+        <label aria-live="polite" hidden$="[[!settings.rasterize.available]]">
+          <input type="checkbox" id="rasterize"
+              on-change="onRasterizeChange_"
+              checked$="[[settings.rasterize.value]]">
+          <span>$i18n{optionRasterize}</span>
+        </label>
+        <label aria-live="polite"
             hidden$="[[!settings.selectionOnly.available]]">
-          <label aria-live="polite">
-            <input type="checkbox">
-            <span>$i18n{optionSelectionOnly}</span>
-          </label>
-        </div>
+          <input type="checkbox" id="selection-only"
+              on-change="onSelectionOnlyChange_"
+              checked$="[[settings.selectionOnly.value]]">
+          <span>$i18n{optionSelectionOnly}</span>
+        </label>
       </div>
     </print-preview-settings-section>
   </template>
diff --git a/chrome/browser/resources/print_preview/new/other_options_settings.js b/chrome/browser/resources/print_preview/new/other_options_settings.js
index 5399d54..07e21f5 100644
--- a/chrome/browser/resources/print_preview/new/other_options_settings.js
+++ b/chrome/browser/resources/print_preview/new/other_options_settings.js
@@ -7,26 +7,76 @@
 
   behaviors: [SettingsBehavior],
 
-  properties: {
-    /** @private {boolean} */
-    duplexValue_: Boolean,
-  },
-
   observers: [
-    'onInitialized_(settings.duplex.value)',
-    'onDuplexChange_(duplexValue_)',
+    'onHeaderFooterSettingChange_(settings.headerFooter.value)',
+    'onDuplexSettingChange_(settings.duplex.value)',
+    'onCssBackgroundSettingChange_(settings.cssBackground.value)',
+    'onRasterizeSettingChange_(settings.rasterize.value)',
+    'onSelectionOnlySettingChange_(settings.selectionOnly.value)',
   ],
 
-  isInitialized_: false,
-
-  onInitialized_: function() {
-    if (this.isInitialized_)
-      return;
-    this.set('duplexValue_', this.getSetting('duplex').value);
-    this.isInitialized_ = true;
+  /**
+   * @param {boolean} value The new value of the header footer setting.
+   * @private
+   */
+  onHeaderFooterSettingChange_: function(value) {
+    this.$$('#header-footer').checked = value;
   },
 
+  /**
+   * @param {boolean} value The new value of the duplex setting.
+   * @private
+   */
+  onDuplexSettingChange_: function(value) {
+    this.$$('#duplex').checked = value;
+  },
+
+  /**
+   * @param {boolean} value The new value of the css background setting.
+   * @private
+   */
+  onCssBackgroundSettingChange_: function(value) {
+    this.$$('#css-background').checked = value;
+  },
+
+  /**
+   * @param {boolean} value The new value of the rasterize setting.
+   * @private
+   */
+  onRasterizeSettingChange_: function(value) {
+    this.$$('#rasterize').checked = value;
+  },
+
+  /**
+   * @param {boolean} value The new value of the selection only setting.
+   * @private
+   */
+  onSelectionOnlySettingChange_: function(value) {
+    this.$$('#selection-only').checked = value;
+  },
+
+  /** @private */
+  onHeaderFooterChange_: function() {
+    this.setSetting('headerFooter', this.$$('#header-footer').checked);
+  },
+
+  /** @private */
   onDuplexChange_: function() {
-    this.setSetting('duplex', this.duplexValue_);
+    this.setSetting('duplex', this.$$('#duplex').checked);
+  },
+
+  /** @private */
+  onCssBackgroundChange_: function() {
+    this.setSetting('cssBackground', this.$$('#css-background').checked);
+  },
+
+  /** @private */
+  onRasterizeChange_: function() {
+    this.setSetting('rasterize', this.$$('#rasterize').checked);
+  },
+
+  /** @private */
+  onSelectionOnlyChange_: function() {
+    this.setSetting('selectionOnly', this.$$('#selection-only').checked);
   },
 });
diff --git a/chrome/browser/sync/test/integration/sync_app_list_helper.cc b/chrome/browser/sync/test/integration/sync_app_list_helper.cc
index 1fe6262..630aaba 100644
--- a/chrome/browser/sync/test/integration/sync_app_list_helper.cc
+++ b/chrome/browser/sync/test/integration/sync_app_list_helper.cc
@@ -11,10 +11,10 @@
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/sync/test/integration/sync_datatype_helper.h"
 #include "chrome/browser/sync/test/integration/sync_test.h"
-#include "chrome/browser/ui/app_list/app_list_model_updater.h"
 #include "chrome/browser/ui/app_list/app_list_syncable_service.h"
 #include "chrome/browser/ui/app_list/app_list_syncable_service_factory.h"
 #include "chrome/browser/ui/app_list/chrome_app_list_item.h"
+#include "chrome/browser/ui/app_list/chrome_app_list_model_updater.h"
 #include "chrome/common/extensions/sync_helper.h"
 #include "extensions/browser/app_sorting.h"
 #include "extensions/browser/extension_system.h"
diff --git a/chrome/browser/task_manager/task_manager_interface.cc b/chrome/browser/task_manager/task_manager_interface.cc
index 09c8843..f58357d3 100644
--- a/chrome/browser/task_manager/task_manager_interface.cc
+++ b/chrome/browser/task_manager/task_manager_interface.cc
@@ -13,6 +13,7 @@
 #include "components/prefs/pref_service.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/resource_request_info.h"
+#include "content/public/common/child_process_host.h"
 
 #if defined(OS_MACOSX)
 #include "chrome/browser/ui/browser_dialogs.h"
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn
index 118ede6d..6203bfc 100644
--- a/chrome/browser/ui/BUILD.gn
+++ b/chrome/browser/ui/BUILD.gn
@@ -1218,6 +1218,8 @@
       "ash/ash_util.h",
       "ash/cast_config_client_media_router.cc",
       "ash/cast_config_client_media_router.h",
+      "ash/chrome_browser_main_extra_parts_ash.cc",
+      "ash/chrome_browser_main_extra_parts_ash.h",
       "ash/chrome_keyboard_ui.cc",
       "ash/chrome_keyboard_ui.h",
       "ash/chrome_launcher_prefs.cc",
@@ -1296,6 +1298,8 @@
       "ash/sort_windows_by_z_index.cc",
       "ash/system_tray_client.cc",
       "ash/system_tray_client.h",
+      "ash/tab_scrubber.cc",
+      "ash/tab_scrubber.h",
       "ash/tablet_mode_client.cc",
       "ash/tablet_mode_client.h",
       "ash/tablet_mode_client_observer.h",
@@ -1320,10 +1324,6 @@
       "views/apps/app_info_dialog/arc_app_info_links_panel.h",
       "views/apps/chrome_native_app_window_views_aura_ash.cc",
       "views/apps/chrome_native_app_window_views_aura_ash.h",
-      "views/ash/chrome_browser_main_extra_parts_ash.cc",
-      "views/ash/chrome_browser_main_extra_parts_ash.h",
-      "views/ash/tab_scrubber.cc",
-      "views/ash/tab_scrubber.h",
       "views/chrome_views_delegate_chromeos.cc",
       "views/extensions/request_file_system_dialog_view.cc",
       "views/extensions/request_file_system_dialog_view.h",
diff --git a/chrome/browser/ui/app_list/app_list_syncable_service.cc b/chrome/browser/ui/app_list/app_list_syncable_service.cc
index fe1dfb6..8d68e42 100644
--- a/chrome/browser/ui/app_list/app_list_syncable_service.cc
+++ b/chrome/browser/ui/app_list/app_list_syncable_service.cc
@@ -422,7 +422,7 @@
   model_updater_->SetItemName(kOemFolderId, oem_folder_name_);
 }
 
-AppListModelUpdater* AppListSyncableService::GetModelUpdater() {
+ChromeAppListModelUpdater* AppListSyncableService::GetModelUpdater() {
   DCHECK(IsInitialized());
   return model_updater_.get();
 }
diff --git a/chrome/browser/ui/app_list/app_list_syncable_service.h b/chrome/browser/ui/app_list/app_list_syncable_service.h
index 4ee3bf3..2fd9562f 100644
--- a/chrome/browser/ui/app_list/app_list_syncable_service.h
+++ b/chrome/browser/ui/app_list/app_list_syncable_service.h
@@ -24,7 +24,6 @@
 #include "components/sync/model/syncable_service.h"
 #include "components/sync/protocol/app_list_specifics.pb.h"
 
-class AppListModelUpdater;
 class ArcAppModelBuilder;
 class ChromeAppListModelUpdater;
 class ChromeAppListItem;
@@ -121,7 +120,7 @@
                       const syncer::StringOrdinal& item_pin_ordinal);
 
   // Gets the app list model updater.
-  AppListModelUpdater* GetModelUpdater();
+  ChromeAppListModelUpdater* GetModelUpdater();
 
   // Gets the app list model.
   // Note: This will be removed. Use |GetModelUpdater| instead.
diff --git a/chrome/browser/ui/app_list/app_list_syncable_service_unittest.cc b/chrome/browser/ui/app_list/app_list_syncable_service_unittest.cc
index ec1b649..2af1b68 100644
--- a/chrome/browser/ui/app_list/app_list_syncable_service_unittest.cc
+++ b/chrome/browser/ui/app_list/app_list_syncable_service_unittest.cc
@@ -9,6 +9,7 @@
 #include "chrome/browser/ui/app_list/app_list_model_updater.h"
 #include "chrome/browser/ui/app_list/app_list_test_util.h"
 #include "chrome/browser/ui/app_list/chrome_app_list_item.h"
+#include "chrome/browser/ui/app_list/chrome_app_list_model_updater.h"
 #include "chrome/test/base/testing_browser_process.h"
 #include "chrome/test/base/testing_profile.h"
 #include "components/crx_file/id_util.h"
@@ -185,7 +186,7 @@
 
   void TearDown() override { app_list_syncable_service_.reset(); }
 
-  AppListModelUpdater* model_updater() {
+  ChromeAppListModelUpdater* model_updater() {
     return app_list_syncable_service_->GetModelUpdater();
   }
 
diff --git a/chrome/browser/ui/app_list/app_list_view_delegate.cc b/chrome/browser/ui/app_list/app_list_view_delegate.cc
index daf4fdc..bbe8f282 100644
--- a/chrome/browser/ui/app_list/app_list_view_delegate.cc
+++ b/chrome/browser/ui/app_list/app_list_view_delegate.cc
@@ -357,6 +357,14 @@
   *colors = wallpaper_prominent_colors_;
 }
 
+void AppListViewDelegate::ActivateItem(const std::string& id, int event_flags) {
+  model_updater_->ActivateChromeItem(id, event_flags);
+}
+
+ui::MenuModel* AppListViewDelegate::GetContextMenuModel(const std::string& id) {
+  return model_updater_->GetContextMenuModel(id);
+}
+
 void AppListViewDelegate::AddObserver(
     app_list::AppListViewDelegateObserver* observer) {
   observers_.AddObserver(observer);
diff --git a/chrome/browser/ui/app_list/app_list_view_delegate.h b/chrome/browser/ui/app_list/app_list_view_delegate.h
index c3b7301..81dd4f3 100644
--- a/chrome/browser/ui/app_list/app_list_view_delegate.h
+++ b/chrome/browser/ui/app_list/app_list_view_delegate.h
@@ -17,7 +17,7 @@
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
 #include "base/scoped_observer.h"
-#include "chrome/browser/ui/app_list/app_list_model_updater.h"
+#include "chrome/browser/ui/app_list/chrome_app_list_model_updater.h"
 #include "chrome/browser/ui/app_list/start_page_observer.h"
 #include "components/search_engines/template_url_service.h"
 #include "components/search_engines/template_url_service_observer.h"
@@ -83,6 +83,8 @@
   views::View* CreateStartPageWebView(const gfx::Size& size) override;
   bool IsSpeechRecognitionEnabled() override;
   void GetWallpaperProminentColors(std::vector<SkColor>* colors) override;
+  void ActivateItem(const std::string& id, int event_flags) override;
+  ui::MenuModel* GetContextMenuModel(const std::string& id) override;
   void AddObserver(app_list::AppListViewDelegateObserver* observer) override;
   void RemoveObserver(app_list::AppListViewDelegateObserver* observer) override;
 
@@ -122,7 +124,7 @@
 
   // Unowned pointer to the model updater owned by AppListSyncableService.
   // Will change if |profile_| changes.
-  AppListModelUpdater* model_updater_;
+  ChromeAppListModelUpdater* model_updater_;
 
   // Note: order ensures |search_resource_manager_| is destroyed before
   // |speech_ui_|.
diff --git a/chrome/browser/ui/app_list/chrome_app_list_item.h b/chrome/browser/ui/app_list/chrome_app_list_item.h
index f8b4f1b..3bd79e0 100644
--- a/chrome/browser/ui/app_list/chrome_app_list_item.h
+++ b/chrome/browser/ui/app_list/chrome_app_list_item.h
@@ -24,6 +24,10 @@
 class ImageSkia;
 }  // namespace gfx
 
+namespace ui {
+class MenuModel;
+}  // namespace ui
+
 // Base class of all chrome app list items.
 class ChromeAppListItem : public app_list::AppListItem {
  public:
@@ -55,7 +59,7 @@
   static gfx::ImageSkia CreateDisabledIcon(const gfx::ImageSkia& icon);
 
   // Activates (opens) the item. Does nothing by default.
-  void Activate(int event_flags) override;
+  virtual void Activate(int event_flags);
 
   // Returns a static const char* identifier for the subclass (defaults to "").
   // Pointers can be compared for quick type checking.
@@ -64,7 +68,7 @@
   // Returns the context menu model for this item, or NULL if there is currently
   // no menu for the item (e.g. during install).
   // Note the returned menu model is owned by this item.
-  ui::MenuModel* GetContextMenuModel() override;
+  virtual ui::MenuModel* GetContextMenuModel();
 
   bool CompareForTest(const app_list::AppListItem* other) const override;
 
diff --git a/chrome/browser/ui/app_list/chrome_app_list_model_updater.cc b/chrome/browser/ui/app_list/chrome_app_list_model_updater.cc
index 4a14957..a0b0ee7f 100644
--- a/chrome/browser/ui/app_list/chrome_app_list_model_updater.cc
+++ b/chrome/browser/ui/app_list/chrome_app_list_model_updater.cc
@@ -13,6 +13,7 @@
 #include "ash/app_list/model/search/search_model.h"
 #include "chrome/browser/ui/app_list/chrome_app_list_item.h"
 #include "extensions/common/constants.h"
+#include "ui/base/models/menu_model.h"
 
 ChromeAppListModelUpdater::ChromeAppListModelUpdater()
     : model_(std::make_unique<app_list::AppListModel>()),
@@ -85,6 +86,15 @@
   search_model_->search_box()->Update(text, initiated_by_user);
 }
 
+void ChromeAppListModelUpdater::ActivateChromeItem(const std::string& id,
+                                                   int event_flags) {
+  app_list::AppListItem* item = model_->FindItem(id);
+  if (!item)
+    return;
+  DCHECK(!item->is_folder());
+  static_cast<ChromeAppListItem*>(item)->Activate(event_flags);
+}
+
 ////////////////////////////////////////////////////////////////////////////////
 // Methods only used by ChromeAppListItem that talk to ash directly.
 
@@ -201,6 +211,15 @@
   return oem_folder;
 }
 
+ui::MenuModel* ChromeAppListModelUpdater::GetContextMenuModel(
+    const std::string& id) {
+  app_list::AppListItem* item = model_->FindItem(id);
+  // TODO(stevenjb/jennyz): Implement this for folder items
+  if (!item || item->is_folder())
+    return nullptr;
+  return static_cast<ChromeAppListItem*>(item)->GetContextMenuModel();
+}
+
 ////////////////////////////////////////////////////////////////////////////////
 // Methods for AppListSyncableService
 
diff --git a/chrome/browser/ui/app_list/chrome_app_list_model_updater.h b/chrome/browser/ui/app_list/chrome_app_list_model_updater.h
index a3dcf43..f9b01cb 100644
--- a/chrome/browser/ui/app_list/chrome_app_list_model_updater.h
+++ b/chrome/browser/ui/app_list/chrome_app_list_model_updater.h
@@ -12,6 +12,10 @@
 #include "chrome/browser/ui/app_list/app_list_model_updater.h"
 #include "chrome/browser/ui/app_list/app_list_syncable_service.h"
 
+namespace ui {
+class MenuModel;
+}  // namespace ui
+
 class ChromeAppListItem;
 class SearchModel;
 
@@ -41,6 +45,9 @@
   void UpdateSearchBox(const base::string16& text,
                        bool initiated_by_user) override;
 
+  // Methods only for visiting Chrome items that never talk to ash.
+  void ActivateChromeItem(const std::string& id, int event_flags);
+
   // Methods for item querying.
   ChromeAppListItem* FindItem(const std::string& id) override;
   size_t ItemCount() override;
@@ -52,6 +59,7 @@
   app_list::AppListViewState StateFullscreen() override;
   bool SearchEngineIsGoogle() override;
   std::map<std::string, size_t> GetIdToAppListIndexMap() override;
+  ui::MenuModel* GetContextMenuModel(const std::string& id);
 
   // Methods for AppListSyncableService:
   void AddItemToOemFolder(
diff --git a/chrome/browser/ui/app_list/test/chrome_app_list_test_support.cc b/chrome/browser/ui/app_list/test/chrome_app_list_test_support.cc
index 7c147d90..7ed2e58 100644
--- a/chrome/browser/ui/app_list/test/chrome_app_list_test_support.cc
+++ b/chrome/browser/ui/app_list/test/chrome_app_list_test_support.cc
@@ -54,7 +54,7 @@
 
 }  // namespace
 
-AppListModelUpdater* GetModelUpdater(AppListService* service) {
+ChromeAppListModelUpdater* GetModelUpdater(AppListService* service) {
   return app_list::AppListSyncableServiceFactory::GetForProfile(
              service->GetCurrentAppListProfile())
       ->GetModelUpdater();
diff --git a/chrome/browser/ui/app_list/test/chrome_app_list_test_support.h b/chrome/browser/ui/app_list/test/chrome_app_list_test_support.h
index 3e94f91..3562683 100644
--- a/chrome/browser/ui/app_list/test/chrome_app_list_test_support.h
+++ b/chrome/browser/ui/app_list/test/chrome_app_list_test_support.h
@@ -9,7 +9,7 @@
 class SearchModel;
 }
 
-class AppListModelUpdater;
+class ChromeAppListModelUpdater;
 class AppListService;
 class AppListServiceImpl;
 class Profile;
@@ -18,7 +18,7 @@
 
 // Gets the model updater keyed to the profile currently associated with
 // |service|.
-AppListModelUpdater* GetModelUpdater(AppListService* service);
+ChromeAppListModelUpdater* GetModelUpdater(AppListService* service);
 
 // TODO(hejq): Merge it into model updater.
 // Gets the search model keyed to the profile currently associated with
diff --git a/chrome/browser/ui/ash/DEPS b/chrome/browser/ui/ash/DEPS
index 102594e..37f4246 100644
--- a/chrome/browser/ui/ash/DEPS
+++ b/chrome/browser/ui/ash/DEPS
@@ -7,10 +7,8 @@
   # those are owned by the ash process under mash. See //ash/README.md.
   "-ash/wm/window_util.h",
 
-  # TODO(ananta): Remove this when we move files which display UI in
-  # chrome/browser/ui/ash to chrome/browser/ui/views/ash
-  # crbug.com/728877
-  "+chrome/browser/ui/views/harmony/chrome_layout_provider.h",
+  # ash depends on views, so code in ui/ash is allowed to depend on ui/views.
+  "+chrome/browser/ui/views",
 
   "+components/arc",
   "+components/drive",
diff --git a/chrome/browser/ui/views/ash/chrome_browser_main_extra_parts_ash.cc b/chrome/browser/ui/ash/chrome_browser_main_extra_parts_ash.cc
similarity index 89%
rename from chrome/browser/ui/views/ash/chrome_browser_main_extra_parts_ash.cc
rename to chrome/browser/ui/ash/chrome_browser_main_extra_parts_ash.cc
index e87a6e98..e1dbf44 100644
--- a/chrome/browser/ui/views/ash/chrome_browser_main_extra_parts_ash.cc
+++ b/chrome/browser/ui/ash/chrome_browser_main_extra_parts_ash.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 "chrome/browser/ui/views/ash/chrome_browser_main_extra_parts_ash.h"
+#include "chrome/browser/ui/ash/chrome_browser_main_extra_parts_ash.h"
 
 #include "ash/public/cpp/mus_property_mirror_ash.h"
 #include "ash/public/cpp/window_pin_type.h"
@@ -11,10 +11,8 @@
 #include "ash/public/interfaces/window_pin_type.mojom.h"
 #include "ash/public/interfaces/window_properties.mojom.h"
 #include "ash/public/interfaces/window_state_type.mojom.h"
-#include "ash/root_window_controller.h"
 #include "ash/shell.h"
 #include "base/memory/ptr_util.h"
-#include "chrome/browser/chrome_browser_main.h"
 #include "chrome/browser/ui/ash/accessibility/accessibility_controller_client.h"
 #include "chrome/browser/ui/ash/ash_init.h"
 #include "chrome/browser/ui/ash/ash_util.h"
@@ -26,9 +24,9 @@
 #include "chrome/browser/ui/ash/media_client.h"
 #include "chrome/browser/ui/ash/session_controller_client.h"
 #include "chrome/browser/ui/ash/system_tray_client.h"
+#include "chrome/browser/ui/ash/tab_scrubber.h"
 #include "chrome/browser/ui/ash/volume_controller.h"
 #include "chrome/browser/ui/ash/vpn_list_forwarder.h"
-#include "chrome/browser/ui/views/ash/tab_scrubber.h"
 #include "chrome/browser/ui/views/frame/immersive_context_mus.h"
 #include "chrome/browser/ui/views/frame/immersive_handler_factory_mus.h"
 #include "chrome/browser/ui/views/select_file_dialog_extension.h"
@@ -39,11 +37,8 @@
 #include "services/ui/public/interfaces/user_activity_monitor.mojom.h"
 #include "ui/aura/mus/property_converter.h"
 #include "ui/aura/mus/user_activity_forwarder.h"
-#include "ui/base/class_property.h"
 #include "ui/base/ime/chromeos/input_method_manager.h"
 #include "ui/base/user_activity/user_activity_detector.h"
-#include "ui/keyboard/content/keyboard.h"
-#include "ui/keyboard/keyboard_controller.h"
 #include "ui/views/mus/mus_client.h"
 
 #if BUILDFLAG(ENABLE_WAYLAND_SERVER)
@@ -135,11 +130,6 @@
   volume_controller_ = base::MakeUnique<VolumeController>();
   vpn_list_forwarder_ = base::MakeUnique<VpnListForwarder>();
 
-  // For OS_CHROMEOS, virtual keyboard needs to be initialized before profile
-  // initialized. Otherwise, virtual keyboard extension will not load at login
-  // screen.
-  keyboard::InitializeKeyboard();
-
   ui::SelectFileDialog::SetFactory(new SelectFileDialogExtensionFactory);
 
 #if BUILDFLAG(ENABLE_WAYLAND_SERVER)
@@ -156,17 +146,12 @@
   media_client_ = base::MakeUnique<MediaClient>();
   login_screen_client_ = base::MakeUnique<LoginScreenClient>();
 
-  // TODO(mash): Port TabScrubber and keyboard initialization.
+  // TODO(mash): Port TabScrubber.
   if (ash_util::IsRunningInMash())
     return;
 
   // Initialize TabScrubber after the Ash Shell has been initialized.
   TabScrubber::GetInstance();
-
-  // Activate virtual keyboard after profile is initialized. It depends on the
-  // default profile.
-  ash::Shell::GetPrimaryRootWindowController()->ActivateKeyboard(
-      keyboard::KeyboardController::GetInstance());
 }
 
 void ChromeBrowserMainExtraPartsAsh::PostMainMessageLoopRun() {
diff --git a/chrome/browser/ui/views/ash/chrome_browser_main_extra_parts_ash.h b/chrome/browser/ui/ash/chrome_browser_main_extra_parts_ash.h
similarity index 87%
rename from chrome/browser/ui/views/ash/chrome_browser_main_extra_parts_ash.h
rename to chrome/browser/ui/ash/chrome_browser_main_extra_parts_ash.h
index d3a1f5a4..da1bb97 100644
--- a/chrome/browser/ui/views/ash/chrome_browser_main_extra_parts_ash.h
+++ b/chrome/browser/ui/ash/chrome_browser_main_extra_parts_ash.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 CHROME_BROWSER_UI_VIEWS_ASH_CHROME_BROWSER_MAIN_EXTRA_PARTS_ASH_H_
-#define CHROME_BROWSER_UI_VIEWS_ASH_CHROME_BROWSER_MAIN_EXTRA_PARTS_ASH_H_
+#ifndef CHROME_BROWSER_UI_ASH_CHROME_BROWSER_MAIN_EXTRA_PARTS_ASH_H_
+#define CHROME_BROWSER_UI_ASH_CHROME_BROWSER_MAIN_EXTRA_PARTS_ASH_H_
 
 #include <memory>
 
@@ -38,8 +38,8 @@
 class ExoParts;
 #endif
 
-// Browser initialization for Ash. Only runs on Chrome OS.
-// TODO(jamescook): Fold this into ChromeBrowserMainPartsChromeOS.
+// Browser initialization for Ash UI. Only use this for initialization of
+// chrome/browser/ui/ash classes.
 class ChromeBrowserMainExtraPartsAsh : public ChromeBrowserMainExtraParts {
  public:
   ChromeBrowserMainExtraPartsAsh();
@@ -80,4 +80,4 @@
   DISALLOW_COPY_AND_ASSIGN(ChromeBrowserMainExtraPartsAsh);
 };
 
-#endif  // CHROME_BROWSER_UI_VIEWS_ASH_CHROME_BROWSER_MAIN_EXTRA_PARTS_ASH_H_
+#endif  // CHROME_BROWSER_UI_ASH_CHROME_BROWSER_MAIN_EXTRA_PARTS_ASH_H_
diff --git a/chrome/browser/ui/ash/chrome_shell_delegate.cc b/chrome/browser/ui/ash/chrome_shell_delegate.cc
index b646109..855d888 100644
--- a/chrome/browser/ui/ash/chrome_shell_delegate.cc
+++ b/chrome/browser/ui/ash/chrome_shell_delegate.cc
@@ -12,6 +12,7 @@
 #include "ash/accelerators/magnifier_key_scroller.h"
 #include "ash/accelerators/spoken_feedback_toggler.h"
 #include "ash/accessibility/accessibility_delegate.h"
+#include "ash/display/display_prefs.h"
 #include "ash/public/cpp/accessibility_types.h"
 #include "ash/shell.h"
 #include "ash/system/tray/system_tray_controller.h"
@@ -31,7 +32,6 @@
 #include "chrome/browser/chromeos/ash_config.h"
 #include "chrome/browser/chromeos/background/ash_wallpaper_delegate.h"
 #include "chrome/browser/chromeos/display/display_configuration_observer.h"
-#include "chrome/browser/chromeos/display/display_prefs.h"
 #include "chrome/browser/chromeos/policy/display_rotation_default_handler.h"
 #include "chrome/browser/chromeos/profiles/profile_helper.h"
 #include "chrome/browser/profiles/profile.h"
@@ -302,13 +302,11 @@
   if (chromeos::GetAshConfig() == ash::Config::MASH)
     return;
 
-  bool first_run_after_boot = base::CommandLine::ForCurrentProcess()->HasSwitch(
-      chromeos::switches::kFirstExecAfterBoot);
-  display_prefs_ = std::make_unique<chromeos::DisplayPrefs>(
-      g_browser_process->local_state());
-  display_prefs_->LoadDisplayPreferences(first_run_after_boot);
-  // Object owns itself, and deletes itself when Observer::OnShutdown is called:
+  // Object owns itself and deletes itself in OnWindowTreeHostManagerShutdown().
+  // Setup is done in OnShellInitialized() so this needs to be constructed after
+  // Shell is constructed but before OnShellInitialized() is called.
   new policy::DisplayRotationDefaultHandler();
+
   // Set the observer now so that we can save the initial state
   // in Shell::Init.
   display_configuration_observer_.reset(
diff --git a/chrome/browser/ui/ash/chrome_shell_delegate.h b/chrome/browser/ui/ash/chrome_shell_delegate.h
index ace03ba..76572659 100644
--- a/chrome/browser/ui/ash/chrome_shell_delegate.h
+++ b/chrome/browser/ui/ash/chrome_shell_delegate.h
@@ -16,7 +16,6 @@
 
 namespace chromeos {
 class DisplayConfigurationObserver;
-class DisplayPrefs;
 }
 
 namespace keyboard {
@@ -55,7 +54,6 @@
 
   content::NotificationRegistrar registrar_;
 
-  std::unique_ptr<chromeos::DisplayPrefs> display_prefs_;
   std::unique_ptr<chromeos::DisplayConfigurationObserver>
       display_configuration_observer_;
 
diff --git a/chrome/browser/ui/views/ash/tab_scrubber.cc b/chrome/browser/ui/ash/tab_scrubber.cc
similarity index 93%
rename from chrome/browser/ui/views/ash/tab_scrubber.cc
rename to chrome/browser/ui/ash/tab_scrubber.cc
index 07d78dc0..0f12870 100644
--- a/chrome/browser/ui/views/ash/tab_scrubber.cc
+++ b/chrome/browser/ui/ash/tab_scrubber.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 "chrome/browser/ui/views/ash/tab_scrubber.h"
+#include "chrome/browser/ui/ash/tab_scrubber.h"
 
 #include <stdint.h>
 
@@ -53,9 +53,8 @@
   // non-RTL layouts (in non-RTL layouts GetMirroredBounds() is the same as
   // bounds()).
   gfx::Rect tab_bounds = tab_strip->tab_at(index)->GetMirroredBounds();
-  float x = direction == LEFT ?
-      tab_bounds.x() + initial_tab_offset :
-          tab_bounds.right() - initial_tab_offset;
+  float x = direction == LEFT ? tab_bounds.x() + initial_tab_offset
+                              : tab_bounds.right() - initial_tab_offset;
   return gfx::Point(x, tab_bounds.CenterPoint().y());
 }
 
@@ -79,10 +78,8 @@
   // gestures on browser windows is not sufficient, as this feature works when
   // the cursor is over the shelf, desktop, etc.
   ash::Shell::Get()->AddPreTargetHandler(this);
-  registrar_.Add(
-      this,
-      chrome::NOTIFICATION_BROWSER_CLOSED,
-      content::NotificationService::AllSources());
+  registrar_.Add(this, chrome::NOTIFICATION_BROWSER_CLOSED,
+                 content::NotificationService::AllSources());
 }
 
 TabScrubber::~TabScrubber() {
@@ -105,14 +102,13 @@
   Browser* browser = GetActiveBrowser();
   if (!browser || (scrubbing_ && browser_ && browser != browser_) ||
       (highlighted_tab_ != -1 &&
-          highlighted_tab_ >= browser->tab_strip_model()->count())) {
+       highlighted_tab_ >= browser->tab_strip_model()->count())) {
     FinishScrub(false);
     return;
   }
 
-  BrowserView* browser_view =
-      BrowserView::GetBrowserViewForNativeWindow(
-          browser->window()->GetNativeWindow());
+  BrowserView* browser_view = BrowserView::GetBrowserViewForNativeWindow(
+      browser->window()->GetNativeWindow());
   TabStripImpl* tab_strip = browser_view->tabstrip()->AsTabStripImpl();
   if (!tab_strip) {
     DLOG(WARNING) << "TabScrubber disabled for experimental tab strip.";
@@ -203,7 +199,7 @@
 
   if (from_index == highlighted_tab_)
     highlighted_tab_ = to_index;
-  else if (from_index < highlighted_tab_&& highlighted_tab_<= to_index)
+  else if (from_index < highlighted_tab_ && highlighted_tab_ <= to_index)
     --highlighted_tab_;
   else if (from_index > highlighted_tab_ && highlighted_tab_ >= to_index)
     ++highlighted_tab_;
@@ -267,9 +263,8 @@
   activate_timer_.Stop();
 
   if (browser_ && browser_->window()) {
-    BrowserView* browser_view =
-        BrowserView::GetBrowserViewForNativeWindow(
-            browser_->window()->GetNativeWindow());
+    BrowserView* browser_view = BrowserView::GetBrowserViewForNativeWindow(
+        browser_->window()->GetNativeWindow());
     TabStripImpl* tab_strip = browser_view->tabstrip()->AsTabStripImpl();
     if (tab_strip) {
       if (activate && highlighted_tab_ != -1) {
diff --git a/chrome/browser/ui/views/ash/tab_scrubber.h b/chrome/browser/ui/ash/tab_scrubber.h
similarity index 95%
rename from chrome/browser/ui/views/ash/tab_scrubber.h
rename to chrome/browser/ui/ash/tab_scrubber.h
index 54267028..aeb5d72 100644
--- a/chrome/browser/ui/views/ash/tab_scrubber.h
+++ b/chrome/browser/ui/ash/tab_scrubber.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 CHROME_BROWSER_UI_VIEWS_ASH_TAB_SCRUBBER_H_
-#define CHROME_BROWSER_UI_VIEWS_ASH_TAB_SCRUBBER_H_
+#ifndef CHROME_BROWSER_UI_ASH_TAB_SCRUBBER_H_
+#define CHROME_BROWSER_UI_ASH_TAB_SCRUBBER_H_
 
 #include <memory>
 
@@ -28,7 +28,7 @@
                     public content::NotificationObserver,
                     public TabStripObserver {
  public:
-  enum Direction {LEFT, RIGHT};
+  enum Direction { LEFT, RIGHT };
 
   // Returns a the single instance of a TabScrubber.
   static TabScrubber* GetInstance();
@@ -113,4 +113,4 @@
   DISALLOW_COPY_AND_ASSIGN(TabScrubber);
 };
 
-#endif  // CHROME_BROWSER_UI_VIEWS_ASH_TAB_SCRUBBER_H_
+#endif  // CHROME_BROWSER_UI_ASH_TAB_SCRUBBER_H_
diff --git a/chrome/browser/ui/views/ash/tab_scrubber_browsertest.cc b/chrome/browser/ui/ash/tab_scrubber_browsertest.cc
similarity index 96%
rename from chrome/browser/ui/views/ash/tab_scrubber_browsertest.cc
rename to chrome/browser/ui/ash/tab_scrubber_browsertest.cc
index 430ecbce..93b8726 100644
--- a/chrome/browser/ui/views/ash/tab_scrubber_browsertest.cc
+++ b/chrome/browser/ui/ash/tab_scrubber_browsertest.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 "chrome/browser/ui/views/ash/tab_scrubber.h"
+#include "chrome/browser/ui/ash/tab_scrubber.h"
 
 #include <memory>
 
@@ -80,9 +80,7 @@
 class TabScrubberTest : public InProcessBrowserTest,
                         public TabStripModelObserver {
  public:
-  TabScrubberTest()
-      : target_index_(-1) {
-  }
+  TabScrubberTest() : target_index_(-1) {}
 
   void SetUpCommandLine(base::CommandLine* command_line) override {
     command_line->AppendSwitch(chromeos::switches::kNaturalScrollDefault);
@@ -115,8 +113,8 @@
   float GetStartX(Browser* browser,
                   int index,
                   TabScrubber::Direction direction) {
-    return static_cast<float>(TabScrubber::GetStartPoint(
-        GetTabStrip(browser), index, direction).x());
+    return static_cast<float>(
+        TabScrubber::GetStartPoint(GetTabStrip(browser), index, direction).x());
   }
 
   float GetTabCenter(Browser* browser, int index) {
@@ -151,13 +149,13 @@
     aura::Window* root = window->GetRootWindow();
     ui::test::EventGenerator event_generator(root, window);
     int active_index = browser->tab_strip_model()->active_index();
-    TabScrubber::Direction direction = index < active_index ?
-        TabScrubber::LEFT : TabScrubber::RIGHT;
+    TabScrubber::Direction direction =
+        index < active_index ? TabScrubber::LEFT : TabScrubber::RIGHT;
 
     direction = InvertDirectionIfNeeded(direction);
 
     float offset = GetTabCenter(browser, index) -
-        GetStartX(browser, active_index, direction);
+                   GetStartX(browser, active_index, direction);
     ui::ScrollEvent scroll_event(ui::ET_SCROLL, gfx::Point(0, 0),
                                  ui::EventTimeForNow(), 0, offset, 0, offset, 0,
                                  3);
@@ -207,10 +205,8 @@
         last += increment;
       }
     }
-    event_generator.ScrollSequence(gfx::Point(0, 0),
-                                   base::TimeDelta::FromMilliseconds(100),
-                                   offsets,
-                                   3);
+    event_generator.ScrollSequence(
+        gfx::Point(0, 0), base::TimeDelta::FromMilliseconds(100), offsets, 3);
     RunUntilTabActive(browser, index);
   }
 
diff --git a/chrome/browser/ui/views/ash/time_to_first_present_recorder_browsertest.cc b/chrome/browser/ui/ash/time_to_first_present_recorder_browsertest.cc
similarity index 100%
rename from chrome/browser/ui/views/ash/time_to_first_present_recorder_browsertest.cc
rename to chrome/browser/ui/ash/time_to_first_present_recorder_browsertest.cc
diff --git a/chrome/browser/ui/cocoa/keystone_infobar_delegate.h b/chrome/browser/ui/cocoa/keystone_infobar_delegate.h
index 7102ea8..85f6dc0 100644
--- a/chrome/browser/ui/cocoa/keystone_infobar_delegate.h
+++ b/chrome/browser/ui/cocoa/keystone_infobar_delegate.h
@@ -5,8 +5,51 @@
 #ifndef CHROME_BROWSER_UI_COCOA_KEYSTONE_INFOBAR_DELEGATE_H_
 #define CHROME_BROWSER_UI_COCOA_KEYSTONE_INFOBAR_DELEGATE_H_
 
+#include "base/memory/weak_ptr.h"
+#include "components/infobars/core/confirm_infobar_delegate.h"
+
+class PrefService;
 class Profile;
 
+namespace content {
+class WebContents;
+}
+
+class KeystonePromotionInfoBarDelegate : public ConfirmInfoBarDelegate {
+ public:
+  // Creates a keystone promotion delegate and adds it to the InfoBarService
+  // associated with |webContents|.
+  static void Create(content::WebContents* webContents);
+
+ private:
+  explicit KeystonePromotionInfoBarDelegate(PrefService* prefs);
+  ~KeystonePromotionInfoBarDelegate() override;
+
+  // Sets this info bar to be able to expire.  Called a predetermined amount
+  // of time after this object is created.
+  void SetCanExpire() { can_expire_ = true; }
+
+  // ConfirmInfoBarDelegate
+  infobars::InfoBarDelegate::InfoBarIdentifier GetIdentifier() const override;
+  int GetIconId() const override;
+  bool ShouldExpire(const NavigationDetails& details) const override;
+  base::string16 GetMessageText() const override;
+  base::string16 GetButtonLabel(InfoBarButton button) const override;
+  bool Accept() override;
+  bool Cancel() override;
+
+  // The prefs to use.
+  PrefService* prefs_;  // weak
+
+  // Whether the info bar should be dismissed on the next navigation.
+  bool can_expire_;
+
+  // Used to delay the expiration of the info bar.
+  base::WeakPtrFactory<KeystonePromotionInfoBarDelegate> weak_ptr_factory_;
+
+  DISALLOW_COPY_AND_ASSIGN(KeystonePromotionInfoBarDelegate);
+};
+
 class KeystoneInfoBar {
  public:
   // If the application is Keystone-enabled and not on a read-only filesystem
diff --git a/chrome/browser/ui/cocoa/keystone_infobar_delegate.mm b/chrome/browser/ui/cocoa/keystone_infobar_delegate.mm
index f5d9c6e..8c809b2 100644
--- a/chrome/browser/ui/cocoa/keystone_infobar_delegate.mm
+++ b/chrome/browser/ui/cocoa/keystone_infobar_delegate.mm
@@ -11,7 +11,6 @@
 #include "base/bind.h"
 #include "base/command_line.h"
 #include "base/macros.h"
-#include "base/memory/weak_ptr.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "chrome/browser/first_run/first_run.h"
 #include "chrome/browser/infobars/infobar_service.h"
@@ -25,7 +24,6 @@
 #include "chrome/grit/chromium_strings.h"
 #include "chrome/grit/generated_resources.h"
 #include "chrome/grit/theme_resources.h"
-#include "components/infobars/core/confirm_infobar_delegate.h"
 #include "components/infobars/core/infobar.h"
 #include "components/prefs/pref_service.h"
 #include "content/public/browser/web_contents.h"
@@ -33,54 +31,11 @@
 
 class SkBitmap;
 
-namespace {
-
 // KeystonePromotionInfoBarDelegate -------------------------------------------
 
-class KeystonePromotionInfoBarDelegate : public ConfirmInfoBarDelegate {
- public:
-  // If there's an active tab, creates a keystone promotion delegate and adds it
-  // to the InfoBarService associated with that tab.
-  static void Create();
-
- private:
-  explicit KeystonePromotionInfoBarDelegate(PrefService* prefs);
-  ~KeystonePromotionInfoBarDelegate() override;
-
-  // Sets this info bar to be able to expire.  Called a predetermined amount
-  // of time after this object is created.
-  void SetCanExpire() { can_expire_ = true; }
-
-  // ConfirmInfoBarDelegate
-  infobars::InfoBarDelegate::InfoBarIdentifier GetIdentifier() const override;
-  int GetIconId() const override;
-  bool ShouldExpire(const NavigationDetails& details) const override;
-  base::string16 GetMessageText() const override;
-  base::string16 GetButtonLabel(InfoBarButton button) const override;
-  bool Accept() override;
-  bool Cancel() override;
-
-  // The prefs to use.
-  PrefService* prefs_;  // weak
-
-  // Whether the info bar should be dismissed on the next navigation.
-  bool can_expire_;
-
-  // Used to delay the expiration of the info bar.
-  base::WeakPtrFactory<KeystonePromotionInfoBarDelegate> weak_ptr_factory_;
-
-  DISALLOW_COPY_AND_ASSIGN(KeystonePromotionInfoBarDelegate);
-};
-
 // static
-void KeystonePromotionInfoBarDelegate::Create() {
-  Browser* browser = chrome::GetLastActiveBrowser();
-  if (!browser)
-    return;
-  content::WebContents* webContents =
-      browser->tab_strip_model()->GetActiveWebContents();
-  if (!webContents)
-    return;
+void KeystonePromotionInfoBarDelegate::Create(
+    content::WebContents* webContents) {
   InfoBarService* infobar_service =
       InfoBarService::FromWebContents(webContents);
   infobar_service->AddInfoBar(infobar_service->CreateConfirmInfoBar(
@@ -142,9 +97,6 @@
   return true;
 }
 
-}  // namespace
-
-
 // KeystonePromotionInfoBar ---------------------------------------------------
 
 @interface KeystonePromotionInfoBar : NSObject
@@ -213,7 +165,13 @@
 
   if (status != kAutoupdateRegisterFailed &&
       [[KeystoneGlue defaultKeystoneGlue] needsPromotion]) {
-    KeystonePromotionInfoBarDelegate::Create();
+    Browser* browser = chrome::GetLastActiveBrowser();
+    if (browser) {
+      content::WebContents* webContents =
+          browser->tab_strip_model()->GetActiveWebContents();
+      if (webContents)
+        KeystonePromotionInfoBarDelegate::Create(webContents);
+    }
   }
 
   [self release];
diff --git a/chrome/browser/ui/omnibox/chrome_omnibox_client.cc b/chrome/browser/ui/omnibox/chrome_omnibox_client.cc
index a18f852a..50522d21 100644
--- a/chrome/browser/ui/omnibox/chrome_omnibox_client.cc
+++ b/chrome/browser/ui/omnibox/chrome_omnibox_client.cc
@@ -22,6 +22,7 @@
 #include "chrome/browser/bookmarks/bookmark_stats.h"
 #include "chrome/browser/command_updater.h"
 #include "chrome/browser/extensions/api/omnibox/omnibox_api.h"
+#include "chrome/browser/favicon/favicon_service_factory.h"
 #include "chrome/browser/net/predictor.h"
 #include "chrome/browser/predictors/autocomplete_action_predictor.h"
 #include "chrome/browser/predictors/autocomplete_action_predictor_factory.h"
@@ -100,7 +101,9 @@
       profile_(profile),
       scheme_classifier_(profile),
       request_id_(BitmapFetcherService::REQUEST_ID_INVALID),
-      favicon_cache_(profile) {}
+      favicon_cache_(FaviconServiceFactory::GetForProfile(
+          profile,
+          ServiceAccessType::EXPLICIT_ACCESS)) {}
 
 ChromeOmniboxClient::~ChromeOmniboxClient() {
   BitmapFetcherService* image_service =
diff --git a/chrome/browser/ui/omnibox/favicon_cache.cc b/chrome/browser/ui/omnibox/favicon_cache.cc
index a7bee4a8..30e742dd 100644
--- a/chrome/browser/ui/omnibox/favicon_cache.cc
+++ b/chrome/browser/ui/omnibox/favicon_cache.cc
@@ -5,7 +5,6 @@
 #include "chrome/browser/ui/omnibox/favicon_cache.h"
 
 #include "base/containers/mru_cache.h"
-#include "chrome/browser/favicon/favicon_service_factory.h"
 #include "components/favicon/core/favicon_service.h"
 #include "components/omnibox/browser/autocomplete_result.h"
 
@@ -19,9 +18,9 @@
 
 }  // namespace
 
-FaviconCache::FaviconCache(Profile* profile)
-    : mru_cache_(GetFaviconCacheSize()),
-      profile_(profile),
+FaviconCache::FaviconCache(favicon::FaviconService* favicon_service)
+    : favicon_service_(favicon_service),
+      mru_cache_(GetFaviconCacheSize()),
       weak_factory_(this) {}
 
 FaviconCache::~FaviconCache() {}
@@ -35,15 +34,12 @@
 
   // We don't have the favicon in the cache. We kick off the request and return
   // an empty gfx::Image.
-  favicon::FaviconService* favicon_service =
-      FaviconServiceFactory::GetForProfile(profile_,
-                                           ServiceAccessType::EXPLICIT_ACCESS);
-  if (!favicon_service)
+  if (!favicon_service_)
     return gfx::Image();
 
   // TODO(tommycli): Investigate using the version of this method that specifies
   // the desired size.
-  favicon_service->GetFaviconImageForPageURL(
+  favicon_service_->GetFaviconImageForPageURL(
       page_url,
       base::BindRepeating(&FaviconCache::OnFaviconFetched,
                           weak_factory_.GetWeakPtr(), page_url,
diff --git a/chrome/browser/ui/omnibox/favicon_cache.h b/chrome/browser/ui/omnibox/favicon_cache.h
index 147934c..6e67ff9 100644
--- a/chrome/browser/ui/omnibox/favicon_cache.h
+++ b/chrome/browser/ui/omnibox/favicon_cache.h
@@ -12,12 +12,15 @@
 #include "base/task/cancelable_task_tracker.h"
 #include "components/favicon_base/favicon_types.h"
 
+namespace favicon {
+class FaviconService;
+}
+
 namespace gfx {
 class Image;
 }
 
 class GURL;
-class Profile;
 
 typedef base::OnceCallback<void(const gfx::Image& favicon)>
     FaviconFetchedCallback;
@@ -26,7 +29,7 @@
 // them to prevent flicker as the user types.
 class FaviconCache {
  public:
-  explicit FaviconCache(Profile* profile);
+  explicit FaviconCache(favicon::FaviconService* favicon_service);
   virtual ~FaviconCache();
 
   gfx::Image GetFaviconForPageUrl(const GURL& page_url,
@@ -37,9 +40,11 @@
                         FaviconFetchedCallback on_favicon_fetched,
                         const favicon_base::FaviconImageResult& result);
 
+  // Non-owning pointer to a KeyedService.
+  favicon::FaviconService* favicon_service_;
+
   base::CancelableTaskTracker task_tracker_;
   base::MRUCache<GURL, gfx::Image> mru_cache_;
-  Profile* profile_;
   base::WeakPtrFactory<FaviconCache> weak_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(FaviconCache);
diff --git a/chrome/browser/ui/omnibox/favicon_cache_unittest.cc b/chrome/browser/ui/omnibox/favicon_cache_unittest.cc
new file mode 100644
index 0000000..ad53ee0
--- /dev/null
+++ b/chrome/browser/ui/omnibox/favicon_cache_unittest.cc
@@ -0,0 +1,69 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/ui/omnibox/favicon_cache.h"
+
+#include "components/favicon/core/test/mock_favicon_service.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/skia/include/core/SkBitmap.h"
+#include "ui/gfx/favicon_size.h"
+
+using testing::_;
+using testing::DoAll;
+using testing::Return;
+using testing::SaveArg;
+
+namespace {
+
+favicon_base::FaviconImageResult GetDummyFaviconResult() {
+  favicon_base::FaviconImageResult result;
+
+  result.icon_url = GURL("http://example.com/favicon.ico");
+
+  SkBitmap bitmap;
+  bitmap.allocN32Pixels(gfx::kFaviconSize, gfx::kFaviconSize);
+  bitmap.eraseColor(SK_ColorBLUE);
+  result.image = gfx::Image::CreateFrom1xBitmap(bitmap);
+
+  return result;
+}
+
+void VerifyFetchedFavicon(const gfx::Image& favicon) {
+  EXPECT_FALSE(favicon.IsEmpty());
+}
+
+void ExpectNoAsyncFavicon(const gfx::Image& favicon) {
+  FAIL() << "The favicon should have been provided synchronously by the cache, "
+            "and this asynchronous callback should never have been called.";
+}
+
+}  // namespace
+
+TEST(FaviconCacheTest, Basic) {
+  GURL page_url("http://a.com/");
+  favicon_base::FaviconImageCallback service_response_callback;
+
+  testing::NiceMock<favicon::MockFaviconService> favicon_service;
+  EXPECT_CALL(favicon_service, GetFaviconImageForPageURL(page_url, _, _))
+      .WillOnce(DoAll(SaveArg<1>(&service_response_callback),
+                      Return(base::CancelableTaskTracker::kBadTaskId)));
+
+  FaviconCache cache(&favicon_service);
+  gfx::Image result = cache.GetFaviconForPageUrl(
+      page_url, base::BindOnce(&VerifyFetchedFavicon));
+
+  // Expect the synchronous result to be empty.
+  EXPECT_TRUE(result.IsEmpty());
+
+  // Simulate the favicon service returning the result.
+  service_response_callback.Run(GetDummyFaviconResult());
+
+  // Re-request the same favicon and expect a non-empty result now that the
+  // cache is populated. The above EXPECT_CALL will also verify that the
+  // backing FaviconService is not hit again.
+  result = cache.GetFaviconForPageUrl(page_url,
+                                      base::BindOnce(&ExpectNoAsyncFavicon));
+  EXPECT_FALSE(result.IsEmpty());
+}
diff --git a/chrome/browser/ui/passwords/account_avatar_fetcher.cc b/chrome/browser/ui/passwords/account_avatar_fetcher.cc
index a07a3ca..6d054f3 100644
--- a/chrome/browser/ui/passwords/account_avatar_fetcher.cc
+++ b/chrome/browser/ui/passwords/account_avatar_fetcher.cc
@@ -54,7 +54,7 @@
 
 void AccountAvatarFetcher::Start(
     content::mojom::URLLoaderFactory* loader_factory) {
-  fetcher_.Init(std::string(), blink::kWebReferrerPolicyAlways,
+  fetcher_.Init(std::string(), net::URLRequest::NEVER_CLEAR_REFERRER,
                 net::LOAD_DO_NOT_SEND_COOKIES | net::LOAD_DO_NOT_SAVE_COOKIES |
                     net::LOAD_DO_NOT_SEND_AUTH_DATA |
                     net::LOAD_MAYBE_USER_GESTURE);
diff --git a/chrome/browser/ui/startup/OWNERS b/chrome/browser/ui/startup/OWNERS
new file mode 100644
index 0000000..9a9eaea2
--- /dev/null
+++ b/chrome/browser/ui/startup/OWNERS
@@ -0,0 +1 @@
+tmartino@chromium.org
\ No newline at end of file
diff --git a/chrome/browser/ui/startup/obsolete_system_infobar_delegate.cc b/chrome/browser/ui/startup/obsolete_system_infobar_delegate.cc
index 15800640..f4f948f 100644
--- a/chrome/browser/ui/startup/obsolete_system_infobar_delegate.cc
+++ b/chrome/browser/ui/startup/obsolete_system_infobar_delegate.cc
@@ -4,26 +4,14 @@
 
 #include "chrome/browser/ui/startup/obsolete_system_infobar_delegate.h"
 
-#include "chrome/browser/browser_process.h"
 #include "chrome/browser/infobars/infobar_service.h"
 #include "chrome/browser/obsolete_system/obsolete_system.h"
-#include "chrome/common/pref_names.h"
-#include "chrome/common/url_constants.h"
 #include "components/infobars/core/infobar.h"
-#include "components/prefs/pref_service.h"
 #include "components/strings/grit/components_strings.h"
-#include "content/public/browser/web_contents.h"
 #include "ui/base/l10n/l10n_util.h"
 
 // static
 void ObsoleteSystemInfoBarDelegate::Create(InfoBarService* infobar_service) {
-  PrefService* local_state = g_browser_process->local_state();
-  if (local_state &&
-      local_state->GetBoolean(prefs::kSuppressUnsupportedOSWarning)) {
-    return;
-  }
-  if (!ObsoleteSystem::IsObsoleteNowOrSoon())
-    return;
   infobar_service->AddInfoBar(infobar_service->CreateConfirmInfoBar(
       std::unique_ptr<ConfirmInfoBarDelegate>(
           new ObsoleteSystemInfoBarDelegate())));
diff --git a/chrome/browser/ui/startup/startup_browser_creator_impl.cc b/chrome/browser/ui/startup/startup_browser_creator_impl.cc
index 18b49d4..2218238d 100644
--- a/chrome/browser/ui/startup/startup_browser_creator_impl.cc
+++ b/chrome/browser/ui/startup/startup_browser_creator_impl.cc
@@ -26,6 +26,7 @@
 #include "chrome/browser/extensions/extension_util.h"
 #include "chrome/browser/extensions/launch_util.h"
 #include "chrome/browser/infobars/infobar_service.h"
+#include "chrome/browser/obsolete_system/obsolete_system.h"
 #include "chrome/browser/prefs/session_startup_pref.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_io_data.h"
@@ -53,6 +54,7 @@
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/extensions/extension_constants.h"
 #include "chrome/common/extensions/extension_metrics.h"
+#include "chrome/common/pref_names.h"
 #include "chrome/common/url_constants.h"
 #include "components/rappor/public/rappor_utils.h"
 #include "components/rappor/rappor_service_impl.h"
@@ -792,10 +794,15 @@
       !command_line_.HasSwitch(switches::kTestType) &&
       !command_line_.HasSwitch(switches::kEnableAutomation)) {
     chrome::ShowBadFlagsPrompt(browser);
-    GoogleApiKeysInfoBarDelegate::Create(InfoBarService::FromWebContents(
-        browser->tab_strip_model()->GetActiveWebContents()));
-    ObsoleteSystemInfoBarDelegate::Create(InfoBarService::FromWebContents(
-        browser->tab_strip_model()->GetActiveWebContents()));
+    InfoBarService* infobar_service = InfoBarService::FromWebContents(
+        browser->tab_strip_model()->GetActiveWebContents());
+    GoogleApiKeysInfoBarDelegate::Create(infobar_service);
+    if (ObsoleteSystem::IsObsoleteNowOrSoon()) {
+      PrefService* local_state = g_browser_process->local_state();
+      if (!local_state ||
+          !local_state->GetBoolean(prefs::kSuppressUnsupportedOSWarning))
+        ObsoleteSystemInfoBarDelegate::Create(infobar_service);
+    }
 
 #if !defined(OS_CHROMEOS)
     if (!command_line_.HasSwitch(switches::kNoDefaultBrowserCheck)) {
diff --git a/chrome/browser/ui/views/ash/OWNERS b/chrome/browser/ui/views/ash/OWNERS
deleted file mode 100644
index 28ae752..0000000
--- a/chrome/browser/ui/views/ash/OWNERS
+++ /dev/null
@@ -1,6 +0,0 @@
-derat@chromium.org
-sky@chromium.org
-jamescook@chromium.org
-erg@chromium.org
-
-# COMPONENT: UI>Shell
diff --git a/chrome/browser/ui/views/passwords/manage_password_items_view.cc b/chrome/browser/ui/views/passwords/manage_password_items_view.cc
index b7ff76bf..3dad6b95 100644
--- a/chrome/browser/ui/views/passwords/manage_password_items_view.cc
+++ b/chrome/browser/ui/views/passwords/manage_password_items_view.cc
@@ -119,12 +119,13 @@
 
 std::unique_ptr<views::Label> CreatePasswordLabel(
     const autofill::PasswordForm& form,
+    int federation_message_id,
     bool is_password_visible) {
   base::string16 text =
       form.federation_origin.unique()
           ? form.password_value
           : l10n_util::GetStringFUTF16(
-                IDS_PASSWORD_MANAGER_SIGNIN_VIA_FEDERATION,
+                federation_message_id,
                 base::UTF8ToUTF16(form.federation_origin.host()));
   auto label = std::make_unique<views::Label>(text, CONTEXT_BODY_TEXT_LARGE,
                                               STYLE_SECONDARY);
@@ -193,7 +194,7 @@
   std::unique_ptr<views::Label> username_label =
       CreateUsernameLabel(*password_form_);
   std::unique_ptr<views::Label> password_label =
-      CreatePasswordLabel(*password_form_, false);
+      CreatePasswordLabel(*password_form_, IDS_PASSWORDS_VIA_FEDERATION, false);
   std::unique_ptr<views::ImageButton> delete_button =
       CreateDeleteButton(this, GetDisplayUsername(*password_form_));
   StartRow(layout, PASSWORD_COLUMN_SET);
diff --git a/chrome/browser/ui/views/passwords/manage_password_items_view.h b/chrome/browser/ui/views/passwords/manage_password_items_view.h
index 6dddcb4..81604f22 100644
--- a/chrome/browser/ui/views/passwords/manage_password_items_view.h
+++ b/chrome/browser/ui/views/passwords/manage_password_items_view.h
@@ -25,6 +25,7 @@
     const autofill::PasswordForm& form);
 std::unique_ptr<views::Label> CreatePasswordLabel(
     const autofill::PasswordForm& form,
+    int federation_message_id,
     bool is_password_visible);
 std::unique_ptr<views::Textfield> CreateUsernameEditable(
     const autofill::PasswordForm& form);
diff --git a/chrome/browser/ui/views/passwords/manage_passwords_bubble_view.cc b/chrome/browser/ui/views/passwords/manage_passwords_bubble_view.cc
index 72e9b466..8cb3a39 100644
--- a/chrome/browser/ui/views/passwords/manage_passwords_bubble_view.cc
+++ b/chrome/browser/ui/views/passwords/manage_passwords_bubble_view.cc
@@ -589,7 +589,10 @@
     password_dropdown_ = CreatePasswordDropdownView(password_form).release();
   } else {
     password_label_ =
-        CreatePasswordLabel(password_form, password_visible_).release();
+        CreatePasswordLabel(password_form,
+                            IDS_PASSWORD_MANAGER_SIGNIN_VIA_FEDERATION,
+                            password_visible_)
+            .release();
   }
 }
 
@@ -815,10 +818,13 @@
   } else {
     const autofill::PasswordForm& password_form =
         parent_->model()->pending_password();
-    BuildCredentialRows(layout, CreateUsernameLabel(password_form).release(),
-                        CreatePasswordLabel(password_form, false).release(),
-                        nullptr, /* password_view_button */
-                        true /* show_password_label */);
+    BuildCredentialRows(
+        layout, CreateUsernameLabel(password_form).release(),
+        CreatePasswordLabel(password_form,
+                            IDS_PASSWORD_MANAGER_SIGNIN_VIA_FEDERATION, false)
+            .release(),
+        nullptr, /* password_view_button */
+        true /* show_password_label */);
   }
   layout->AddPaddingRow(
       0, layout_provider->GetDistanceMetric(
diff --git a/chrome/browser/ui/webui/discards/discards.mojom b/chrome/browser/ui/webui/discards/discards.mojom
index c06e60c..c1be52bd 100644
--- a/chrome/browser/ui/webui/discards/discards.mojom
+++ b/chrome/browser/ui/webui/discards/discards.mojom
@@ -13,15 +13,9 @@
   string favicon_url;
   // The title of the tab, as displayed on the tab itself.
   string title;
-  // If the tab corresponds to a Chrome App, this is true.
-  bool is_app;
-  // If the tab corresponds to internal Chrome WebUI, this is true.
-  bool is_internal;
   // If the tab is currently using media functionality (casting, WebRTC, playing
   // audio, etc) this is true.
   bool is_media;
-  // If the tab is pinned in its TabStripModel, this is true.
-  bool is_pinned;
   // If the tab is currently discarded, this is true.
   bool is_discarded;
   // The number of times this tab has been discarded in the current browser
diff --git a/chrome/browser/ui/webui/discards/discards_ui.cc b/chrome/browser/ui/webui/discards/discards_ui.cc
index 3c25b72..d237795 100644
--- a/chrome/browser/ui/webui/discards/discards_ui.cc
+++ b/chrome/browser/ui/webui/discards/discards_ui.cc
@@ -62,10 +62,7 @@
       // showing the chrome://favicon default in that case.
       info->favicon_url = tab.favicon_url;
       info->title = base::UTF16ToUTF8(tab.title);
-      info->is_app = tab.is_app;
-      info->is_internal = tab.is_internal_page;
       info->is_media = tab.is_media;
-      info->is_pinned = tab.is_pinned;
       info->is_discarded = tab.is_discarded;
       info->discard_count = tab.discard_count;
       info->utility_rank = rank++;
diff --git a/chrome/browser/vr/BUILD.gn b/chrome/browser/vr/BUILD.gn
index df58521c..feb34bb 100644
--- a/chrome/browser/vr/BUILD.gn
+++ b/chrome/browser/vr/BUILD.gn
@@ -245,6 +245,7 @@
     "animation_player_unittest.cc",
     "databinding/binding_unittest.cc",
     "databinding/vector_binding_unittest.cc",
+    "elements/button_unittest.cc",
     "elements/disc_button_unittest.cc",
     "elements/exit_prompt_unittest.cc",
     "elements/linear_layout_unittest.cc",
diff --git a/chrome/browser/vr/elements/button.cc b/chrome/browser/vr/elements/button.cc
index 5abc191..4dcf8a9 100644
--- a/chrome/browser/vr/elements/button.cc
+++ b/chrome/browser/vr/elements/button.cc
@@ -97,6 +97,10 @@
 
 void Button::OnStateUpdated() {
   pressed_ = hovered_ ? down_ : false;
+  background_->SetColor(colors_.GetBackgroundColor(hovered_, pressed_));
+
+  if (hover_offset_ == 0.0f)
+    return;
 
   if (hovered()) {
     background_->SetTranslate(0.0, 0.0, hover_offset_);
@@ -106,7 +110,6 @@
     background_->SetTranslate(0.0, 0.0, 0.0);
     hit_plane_->SetScale(1.0f, 1.0f, 1.0f);
   }
-  background_->SetColor(colors_.GetBackgroundColor(hovered_, pressed_));
 }
 
 void Button::OnSetDrawPhase() {
diff --git a/chrome/browser/vr/elements/button_unittest.cc b/chrome/browser/vr/elements/button_unittest.cc
new file mode 100644
index 0000000..534679a
--- /dev/null
+++ b/chrome/browser/vr/elements/button_unittest.cc
@@ -0,0 +1,28 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/vr/elements/button.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace vr {
+
+TEST(Button, Hover) {
+  base::RepeatingCallback<void()> callback;
+  Button button(callback);
+  button.set_hover_offset(0.0f);
+  button.SetSize(1.0f, 1.0f);
+
+  gfx::Transform xform = button.hit_plane()->LocalTransform();
+
+  button.OnHoverEnter(gfx::PointF(0.5f, 0.5f));
+  EXPECT_EQ(xform.ToString(), button.hit_plane()->LocalTransform().ToString());
+  button.OnHoverLeave();
+
+  button.set_hover_offset(0.04f);
+  button.OnHoverEnter(gfx::PointF(0.5f, 0.5f));
+  EXPECT_NE(xform.ToString(), button.hit_plane()->LocalTransform().ToString());
+}
+
+}  // namespace vr
diff --git a/chrome/browser/vr/elements/environment/background.cc b/chrome/browser/vr/elements/environment/background.cc
index 2455a38..b887a6e 100644
--- a/chrome/browser/vr/elements/environment/background.cc
+++ b/chrome/browser/vr/elements/environment/background.cc
@@ -29,15 +29,27 @@
 
   void main() {
     vec4 sphereVertex;
+    // The x coordinate maps linearly to yaw, so we just need to scale the input
+    // range 0..1 to 0..2*pi.
     float theta = a_TexCoordinate.x * 6.28319;
-    float phi = a_TexCoordinate.y * 3.14159;
+
+    // The projection we use maps the y axis of the source image to sphere
+    // altitude, not the pitch. If it were pitch, we would scale the y
+    // coordinates from 0..1 to 0..pi, where 0 corresponds to the head pointing
+    // straight down and pi is the head pointing straight up. But, if our source
+    // is altitude, then we've roughly been given the cosine of the pitch - we
+    // just need to remap the range 0..1 to 1..-1. And because the sine of the
+    // pitch angle is always positive, we can easily compute it using the
+    // sin^2(x) + cos^2(x) = 1 identity without worrying about sign.
+    float cos_phi = 1.0 - 2.0 * a_TexCoordinate.y;
+    float sin_phi = sqrt(1.0 - cos_phi * cos_phi);
 
     // Place the background at 1000 m, an arbitrary large distance. This
     // nullifies the translational portion of eye transforms, which is what we
     // want for ODS backgrounds.
-    sphereVertex.x = 1000. * -cos(theta) * sin(phi);
-    sphereVertex.y = 1000. * cos(phi);
-    sphereVertex.z = 1000. * -sin(theta) * sin(phi);
+    sphereVertex.x = 1000. * -cos(theta) * sin_phi;
+    sphereVertex.y = 1000. * cos_phi;
+    sphereVertex.z = 1000. * -sin(theta) * sin_phi;
     sphereVertex.w = 1.0;
 
     gl_Position = u_ModelViewProjMatrix * sphereVertex;
diff --git a/chrome/common/pref_names.cc b/chrome/common/pref_names.cc
index a80f848f..d4def242 100644
--- a/chrome/common/pref_names.cc
+++ b/chrome/common/pref_names.cc
@@ -594,25 +594,6 @@
 // A string pref that contains version where "What's new" promo was shown.
 const char kChromeOSReleaseNotesVersion[] = "settings.release_notes.version";
 
-// Power state of the current displays from the last run.
-const char kDisplayPowerState[] = "settings.display.power_state";
-// A dictionary pref that stores per display preferences.
-const char kDisplayProperties[] = "settings.display.properties";
-// A dictionary pref that stores the touch associations for the device.
-const char kDisplayTouchAssociations[] = "settings.display.touch_associations";
-// A list pref that stores the mirror info for each external display.
-const char kExternalDisplayMirrorInfo[] =
-    "settings.display.external_display_mirror_info";
-
-// A dictionary pref that specifies per-display layout/offset information.
-// Its key is the ID of the display and its value is a dictionary for the
-// layout/offset information.
-const char kSecondaryDisplays[] = "settings.display.secondary_displays";
-
-// A dictionary pref that specifies the state of the rotation lock, and the
-// display orientation, for the internal display.
-const char kDisplayRotationLock[] = "settings.display.rotation_lock";
-
 // A string pref that contains either a Chrome app ID (see
 // extensions::ExtensionId) or an Android package name (using Java package
 // naming conventions) of the preferred note-taking app. An empty value
diff --git a/chrome/common/pref_names.h b/chrome/common/pref_names.h
index 19ff2e4..1711e89 100644
--- a/chrome/common/pref_names.h
+++ b/chrome/common/pref_names.h
@@ -218,12 +218,6 @@
 extern const char kShow3gPromoNotification[];
 extern const char kDataSaverPromptsShown[];
 extern const char kChromeOSReleaseNotesVersion[];
-extern const char kDisplayPowerState[];
-extern const char kDisplayProperties[];
-extern const char kDisplayTouchAssociations[];
-extern const char kExternalDisplayMirrorInfo[];
-extern const char kSecondaryDisplays[];
-extern const char kDisplayRotationLock[];
 extern const char kNoteTakingAppId[];
 extern const char kNoteTakingAppEnabledOnLockScreen[];
 extern const char kNoteTakingAppsLockScreenWhitelist[];
diff --git a/chrome/installer/zucchini/zucchini_main.cc b/chrome/installer/zucchini/zucchini_main.cc
index 170e814..d3a27b14 100644
--- a/chrome/installer/zucchini/zucchini_main.cc
+++ b/chrome/installer/zucchini/zucchini_main.cc
@@ -46,7 +46,9 @@
   InitErrorHandling(command_line);
   zucchini::status::Code status =
       RunZucchiniCommand(command_line, std::cout, std::cerr);
-  if (status != zucchini::status::kStatusSuccess)
+  if (!(status == zucchini::status::kStatusSuccess ||
+        status == zucchini::status::kStatusInvalidParam)) {
     std::cerr << "Failed with code " << static_cast<int>(status) << std::endl;
+  }
   return static_cast<int>(status);
 }
diff --git a/chrome/renderer/autofill/password_autofill_agent_browsertest.cc b/chrome/renderer/autofill/password_autofill_agent_browsertest.cc
index 8591c01..b24e895a 100644
--- a/chrome/renderer/autofill/password_autofill_agent_browsertest.cc
+++ b/chrome/renderer/autofill/password_autofill_agent_browsertest.cc
@@ -28,7 +28,6 @@
 #include "components/password_manager/core/common/password_manager_features.h"
 #include "content/public/renderer/render_frame.h"
 #include "content/public/renderer/render_view.h"
-#include "content/public/test/browser_test_utils.h"
 #include "services/service_manager/public/cpp/interface_provider.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/WebKit/common/associated_interfaces/associated_interface_provider.h"
@@ -427,14 +426,12 @@
       const base::string16& password) {
     // This call is necessary to setup the autofill agent appropriate for the
     // user selection; simulates the menu actually popping up.
-    SimulatePointClick(gfx::Point(1, 1));
     autofill_agent_->FormControlElementClicked(input, false);
 
     autofill_agent_->FillPasswordSuggestion(username, password);
   }
 
   void SimulateUsernameTyping(const std::string& username) {
-    SimulatePointClick(gfx::Point(1, 1));
     SimulateUserInputChangeForElement(&username_element_, username);
   }
 
@@ -488,10 +485,10 @@
 
   // Checks the DOM-accessible value of the username element and the
   // *suggested* value of the password element.
-  void CheckUsernameDOMStatePasswordSuggestedState(const std::string& username,
-                                                   bool username_autofilled,
-                                                   const std::string& password,
-                                                   bool password_autofilled) {
+  void CheckTextFieldsState(const std::string& username,
+                            bool username_autofilled,
+                            const std::string& password,
+                            bool password_autofilled) {
     CheckTextFieldsStateForElements(
         username_element_, username, username_autofilled, password_element_,
         password, password_autofilled, false /* check_suggested_username */,
@@ -730,7 +727,7 @@
   SimulateOnFillPasswordForm(fill_data_);
 
   // The username and password should have been autocompleted.
-  CheckTextFieldsSuggestedState(kAliceUsername, true, kAlicePassword, true);
+  CheckTextFieldsState(kAliceUsername, true, kAlicePassword, true);
 }
 
 // Tests that we correctly fill forms having an empty 'action' attribute.
@@ -755,7 +752,7 @@
   SimulateOnFillPasswordForm(fill_data_);
 
   // The username and password should have been autocompleted.
-  CheckTextFieldsSuggestedState(kAliceUsername, true, kAlicePassword, true);
+  CheckTextFieldsState(kAliceUsername, true, kAlicePassword, true);
 }
 
 // Tests that if a password is marked as readonly, neither field is autofilled
@@ -767,7 +764,7 @@
   // autocomplete.
   SimulateOnFillPasswordForm(fill_data_);
 
-  CheckTextFieldsSuggestedState(std::string(), false, std::string(), false);
+  CheckTextFieldsState(std::string(), false, std::string(), false);
 }
 
 // Can still fill a password field if the username is set to a value that
@@ -779,8 +776,8 @@
 
   // Filled even though username is not the preferred match.
   SimulateOnFillPasswordForm(fill_data_);
-  CheckUsernameDOMStatePasswordSuggestedState(UTF16ToUTF8(username3_), false,
-                                              UTF16ToUTF8(password3_), true);
+  CheckTextFieldsState(UTF16ToUTF8(username3_), false,
+                       UTF16ToUTF8(password3_), true);
 }
 
 // Fill a password field if the stored username is a prefix of username in
@@ -794,8 +791,8 @@
   // Filled even though the username in the form is only a proper prefix of the
   // stored username.
   SimulateOnFillPasswordForm(fill_data_);
-  CheckUsernameDOMStatePasswordSuggestedState(UTF16ToUTF8(username_at), false,
-                                              UTF16ToUTF8(password3_), true);
+  CheckTextFieldsState(UTF16ToUTF8(username_at), false, UTF16ToUTF8(password3_),
+                       true);
 }
 
 // Do not fill a password field if the stored username is a prefix without @
@@ -810,8 +807,8 @@
   // Filled even though the username in the form is only a proper prefix of the
   // stored username.
   SimulateOnFillPasswordForm(fill_data_);
-  CheckUsernameDOMStatePasswordSuggestedState(UTF16ToUTF8(prefilled_username),
-                                              false, std::string(), false);
+  CheckTextFieldsState(UTF16ToUTF8(prefilled_username), false, std::string(),
+                       false);
 }
 
 // Do not fill a password field if the field isn't readonly despite the stored
@@ -826,8 +823,8 @@
   // Filled even though the username in the form is only a proper prefix of the
   // stored username.
   SimulateOnFillPasswordForm(fill_data_);
-  CheckUsernameDOMStatePasswordSuggestedState(UTF16ToUTF8(prefilled_username),
-                                              false, std::string(), false);
+  CheckTextFieldsState(UTF16ToUTF8(prefilled_username), false, std::string(),
+                       false);
 }
 
 // If a username field is empty and readonly, don't autofill.
@@ -837,8 +834,7 @@
   SetElementReadOnly(username_element_, true);
 
   SimulateOnFillPasswordForm(fill_data_);
-  CheckUsernameDOMStatePasswordSuggestedState(std::string(), false,
-                                              std::string(), false);
+  CheckTextFieldsState(std::string(), false, std::string(), false);
 }
 
 // Tests that having a non-matching username precludes the autocomplete.
@@ -850,8 +846,7 @@
   SimulateOnFillPasswordForm(fill_data_);
 
   // Neither field should be autocompleted.
-  CheckUsernameDOMStatePasswordSuggestedState("bogus", false, std::string(),
-                                              false);
+  CheckTextFieldsState("bogus", false, std::string(), false);
 }
 
 // Don't try to complete a prefilled value even if it's a partial match
@@ -861,9 +856,7 @@
 
   SimulateOnFillPasswordForm(fill_data_);
 
-  CheckTextFieldsSuggestedState("", false, std::string(), false);
-  CheckUsernameDOMStatePasswordSuggestedState("ali", false, std::string(),
-                                              false);
+  CheckTextFieldsState("ali", false, std::string(), false);
 }
 
 TEST_F(PasswordAutofillAgentTest, InputWithNoForms) {
@@ -875,7 +868,7 @@
   SimulateOnFillPasswordForm(fill_data_);
 
   // Input elements that aren't in a <form> won't autofill.
-  CheckTextFieldsSuggestedState(std::string(), false, std::string(), false);
+  CheckTextFieldsState(std::string(), false, std::string(), false);
 }
 
 TEST_F(PasswordAutofillAgentTest, NoAutocompleteForTextFieldPasswords) {
@@ -896,7 +889,7 @@
   SimulateOnFillPasswordForm(fill_data_);
 
   // Fields should still be empty.
-  CheckTextFieldsSuggestedState(std::string(), false, std::string(), false);
+  CheckTextFieldsState(std::string(), false, std::string(), false);
 }
 
 TEST_F(PasswordAutofillAgentTest, NoAutocompleteForPasswordFieldUsernames) {
@@ -917,7 +910,7 @@
   SimulateOnFillPasswordForm(fill_data_);
 
   // Fields should still be empty.
-  CheckTextFieldsSuggestedState(std::string(), false, std::string(), false);
+  CheckTextFieldsState(std::string(), false, std::string(), false);
 }
 
 // Tests that having a matching username does not preclude the autocomplete.
@@ -929,8 +922,7 @@
   SimulateOnFillPasswordForm(fill_data_);
 
   // The username and password should have been autocompleted.
-  CheckUsernameDOMStatePasswordSuggestedState(kAliceUsername, true,
-                                              kAlicePassword, true);
+  CheckTextFieldsState(kAliceUsername, true, kAlicePassword, true);
 }
 
 TEST_F(PasswordAutofillAgentTest, PasswordNotClearedOnEdit) {
@@ -953,15 +945,14 @@
   SimulateOnFillPasswordForm(fill_data_);
 
   // No auto-fill should have taken place.
-  CheckTextFieldsSuggestedState(std::string(), false, std::string(), false);
+  CheckTextFieldsState(std::string(), false, std::string(), false);
 
   SimulateUsernameTyping(kAliceUsername);
   // Change focus in between to make sure blur events don't trigger filling.
   SetFocused(password_element_);
   SetFocused(username_element_);
   // No autocomplete should happen when text is entered in the username.
-  CheckUsernameDOMStatePasswordSuggestedState(kAliceUsername, false,
-                                              std::string(), false);
+  CheckTextFieldsState(kAliceUsername, false, std::string(), false);
 }
 
 TEST_F(PasswordAutofillAgentTest, IsWebElementVisibleTest) {
@@ -1144,12 +1135,12 @@
   SimulateOnFillPasswordForm(fill_data_);
 
   // The username and password should have been autocompleted.
-  CheckTextFieldsSuggestedState(kAliceUsername, true, kAlicePassword, true);
+  CheckTextFieldsState(kAliceUsername, true, kAlicePassword, true);
 
   // However, it should only have completed with the suggested value, as tested
   // above, and it should not have completed into the DOM accessible value for
   // the password field.
-  CheckTextFieldsDOMState(std::string(), true, std::string(), true);
+  CheckTextFieldsDOMState(kAliceUsername, true, std::string(), true);
 
   // Simulate a user click so that the password field's real value is filled.
   SimulateElementClick(kUsernameName);
@@ -1162,7 +1153,7 @@
   SimulateOnFillPasswordForm(fill_data_);
 
   ExecuteJavaScriptForTests(kJavaScriptClick);
-  CheckTextFieldsDOMState("", true, "", true);
+  CheckTextFieldsDOMState(kAliceUsername, true, "", true);
 }
 
 // Verifies that password autofill triggers events in JavaScript for forms that
@@ -1184,22 +1175,21 @@
   SimulateOnFillPasswordForm(fill_data_);
 
   // The username and password should have been autocompleted...
-  CheckTextFieldsSuggestedState(kAliceUsername, true, kAlicePassword, true);
+  CheckTextFieldsState(kAliceUsername, true, kAlicePassword, true);
   // ... but since there hasn't been a user gesture yet, the autocompleted
-  // username and password should only be visible to the user.
-  CheckTextFieldsDOMState(std::string(), true, std::string(), true);
+  // password should only be visible to the user.
+  CheckTextFieldsDOMState(kAliceUsername, true, std::string(), true);
 
-  // JavaScript events shouldn't have been triggered for the username and the
-  // password yet.
-  CheckIfEventsAreCalled(username_event_checkers, false);
+  // JavaScript events should have been triggered for the username, but not yet
+  // for the password.
+  CheckIfEventsAreCalled(username_event_checkers, true);
   CheckIfEventsAreCalled(password_event_checkers, false);
 
   // Simulate a user click so that the password field's real value is filled.
   SimulateElementClick(kUsernameName);
   CheckTextFieldsDOMState(kAliceUsername, true, kAlicePassword, true);
 
-  // Now, JavaScript events should have been triggered.
-  CheckIfEventsAreCalled(username_event_checkers, true);
+  // Now, JavaScript events should have been triggered for the password as well.
   CheckIfEventsAreCalled(password_event_checkers, true);
 }
 
@@ -1222,7 +1212,7 @@
   SimulateOnFillPasswordForm(fill_data_);
 
   // The username and password should not yet have been autocompleted.
-  CheckTextFieldsSuggestedState(std::string(), false, std::string(), false);
+  CheckTextFieldsState(std::string(), false, std::string(), false);
 
   // Simulate a click just to force a user gesture, since the username value is
   // set directly.
@@ -1829,8 +1819,7 @@
   // The username should not be autofilled, because it was typed by the user.
   CheckTextFieldsDOMState(old_username, false, new_password, false);
   // The password should not have a suggested value.
-  CheckUsernameDOMStatePasswordSuggestedState(old_username, false,
-                                              std::string(), false);
+  CheckTextFieldsState(old_username, false, std::string(), false);
 }
 
 // The user types the username, then accepts a suggestion. This test checks
@@ -1883,9 +1872,9 @@
 
   std::map<base::string16, FieldPropertiesMask> expected_properties_masks;
   expected_properties_masks[ASCIIToUTF16("random_field")] =
-      FieldPropertiesFlags::HAD_FOCUS;
+      FieldPropertiesFlags::NO_FLAGS;
   expected_properties_masks[ASCIIToUTF16("username")] =
-      FieldPropertiesFlags::USER_TYPED | FieldPropertiesFlags::HAD_FOCUS;
+      FieldPropertiesFlags::USER_TYPED;
   expected_properties_masks[ASCIIToUTF16("password")] =
       FieldPropertiesFlags::USER_TYPED | FieldPropertiesFlags::HAD_FOCUS;
 
@@ -1910,7 +1899,7 @@
 
   std::map<base::string16, FieldPropertiesMask> expected_properties_masks;
   expected_properties_masks[ASCIIToUTF16("username")] =
-      FieldPropertiesFlags::USER_TYPED | FieldPropertiesFlags::HAD_FOCUS;
+      FieldPropertiesFlags::USER_TYPED;
   expected_properties_masks[ASCIIToUTF16("password")] =
       FieldPropertiesFlags::USER_TYPED | FieldPropertiesFlags::HAD_FOCUS;
 
@@ -1938,7 +1927,7 @@
 
   std::map<base::string16, FieldPropertiesMask> expected_properties_masks;
   expected_properties_masks[ASCIIToUTF16("username")] =
-      FieldPropertiesFlags::USER_TYPED | FieldPropertiesFlags::HAD_FOCUS;
+      FieldPropertiesFlags::USER_TYPED;
   expected_properties_masks[ASCIIToUTF16("password")] =
       FieldPropertiesFlags::USER_TYPED | FieldPropertiesFlags::HAD_FOCUS;
 
@@ -2037,7 +2026,7 @@
   SimulateOnFillPasswordForm(no_username_fill_data);
 
   // The username and password should not have been autocompleted.
-  CheckTextFieldsSuggestedState("", false, "", false);
+  CheckTextFieldsState("", false, "", false);
 }
 
 TEST_F(PasswordAutofillAgentTest, FillOnAccountSelectOnly) {
@@ -2048,7 +2037,7 @@
   // Simulate the browser sending back the login info for an initial page load.
   SimulateOnShowInitialPasswordAccountSuggestions(fill_data_);
 
-  CheckTextFieldsSuggestedState(std::string(), false, std::string(), false);
+  CheckTextFieldsState(std::string(), false, std::string(), false);
   CheckSuggestions(std::string(), true);
 }
 
@@ -2063,8 +2052,7 @@
   // Simulate the browser sending back the login info for an initial page load.
   SimulateOnShowInitialPasswordAccountSuggestions(fill_data_);
 
-  CheckUsernameDOMStatePasswordSuggestedState(std::string("alice"), false,
-                                              std::string(), false);
+  CheckTextFieldsState(std::string("alice"), false, std::string(), false);
 }
 
 TEST_F(PasswordAutofillAgentTest,
@@ -2079,8 +2067,7 @@
   // Simulate the browser sending back the login info for an initial page load.
   SimulateOnShowInitialPasswordAccountSuggestions(fill_data_);
 
-  CheckUsernameDOMStatePasswordSuggestedState(std::string("Carol"), false,
-                                              std::string(), false);
+  CheckTextFieldsState(std::string("Carol"), false, std::string(), false);
 }
 
 TEST_F(PasswordAutofillAgentTest, FillOnAccountSelectOnlyNoUsername) {
@@ -2194,8 +2181,7 @@
   username_element_.SetValue("foobar");
   SetElementReadOnly(username_element_, true);
 
-  CheckUsernameDOMStatePasswordSuggestedState(std::string("foobar"), false,
-                                              std::string(), false);
+  CheckTextFieldsState(std::string("foobar"), false, std::string(), false);
 }
 
 // Test that the last plain text field before a password field is chosen as a
@@ -2474,7 +2460,7 @@
   fill_data_.additional_logins.clear();
   SimulateOnFillPasswordForm(fill_data_);
 
-  CheckTextFieldsSuggestedState("", false, kAlicePassword, true);
+  CheckTextFieldsState("", false, kAlicePassword, true);
 }
 
 // Tests that both the username and the password fields are autocompleted
@@ -2486,7 +2472,7 @@
   ASSERT_FALSE(fill_data_.additional_logins.empty());
   SimulateOnFillPasswordForm(fill_data_);
 
-  CheckTextFieldsSuggestedState("", true, kAlicePassword, true);
+  CheckTextFieldsState("", true, kAlicePassword, true);
 }
 
 TEST_F(PasswordAutofillAgentTest, NoForm_PromptForAJAXSubmitWithoutNavigation) {
@@ -3129,7 +3115,7 @@
   SimulateOnFillPasswordForm(fill_data_);
 
   // The username and password should have been autocompleted.
-  CheckTextFieldsSuggestedState(kAliceUsername, true, kAlicePassword, true);
+  CheckTextFieldsState(kAliceUsername, true, kAlicePassword, true);
 }
 
 // Regression test for https://crbug.com/728028.
@@ -3313,15 +3299,14 @@
   // Supply old fill data
   password_autofill_agent_->FillPasswordForm(0, fill_data_);
   // The username and password should have been autocompleted.
-  CheckTextFieldsSuggestedState(kAliceUsername, true, kAlicePassword, true);
+  CheckTextFieldsState(kAliceUsername, true, kAlicePassword, true);
 
   // Change fill data
   fill_data_.password_field.value = ASCIIToUTF16("a-changed-password");
   // Supply changed fill data
   password_autofill_agent_->FillPasswordForm(1 /* New key means new data */,
                                              fill_data_);
-  CheckTextFieldsSuggestedState(kAliceUsername, true, "a-changed-password",
-                                true);
+  CheckTextFieldsState(kAliceUsername, true, "a-changed-password", true);
 }
 
 TEST_F(PasswordAutofillAgentTest, SuggestLatestCredentials) {
diff --git a/chrome/renderer/media/DEPS b/chrome/renderer/media/DEPS
index 0e86e5c..83e7d84 100644
--- a/chrome/renderer/media/DEPS
+++ b/chrome/renderer/media/DEPS
@@ -4,4 +4,5 @@
   "+media/base",  # For basic media functions.
   "+media/cast",  # For cast streaming library.
   "+media/capture",  # For capture library.
+  "+media/mojo/interfaces",  # For mojo interfaces.
 ]
diff --git a/chrome/renderer/media/chrome_key_systems.cc b/chrome/renderer/media/chrome_key_systems.cc
index 57943e8..f3033337 100644
--- a/chrome/renderer/media/chrome_key_systems.cc
+++ b/chrome/renderer/media/chrome_key_systems.cc
@@ -14,7 +14,6 @@
 #include "base/strings/string_split.h"
 #include "base/strings/utf_string_conversions.h"
 #include "build/build_config.h"
-#include "chrome/renderer/chrome_content_renderer_client.h"
 #include "chrome/renderer/chrome_render_thread_observer.h"
 #include "components/cdm/renderer/external_clear_key_key_system_properties.h"
 #include "components/cdm/renderer/widevine_key_system_properties.h"
@@ -29,7 +28,9 @@
 
 #if BUILDFLAG(ENABLE_LIBRARY_CDMS)
 #include "base/feature_list.h"
+#include "content/public/renderer/key_system_support.h"
 #include "media/base/media_switches.h"
+#include "media/base/video_codecs.h"
 #endif
 
 #include "widevine_cdm_version.h" // In SHARED_INTERMEDIATE_DIR.
@@ -41,31 +42,12 @@
 #include "base/version.h"
 #endif
 
-using content::WebPluginMimeType;
 using media::EmeFeatureSupport;
 using media::EmeSessionTypeSupport;
 using media::KeySystemProperties;
 using media::SupportedCodecs;
 
 #if BUILDFLAG(ENABLE_LIBRARY_CDMS)
-static bool IsPepperCdmAvailable(
-    const std::string& pepper_type,
-    std::vector<WebPluginMimeType::Param>* additional_params) {
-  base::Optional<std::vector<chrome::mojom::PluginParamPtr>>
-      opt_additional_params;
-  ChromeContentRendererClient::GetPluginInfoHost()
-      ->IsInternalPluginAvailableForMimeType(pepper_type,
-                                             &opt_additional_params);
-
-  if (opt_additional_params) {
-    for (auto& p : *opt_additional_params) {
-      additional_params->emplace_back(p->name, p->value);
-    }
-
-    return true;
-  }
-  return false;
-}
 
 // External Clear Key (used for testing).
 static void AddExternalClearKey(
@@ -97,9 +79,11 @@
   static const char kExternalClearKeyCdmProxyTestKeySystem[] =
       "org.chromium.externalclearkey.cdmproxytest";
 
-  std::vector<WebPluginMimeType::Param> additional_params;
-  if (!IsPepperCdmAvailable(cdm::kExternalClearKeyPepperType,
-                            &additional_params)) {
+  std::vector<media::VideoCodec> supported_video_codecs;
+  bool supports_persistent_license;
+  if (!content::IsKeySystemSupported(kExternalClearKeyKeySystem,
+                                     &supported_video_codecs,
+                                     &supports_persistent_license)) {
     return;
   }
 
@@ -154,44 +138,6 @@
 }
 
 #if defined(WIDEVINE_CDM_AVAILABLE)
-// This function finds "codecs" and parses the value into the vector |codecs|.
-// Converts the codec strings to UTF-8 since we only expect ASCII strings and
-// this simplifies the rest of the code in this file.
-void GetSupportedCodecsForPepperCdm(
-    const std::vector<WebPluginMimeType::Param>& additional_params,
-    std::vector<std::string>* codecs) {
-  DCHECK(codecs->empty());
-  for (const auto& p : additional_params) {
-    if (p.name == base::ASCIIToUTF16(kCdmSupportedCodecsParamName)) {
-      const base::string16& codecs_string16 = p.value;
-      std::string codecs_string;
-      if (!base::UTF16ToUTF8(codecs_string16.c_str(),
-                             codecs_string16.length(),
-                             &codecs_string)) {
-        DLOG(WARNING) << "Non-UTF-8 codecs string.";
-        // Continue using the best effort conversion.
-      }
-      *codecs = base::SplitString(
-          codecs_string, std::string(1, kCdmSupportedCodecsValueDelimiter),
-          base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
-      break;
-    }
-  }
-}
-
-// Whether persistent-license session is supported by the CDM.
-bool IsPersistentLicenseSupportedbyCdm(
-    const std::vector<WebPluginMimeType::Param>& additional_params) {
-  const base::string16 expected_param_name =
-      base::ASCIIToUTF16(kCdmPersistentLicenseSupportedParamName);
-  for (const auto& p : additional_params) {
-    if (p.name == expected_param_name) {
-      return p.value == base::ASCIIToUTF16(kCdmFeatureSupported);
-    }
-  }
-  return false;
-}
-
 // Returns persistent-license session support.
 EmeSessionTypeSupport GetPersistentLicenseSupport(bool supported_by_the_cdm) {
   // Do not support persistent-license if the process cannot persist data.
@@ -246,15 +192,15 @@
     return;
 #endif  // defined(WIDEVINE_CDM_MIN_GLIBC_VERSION)
 
-  std::vector<WebPluginMimeType::Param> additional_params;
-  if (!IsPepperCdmAvailable(kWidevineCdmPluginMimeType, &additional_params)) {
+  std::vector<media::VideoCodec> supported_video_codecs;
+  bool supports_persistent_license = false;
+  if (!content::IsKeySystemSupported(kWidevineKeySystem,
+                                     &supported_video_codecs,
+                                     &supports_persistent_license)) {
     DVLOG(1) << "Widevine CDM is not currently available.";
     return;
   }
 
-  std::vector<std::string> codecs;
-  GetSupportedCodecsForPepperCdm(additional_params, &codecs);
-
   SupportedCodecs supported_codecs = media::EME_CODEC_NONE;
 
   // Audio codecs are always supported.
@@ -266,22 +212,29 @@
   supported_codecs |= media::EME_CODEC_MP4_AAC;
 #endif  // BUILDFLAG(USE_PROPRIETARY_CODECS)
 
-  for (size_t i = 0; i < codecs.size(); ++i) {
-    if (codecs[i] == kCdmSupportedCodecVp8)
-      supported_codecs |= media::EME_CODEC_WEBM_VP8;
-    if (codecs[i] == kCdmSupportedCodecVp9) {
-      supported_codecs |= media::EME_CODEC_WEBM_VP9;
-      supported_codecs |= media::EME_CODEC_COMMON_VP9;
-    }
+  // Video codecs are determined by what was registered for the CDM.
+  for (const auto& codec : supported_video_codecs) {
+    switch (codec) {
+      case media::VideoCodec::kCodecVP8:
+        supported_codecs |= media::EME_CODEC_WEBM_VP8;
+        break;
+      case media::VideoCodec::kCodecVP9:
+        supported_codecs |= media::EME_CODEC_WEBM_VP9;
+        supported_codecs |= media::EME_CODEC_COMMON_VP9;
+        break;
 #if BUILDFLAG(USE_PROPRIETARY_CODECS)
-    if (codecs[i] == kCdmSupportedCodecAvc1)
-      supported_codecs |= media::EME_CODEC_MP4_AVC1;
+      case media::VideoCodec::kCodecH264:
+        supported_codecs |= media::EME_CODEC_MP4_AVC1;
+        break;
 #endif  // BUILDFLAG(USE_PROPRIETARY_CODECS)
+      default:
+        DVLOG(1) << "Unexpected supported codec: " << GetCodecName(codec);
+        break;
+    }
   }
 
   EmeSessionTypeSupport persistent_license_support =
-      GetPersistentLicenseSupport(
-          IsPersistentLicenseSupportedbyCdm(additional_params));
+      GetPersistentLicenseSupport(supports_persistent_license);
 
   using Robustness = cdm::WidevineKeySystemProperties::Robustness;
 
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index cc46bda6..ca0d5e0 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -1623,11 +1623,11 @@
         "../browser/ui/ash/shelf_browsertest.cc",
         "../browser/ui/ash/system_tray_client_browsertest.cc",
         "../browser/ui/ash/system_tray_tray_cast_browsertest_media_router_chromeos.cc",
+        "../browser/ui/ash/time_to_first_present_recorder_browsertest.cc",
         "../browser/ui/ash/volume_controller_browsertest.cc",
         "../browser/ui/sort_windows_by_z_index_browsertest.cc",
         "../browser/ui/views/apps/chrome_native_app_window_views_aura_ash_browsertest.cc",
         "../browser/ui/views/arc_app_dialog_view_browsertest.cc",
-        "../browser/ui/views/ash/time_to_first_present_recorder_browsertest.cc",
         "../browser/ui/views/frame/browser_frame_ash_browsertest.cc",
         "../browser/ui/views/frame/browser_non_client_frame_view_ash_browsertest.cc",
         "../browser/ui/views/frame/immersive_mode_controller_ash_browsertest.cc",
@@ -2878,6 +2878,7 @@
       "../browser/ui/global_error/global_error_service_unittest.cc",
       "../browser/ui/omnibox/chrome_omnibox_navigation_observer_unittest.cc",
       "../browser/ui/omnibox/clipboard_utils_unittest.cc",
+      "../browser/ui/omnibox/favicon_cache_unittest.cc",
       "../browser/ui/omnibox/omnibox_controller_unittest.cc",
       "../browser/ui/omnibox/test_omnibox_client.cc",
       "../browser/ui/omnibox/test_omnibox_client.h",
@@ -2961,6 +2962,7 @@
       "../utility/importer/safari_importer_unittest.mm",
     ]
     deps += [
+      "//components/favicon/core/test:test_support",
       "//components/signin/core/browser:signin_features",
       "//third_party/libaddressinput",
     ]
@@ -4705,8 +4707,8 @@
         "../browser/chromeos/login/users/wallpaper/wallpaper_manager_test_utils.h",
         "../browser/notifications/login_state_notification_blocker_chromeos_browsertest.cc",
         "../browser/ui/ash/app_list/app_list_interactive_uitest.cc",
+        "../browser/ui/ash/tab_scrubber_browsertest.cc",
         "../browser/ui/views/apps/chrome_native_app_window_views_aura_ash_interactive_uitest.cc",
-        "../browser/ui/views/ash/tab_scrubber_browsertest.cc",
         "../browser/ui/webui/chromeos/login/oobe_display_chooser_browsertest.cc",
         "../browser/ui/window_sizer/window_sizer_ash_uitest.cc",
         "//ash/accelerators/accelerator_interactive_uitest_chromeos.cc",
diff --git a/chrome/test/data/webui/discards/discards_browsertest.js b/chrome/test/data/webui/discards/discards_browsertest.js
index 7479c997..114a987 100644
--- a/chrome/test/data/webui/discards/discards_browsertest.js
+++ b/chrome/test/data/webui/discards/discards_browsertest.js
@@ -20,10 +20,7 @@
   let dummy1 = {
     title: 'title 1',
     tabUrl: 'http://urlone.com',
-    isApp: false,
-    isInternal: false,
     isMedia: false,
-    isPinned: false,
     isDiscarded: false,
     isAutoDiscardable: false,
     discardCount: 0,
@@ -33,10 +30,7 @@
   let dummy2 = {
     title: 'title 2',
     tabUrl: 'http://urltwo.com',
-    isApp: true,
-    isInternal: true,
     isMedia: true,
-    isPinned: true,
     isDiscarded: true,
     isAutoDiscardable: true,
     discardCount: 1,
@@ -44,9 +38,8 @@
     lastActiveSeconds: 1
   };
 
-  ['title', 'tabUrl', 'isApp', 'isInternal', 'isMedia', 'isPinned',
-      'isDiscarded', 'isAutoDiscardable', 'discardCount', 'utilityRank',
-      'lastActiveSeconds'].forEach((sortKey) => {
+  ['title', 'tabUrl', 'isMedia', 'isDiscarded', 'isAutoDiscardable',
+      'discardCount', 'utilityRank', 'lastActiveSeconds'].forEach((sortKey) => {
     assertTrue(
         discards.compareTabDiscardsInfos(sortKey, dummy1, dummy2) < 0);
     assertTrue(
diff --git a/chrome/test/data/webui/print_preview/new_print_preview_ui_browsertest.js b/chrome/test/data/webui/print_preview/new_print_preview_ui_browsertest.js
index 5858ebed..1deb74c 100644
--- a/chrome/test/data/webui/print_preview/new_print_preview_ui_browsertest.js
+++ b/chrome/test/data/webui/print_preview/new_print_preview_ui_browsertest.js
@@ -121,6 +121,10 @@
   this.runMochaTest(settings_sections_tests.TestNames.SetScaling);
 });
 
+TEST_F('PrintPreviewSettingsSectionsTest', 'SetOther', function() {
+  this.runMochaTest(settings_sections_tests.TestNames.SetOther);
+});
+
 PrintPreviewRestoreStateTest = class extends NewPrintPreviewTest {
   /** @override */
   get browsePreload() {
diff --git a/chrome/test/data/webui/print_preview/settings_section_test.js b/chrome/test/data/webui/print_preview/settings_section_test.js
index 9cf11fdf..f83d8795 100644
--- a/chrome/test/data/webui/print_preview/settings_section_test.js
+++ b/chrome/test/data/webui/print_preview/settings_section_test.js
@@ -20,6 +20,7 @@
     SetDpi: 'set dpi',
     SetMargins: 'set margins',
     SetScaling: 'set scaling',
+    SetOther: 'set other',
   };
 
   const suiteName = 'SettingsSectionsTests';
@@ -40,14 +41,17 @@
           print_preview_test_utils.getCddTemplate(fooDestination.id)
               .capabilities;
       page.set('destination_', fooDestination);
-      setPdfDocument(false);
+      initDocumentInfo(false, false);
       Polymer.dom.flush();
     });
 
-    /** @param {boolean} isPdf Whether the document should be a PDF. */
-    function setPdfDocument(isPdf) {
+    /**
+     * @param {boolean} isPdf Whether the document should be a PDF.
+     * @param {boolean} hasSelection Whether the document has a selection.
+     */
+    function initDocumentInfo(isPdf, hasSelection) {
       const info = new print_preview.DocumentInfo();
-      info.init(!isPdf, 'title', false);
+      info.init(!isPdf, 'title', hasSelection);
       if (isPdf)
         info.fitToPageScaling_ = '98';
       page.set('documentInfo_', info);
@@ -83,8 +87,8 @@
     test(assert(TestNames.Layout), function() {
       const layoutElement = page.$$('print-preview-layout-settings');
 
-      // Set up with HTML document.
-      setPdfDocument(false);
+      // Set up with HTML document. No selection.
+      initDocumentInfo(false, false);
       expectEquals(false, layoutElement.hidden);
 
       // Remove layout capability.
@@ -111,7 +115,7 @@
       expectEquals(false, layoutElement.hidden);
 
       // Test with PDF - should be hidden.
-      setPdfDocument(true);
+      initDocumentInfo(true, false);
       expectEquals(true, layoutElement.hidden);
     });
 
@@ -175,7 +179,7 @@
       page.set('destination_.capabilities', capabilities);
 
       // Set PDF document type.
-      setPdfDocument(true);
+      initDocumentInfo(true, false);
       expectEquals(false, mediaSizeElement.hidden);
 
       // Set save as PDF. This should hide the settings section.
@@ -183,7 +187,7 @@
       expectEquals(true, mediaSizeElement.hidden);
 
       // Set HTML document type, should now show the section.
-      setPdfDocument(false);
+      initDocumentInfo(false, false);
       expectEquals(false, mediaSizeElement.hidden);
     });
 
@@ -191,11 +195,11 @@
       const marginsElement = page.$$('print-preview-margins-settings');
 
       // Section is available for HTML (modifiable) documents
-      setPdfDocument(false);
+      initDocumentInfo(false, false);
       expectEquals(false, marginsElement.hidden);
 
       // Unavailable for PDFs.
-      setPdfDocument(true);
+      initDocumentInfo(true, false);
       expectEquals(true, marginsElement.hidden);
     });
 
@@ -225,7 +229,7 @@
       expectEquals(false, scalingElement.hidden);
 
       // HTML to non-PDF destination -> only input shown
-      setPdfDocument(false);
+      initDocumentInfo(false, false);
       const fitToPageContainer = scalingElement.$$('.checkbox');
       const scalingInput =
           scalingElement.$$('print-preview-number-settings-section')
@@ -235,7 +239,7 @@
       expectEquals(false, scalingInput.hidden);
 
       // PDF to non-PDF destination -> checkbox and input shown.
-      setPdfDocument(true);
+      initDocumentInfo(true, false);
       expectEquals(false, scalingElement.hidden);
       expectEquals(false, fitToPageContainer.hidden);
       expectEquals(false, scalingInput.hidden);
@@ -247,14 +251,14 @@
 
     test(assert(TestNames.Other), function() {
       const optionsElement = page.$$('print-preview-other-options-settings');
-      const headerFooter = optionsElement.$$('#header-footer-container');
-      const duplex = optionsElement.$$('#duplex-container');
-      const cssBackground = optionsElement.$$('#css-background-container');
-      const rasterize = optionsElement.$$('#rasterize-container');
-      const selectionOnly = optionsElement.$$('#selection-only-container');
+      const headerFooter = optionsElement.$$('#header-footer').parentElement;
+      const duplex = optionsElement.$$('#duplex').parentElement;
+      const cssBackground = optionsElement.$$('#css-background').parentElement;
+      const rasterize = optionsElement.$$('#rasterize').parentElement;
+      const selectionOnly = optionsElement.$$('#selection-only').parentElement;
 
       // Start with HTML + duplex capability.
-      setPdfDocument(false);
+      initDocumentInfo(false, false);
       let capabilities =
           print_preview_test_utils.getCddTemplate('FooPrinter').capabilities;
       page.set('destination_.capabilities', capabilities);
@@ -265,10 +269,8 @@
       expectEquals(true, rasterize.hidden);
       expectEquals(true, selectionOnly.hidden);
 
-      // Add a selection.
-      let info = new print_preview.DocumentInfo();
-      info.init(true, 'title', true);
-      page.set('documentInfo_', info);
+      // Add a selection - should show selection only.
+      initDocumentInfo(false, true);
       expectEquals(false, optionsElement.hidden);
       expectEquals(false, selectionOnly.hidden);
 
@@ -277,11 +279,13 @@
           print_preview_test_utils.getCddTemplate('FooPrinter').capabilities;
       delete capabilities.printer.duplex;
       page.set('destination_.capabilities', capabilities);
+      Polymer.dom.flush();
       expectEquals(false, optionsElement.hidden);
       expectEquals(true, duplex.hidden);
 
       // PDF
-      setPdfDocument(true);
+      initDocumentInfo(true, false);
+      Polymer.dom.flush();
       expectEquals(cr.isWindows || cr.isMac, optionsElement.hidden);
       expectEquals(true, headerFooter.hidden);
       expectEquals(true, duplex.hidden);
@@ -290,9 +294,7 @@
       expectEquals(true, selectionOnly.hidden);
 
       // Add a selection - should do nothing for PDFs.
-      info = new print_preview.DocumentInfo();
-      info.init(false, 'title', true);
-      page.set('documentInfo_', info);
+      initDocumentInfo(true, true);
       expectEquals(cr.isWindows || cr.isMac, optionsElement.hidden);
       expectEquals(true, selectionOnly.hidden);
 
@@ -300,6 +302,7 @@
       capabilities =
           print_preview_test_utils.getCddTemplate('FooPrinter').capabilities;
       page.set('destination_.capabilities', capabilities);
+      Polymer.dom.flush();
       expectEquals(false, optionsElement.hidden);
       expectEquals(false, duplex.hidden);
     });
@@ -425,7 +428,7 @@
           print_preview_new.MarginsTypeValue.DEFAULT,
           page.settings.margins.value);
 
-      // Change to black and white.
+      // Change to minimum.
       marginsInput.value =
           print_preview_new.MarginsTypeValue.MINIMUM.toString();
       marginsInput.dispatchEvent(new CustomEvent('change'));
@@ -436,7 +439,7 @@
 
     test(assert(TestNames.SetScaling), function() {
       // Set PDF so both scaling and fit to page are active.
-      setPdfDocument(true);
+      initDocumentInfo(true, false);
       const scalingElement = page.$$('print-preview-scaling-settings');
       expectEquals(false, scalingElement.hidden);
 
@@ -495,6 +498,44 @@
       fitToPageCheckbox.dispatchEvent(new CustomEvent('change'));
       validateScalingState('95', true, false);
     });
+
+    test(assert(TestNames.SetOther), function() {
+      const optionsElement = page.$$('print-preview-other-options-settings');
+      expectEquals(false, optionsElement.hidden);
+
+      // HTML - Header/footer, duplex, and CSS background. Also add seleciton.
+      initDocumentInfo(false, true);
+
+      const testOptionCheckbox = (element, defaultValue, optionSetting) => {
+        expectEquals(false, element.hidden);
+        expectEquals(defaultValue, element.checked);
+        expectEquals(defaultValue, optionSetting.value);
+        element.checked = !defaultValue;
+        element.dispatchEvent(new CustomEvent('change'));
+        expectEquals(!defaultValue, optionSetting.value);
+      };
+
+      // Check HTML settings
+      const ids =
+          ['header-footer', 'duplex', 'css-background', 'selection-only'];
+      const defaults = [true, true, false, false];
+      const optionSettings =
+          [page.settings.headerFooter, page.settings.duplex,
+           page.settings.cssBackground, page.settings.selectionOnly];
+
+      optionSettings.forEach((option, index) => {
+        testOptionCheckbox(
+            optionsElement.$$('#' + ids[index]), defaults[index],
+            optionSettings[index]);
+      });
+
+      // Set PDF to test rasterize
+      if (!cr.isWindows && !cr.isMac) {
+        initDocumentInfo(true, false);
+        testOptionCheckbox(
+            optionsElement.$$('#rasterize'), false, page.settings.rasterize);
+      }
+    });
   });
 
   return {
diff --git a/chrome/test/data/webui/settings/quick_unlock_authenticate_browsertest_chromeos.js b/chrome/test/data/webui/settings/quick_unlock_authenticate_browsertest_chromeos.js
index eff47d1..b25ef9b 100644
--- a/chrome/test/data/webui/settings/quick_unlock_authenticate_browsertest_chromeos.js
+++ b/chrome/test/data/webui/settings/quick_unlock_authenticate_browsertest_chromeos.js
@@ -545,6 +545,15 @@
         pinKeyboard.value = '11';
         assertFalse(continueButton.disabled);
       });
+
+      test('BackspaceDisabledWhenNothingEntered', function() {
+        let backspaceButton = pinKeyboard.$$(
+            'paper-icon-button[class="digit-button backspace-button"]');
+        assertTrue(backspaceButton.disabled);
+
+        pinKeyboard.value = '11';
+        assertFalse(backspaceButton.disabled);
+      });
     });
   }
 
diff --git a/chromecast/app/BUILD.gn b/chromecast/app/BUILD.gn
index 7f742ed3..b8399665 100644
--- a/chromecast/app/BUILD.gn
+++ b/chromecast/app/BUILD.gn
@@ -15,6 +15,7 @@
   deps = [
     ":cast_crash_client",
     "//base",
+    "//chromecast:chromecast_features",
     "//chromecast/base",
     "//chromecast/browser",
     "//chromecast/common",
diff --git a/chromecast/app/cast_main_delegate.cc b/chromecast/app/cast_main_delegate.cc
index a82bbef..7ae8008 100644
--- a/chromecast/app/cast_main_delegate.cc
+++ b/chromecast/app/cast_main_delegate.cc
@@ -18,6 +18,7 @@
 #include "base/path_service.h"
 #include "base/posix/global_descriptors.h"
 #include "build/build_config.h"
+#include "chromecast/chromecast_features.h"
 #include "chromecast/base/cast_paths.h"
 #include "chromecast/browser/cast_content_browser_client.h"
 #include "chromecast/common/cast_resource_delegate.h"
@@ -78,8 +79,12 @@
   }
 #endif  // defined(OS_ANDROID)
   logging::InitLogging(settings);
-  // Time, process, and thread ID are available through logcat.
+#if BUILDFLAG(IS_CAST_DESKTOP_BUILD)
+  logging::SetLogItems(true, true, true, false);
+#else
+  // Timestamp available through logcat -v time.
   logging::SetLogItems(true, true, false, false);
+#endif  // BUILDFLAG(IS_CAST_DESKTOP_BUILD)
 
 #if defined(OS_ANDROID)
   // Only delete the old crash dumps if the current process is the browser
diff --git a/chromecast/base/BUILD.gn b/chromecast/base/BUILD.gn
index cf14f0a..02a81b5 100644
--- a/chromecast/base/BUILD.gn
+++ b/chromecast/base/BUILD.gn
@@ -118,6 +118,7 @@
 
   deps = [
     "//base",
+    "//chromecast:chromecast_features",
   ]
 }
 
diff --git a/chromecast/base/init_command_line_shlib.cc b/chromecast/base/init_command_line_shlib.cc
index 92e44de..4f162310 100644
--- a/chromecast/base/init_command_line_shlib.cc
+++ b/chromecast/base/init_command_line_shlib.cc
@@ -6,6 +6,7 @@
 
 #include "base/command_line.h"
 #include "base/logging.h"
+#include "chromecast/chromecast_features.h"
 
 namespace chromecast {
 
@@ -18,6 +19,12 @@
   base::CommandLine::ForCurrentProcess()->InitFromArgv(argv);
 
   logging::InitLogging(logging::LoggingSettings());
+#if BUILDFLAG(IS_CAST_DESKTOP_BUILD)
+  logging::SetLogItems(true, true, true, false);
+#else
+  // Timestamp available through logcat -v time.
+  logging::SetLogItems(true, true, false, false);
+#endif  // BUILDFLAG(IS_CAST_DESKTOP_BUILD)
 }
 
 }  // namespace chromecast
diff --git a/chromecast/browser/android/apk/src/org/chromium/chromecast/shell/CastWebContentsActivity.java b/chromecast/browser/android/apk/src/org/chromium/chromecast/shell/CastWebContentsActivity.java
index 911e735c3..c0e1be4 100644
--- a/chromecast/browser/android/apk/src/org/chromium/chromecast/shell/CastWebContentsActivity.java
+++ b/chromecast/browser/android/apk/src/org/chromium/chromecast/shell/CastWebContentsActivity.java
@@ -401,6 +401,7 @@
         if (DEBUG) Log.d(TAG, "detachWebContentsIfAny");
         if (mContentView != null) {
             mCastWebContentsLayout.removeView(mContentView);
+            mCastWebContentsLayout.removeView(mContentViewRenderView);
             mContentViewCore.destroy();
             mContentViewRenderView.destroy();
             mWindow.destroy();
diff --git a/chromecast/graphics/cast_window_manager.h b/chromecast/graphics/cast_window_manager.h
index 8ff8427..e75336f 100644
--- a/chromecast/graphics/cast_window_manager.h
+++ b/chromecast/graphics/cast_window_manager.h
@@ -30,7 +30,8 @@
     INFO_OVERLAY,
     SOFT_KEYBOARD,
     VOLUME,
-    TOP = VOLUME
+    MEDIA_INFO,
+    TOP = MEDIA_INFO
   };
 
   // Creates the platform-specific CastWindowManager.
diff --git a/chromeos/components/tether/BUILD.gn b/chromeos/components/tether/BUILD.gn
index cca2712..1bf8f6d 100644
--- a/chromeos/components/tether/BUILD.gn
+++ b/chromeos/components/tether/BUILD.gn
@@ -75,6 +75,8 @@
     "host_scanner.h",
     "host_scanner_operation.cc",
     "host_scanner_operation.h",
+    "hotspot_usage_duration_tracker.cc",
+    "hotspot_usage_duration_tracker.h",
     "keep_alive_operation.cc",
     "keep_alive_operation.h",
     "keep_alive_scheduler.cc",
@@ -253,6 +255,7 @@
     "host_scan_scheduler_impl_unittest.cc",
     "host_scanner_operation_unittest.cc",
     "host_scanner_unittest.cc",
+    "hotspot_usage_duration_tracker_unittest.cc",
     "keep_alive_operation_unittest.cc",
     "keep_alive_scheduler_unittest.cc",
     "master_host_scan_cache_unittest.cc",
diff --git a/chromeos/components/tether/active_host.cc b/chromeos/components/tether/active_host.cc
index a417786..a5d3e5d03 100644
--- a/chromeos/components/tether/active_host.cc
+++ b/chromeos/components/tether/active_host.cc
@@ -18,6 +18,18 @@
 
 namespace tether {
 
+// static
+std::string ActiveHost::StatusToString(const ActiveHostStatus& status) {
+  switch (status) {
+    case ActiveHostStatus::DISCONNECTED:
+      return "DISCONNECTED";
+    case ActiveHostStatus::CONNECTING:
+      return "CONNECTING";
+    case ActiveHostStatus::CONNECTED:
+      return "CONNECTED";
+  }
+}
+
 bool operator==(const ActiveHost::ActiveHostChangeInfo& first,
                 const ActiveHost::ActiveHostChangeInfo& second) {
   bool new_devices_equal;
diff --git a/chromeos/components/tether/active_host.h b/chromeos/components/tether/active_host.h
index 8d48f82..a5314c99 100644
--- a/chromeos/components/tether/active_host.h
+++ b/chromeos/components/tether/active_host.h
@@ -36,6 +36,7 @@
     CONNECTING = 1,
     CONNECTED = 2
   };
+  static std::string StatusToString(const ActiveHostStatus& status);
 
   struct ActiveHostChangeInfo {
     ActiveHostChangeInfo();
diff --git a/chromeos/components/tether/hotspot_usage_duration_tracker.cc b/chromeos/components/tether/hotspot_usage_duration_tracker.cc
new file mode 100644
index 0000000..0a8727a3
--- /dev/null
+++ b/chromeos/components/tether/hotspot_usage_duration_tracker.cc
@@ -0,0 +1,100 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chromeos/components/tether/hotspot_usage_duration_tracker.h"
+
+#include "base/metrics/histogram_macros.h"
+#include "base/time/clock.h"
+#include "components/proximity_auth/logging/logging.h"
+
+namespace chromeos {
+
+namespace tether {
+
+namespace {
+
+// Minimum value for the usage duration metric.
+const int64_t kMinDurationSeconds = 1;
+
+// Maximum value for the usage duration metric.
+const int64_t kMaxDurationHours = 5;
+
+// Number of buckets in the metric.
+const int kNumMetricsBuckets = 100;
+
+}  // namespace
+
+HotspotUsageDurationTracker::HotspotUsageDurationTracker(
+    ActiveHost* active_host,
+    base::Clock* clock)
+    : active_host_(active_host), clock_(clock) {
+  active_host_->AddObserver(this);
+}
+
+HotspotUsageDurationTracker::~HotspotUsageDurationTracker() {
+  active_host_->RemoveObserver(this);
+}
+
+void HotspotUsageDurationTracker::OnActiveHostChanged(
+    const ActiveHost::ActiveHostChangeInfo& change_info) {
+  // Handle the case that a session is being tracked but the active host's
+  // status changes unexpectedly.
+  HandleUnexpectedCurrentSession(change_info.new_status);
+
+  switch (change_info.new_status) {
+    case ActiveHost::ActiveHostStatus::CONNECTED:
+      last_connection_start_ = clock_->Now();
+      break;
+    case ActiveHost::ActiveHostStatus::DISCONNECTED: {
+      // If |last_connection_start_| has not been set, there was no active
+      // connection before this status change; thus, there is nothing to do.
+      if (last_connection_start_.is_null())
+        break;
+
+      base::TimeDelta duration = clock_->Now() - last_connection_start_;
+
+      // Reset |last_connection_start_|; it will be set again the next time that
+      // a connection is established.
+      last_connection_start_ = base::Time();
+
+      PA_LOG(INFO) << "Connection to hotspot has ended. Duration was "
+                   << duration.InSeconds() << " second(s).";
+      UMA_HISTOGRAM_CUSTOM_TIMES(
+          "InstantTethering.HotspotUsageDuration", duration,
+          base::TimeDelta::FromSeconds(kMinDurationSeconds) /* min */,
+          base::TimeDelta::FromHours(kMaxDurationHours) /* max */,
+          kNumMetricsBuckets /* bucket_count */);
+      break;
+    }
+    default:
+      break;
+  }
+}
+
+void HotspotUsageDurationTracker::HandleUnexpectedCurrentSession(
+    const ActiveHost::ActiveHostStatus& active_host_status) {
+  // If there is no start timestamp, no session is being tracked.
+  if (last_connection_start_.is_null())
+    return;
+
+  // It is expected that when a current session ends, the active host's status
+  // will change to DISCONNECTED.
+  if (active_host_status == ActiveHost::ActiveHostStatus::DISCONNECTED)
+    return;
+
+  base::TimeDelta previous_duration = clock_->Now() - last_connection_start_;
+  PA_LOG(ERROR) << "Active host status changed to "
+                << ActiveHost::StatusToString(active_host_status) << ", but a "
+                << "session was already being tracked ("
+                << previous_duration.InSeconds() << " second(s)). "
+                << "Not recording any metrics for this session since this "
+                << "situation was reached in error.";
+
+  // Delete the erroneously started session.
+  last_connection_start_ = base::Time();
+}
+
+}  // namespace tether
+
+}  // namespace chromeos
diff --git a/chromeos/components/tether/hotspot_usage_duration_tracker.h b/chromeos/components/tether/hotspot_usage_duration_tracker.h
new file mode 100644
index 0000000..3d124da
--- /dev/null
+++ b/chromeos/components/tether/hotspot_usage_duration_tracker.h
@@ -0,0 +1,51 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROMEOS_COMPONENTS_TETHER_HOTSPOT_USAGE_DURATION_TRACKER_H_
+#define CHROMEOS_COMPONENTS_TETHER_HOTSPOT_USAGE_DURATION_TRACKER_H_
+
+#include <memory>
+
+#include "base/macros.h"
+#include "base/time/time.h"
+#include "chromeos/components/tether/active_host.h"
+
+namespace base {
+class Clock;
+}  // namespace base
+
+namespace chromeos {
+
+namespace tether {
+
+// Records a metric which tracks the amount of time that users spend connected
+// to Tether hotspots.
+class HotspotUsageDurationTracker : public ActiveHost::Observer {
+ public:
+  explicit HotspotUsageDurationTracker(ActiveHost* active_host,
+                                       base::Clock* clock);
+  virtual ~HotspotUsageDurationTracker();
+
+ protected:
+  // ActiveHost::Observer:
+  void OnActiveHostChanged(
+      const ActiveHost::ActiveHostChangeInfo& change_info) override;
+
+ private:
+  void HandleUnexpectedCurrentSession(
+      const ActiveHost::ActiveHostStatus& active_host_status);
+
+  ActiveHost* active_host_;
+  base::Clock* clock_;
+
+  base::Time last_connection_start_;
+
+  DISALLOW_COPY_AND_ASSIGN(HotspotUsageDurationTracker);
+};
+
+}  // namespace tether
+
+}  // namespace chromeos
+
+#endif  // CHROMEOS_COMPONENTS_TETHER_HOTSPOT_USAGE_DURATION_TRACKER_H_
diff --git a/chromeos/components/tether/hotspot_usage_duration_tracker_unittest.cc b/chromeos/components/tether/hotspot_usage_duration_tracker_unittest.cc
new file mode 100644
index 0000000..50db42d
--- /dev/null
+++ b/chromeos/components/tether/hotspot_usage_duration_tracker_unittest.cc
@@ -0,0 +1,120 @@
+// 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 "chromeos/components/tether/hotspot_usage_duration_tracker.h"
+
+#include <memory>
+
+#include "base/test/histogram_tester.h"
+#include "base/test/simple_test_clock.h"
+#include "chromeos/components/tether/fake_active_host.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace chromeos {
+
+namespace tether {
+
+namespace {
+
+const char kTestDeviceId[] = "testDeviceId";
+const char kTestTetherNetworkGuid[] = "testTetherNetworkGuid";
+const char kTestWifiNetworkGuid[] = "testWifiNetworkGuid";
+
+constexpr const base::TimeDelta kTestDuration = base::TimeDelta::FromSeconds(5);
+
+}  // namespace
+
+class HotspotUsageDurationTrackerTest : public testing::Test {
+ protected:
+  HotspotUsageDurationTrackerTest() = default;
+  ~HotspotUsageDurationTrackerTest() override = default;
+
+  void SetUp() override {
+    fake_active_host_ = std::make_unique<FakeActiveHost>();
+    test_clock_ = std::make_unique<base::SimpleTestClock>();
+    test_clock_->SetNow(base::Time::UnixEpoch());
+
+    tracker_ = std::make_unique<HotspotUsageDurationTracker>(
+        fake_active_host_.get(), test_clock_.get());
+  }
+
+  void AdvanceClock() { test_clock_->Advance(kTestDuration); }
+
+  std::unique_ptr<FakeActiveHost> fake_active_host_;
+  std::unique_ptr<base::SimpleTestClock> test_clock_;
+
+  base::HistogramTester histogram_tester_;
+
+  std::unique_ptr<HotspotUsageDurationTracker> tracker_;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(HotspotUsageDurationTrackerTest);
+};
+
+TEST_F(HotspotUsageDurationTrackerTest, TestNoConnection) {
+  // Attempt a connection but fail to connect. No duration should be logged.
+  fake_active_host_->SetActiveHostConnecting(kTestDeviceId,
+                                             kTestTetherNetworkGuid);
+  AdvanceClock();
+  fake_active_host_->SetActiveHostDisconnected();
+  histogram_tester_.ExpectTotalCount("InstantTethering.HotspotUsageDuration",
+                                     0 /* count */);
+
+  AdvanceClock();
+
+  // Fail one more attempt.
+  fake_active_host_->SetActiveHostConnecting(kTestDeviceId,
+                                             kTestTetherNetworkGuid);
+  AdvanceClock();
+  fake_active_host_->SetActiveHostDisconnected();
+  histogram_tester_.ExpectTotalCount("InstantTethering.HotspotUsageDuration",
+                                     0 /* count */);
+}
+
+TEST_F(HotspotUsageDurationTrackerTest, TestConnections) {
+  // Connect, have some time pass, then disconnect. Metric should have been
+  // logged.
+  fake_active_host_->SetActiveHostConnecting(kTestDeviceId,
+                                             kTestTetherNetworkGuid);
+  fake_active_host_->SetActiveHostConnected(
+      kTestDeviceId, kTestTetherNetworkGuid, kTestWifiNetworkGuid);
+  AdvanceClock();
+  fake_active_host_->SetActiveHostDisconnected();
+  histogram_tester_.ExpectTimeBucketCount(
+      "InstantTethering.HotspotUsageDuration", kTestDuration, 1 /* count */);
+
+  AdvanceClock();
+
+  // Try one more time, advancing the clock for twice as long.
+  fake_active_host_->SetActiveHostConnecting(kTestDeviceId,
+                                             kTestTetherNetworkGuid);
+  fake_active_host_->SetActiveHostConnected(
+      kTestDeviceId, kTestTetherNetworkGuid, kTestWifiNetworkGuid);
+  AdvanceClock();
+  AdvanceClock();
+  fake_active_host_->SetActiveHostDisconnected();
+  histogram_tester_.ExpectTimeBucketCount(
+      "InstantTethering.HotspotUsageDuration", 2 * kTestDuration,
+      1 /* count */);
+}
+
+TEST_F(HotspotUsageDurationTrackerTest, TestErrorCondition) {
+  fake_active_host_->SetActiveHostConnecting(kTestDeviceId,
+                                             kTestTetherNetworkGuid);
+  fake_active_host_->SetActiveHostConnected(
+      kTestDeviceId, kTestTetherNetworkGuid, kTestWifiNetworkGuid);
+  AdvanceClock();
+
+  // Transition from CONNECTED to CONNECTING. This should never actually happen,
+  // so we can assume that some error occurred. No metric should be logged.
+  fake_active_host_->SetActiveHostConnecting(kTestDeviceId,
+                                             kTestTetherNetworkGuid);
+  histogram_tester_.ExpectTotalCount("InstantTethering.HotspotUsageDuration",
+                                     0 /* count */);
+}
+
+}  // namespace tether
+
+}  // namespace chromeos
diff --git a/chromeos/components/tether/synchronous_shutdown_object_container_impl.cc b/chromeos/components/tether/synchronous_shutdown_object_container_impl.cc
index 0e24337..bf7f8258 100644
--- a/chromeos/components/tether/synchronous_shutdown_object_container_impl.cc
+++ b/chromeos/components/tether/synchronous_shutdown_object_container_impl.cc
@@ -15,6 +15,7 @@
 #include "chromeos/components/tether/host_scan_device_prioritizer_impl.h"
 #include "chromeos/components/tether/host_scan_scheduler_impl.h"
 #include "chromeos/components/tether/host_scanner.h"
+#include "chromeos/components/tether/hotspot_usage_duration_tracker.h"
 #include "chromeos/components/tether/keep_alive_scheduler.h"
 #include "chromeos/components/tether/master_host_scan_cache.h"
 #include "chromeos/components/tether/network_connection_handler_tether_delegate.h"
@@ -129,6 +130,9 @@
           master_host_scan_cache_.get(),
           device_id_tether_network_guid_map_.get())),
       clock_(std::make_unique<base::DefaultClock>()),
+      hotspot_usage_duration_tracker_(
+          std::make_unique<HotspotUsageDurationTracker>(active_host_.get(),
+                                                        clock_.get())),
       host_scanner_(std::make_unique<HostScanner>(
           network_state_handler_,
           asychronous_container->tether_host_fetcher(),
diff --git a/chromeos/components/tether/synchronous_shutdown_object_container_impl.h b/chromeos/components/tether/synchronous_shutdown_object_container_impl.h
index 870a278..28d8652 100644
--- a/chromeos/components/tether/synchronous_shutdown_object_container_impl.h
+++ b/chromeos/components/tether/synchronous_shutdown_object_container_impl.h
@@ -32,6 +32,7 @@
 class HostScanner;
 class HostScanScheduler;
 class HostScanDevicePrioritizerImpl;
+class HotspotUsageDurationTracker;
 class KeepAliveScheduler;
 class HostConnectionMetricsLogger;
 class MasterHostScanCache;
@@ -114,6 +115,7 @@
   std::unique_ptr<NotificationRemover> notification_remover_;
   std::unique_ptr<KeepAliveScheduler> keep_alive_scheduler_;
   std::unique_ptr<base::Clock> clock_;
+  std::unique_ptr<HotspotUsageDurationTracker> hotspot_usage_duration_tracker_;
   std::unique_ptr<HostScanner> host_scanner_;
   std::unique_ptr<HostScanScheduler> host_scan_scheduler_;
   std::unique_ptr<HostConnectionMetricsLogger> host_connection_metrics_logger_;
diff --git a/chromeos/network/onc/onc_signature.cc b/chromeos/network/onc/onc_signature.cc
index d23c9f73..d6bf59c 100644
--- a/chromeos/network/onc/onc_signature.cc
+++ b/chromeos/network/onc/onc_signature.cc
@@ -141,7 +141,6 @@
     {::onc::openvpn::kTLSVersionMin, &kStringSignature},
     {::onc::openvpn::kUserAuthenticationType, &kStringSignature},
     {::onc::vpn::kUsername, &kStringSignature},
-    // Not supported, yet.
     {::onc::openvpn::kVerb, &kStringSignature},
     {::onc::openvpn::kVerifyHash, &kStringSignature},
     {::onc::openvpn::kVerifyX509, &kVerifyX509Signature},
diff --git a/chromeos/network/onc/onc_translation_tables.cc b/chromeos/network/onc/onc_translation_tables.cc
index 857b968..a27fd34 100644
--- a/chromeos/network/onc/onc_translation_tables.cc
+++ b/chromeos/network/onc/onc_translation_tables.cc
@@ -106,6 +106,7 @@
     {::onc::openvpn::kTLSRemote, shill::kOpenVPNTLSRemoteProperty},
     {::onc::openvpn::kTLSVersionMin, shill::kOpenVPNTLSVersionMinProperty},
     {::onc::vpn::kUsername, shill::kOpenVPNUserProperty},
+    {::onc::openvpn::kVerb, shill::kOpenVPNVerbProperty},
     {::onc::openvpn::kVerifyHash, shill::kOpenVPNVerifyHashProperty},
     {NULL}};
 
diff --git a/chromeos/printing/printer_configuration.h b/chromeos/printing/printer_configuration.h
index ad6399f9..7d26aca3 100644
--- a/chromeos/printing/printer_configuration.h
+++ b/chromeos/printing/printer_configuration.h
@@ -131,7 +131,7 @@
   // |uri_|.
   bool IsIppEverywhere() const;
 
-  // Returns true if |effective_uri_| needs to be computed before the pritner
+  // Returns true if |effective_uri_| needs to be computed before the printer
   // can be installed.
   bool RequiresIpResolution() const;
 
diff --git a/components/arc/arc_session_runner.cc b/components/arc/arc_session_runner.cc
index cda3d8a..5a45300 100644
--- a/components/arc/arc_session_runner.cc
+++ b/components/arc/arc_session_runner.cc
@@ -8,7 +8,6 @@
 #include "base/metrics/histogram_macros.h"
 #include "base/optional.h"
 #include "base/task_runner.h"
-#include "chromeos/dbus/dbus_thread_manager.h"
 #include "components/arc/arc_util.h"
 
 namespace arc {
@@ -18,16 +17,6 @@
 constexpr base::TimeDelta kDefaultRestartDelay =
     base::TimeDelta::FromSeconds(5);
 
-chromeos::SessionManagerClient* GetSessionManagerClient() {
-  // If the DBusThreadManager or the SessionManagerClient aren't available,
-  // there isn't much we can do. This should only happen when running tests.
-  if (!chromeos::DBusThreadManager::IsInitialized() ||
-      !chromeos::DBusThreadManager::Get() ||
-      !chromeos::DBusThreadManager::Get()->GetSessionManagerClient())
-    return nullptr;
-  return chromeos::DBusThreadManager::Get()->GetSessionManagerClient();
-}
-
 void RecordInstanceCrashUma(ArcContainerLifetimeEvent sample) {
   UMA_HISTOGRAM_ENUMERATION("Arc.ContainerLifetimeEvent", sample,
                             ArcContainerLifetimeEvent::COUNT);
@@ -147,18 +136,12 @@
       restart_after_crash_count_(0),
       factory_(factory),
       weak_ptr_factory_(this) {
-  chromeos::SessionManagerClient* client = GetSessionManagerClient();
-  if (client)
-    client->AddObserver(this);
 }
 
 ArcSessionRunner::~ArcSessionRunner() {
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
   if (arc_session_)
     arc_session_->RemoveObserver(this);
-  chromeos::SessionManagerClient* client = GetSessionManagerClient();
-  if (client)
-    client->RemoveObserver(this);
 }
 
 void ArcSessionRunner::AddObserver(Observer* observer) {
@@ -328,13 +311,4 @@
   }
 }
 
-void ArcSessionRunner::EmitLoginPromptVisibleCalled() {
-  // Since 'login-prompt-visible' Upstart signal starts all Upstart jobs the
-  // instance may depend on such as cras, EmitLoginPromptVisibleCalled() is the
-  // safe place to start a mini instance.
-  DCHECK(!arc_session_);
-  if (IsArcAvailable())
-    RequestStart(ArcInstanceMode::MINI_INSTANCE);
-}
-
 }  // namespace arc
diff --git a/components/arc/arc_session_runner.h b/components/arc/arc_session_runner.h
index 5db5991..4b7f546 100644
--- a/components/arc/arc_session_runner.h
+++ b/components/arc/arc_session_runner.h
@@ -14,7 +14,6 @@
 #include "base/threading/thread_checker.h"
 #include "base/time/time.h"
 #include "base/timer/timer.h"
-#include "chromeos/dbus/session_manager_client.h"
 #include "components/arc/arc_instance_mode.h"
 #include "components/arc/arc_session.h"
 #include "components/arc/arc_stop_reason.h"
@@ -42,8 +41,7 @@
 
 // Accept requests to start/stop ARC instance. Also supports automatic
 // restarting on unexpected ARC instance crash.
-class ArcSessionRunner : public ArcSession::Observer,
-                         public chromeos::SessionManagerClient::Observer {
+class ArcSessionRunner : public ArcSession::Observer {
  public:
   // Observer to notify events across multiple ARC session runs.
   class Observer {
@@ -106,9 +104,6 @@
   // ArcSession::Observer:
   void OnSessionStopped(ArcStopReason reason, bool was_running) override;
 
-  // chromeos::SessionManagerClient::Observer:
-  void EmitLoginPromptVisibleCalled() override;
-
   THREAD_CHECKER(thread_checker_);
 
   // Observers for the ARC instance state change events.
diff --git a/components/arc/arc_session_runner_unittest.cc b/components/arc/arc_session_runner_unittest.cc
index 8a531e8..7cf9955 100644
--- a/components/arc/arc_session_runner_unittest.cc
+++ b/components/arc/arc_session_runner_unittest.cc
@@ -259,8 +259,8 @@
   EXPECT_FALSE(stopped_called());
 }
 
-// Tests that RequestStart() works even after EmitLoginPromptVisibleCalled()
-// is called.
+// Tests that RequestStart(FULL_INSTANCE) works after calling
+// RequestStart(MINI_INSTANCE).
 TEST_F(ArcSessionRunnerTest, Upgrade) {
   EXPECT_FALSE(arc_session());
 
@@ -273,31 +273,6 @@
   EXPECT_TRUE(arc_session()->is_running());
 }
 
-// We expect mini instance starts to run if EmitLoginPromptVisible signal is
-// emitted.
-TEST_F(ArcSessionRunnerTest, EmitLoginPromptVisible) {
-  EXPECT_FALSE(arc_session());
-
-  SetArcAvailableCommandLineForTesting(base::CommandLine::ForCurrentProcess());
-
-  chromeos::DBusThreadManager::Get()
-      ->GetSessionManagerClient()
-      ->EmitLoginPromptVisible();
-  ASSERT_TRUE(arc_session());
-  EXPECT_FALSE(arc_session()->is_running());
-}
-
-// We expect mini instance does not start on EmitLoginPromptVisible when ARC
-// is not available.
-TEST_F(ArcSessionRunnerTest, EmitLoginPromptVisible_NoOp) {
-  EXPECT_FALSE(arc_session());
-
-  chromeos::DBusThreadManager::Get()
-      ->GetSessionManagerClient()
-      ->EmitLoginPromptVisible();
-  EXPECT_FALSE(arc_session());
-}
-
 // If the instance is stopped, it should be re-started.
 TEST_F(ArcSessionRunnerTest, Restart) {
   arc_session_runner()->SetRestartDelayForTesting(base::TimeDelta());
diff --git a/components/arc/intent_helper/arc_intent_helper_bridge.cc b/components/arc/intent_helper/arc_intent_helper_bridge.cc
index 5e7e236..a80e61b4 100644
--- a/components/arc/intent_helper/arc_intent_helper_bridge.cc
+++ b/components/arc/intent_helper/arc_intent_helper_bridge.cc
@@ -61,12 +61,8 @@
     {mojom::ChromePage::ABOUTDOWNLOADS, "about:downloads"},
     {mojom::ChromePage::ABOUTHISTORY, "about:history"}};
 
-// TODO(djacobo): Propose geo: as a constant.
-constexpr const char* kArcSchemes[] = {url::kHttpScheme,
-                                       url::kHttpsScheme,
-                                       url::kContentScheme,
-                                       url::kFileScheme,
-                                       "geo",
+constexpr const char* kArcSchemes[] = {url::kHttpScheme, url::kHttpsScheme,
+                                       url::kContentScheme, url::kFileScheme,
                                        url::kMailToScheme};
 
 // mojom::ChromePage::LAST returns the ammout of valid entries - 1.
diff --git a/components/autofill/content/renderer/password_autofill_agent.cc b/components/autofill/content/renderer/password_autofill_agent.cc
index 062ef9dc..d2b003f 100644
--- a/components/autofill/content/renderer/password_autofill_agent.cc
+++ b/components/autofill/content/renderer/password_autofill_agent.cc
@@ -1736,20 +1736,9 @@
   if (!IsElementAutocompletable(*password_element))
     return false;
 
-  // |current_username| is the username for credentials that are going to be
-  // autofilled. It is selected according to the algorithm:
-  // 1. If the page already contain a non-empty value in |username_element|,
-  // this is adopted and not overridden.
-  // 2. Default username from |fill_data| if the username field is
-  // autocompletable.
-  // 3. Empty if username field doesn't exist or if username field is empty and
-  // not autocompletable (no username case).
   base::string16 current_username;
   if (!username_element->IsNull()) {
-    if (!username_element->Value().IsEmpty())
-      current_username = username_element->Value().Utf16();
-    else if (IsElementAutocompletable(*username_element))
-      current_username = fill_data.username_field.value;
+    current_username = username_element->Value().Utf16();
   }
 
   // username and password will contain the match found if any.
@@ -1762,6 +1751,9 @@
   if (password.empty())
     return false;
 
+  // TODO(tkent): Check maxlength and pattern for both username and password
+  // fields.
+
   // Call OnFieldAutofilled before WebInputElement::SetAutofilled which may
   // cause frame closing.
   if (password_generation_agent_)
@@ -1770,12 +1762,9 @@
   // Input matches the username, fill in required values.
   if (!username_element->IsNull() &&
       IsElementAutocompletable(*username_element)) {
-    // Fill username only when it's not empty and not set by the page.
-    if (!username.empty() && username_element->Value().IsEmpty()) {
-      username_element->SetSuggestedValue(
-          blink::WebString::FromUTF16(username));
-      registration_callback.Run(username_element);
-    }
+    // TODO(crbug.com/507714): Why not setSuggestedValue?
+    if (username_element->Value().Utf16() != username)
+      username_element->SetAutofillValue(blink::WebString::FromUTF16(username));
     UpdateFieldValueAndPropertiesMaskMap(*username_element, &username,
                                          FieldPropertiesFlags::AUTOFILLED,
                                          field_value_and_properties_map);
@@ -1833,6 +1822,40 @@
   if (!IsElementAutocompletable(password_element))
     return false;
 
+  bool form_contains_fillable_username_field =
+      FillDataContainsFillableUsername(fill_data);
+  bool ambiguous_or_empty_names =
+      DoesFormContainAmbiguousOrEmptyNames(fill_data);
+  base::string16 username_field_name;
+  if (form_contains_fillable_username_field)
+    username_field_name =
+        FieldName(fill_data.username_field, ambiguous_or_empty_names);
+
+  // If the form contains an autocompletable username field, try to set the
+  // username to the preferred name, but only if:
+  //   (a) The fill-on-account-select flag is not set, and
+  //   (b) The username element isn't prefilled
+  //
+  // If (a) is false, then just mark the username element as autofilled if the
+  // user is not in the "no highlighting" group and return so the fill step is
+  // skipped.
+  //
+  // If there is no autocompletable username field, and (a) is false, then the
+  // username element cannot be autofilled, but the user should still be able to
+  // select to fill the password element, so the password element must be marked
+  // as autofilled and the fill step should also be skipped if the user is not
+  // in the "no highlighting" group.
+  //
+  // In all other cases, do nothing.
+  bool form_has_fillable_username = !username_field_name.empty() &&
+                                    IsElementAutocompletable(username_element);
+
+  if (form_has_fillable_username && username_element.Value().IsEmpty()) {
+    // TODO(tkent): Check maxlength and pattern.
+    username_element.SetAutofillValue(
+        blink::WebString::FromUTF16(fill_data.username_field.value));
+  }
+
   bool exact_username_match =
       username_element.IsNull() || IsElementEditable(username_element);
   // Use the exact match for the editable username fields and allow prefix
diff --git a/components/autofill/content/renderer/password_autofill_agent.h b/components/autofill/content/renderer/password_autofill_agent.h
index 4594db1..5df0f36 100644
--- a/components/autofill/content/renderer/password_autofill_agent.h
+++ b/components/autofill/content/renderer/password_autofill_agent.h
@@ -283,12 +283,11 @@
                                  ProvisionallySaveRestriction restriction);
 
   // This function attempts to fill |username_element| and |password_element|
-  // with values from |fill_data|. The |username_element| and |password_element|
-  // will only have the suggestedValue set, and will be registered for copying
-  // that to the real value through |registration_callback|. If a match is
-  // found, return true and |field_value_and_properties_map| will be modified
-  // with the autofilled credentials and |FieldPropertiesFlags::AUTOFILLED|
-  // flag.
+  // with values from |fill_data|. The |password_element| will only have the
+  // suggestedValue set, and will be registered for copying that to the real
+  // value through |registration_callback|. If a match is found, return true and
+  // |field_value_and_properties_map| will be modified with the autofilled
+  // credentials and |FieldPropertiesFlags::AUTOFILLED| flag.
   bool FillUserNameAndPassword(
       blink::WebInputElement* username_element,
       blink::WebInputElement* password_element,
diff --git a/components/autofill/core/browser/BUILD.gn b/components/autofill/core/browser/BUILD.gn
index e1f163b..490257a 100644
--- a/components/autofill/core/browser/BUILD.gn
+++ b/components/autofill/core/browser/BUILD.gn
@@ -284,6 +284,8 @@
     "test_autofill_client.h",
     "test_autofill_clock.cc",
     "test_autofill_clock.h",
+    "test_autofill_download_manager.cc",
+    "test_autofill_download_manager.h",
     "test_autofill_driver.cc",
     "test_autofill_driver.h",
     "test_autofill_external_delegate.cc",
diff --git a/components/autofill/core/browser/autofill_manager_unittest.cc b/components/autofill/core/browser/autofill_manager_unittest.cc
index 1d6d3ff0..6d9b3e6 100644
--- a/components/autofill/core/browser/autofill_manager_unittest.cc
+++ b/components/autofill/core/browser/autofill_manager_unittest.cc
@@ -38,6 +38,7 @@
 #include "components/autofill/core/browser/popup_item_ids.h"
 #include "components/autofill/core/browser/test_autofill_client.h"
 #include "components/autofill/core/browser/test_autofill_clock.h"
+#include "components/autofill/core/browser/test_autofill_download_manager.h"
 #include "components/autofill/core/browser/test_autofill_driver.h"
 #include "components/autofill/core/browser/test_autofill_external_delegate.h"
 #include "components/autofill/core/browser/test_autofill_manager.h"
@@ -102,24 +103,11 @@
   DISALLOW_COPY_AND_ASSIGN(MockAutofillClient);
 };
 
-class TestAutofillDownloadManager : public AutofillDownloadManager {
+class MockAutofillDownloadManager : public TestAutofillDownloadManager {
  public:
-  TestAutofillDownloadManager(AutofillDriver* driver,
+  MockAutofillDownloadManager(AutofillDriver* driver,
                               AutofillDownloadManager::Observer* observer)
-      : AutofillDownloadManager(driver, observer) {}
-
-  bool StartQueryRequest(const std::vector<FormStructure*>& forms) override {
-    last_queried_forms_ = forms;
-    return true;
-  }
-
-  // Verify that the last queried forms equal |expected_forms|.
-  void VerifyLastQueriedForms(const std::vector<FormData>& expected_forms) {
-    ASSERT_EQ(expected_forms.size(), last_queried_forms_.size());
-    for (size_t i = 0; i < expected_forms.size(); ++i) {
-      EXPECT_EQ(*last_queried_forms_[i], expected_forms[i]);
-    }
-  }
+      : TestAutofillDownloadManager(driver, observer) {}
 
   MOCK_METHOD5(StartUploadRequest,
                bool(const FormStructure&,
@@ -129,9 +117,7 @@
                     bool));
 
  private:
-  std::vector<FormStructure*> last_queried_forms_;
-
-  DISALLOW_COPY_AND_ASSIGN(TestAutofillDownloadManager);
+  DISALLOW_COPY_AND_ASSIGN(MockAutofillDownloadManager);
 };
 
 void ExpectFilledField(const char* expected_label,
@@ -287,8 +273,7 @@
 
 class MockAutofillDriver : public TestAutofillDriver {
  public:
-  MockAutofillDriver()
-      : is_incognito_(false), did_interact_with_credit_card_form_(false) {}
+  MockAutofillDriver() {}
 
   // Mock methods to enable testability.
   MOCK_METHOD3(SendFormDataToRenderer,
@@ -299,25 +284,7 @@
   MOCK_METHOD1(SendAutofillTypePredictionsToRenderer,
                void(const std::vector<FormStructure*>& forms));
 
-  void SetIsIncognito(bool is_incognito) { is_incognito_ = is_incognito; }
-
-  bool IsIncognito() const override { return is_incognito_; }
-
-  void DidInteractWithCreditCardForm() override {
-    did_interact_with_credit_card_form_ = true;
-  }
-
-  void ClearDidInteractWithCreditCardForm() {
-    did_interact_with_credit_card_form_ = false;
-  }
-
-  bool did_interact_with_credit_card_form() const {
-    return did_interact_with_credit_card_form_;
-  }
-
  private:
-  bool is_incognito_;
-  bool did_interact_with_credit_card_form_;
   DISALLOW_COPY_AND_ASSIGN(MockAutofillDriver);
 };
 
@@ -452,7 +419,7 @@
     autofill_driver_->SetURLRequestContext(request_context_.get());
     autofill_manager_.reset(new TestAutofillManager(
         autofill_driver_.get(), &autofill_client_, &personal_data_));
-    download_manager_ = new TestAutofillDownloadManager(
+    download_manager_ = new MockAutofillDownloadManager(
         autofill_driver_.get(), autofill_manager_.get());
     // AutofillManager takes ownership of |download_manager_|.
     autofill_manager_->set_download_manager(download_manager_);
@@ -685,7 +652,7 @@
   std::unique_ptr<TestAutofillManager> autofill_manager_;
   std::unique_ptr<TestAutofillExternalDelegate> external_delegate_;
   scoped_refptr<net::TestURLRequestContextGetter> request_context_;
-  TestAutofillDownloadManager* download_manager_;
+  MockAutofillDownloadManager* download_manager_;
   TestPersonalDataManager personal_data_;
   base::test::ScopedFeatureList scoped_feature_list_;
   variations::testing::VariationParamsManager variation_params_;
@@ -5749,12 +5716,12 @@
   form.fields.push_back(field);
   std::vector<FormData> forms(1, form);
   FormsSeen(forms);
-  EXPECT_FALSE(autofill_driver_->did_interact_with_credit_card_form());
+  EXPECT_FALSE(autofill_driver_->GetDidInteractWithCreditCardForm());
 
   // The driver should always be notified.
   for (const FormFieldData& field : form.fields) {
     GetAutofillSuggestions(form, field);
-    EXPECT_TRUE(autofill_driver_->did_interact_with_credit_card_form());
+    EXPECT_TRUE(autofill_driver_->GetDidInteractWithCreditCardForm());
     autofill_driver_->ClearDidInteractWithCreditCardForm();
   }
 }
diff --git a/components/autofill/core/browser/test_autofill_download_manager.cc b/components/autofill/core/browser/test_autofill_download_manager.cc
new file mode 100644
index 0000000..ea4795ed
--- /dev/null
+++ b/components/autofill/core/browser/test_autofill_download_manager.cc
@@ -0,0 +1,33 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/autofill/core/browser/test_autofill_download_manager.h"
+
+#include "components/autofill/core/browser/form_structure.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace autofill {
+
+TestAutofillDownloadManager::TestAutofillDownloadManager(
+    AutofillDriver* driver,
+    AutofillDownloadManager::Observer* observer)
+    : AutofillDownloadManager(driver, observer) {}
+
+TestAutofillDownloadManager::~TestAutofillDownloadManager() {}
+
+bool TestAutofillDownloadManager::StartQueryRequest(
+    const std::vector<FormStructure*>& forms) {
+  last_queried_forms_ = forms;
+  return true;
+}
+
+void TestAutofillDownloadManager::VerifyLastQueriedForms(
+    const std::vector<FormData>& expected_forms) {
+  ASSERT_EQ(expected_forms.size(), last_queried_forms_.size());
+  for (size_t i = 0; i < expected_forms.size(); ++i) {
+    EXPECT_EQ(*last_queried_forms_[i], expected_forms[i]);
+  }
+}
+
+}  // namespace autofill
diff --git a/components/autofill/core/browser/test_autofill_download_manager.h b/components/autofill/core/browser/test_autofill_download_manager.h
new file mode 100644
index 0000000..27e6e2ec
--- /dev/null
+++ b/components/autofill/core/browser/test_autofill_download_manager.h
@@ -0,0 +1,39 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_TEST_AUTOFILL_DOWNLOAD_MANAGER_H_
+#define COMPONENTS_AUTOFILL_CORE_BROWSER_TEST_AUTOFILL_DOWNLOAD_MANAGER_H_
+
+#include <vector>
+
+#include "components/autofill/core/browser/autofill_download_manager.h"
+#include "components/autofill/core/common/form_data.h"
+
+namespace autofill {
+
+class FormStructure;
+
+class TestAutofillDownloadManager : public AutofillDownloadManager {
+ public:
+  TestAutofillDownloadManager(AutofillDriver* driver,
+                              AutofillDownloadManager::Observer* observer);
+  ~TestAutofillDownloadManager() override;
+
+  // AutofillDownloadManager overrides.
+  bool StartQueryRequest(const std::vector<FormStructure*>& forms) override;
+
+  // Unique to TestAutofillDownloadManager:
+
+  // Verify that the last queried forms equal |expected_forms|.
+  void VerifyLastQueriedForms(const std::vector<FormData>& expected_forms);
+
+ private:
+  std::vector<FormStructure*> last_queried_forms_;
+
+  DISALLOW_COPY_AND_ASSIGN(TestAutofillDownloadManager);
+};
+
+}  // namespace autofill
+
+#endif  // COMPONENTS_AUTOFILL_CORE_BROWSER_TEST_AUTOFILL_DOWNLOAD_MANAGER_H_
diff --git a/components/autofill/core/browser/test_autofill_driver.cc b/components/autofill/core/browser/test_autofill_driver.cc
index 26eb8f6..53327e7 100644
--- a/components/autofill/core/browser/test_autofill_driver.cc
+++ b/components/autofill/core/browser/test_autofill_driver.cc
@@ -13,7 +13,7 @@
 TestAutofillDriver::~TestAutofillDriver() {}
 
 bool TestAutofillDriver::IsIncognito() const {
-  return false;
+  return is_incognito_;
 }
 
 net::URLRequestContextGetter* TestAutofillDriver::GetURLRequestContext() {
@@ -47,11 +47,6 @@
 void TestAutofillDriver::RendererShouldClearPreviewedForm() {
 }
 
-void TestAutofillDriver::SetURLRequestContext(
-    net::URLRequestContextGetter* url_request_context) {
-  url_request_context_ = url_request_context;
-}
-
 void TestAutofillDriver::RendererShouldFillFieldWithValue(
     const base::string16& value) {
 }
@@ -68,6 +63,25 @@
   return bounding_box;
 }
 
-void TestAutofillDriver::DidInteractWithCreditCardForm() {}
+void TestAutofillDriver::DidInteractWithCreditCardForm() {
+  did_interact_with_credit_card_form_ = true;
+}
+
+void TestAutofillDriver::ClearDidInteractWithCreditCardForm() {
+  did_interact_with_credit_card_form_ = false;
+}
+
+bool TestAutofillDriver::GetDidInteractWithCreditCardForm() const {
+  return did_interact_with_credit_card_form_;
+}
+
+void TestAutofillDriver::SetIsIncognito(bool is_incognito) {
+  is_incognito_ = is_incognito;
+}
+
+void TestAutofillDriver::SetURLRequestContext(
+    net::URLRequestContextGetter* url_request_context) {
+  url_request_context_ = url_request_context;
+}
 
 }  // namespace autofill
diff --git a/components/autofill/core/browser/test_autofill_driver.h b/components/autofill/core/browser/test_autofill_driver.h
index bc4898b..ef51d80 100644
--- a/components/autofill/core/browser/test_autofill_driver.h
+++ b/components/autofill/core/browser/test_autofill_driver.h
@@ -17,7 +17,7 @@
   TestAutofillDriver();
   ~TestAutofillDriver() override;
 
-  // AutofillDriver implementation.
+  // AutofillDriver implementation overrides.
   bool IsIncognito() const override;
   // Returns the value passed in to the last call to |SetURLRequestContext()|
   // or NULL if that method has never been called.
@@ -42,7 +42,14 @@
       const gfx::RectF& bounding_box) override;
   void DidInteractWithCreditCardForm() override;
 
-  // Methods that tests can use to specialize functionality.
+  // Methods unique to TestAutofillDriver that tests can use to specialize
+  // functionality.
+
+  void ClearDidInteractWithCreditCardForm();
+
+  bool GetDidInteractWithCreditCardForm() const;
+
+  void SetIsIncognito(bool is_incognito);
 
   // Sets the URL request context for this instance. |url_request_context|
   // should outlive this instance.
@@ -50,6 +57,8 @@
 
  private:
   net::URLRequestContextGetter* url_request_context_;
+  bool is_incognito_ = false;
+  bool did_interact_with_credit_card_form_ = false;
 
   DISALLOW_COPY_AND_ASSIGN(TestAutofillDriver);
 };
diff --git a/components/browsing_data/OWNERS b/components/browsing_data/OWNERS
index 1f8f137..9ab8416 100644
--- a/components/browsing_data/OWNERS
+++ b/components/browsing_data/OWNERS
@@ -1,7 +1,3 @@
-bauerb@chromium.org
-markusheintz@chromium.org
-michaeln@chromium.org
-mkwst@chromium.org
-msramek@chromium.org
+file://content/browser/browsing_data/OWNERS
 
 # COMPONENT: Privacy
diff --git a/components/cronet/android/test/javaperftests/run.py b/components/cronet/android/test/javaperftests/run.py
index 4d72854..cce6d7e 100755
--- a/components/cronet/android/test/javaperftests/run.py
+++ b/components/cronet/android/test/javaperftests/run.py
@@ -42,6 +42,7 @@
 
 import logging
 import json
+import optparse
 import os
 import posixpath
 import shutil
@@ -306,6 +307,13 @@
 
 
 def main():
+  parser = optparse.OptionParser()
+  parser.add_option('--output-format', default='html',
+                   help='The output format of the results file.')
+  parser.add_option('--output-dir', default=None,
+                   help='The directory for the output file. Default value is '
+                        'the base directory of this script.')
+  options, _ = parser.parse_args()
   constants.SetBuildType(BUILD_TYPE)
   # Install APK
   device = GetDevice()
@@ -339,6 +347,9 @@
   sys.argv.insert(1, 'run')
   sys.argv.insert(2, 'run.CronetPerfTestBenchmark')
   sys.argv.insert(3, '--browser=any')
+  sys.argv.insert(4, '--output-format=' + options.output_format)
+  if options.output_dir:
+    sys.argv.insert(5, '--output-dir=' + options.output_dir)
   benchmark_runner.main(runner_config)
   # Shutdown.
   quic_server.ShutdownQuicServer()
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_compression_stats.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_compression_stats.cc
index d203ee0..504cf46c 100644
--- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_compression_stats.cc
+++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_compression_stats.cc
@@ -369,15 +369,6 @@
           &DataReductionProxyCompressionStats::OnDataUsageReportingPrefChanged,
           weak_factory_.GetWeakPtr()));
 
-#if defined(OS_ANDROID)
-  if (!base::FeatureList::IsEnabled(features::kDataReductionSiteBreakdown)) {
-    // If the user is moved out of the experiment make sure that data usage
-    // reporting is not enabled and the map is cleared.
-    SetDataUsageReportingEnabled(false);
-    DeleteHistoricalDataUsage();
-  }
-#endif
-
   if (data_usage_reporting_enabled_.GetValue()) {
     current_data_usage_load_status_ = LOADING;
     service_->LoadCurrentDataUsageBucket(base::Bind(
@@ -645,13 +636,15 @@
 
 void DataReductionProxyCompressionStats::OnCurrentDataUsageLoaded(
     std::unique_ptr<DataUsageBucket> data_usage) {
-  DCHECK(current_data_usage_load_status_ == LOADING);
-
   // Exit early if the pref was turned off before loading from storage
   // completed.
   if (!data_usage_reporting_enabled_.GetValue()) {
+    DCHECK_EQ(NOT_LOADED, current_data_usage_load_status_);
+    DCHECK(data_usage_map_.empty());
     current_data_usage_load_status_ = NOT_LOADED;
     return;
+  } else {
+    DCHECK_EQ(LOADING, current_data_usage_load_status_);
   }
 
   DCHECK(data_usage_map_last_updated_.is_null());
@@ -1277,8 +1270,6 @@
   } else {
 // Don't delete the historical data on Android, but clear the map.
 #if defined(OS_ANDROID)
-    DCHECK(current_data_usage_load_status_ != LOADING);
-
     if (current_data_usage_load_status_ == LOADED)
       PersistDataUsage();
 
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_unittest.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_unittest.cc
index a1321eb..e0effac 100644
--- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_unittest.cc
+++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_unittest.cc
@@ -457,13 +457,10 @@
     TestDataReductionProxyConfig config(task_runner(), nullptr, configurator(),
                                         event_creator());
 
-    scoped_refptr<net::URLRequestContextGetter> request_context_getter_ =
-        new net::TestURLRequestContextGetter(task_runner());
-
     NetworkPropertiesManager network_properties_manager(
         test_context_->pref_service(), test_context_->task_runner());
-    config.InitializeOnIOThread(request_context_getter_.get(),
-                                request_context_getter_.get(),
+    config.InitializeOnIOThread(test_context_->request_context_getter(),
+                                test_context_->request_context_getter(),
                                 &network_properties_manager);
     RunUntilIdle();
 
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate_unittest.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate_unittest.cc
index 100eaf4..33c20c1e 100644
--- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate_unittest.cc
+++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate_unittest.cc
@@ -368,6 +368,7 @@
     proxy_service_ =
         net::ProxyService::CreateFixedFromPacResult(proxy_server.ToPacString());
     context_->set_proxy_service(proxy_service_.get());
+    context_->set_network_quality_estimator(&test_network_quality_estimator_);
 
     mock_socket_factory_.reset(new net::MockClientSocketFactory());
 
@@ -395,7 +396,6 @@
     test_context_->io_data()->set_lofi_ui_service(std::move(lofi_ui_service));
 
     context_->set_enable_brotli(enable_brotli_globally);
-    context_->set_network_quality_estimator(&test_network_quality_estimator_);
     context_->Init();
 
     test_context_->DisableWarmupURLFetch();
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_settings.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_settings.cc
index bc58d38..8507040 100644
--- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_settings.cc
+++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_settings.cc
@@ -12,6 +12,7 @@
 #include "base/metrics/histogram_macros.h"
 #include "base/time/clock.h"
 #include "base/time/default_clock.h"
+#include "build/build_config.h"
 #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_compression_stats.h"
 #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_config.h"
 #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_io_data.h"
@@ -88,11 +89,12 @@
   InitPrefMembers();
   RecordDataReductionInit();
 
-  if (base::FeatureList::IsEnabled(features::kDataReductionSiteBreakdown) &&
-      spdy_proxy_auth_enabled_.GetValue()) {
+#if defined(OS_ANDROID)
+  if (spdy_proxy_auth_enabled_.GetValue()) {
     data_reduction_proxy_service_->compression_stats()
         ->SetDataUsageReportingEnabled(true);
   }
+#endif  // defined(OS_ANDROID)
 }
 
 void DataReductionProxySettings::OnServiceInitialized() {
@@ -133,10 +135,10 @@
   if (spdy_proxy_auth_enabled_.GetValue() != enabled) {
     spdy_proxy_auth_enabled_.SetValue(enabled);
     OnProxyEnabledPrefChange();
-    if (base::FeatureList::IsEnabled(features::kDataReductionSiteBreakdown)) {
-      data_reduction_proxy_service_->compression_stats()
-          ->SetDataUsageReportingEnabled(enabled);
-    }
+#if defined(OS_ANDROID)
+    data_reduction_proxy_service_->compression_stats()
+        ->SetDataUsageReportingEnabled(enabled);
+#endif  // defined(OS_ANDROID)
   }
 }
 
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_test_utils.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_test_utils.cc
index 2b1b93e..7f8d401 100644
--- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_test_utils.cc
+++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_test_utils.cc
@@ -35,6 +35,7 @@
 #include "components/prefs/pref_registry_simple.h"
 #include "components/prefs/testing_pref_service.h"
 #include "net/base/network_delegate_impl.h"
+#include "net/nqe/network_quality_estimator_test_util.h"
 #include "net/proxy/proxy_config.h"
 #include "net/proxy/proxy_info.h"
 #include "net/proxy/proxy_list.h"
@@ -419,14 +420,24 @@
   std::unique_ptr<net::TestNetLog> net_log(new net::TestNetLog());
   std::unique_ptr<TestConfigStorer> config_storer(
       new TestConfigStorer(pref_service.get()));
+  std::unique_ptr<net::TestNetworkQualityEstimator> estimator;
+
   if (request_context_) {
     request_context_getter = new net::TrivialURLRequestContextGetter(
         request_context_, task_runner);
+    if (!request_context_->network_quality_estimator()) {
+      estimator.reset(new net::TestNetworkQualityEstimator());
+      request_context_->set_network_quality_estimator(estimator.get());
+    }
   } else {
     std::unique_ptr<net::TestURLRequestContext> test_request_context(
         new net::TestURLRequestContext(true));
     if (mock_socket_factory_)
       test_request_context->set_client_socket_factory(mock_socket_factory_);
+    if (!test_request_context->network_quality_estimator()) {
+      estimator.reset(new net::TestNetworkQualityEstimator());
+      test_request_context->set_network_quality_estimator(estimator.get());
+    }
     test_request_context->Init();
     request_context_getter = new net::TestURLRequestContextGetter(
         task_runner, std::move(test_request_context));
@@ -530,7 +541,8 @@
           task_runner, std::move(pref_service), std::move(net_log),
           request_context_getter, mock_socket_factory_, std::move(io_data),
           std::move(settings), std::move(storage_delegate),
-          std::move(config_storer), raw_params, test_context_flags));
+          std::move(config_storer), std::move(estimator), raw_params,
+          test_context_flags));
 
   if (!skip_settings_initialization_)
     test_context->InitSettingsWithoutCheck();
@@ -549,6 +561,7 @@
     std::unique_ptr<TestDataReductionProxyEventStorageDelegate>
         storage_delegate,
     std::unique_ptr<TestConfigStorer> config_storer,
+    std::unique_ptr<net::TestNetworkQualityEstimator> estimator,
     TestDataReductionProxyParams* params,
     unsigned int test_context_flags)
     : test_context_flags_(test_context_flags),
@@ -556,6 +569,7 @@
       simple_pref_service_(std::move(simple_pref_service)),
       net_log_(std::move(net_log)),
       request_context_getter_(request_context_getter),
+      estimator_(std::move(estimator)),
       mock_socket_factory_(mock_socket_factory),
       io_data_(std::move(io_data)),
       settings_(std::move(settings)),
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_test_utils.h b/components/data_reduction_proxy/core/browser/data_reduction_proxy_test_utils.h
index c4a3962b..f586606 100644
--- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_test_utils.h
+++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_test_utils.h
@@ -39,6 +39,7 @@
 namespace net {
 class MockClientSocketFactory;
 class NetLog;
+class TestNetworkQualityEstimator;
 class URLRequestContext;
 class URLRequestContextStorage;
 }
@@ -509,6 +510,7 @@
       std::unique_ptr<TestDataReductionProxyEventStorageDelegate>
           storage_delegate,
       std::unique_ptr<TestConfigStorer> config_storer,
+      std::unique_ptr<net::TestNetworkQualityEstimator> estimator,
       TestDataReductionProxyParams* params,
       unsigned int test_context_flags);
 
@@ -521,6 +523,7 @@
   std::unique_ptr<TestingPrefServiceSimple> simple_pref_service_;
   std::unique_ptr<net::TestNetLog> net_log_;
   scoped_refptr<net::URLRequestContextGetter> request_context_getter_;
+  std::unique_ptr<net::TestNetworkQualityEstimator> estimator_;
   // Non-owned pointer. Will be NULL if |this| was built without specifying a
   // |net::MockClientSocketFactory|.
   net::MockClientSocketFactory* mock_socket_factory_;
diff --git a/components/data_reduction_proxy/core/browser/warmup_url_fetcher.cc b/components/data_reduction_proxy/core/browser/warmup_url_fetcher.cc
index 8ff36c2..2d4c5094 100644
--- a/components/data_reduction_proxy/core/browser/warmup_url_fetcher.cc
+++ b/components/data_reduction_proxy/core/browser/warmup_url_fetcher.cc
@@ -16,8 +16,10 @@
 #include "components/data_use_measurement/core/data_use_user_data.h"
 #include "net/base/load_flags.h"
 #include "net/http/http_status_code.h"
+#include "net/nqe/network_quality_estimator.h"
 #include "net/traffic_annotation/network_traffic_annotation.h"
 #include "net/url_request/url_fetcher.h"
+#include "net/url_request/url_request_context.h"
 #include "net/url_request/url_request_context_getter.h"
 #include "net/url_request/url_request_status.h"
 
@@ -31,6 +33,8 @@
       is_fetch_in_flight_(false),
       callback_(callback) {
   DCHECK(url_request_context_getter_);
+  DCHECK(url_request_context_getter_->GetURLRequestContext()
+             ->network_quality_estimator());
 }
 
 WarmupURLFetcher::~WarmupURLFetcher() {}
@@ -127,6 +131,8 @@
 
 void WarmupURLFetcher::OnURLFetchComplete(const net::URLFetcher* source) {
   DCHECK_EQ(source, fetcher_.get());
+  DCHECK(is_fetch_in_flight_);
+
   is_fetch_in_flight_ = false;
   UMA_HISTOGRAM_BOOLEAN(
       "DataReductionProxy.WarmupURL.FetchSuccessful",
diff --git a/components/data_reduction_proxy/core/browser/warmup_url_fetcher_unittest.cc b/components/data_reduction_proxy/core/browser/warmup_url_fetcher_unittest.cc
index 44eee2e9..61d1712 100644
--- a/components/data_reduction_proxy/core/browser/warmup_url_fetcher_unittest.cc
+++ b/components/data_reduction_proxy/core/browser/warmup_url_fetcher_unittest.cc
@@ -18,6 +18,7 @@
 #include "components/data_reduction_proxy/core/common/data_reduction_proxy_features.h"
 #include "components/data_reduction_proxy/core/common/data_reduction_proxy_util.h"
 #include "net/http/http_status_code.h"
+#include "net/nqe/network_quality_estimator_test_util.h"
 #include "net/proxy/proxy_server.h"
 #include "net/socket/socket_test_util.h"
 #include "net/url_request/url_fetcher.h"
@@ -89,6 +90,10 @@
   base::MessageLoopForIO message_loop;
   scoped_refptr<net::URLRequestContextGetter> request_context_getter =
       new net::TestURLRequestContextGetter(message_loop.task_runner());
+  net::TestNetworkQualityEstimator estimator;
+  request_context_getter->GetURLRequestContext()->set_network_quality_estimator(
+      &estimator);
+
   WarmupURLFetcherTest warmup_url_fetcher(request_context_getter);
 
   GURL gurl_original;
@@ -143,6 +148,9 @@
   scoped_refptr<net::URLRequestContextGetter> request_context_getter =
       new net::TestURLRequestContextGetter(message_loop.task_runner(),
                                            std::move(test_request_context));
+  net::TestNetworkQualityEstimator estimator;
+  request_context_getter->GetURLRequestContext()->set_network_quality_estimator(
+      &estimator);
 
   WarmupURLFetcherTest warmup_url_fetcher(request_context_getter);
   EXPECT_FALSE(warmup_url_fetcher.IsFetchInFlight());
@@ -202,6 +210,9 @@
   scoped_refptr<net::URLRequestContextGetter> request_context_getter =
       new net::TestURLRequestContextGetter(message_loop.task_runner(),
                                            std::move(test_request_context));
+  net::TestNetworkQualityEstimator estimator;
+  request_context_getter->GetURLRequestContext()->set_network_quality_estimator(
+      &estimator);
 
   WarmupURLFetcherTest warmup_url_fetcher(request_context_getter);
   EXPECT_FALSE(warmup_url_fetcher.IsFetchInFlight());
@@ -259,6 +270,9 @@
   scoped_refptr<net::URLRequestContextGetter> request_context_getter =
       new net::TestURLRequestContextGetter(message_loop.task_runner(),
                                            std::move(test_request_context));
+  net::TestNetworkQualityEstimator estimator;
+  request_context_getter->GetURLRequestContext()->set_network_quality_estimator(
+      &estimator);
 
   WarmupURLFetcherTest warmup_url_fetcher(request_context_getter);
   warmup_url_fetcher.FetchWarmupURL(0);
@@ -308,6 +322,9 @@
   scoped_refptr<net::URLRequestContextGetter> request_context_getter =
       new net::TestURLRequestContextGetter(message_loop.task_runner(),
                                            std::move(test_request_context));
+  net::TestNetworkQualityEstimator estimator;
+  request_context_getter->GetURLRequestContext()->set_network_quality_estimator(
+      &estimator);
 
   WarmupURLFetcherTest warmup_url_fetcher(request_context_getter);
   EXPECT_FALSE(warmup_url_fetcher.IsFetchInFlight());
@@ -363,6 +380,9 @@
   scoped_refptr<net::URLRequestContextGetter> request_context_getter =
       new net::TestURLRequestContextGetter(message_loop.task_runner(),
                                            std::move(test_request_context));
+  net::TestNetworkQualityEstimator estimator;
+  request_context_getter->GetURLRequestContext()->set_network_quality_estimator(
+      &estimator);
 
   WarmupURLFetcherTest warmup_url_fetcher(request_context_getter);
   EXPECT_FALSE(warmup_url_fetcher.IsFetchInFlight());
diff --git a/components/data_reduction_proxy/core/common/data_reduction_proxy_features.cc b/components/data_reduction_proxy/core/common/data_reduction_proxy_features.cc
index 871d225..3b007a4b 100644
--- a/components/data_reduction_proxy/core/common/data_reduction_proxy_features.cc
+++ b/components/data_reduction_proxy/core/common/data_reduction_proxy_features.cc
@@ -13,10 +13,6 @@
 const base::Feature kDataReductionMainMenu{"DataReductionProxyMainMenu",
                                            base::FEATURE_DISABLED_BY_DEFAULT};
 
-// Enables the site breakdown on the Data Reduction Proxy settings page.
-const base::Feature kDataReductionSiteBreakdown{
-    "DataReductionProxySiteBreakdown", base::FEATURE_DISABLED_BY_DEFAULT};
-
 // Enables a new version of the data reduction proxy protocol where the server
 // decides if a server-generated preview should be served. The previous
 // version required the client to make this decision. The new protocol relies
diff --git a/components/data_reduction_proxy/core/common/data_reduction_proxy_features.h b/components/data_reduction_proxy/core/common/data_reduction_proxy_features.h
index fa7fef5..d9711e1 100644
--- a/components/data_reduction_proxy/core/common/data_reduction_proxy_features.h
+++ b/components/data_reduction_proxy/core/common/data_reduction_proxy_features.h
@@ -11,7 +11,6 @@
 namespace features {
 
 extern const base::Feature kDataReductionMainMenu;
-extern const base::Feature kDataReductionSiteBreakdown;
 extern const base::Feature kDataReductionProxyDecidesTransform;
 extern const base::Feature kDataReductionProxyLowMemoryDevicePromo;
 extern const base::Feature kMissingViaHeaderShortDuration;
diff --git a/components/exo/wayland/clients/rects.cc b/components/exo/wayland/clients/rects.cc
index 307ad3a..f15af306 100644
--- a/components/exo/wayland/clients/rects.cc
+++ b/components/exo/wayland/clients/rects.cc
@@ -196,9 +196,14 @@
                        struct wp_presentation_feedback* presentation_feedback) {
   Presentation* presentation = static_cast<Presentation*>(data);
   DCHECK_GT(presentation->scheduled_frames.size(), 0u);
-  std::unique_ptr<Frame> frame =
-      std::move(presentation->scheduled_frames.front());
-  presentation->scheduled_frames.pop_front();
+  auto it =
+      std::find_if(presentation->scheduled_frames.begin(),
+                   presentation->scheduled_frames.end(),
+                   [presentation_feedback](std::unique_ptr<Frame>& frame) {
+                     return frame->feedback.get() == presentation_feedback;
+                   });
+  DCHECK(it != presentation->scheduled_frames.end());
+  presentation->scheduled_frames.erase(it);
   LOG(WARNING) << "Frame discarded";
 }
 
diff --git a/components/exo/wayland/clients/simple.cc b/components/exo/wayland/clients/simple.cc
index 6f59102..2712e35 100644
--- a/components/exo/wayland/clients/simple.cc
+++ b/components/exo/wayland/clients/simple.cc
@@ -68,10 +68,12 @@
 void FeedbackDiscarded(void* data, struct wp_presentation_feedback* feedback) {
   Presentation* presentation = static_cast<Presentation*>(data);
   DCHECK_GT(presentation->submitted_frames.size(), 0u);
-
-  Frame& frame = presentation->submitted_frames.front();
-  DCHECK_EQ(frame.feedback.get(), feedback);
-  presentation->submitted_frames.pop_front();
+  auto it = std::find_if(
+      presentation->submitted_frames.begin(),
+      presentation->submitted_frames.end(),
+      [feedback](Frame& frame) { return frame.feedback.get() == feedback; });
+  DCHECK(it != presentation->submitted_frames.end());
+  presentation->submitted_frames.erase(it);
 }
 
 }  // namespace
diff --git a/components/history/core/browser/history_constants.cc b/components/history/core/browser/history_constants.cc
index 6a12b6b..79cd33fa6e 100644
--- a/components/history/core/browser/history_constants.cc
+++ b/components/history/core/browser/history_constants.cc
@@ -18,4 +18,9 @@
 
 const int kMaxTopHosts = 50;
 
+base::TimeDelta GetTitleSettingWindow() {
+  const auto value = base::TimeDelta::FromSeconds(5);
+  return value;
+}
+
 }  // namespace history
diff --git a/components/history/core/browser/history_constants.h b/components/history/core/browser/history_constants.h
index 2ae59a29..b89804c 100644
--- a/components/history/core/browser/history_constants.h
+++ b/components/history/core/browser/history_constants.h
@@ -6,6 +6,7 @@
 #define COMPONENTS_HISTORY_CORE_BROWSER_HISTORY_CONSTANTS_H_
 
 #include "base/files/file_path.h"
+#include "base/time/time.h"
 
 namespace history {
 
@@ -17,6 +18,10 @@
 // The maximum size of the list returned by history::HistoryService::TopHosts().
 extern const int kMaxTopHosts;
 
+// The span of time after load is complete during which a page may set its title
+// and have the title change be saved in history.
+base::TimeDelta GetTitleSettingWindow();
+
 }  // namespace history
 
 #endif  // COMPONENTS_HISTORY_CORE_BROWSER_HISTORY_CONSTANTS_H_
diff --git a/components/safe_browsing/BUILD.gn b/components/safe_browsing/BUILD.gn
index 974b9d7..5fba677 100644
--- a/components/safe_browsing/BUILD.gn
+++ b/components/safe_browsing/BUILD.gn
@@ -20,12 +20,8 @@
   sources = [
     "base_blocking_page.cc",
     "base_blocking_page.h",
-    "base_resource_throttle.cc",
-    "base_resource_throttle.h",
     "base_ui_manager.cc",
     "base_ui_manager.h",
-    "net_event_logger.cc",
-    "net_event_logger.h",
   ]
   public_deps = [
     "//components/security_interstitials/content:security_interstitial_page",
diff --git a/components/safe_browsing/base_resource_throttle.cc b/components/safe_browsing/base_resource_throttle.cc
deleted file mode 100644
index e44251a..0000000
--- a/components/safe_browsing/base_resource_throttle.cc
+++ /dev/null
@@ -1,373 +0,0 @@
-// Copyright (c) 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 "components/safe_browsing/base_resource_throttle.h"
-
-#include <utility>
-
-#include "base/metrics/histogram_macros.h"
-#include "base/trace_event/trace_event.h"
-#include "components/safe_browsing/base_ui_manager.h"
-#include "components/safe_browsing/common/utils.h"
-#include "components/safe_browsing/db/util.h"
-#include "components/safe_browsing/web_ui/constants.h"
-#include "components/security_interstitials/content/unsafe_resource.h"
-#include "content/public/browser/browser_thread.h"
-#include "content/public/browser/resource_request_info.h"
-#include "content/public/browser/web_contents.h"
-#include "net/base/load_flags.h"
-#include "net/log/net_log_event_type.h"
-#include "net/url_request/redirect_info.h"
-#include "net/url_request/url_request.h"
-
-using net::NetLogEventType;
-
-namespace safe_browsing {
-
-namespace {
-
-// Maximum time in milliseconds to wait for the safe browsing service to
-// verify a URL. After this amount of time the outstanding check will be
-// aborted, and the URL will be treated as if it were safe.
-const int kCheckUrlTimeoutMs = 5000;
-
-}  // namespace
-
-// TODO(eroman): Downgrade these CHECK()s to DCHECKs once there is more
-//               unit test coverage.
-
-BaseResourceThrottle::BaseResourceThrottle(
-    const net::URLRequest* request,
-    content::ResourceType resource_type,
-    SBThreatTypeSet threat_types,
-    scoped_refptr<SafeBrowsingDatabaseManager> database_manager,
-    scoped_refptr<BaseUIManager> ui_manager)
-    : ui_manager_(ui_manager),
-      threat_type_(SB_THREAT_TYPE_SAFE),
-      threat_types_(std::move(threat_types)),
-      database_manager_(database_manager),
-      request_(request),
-      state_(STATE_NONE),
-      defer_state_(DEFERRED_NONE),
-      resource_type_(resource_type),
-      net_event_logger_(&request->net_log()) {}
-
-BaseResourceThrottle::~BaseResourceThrottle() {
-  if (defer_state_ != DEFERRED_NONE) {
-    net_event_logger_.EndNetLogEvent(NetLogEventType::SAFE_BROWSING_DEFERRED,
-                                     nullptr, nullptr);
-  }
-
-  if (state_ == STATE_CHECKING_URL) {
-    database_manager_->CancelCheck(this);
-    net_event_logger_.EndNetLogEvent(
-        NetLogEventType::SAFE_BROWSING_CHECKING_URL, "result",
-        "request_canceled");
-  }
-
-  if (!user_action_involved_)
-    LogNoUserActionResourceLoadingDelay(total_delay_);
-}
-
-void BaseResourceThrottle::WillStartRequest(bool* defer) {
-  // We need to check the new URL before starting the request.
-  if (CheckUrl(request_->url()))
-    return;
-
-  // We let the check run in parallel with resource load only if this
-  // db_manager only supports asynchronous checks, like on mobile.
-  // Otherwise, we defer now.
-  if (database_manager_->ChecksAreAlwaysAsync())
-    return;
-
-  // If the URL couldn't be verified synchronously, defer starting the
-  // request until the check has completed.
-  defer_state_ = DEFERRED_START;
-  defer_start_time_ = base::TimeTicks::Now();
-  *defer = true;
-  net_event_logger_.BeginNetLogEvent(NetLogEventType::SAFE_BROWSING_DEFERRED,
-                                     request_->url(), "defer_reason",
-                                     "at_start");
-}
-
-void BaseResourceThrottle::WillProcessResponse(bool* defer) {
-  CHECK_EQ(defer_state_, DEFERRED_NONE);
-  // TODO(nparker): Maybe remove this check, since it should have no effect.
-  if (!database_manager_->ChecksAreAlwaysAsync())
-    return;
-
-  if (state_ == STATE_CHECKING_URL ||
-      state_ == STATE_DISPLAYING_BLOCKING_PAGE) {
-    defer_state_ = DEFERRED_PROCESSING;
-    defer_start_time_ = base::TimeTicks::Now();
-    *defer = true;
-    net_event_logger_.BeginNetLogEvent(NetLogEventType::SAFE_BROWSING_DEFERRED,
-                                       request_->url(), "defer_reason",
-                                       "at_response");
-  }
-}
-
-bool BaseResourceThrottle::MustProcessResponseBeforeReadingBody() {
-  // On Android, SafeBrowsing may only decide to cancel the request when the
-  // response has been received. Therefore, no part of it should be cached
-  // until this ResourceThrottle has been able to check the response. This
-  // prevents the following scenario:
-  //   1) A request is made for foo.com which has been hacked.
-  //   2) The request is only canceled at WillProcessResponse stage, but part of
-  //   it has been cached.
-  //   3) foo.com is no longer hacked and removed from the SafeBrowsing list.
-  //   4) The user requests foo.com, which is not on the SafeBrowsing list. This
-  //   is deemed safe. However, the resource is actually served from cache,
-  //   using the version that was previously stored.
-  //   5) This results in the  user accessing an unsafe resource without being
-  //   notified that it's dangerous.
-  // TODO(clamy): Add a browser test that checks this specific scenario.
-  return true;
-}
-
-void BaseResourceThrottle::WillRedirectRequest(
-    const net::RedirectInfo& redirect_info,
-    bool* defer) {
-  CHECK_EQ(defer_state_, DEFERRED_NONE);
-
-  // Prev check completed and was safe.
-  if (state_ == STATE_NONE) {
-    // Save the redirect urls for possible malware detail reporting later.
-    redirect_urls_.push_back(redirect_info.new_url);
-
-    // We need to check the new URL before following the redirect.
-    if (CheckUrl(redirect_info.new_url))
-      return;
-    defer_state_ = DEFERRED_REDIRECT;
-  } else {
-    CHECK(state_ == STATE_CHECKING_URL ||
-          state_ == STATE_DISPLAYING_BLOCKING_PAGE);
-    // We can't check this new URL until we have finished checking
-    // the prev one, or resumed from the blocking page.
-    unchecked_redirect_url_ = redirect_info.new_url;
-    defer_state_ = DEFERRED_UNCHECKED_REDIRECT;
-  }
-
-  defer_start_time_ = base::TimeTicks::Now();
-  *defer = true;
-  net_event_logger_.BeginNetLogEvent(
-      NetLogEventType::SAFE_BROWSING_DEFERRED, redirect_info.new_url,
-      "defer_reason",
-      defer_state_ == DEFERRED_REDIRECT ? "redirect" : "unchecked_redirect");
-}
-
-const char* BaseResourceThrottle::GetNameForLogging() const {
-  return "BaseResourceThrottle";
-}
-
-void BaseResourceThrottle::MaybeDestroyPrerenderContents(
-    const content::ResourceRequestInfo* info) {}
-
-// SafeBrowsingService::Client implementation, called on the IO thread once
-// the URL has been classified.
-void BaseResourceThrottle::OnCheckBrowseUrlResult(
-    const GURL& url,
-    SBThreatType threat_type,
-    const ThreatMetadata& metadata) {
-  CHECK_EQ(state_, STATE_CHECKING_URL);
-  CHECK(url.is_valid());
-  CHECK(url_being_checked_.is_valid());
-  CHECK_EQ(url, url_being_checked_);
-
-  timer_.Stop();  // Cancel the timeout timer.
-  threat_type_ = threat_type;
-  state_ = STATE_NONE;
-
-  if (defer_state_ != DEFERRED_NONE) {
-    total_delay_ += base::TimeTicks::Now() - defer_start_time_;
-    net_event_logger_.EndNetLogEvent(NetLogEventType::SAFE_BROWSING_DEFERRED,
-                                     nullptr, nullptr);
-  }
-  net_event_logger_.EndNetLogEvent(
-      NetLogEventType::SAFE_BROWSING_CHECKING_URL, "result",
-      threat_type_ == SB_THREAT_TYPE_SAFE ? "safe" : "unsafe");
-
-  if (threat_type == SB_THREAT_TYPE_SAFE) {
-    if (defer_state_ != DEFERRED_NONE) {
-      // Log how much time the safe browsing check cost us.
-      LogDelay(base::TimeTicks::Now() - defer_start_time_);
-      ResumeRequest();
-    } else {
-      LogDelay(base::TimeDelta());
-    }
-    return;
-  }
-
-  const content::ResourceRequestInfo* info =
-      content::ResourceRequestInfo::ForRequest(request_);
-
-  if (request_->load_flags() & net::LOAD_PREFETCH) {
-    // Destroy the prefetch with FINAL_STATUS_SAFEBROSWING.
-    if (resource_type_ == content::RESOURCE_TYPE_MAIN_FRAME) {
-      MaybeDestroyPrerenderContents(info);
-    }
-    // Don't prefetch resources that fail safe browsing, disallow them.
-    Cancel();
-    UMA_HISTOGRAM_ENUMERATION("SB2.ResourceTypes2.UnsafePrefetchCanceled",
-                              resource_type_, content::RESOURCE_TYPE_LAST_TYPE);
-    return;
-  }
-
-  UMA_HISTOGRAM_ENUMERATION("SB2.ResourceTypes2.Unsafe", resource_type_,
-                            content::RESOURCE_TYPE_LAST_TYPE);
-
-  user_action_involved_ = true;
-
-  security_interstitials::UnsafeResource resource;
-  resource.url = url;
-  resource.original_url = request_->original_url();
-  resource.redirect_urls = redirect_urls_;
-  resource.is_subresource = resource_type_ != content::RESOURCE_TYPE_MAIN_FRAME;
-  resource.is_subframe = resource_type_ == content::RESOURCE_TYPE_SUB_FRAME;
-  resource.threat_type = threat_type;
-  resource.threat_metadata = metadata;
-  resource.callback = base::Bind(
-      &BaseResourceThrottle::OnBlockingPageComplete, AsWeakPtr());
-  resource.callback_thread = content::BrowserThread::GetTaskRunnerForThread(
-      content::BrowserThread::IO);
-  resource.web_contents_getter = info->GetWebContentsGetterForRequest();
-  resource.threat_source = database_manager_->GetThreatSource();
-
-  state_ = STATE_DISPLAYING_BLOCKING_PAGE;
-
-  StartDisplayingBlockingPageHelper(resource);
-}
-
-void BaseResourceThrottle::OnBlockingPageComplete(bool proceed) {
-  CHECK_EQ(state_, STATE_DISPLAYING_BLOCKING_PAGE);
-  state_ = STATE_NONE;
-
-  if (proceed) {
-    threat_type_ = SB_THREAT_TYPE_SAFE;
-    if (defer_state_ != DEFERRED_NONE) {
-      ResumeRequest();
-    }
-  } else {
-    CancelResourceLoad();
-  }
-}
-
-void BaseResourceThrottle::CancelResourceLoad() {
-  Cancel();
-}
-
-scoped_refptr<BaseUIManager> BaseResourceThrottle::ui_manager() {
-  return ui_manager_;
-}
-
-bool BaseResourceThrottle::CheckUrl(const GURL& url) {
-  TRACE_EVENT1("loader", "BaseResourceThrottle::CheckUrl", "url",
-               url.spec());
-  CHECK_EQ(state_, STATE_NONE);
-  // To reduce aggregate latency on mobile, check only the most dangerous
-  // resource types.
-  if (!database_manager_->CanCheckResourceType(resource_type_)) {
-    // TODO(vakh): Consider changing this metric to SafeBrowsing.V4ResourceType
-    // to be consistent with the other PVer4 metrics.
-    UMA_HISTOGRAM_ENUMERATION("SB2.ResourceTypes2.Skipped", resource_type_,
-                              content::RESOURCE_TYPE_LAST_TYPE);
-    return true;
-  }
-
-  // TODO(vakh): Consider changing this metric to SafeBrowsing.V4ResourceType to
-  // be consistent with the other PVer4 metrics.
-  UMA_HISTOGRAM_ENUMERATION("SB2.ResourceTypes2.Checked", resource_type_,
-                            content::RESOURCE_TYPE_LAST_TYPE);
-
-  if (CheckWebUIUrls(url)) {
-    return false;
-  }
-
-  if (database_manager_->CheckBrowseUrl(url, threat_types_, this)) {
-    threat_type_ = SB_THREAT_TYPE_SAFE;
-    LogDelay(base::TimeDelta());  // No delay.
-    return true;
-  }
-
-  state_ = STATE_CHECKING_URL;
-  url_being_checked_ = url;
-  // Note on net_log calls: Synchronous checks are not logged at all.
-  net_event_logger_.BeginNetLogEvent(
-      NetLogEventType::SAFE_BROWSING_CHECKING_URL, url, nullptr, nullptr);
-
-  // Start a timer to abort the check if it takes too long.
-  // TODO(nparker): Set this only when we defer, based on remaining time,
-  // so we don't cancel earlier than necessary.
-  timer_.Start(FROM_HERE, base::TimeDelta::FromMilliseconds(kCheckUrlTimeoutMs),
-               this, &BaseResourceThrottle::OnCheckUrlTimeout);
-
-  return false;
-}
-
-bool BaseResourceThrottle::CheckWebUIUrls(const GURL& url) {
-  DCHECK(threat_type_ == safe_browsing::SB_THREAT_TYPE_SAFE);
-  if (url == kChromeUISafeBrowsingMatchMalwareUrl) {
-    threat_type_ = safe_browsing::SB_THREAT_TYPE_URL_MALWARE;
-  } else if (url == kChromeUISafeBrowsingMatchPhishingUrl) {
-    threat_type_ = safe_browsing::SB_THREAT_TYPE_URL_PHISHING;
-  } else if (url == kChromeUISafeBrowsingMatchUnwantedUrl) {
-    threat_type_ = safe_browsing::SB_THREAT_TYPE_URL_UNWANTED;
-  }
-
-  if (threat_type_ != safe_browsing::SB_THREAT_TYPE_SAFE) {
-    state_ = STATE_CHECKING_URL;
-    url_being_checked_ = url;
-    content::BrowserThread::PostTask(
-        content::BrowserThread::IO, FROM_HERE,
-        base::Bind(&BaseResourceThrottle::OnCheckBrowseUrlResult, AsWeakPtr(),
-                   url, threat_type_, ThreatMetadata()));
-    return true;
-  }
-  return false;
-}
-
-void BaseResourceThrottle::OnCheckUrlTimeout() {
-  CHECK_EQ(state_, STATE_CHECKING_URL);
-
-  database_manager_->CancelCheck(this);
-
-  OnCheckBrowseUrlResult(url_being_checked_, safe_browsing::SB_THREAT_TYPE_SAFE,
-                         ThreatMetadata());
-}
-
-void BaseResourceThrottle::ResumeRequest() {
-  CHECK_EQ(state_, STATE_NONE);
-  CHECK_NE(defer_state_, DEFERRED_NONE);
-
-  bool resume = true;
-  if (defer_state_ == DEFERRED_UNCHECKED_REDIRECT) {
-    // Save the redirect urls for possible malware detail reporting later.
-    redirect_urls_.push_back(unchecked_redirect_url_);
-    if (!CheckUrl(unchecked_redirect_url_)) {
-      // We're now waiting for the unchecked_redirect_url_.
-      defer_state_ = DEFERRED_REDIRECT;
-      defer_start_time_ = base::TimeTicks::Now();
-      resume = false;
-      net_event_logger_.BeginNetLogEvent(
-          NetLogEventType::SAFE_BROWSING_DEFERRED, unchecked_redirect_url_,
-          "defer_reason", "resumed_redirect");
-    }
-  }
-
-  if (resume) {
-    defer_state_ = DEFERRED_NONE;
-    Resume();
-  }
-}
-
-void BaseResourceThrottle::LogDelay(base::TimeDelta time) {
-  UMA_HISTOGRAM_LONG_TIMES("SB2.Delay", time);
-  if (resource_type_ == content::RESOURCE_TYPE_MAIN_FRAME) {
-    UMA_HISTOGRAM_LONG_TIMES("SB2.Delay.MainFrame", time);
-  } else {
-    UMA_HISTOGRAM_LONG_TIMES("SB2.Delay.Subresource", time);
-  }
-}
-
-}  // namespace safe_browsing
diff --git a/components/safe_browsing/base_resource_throttle.h b/components/safe_browsing/base_resource_throttle.h
deleted file mode 100644
index 758a825aa..0000000
--- a/components/safe_browsing/base_resource_throttle.h
+++ /dev/null
@@ -1,189 +0,0 @@
-// Copyright (c) 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 COMPONENTS_SAFE_BROWSING_BASE_RESOURCE_THROTTLE_H_
-#define COMPONENTS_SAFE_BROWSING_BASE_RESOURCE_THROTTLE_H_
-
-#include <vector>
-
-#include "base/macros.h"
-#include "base/memory/ref_counted.h"
-#include "base/time/time.h"
-#include "base/timer/timer.h"
-#include "components/safe_browsing/base_ui_manager.h"
-#include "components/safe_browsing/db/database_manager.h"
-#include "components/safe_browsing/db/v4_protocol_manager_util.h"
-#include "components/safe_browsing/net_event_logger.h"
-#include "components/security_interstitials/content/unsafe_resource.h"
-#include "content/public/browser/resource_throttle.h"
-#include "content/public/common/resource_type.h"
-#include "url/gurl.h"
-
-namespace content {
-class ResourceRequestInfo;
-}
-
-namespace net {
-class URLRequest;
-}
-
-namespace safe_browsing {
-
-// BaseResourceThrottle checks that URLs are "safe" before
-// navigating to them. To be considered "safe", a URL must not appear in the
-// malware/phishing blacklists (see SafeBrowsingService for details).
-//
-// Note that the safe browsing check takes at most kCheckUrlTimeoutMs
-// milliseconds. If it takes longer than this, then the system defaults to
-// treating the URL as safe.
-//
-// If the URL is classified as dangerous, a warning page is thrown up and
-// the request remains suspended.  If the user clicks "proceed" on warning
-// page, we resume the request.
-//
-// Note: The ResourceThrottle interface is called in this order:
-// WillStartRequest once, WillRedirectRequest zero or more times, and then
-// WillProcessReponse once.
-class BaseResourceThrottle
-    : public content::ResourceThrottle,
-      public SafeBrowsingDatabaseManager::Client,
-      public base::SupportsWeakPtr<BaseResourceThrottle> {
- public:
-  // content::ResourceThrottle implementation (called on IO thread):
-  void WillStartRequest(bool* defer) override;
-  void WillRedirectRequest(const net::RedirectInfo& redirect_info,
-                           bool* defer) override;
-  void WillProcessResponse(bool* defer) override;
-  bool MustProcessResponseBeforeReadingBody() override;
-
-  const char* GetNameForLogging() const override;
-
-  // SafeBrowsingDatabaseManager::Client implementation (called on IO thread):
-  void OnCheckBrowseUrlResult(
-      const GURL& url,
-      SBThreatType threat_type,
-      const ThreatMetadata& metadata) override;
-
-  // Called on the IO thread when the user has decided to proceed with the
-  // current request, or go back.
-  void OnBlockingPageComplete(bool proceed);
-
- protected:
-  BaseResourceThrottle(
-      const net::URLRequest* request,
-      content::ResourceType resource_type,
-      SBThreatTypeSet threat_types,
-      scoped_refptr<SafeBrowsingDatabaseManager> database_manager,
-      scoped_refptr<BaseUIManager> ui_manager);
-
-  ~BaseResourceThrottle() override;
-
-  // If our blocked resource is the main frame, this calls
-  // ContentSubresourceFilterDriverFactory's
-  // OnMainResourceMatchedSafeBrowsingBlacklist method.
-  static void NotifySubresourceFilterOfBlockedResource(
-      const security_interstitials::UnsafeResource& resource);
-
-  // Does nothing in the base class. Override this to destroy prerender contents
-  // in chrome.
-  virtual void MaybeDestroyPrerenderContents(
-      const content::ResourceRequestInfo* info);
-
-  // Posts a task for StartDisplayingBlockingPage
-  virtual void StartDisplayingBlockingPageHelper(
-      security_interstitials::UnsafeResource resource) = 0;
-
-  // Called by OnBlockingPageComplete when proceed == false. This removes the
-  // blocking page. This calls ResourceThrottle::Cancel() to show the previous
-  // page, but may be overridden in a subclass. The override in subclass should
-  // call this base implementation for cancellation, instead of calling
-  // ResourceThrottle::Cancel() directly.
-  virtual void CancelResourceLoad();
-
-  // Starts running |url| through the safe browsing check. Returns true if the
-  // URL is safe to visit. Otherwise returns false and will call
-  // OnBrowseUrlResult() when the check has completed.
-  virtual bool CheckUrl(const GURL& url);
-
-  scoped_refptr<BaseUIManager> ui_manager();
-
- private:
-  // Describes what phase of the check a throttle is in.
-  enum State {
-    // Haven't started checking or checking is complete. Not deferred.
-    STATE_NONE,
-    // We have one outstanding URL-check. Could be deferred.
-    STATE_CHECKING_URL,
-    // We're displaying a blocking page. Could be deferred.
-    STATE_DISPLAYING_BLOCKING_PAGE,
-  };
-
-  // Describes what stage of the request got paused by the check.
-  enum DeferState {
-    DEFERRED_NONE,
-    DEFERRED_START,
-    DEFERRED_REDIRECT,
-    DEFERRED_UNCHECKED_REDIRECT,  // unchecked_redirect_url_ is populated.
-    DEFERRED_PROCESSING,
-  };
-
-  // Checks if |url| is one of the hardcoded WebUI match URLs. Returns true if
-  // the URL is one of the hardcoded URLs and will post a task to
-  // OnCheckBrowseUrlResult.
-  bool CheckWebUIUrls(const GURL& url);
-
-  scoped_refptr<BaseUIManager> ui_manager_;
-
-  // Callback for when the safe browsing check (which was initiated by
-  // StartCheckingUrl()) has taken longer than kCheckUrlTimeoutMs.
-  void OnCheckUrlTimeout();
-
-  void ResumeRequest();
-
-  // UMA histogram helper for logging "SB2.Delay".
-  // Logs the user perceived delay caused by SafeBrowsing. This delay is the
-  // time delta starting from when we would have started reading data from the
-  // network, and ending when the SafeBrowsing check completes.
-  void LogDelay(base::TimeDelta delay);
-
-  // The result of the most recent safe browsing check. Only valid to read this
-  // when state_ != STATE_CHECKING_URL.
-  safe_browsing::SBThreatType threat_type_;
-
-  // The time when we started deferring the request.
-  base::TimeTicks defer_start_time_;
-
-  // Timer to abort the safe browsing check if it takes too long.
-  base::OneShotTimer timer_;
-
-  // The redirect chain for this resource
-  std::vector<GURL> redirect_urls_;
-
-  // If in DEFERRED_UNCHECKED_REDIRECT state, this is the
-  // URL we still need to check before resuming.
-  GURL unchecked_redirect_url_;
-  GURL url_being_checked_;
-
-  const SBThreatTypeSet threat_types_;
-  scoped_refptr<SafeBrowsingDatabaseManager> database_manager_;
-  const net::URLRequest* request_;
-
-  State state_;
-  DeferState defer_state_;
-
-  const content::ResourceType resource_type_;
-  NetEventLogger net_event_logger_;
-
-  // The total delay caused by SafeBrowsing deferring the resource load.
-  base::TimeDelta total_delay_;
-  // Whether the interstitial page has been shown and therefore user action has
-  // been involved.
-  bool user_action_involved_ = false;
-
-  DISALLOW_COPY_AND_ASSIGN(BaseResourceThrottle);
-};
-
-}  // namespace safe_browsing
-
-#endif  // COMPONENTS_SAFE_BROWSING_BASE_RESOURCE_THROTTLE_H_
diff --git a/components/safe_browsing/browser/base_parallel_resource_throttle.h b/components/safe_browsing/browser/base_parallel_resource_throttle.h
index f0b3be8a..ab4da82 100644
--- a/components/safe_browsing/browser/base_parallel_resource_throttle.h
+++ b/components/safe_browsing/browser/base_parallel_resource_throttle.h
@@ -22,7 +22,6 @@
 
 // A thin wrapper around BrowserURLLoaderThrottle to adapt to the
 // content::ResourceThrottle interface.
-// Used when --enable-features=S13nSafeBrowsingParallelUrlCheck is in effect.
 class BaseParallelResourceThrottle : public content::ResourceThrottle {
  protected:
   BaseParallelResourceThrottle(
diff --git a/components/safe_browsing/browser/browser_url_loader_throttle.cc b/components/safe_browsing/browser/browser_url_loader_throttle.cc
index a81ab89..ef28558 100644
--- a/components/safe_browsing/browser/browser_url_loader_throttle.cc
+++ b/components/safe_browsing/browser/browser_url_loader_throttle.cc
@@ -54,7 +54,8 @@
   original_url_ = request->url;
   pending_checks_++;
   url_checker_ = base::MakeUnique<SafeBrowsingUrlCheckerImpl>(
-      request->headers, request->load_flags, request->resource_type,
+      request->headers, request->load_flags,
+      static_cast<content::ResourceType>(request->resource_type),
       request->has_user_gesture, std::move(url_checker_delegate_),
       web_contents_getter_);
 
diff --git a/components/safe_browsing/browser/browser_url_loader_throttle.h b/components/safe_browsing/browser/browser_url_loader_throttle.h
index 8d31786..45c9722 100644
--- a/components/safe_browsing/browser/browser_url_loader_throttle.h
+++ b/components/safe_browsing/browser/browser_url_loader_throttle.h
@@ -25,8 +25,13 @@
 
 // BrowserURLLoaderThrottle is used in the browser process to query
 // SafeBrowsing to determine whether a URL and also its redirect URLs are safe
-// to load. It defers response processing until all URL checks are completed;
-// cancels the load if any URLs turn out to be bad.
+// to load.
+//
+// This throttle never defers starting the URL request or following redirects,
+// no matter on mobile or desktop. If any of the checks for the original URL
+// and redirect chain are not complete by the time the response headers are
+// available, the request is deferred until all the checks are done. It cancels
+// the load if any URLs turn out to be bad.
 class BrowserURLLoaderThrottle : public content::URLLoaderThrottle {
  public:
   static std::unique_ptr<BrowserURLLoaderThrottle> MaybeCreate(
diff --git a/components/safe_browsing/browser/safe_browsing_url_checker_impl.cc b/components/safe_browsing/browser/safe_browsing_url_checker_impl.cc
index 5e9e22c..e6c49ac 100644
--- a/components/safe_browsing/browser/safe_browsing_url_checker_impl.cc
+++ b/components/safe_browsing/browser/safe_browsing_url_checker_impl.cc
@@ -18,7 +18,6 @@
 namespace safe_browsing {
 namespace {
 
-// TODO(yzshen): Share such value with safe_browsing::BaseResourceThrottle.
 // Maximum time in milliseconds to wait for the SafeBrowsing service reputation
 // check. After this amount of time the outstanding check will be aborted, and
 // the resource will be treated as if it were safe.
@@ -316,9 +315,6 @@
 }
 
 SBThreatType SafeBrowsingUrlCheckerImpl::CheckWebUIUrls(const GURL& url) {
-  // TODO(yzshen): This duplicates the logic in
-  // safe_browsing::BaseResourceThrottle::CheckWebUIUrls(), which eventually
-  // will go away. crbug.com/715673
   if (url == kChromeUISafeBrowsingMatchMalwareUrl)
     return safe_browsing::SB_THREAT_TYPE_URL_MALWARE;
   if (url == kChromeUISafeBrowsingMatchPhishingUrl)
diff --git a/components/safe_browsing/browser/safe_browsing_url_checker_impl.h b/components/safe_browsing/browser/safe_browsing_url_checker_impl.h
index c0479e0..9a7106a 100644
--- a/components/safe_browsing/browser/safe_browsing_url_checker_impl.h
+++ b/components/safe_browsing/browser/safe_browsing_url_checker_impl.h
@@ -30,6 +30,17 @@
 // be used to handle queries from renderers. But it is also used to handle
 // queries from the browser. In that case, the public methods are called
 // directly instead of through Mojo.
+//
+// To be considered "safe", a URL must not appear in the SafeBrowsing blacklists
+// (see SafeBrowsingService for details).
+//
+// Note that the SafeBrowsing check takes at most kCheckUrlTimeoutMs
+// milliseconds. If it takes longer than this, then the system defaults to
+// treating the URL as safe.
+//
+// If the URL is classified as dangerous, a warning interstitial page is
+// displayed. In that case, the user can click through the warning page if they
+// decides to procced with loading the URL anyway.
 class SafeBrowsingUrlCheckerImpl : public mojom::SafeBrowsingUrlChecker,
                                    public SafeBrowsingDatabaseManager::Client {
  public:
diff --git a/components/safe_browsing/features.cc b/components/safe_browsing/features.cc
index eaf0c20..b6655dcf 100644
--- a/components/safe_browsing/features.cc
+++ b/components/safe_browsing/features.cc
@@ -35,15 +35,6 @@
     "PasswordProtectionGoogleBrandedPhishingWarning",
     base::FEATURE_DISABLED_BY_DEFAULT};
 
-// If enabled, SafeBrowsing URL checks don't defer starting requests or
-// following redirects, no matter on desktop or mobile. Instead they only defer
-// response processing.
-// Please note that when --enable-features=NetworkService is in effect,
-// SafeBrowsing URL checks never block starting requests or following redirects.
-// S13nSafeBrowsingParallelUrlCheck is ignored in that case.
-const base::Feature kParallelUrlCheck{"S13nSafeBrowsingParallelUrlCheck",
-                                      base::FEATURE_DISABLED_BY_DEFAULT};
-
 const base::Feature kThreatDomDetailsTagAndAttributeFeature{
     "ThreatDomDetailsTagAttributes", base::FEATURE_DISABLED_BY_DEFAULT};
 
@@ -71,7 +62,6 @@
     {&kAppendRecentNavigationEvents, true},
     {&kGaiaPasswordReuseReporting, true},
     {&kGoogleBrandedPhishingWarning, true},
-    {&kParallelUrlCheck, true},
     {&kThreatDomDetailsTagAndAttributeFeature, false},
     {&kTriggerThrottlerDailyQuotaFeature, false},
     {&kDispatchSafetyNetCheckOffThread, false},
diff --git a/components/safe_browsing/features.h b/components/safe_browsing/features.h
index cf03c74..e383db9e 100644
--- a/components/safe_browsing/features.h
+++ b/components/safe_browsing/features.h
@@ -24,7 +24,6 @@
 // Gates logging of GaiaPasswordReuse user events.
 extern const base::Feature kGaiaPasswordReuseReporting;
 extern const base::Feature kGoogleBrandedPhishingWarning;
-extern const base::Feature kParallelUrlCheck;
 
 // Specifies which non-resource HTML Elements to collect based on their tag and
 // attributes. It's a single param containing a comma-separated list of pairs.
diff --git a/components/safe_browsing/net_event_logger.cc b/components/safe_browsing/net_event_logger.cc
deleted file mode 100644
index 82b38c1..0000000
--- a/components/safe_browsing/net_event_logger.cc
+++ /dev/null
@@ -1,75 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/safe_browsing/net_event_logger.h"
-
-#include <memory>
-
-#include "base/bind.h"
-#include "base/values.h"
-#include "net/log/net_log_capture_mode.h"
-#include "net/log/net_log_source.h"
-#include "net/log/net_log_source_type.h"
-#include "url/gurl.h"
-
-namespace safe_browsing {
-namespace {
-
-// Return a dictionary with "url"=|url-spec| and optionally
-// |name|=|value| (if not null), for netlogging.
-// This will also add a reference to the original request's net_log ID.
-std::unique_ptr<base::Value> NetLogUrlCallback(
-    const net::NetLogWithSource* net_log,
-    const GURL& url,
-    const char* name,
-    const char* value,
-    net::NetLogCaptureMode /* capture_mode */) {
-  std::unique_ptr<base::DictionaryValue> event_params(
-      new base::DictionaryValue());
-  event_params->SetString("url", url.spec());
-  if (name && value)
-    event_params->SetString(name, value);
-  net_log->source().AddToEventParameters(event_params.get());
-  return std::move(event_params);
-}
-
-// Return a dictionary with |name|=|value|, for netlogging.
-std::unique_ptr<base::Value> NetLogStringCallback(const char* name,
-                                                  const char* value,
-                                                  net::NetLogCaptureMode) {
-  std::unique_ptr<base::DictionaryValue> event_params(
-      new base::DictionaryValue());
-  if (name && value)
-    event_params->SetString(name, value);
-  return std::move(event_params);
-}
-
-}  // namespace
-
-NetEventLogger::NetEventLogger(const net::NetLogWithSource* net_log)
-    : net_log_(net_log),
-      net_log_with_sb_source_(
-          net::NetLogWithSource::Make(net_log_->net_log(),
-                                      net::NetLogSourceType::SAFE_BROWSING)) {}
-
-void NetEventLogger::BeginNetLogEvent(net::NetLogEventType type,
-                                      const GURL& url,
-                                      const char* name,
-                                      const char* value) {
-  net_log_with_sb_source_.BeginEvent(
-      type, base::Bind(&NetLogUrlCallback, net_log_, url, name, value));
-  net_log_->AddEvent(
-      type, net_log_with_sb_source_.source().ToEventParametersCallback());
-}
-
-void NetEventLogger::EndNetLogEvent(net::NetLogEventType type,
-                                    const char* name,
-                                    const char* value) {
-  net_log_with_sb_source_.EndEvent(
-      type, base::Bind(&NetLogStringCallback, name, value));
-  net_log_->AddEvent(
-      type, net_log_with_sb_source_.source().ToEventParametersCallback());
-}
-
-}  // namespace safe_browsing
diff --git a/components/safe_browsing/net_event_logger.h b/components/safe_browsing/net_event_logger.h
deleted file mode 100644
index 7da4097..0000000
--- a/components/safe_browsing/net_event_logger.h
+++ /dev/null
@@ -1,40 +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 COMPONENTS_SAFE_BROWSING_NET_EVENT_LOGGER_H_
-#define COMPONENTS_SAFE_BROWSING_NET_EVENT_LOGGER_H_
-
-#include "base/macros.h"
-#include "net/log/net_log_event_type.h"
-#include "net/log/net_log_with_source.h"
-
-class GURL;
-
-namespace safe_browsing {
-
-// A helper class to log network events for SafeBrowsing.
-class NetEventLogger {
- public:
-  // |net_log| must outlive this class.
-  explicit NetEventLogger(const net::NetLogWithSource* net_log);
-
-  // For marking network events.  |name| and |value| can be null.
-  void BeginNetLogEvent(net::NetLogEventType type,
-                        const GURL& url,
-                        const char* name,
-                        const char* value);
-  void EndNetLogEvent(net::NetLogEventType type,
-                      const char* name,
-                      const char* value);
-
- private:
-  const net::NetLogWithSource* net_log_;
-  net::NetLogWithSource net_log_with_sb_source_;
-
-  DISALLOW_COPY_AND_ASSIGN(NetEventLogger);
-};
-
-}  // namespace safe_browsing
-
-#endif  // COMPONENTS_SAFE_BROWSING_NET_EVENT_LOGGER_H_
diff --git a/components/safe_browsing/renderer/renderer_url_loader_throttle.cc b/components/safe_browsing/renderer/renderer_url_loader_throttle.cc
index 4116c54..a85f8f8 100644
--- a/components/safe_browsing/renderer/renderer_url_loader_throttle.cc
+++ b/components/safe_browsing/renderer/renderer_url_loader_throttle.cc
@@ -57,7 +57,8 @@
   headers.CopyFrom(request->headers);
   safe_browsing_->CreateCheckerAndCheck(
       render_frame_id_, mojo::MakeRequest(&url_checker_), request->url,
-      request->method, headers, request->load_flags, request->resource_type,
+      request->method, headers, request->load_flags,
+      static_cast<content::ResourceType>(request->resource_type),
       request->has_user_gesture,
       base::BindOnce(&RendererURLLoaderThrottle::OnCheckUrlResult,
                      weak_factory_.GetWeakPtr()));
diff --git a/components/startup_metric_utils/browser/startup_metric_utils.cc b/components/startup_metric_utils/browser/startup_metric_utils.cc
index 7952fe04..16c50ef8 100644
--- a/components/startup_metric_utils/browser/startup_metric_utils.cc
+++ b/components/startup_metric_utils/browser/startup_metric_utils.cc
@@ -45,8 +45,11 @@
 base::LazyInstance<base::TimeTicks>::Leaky g_process_creation_ticks =
     LAZY_INSTANCE_INITIALIZER;
 
-base::LazyInstance<base::TimeTicks>::Leaky g_browser_main_entry_point_ticks =
-    LAZY_INSTANCE_INITIALIZER;
+base::LazyInstance<base::TimeTicks>::Leaky
+    g_browser_main_entry_point_ticks_computed_from_time =
+        LAZY_INSTANCE_INITIALIZER;
+
+base::TimeTicks g_browser_main_entry_point_ticks;
 
 base::LazyInstance<base::TimeTicks>::Leaky g_renderer_main_entry_point_ticks =
     LAZY_INSTANCE_INITIALIZER;
@@ -425,7 +428,7 @@
 // Record renderer main entry time histogram.
 void RecordRendererMainEntryHistogram() {
   const base::TimeTicks browser_main_entry_point_ticks =
-      g_browser_main_entry_point_ticks.Get();
+      g_browser_main_entry_point_ticks_computed_from_time.Get();
   const base::TimeTicks renderer_main_entry_point_ticks =
       g_renderer_main_entry_point_ticks.Get();
 
@@ -439,11 +442,11 @@
 
 void AddStartupEventsForTelemetry()
 {
-  DCHECK(!g_browser_main_entry_point_ticks.Get().is_null());
+  DCHECK(!g_browser_main_entry_point_ticks_computed_from_time.Get().is_null());
 
   TRACE_EVENT_INSTANT_WITH_TIMESTAMP0(
       "startup", "Startup.BrowserMainEntryPoint", 0,
-      g_browser_main_entry_point_ticks.Get());
+      g_browser_main_entry_point_ticks_computed_from_time.Get());
 }
 
 // Logs the Startup.TimeSinceLastStartup histogram. Obtains the timestamp of the
@@ -542,10 +545,15 @@
   DCHECK(!g_process_creation_ticks.Get().is_null());
 }
 
-void RecordMainEntryPointTime(base::Time time) {
-  DCHECK(g_browser_main_entry_point_ticks.Get().is_null());
-  g_browser_main_entry_point_ticks.Get() = StartupTimeToTimeTicks(time);
-  DCHECK(!g_browser_main_entry_point_ticks.Get().is_null());
+void RecordMainEntryPointTime(base::Time wall_time, base::TimeTicks ticks) {
+  DCHECK(g_browser_main_entry_point_ticks.is_null());
+  g_browser_main_entry_point_ticks = ticks;
+  DCHECK(!g_browser_main_entry_point_ticks.is_null());
+
+  DCHECK(g_browser_main_entry_point_ticks_computed_from_time.Get().is_null());
+  g_browser_main_entry_point_ticks_computed_from_time.Get() =
+      StartupTimeToTimeTicks(wall_time);
+  DCHECK(!g_browser_main_entry_point_ticks_computed_from_time.Get().is_null());
 }
 
 void RecordExeMainEntryPointTicks(base::TimeTicks ticks) {
@@ -589,12 +597,18 @@
     UMA_HISTOGRAM_AND_TRACE_WITH_TEMPERATURE(
         UMA_HISTOGRAM_LONG_TIMES,
         "Startup.BrowserMessageLoopStartTimeFromMainEntry.FirstRun2",
-        g_browser_main_entry_point_ticks.Get(), ticks);
+        g_browser_main_entry_point_ticks_computed_from_time.Get(), ticks);
   } else {
+    // TODO(pasko): Stop recording the "...MainEntry2" histogram after M65 hits
+    // Stable.
     UMA_HISTOGRAM_AND_TRACE_WITH_TEMPERATURE_AND_SAME_VERSION_COUNT(
         UMA_HISTOGRAM_LONG_TIMES,
         "Startup.BrowserMessageLoopStartTimeFromMainEntry2",
-        g_browser_main_entry_point_ticks.Get(), ticks);
+        g_browser_main_entry_point_ticks_computed_from_time.Get(), ticks);
+    UMA_HISTOGRAM_AND_TRACE_WITH_TEMPERATURE_AND_SAME_VERSION_COUNT(
+        UMA_HISTOGRAM_LONG_TIMES,
+        "Startup.BrowserMessageLoopStartTimeFromMainEntry3",
+        g_browser_main_entry_point_ticks, ticks);
   }
 
   AddStartupEventsForTelemetry();
@@ -608,7 +622,7 @@
     const base::TimeTicks exe_main_ticks =
         g_browser_exe_main_entry_point_ticks.Get();
     const base::TimeTicks main_entry_ticks =
-        g_browser_main_entry_point_ticks.Get();
+        g_browser_main_entry_point_ticks_computed_from_time.Get();
     // Process create to chrome.exe:main().
     UMA_HISTOGRAM_AND_TRACE_WITH_TEMPERATURE_AND_SAME_VERSION_COUNT(
         UMA_HISTOGRAM_LONG_TIMES, "Startup.LoadTime.ProcessCreateToExeMain2",
@@ -782,7 +796,7 @@
 }
 
 base::TimeTicks MainEntryPointTicks() {
-  return g_browser_main_entry_point_ticks.Get();
+  return g_browser_main_entry_point_ticks_computed_from_time.Get();
 }
 
 }  // namespace startup_metric_utils
diff --git a/components/startup_metric_utils/browser/startup_metric_utils.h b/components/startup_metric_utils/browser/startup_metric_utils.h
index 6066d71..38767a7d 100644
--- a/components/startup_metric_utils/browser/startup_metric_utils.h
+++ b/components/startup_metric_utils/browser/startup_metric_utils.h
@@ -52,7 +52,9 @@
 // Call this with a time recorded as early as possible in the startup process.
 // On Android, the entry point time is the time at which the Java code starts.
 // In Mojo, the entry point time is the time at which the shell starts.
-void RecordMainEntryPointTime(base::Time time);
+// TODO(pasko): Remove the wallclock-based main entry point time calculation,
+// see: http://crbug.com/797762.
+void RecordMainEntryPointTime(base::Time wall_time, base::TimeTicks ticks);
 
 // Call this with the time when the executable is loaded and main() is entered.
 // Can be different from |RecordMainEntryPointTime| when the startup process is
@@ -106,7 +108,7 @@
 void RecordBrowserWindowFirstPaintCompositingEnded(base::TimeTicks ticks);
 
 // Returns the TimeTicks corresponding to main entry as recorded by
-// RecordMainEntryPointTime. Returns a null TimeTicks if a value has not been
+// |RecordMainEntryPointTime|. Returns a null TimeTicks if a value has not been
 // recorded yet. This method is expected to be called from the UI thread.
 base::TimeTicks MainEntryPointTicks();
 
diff --git a/components/viz/common/yuv_readback_unittest.cc b/components/viz/common/yuv_readback_unittest.cc
index d75228ac..acdb53c 100644
--- a/components/viz/common/yuv_readback_unittest.cc
+++ b/components/viz/common/yuv_readback_unittest.cc
@@ -374,7 +374,7 @@
 
     scoped_refptr<media::VideoFrame> output_frame =
         media::VideoFrame::CreateFrame(
-            media::PIXEL_FORMAT_YV12,
+            media::PIXEL_FORMAT_I420,
             // The coded size of the output frame is rounded up to the next
             // 16-byte boundary.  This tests that the readback is being
             // positioned inside the frame's visible region, and not dependent
@@ -385,7 +385,7 @@
             base::TimeDelta::FromSeconds(0));
     scoped_refptr<media::VideoFrame> truth_frame =
         media::VideoFrame::CreateFrame(
-            media::PIXEL_FORMAT_YV12, gfx::Size(output_xsize, output_ysize),
+            media::PIXEL_FORMAT_I420, gfx::Size(output_xsize, output_ysize),
             gfx::Rect(0, 0, output_xsize, output_ysize),
             gfx::Size(output_xsize, output_ysize),
             base::TimeDelta::FromSeconds(0));
diff --git a/components/viz/service/display/renderer_pixeltest.cc b/components/viz/service/display/renderer_pixeltest.cc
index bb2bd0a..db4a4f1 100644
--- a/components/viz/service/display/renderer_pixeltest.cc
+++ b/components/viz/service/display/renderer_pixeltest.cc
@@ -405,7 +405,6 @@
   media::VideoPixelFormat format;
   switch (video_frame->format()) {
     case media::PIXEL_FORMAT_I420:
-    case media::PIXEL_FORMAT_YV12:
       format = media::PIXEL_FORMAT_YUV420P10;
       break;
     case media::PIXEL_FORMAT_I422:
@@ -1281,14 +1280,14 @@
       (this->quad_rect_.height() / 2) & ~0xF);
 
   CreateTestYUVVideoDrawQuad_TwoColor(
-      this->front_quad_state_, media::PIXEL_FORMAT_YV12,
+      this->front_quad_state_, media::PIXEL_FORMAT_I420,
       media::COLOR_SPACE_JPEG, false, gfx::RectF(0.0f, 0.0f, 1.0f, 1.0f),
       this->quad_rect_.size(), this->quad_rect_, 0, 128, 128, inner_rect, 29,
       255, 107, this->render_pass_.get(), this->video_resource_updater_.get(),
       this->resource_provider_.get(), this->child_resource_provider_.get());
 
   CreateTestYUVVideoDrawQuad_TwoColor(
-      this->back_quad_state_, media::PIXEL_FORMAT_YV12, media::COLOR_SPACE_JPEG,
+      this->back_quad_state_, media::PIXEL_FORMAT_I420, media::COLOR_SPACE_JPEG,
       false, gfx::RectF(0.0f, 0.0f, 1.0f, 1.0f), this->quad_rect_.size(),
       this->quad_rect_, 149, 43, 21, inner_rect, 0, 128, 128,
       this->render_pass_.get(), this->video_resource_updater2_.get(),
@@ -1484,7 +1483,7 @@
   SetSupportHighbitTexture(format);
 
   CreateTestYUVVideoDrawQuad_Striped(
-      shared_state, media::PIXEL_FORMAT_YV12, media::COLOR_SPACE_SD_REC601,
+      shared_state, media::PIXEL_FORMAT_I420, media::COLOR_SPACE_SD_REC601,
       false, highbit, gfx::RectF(0.0f, 0.0f, 1.0f, 1.0f), pass.get(),
       video_resource_updater_.get(), rect, rect, resource_provider_.get(),
       child_resource_provider_.get());
@@ -1516,7 +1515,7 @@
   SetSupportHighbitTexture(format);
 
   CreateTestYUVVideoDrawQuad_Striped(
-      shared_state, media::PIXEL_FORMAT_YV12, media::COLOR_SPACE_SD_REC601,
+      shared_state, media::PIXEL_FORMAT_I420, media::COLOR_SPACE_SD_REC601,
       false, highbit, gfx::RectF(0.0f, 0.0f, 1.0f, 1.0f), pass.get(),
       video_resource_updater_.get(), draw_rect, viewport,
       resource_provider_.get(), child_resource_provider_.get());
@@ -1569,7 +1568,7 @@
 
   // In MPEG color range YUV values of (15,128,128) should produce black.
   CreateTestYUVVideoDrawQuad_Solid(
-      shared_state, media::PIXEL_FORMAT_YV12, media::COLOR_SPACE_SD_REC601,
+      shared_state, media::PIXEL_FORMAT_I420, media::COLOR_SPACE_SD_REC601,
       false, gfx::RectF(0.0f, 0.0f, 1.0f, 1.0f), 15, 128, 128, pass.get(),
       video_resource_updater_.get(), rect, rect, resource_provider_.get(),
       child_resource_provider_.get());
@@ -1603,7 +1602,7 @@
 
   // YUV of (149,43,21) should be green (0,255,0) in RGB.
   CreateTestYUVVideoDrawQuad_Solid(
-      shared_state, media::PIXEL_FORMAT_YV12, media::COLOR_SPACE_JPEG, false,
+      shared_state, media::PIXEL_FORMAT_I420, media::COLOR_SPACE_JPEG, false,
       gfx::RectF(0.0f, 0.0f, 1.0f, 1.0f), 149, 43, 21, pass.get(),
       video_resource_updater_.get(), rect, rect, resource_provider_.get(),
       child_resource_provider_.get());
@@ -1643,7 +1642,7 @@
 // tex coord rect is only a partial subrectangle of the coded contents.
 TEST_F(VideoGLRendererPixelTest, YUVEdgeBleed) {
   RenderPassList pass_list;
-  CreateEdgeBleedPass(media::PIXEL_FORMAT_YV12, media::COLOR_SPACE_JPEG,
+  CreateEdgeBleedPass(media::PIXEL_FORMAT_I420, media::COLOR_SPACE_JPEG,
                       &pass_list);
   EXPECT_TRUE(this->RunPixelTest(&pass_list,
                                  base::FilePath(FILE_PATH_LITERAL("green.png")),
@@ -1674,7 +1673,7 @@
 
   // Dark grey in JPEG color range (in MPEG, this is black).
   CreateTestYUVVideoDrawQuad_Solid(
-      shared_state, media::PIXEL_FORMAT_YV12, media::COLOR_SPACE_JPEG, false,
+      shared_state, media::PIXEL_FORMAT_I420, media::COLOR_SPACE_JPEG, false,
       gfx::RectF(0.0f, 0.0f, 1.0f, 1.0f), 15, 128, 128, pass.get(),
       video_resource_updater_.get(), rect, rect, resource_provider_.get(),
       child_resource_provider_.get());
diff --git a/components/viz/service/frame_sinks/video_capture/frame_sink_video_capturer_impl.cc b/components/viz/service/frame_sinks/video_capture/frame_sink_video_capturer_impl.cc
index 0cb1e8f..9a3559b 100644
--- a/components/viz/service/frame_sinks/video_capture/frame_sink_video_capturer_impl.cc
+++ b/components/viz/service/frame_sinks/video_capture/frame_sink_video_capturer_impl.cc
@@ -127,9 +127,8 @@
                                            media::ColorSpace color_space) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
-  if (format != media::PIXEL_FORMAT_I420 &&
-      format != media::PIXEL_FORMAT_YV12) {
-    LOG(DFATAL) << "Invalid pixel format: Only I420 or YV12 are supported.";
+  if (format != media::PIXEL_FORMAT_I420) {
+    LOG(DFATAL) << "Invalid pixel format: Only I420 supported.";
   } else {
     pixel_format_ = format;
   }
diff --git a/content/browser/BUILD.gn b/content/browser/BUILD.gn
index cd5af16..6648c537 100644
--- a/content/browser/BUILD.gn
+++ b/content/browser/BUILD.gn
@@ -1967,6 +1967,8 @@
       "media/cdm_file_impl.h",
       "media/cdm_storage_impl.cc",
       "media/cdm_storage_impl.h",
+      "media/key_system_support_impl.cc",
+      "media/key_system_support_impl.h",
     ]
   }
 
diff --git a/content/browser/android/gesture_listener_manager.cc b/content/browser/android/gesture_listener_manager.cc
index 20bc0b6..2cd208c 100644
--- a/content/browser/android/gesture_listener_manager.cc
+++ b/content/browser/android/gesture_listener_manager.cc
@@ -5,6 +5,7 @@
 #include "content/browser/android/gesture_listener_manager.h"
 #include "content/browser/web_contents/web_contents_impl.h"
 #include "content/browser/web_contents/web_contents_view_android.h"
+#include "content/public/browser/web_contents.h"
 #include "jni/GestureListenerManagerImpl_jni.h"
 #include "third_party/WebKit/public/platform/WebInputEvent.h"
 #include "ui/events/android/gesture_event_type.h"
@@ -18,14 +19,10 @@
 
 namespace content {
 
-DEFINE_WEB_CONTENTS_USER_DATA_KEY(GestureListenerManager);
-
 GestureListenerManager::GestureListenerManager(JNIEnv* env,
                                                const JavaParamRef<jobject>& obj,
                                                WebContents* web_contents)
     : java_ref_(env, obj) {
-  // Does what GestureListenerManager::CreateForWebContents is supposed to do.
-  web_contents->SetUserData(UserDataKey(), base::WrapUnique(this));
 }
 
 GestureListenerManager::~GestureListenerManager() {
@@ -93,10 +90,11 @@
     const JavaParamRef<jobject>& jweb_contents) {
   auto* web_contents = WebContents::FromJavaWebContents(jweb_contents);
   CHECK(web_contents) << "Should be created with a valid WebContents.";
-  DCHECK(!GestureListenerManager::FromWebContents(web_contents));
 
-  // Owned and managed via WebContentsUserData.
-  new GestureListenerManager(env, obj, web_contents);
+  WebContentsViewAndroid* view = static_cast<WebContentsViewAndroid*>(
+      static_cast<WebContentsImpl*>(web_contents)->GetView());
+  view->SetGestureListenerManager(
+      base::MakeUnique<GestureListenerManager>(env, obj, web_contents));
 }
 
 }  // namespace content
diff --git a/content/browser/android/gesture_listener_manager.h b/content/browser/android/gesture_listener_manager.h
index 6b314f22a..8c518d4e 100644
--- a/content/browser/android/gesture_listener_manager.h
+++ b/content/browser/android/gesture_listener_manager.h
@@ -5,11 +5,9 @@
 #ifndef CONTENT_BROWSER_ANDROID_GESTURE_LISTENER_MANAGER_H_
 #define CONTENT_BROWSER_ANDROID_GESTURE_LISTENER_MANAGER_H_
 
-#include "base/android/jni_android.h"
 #include "base/android/jni_weak_ref.h"
 #include "base/android/scoped_java_ref.h"
 #include "base/macros.h"
-#include "content/public/browser/web_contents_user_data.h"
 #include "content/public/common/input_event_ack_state.h"
 
 namespace blink {
@@ -18,15 +16,16 @@
 
 namespace content {
 
+class WebContents;
+
 // Native class for GestureListenerManagerImpl. Owned by
 // |WebContentsViewAndroid|.
-class GestureListenerManager
-    : public WebContentsUserData<GestureListenerManager> {
+class GestureListenerManager {
  public:
   GestureListenerManager(JNIEnv* env,
                          const base::android::JavaParamRef<jobject>& obj,
                          WebContents* web_contents);
-  ~GestureListenerManager() override;
+  ~GestureListenerManager();
 
   void GestureEventAck(const blink::WebGestureEvent& event,
                        InputEventAckState ack_result);
diff --git a/content/browser/appcache/appcache_request_handler.cc b/content/browser/appcache/appcache_request_handler.cc
index e5dd7d28..602c227 100644
--- a/content/browser/appcache/appcache_request_handler.cc
+++ b/content/browser/appcache/appcache_request_handler.cc
@@ -261,7 +261,8 @@
     URLLoaderFactoryGetter* url_loader_factory_getter) {
   std::unique_ptr<AppCacheRequestHandler> handler =
       appcache_handle_core->host()->CreateRequestHandler(
-          AppCacheURLLoaderRequest::Create(request), request.resource_type,
+          AppCacheURLLoaderRequest::Create(request),
+          static_cast<ResourceType>(request.resource_type),
           request.should_reset_appcache);
   handler->network_url_loader_factory_getter_ = url_loader_factory_getter;
   handler->appcache_host_ = appcache_handle_core->host()->GetWeakPtr();
diff --git a/content/browser/appcache/appcache_subresource_url_factory.cc b/content/browser/appcache/appcache_subresource_url_factory.cc
index 29ea40f2..601eb381 100644
--- a/content/browser/appcache/appcache_subresource_url_factory.cc
+++ b/content/browser/appcache/appcache_subresource_url_factory.cc
@@ -76,7 +76,8 @@
       return;
     }
     handler_ = host_->CreateRequestHandler(
-        AppCacheURLLoaderRequest::Create(request_), request_.resource_type,
+        AppCacheURLLoaderRequest::Create(request_),
+        static_cast<ResourceType>(request_.resource_type),
         request_.should_reset_appcache);
     if (!handler_) {
       CreateAndStartNetworkLoader();
diff --git a/content/browser/appcache/appcache_url_loader_job.cc b/content/browser/appcache/appcache_url_loader_job.cc
index 321d10a..82d9d15 100644
--- a/content/browser/appcache/appcache_url_loader_job.cc
+++ b/content/browser/appcache/appcache_url_loader_job.cc
@@ -148,8 +148,8 @@
                                mojo::SimpleWatcher::ArmingPolicy::MANUAL),
       loader_callback_(std::move(loader_callback)),
       appcache_request_(appcache_request->GetWeakPtr()),
-      is_main_resource_load_(IsResourceTypeFrame(
-          appcache_request->GetResourceRequest()->resource_type)),
+      is_main_resource_load_(IsResourceTypeFrame(static_cast<ResourceType>(
+          appcache_request->GetResourceRequest()->resource_type))),
       weak_factory_(this) {}
 
 void AppCacheURLLoaderJob::CallLoaderCallback() {
diff --git a/content/browser/browser_main_loop.cc b/content/browser/browser_main_loop.cc
index 80790c3..5d532ca3 100644
--- a/content/browser/browser_main_loop.cc
+++ b/content/browser/browser_main_loop.cc
@@ -267,7 +267,12 @@
 
   // Tickle the zygote host so it forks now.
   ZygoteHostImpl::GetInstance()->Init(parsed_command_line);
-  ZygoteHandle generic_zygote = CreateGenericZygote();
+  ZygoteHandle generic_zygote =
+      CreateGenericZygote(base::BindOnce([](base::CommandLine* cmd_line) {
+        GetContentClient()->browser()->AppendExtraCommandLineSwitches(cmd_line,
+                                                                      -1);
+      }));
+
   // TODO(kerrnel): Investigate doing this without the ZygoteHostImpl as a
   // proxy. It is currently done this way due to concerns about race
   // conditions.
diff --git a/content/browser/browsing_data/OWNERS b/content/browser/browsing_data/OWNERS
index 1f8f137..8d413bc7 100644
--- a/content/browser/browsing_data/OWNERS
+++ b/content/browser/browsing_data/OWNERS
@@ -1,7 +1,7 @@
 bauerb@chromium.org
+dullweber@chromium.org
 markusheintz@chromium.org
 michaeln@chromium.org
-mkwst@chromium.org
 msramek@chromium.org
 
 # COMPONENT: Privacy
diff --git a/content/browser/child_process_launcher_helper_mac.cc b/content/browser/child_process_launcher_helper_mac.cc
index 44ac3507..314db6c 100644
--- a/content/browser/child_process_launcher_helper_mac.cc
+++ b/content/browser/child_process_launcher_helper_mac.cc
@@ -23,6 +23,7 @@
 #include "sandbox/mac/seatbelt_exec.h"
 #include "services/service_manager/sandbox/mac/cdm.sb.h"
 #include "services/service_manager/sandbox/mac/common_v2.sb.h"
+#include "services/service_manager/sandbox/mac/gpu_v2.sb.h"
 #include "services/service_manager/sandbox/mac/ppapi_v2.sb.h"
 #include "services/service_manager/sandbox/mac/renderer_v2.sb.h"
 #include "services/service_manager/sandbox/mac/utility.sb.h"
@@ -69,6 +70,7 @@
   bool v2_process = false;
   switch (sandbox_type) {
     case service_manager::SANDBOX_TYPE_CDM:
+    case service_manager::SANDBOX_TYPE_GPU:
     case service_manager::SANDBOX_TYPE_PPAPI:
     case service_manager::SANDBOX_TYPE_RENDERER:
     case service_manager::SANDBOX_TYPE_UTILITY:
@@ -90,6 +92,9 @@
       case service_manager::SANDBOX_TYPE_CDM:
         profile += service_manager::kSeatbeltPolicyString_cdm;
         break;
+      case service_manager::SANDBOX_TYPE_GPU:
+        profile += service_manager::kSeatbeltPolicyString_gpu_v2;
+        break;
       case service_manager::SANDBOX_TYPE_PPAPI:
         profile += service_manager::kSeatbeltPolicyString_ppapi_v2;
         break;
@@ -110,14 +115,21 @@
     seatbelt_exec_client_ = std::make_unique<sandbox::SeatbeltExecClient>();
     seatbelt_exec_client_->SetProfile(profile);
 
-    if (sandbox_type == service_manager::SANDBOX_TYPE_RENDERER ||
-        sandbox_type == service_manager::SANDBOX_TYPE_PPAPI) {
-      SetupCommonSandboxParameters(seatbelt_exec_client_.get());
-    } else if (sandbox_type == service_manager::SANDBOX_TYPE_UTILITY) {
-      SetupUtilitySandboxParameters(seatbelt_exec_client_.get(),
-                                    *command_line_.get());
-    } else if (sandbox_type == service_manager::SANDBOX_TYPE_CDM) {
-      SetupCDMSandboxParameters(seatbelt_exec_client_.get());
+    switch (sandbox_type) {
+      case service_manager::SANDBOX_TYPE_CDM:
+        SetupCDMSandboxParameters(seatbelt_exec_client_.get());
+        break;
+      case service_manager::SANDBOX_TYPE_GPU:
+      case service_manager::SANDBOX_TYPE_PPAPI:
+      case service_manager::SANDBOX_TYPE_RENDERER:
+        SetupCommonSandboxParameters(seatbelt_exec_client_.get());
+        break;
+      case service_manager::SANDBOX_TYPE_UTILITY:
+        SetupUtilitySandboxParameters(seatbelt_exec_client_.get(),
+                                      *command_line_.get());
+        break;
+      default:
+        NOTREACHED();
     }
 
     int pipe = seatbelt_exec_client_->SendProfileAndGetFD();
diff --git a/content/browser/devtools/devtools_agent_host_impl.cc b/content/browser/devtools/devtools_agent_host_impl.cc
index acc46f7ee..41f3a495 100644
--- a/content/browser/devtools/devtools_agent_host_impl.cc
+++ b/content/browser/devtools/devtools_agent_host_impl.cc
@@ -414,92 +414,4 @@
   g_devtools_instances.Get().erase(id_);
 }
 
-// DevToolsMessageChunkProcessor -----------------------------------------------
-
-DevToolsMessageChunkProcessor::DevToolsMessageChunkProcessor(
-    const SendMessageIPCCallback& ipc_callback,
-    const SendMessageCallback& callback)
-    : ipc_callback_(ipc_callback),
-      callback_(callback),
-      message_buffer_size_(0),
-      last_call_id_(0) {}
-
-DevToolsMessageChunkProcessor::~DevToolsMessageChunkProcessor() {
-}
-
-bool DevToolsMessageChunkProcessor::ProcessChunkedMessageFromAgent(
-    const DevToolsMessageChunk& chunk) {
-  if (chunk.is_last && !chunk.post_state.empty())
-    state_cookie_ = chunk.post_state;
-  if (chunk.is_last)
-    last_call_id_ = chunk.call_id;
-
-  if (chunk.is_first && chunk.is_last) {
-    if (message_buffer_size_ != 0)
-      return false;
-    ipc_callback_.Run(chunk.session_id, chunk.data);
-    return true;
-  }
-
-  if (chunk.is_first) {
-    message_buffer_ = std::string();
-    message_buffer_.reserve(chunk.message_size);
-    message_buffer_size_ = chunk.message_size;
-  }
-
-  if (message_buffer_.size() + chunk.data.size() > message_buffer_size_)
-    return false;
-  message_buffer_.append(chunk.data);
-
-  if (chunk.is_last) {
-    if (message_buffer_.size() != message_buffer_size_)
-      return false;
-    ipc_callback_.Run(chunk.session_id, message_buffer_);
-    message_buffer_ = std::string();
-    message_buffer_size_ = 0;
-  }
-  return true;
-}
-
-bool DevToolsMessageChunkProcessor::ProcessChunkedMessageFromAgent(
-    mojom::DevToolsMessageChunkPtr chunk) {
-  if (chunk->is_last && !chunk->post_state.empty())
-    state_cookie_ = chunk->post_state;
-  if (chunk->is_last)
-    last_call_id_ = chunk->call_id;
-
-  if (chunk->is_first && chunk->is_last) {
-    if (message_buffer_size_ != 0)
-      return false;
-    callback_.Run(chunk->data);
-    return true;
-  }
-
-  if (chunk->is_first) {
-    message_buffer_ = std::string();
-    message_buffer_.reserve(chunk->message_size);
-    message_buffer_size_ = chunk->message_size;
-  }
-
-  if (message_buffer_.size() + chunk->data.size() > message_buffer_size_)
-    return false;
-  message_buffer_.append(chunk->data);
-
-  if (chunk->is_last) {
-    if (message_buffer_.size() != message_buffer_size_)
-      return false;
-    callback_.Run(message_buffer_);
-    message_buffer_ = std::string();
-    message_buffer_size_ = 0;
-  }
-  return true;
-}
-
-void DevToolsMessageChunkProcessor::Reset() {
-  message_buffer_ = std::string();
-  message_buffer_size_ = 0;
-  state_cookie_ = std::string();
-  last_call_id_ = 0;
-}
-
 }  // namespace content
diff --git a/content/browser/devtools/devtools_agent_host_impl.h b/content/browser/devtools/devtools_agent_host_impl.h
index 746e2e5..32231c7 100644
--- a/content/browser/devtools/devtools_agent_host_impl.h
+++ b/content/browser/devtools/devtools_agent_host_impl.h
@@ -102,30 +102,6 @@
   static int s_last_session_id_;
 };
 
-class DevToolsMessageChunkProcessor {
- public:
-  using SendMessageIPCCallback = base::Callback<void(int, const std::string&)>;
-  using SendMessageCallback = base::Callback<void(const std::string&)>;
-  DevToolsMessageChunkProcessor(const SendMessageIPCCallback& ipc_callback,
-                                const SendMessageCallback& callback);
-  ~DevToolsMessageChunkProcessor();
-
-  const std::string& state_cookie() const { return state_cookie_; }
-  void set_state_cookie(const std::string& cookie) { state_cookie_ = cookie; }
-  int last_call_id() const { return last_call_id_; }
-  bool ProcessChunkedMessageFromAgent(const DevToolsMessageChunk& chunk);
-  bool ProcessChunkedMessageFromAgent(mojom::DevToolsMessageChunkPtr chunk);
-  void Reset();
-
- private:
-  SendMessageIPCCallback ipc_callback_;
-  SendMessageCallback callback_;
-  std::string message_buffer_;
-  uint32_t message_buffer_size_;
-  std::string state_cookie_;
-  int last_call_id_;
-};
-
 }  // namespace content
 
 #endif  // CONTENT_BROWSER_DEVTOOLS_DEVTOOLS_AGENT_HOST_IMPL_H_
diff --git a/content/browser/devtools/devtools_session.cc b/content/browser/devtools/devtools_session.cc
index 93a74b7..2bb5a73 100644
--- a/content/browser/devtools/devtools_session.cc
+++ b/content/browser/devtools/devtools_session.cc
@@ -38,10 +38,6 @@
       process_(nullptr),
       host_(nullptr),
       dispatcher_(new protocol::UberDispatcher(this)),
-      chunk_processor_(base::Bind(&DevToolsSession::SendMessageFromProcessorIPC,
-                                  base::Unretained(this)),
-                       base::Bind(&DevToolsSession::SendMessageFromProcessor,
-                                  base::Unretained(this))),
       weak_factory_(this) {}
 
 DevToolsSession::~DevToolsSession() {
@@ -87,28 +83,11 @@
   binding_.Bind(mojo::MakeRequest(&host_ptr_info));
   agent->AttachDevToolsSession(
       std::move(host_ptr_info), mojo::MakeRequest(&session_ptr_),
-      mojo::MakeRequest(&io_session_ptr_), state_cookie());
+      mojo::MakeRequest(&io_session_ptr_), state_cookie_);
   session_ptr_.set_connection_error_handler(base::BindOnce(
       &DevToolsSession::MojoConnectionDestroyed, base::Unretained(this)));
 }
 
-void DevToolsSession::SendMessageFromProcessorIPC(int session_id,
-                                                  const std::string& message) {
-  if (session_id != session_id_)
-    return;
-  int id = chunk_processor_.last_call_id();
-  waiting_for_response_messages_.erase(id);
-  client_->DispatchProtocolMessage(agent_host_, message);
-  // |this| may be deleted at this point.
-}
-
-void DevToolsSession::SendMessageFromProcessor(const std::string& message) {
-  int id = chunk_processor_.last_call_id();
-  waiting_for_response_messages_.erase(id);
-  client_->DispatchProtocolMessage(agent_host_, message);
-  // |this| may be deleted at this point.
-}
-
 void DevToolsSession::SendResponse(
     std::unique_ptr<base::DictionaryValue> response) {
   std::string json;
@@ -166,8 +145,39 @@
     session_ptr_->InspectElement(point);
 }
 
-bool DevToolsSession::ReceiveMessageChunk(const DevToolsMessageChunk& chunk) {
-  return chunk_processor_.ProcessChunkedMessageFromAgent(chunk);
+void DevToolsSession::ReceiveMessageChunk(const DevToolsMessageChunk& chunk) {
+  if (chunk.session_id != session_id_)
+    return;
+
+  if (chunk.is_first) {
+    if (response_message_buffer_size_ != 0)
+      return;
+    if (chunk.is_last) {
+      response_message_buffer_size_ = chunk.data.size();
+    } else {
+      response_message_buffer_size_ = chunk.message_size;
+      response_message_buffer_.reserve(chunk.message_size);
+    }
+  }
+
+  if (response_message_buffer_.size() + chunk.data.size() >
+      response_message_buffer_size_)
+    return;
+  response_message_buffer_.append(chunk.data);
+
+  if (!chunk.is_last)
+    return;
+  if (response_message_buffer_.size() != response_message_buffer_size_)
+    return;
+
+  if (!chunk.post_state.empty())
+    state_cookie_ = chunk.post_state;
+  waiting_for_response_messages_.erase(chunk.call_id);
+  response_message_buffer_size_ = 0;
+  std::string message;
+  message.swap(response_message_buffer_);
+  client_->DispatchProtocolMessage(agent_host_, message);
+  // |this| may be deleted at this point.
 }
 
 void DevToolsSession::sendProtocolResponse(
@@ -186,9 +196,44 @@
 
 void DevToolsSession::DispatchProtocolMessage(
     mojom::DevToolsMessageChunkPtr chunk) {
-  if (chunk_processor_.ProcessChunkedMessageFromAgent(std::move(chunk)))
-    return;
+  if (chunk->is_first) {
+    if (response_message_buffer_size_ != 0) {
+      ReceivedBadMessage();
+      return;
+    }
+    if (chunk->is_last) {
+      response_message_buffer_size_ = chunk->data.size();
+    } else {
+      response_message_buffer_size_ = chunk->message_size;
+      response_message_buffer_.reserve(chunk->message_size);
+    }
+  }
 
+  if (response_message_buffer_.size() + chunk->data.size() >
+      response_message_buffer_size_) {
+    ReceivedBadMessage();
+    return;
+  }
+  response_message_buffer_.append(std::move(chunk->data));
+
+  if (!chunk->is_last)
+    return;
+  if (response_message_buffer_.size() != response_message_buffer_size_) {
+    ReceivedBadMessage();
+    return;
+  }
+
+  if (!chunk->post_state.empty())
+    state_cookie_ = std::move(chunk->post_state);
+  waiting_for_response_messages_.erase(chunk->call_id);
+  response_message_buffer_size_ = 0;
+  std::string message;
+  message.swap(response_message_buffer_);
+  client_->DispatchProtocolMessage(agent_host_, message);
+  // |this| may be deleted at this point.
+}
+
+void DevToolsSession::ReceivedBadMessage() {
   MojoConnectionDestroyed();
   if (process_) {
     bad_message::ReceivedBadMessage(
diff --git a/content/browser/devtools/devtools_session.h b/content/browser/devtools/devtools_session.h
index bc8e982..24de333 100644
--- a/content/browser/devtools/devtools_session.h
+++ b/content/browser/devtools/devtools_session.h
@@ -44,7 +44,7 @@
   };
   using MessageByCallId = std::map<int, Message>;
   MessageByCallId& waiting_messages() { return waiting_for_response_messages_; }
-  const std::string& state_cookie() { return chunk_processor_.state_cookie(); }
+  const std::string& state_cookie() { return state_cookie_; }
 
   protocol::Response::Status Dispatch(
       const std::string& message,
@@ -54,7 +54,7 @@
                                       const std::string& method,
                                       const std::string& message);
   void InspectElement(const gfx::Point& point);
-  bool ReceiveMessageChunk(const DevToolsMessageChunk& chunk);
+  void ReceiveMessageChunk(const DevToolsMessageChunk& chunk);
 
   template <typename Handler>
   static std::vector<Handler*> HandlersForAgentHost(
@@ -72,10 +72,9 @@
   }
 
  private:
-  void SendMessageFromProcessorIPC(int session_id, const std::string& message);
-  void SendMessageFromProcessor(const std::string& message);
   void SendResponse(std::unique_ptr<base::DictionaryValue> response);
   void MojoConnectionDestroyed();
+  void ReceivedBadMessage();
 
   // protocol::FrontendChannel implementation.
   void sendProtocolResponse(
@@ -99,11 +98,14 @@
   RenderProcessHost* process_;
   RenderFrameHostImpl* host_;
   std::unique_ptr<protocol::UberDispatcher> dispatcher_;
-  // Chunk processor's state cookie always corresponds to a state before
-  // any of the waiting for response messages have been handled.
-  DevToolsMessageChunkProcessor chunk_processor_;
   MessageByCallId waiting_for_response_messages_;
 
+  // |state_cookie_| always corresponds to a state before
+  // any of the waiting for response messages have been handled.
+  std::string state_cookie_;
+  std::string response_message_buffer_;
+  uint32_t response_message_buffer_size_ = 0;
+
   base::WeakPtrFactory<DevToolsSession> weak_factory_;
 };
 
diff --git a/content/browser/download/resource_downloader.cc b/content/browser/download/resource_downloader.cc
index f943534..d1d9d261 100644
--- a/content/browser/download/resource_downloader.cc
+++ b/content/browser/download/resource_downloader.cc
@@ -163,8 +163,7 @@
         std::move(url_loader_request),
         0,  // routing_id
         0,  // request_id
-        mojom::kURLLoadOptionSendSSLInfoWithResponse |
-            mojom::kURLLoadOptionSniffMimeType,
+        mojom::kURLLoadOptionSendSSLInfoWithResponse,
         *(resource_request_.get()), std::move(url_loader_client_ptr),
         net::MutableNetworkTrafficAnnotationTag(
             download_url_parameters->GetNetworkTrafficAnnotation()));
diff --git a/content/browser/loader/mojo_async_resource_handler.cc b/content/browser/loader/mojo_async_resource_handler.cc
index 5f9070b..6a8fd0a 100644
--- a/content/browser/loader/mojo_async_resource_handler.cc
+++ b/content/browser/loader/mojo_async_resource_handler.cc
@@ -98,14 +98,19 @@
     mojom::URLLoaderRequest mojo_request,
     mojom::URLLoaderClientPtr url_loader_client,
     ResourceType resource_type,
-    bool defer_on_response_started)
+    uint32_t url_loader_options)
     : ResourceHandler(request),
       rdh_(rdh),
       binding_(this, std::move(mojo_request)),
-      defer_on_response_started_(defer_on_response_started),
+      url_loader_options_(url_loader_options),
       handle_watcher_(FROM_HERE, mojo::SimpleWatcher::ArmingPolicy::MANUAL),
       url_loader_client_(std::move(url_loader_client)),
       weak_factory_(this) {
+  DCHECK(IsResourceTypeFrame(resource_type) ||
+         !(url_loader_options_ & mojom::kURLLoadOptionSendSSLInfoWithResponse));
+  DCHECK(resource_type == RESOURCE_TYPE_MAIN_FRAME ||
+         !(url_loader_options_ &
+           mojom::kURLLoadOptionSendSSLInfoForCertificateError));
   DCHECK(url_loader_client_);
   InitializeResourceBufferConstants();
   // This unretained pointer is safe, because |binding_| is owned by |this| and
@@ -184,7 +189,11 @@
                                      response->head.download_file_path);
   }
 
-  url_loader_client_->OnReceiveResponse(response->head, base::nullopt,
+  base::Optional<net::SSLInfo> ssl_info;
+  if (url_loader_options_ & mojom::kURLLoadOptionSendSSLInfoWithResponse)
+    ssl_info = request()->ssl_info();
+
+  url_loader_client_->OnReceiveResponse(response->head, std::move(ssl_info),
                                         std::move(downloaded_file_ptr));
 
   net::IOBufferWithSize* metadata = GetResponseMetadata(request());
@@ -195,7 +204,7 @@
         std::vector<uint8_t>(data, data + metadata->size()));
   }
 
-  if (defer_on_response_started_) {
+  if (url_loader_options_ & mojom::kURLLoadOptionPauseOnResponseStarted) {
     did_defer_on_response_started_ = true;
     DCHECK(!has_controller());
     request()->LogBlockedBy("MojoAsyncResourceHandler");
@@ -470,6 +479,13 @@
   loader_status.blocked_cross_site_document =
       GetRequestInfo()->blocked_cross_site_document();
 
+  if ((url_loader_options_ &
+       mojom::kURLLoadOptionSendSSLInfoForCertificateError) &&
+      net::IsCertStatusError(request()->ssl_info().cert_status) &&
+      !net::IsCertStatusMinorError(request()->ssl_info().cert_status)) {
+    loader_status.ssl_info = request()->ssl_info();
+  }
+
   url_loader_client_->OnComplete(loader_status);
   controller->Resume();
 }
diff --git a/content/browser/loader/mojo_async_resource_handler.h b/content/browser/loader/mojo_async_resource_handler.h
index a8e7282..0d26e2d 100644
--- a/content/browser/loader/mojo_async_resource_handler.h
+++ b/content/browser/loader/mojo_async_resource_handler.h
@@ -56,7 +56,7 @@
                            mojom::URLLoaderRequest mojo_request,
                            mojom::URLLoaderClientPtr url_loader_client,
                            ResourceType resource_type,
-                           bool defer_on_response_started);
+                           uint32_t url_loader_options);
   ~MojoAsyncResourceHandler() override;
 
   // ResourceHandler implementation:
@@ -133,7 +133,7 @@
   ResourceDispatcherHostImpl* rdh_;
   mojo::Binding<mojom::URLLoader> binding_;
 
-  bool defer_on_response_started_;
+  uint32_t url_loader_options_;
 
   bool has_checked_for_sufficient_resources_ = false;
   bool sent_received_response_message_ = false;
diff --git a/content/browser/loader/mojo_async_resource_handler_unittest.cc b/content/browser/loader/mojo_async_resource_handler_unittest.cc
index 1dff2e2..85a8c4f 100644
--- a/content/browser/loader/mojo_async_resource_handler_unittest.cc
+++ b/content/browser/loader/mojo_async_resource_handler_unittest.cc
@@ -44,11 +44,13 @@
 #include "mojo/public/cpp/system/data_pipe.h"
 #include "net/base/auth.h"
 #include "net/base/net_errors.h"
+#include "net/cert/cert_status_flags.h"
 #include "net/http/http_response_headers.h"
 #include "net/http/http_response_info.h"
 #include "net/http/http_status_code.h"
 #include "net/http/http_util.h"
 #include "net/ssl/client_cert_store.h"
+#include "net/ssl/ssl_info.h"
 #include "net/test/url_request/url_request_mock_data_job.h"
 #include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
 #include "net/url_request/url_request.h"
@@ -206,13 +208,13 @@
       ResourceDispatcherHostImpl* rdh,
       mojom::URLLoaderRequest mojo_request,
       mojom::URLLoaderClientPtr url_loader_client,
-      bool defer_on_response_started)
+      uint32_t options)
       : MojoAsyncResourceHandler(request,
                                  rdh,
                                  std::move(mojo_request),
                                  std::move(url_loader_client),
                                  RESOURCE_TYPE_MAIN_FRAME,
-                                 defer_on_response_started),
+                                 options),
         task_runner_(new base::TestSimpleTaskRunner) {}
   ~MojoAsyncResourceHandlerWithStubOperations() override {}
 
@@ -320,7 +322,7 @@
  public:
   MojoAsyncResourceHandlerTestBase(
       std::unique_ptr<net::UploadDataStream> upload_stream,
-      bool defer_on_response_started)
+      uint32_t options)
       : thread_bundle_(TestBrowserThreadBundle::IO_MAINLOOP),
         browser_context_(new TestBrowserContext()) {
     MojoAsyncResourceHandler::SetAllocationSizeForTesting(32 * 1024);
@@ -365,7 +367,7 @@
 
     handler_.reset(new MojoAsyncResourceHandlerWithStubOperations(
         request_.get(), &rdh_, factory_impl->PassLoaderRequest(),
-        factory_impl->PassClientPtr(), defer_on_response_started));
+        factory_impl->PassClientPtr(), options));
     mock_loader_.reset(new MockResourceLoader(handler_.get()));
   }
 
@@ -434,9 +436,7 @@
                                      public ::testing::Test {
  protected:
   MojoAsyncResourceHandlerTest()
-      : MojoAsyncResourceHandlerTestBase(
-            nullptr,
-            false /* defer_on_response_started */) {}
+      : MojoAsyncResourceHandlerTestBase(nullptr, mojom::kURLLoadOptionNone) {}
 };
 
 class MojoAsyncResourceHandlerDeferOnResponseStartedTest
@@ -444,9 +444,29 @@
       public ::testing::Test {
  protected:
   MojoAsyncResourceHandlerDeferOnResponseStartedTest()
-      : MojoAsyncResourceHandlerTestBase(nullptr,
-                                         true /* defer_on_response_started */) {
-  }
+      : MojoAsyncResourceHandlerTestBase(
+            nullptr,
+            mojom::kURLLoadOptionPauseOnResponseStarted) {}
+};
+
+class MojoAsyncResourceHandlerSendSSLInfoWithResponseTest
+    : public MojoAsyncResourceHandlerTestBase,
+      public ::testing::Test {
+ protected:
+  MojoAsyncResourceHandlerSendSSLInfoWithResponseTest()
+      : MojoAsyncResourceHandlerTestBase(
+            nullptr,
+            mojom::kURLLoadOptionSendSSLInfoWithResponse) {}
+};
+
+class MojoAsyncResourceHandlerSendSSLInfoForCertificateError
+    : public MojoAsyncResourceHandlerTestBase,
+      public ::testing::Test {
+ protected:
+  MojoAsyncResourceHandlerSendSSLInfoForCertificateError()
+      : MojoAsyncResourceHandlerTestBase(
+            nullptr,
+            mojom::kURLLoadOptionSendSSLInfoForCertificateError) {}
 };
 
 // This test class is parameterized with MojoAsyncResourceHandler's allocation
@@ -456,9 +476,7 @@
       public ::testing::TestWithParam<size_t> {
  protected:
   MojoAsyncResourceHandlerWithAllocationSizeTest()
-      : MojoAsyncResourceHandlerTestBase(
-            nullptr,
-            false /* defer_on_response_started */) {
+      : MojoAsyncResourceHandlerTestBase(nullptr, mojom::kURLLoadOptionNone) {
     MojoAsyncResourceHandler::SetAllocationSizeForTesting(GetParam());
   }
 };
@@ -470,7 +488,7 @@
   MojoAsyncResourceHandlerUploadTest()
       : MojoAsyncResourceHandlerTestBase(
             std::make_unique<DummyUploadDataStream>(),
-            false /* defer_on_response_started */) {}
+            mojom::kURLLoadOptionNone) {}
 };
 
 TEST_F(MojoAsyncResourceHandlerTest, InFlightRequests) {
@@ -1385,6 +1403,73 @@
   }
 }
 
+// Test that SSLInfo is not attached to OnResponseStarted when there is no
+// kURLLoadOptionsSendSSLInfoWithResponse option.
+TEST_F(MojoAsyncResourceHandlerTest, SSLInfoOnResponseStarted) {
+  EXPECT_TRUE(CallOnWillStartAndOnResponseStarted());
+  EXPECT_FALSE(url_loader_client_.ssl_info());
+}
+
+// Test that SSLInfo is attached to OnResponseStarted when there is a
+// kURLLoadOptionsSendSSLInfoWithResponse option.
+TEST_F(MojoAsyncResourceHandlerSendSSLInfoWithResponseTest,
+       SSLInfoOnResponseStarted) {
+  EXPECT_TRUE(CallOnWillStartAndOnResponseStarted());
+  EXPECT_TRUE(url_loader_client_.ssl_info());
+}
+
+// Test that SSLInfo is not attached to OnResponseComplete when there is no
+// kURLLoadOptionsSendSSLInfoForCertificateError option.
+TEST_F(MojoAsyncResourceHandlerTest, SSLInfoOnComplete) {
+  EXPECT_TRUE(CallOnWillStart());
+
+  // Simulates the request getting a major SSL error.
+  const_cast<net::SSLInfo&>(request_->ssl_info()).cert_status =
+      net::CERT_STATUS_AUTHORITY_INVALID;
+  ASSERT_EQ(
+      MockResourceLoader::Status::IDLE,
+      mock_loader_->OnResponseCompleted(net::URLRequestStatus(
+          net::URLRequestStatus::CANCELED, net::ERR_CERT_AUTHORITY_INVALID)));
+
+  url_loader_client_.RunUntilComplete();
+  EXPECT_FALSE(url_loader_client_.completion_status().ssl_info);
+};
+
+// Test that SSLInfo is attached to OnResponseComplete when there is the
+// kURLLoadOptionsSendSSLInfoForCertificateError option.
+TEST_F(MojoAsyncResourceHandlerSendSSLInfoForCertificateError,
+       SSLInfoOnCompleteMajorError) {
+  EXPECT_TRUE(CallOnWillStart());
+
+  // Simulates the request getting a major SSL error.
+  const_cast<net::SSLInfo&>(request_->ssl_info()).cert_status =
+      net::CERT_STATUS_AUTHORITY_INVALID;
+  ASSERT_EQ(
+      MockResourceLoader::Status::IDLE,
+      mock_loader_->OnResponseCompleted(net::URLRequestStatus(
+          net::URLRequestStatus::CANCELED, net::ERR_CERT_AUTHORITY_INVALID)));
+
+  url_loader_client_.RunUntilComplete();
+  EXPECT_TRUE(url_loader_client_.completion_status().ssl_info);
+};
+
+// Test that SSLInfo is not attached to OnResponseComplete when there is the
+// kURLLoadOptionsSendSSLInfoForCertificateError option and a minor SSL error.
+TEST_F(MojoAsyncResourceHandlerSendSSLInfoForCertificateError,
+       SSLInfoOnCompleteMinorError) {
+  EXPECT_TRUE(CallOnWillStart());
+
+  // Simulates the request getting a minor SSL error.
+  const_cast<net::SSLInfo&>(request_->ssl_info()).cert_status =
+      net::CERT_STATUS_UNABLE_TO_CHECK_REVOCATION;
+
+  EXPECT_TRUE(CallOnResponseStarted());
+  ASSERT_EQ(MockResourceLoader::Status::IDLE,
+            mock_loader_->OnResponseCompleted(net::URLRequestStatus()));
+  url_loader_client_.RunUntilComplete();
+  EXPECT_FALSE(url_loader_client_.completion_status().ssl_info);
+};
+
 INSTANTIATE_TEST_CASE_P(MojoAsyncResourceHandlerWithAllocationSizeTest,
                         MojoAsyncResourceHandlerWithAllocationSizeTest,
                         ::testing::Values(8, 32 * 2014));
diff --git a/content/browser/loader/navigation_url_loader_impl_core.cc b/content/browser/loader/navigation_url_loader_impl_core.cc
index 6a7d05c8..6917407 100644
--- a/content/browser/loader/navigation_url_loader_impl_core.cc
+++ b/content/browser/loader/navigation_url_loader_impl_core.cc
@@ -19,6 +19,7 @@
 #include "content/public/browser/ssl_status.h"
 #include "content/public/browser/stream_handle.h"
 #include "content/public/common/resource_response.h"
+#include "content/public/common/url_loader_factory.mojom.h"
 #include "net/base/net_errors.h"
 #include "net/url_request/redirect_info.h"
 #include "net/url_request/url_request_context_getter.h"
@@ -56,7 +57,7 @@
         upload_file_system_context, *request_info,
         std::move(navigation_ui_data), this, mojom::URLLoaderClientPtr(),
         mojom::URLLoaderRequest(), service_worker_handle_core,
-        appcache_handle_core);
+        appcache_handle_core, mojom::kURLLoadOptionNone);
   }
 
   // Careful, |this| could be destroyed at this point. Don't notify start if
diff --git a/content/browser/loader/navigation_url_loader_network_service.cc b/content/browser/loader/navigation_url_loader_network_service.cc
index d3f8d1a..7b96343 100644
--- a/content/browser/loader/navigation_url_loader_network_service.cc
+++ b/content/browser/loader/navigation_url_loader_network_service.cc
@@ -185,6 +185,23 @@
     DCHECK_CURRENTLY_ON(BrowserThread::IO);
   }
 
+  static uint32_t GetURLLoaderOptions(bool is_main_frame) {
+    uint32_t options = mojom::kURLLoadOptionSendSSLInfoWithResponse;
+    if (is_main_frame)
+      options |= mojom::kURLLoadOptionSendSSLInfoForCertificateError;
+
+    if (base::FeatureList::IsEnabled(features::kNetworkService)) {
+      options |= mojom::kURLLoadOptionSniffMimeType;
+    } else {
+      // TODO(arthursonzogni): This is a temporary option. Remove this as soon
+      // as the InterceptingResourceHandler is removed.
+      // See https://crbug.com/791049.
+      options |= mojom::kURLLoadOptionPauseOnResponseStarted;
+    }
+
+    return options;
+  }
+
   void CreateNonNetworkServiceURLLoader(
       net::URLRequestContextGetter* url_request_context_getter,
       storage::FileSystemContext* upload_file_system_context,
@@ -204,7 +221,8 @@
           upload_file_system_context, *request_info,
           std::move(navigation_ui_data), nullptr, std::move(url_loader_client),
           std::move(url_loader), service_worker_navigation_handle_core,
-          appcache_handle_core);
+          appcache_handle_core,
+          GetURLLoaderOptions(request_info->is_main_frame));
     }
 
     // TODO(arthursonzogni): Detect when the ResourceDispatcherHost didn't
@@ -414,10 +432,8 @@
       default_loader_used_ = true;
     }
     url_chain_.push_back(resource_request_->url);
-    uint32_t options = mojom::kURLLoadOptionSendSSLInfoWithResponse |
-                       mojom::kURLLoadOptionSniffMimeType;
-    if (resource_request_->resource_type == RESOURCE_TYPE_MAIN_FRAME)
-      options |= mojom::kURLLoadOptionSendSSLInfoForCertificateError;
+    uint32_t options = GetURLLoaderOptions(resource_request_->resource_type ==
+                                           RESOURCE_TYPE_MAIN_FRAME);
     url_loader_ = ThrottlingURLLoader::CreateLoaderAndStart(
         factory,
         GetContentClient()->browser()->CreateURLLoaderThrottles(
@@ -757,7 +773,8 @@
   new_request->fetch_request_mode = network::mojom::FetchRequestMode::kNavigate;
   new_request->fetch_credentials_mode =
       network::mojom::FetchCredentialsMode::kInclude;
-  new_request->fetch_redirect_mode = FetchRedirectMode::MANUAL_MODE;
+  new_request->fetch_redirect_mode =
+      static_cast<int>(FetchRedirectMode::MANUAL_MODE);
 
   // Check if a web UI scheme wants to handle this request.
   FrameTreeNode* frame_tree_node =
diff --git a/content/browser/loader/resource_dispatcher_host_impl.cc b/content/browser/loader/resource_dispatcher_host_impl.cc
index 6fa19390..135b728 100644
--- a/content/browser/loader/resource_dispatcher_host_impl.cc
+++ b/content/browser/loader/resource_dispatcher_host_impl.cc
@@ -26,7 +26,6 @@
 #include "base/memory/shared_memory.h"
 #include "base/message_loop/message_loop.h"
 #include "base/metrics/field_trial.h"
-#include "base/metrics/field_trial_params.h"
 #include "base/metrics/histogram_functions.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/stl_util.h"
@@ -832,7 +831,8 @@
   DCHECK(request_data.transferred_request_child_id != -1 ||
          request_data.transferred_request_request_id != -1);
 
-  if (!IsResourceTypeFrame(request_data.resource_type)) {
+  if (!IsResourceTypeFrame(
+          static_cast<ResourceType>(request_data.resource_type))) {
     // Transfers apply only to navigational requests - the renderer seems to
     // have sent bogus IPC data.
     bad_message::ReceivedBadMessage(
@@ -898,7 +898,8 @@
   // PlzNavigate: reject invalid renderer main resource request.
   bool is_navigation_stream_request =
       IsBrowserSideNavigationEnabled() &&
-      IsResourceTypeFrame(request_data.resource_type);
+      IsResourceTypeFrame(
+          static_cast<ResourceType>(request_data.resource_type));
   if (is_navigation_stream_request &&
       !request_data.resource_body_stream_url.SchemeIs(url::kBlobScheme)) {
     // The resource_type of navigation preload requests must be SUB_RESOURCE.
@@ -936,8 +937,9 @@
 
   ResourceContext* resource_context = nullptr;
   net::URLRequestContext* request_context = nullptr;
-  requester_info->GetContexts(request_data.resource_type, &resource_context,
-                              &request_context);
+  requester_info->GetContexts(
+      static_cast<ResourceType>(request_data.resource_type), &resource_context,
+      &request_context);
 
   // Parse the headers before calling ShouldServiceRequest, so that they are
   // available to be validated.
@@ -1044,18 +1046,20 @@
   int load_flags = BuildLoadFlagsForRequest(request_data);
   bool is_navigation_stream_request =
       IsBrowserSideNavigationEnabled() &&
-      IsResourceTypeFrame(request_data.resource_type);
+      IsResourceTypeFrame(
+          static_cast<ResourceType>(request_data.resource_type));
 
   ResourceContext* resource_context = nullptr;
   net::URLRequestContext* request_context = nullptr;
-  requester_info->GetContexts(request_data.resource_type, &resource_context,
-                              &request_context);
+  requester_info->GetContexts(
+      static_cast<ResourceType>(request_data.resource_type), &resource_context,
+      &request_context);
 
   // Allow the observer to block/handle the request.
-  if (delegate_ && !delegate_->ShouldBeginRequest(request_data.method,
-                                                  request_data.url,
-                                                  request_data.resource_type,
-                                                  resource_context)) {
+  if (delegate_ && !delegate_->ShouldBeginRequest(
+                       request_data.method, request_data.url,
+                       static_cast<ResourceType>(request_data.resource_type),
+                       resource_context)) {
     AbortRequestBeforeItStarts(requester_info->filter(), request_id,
                                std::move(url_loader_client));
     return;
@@ -1090,7 +1094,8 @@
     // Browser-initiated navigations don't have an initiator document, the
     // others have one.
     DCHECK(request_data.request_initiator.has_value() ||
-           IsResourceTypeFrame(request_data.resource_type));
+           IsResourceTypeFrame(
+               static_cast<ResourceType>(request_data.resource_type)));
     new_request->set_initiator(request_data.request_initiator);
 
     if (request_data.originated_from_service_worker) {
@@ -1130,7 +1135,8 @@
     }
 
     allow_download = request_data.allow_download &&
-                     IsResourceTypeFrame(request_data.resource_type);
+                     IsResourceTypeFrame(
+                         static_cast<ResourceType>(request_data.resource_type));
     do_not_prompt_for_login = request_data.do_not_prompt_for_login;
 
     // Raw headers are sensitive, as they include Cookie/Set-Cookie, so only
@@ -1207,8 +1213,10 @@
       requester_info, route_id,
       -1,  // frame_tree_node_id
       request_data.plugin_child_id, request_id, request_data.render_frame_id,
-      request_data.is_main_frame, request_data.resource_type,
-      request_data.transition_type, request_data.should_replace_current_entry,
+      request_data.is_main_frame,
+      static_cast<ResourceType>(request_data.resource_type),
+      static_cast<ui::PageTransition>(request_data.transition_type),
+      request_data.should_replace_current_entry,
       false,  // is download
       false,  // is stream
       allow_download, request_data.has_user_gesture,
@@ -1241,27 +1249,32 @@
     // the initial request.
     handler = CreateBaseResourceHandler(
         new_request.get(), std::move(mojo_request),
-        std::move(url_loader_client), request_data.resource_type);
+        std::move(url_loader_client),
+        static_cast<ResourceType>(request_data.resource_type));
   } else {
     // Initialize the service worker handler for the request. We don't use
     // ServiceWorker for synchronous loads to avoid renderer deadlocks.
     const ServiceWorkerMode service_worker_mode =
-        is_sync_load ? ServiceWorkerMode::NONE
-                     : request_data.service_worker_mode;
+        is_sync_load
+            ? ServiceWorkerMode::NONE
+            : static_cast<ServiceWorkerMode>(request_data.service_worker_mode);
     ServiceWorkerRequestHandler::InitializeHandler(
         new_request.get(), requester_info->service_worker_context(),
         blob_context, child_id, request_data.service_worker_provider_id,
         service_worker_mode != ServiceWorkerMode::ALL,
         request_data.fetch_request_mode, request_data.fetch_credentials_mode,
-        request_data.fetch_redirect_mode, request_data.fetch_integrity,
-        request_data.keepalive, request_data.resource_type,
-        request_data.fetch_request_context_type, request_data.fetch_frame_type,
-        request_data.request_body);
+        static_cast<FetchRedirectMode>(request_data.fetch_redirect_mode),
+        request_data.fetch_integrity, request_data.keepalive,
+        static_cast<ResourceType>(request_data.resource_type),
+        static_cast<RequestContextType>(
+            request_data.fetch_request_context_type),
+        request_data.fetch_frame_type, request_data.request_body);
 
     // Have the appcache associate its extra info with the request.
     AppCacheInterceptor::SetExtraRequestInfo(
         new_request.get(), requester_info->appcache_service(), child_id,
-        request_data.appcache_host_id, request_data.resource_type,
+        request_data.appcache_host_id,
+        static_cast<ResourceType>(request_data.resource_type),
         request_data.should_reset_appcache);
     handler = CreateResourceHandler(requester_info.get(), new_request.get(),
                                     request_data, route_id, child_id,
@@ -1285,9 +1298,9 @@
   DCHECK(requester_info->IsRenderer() || requester_info->IsNavigationPreload());
   // Construct the IPC resource handler.
   std::unique_ptr<ResourceHandler> handler;
-  handler = CreateBaseResourceHandler(request, std::move(mojo_request),
-                                      std::move(url_loader_client),
-                                      request_data.resource_type);
+  handler = CreateBaseResourceHandler(
+      request, std::move(mojo_request), std::move(url_loader_client),
+      static_cast<ResourceType>(request_data.resource_type));
 
   // The RedirectToFileResourceHandler depends on being next in the chain.
   if (request_data.download_to_file) {
@@ -1300,29 +1313,21 @@
   // Prefetches and <a ping> requests outlive their child process.
   if (start_detached || request_data.resource_type == RESOURCE_TYPE_PREFETCH ||
       request_data.keepalive) {
-    auto timeout =
-        base::TimeDelta::FromMilliseconds(kDefaultDetachableCancelDelayMs);
-    int timeout_set_by_finch_in_sec = base::GetFieldTrialParamByFeatureAsInt(
-        features::kFetchKeepaliveTimeoutSetting, "timeout_in_sec", 0);
-    // Adopt only "reasonable" values.
-    if (timeout_set_by_finch_in_sec > 0 &&
-        timeout_set_by_finch_in_sec < 60 * 60) {
-      timeout = base::TimeDelta::FromSeconds(timeout_set_by_finch_in_sec);
-    }
-
-    std::unique_ptr<DetachableResourceHandler> detachable_handler =
-        std::make_unique<DetachableResourceHandler>(request, timeout,
-                                                    std::move(handler));
+    auto detachable_handler = std::make_unique<DetachableResourceHandler>(
+        request,
+        base::TimeDelta::FromMilliseconds(kDefaultDetachableCancelDelayMs),
+        std::move(handler));
     if (start_detached)
       detachable_handler->Detach();
     handler = std::move(detachable_handler);
   }
 
-  return AddStandardHandlers(request, request_data.resource_type,
-                             resource_context, request_data.fetch_request_mode,
-                             request_data.fetch_request_context_type,
-                             requester_info->appcache_service(), child_id,
-                             route_id, std::move(handler), nullptr, nullptr);
+  return AddStandardHandlers(
+      request, static_cast<ResourceType>(request_data.resource_type),
+      resource_context, request_data.fetch_request_mode,
+      static_cast<RequestContextType>(request_data.fetch_request_context_type),
+      requester_info->appcache_service(), child_id, route_id,
+      std::move(handler), nullptr, nullptr);
 }
 
 std::unique_ptr<ResourceHandler>
@@ -1332,10 +1337,9 @@
     mojom::URLLoaderClientPtr url_loader_client,
     ResourceType resource_type) {
   std::unique_ptr<ResourceHandler> handler;
-  handler.reset(
-      new MojoAsyncResourceHandler(request, this, std::move(mojo_request),
-                                   std::move(url_loader_client), resource_type,
-                                   false));  // defer_on_response_started.
+  handler.reset(new MojoAsyncResourceHandler(
+      request, this, std::move(mojo_request), std::move(url_loader_client),
+      resource_type, mojom::kURLLoadOptionNone));
   return handler;
 }
 
@@ -1817,7 +1821,8 @@
     mojom::URLLoaderClientPtr url_loader_client,
     mojom::URLLoaderRequest url_loader_request,
     ServiceWorkerNavigationHandleCore* service_worker_handle_core,
-    AppCacheNavigationHandleCore* appcache_handle_core) {
+    AppCacheNavigationHandleCore* appcache_handle_core,
+    uint32_t url_loader_options) {
   // PlzNavigate: BeginNavigationRequest currently should only be used for the
   // browser-side navigations project.
   CHECK(IsBrowserSideNavigationEnabled());
@@ -1990,8 +1995,7 @@
   if (IsNavigationMojoResponseEnabled()) {
     handler = std::make_unique<MojoAsyncResourceHandler>(
         new_request.get(), this, std::move(url_loader_request),
-        std::move(url_loader_client), resource_type,
-        true);  // defer_on_response_started.
+        std::move(url_loader_client), resource_type, url_loader_options);
   } else {
     StreamContext* stream_context =
         GetStreamContextForResourceContext(resource_context);
@@ -2465,7 +2469,8 @@
       ChildProcessSecurityPolicyImpl::GetInstance();
   bool is_navigation_stream_request =
       IsBrowserSideNavigationEnabled() &&
-      IsResourceTypeFrame(request_data.resource_type);
+      IsResourceTypeFrame(
+          static_cast<ResourceType>(request_data.resource_type));
   // Check if the renderer is permitted to request the requested URL.
   // PlzNavigate: no need to check the URL here. The browser already picked the
   // right renderer to send the request to. The original URL isn't used, as the
diff --git a/content/browser/loader/resource_dispatcher_host_impl.h b/content/browser/loader/resource_dispatcher_host_impl.h
index 391e7667..595a25b5 100644
--- a/content/browser/loader/resource_dispatcher_host_impl.h
+++ b/content/browser/loader/resource_dispatcher_host_impl.h
@@ -259,7 +259,8 @@
       mojom::URLLoaderClientPtr url_loader_client,
       mojom::URLLoaderRequest url_loader_request,
       ServiceWorkerNavigationHandleCore* service_worker_handle_core,
-      AppCacheNavigationHandleCore* appcache_handle_core);
+      AppCacheNavigationHandleCore* appcache_handle_core,
+      uint32_t url_loader_options);
 
   int num_in_flight_requests_for_testing() const {
     return num_in_flight_requests_;
diff --git a/content/browser/media/capture/cursor_renderer_aura_unittest.cc b/content/browser/media/capture/cursor_renderer_aura_unittest.cc
index 2c6439d..b9017fa 100644
--- a/content/browser/media/capture/cursor_renderer_aura_unittest.cc
+++ b/content/browser/media/capture/cursor_renderer_aura_unittest.cc
@@ -73,7 +73,7 @@
     if (!dummy_frame_) {
       constexpr gfx::Size dummy_frame_size = gfx::Size(320, 200);
       dummy_frame_ = media::VideoFrame::CreateZeroInitializedFrame(
-          media::PIXEL_FORMAT_YV12, dummy_frame_size,
+          media::PIXEL_FORMAT_I420, dummy_frame_size,
           gfx::Rect(dummy_frame_size), dummy_frame_size, base::TimeDelta());
     }
     return RenderCursorOnVideoFrame(dummy_frame_.get(), nullptr);
@@ -226,7 +226,7 @@
 
   gfx::Size size(800, 600);
   scoped_refptr<media::VideoFrame> frame =
-      media::VideoFrame::CreateZeroInitializedFrame(media::PIXEL_FORMAT_YV12,
+      media::VideoFrame::CreateZeroInitializedFrame(media::PIXEL_FORMAT_I420,
                                                     size, gfx::Rect(size), size,
                                                     base::TimeDelta());
 
diff --git a/content/browser/media/capture/cursor_renderer_mac_unittest.mm b/content/browser/media/capture/cursor_renderer_mac_unittest.mm
index a2d35fd..3bf343b 100644
--- a/content/browser/media/capture/cursor_renderer_mac_unittest.mm
+++ b/content/browser/media/capture/cursor_renderer_mac_unittest.mm
@@ -62,7 +62,7 @@
     if (!dummy_frame_) {
       constexpr gfx::Size dummy_frame_size = gfx::Size(320, 200);
       dummy_frame_ = media::VideoFrame::CreateZeroInitializedFrame(
-          media::PIXEL_FORMAT_YV12, dummy_frame_size,
+          media::PIXEL_FORMAT_I420, dummy_frame_size,
           gfx::Rect(dummy_frame_size), dummy_frame_size, base::TimeDelta());
     }
     return RenderCursorOnVideoFrame(dummy_frame_.get(), nullptr);
@@ -210,7 +210,7 @@
 
   gfx::Size size(kTestViewWidth, kTestViewHeight);
   scoped_refptr<media::VideoFrame> frame =
-      media::VideoFrame::CreateZeroInitializedFrame(media::PIXEL_FORMAT_YV12,
+      media::VideoFrame::CreateZeroInitializedFrame(media::PIXEL_FORMAT_I420,
                                                     size, gfx::Rect(size), size,
                                                     base::TimeDelta());
 
diff --git a/content/browser/media/key_system_support_impl.cc b/content/browser/media/key_system_support_impl.cc
new file mode 100644
index 0000000..9a55c26
--- /dev/null
+++ b/content/browser/media/key_system_support_impl.cc
@@ -0,0 +1,90 @@
+// 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 "content/browser/media/key_system_support_impl.h"
+
+#include <vector>
+
+#include "base/logging.h"
+#include "content/public/browser/cdm_registry.h"
+#include "content/public/common/cdm_info.h"
+#include "media/base/key_system_names.h"
+#include "mojo/public/cpp/bindings/strong_binding.h"
+
+#if DCHECK_IS_ON()
+#include "base/strings/utf_string_conversions.h"
+#include "content/public/browser/plugin_service.h"
+#include "content/public/common/webplugininfo.h"
+#endif  // DCHECK_IS_ON()
+
+namespace content {
+
+#if DCHECK_IS_ON()
+namespace {
+
+// TODO(crbug.com/772160) Remove this when pepper CDM support removed.
+bool IsPepperPluginRegistered(const std::string& plugin_name) {
+  std::vector<WebPluginInfo> plugins;
+  PluginService::GetInstance()->GetInternalPlugins(&plugins);
+  for (const auto& plugin : plugins) {
+    if (plugin.is_pepper_plugin() &&
+        plugin.name == base::ASCIIToUTF16(plugin_name))
+      return true;
+  }
+  return false;
+}
+
+}  // namespace
+#endif  // DCHECK_IS_ON()
+
+// static
+void KeySystemSupportImpl::Create(
+    media::mojom::KeySystemSupportRequest request) {
+  DVLOG(3) << __func__;
+  // The created object is bound to (and owned by) |request|.
+  mojo::MakeStrongBinding(std::make_unique<KeySystemSupportImpl>(),
+                          std::move(request));
+}
+
+// static
+std::unique_ptr<CdmInfo> KeySystemSupportImpl::GetCdmInfoForKeySystem(
+    const std::string& key_system) {
+  DVLOG(2) << __func__ << ": key_system = " << key_system;
+  for (const auto& cdm : CdmRegistry::GetInstance()->GetAllRegisteredCdms()) {
+    if (cdm.supported_key_system == key_system ||
+        (cdm.supports_sub_key_systems &&
+         media::IsChildKeySystemOf(key_system, cdm.supported_key_system))) {
+      return std::make_unique<CdmInfo>(cdm);
+    }
+  }
+
+  return nullptr;
+}
+
+KeySystemSupportImpl::KeySystemSupportImpl() = default;
+
+KeySystemSupportImpl::~KeySystemSupportImpl() = default;
+
+void KeySystemSupportImpl::IsKeySystemSupported(
+    const std::string& key_system,
+    IsKeySystemSupportedCallback callback) {
+  DVLOG(3) << __func__;
+  std::unique_ptr<CdmInfo> cdm = GetCdmInfoForKeySystem(key_system);
+  if (!cdm) {
+    std::move(callback).Run(false, {}, false);
+    return;
+  }
+
+#if DCHECK_IS_ON()
+  DCHECK(IsPepperPluginRegistered(cdm->name))
+      << "Pepper plugin for " << key_system << " should also be registered.";
+#endif
+
+  // TODO(jrummell): Add UMA to replace "Plugin.AvailabilityStatus.WidevineCdm"
+  // which will go away when the Pepper plugin code is removed.
+  std::move(callback).Run(true, cdm->supported_video_codecs,
+                          cdm->supports_persistent_license);
+}
+
+}  // namespace content
diff --git a/content/browser/media/key_system_support_impl.h b/content/browser/media/key_system_support_impl.h
new file mode 100644
index 0000000..ad32f7a
--- /dev/null
+++ b/content/browser/media/key_system_support_impl.h
@@ -0,0 +1,42 @@
+// 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_BROWSER_MEDIA_KEY_SYSTEM_SUPPORT_IMPL_H_
+#define CONTENT_BROWSER_MEDIA_KEY_SYSTEM_SUPPORT_IMPL_H_
+
+#include <memory>
+#include <string>
+
+#include "base/macros.h"
+#include "content/common/content_export.h"
+#include "content/public/common/cdm_info.h"
+#include "media/mojo/interfaces/key_system_support.mojom.h"
+
+namespace content {
+
+class CONTENT_EXPORT KeySystemSupportImpl final
+    : public media::mojom::KeySystemSupport {
+ public:
+  KeySystemSupportImpl();
+  ~KeySystemSupportImpl() final;
+
+  // Create a KeySystemSupportImpl object and bind it to |request|.
+  static void Create(media::mojom::KeySystemSupportRequest request);
+
+  // Returns CdmInfo registered for |key_system|. Returns null if no CdmInfo is
+  // registered for |key_system|, or if the CdmInfo registered is invalid.
+  static std::unique_ptr<CdmInfo> GetCdmInfoForKeySystem(
+      const std::string& key_system);
+
+  // media::mojom::KeySystemSupport implementation.
+  void IsKeySystemSupported(const std::string& key_system,
+                            IsKeySystemSupportedCallback callback) final;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(KeySystemSupportImpl);
+};
+
+}  // namespace content
+
+#endif  // CONTENT_BROWSER_MEDIA_KEY_SYSTEM_SUPPORT_IMPL_H_
diff --git a/content/browser/media/key_system_support_impl_unittest.cc b/content/browser/media/key_system_support_impl_unittest.cc
new file mode 100644
index 0000000..719dcf29
--- /dev/null
+++ b/content/browser/media/key_system_support_impl_unittest.cc
@@ -0,0 +1,116 @@
+// 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 "content/browser/media/key_system_support_impl.h"
+
+#include <string>
+#include <vector>
+
+#include "base/logging.h"
+#include "base/strings/utf_string_conversions.h"
+#include "content/public/browser/cdm_registry.h"
+#include "content/public/browser/plugin_service.h"
+#include "content/public/common/cdm_info.h"
+#include "content/public/common/webplugininfo.h"
+#include "content/public/test/test_browser_thread_bundle.h"
+#include "media/base/video_codecs.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace content {
+
+namespace {
+
+const char kTestCdmGuid[] = "62FE9C4B-384E-48FD-B28A-9F6F248BC8CC";
+const char kVersion[] = "1.1.1.1";
+const char kTestPath[] = "/aa/bb";
+const char kTestFileSystemId[] = "file_system_id";
+
+}  // namespace
+
+class KeySystemSupportTest : public testing::Test {
+ protected:
+  void SetUp() final {
+    DVLOG(1) << __func__;
+    KeySystemSupportImpl::Create(mojo::MakeRequest(&key_system_support_));
+  }
+
+  // Registers |key_system| with |supported_video_codecs| and
+  // |supports_persistent_license|. All other values for CdmInfo have some
+  // default value as they're not returned by IsKeySystemSupported().
+  void Register(const std::string& key_system,
+                const std::vector<media::VideoCodec> supported_video_codecs,
+                bool supports_persistent_license) {
+    DVLOG(1) << __func__;
+
+    CdmRegistry::GetInstance()->RegisterCdm(
+        CdmInfo(key_system, kTestCdmGuid, base::Version(kVersion),
+                base::FilePath::FromUTF8Unsafe(kTestPath), kTestFileSystemId,
+                supported_video_codecs, supports_persistent_license, key_system,
+                false));
+
+    // As IsKeySystemSupported() checks for the matching pepper plugin,
+    // register a dummy one.
+    // TODO(crbug.com/772160) Remove this when pepper CDM support removed.
+    PluginService::GetInstance()->RegisterInternalPlugin(
+        WebPluginInfo(base::ASCIIToUTF16(key_system),
+                      base::FilePath::FromUTF8Unsafe(kTestPath),
+                      base::ASCIIToUTF16(kVersion), base::string16()),
+        true);
+  }
+
+  // Determines if |key_system| is registered. If it is, updates |codecs_|
+  // and |persistent_|.
+  bool IsSupported(const std::string& key_system) {
+    DVLOG(1) << __func__;
+    bool is_available = false;
+    key_system_support_->IsKeySystemSupported(key_system, &is_available,
+                                              &codecs_, &persistent_);
+    return is_available;
+  }
+
+  media::mojom::KeySystemSupportPtr key_system_support_;
+  TestBrowserThreadBundle test_browser_thread_bundle_;
+
+  // Updated by IsSupported().
+  std::vector<media::VideoCodec> codecs_;
+  bool persistent_;
+};
+
+// Note that as CdmRegistry::GetInstance() is a static, it is shared between
+// tests. So use unique key system names in each test below to avoid
+// interactions between the tests.
+
+TEST_F(KeySystemSupportTest, NoKeySystems) {
+  EXPECT_FALSE(IsSupported("KeySystem1"));
+}
+
+TEST_F(KeySystemSupportTest, OneKeySystem) {
+  Register("KeySystem2", {media::VideoCodec::kCodecVP8}, true);
+  EXPECT_TRUE(IsSupported("KeySystem2"));
+  EXPECT_EQ(1u, codecs_.size());
+  EXPECT_EQ(media::VideoCodec::kCodecVP8, codecs_[0]);
+  EXPECT_TRUE(persistent_);
+}
+
+TEST_F(KeySystemSupportTest, MultipleKeySystems) {
+  Register("KeySystem3",
+           {media::VideoCodec::kCodecVP8, media::VideoCodec::kCodecVP9}, true);
+  Register("KeySystem4", {media::VideoCodec::kCodecVP9}, false);
+  EXPECT_TRUE(IsSupported("KeySystem3"));
+  EXPECT_EQ(2u, codecs_.size());
+  EXPECT_EQ(media::VideoCodec::kCodecVP8, codecs_[0]);
+  EXPECT_EQ(media::VideoCodec::kCodecVP9, codecs_[1]);
+  EXPECT_TRUE(persistent_);
+  EXPECT_TRUE(IsSupported("KeySystem4"));
+  EXPECT_EQ(1u, codecs_.size());
+  EXPECT_EQ(media::VideoCodec::kCodecVP9, codecs_[0]);
+  EXPECT_FALSE(persistent_);
+}
+
+TEST_F(KeySystemSupportTest, MissingKeySystem) {
+  Register("KeySystem5", {media::VideoCodec::kCodecVP8}, true);
+  EXPECT_FALSE(IsSupported("KeySystem6"));
+}
+
+}  // namespace content
diff --git a/content/browser/media/media_interface_proxy.cc b/content/browser/media/media_interface_proxy.cc
index 1db9bcf..0e26058 100644
--- a/content/browser/media/media_interface_proxy.cc
+++ b/content/browser/media/media_interface_proxy.cc
@@ -31,7 +31,7 @@
 #if BUILDFLAG(ENABLE_LIBRARY_CDMS)
 #include "base/guid.h"
 #include "content/browser/media/cdm_storage_impl.h"
-#include "content/public/browser/cdm_registry.h"
+#include "content/browser/media/key_system_support_impl.h"
 #include "content/public/common/cdm_info.h"
 #include "media/base/key_system_names.h"
 #include "mojo/public/cpp/bindings/interface_request.h"
@@ -260,24 +260,6 @@
 
 #if BUILDFLAG(ENABLE_STANDALONE_CDM_SERVICE)
 
-#if BUILDFLAG(ENABLE_LIBRARY_CDMS)
-// Returns CdmInfo registered for |key_system|. Returns null if no CdmInfo is
-// registered for |key_system|, or if the CdmInfo registered is invalid.
-static std::unique_ptr<CdmInfo> GetCdmInfoForKeySystem(
-    const std::string& key_system) {
-  DVLOG(2) << __func__ << ": key_system = " << key_system;
-  for (const auto& cdm : CdmRegistry::GetInstance()->GetAllRegisteredCdms()) {
-    if (cdm.supported_key_system == key_system ||
-        (cdm.supports_sub_key_systems &&
-         media::IsChildKeySystemOf(key_system, cdm.supported_key_system))) {
-      return std::make_unique<CdmInfo>(cdm);
-    }
-  }
-
-  return nullptr;
-}
-#endif  // BUILDFLAG(ENABLE_LIBRARY_CDMS)
-
 media::mojom::InterfaceFactory* MediaInterfaceProxy::GetCdmInterfaceFactory(
     const std::string& key_system) {
   DCHECK(thread_checker_.CalledOnValidThread());
@@ -287,7 +269,8 @@
   std::string cdm_file_system_id;
 
 #if BUILDFLAG(ENABLE_LIBRARY_CDMS)
-  std::unique_ptr<CdmInfo> cdm_info = GetCdmInfoForKeySystem(key_system);
+  std::unique_ptr<CdmInfo> cdm_info =
+      KeySystemSupportImpl::GetCdmInfoForKeySystem(key_system);
   if (!cdm_info) {
     NOTREACHED() << "No valid CdmInfo for " << key_system;
     return nullptr;
diff --git a/content/browser/network_service_browsertest.cc b/content/browser/network_service_browsertest.cc
index 72014d5..ecab3580 100644
--- a/content/browser/network_service_browsertest.cc
+++ b/content/browser/network_service_browsertest.cc
@@ -35,10 +35,21 @@
 
   void RenderProcessGone(base::TerminationStatus status) override {
     killed_ = true;
+    run_loop_.Quit();
+  }
+
+  void WaitUntilRenderProcessDied() {
+    if (killed_)
+      return;
+    run_loop_.Run();
   }
 
  private:
   bool killed_ = false;
+
+  // Used to wait for the render process being killed. Android doesn't
+  // immediately kill the render process.
+  base::RunLoop run_loop_;
 };
 
 class WebUITestWebUIControllerFactory : public WebUIControllerFactory {
@@ -146,6 +157,7 @@
   NavigateToURL(shell(), test_url);
   RenderProcessKilledObserver killed_observer(shell()->web_contents());
   ASSERT_FALSE(CheckCanLoadHttp());
+  killed_observer.WaitUntilRenderProcessDied();
   ASSERT_TRUE(killed_observer.killed());
 }
 
diff --git a/content/browser/renderer_host/delegated_frame_host.cc b/content/browser/renderer_host/delegated_frame_host.cc
index a3c087c..51cd0a4 100644
--- a/content/browser/renderer_host/delegated_frame_host.cc
+++ b/content/browser/renderer_host/delegated_frame_host.cc
@@ -180,8 +180,7 @@
 }
 
 bool DelegatedFrameHost::CanCopyFromCompositingSurface() const {
-  return compositor_ &&
-         client_->DelegatedFrameHostGetLayer()->has_external_content();
+  return compositor_ && HasFallbackSurface();
 }
 
 void DelegatedFrameHost::BeginFrameSubscription(
diff --git a/content/browser/renderer_host/render_process_host_impl.cc b/content/browser/renderer_host/render_process_host_impl.cc
index 2aead998..35e8695 100644
--- a/content/browser/renderer_host/render_process_host_impl.cc
+++ b/content/browser/renderer_host/render_process_host_impl.cc
@@ -250,6 +250,10 @@
 #include "ppapi/shared_impl/ppapi_switches.h"  // nogncheck
 #endif
 
+#if BUILDFLAG(ENABLE_LIBRARY_CDMS)
+#include "content/browser/media/key_system_support_impl.h"
+#endif
+
 #if BUILDFLAG(ENABLE_WEBRTC)
 #include "content/browser/renderer_host/media/media_stream_track_metrics_host.h"
 #include "content/browser/renderer_host/p2p/socket_dispatcher_host.h"
@@ -1971,6 +1975,10 @@
                    storage_partition_impl_->GetBlobRegistry(), GetID()));
   }
 
+#if BUILDFLAG(ENABLE_LIBRARY_CDMS)
+  registry->AddInterface(base::BindRepeating(&KeySystemSupportImpl::Create));
+#endif  // BUILDFLAG(ENABLE_LIBRARY_CDMS)
+
   ServiceManagerConnection* service_manager_connection =
       BrowserContext::GetServiceManagerConnectionFor(browser_context_);
   std::unique_ptr<ConnectionFilterImpl> connection_filter(
diff --git a/content/browser/renderer_host/render_widget_host_view_aura_unittest.cc b/content/browser/renderer_host/render_widget_host_view_aura_unittest.cc
index 1c04e9f..0ec431c 100644
--- a/content/browser/renderer_host/render_widget_host_view_aura_unittest.cc
+++ b/content/browser/renderer_host/render_widget_host_view_aura_unittest.cc
@@ -221,7 +221,7 @@
     if (!should_capture_)
       return false;
     last_present_time_ = present_time;
-    *storage = media::VideoFrame::CreateFrame(media::PIXEL_FORMAT_YV12, size_,
+    *storage = media::VideoFrame::CreateFrame(media::PIXEL_FORMAT_I420, size_,
                                               gfx::Rect(size_), size_,
                                               base::TimeDelta());
     *callback = base::Bind(&FakeFrameSubscriber::CallbackMethod, callback_);
diff --git a/content/browser/renderer_host/render_widget_host_view_browsertest.cc b/content/browser/renderer_host/render_widget_host_view_browsertest.cc
index fe6e3d06..fed3084 100644
--- a/content/browser/renderer_host/render_widget_host_view_browsertest.cc
+++ b/content/browser/renderer_host/render_widget_host_view_browsertest.cc
@@ -674,7 +674,7 @@
             gfx::Rect(output_size.width() / 2 - 1, 0, 2, output_size.height()));
 
         scoped_refptr<media::VideoFrame> video_frame =
-            media::VideoFrame::CreateFrame(media::PIXEL_FORMAT_YV12,
+            media::VideoFrame::CreateFrame(media::PIXEL_FORMAT_I420,
                                            output_size, gfx::Rect(output_size),
                                            output_size, base::TimeDelta());
 
diff --git a/content/browser/renderer_host/render_widget_host_view_child_frame.cc b/content/browser/renderer_host/render_widget_host_view_child_frame.cc
index e752b4d..575f78d 100644
--- a/content/browser/renderer_host/render_widget_host_view_child_frame.cc
+++ b/content/browser/renderer_host/render_widget_host_view_child_frame.cc
@@ -903,6 +903,16 @@
     support_->SetNeedsBeginFrame(needs_begin_frames);
 }
 
+TouchSelectionControllerClientManager*
+RenderWidgetHostViewChildFrame::GetTouchSelectionControllerClientManager() {
+  auto* root_view = frame_connector_->GetRootRenderWidgetHostView();
+  if (!root_view)
+    return nullptr;
+
+  // There is only ever one manager, and it's owned by the root view.
+  return root_view->GetTouchSelectionControllerClientManager();
+}
+
 InputEventAckState RenderWidgetHostViewChildFrame::FilterInputEvent(
     const blink::WebInputEvent& input_event) {
   if (input_event.GetType() == blink::WebInputEvent::kGestureFlingStart) {
diff --git a/content/browser/renderer_host/render_widget_host_view_child_frame.h b/content/browser/renderer_host/render_widget_host_view_child_frame.h
index 6f1ed4a..bca6513e 100644
--- a/content/browser/renderer_host/render_widget_host_view_child_frame.h
+++ b/content/browser/renderer_host/render_widget_host_view_child_frame.h
@@ -153,6 +153,8 @@
       const gfx::PointF& point,
       RenderWidgetHostViewBase* target_view,
       gfx::PointF* transformed_point) override;
+  TouchSelectionControllerClientManager*
+  GetTouchSelectionControllerClientManager() override;
 
   bool IsRenderWidgetHostViewChildFrame() override;
 
diff --git a/content/browser/renderer_host/render_widget_host_view_frame_subscriber.h b/content/browser/renderer_host/render_widget_host_view_frame_subscriber.h
index 4289386..392cb7d 100644
--- a/content/browser/renderer_host/render_widget_host_view_frame_subscriber.h
+++ b/content/browser/renderer_host/render_widget_host_view_frame_subscriber.h
@@ -59,7 +59,7 @@
   // space conversion to fit into the output frame.
   //
   // Destination format is determined by |storage|, currently only
-  // media::PIXEL_FORMAT_YV12 is supported. Platform layer will perform color
+  // media::PIXEL_FORMAT_I420 is supported. Platform layer will perform color
   // space conversion if needed.
   //
   // When the frame is available |callback| will be called. It is up to the
diff --git a/content/browser/renderer_host/render_widget_targeter.cc b/content/browser/renderer_host/render_widget_targeter.cc
index b6cee9d..9252c48a 100644
--- a/content/browser/renderer_host/render_widget_targeter.cc
+++ b/content/browser/renderer_host/render_widget_targeter.cc
@@ -125,13 +125,10 @@
   if (mouse_event.GetType() == blink::WebInputEvent::kUndefined)
     return;
   request_in_flight_ = true;
-  float scale_factor = root_view->current_device_scale_factor();
   auto* target_client =
       target->GetRenderWidgetHostImpl()->input_target_client();
   target_client->FrameSinkIdAt(
-      gfx::ScaleToCeiledPoint(
-          gfx::ToCeiledPoint(mouse_event.PositionInWidget()), scale_factor,
-          scale_factor),
+      gfx::ToCeiledPoint(mouse_event.PositionInWidget()),
       base::BindOnce(&RenderWidgetTargeter::FoundFrameSinkId,
                      weak_ptr_factory_.GetWeakPtr(), root_view->GetWeakPtr(),
                      target->GetWeakPtr(),
@@ -169,7 +166,15 @@
   if (view == target.get()) {
     FoundTarget(root_view.get(), view, event, latency, target_location);
   } else {
-    QueryClient(root_view.get(), view, event, latency, target_location);
+    base::Optional<gfx::PointF> location = target_location;
+    if (target_location) {
+      gfx::PointF updated_location = *target_location;
+      if (target->TransformPointToCoordSpaceForView(updated_location, view,
+                                                    &updated_location)) {
+        location.emplace(updated_location);
+      }
+    }
+    QueryClient(root_view.get(), view, event, latency, location);
   }
 }
 
diff --git a/content/browser/service_worker/service_worker_fetch_dispatcher.cc b/content/browser/service_worker/service_worker_fetch_dispatcher.cc
index a64ec68..059ff46 100644
--- a/content/browser/service_worker/service_worker_fetch_dispatcher.cc
+++ b/content/browser/service_worker/service_worker_fetch_dispatcher.cc
@@ -463,7 +463,7 @@
     FetchCallback fetch_callback)
     : request_(std::move(request)),
       version_(std::move(version)),
-      resource_type_(request_->resource_type),
+      resource_type_(static_cast<ResourceType>(request_->resource_type)),
       net_log_(net_log),
       prepare_callback_(std::move(prepare_callback)),
       fetch_callback_(std::move(fetch_callback)),
@@ -730,7 +730,7 @@
   // for the service worker navigation preload request.
   request.resource_type = RESOURCE_TYPE_SUB_RESOURCE;
   request.priority = original_request->priority();
-  request.service_worker_mode = ServiceWorkerMode::NONE;
+  request.service_worker_mode = static_cast<int>(ServiceWorkerMode::NONE);
   request.do_not_prompt_for_login = true;
   request.render_frame_id = original_info->GetRenderFrameID();
   request.is_main_frame = original_info->IsMainFrame();
@@ -794,7 +794,8 @@
   // Set to SUB_RESOURCE because we shouldn't trigger NavigationResourceThrottle
   // for the service worker navigation preload request.
   resource_request.resource_type = RESOURCE_TYPE_SUB_RESOURCE;
-  resource_request.service_worker_mode = ServiceWorkerMode::NONE;
+  resource_request.service_worker_mode =
+      static_cast<int>(ServiceWorkerMode::NONE);
   resource_request.do_not_prompt_for_login = true;
   DCHECK(net::HttpUtil::IsValidHeaderValue(
       version_->navigation_preload_state().header));
diff --git a/content/browser/service_worker/service_worker_script_url_loader.cc b/content/browser/service_worker/service_worker_script_url_loader.cc
index 1098c45f..b405c01 100644
--- a/content/browser/service_worker/service_worker_script_url_loader.cc
+++ b/content/browser/service_worker/service_worker_script_url_loader.cc
@@ -37,7 +37,7 @@
     scoped_refptr<URLLoaderFactoryGetter> loader_factory_getter,
     const net::MutableNetworkTrafficAnnotationTag& traffic_annotation)
     : request_url_(resource_request.url),
-      resource_type_(resource_request.resource_type),
+      resource_type_(static_cast<ResourceType>(resource_request.resource_type)),
       version_(version),
       network_client_binding_(this),
       network_watcher_(FROM_HERE, mojo::SimpleWatcher::ArmingPolicy::MANUAL),
diff --git a/content/browser/service_worker/service_worker_url_loader_job.cc b/content/browser/service_worker/service_worker_url_loader_job.cc
index 34546e15..ea26b2a 100644
--- a/content/browser/service_worker/service_worker_url_loader_job.cc
+++ b/content/browser/service_worker/service_worker_url_loader_job.cc
@@ -67,14 +67,15 @@
       url_loader_factory_getter_(std::move(url_loader_factory_getter)),
       binding_(this),
       weak_factory_(this) {
-  DCHECK(
-      ServiceWorkerUtils::IsMainResourceType(resource_request.resource_type));
+  DCHECK(ServiceWorkerUtils::IsMainResourceType(
+      static_cast<ResourceType>(resource_request.resource_type)));
   DCHECK_EQ(network::mojom::FetchRequestMode::kNavigate,
             resource_request_.fetch_request_mode);
   DCHECK_EQ(network::mojom::FetchCredentialsMode::kInclude,
             resource_request_.fetch_credentials_mode);
-  DCHECK_EQ(FetchRedirectMode::MANUAL_MODE,
-            resource_request_.fetch_redirect_mode);
+  DCHECK_EQ(
+      FetchRedirectMode::MANUAL_MODE,
+      static_cast<FetchRedirectMode>(resource_request_.fetch_redirect_mode));
   response_head_.load_timing.request_start = base::TimeTicks::Now();
   response_head_.load_timing.request_start_time = base::Time::Now();
 }
diff --git a/content/browser/service_worker/service_worker_url_loader_job_unittest.cc b/content/browser/service_worker/service_worker_url_loader_job_unittest.cc
index 2c98a80..f23908e 100644
--- a/content/browser/service_worker/service_worker_url_loader_job_unittest.cc
+++ b/content/browser/service_worker/service_worker_url_loader_job_unittest.cc
@@ -285,7 +285,8 @@
       mojom::ServiceWorkerEventDispatcher::DispatchFetchEventCallback
           finish_callback) override {
     // Basic checks on DispatchFetchEvent parameters.
-    EXPECT_TRUE(ServiceWorkerUtils::IsMainResourceType(request.resource_type));
+    EXPECT_TRUE(ServiceWorkerUtils::IsMainResourceType(
+        static_cast<ResourceType>(request.resource_type)));
 
     request_body_ = request.request_body;
 
@@ -575,7 +576,8 @@
     request->fetch_request_mode = network::mojom::FetchRequestMode::kNavigate;
     request->fetch_credentials_mode =
         network::mojom::FetchCredentialsMode::kInclude;
-    request->fetch_redirect_mode = FetchRedirectMode::MANUAL_MODE;
+    request->fetch_redirect_mode =
+        static_cast<int>(FetchRedirectMode::MANUAL_MODE);
     return request;
   }
 
@@ -904,7 +906,8 @@
   request.fetch_request_mode = network::mojom::FetchRequestMode::kNavigate;
   request.fetch_credentials_mode =
       network::mojom::FetchCredentialsMode::kInclude;
-  request.fetch_redirect_mode = FetchRedirectMode::MANUAL_MODE;
+  request.fetch_redirect_mode =
+      static_cast<int>(FetchRedirectMode::MANUAL_MODE);
 
   StartLoaderCallback callback;
   auto job = std::make_unique<ServiceWorkerURLLoaderJob>(
diff --git a/content/browser/site_per_process_browsertest.cc b/content/browser/site_per_process_browsertest.cc
index 6917cbc..22a73db 100644
--- a/content/browser/site_per_process_browsertest.cc
+++ b/content/browser/site_per_process_browsertest.cc
@@ -397,6 +397,167 @@
   EXPECT_NEAR(2, main_frame_monitor.event().PositionInWidget().y, 2);
 }
 
+void OverlapSurfaceHitTestHelper(
+    Shell* shell,
+    net::test_server::EmbeddedTestServer* embedded_test_server) {
+  GURL main_url(embedded_test_server->GetURL(
+      "/frame_tree/page_with_content_overlap_positioned_frame.html"));
+  EXPECT_TRUE(NavigateToURL(shell, main_url));
+
+  // It is safe to obtain the root frame tree node here, as it doesn't change.
+  FrameTreeNode* root = static_cast<WebContentsImpl*>(shell->web_contents())
+                            ->GetFrameTree()
+                            ->root();
+  ASSERT_EQ(1U, root->child_count());
+
+  FrameTreeNode* child_node = root->child_at(0);
+  GURL site_url(embedded_test_server->GetURL("baz.com", "/title1.html"));
+  EXPECT_EQ(site_url, child_node->current_url());
+  EXPECT_NE(shell->web_contents()->GetSiteInstance(),
+            child_node->current_frame_host()->GetSiteInstance());
+
+  // Create listeners for mouse events.
+  RenderWidgetHostMouseEventMonitor main_frame_monitor(
+      root->current_frame_host()->GetRenderWidgetHost());
+  RenderWidgetHostMouseEventMonitor child_frame_monitor(
+      child_node->current_frame_host()->GetRenderWidgetHost());
+
+  RenderWidgetHostInputEventRouter* router =
+      static_cast<WebContentsImpl*>(shell->web_contents())
+          ->GetInputEventRouter();
+
+  RenderWidgetHostViewBase* rwhv_root = static_cast<RenderWidgetHostViewBase*>(
+      root->current_frame_host()->GetRenderWidgetHost()->GetView());
+  RenderWidgetHostViewBase* rwhv_child = static_cast<RenderWidgetHostViewBase*>(
+      child_node->current_frame_host()->GetRenderWidgetHost()->GetView());
+
+  WaitForChildFrameSurfaceReady(child_node->current_frame_host());
+
+  // Target input event to the button overlapping the child frame.
+  gfx::PointF button_location(5, 5);
+  button_location =
+      rwhv_child->TransformPointToRootCoordSpaceF(button_location);
+  blink::WebMouseEvent button_event(blink::WebInputEvent::kMouseDown,
+                                    blink::WebInputEvent::kNoModifiers,
+                                    blink::WebInputEvent::kTimeStampForTesting);
+  button_event.button = blink::WebPointerProperties::Button::kLeft;
+  button_event.SetPositionInWidget(button_location.x(), button_location.y());
+  button_event.click_count = 1;
+
+  main_frame_monitor.ResetEventReceived();
+  child_frame_monitor.ResetEventReceived();
+  RouteMouseEventAndWaitUntilDispatch(router, rwhv_root, rwhv_root,
+                                      &button_event);
+
+  // The main-frame should receive the event at the same location it was
+  // dispatched to.
+  EXPECT_TRUE(main_frame_monitor.EventWasReceived());
+  EXPECT_NEAR(button_location.x(),
+              main_frame_monitor.event().PositionInWidget().x, 2);
+  EXPECT_NEAR(button_location.y(),
+              main_frame_monitor.event().PositionInWidget().y, 2);
+  EXPECT_FALSE(child_frame_monitor.EventWasReceived());
+
+  // Now send an event that should go to the bottom-right edge of child.
+  gfx::PointF event_location(95, 95);
+  event_location = rwhv_child->TransformPointToRootCoordSpaceF(event_location);
+  blink::WebMouseEvent child_event(blink::WebInputEvent::kMouseDown,
+                                   blink::WebInputEvent::kNoModifiers,
+                                   blink::WebInputEvent::kTimeStampForTesting);
+  child_event.SetPositionInWidget(event_location.x(), event_location.y());
+  child_event.click_count = 1;
+  main_frame_monitor.ResetEventReceived();
+  child_frame_monitor.ResetEventReceived();
+  RouteMouseEventAndWaitUntilDispatch(router, rwhv_root, rwhv_child,
+                                      &child_event);
+  EXPECT_TRUE(child_frame_monitor.EventWasReceived());
+  // The expected result coordinates are (5, 5) from the bottom-right edge (and
+  // it's sized 100x100), but can get slightly different results due to rounding
+  // error with some page scale factors.
+  EXPECT_NEAR(95, child_frame_monitor.event().PositionInWidget().x, 2);
+  EXPECT_NEAR(95, child_frame_monitor.event().PositionInWidget().y, 2);
+  EXPECT_FALSE(main_frame_monitor.EventWasReceived());
+}
+
+// Helper function that performs a surface hittest in nested frame.
+void NestedSurfaceHitTestTestHelper(
+    Shell* shell,
+    net::test_server::EmbeddedTestServer* embedded_test_server) {
+  auto* web_contents = static_cast<WebContentsImpl*>(shell->web_contents());
+  GURL main_url(embedded_test_server->GetURL(
+      "/frame_tree/page_with_positioned_nested_frames.html"));
+  EXPECT_TRUE(NavigateToURL(shell, main_url));
+
+  // It is safe to obtain the root frame tree node here, as it doesn't change.
+  FrameTreeNode* root = web_contents->GetFrameTree()->root();
+  ASSERT_EQ(1U, root->child_count());
+
+  FrameTreeNode* parent_iframe_node = root->child_at(0);
+  GURL site_url(embedded_test_server->GetURL(
+      "a.com", "/frame_tree/page_with_positioned_frame.html"));
+  EXPECT_EQ(site_url, parent_iframe_node->current_url());
+  EXPECT_NE(shell->web_contents()->GetSiteInstance(),
+            parent_iframe_node->current_frame_host()->GetSiteInstance());
+
+  FrameTreeNode* nested_iframe_node = parent_iframe_node->child_at(0);
+  GURL nested_site_url(embedded_test_server->GetURL("baz.com", "/title1.html"));
+  EXPECT_EQ(nested_site_url, nested_iframe_node->current_url());
+  EXPECT_NE(shell->web_contents()->GetSiteInstance(),
+            nested_iframe_node->current_frame_host()->GetSiteInstance());
+  EXPECT_NE(parent_iframe_node->current_frame_host()->GetSiteInstance(),
+            nested_iframe_node->current_frame_host()->GetSiteInstance());
+
+  // Create listeners for mouse events.
+  RenderWidgetHostMouseEventMonitor main_frame_monitor(
+      root->current_frame_host()->GetRenderWidgetHost());
+  RenderWidgetHostMouseEventMonitor nested_frame_monitor(
+      nested_iframe_node->current_frame_host()->GetRenderWidgetHost());
+
+  RenderWidgetHostInputEventRouter* router =
+      web_contents->GetInputEventRouter();
+
+  RenderWidgetHostViewBase* root_view = static_cast<RenderWidgetHostViewBase*>(
+      root->current_frame_host()->GetRenderWidgetHost()->GetView());
+  RenderWidgetHostViewBase* rwhv_nested =
+      static_cast<RenderWidgetHostViewBase*>(
+          nested_iframe_node->current_frame_host()
+              ->GetRenderWidgetHost()
+              ->GetView());
+
+  WaitForChildFrameSurfaceReady(nested_iframe_node->current_frame_host());
+
+  float scale_factor = GetPageScaleFactor(shell);
+
+  // Get the view bounds of the nested iframe, which should account for the
+  // relative offset of its direct parent within the root frame, for use in
+  // targeting the input event.
+  gfx::Rect bounds = rwhv_nested->GetViewBounds();
+
+  // Target input event to nested frame.
+  blink::WebMouseEvent nested_event(blink::WebInputEvent::kMouseDown,
+                                    blink::WebInputEvent::kNoModifiers,
+                                    blink::WebInputEvent::kTimeStampForTesting);
+  nested_event.button = blink::WebPointerProperties::Button::kLeft;
+  nested_event.SetPositionInWidget(
+      gfx::ToCeiledInt((bounds.x() - root_view->GetViewBounds().x() + 10) *
+                       scale_factor),
+      gfx::ToCeiledInt((bounds.y() - root_view->GetViewBounds().y() + 10) *
+                       scale_factor));
+  nested_event.click_count = 1;
+  nested_frame_monitor.ResetEventReceived();
+  main_frame_monitor.ResetEventReceived();
+  auto* rwhv_child = nested_iframe_node->current_frame_host()
+                         ->GetRenderWidgetHost()
+                         ->GetView();
+  RouteMouseEventAndWaitUntilDispatch(router, root_view, rwhv_child,
+                                      &nested_event);
+
+  EXPECT_TRUE(nested_frame_monitor.EventWasReceived());
+  EXPECT_NEAR(10, nested_frame_monitor.event().PositionInWidget().x, 2);
+  EXPECT_NEAR(10, nested_frame_monitor.event().PositionInWidget().y, 2);
+  EXPECT_FALSE(main_frame_monitor.EventWasReceived());
+}
+
 class RedirectNotificationObserver : public NotificationObserver {
  public:
   // Register to listen for notifications of the given type from either a
@@ -2203,79 +2364,21 @@
 // Test that mouse events are being routed to the correct RenderWidgetHostView
 // when there are nested out-of-process iframes.
 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, NestedSurfaceHitTestTest) {
-  GURL main_url(embedded_test_server()->GetURL(
-      "/frame_tree/page_with_positioned_nested_frames.html"));
-  EXPECT_TRUE(NavigateToURL(shell(), main_url));
+  NestedSurfaceHitTestTestHelper(shell(), embedded_test_server());
+}
 
-  // It is safe to obtain the root frame tree node here, as it doesn't change.
-  FrameTreeNode* root = web_contents()->GetFrameTree()->root();
-  ASSERT_EQ(1U, root->child_count());
+IN_PROC_BROWSER_TEST_F(SitePerProcessHighDPIBrowserTest,
+                       NestedSurfaceHitTestTest) {
+  NestedSurfaceHitTestTestHelper(shell(), embedded_test_server());
+}
 
-  FrameTreeNode* parent_iframe_node = root->child_at(0);
-  GURL site_url(embedded_test_server()->GetURL(
-      "a.com", "/frame_tree/page_with_positioned_frame.html"));
-  EXPECT_EQ(site_url, parent_iframe_node->current_url());
-  EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
-            parent_iframe_node->current_frame_host()->GetSiteInstance());
+IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, OverlapSurfaceHitTestTest) {
+  OverlapSurfaceHitTestHelper(shell(), embedded_test_server());
+}
 
-  FrameTreeNode* nested_iframe_node = parent_iframe_node->child_at(0);
-  GURL nested_site_url(
-      embedded_test_server()->GetURL("baz.com", "/title1.html"));
-  EXPECT_EQ(nested_site_url, nested_iframe_node->current_url());
-  EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
-            nested_iframe_node->current_frame_host()->GetSiteInstance());
-  EXPECT_NE(parent_iframe_node->current_frame_host()->GetSiteInstance(),
-            nested_iframe_node->current_frame_host()->GetSiteInstance());
-
-  // Create listeners for mouse events.
-  RenderWidgetHostMouseEventMonitor main_frame_monitor(
-      root->current_frame_host()->GetRenderWidgetHost());
-  RenderWidgetHostMouseEventMonitor nested_frame_monitor(
-      nested_iframe_node->current_frame_host()->GetRenderWidgetHost());
-
-  RenderWidgetHostInputEventRouter* router =
-      web_contents()->GetInputEventRouter();
-
-  RenderWidgetHostViewBase* root_view = static_cast<RenderWidgetHostViewBase*>(
-      root->current_frame_host()->GetRenderWidgetHost()->GetView());
-  RenderWidgetHostViewBase* rwhv_nested =
-      static_cast<RenderWidgetHostViewBase*>(
-          nested_iframe_node->current_frame_host()
-              ->GetRenderWidgetHost()
-              ->GetView());
-
-  WaitForChildFrameSurfaceReady(nested_iframe_node->current_frame_host());
-
-  float scale_factor = GetPageScaleFactor(shell());
-
-  // Get the view bounds of the nested iframe, which should account for the
-  // relative offset of its direct parent within the root frame, for use in
-  // targeting the input event.
-  gfx::Rect bounds = rwhv_nested->GetViewBounds();
-
-  // Target input event to nested frame.
-  blink::WebMouseEvent nested_event(blink::WebInputEvent::kMouseDown,
-                                    blink::WebInputEvent::kNoModifiers,
-                                    blink::WebInputEvent::kTimeStampForTesting);
-  nested_event.button = blink::WebPointerProperties::Button::kLeft;
-  nested_event.SetPositionInWidget(
-      gfx::ToCeiledInt((bounds.x() - root_view->GetViewBounds().x() + 10) *
-                       scale_factor),
-      gfx::ToCeiledInt((bounds.y() - root_view->GetViewBounds().y() + 10) *
-                       scale_factor));
-  nested_event.click_count = 1;
-  nested_frame_monitor.ResetEventReceived();
-  main_frame_monitor.ResetEventReceived();
-  auto* rwhv_child = nested_iframe_node->current_frame_host()
-                         ->GetRenderWidgetHost()
-                         ->GetView();
-  RouteMouseEventAndWaitUntilDispatch(router, root_view, rwhv_child,
-                                      &nested_event);
-
-  EXPECT_TRUE(nested_frame_monitor.EventWasReceived());
-  EXPECT_NEAR(10, nested_frame_monitor.event().PositionInWidget().x, 2);
-  EXPECT_NEAR(10, nested_frame_monitor.event().PositionInWidget().y, 2);
-  EXPECT_FALSE(main_frame_monitor.EventWasReceived());
+IN_PROC_BROWSER_TEST_F(SitePerProcessHighDPIBrowserTest,
+                       OverlapSurfaceHitTestTest) {
+  OverlapSurfaceHitTestHelper(shell(), embedded_test_server());
 }
 
 // This test tests that browser process hittesting ignores frames with
diff --git a/content/browser/web_contents/web_contents_view_android.cc b/content/browser/web_contents/web_contents_view_android.cc
index bb6d1f6..2ebc122 100644
--- a/content/browser/web_contents/web_contents_view_android.cc
+++ b/content/browser/web_contents/web_contents_view_android.cc
@@ -107,7 +107,8 @@
       content_view_core_(NULL),
       delegate_(delegate),
       view_(this, ui::ViewAndroid::LayoutType::NORMAL),
-      synchronous_compositor_client_(nullptr) {}
+      synchronous_compositor_client_(nullptr),
+      gesture_listener_manager_(nullptr) {}
 
 WebContentsViewAndroid::~WebContentsViewAndroid() {
   if (view_.GetLayer())
@@ -176,6 +177,12 @@
       web_contents_->GetRenderWidgetHostView());
 }
 
+void WebContentsViewAndroid::SetGestureListenerManager(
+    std::unique_ptr<GestureListenerManager> manager) {
+  DCHECK(!gesture_listener_manager_);
+  gesture_listener_manager_ = std::move(manager);
+}
+
 gfx::NativeWindow WebContentsViewAndroid::GetTopLevelNativeWindow() const {
   return content_view_core_ ? content_view_core_->GetWindowAndroid() : nullptr;
 }
@@ -519,10 +526,9 @@
 void WebContentsViewAndroid::GestureEventAck(
     const blink::WebGestureEvent& event,
     InputEventAckState ack_result) {
-  auto* manager = GestureListenerManager::FromWebContents(web_contents_);
-  if (!manager)
+  if (!gesture_listener_manager_)
     return;
-  manager->GestureEventAck(event, ack_result);
+  gesture_listener_manager_->GestureEventAck(event, ack_result);
 }
 
 bool WebContentsViewAndroid::OnTouchEvent(const ui::MotionEventAndroid& event) {
diff --git a/content/browser/web_contents/web_contents_view_android.h b/content/browser/web_contents/web_contents_view_android.h
index 047d454e..b79c6e9 100644
--- a/content/browser/web_contents/web_contents_view_android.h
+++ b/content/browser/web_contents/web_contents_view_android.h
@@ -8,6 +8,7 @@
 #include <memory>
 
 #include "base/macros.h"
+#include "content/browser/android/gesture_listener_manager.h"
 #include "content/browser/renderer_host/render_view_host_delegate_view.h"
 #include "content/browser/web_contents/web_contents_view.h"
 #include "content/public/browser/web_contents_view_delegate.h"
@@ -55,6 +56,9 @@
 
   RenderWidgetHostViewAndroid* GetRenderWidgetHostViewAndroid();
 
+  void SetGestureListenerManager(
+      std::unique_ptr<GestureListenerManager> manager);
+
   // WebContentsView implementation --------------------------------------------
   gfx::NativeView GetNativeView() const override;
   gfx::NativeView GetContentNativeView() const override;
@@ -148,6 +152,9 @@
   // Interface used to get notified of events from the synchronous compositor.
   SynchronousCompositorClient* synchronous_compositor_client_;
 
+  // The manager for gesture event listeners.
+  std::unique_ptr<GestureListenerManager> gesture_listener_manager_;
+
   gfx::PointF drag_location_;
   gfx::PointF drag_screen_location_;
 
diff --git a/content/browser/zygote_host/zygote_communication_linux.cc b/content/browser/zygote_host/zygote_communication_linux.cc
index 07b39e3..034574c3 100644
--- a/content/browser/zygote_host/zygote_communication_linux.cc
+++ b/content/browser/zygote_host/zygote_communication_linux.cc
@@ -18,8 +18,6 @@
 #include "base/posix/unix_domain_socket.h"
 #include "content/browser/zygote_host/zygote_host_impl_linux.h"
 #include "content/common/zygote_commands_linux.h"
-#include "content/public/browser/content_browser_client.h"
-#include "content/public/common/content_client.h"
 #include "content/public/common/content_switches.h"
 #include "content/public/common/result_codes.h"
 #include "media/base/media_switches.h"
@@ -240,7 +238,8 @@
   DCHECK_EQ(1U, num_erased);
 }
 
-void ZygoteCommunication::Init() {
+void ZygoteCommunication::Init(
+    base::OnceCallback<void(base::CommandLine*)> add_switches_callback) {
   CHECK(!init_);
 
   base::FilePath chrome_path;
@@ -277,7 +276,7 @@
   cmd_line.CopySwitchesFrom(browser_command_line, kForwardSwitches,
                             arraysize(kForwardSwitches));
 
-  GetContentClient()->browser()->AppendExtraCommandLineSwitches(&cmd_line, -1);
+  std::move(add_switches_callback).Run(&cmd_line);
 
   pid_ = ZygoteHostImpl::GetInstance()->LaunchZygote(&cmd_line, &control_fd_);
 
diff --git a/content/browser/zygote_host/zygote_communication_linux.h b/content/browser/zygote_host/zygote_communication_linux.h
index 3add2ea..9b0ad91 100644
--- a/content/browser/zygote_host/zygote_communication_linux.h
+++ b/content/browser/zygote_host/zygote_communication_linux.h
@@ -12,6 +12,7 @@
 
 #include <sys/types.h>
 
+#include "base/callback.h"
 #include "base/files/scoped_file.h"
 #include "base/process/kill.h"
 #include "base/process/process_handle.h"
@@ -33,7 +34,7 @@
   ZygoteCommunication();
   ~ZygoteCommunication();
 
-  void Init();
+  void Init(base::OnceCallback<void(base::CommandLine*)> add_switches_callback);
 
   // Tries to start a process of type indicated by process_type.
   // Returns its pid on success, otherwise base::kNullProcessHandle;
diff --git a/content/browser/zygote_host/zygote_handle_linux.cc b/content/browser/zygote_host/zygote_handle_linux.cc
index 6178011..865d5a9 100644
--- a/content/browser/zygote_host/zygote_handle_linux.cc
+++ b/content/browser/zygote_host/zygote_handle_linux.cc
@@ -14,10 +14,11 @@
 
 }  // namespace
 
-ZygoteHandle CreateGenericZygote() {
+ZygoteHandle CreateGenericZygote(
+    base::OnceCallback<void(base::CommandLine*)> add_switches_callback) {
   CHECK(!g_generic_zygote);
   g_generic_zygote = new ZygoteCommunication();
-  g_generic_zygote->Init();
+  g_generic_zygote->Init(std::move(add_switches_callback));
   return g_generic_zygote;
 }
 
diff --git a/content/common/cross_site_document_classifier.cc b/content/common/cross_site_document_classifier.cc
index 6cf2ebe0..58af797 100644
--- a/content/common/cross_site_document_classifier.cc
+++ b/content/common/cross_site_document_classifier.cc
@@ -12,6 +12,7 @@
 #include "base/logging.h"
 #include "base/macros.h"
 #include "base/metrics/histogram_macros.h"
+#include "base/strings/string_piece.h"
 #include "base/strings/string_util.h"
 #include "content/public/common/content_switches.h"
 #include "content/public/common/resource_response_info.h"
@@ -27,13 +28,17 @@
 // MIME types
 const char kTextHtml[] = "text/html";
 const char kTextXml[] = "text/xml";
-const char kAppRssXml[] = "application/rss+xml";
 const char kAppXml[] = "application/xml";
 const char kAppJson[] = "application/json";
+const char kImageSvg[] = "image/svg+xml";
 const char kTextJson[] = "text/json";
 const char kTextXjson[] = "text/x-json";
 const char kTextPlain[] = "text/plain";
 
+// MIME type suffixes
+const char kJsonSuffix[] = "+json";
+const char kXmlSuffix[] = "+xml";
+
 void AdvancePastWhitespace(StringPiece* data) {
   size_t offset = data->find_first_not_of(" \t\r\n");
   if (offset == base::StringPiece::npos) {
@@ -73,27 +78,68 @@
   return CrossSiteDocumentClassifier::kNo;
 }
 
+// Returns true if |mime_type == prefix| or if |mime_type| starts with
+// |prefix + '+'|.  Returns false otherwise.
+//
+// For example:
+// - MatchesMimeTypePrefix("application/json", "application/json") -> true
+// - MatchesMimeTypePrefix("application/json+foo", "application/json") -> true
+// - MatchesMimeTypePrefix("application/jsonp", "application/json") -> false
+// - MatchesMimeTypePrefix("application/foo", "application/json") -> false
+bool MatchesMimeTypePrefix(base::StringPiece mime_type,
+                           base::StringPiece prefix) {
+  constexpr auto kCaseInsensitive = base::CompareCase::INSENSITIVE_ASCII;
+  if (!base::StartsWith(mime_type, prefix, kCaseInsensitive))
+    return false;
+  DCHECK_GE(mime_type.length(), prefix.length());
+
+  if (mime_type.length() == prefix.length()) {
+    // Given StartsWith results above, the above condition is our O(1) check if
+    // |base::LowerCaseEqualsASCII(mime_type, prefix)|.
+    DCHECK(base::LowerCaseEqualsASCII(mime_type, prefix));
+    return true;
+  }
+
+  if (mime_type[prefix.length()] == '+') {
+    // Given StartsWith results above, the above condition is our O(1) check if
+    // |base::StartsWith(mime_type, prefix + '+', kCaseInsensitive)|.
+    DCHECK(base::StartsWith(mime_type, prefix.as_string() + '+',
+                            kCaseInsensitive));
+    return true;
+  }
+
+  return false;
+}
+
 }  // namespace
 
 CrossSiteDocumentMimeType CrossSiteDocumentClassifier::GetCanonicalMimeType(
-    const std::string& mime_type) {
-  if (base::LowerCaseEqualsASCII(mime_type, kTextHtml)) {
+    base::StringPiece mime_type) {
+  // Checking for image/svg+xml early ensures that it won't get classified as
+  // CROSS_SITE_DOCUMENT_MIME_TYPE_XML by the presence of the "+xml" suffix.
+  if (base::LowerCaseEqualsASCII(mime_type, kImageSvg))
+    return CROSS_SITE_DOCUMENT_MIME_TYPE_OTHERS;
+
+  if (base::LowerCaseEqualsASCII(mime_type, kTextHtml))
     return CROSS_SITE_DOCUMENT_MIME_TYPE_HTML;
-  }
 
-  if (base::LowerCaseEqualsASCII(mime_type, kTextPlain)) {
+  if (base::LowerCaseEqualsASCII(mime_type, kTextPlain))
     return CROSS_SITE_DOCUMENT_MIME_TYPE_PLAIN;
-  }
 
-  if (base::LowerCaseEqualsASCII(mime_type, kAppJson) ||
-      base::LowerCaseEqualsASCII(mime_type, kTextJson) ||
-      base::LowerCaseEqualsASCII(mime_type, kTextXjson)) {
+  // StartsWith rather than LowerCaseEqualsASCII is used to account both for
+  // mime types similar to 1) application/json and to 2)
+  // application/json+protobuf.
+  constexpr auto kCaseInsensitive = base::CompareCase::INSENSITIVE_ASCII;
+  if (MatchesMimeTypePrefix(mime_type, kAppJson) ||
+      MatchesMimeTypePrefix(mime_type, kTextJson) ||
+      MatchesMimeTypePrefix(mime_type, kTextXjson) ||
+      base::EndsWith(mime_type, kJsonSuffix, kCaseInsensitive)) {
     return CROSS_SITE_DOCUMENT_MIME_TYPE_JSON;
   }
 
-  if (base::LowerCaseEqualsASCII(mime_type, kTextXml) ||
-      base::LowerCaseEqualsASCII(mime_type, kAppRssXml) ||
-      base::LowerCaseEqualsASCII(mime_type, kAppXml)) {
+  if (MatchesMimeTypePrefix(mime_type, kAppXml) ||
+      MatchesMimeTypePrefix(mime_type, kTextXml) ||
+      base::EndsWith(mime_type, kXmlSuffix, kCaseInsensitive)) {
     return CROSS_SITE_DOCUMENT_MIME_TYPE_XML;
   }
 
diff --git a/content/common/cross_site_document_classifier.h b/content/common/cross_site_document_classifier.h
index c8e95e1..de009cb 100644
--- a/content/common/cross_site_document_classifier.h
+++ b/content/common/cross_site_document_classifier.h
@@ -5,8 +5,10 @@
 #ifndef CONTENT_COMMON_CROSS_SITE_DOCUMENT_CLASSIFIER_H_
 #define CONTENT_COMMON_CROSS_SITE_DOCUMENT_CLASSIFIER_H_
 
+#include <string>
+
 #include "base/macros.h"
-#include "base/strings/string_piece.h"
+#include "base/strings/string_piece_forward.h"
 #include "content/common/content_export.h"
 #include "url/gurl.h"
 #include "url/origin.h"
@@ -47,7 +49,7 @@
   // response. For example, this returns the same value for all text/xml mime
   // type families such as application/xml, application/rss+xml.
   static CrossSiteDocumentMimeType GetCanonicalMimeType(
-      const std::string& mime_type);
+      base::StringPiece mime_type);
 
   // Returns whether this scheme is a target of cross-site document
   // policy(XSDP). This returns true only for http://* and https://* urls.
diff --git a/content/common/cross_site_document_classifier_unittest.cc b/content/common/cross_site_document_classifier_unittest.cc
index b86a3308..5974158b 100644
--- a/content/common/cross_site_document_classifier_unittest.cc
+++ b/content/common/cross_site_document_classifier_unittest.cc
@@ -2,6 +2,9 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include <utility>
+#include <vector>
+
 #include "base/strings/string_piece.h"
 #include "content/common/cross_site_document_classifier.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -187,4 +190,55 @@
       << "A colon character inside a string does not trigger a match";
 }
 
+TEST(CrossSiteDocumentClassifierTest, GetCanonicalMimeType) {
+  std::vector<std::pair<const char*, CrossSiteDocumentMimeType>> tests = {
+      // Basic tests for things in the original implementation:
+      {"text/html", CROSS_SITE_DOCUMENT_MIME_TYPE_HTML},
+      {"text/xml", CROSS_SITE_DOCUMENT_MIME_TYPE_XML},
+      {"application/rss+xml", CROSS_SITE_DOCUMENT_MIME_TYPE_XML},
+      {"application/xml", CROSS_SITE_DOCUMENT_MIME_TYPE_XML},
+      {"application/json", CROSS_SITE_DOCUMENT_MIME_TYPE_JSON},
+      {"text/json", CROSS_SITE_DOCUMENT_MIME_TYPE_JSON},
+      {"text/x-json", CROSS_SITE_DOCUMENT_MIME_TYPE_JSON},
+      {"text/plain", CROSS_SITE_DOCUMENT_MIME_TYPE_PLAIN},
+
+      // Other mime types:
+      {"application/foobar", CROSS_SITE_DOCUMENT_MIME_TYPE_OTHERS},
+
+      // Regression tests for https://crbug.com/799155 (prefix/suffix matching):
+      {"application/json+protobuf", CROSS_SITE_DOCUMENT_MIME_TYPE_JSON},
+      {"text/json+protobuf", CROSS_SITE_DOCUMENT_MIME_TYPE_JSON},
+      {"application/activity+json", CROSS_SITE_DOCUMENT_MIME_TYPE_JSON},
+      {"text/foobar+xml", CROSS_SITE_DOCUMENT_MIME_TYPE_XML},
+      // No match without a '+' character:
+      {"application/jsonfoobar", CROSS_SITE_DOCUMENT_MIME_TYPE_OTHERS},
+      {"application/foobarjson", CROSS_SITE_DOCUMENT_MIME_TYPE_OTHERS},
+      {"application/xmlfoobar", CROSS_SITE_DOCUMENT_MIME_TYPE_OTHERS},
+      {"application/foobarxml", CROSS_SITE_DOCUMENT_MIME_TYPE_OTHERS},
+
+      // Case-insensitive comparison:
+      {"APPLICATION/JSON", CROSS_SITE_DOCUMENT_MIME_TYPE_JSON},
+      {"APPLICATION/JSON+PROTOBUF", CROSS_SITE_DOCUMENT_MIME_TYPE_JSON},
+      {"APPLICATION/ACTIVITY+JSON", CROSS_SITE_DOCUMENT_MIME_TYPE_JSON},
+
+      // Images are allowed cross-site, and SVG is an image, so we should
+      // classify SVG as "other" instead of "xml" (even though it technically is
+      // an xml document).
+      {"image/svg+xml", CROSS_SITE_DOCUMENT_MIME_TYPE_OTHERS},
+
+      // Javascript should not be blocked.
+      {"application/javascript", CROSS_SITE_DOCUMENT_MIME_TYPE_OTHERS},
+      {"application/jsonp", CROSS_SITE_DOCUMENT_MIME_TYPE_OTHERS},
+  };
+
+  for (const auto& test : tests) {
+    const char* input = test.first;  // e.g. "text/html"
+    CrossSiteDocumentMimeType expected = test.second;
+    CrossSiteDocumentMimeType actual =
+        CrossSiteDocumentClassifier::GetCanonicalMimeType(input);
+    EXPECT_EQ(expected, actual)
+        << "when testing with the following input: " << input;
+  }
+}
+
 }  // namespace content
diff --git a/content/common/service_worker/service_worker_loader_helpers.cc b/content/common/service_worker/service_worker_loader_helpers.cc
index 7ed94070..b81d306 100644
--- a/content/common/service_worker/service_worker_loader_helpers.cc
+++ b/content/common/service_worker/service_worker_loader_helpers.cc
@@ -14,6 +14,7 @@
 #include "content/public/common/resource_response.h"
 #include "mojo/public/cpp/bindings/strong_binding.h"
 #include "net/http/http_util.h"
+#include "ui/base/page_transition_types.h"
 
 namespace content {
 namespace {
@@ -44,9 +45,10 @@
 ServiceWorkerLoaderHelpers::CreateFetchRequest(const ResourceRequest& request) {
   auto new_request = std::make_unique<ServiceWorkerFetchRequest>();
   new_request->mode = request.fetch_request_mode;
-  new_request->is_main_resource_load =
-      ServiceWorkerUtils::IsMainResourceType(request.resource_type);
-  new_request->request_context_type = request.fetch_request_context_type;
+  new_request->is_main_resource_load = ServiceWorkerUtils::IsMainResourceType(
+      static_cast<ResourceType>(request.resource_type));
+  new_request->request_context_type =
+      static_cast<RequestContextType>(request.fetch_request_context_type);
   new_request->frame_type = request.fetch_frame_type;
   new_request->url = request.url;
   new_request->method = request.method;
@@ -58,10 +60,12 @@
   new_request->credentials_mode = request.fetch_credentials_mode;
   new_request->cache_mode =
       ServiceWorkerFetchRequest::GetCacheModeFromLoadFlags(request.load_flags);
-  new_request->redirect_mode = request.fetch_redirect_mode;
+  new_request->redirect_mode =
+      static_cast<FetchRedirectMode>(request.fetch_redirect_mode);
   new_request->keepalive = request.keepalive;
   new_request->is_reload = ui::PageTransitionCoreTypeIs(
-      request.transition_type, ui::PAGE_TRANSITION_RELOAD);
+      static_cast<ui::PageTransition>(request.transition_type),
+      ui::PAGE_TRANSITION_RELOAD);
   new_request->referrer = Referrer(
       GURL(request.referrer), Referrer::NetReferrerPolicyToBlinkReferrerPolicy(
                                   request.referrer_policy));
diff --git a/content/network/DEPS b/content/network/DEPS
index d668237c..da779df 100644
--- a/content/network/DEPS
+++ b/content/network/DEPS
@@ -20,6 +20,7 @@
   "+content/public/common/resource_request.h",
   "+content/public/common/resource_request_body.h",
   "+content/public/common/resource_response.h",
+  "+content/public/common/resource_type.h",
   "+content/public/common/url_constants.h",
   "+content/public/common/url_loader.mojom.h",
   "+content/public/common/url_loader_factory.mojom.h",
diff --git a/content/network/url_loader.cc b/content/network/url_loader.cc
index a23ff97..c3c97a6 100644
--- a/content/network/url_loader.cc
+++ b/content/network/url_loader.cc
@@ -201,7 +201,7 @@
                      uint32_t process_id)
     : context_(context),
       options_(options),
-      resource_type_(request.resource_type),
+      resource_type_(static_cast<ResourceType>(request.resource_type)),
       is_load_timing_enabled_(request.enable_load_timing),
       process_id_(process_id),
       render_frame_id_(request.render_frame_id),
@@ -252,7 +252,7 @@
 
   // TODO(qinmin): network service shouldn't know about resource type, need
   // to introduce another field to set this.
-  if (request.resource_type == RESOURCE_TYPE_MAIN_FRAME) {
+  if (resource_type_ == RESOURCE_TYPE_MAIN_FRAME) {
     url_request_->set_first_party_url_policy(
         net::URLRequest::UPDATE_FIRST_PARTY_URL_ON_REDIRECT);
   }
@@ -266,7 +266,7 @@
         base::Bind(&URLLoader::SetRawResponseHeaders, base::Unretained(this)));
   }
 
-  AttachAcceptHeader(request.resource_type, url_request_.get());
+  AttachAcceptHeader(resource_type_, url_request_.get());
 
   url_request_->Start();
 }
diff --git a/content/network/url_loader.h b/content/network/url_loader.h
index 992d714e..6694ecb3 100644
--- a/content/network/url_loader.h
+++ b/content/network/url_loader.h
@@ -12,6 +12,7 @@
 #include "base/memory/weak_ptr.h"
 #include "content/common/content_export.h"
 #include "content/network/upload_progress_tracker.h"
+#include "content/public/common/resource_type.h"
 #include "content/public/common/url_loader.mojom.h"
 #include "mojo/public/cpp/bindings/binding.h"
 #include "mojo/public/cpp/system/data_pipe.h"
diff --git a/content/network/url_loader_unittest.cc b/content/network/url_loader_unittest.cc
index f5b31049a..307f4050 100644
--- a/content/network/url_loader_unittest.cc
+++ b/content/network/url_loader_unittest.cc
@@ -50,6 +50,7 @@
 #include "net/url_request/url_request_test_job.h"
 #include "services/network/public/interfaces/data_pipe_getter.mojom.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "ui/base/page_transition_types.h"
 #include "url/gurl.h"
 
 namespace content {
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/ScreenOrientationListenerTest.java b/content/public/android/javatests/src/org/chromium/content/browser/ScreenOrientationListenerTest.java
index cd580610..49c90b3 100644
--- a/content/public/android/javatests/src/org/chromium/content/browser/ScreenOrientationListenerTest.java
+++ b/content/public/android/javatests/src/org/chromium/content/browser/ScreenOrientationListenerTest.java
@@ -5,6 +5,7 @@
 package org.chromium.content.browser;
 
 import android.content.pm.ActivityInfo;
+import android.support.test.filters.MediumTest;
 import android.view.Surface;
 
 import org.junit.After;
@@ -17,7 +18,7 @@
 import org.chromium.base.ThreadUtils;
 import org.chromium.base.test.BaseJUnit4ClassRunner;
 import org.chromium.base.test.util.CallbackHelper;
-import org.chromium.base.test.util.DisabledTest;
+import org.chromium.base.test.util.Feature;
 import org.chromium.content_public.common.ScreenOrientationValues;
 import org.chromium.content_shell_apk.ContentShellActivityTestRule;
 import org.chromium.ui.display.DisplayAndroid;
@@ -171,10 +172,9 @@
         return mCallbackHelper.getLastRotation();
     }
 
-    // @MediumTest
-    // @Feature({"ScreenOrientation"})
     @Test
-    @DisabledTest(message = "https://crbug.com/797175")
+    @MediumTest
+    @Feature({"ScreenOrientation"})
     public void testOrientationChanges() throws Exception {
         int rotation = lockOrientationAndWait(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
         Assert.assertEquals(
@@ -252,10 +252,9 @@
         return mCallbackHelper.getLastRotation();
     }
 
-    // @MediumTest
-    // @Feature({"ScreenOrientation"})
     @Test
-    @DisabledTest(message = "https://crbug.com/797175")
+    @MediumTest
+    @Feature({"ScreenOrientation"})
     public void testBasicValues() throws Exception {
         int rotation = lockOrientationValueAndWait(ScreenOrientationValues.LANDSCAPE_PRIMARY);
         Assert.assertEquals(
diff --git a/content/public/app/mojo/content_browser_manifest.json b/content/public/app/mojo/content_browser_manifest.json
index 09aa310..af7376e 100644
--- a/content/public/app/mojo/content_browser_manifest.json
+++ b/content/public/app/mojo/content_browser_manifest.json
@@ -53,6 +53,7 @@
           "device::mojom::GamepadHapticsManager",
           "device::mojom::GamepadMonitor",
           "discardable_memory::mojom::DiscardableSharedMemoryManager",
+          "media::mojom::KeySystemSupport",
           "media::mojom::VideoDecodePerfHistory",
           "memory_coordinator::mojom::MemoryCoordinatorHandle",
           "metrics::mojom::SingleSampleMetricsProvider",
diff --git a/content/public/browser/zygote_handle_linux.h b/content/public/browser/zygote_handle_linux.h
index 6337322..5205bd4 100644
--- a/content/public/browser/zygote_handle_linux.h
+++ b/content/public/browser/zygote_handle_linux.h
@@ -5,14 +5,19 @@
 #ifndef CONTENT_PUBLIC_BROWSER_ZYGOTE_HANDLE_LINUX_H_
 #define CONTENT_PUBLIC_BROWSER_ZYGOTE_HANDLE_LINUX_H_
 
+#include "base/callback.h"
+#include "base/command_line.h"
 #include "content/common/content_export.h"
 #include "content/public/common/zygote_handle.h"
 
 namespace content {
 
 // Allocates and initializes the global generic zygote process, and returns the
-// ZygoteHandle used to communicate with it.
-CONTENT_EXPORT ZygoteHandle CreateGenericZygote();
+// ZygoteHandle used to communicate with it. |add_switches_callback| allows
+// adding additional command line switches once the zygote process command line
+// has been composed by this function.
+CONTENT_EXPORT ZygoteHandle CreateGenericZygote(
+    base::OnceCallback<void(base::CommandLine*)> add_switches_callback);
 
 // Returns a handle to a global generic zygote object. This function allows the
 // browser to launch and use a single zygote process until the performance
diff --git a/content/public/common/content_features.cc b/content/public/common/content_features.cc
index 9075bd85..6ffa93b4 100644
--- a/content/public/common/content_features.cc
+++ b/content/public/common/content_features.cc
@@ -112,10 +112,6 @@
 const base::Feature kFeaturePolicy{"FeaturePolicy",
                                    base::FEATURE_ENABLED_BY_DEFAULT};
 
-// Enables Fetch API keepalive timeout setting.
-const base::Feature kFetchKeepaliveTimeoutSetting{
-    "FetchKeepaliveTimeoutSetting", base::FEATURE_ENABLED_BY_DEFAULT};
-
 // Enables a blink::FontCache optimization that reuses a font to serve different
 // size of font.
 const base::Feature kFontCacheScaling{"FontCacheScaling",
diff --git a/content/public/common/content_features.h b/content/public/common/content_features.h
index 1efcd0c..209d257 100644
--- a/content/public/common/content_features.h
+++ b/content/public/common/content_features.h
@@ -36,7 +36,6 @@
 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;
 CONTENT_EXPORT extern const base::Feature kFontCacheScaling;
 CONTENT_EXPORT extern const base::Feature
     kFramebustingNeedsSameOriginOrUserGesture;
diff --git a/content/public/common/resource_request.h b/content/public/common/resource_request.h
index 00d26f8b..9cf6bc2 100644
--- a/content/public/common/resource_request.h
+++ b/content/public/common/resource_request.h
@@ -11,20 +11,13 @@
 #include "base/memory/ref_counted.h"
 #include "base/optional.h"
 #include "content/common/content_export.h"
-#include "content/public/common/child_process_host.h"
-#include "content/public/common/previews_state.h"
-#include "content/public/common/request_context_type.h"
 #include "content/public/common/resource_request_body.h"
-#include "content/public/common/resource_type.h"
-#include "content/public/common/service_worker_modes.h"
 #include "net/base/request_priority.h"
 #include "net/http/http_request_headers.h"
 #include "net/url_request/url_request.h"
+#include "services/network/public/interfaces/cors.mojom.h"
 #include "services/network/public/interfaces/fetch_api.mojom.h"
 #include "services/network/public/interfaces/request_context_frame_type.mojom.h"
-#include "third_party/WebKit/common/page/page_visibility_state.mojom.h"
-#include "third_party/WebKit/public/platform/WebReferrerPolicy.h"
-#include "ui/base/page_transition_types.h"
 #include "url/gurl.h"
 #include "url/origin.h"
 
@@ -72,13 +65,17 @@
   // If this request originated from a pepper plugin running in a child
   // process, this identifies which process it came from. Otherwise, it
   // is zero.
-  int plugin_child_id = ChildProcessHost::kInvalidUniqueID;
+  // -1 to match ChildProcessHost::kInvalidUniqueID
+  // TODO(jam): remove this from the struct since network service shouldn't know
+  // about this.
+  int plugin_child_id = -1;
 
   // What this resource load is for (main frame, sub-frame, sub-resource,
   // object).
-  // TODO(qinmin): this is used for legacy code path. With network service, it
-  // shouldn't know about resource type.
-  ResourceType resource_type = RESOURCE_TYPE_MAIN_FRAME;
+  // Note: this is an enum of type content::ResourceType.
+  // TODO(jam): remove this from the struct since network service shouldn't know
+  // about this.
+  int resource_type = 0;
 
   // The priority of this request determined by Blink.
   net::RequestPriority priority = net::IDLE;
@@ -103,9 +100,11 @@
   network::mojom::CORSPreflightPolicy cors_preflight_policy =
       network::mojom::CORSPreflightPolicy::kConsiderPreflight;
 
-  // Indicates which frame (or worker context) the request is being loaded into,
-  // or kInvalidServiceWorkerProviderId.
-  int service_worker_provider_id = kInvalidServiceWorkerProviderId;
+  // Indicates which frame (or worker context) the request is being loaded into.
+  // -1 corresponds to kInvalidServiceWorkerProviderId.
+  // TODO(jam): remove this from the struct since network service shouldn't know
+  // about this.
+  int service_worker_provider_id = -1;
 
   // True if the request originated from a Service Worker, e.g. due to a
   // fetch() in the Service Worker script.
@@ -113,7 +112,10 @@
 
   // The service worker mode that indicates which service workers should get
   // events for this request.
-  ServiceWorkerMode service_worker_mode = ServiceWorkerMode::ALL;
+  // Note: this is an enum of type content::ServiceWorkerMode.
+  // TODO(jam): remove this from the struct since network service shouldn't know
+  // about this.
+  int service_worker_mode = 0;
 
   // The request mode passed to the ServiceWorker.
   network::mojom::FetchRequestMode fetch_request_mode =
@@ -124,14 +126,20 @@
       network::mojom::FetchCredentialsMode::kOmit;
 
   // The redirect mode used in Fetch API.
-  FetchRedirectMode fetch_redirect_mode = FetchRedirectMode::FOLLOW_MODE;
+  // Note: this is an enum of type content::FetchRedirectMode.
+  // TODO(jam): emove this if network service shouldn't know about this, or
+  // redefine it in /services/network if it is needed to implement CORS in
+  // network service.
+  int fetch_redirect_mode = 0;
 
   // The integrity used in Fetch API.
   std::string fetch_integrity;
 
   // The request context passed to the ServiceWorker.
-  RequestContextType fetch_request_context_type =
-      REQUEST_CONTEXT_TYPE_UNSPECIFIED;
+  // Note: this is an enum of type content::RequestContextType.
+  // TODO(jam): remove this from the struct since network service shouldn't know
+  // about this.
+  int fetch_request_context_type = 0;
 
   // The frame type passed to the ServiceWorker.
   network::mojom::RequestContextFrameType fetch_frame_type =
@@ -169,7 +177,10 @@
   // True if |frame_id| is the main frame of a RenderView.
   bool is_main_frame = false;
 
-  ui::PageTransition transition_type = ui::PAGE_TRANSITION_LINK;
+  // Note: this is an enum of type ui::PageTransition.
+  // TODO(jam): remove this from the struct since network service shouldn't know
+  // about this.
+  int transition_type = 0;
 
   // For navigations, whether this navigation should replace the current session
   // history entry on commit.
@@ -190,7 +201,10 @@
 
   // Whether or not to request a Preview version of the resource or let the
   // browser decide.
-  PreviewsState previews_state = PREVIEWS_UNSPECIFIED;
+  // Note: this is an enum of type PreviewsState.
+  // TODO(jam): remove this from the struct since network service shouldn't know
+  // about this.
+  int previews_state = 0;
 
   // PlzNavigate: the stream url associated with a navigation. Used to get
   // access to the body of the response that has already been fetched by the
diff --git a/content/public/common/url_loader.mojom b/content/public/common/url_loader.mojom
index 241ef40a..05cac6f7 100644
--- a/content/public/common/url_loader.mojom
+++ b/content/public/common/url_loader.mojom
@@ -41,8 +41,8 @@
 
   // Resumes loading the response body if the URLLoader paused the request upon
   // receiving the final response headers.
-  // Note: this is a configuration option for the URLLoader. By default, the
-  // loading isn't paused.
+  // The URLLoader pauses the request when kURLLoadOptionPauseOnResponseStarted
+  // is used.
   // TODO(arthursonzogni): This is a temporary feature. Remove this as soon as
   // the InterceptingResourceHandler is removed. See https://crbug.com/791049.
   ProceedWithResponse();
diff --git a/content/public/common/url_loader_factory.mojom b/content/public/common/url_loader_factory.mojom
index 7e610eb7..0a7c4c4c 100644
--- a/content/public/common/url_loader_factory.mojom
+++ b/content/public/common/url_loader_factory.mojom
@@ -17,6 +17,11 @@
 // Sends the net::SSLInfo struct in OnComplete when the connection had a major
 // certificate error.
 const uint32 kURLLoadOptionSendSSLInfoForCertificateError = 8;
+// Pause the request upon receiving the final response header. The request can
+// be resumed by using URLLoader::ProceedWithResponse.
+// TODO(arthursonzogni): This is a temporary feature. Remove this as soon as
+// the InterceptingResourceHandler is removed. See https://crbug.com/791049.
+const uint32 kURLLoadOptionPauseOnResponseStarted = 16;
 
 interface URLLoaderFactory {
   // Creats a URLLoader and starts loading with the given |request|. |client|'s
diff --git a/content/public/renderer/BUILD.gn b/content/public/renderer/BUILD.gn
index 6d7ba5f..2e391a97 100644
--- a/content/public/renderer/BUILD.gn
+++ b/content/public/renderer/BUILD.gn
@@ -137,4 +137,11 @@
   if (enable_plugins) {
     sources += [ "plugin_instance_throttler.h" ]
   }
+
+  if (enable_library_cdms) {
+    sources += [
+      "key_system_support.cc",
+      "key_system_support.h",
+    ]
+  }
 }
diff --git a/content/public/renderer/key_system_support.cc b/content/public/renderer/key_system_support.cc
new file mode 100644
index 0000000..efc471266
--- /dev/null
+++ b/content/public/renderer/key_system_support.cc
@@ -0,0 +1,35 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/public/renderer/key_system_support.h"
+
+#include "base/logging.h"
+#include "content/public/common/service_names.mojom.h"
+#include "content/public/renderer/render_thread.h"
+#include "media/mojo/interfaces/key_system_support.mojom.h"
+#include "services/service_manager/public/cpp/connector.h"
+
+namespace content {
+
+// TODO(jrummell): As this is replacing IsInternalPluginAvailableForMimeType(),
+// remove it. As well, widevine_cdm_component_installer no longer needs to
+// register additional parameters as they are now no longer used.
+bool IsKeySystemSupported(
+    const std::string& key_system,
+    std::vector<media::VideoCodec>* supported_video_codecs,
+    bool* supports_persistent_license) {
+  DVLOG(3) << __func__ << " key_system: " << key_system;
+
+  bool is_supported = false;
+  media::mojom::KeySystemSupportPtr key_system_support;
+  content::RenderThread::Get()->GetConnector()->BindInterface(
+      mojom::kBrowserServiceName, mojo::MakeRequest(&key_system_support));
+
+  key_system_support->IsKeySystemSupported(key_system, &is_supported,
+                                           supported_video_codecs,
+                                           supports_persistent_license);
+  return is_supported;
+}
+
+}  // namespace content
diff --git a/content/public/renderer/key_system_support.h b/content/public/renderer/key_system_support.h
new file mode 100644
index 0000000..dd8d04a
--- /dev/null
+++ b/content/public/renderer/key_system_support.h
@@ -0,0 +1,27 @@
+// 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_PUBLIC_RENDERER_KEY_SYSTEM_SUPPORT_H_
+#define CONTENT_PUBLIC_RENDERER_KEY_SYSTEM_SUPPORT_H_
+
+#include <string>
+#include <vector>
+
+#include "content/common/content_export.h"
+#include "media/base/video_codecs.h"
+
+namespace content {
+
+// Determines if |key_system| is supported by calling into the browser.
+// If it is supported, return true and |supported_video_codecs| and
+// |supports_persistent_license| are updated to match what |key_system|
+// supports. If not supported, false is returned.
+CONTENT_EXPORT bool IsKeySystemSupported(
+    const std::string& key_system,
+    std::vector<media::VideoCodec>* supported_video_codecs,
+    bool* supports_persistent_license);
+
+}  // namespace content
+
+#endif  // CONTENT_PUBLIC_RENDERER_KEY_SYSTEM_SUPPORT_H_
diff --git a/content/public/test/browser_test_utils.cc b/content/public/test/browser_test_utils.cc
index 72ad87e..7ee39a4 100644
--- a/content/public/test/browser_test_utils.cc
+++ b/content/public/test/browser_test_utils.cc
@@ -924,6 +924,34 @@
       web_contents->GetRenderWidgetHostView())
       ->OnTouchEvent(&touch);
 }
+
+void SimulateLongPressAt(WebContents* web_contents, const gfx::Point& point) {
+  RenderWidgetHostViewAura* rwhva = static_cast<RenderWidgetHostViewAura*>(
+      web_contents->GetRenderWidgetHostView());
+
+  ui::TouchEvent touch_start(
+      ui::ET_TOUCH_PRESSED, point, base::TimeTicks(),
+      ui::PointerDetails(ui::EventPointerType::POINTER_TYPE_TOUCH, 0));
+  rwhva->OnTouchEvent(&touch_start);
+
+  ui::GestureEventDetails tap_down_details(ui::ET_GESTURE_TAP_DOWN);
+  tap_down_details.set_device_type(ui::GestureDeviceType::DEVICE_TOUCHSCREEN);
+  ui::GestureEvent tap_down(point.x(), point.y(), 0, ui::EventTimeForNow(),
+                            tap_down_details, touch_start.unique_event_id());
+  rwhva->OnGestureEvent(&tap_down);
+
+  ui::GestureEventDetails long_press_details(ui::ET_GESTURE_LONG_PRESS);
+  long_press_details.set_device_type(ui::GestureDeviceType::DEVICE_TOUCHSCREEN);
+  ui::GestureEvent long_press(point.x(), point.y(), 0, ui::EventTimeForNow(),
+                              long_press_details,
+                              touch_start.unique_event_id());
+  rwhva->OnGestureEvent(&long_press);
+
+  ui::TouchEvent touch_end(
+      ui::ET_TOUCH_RELEASED, point, base::TimeTicks(),
+      ui::PointerDetails(ui::EventPointerType::POINTER_TYPE_TOUCH, 0));
+  rwhva->OnTouchEvent(&touch_end);
+}
 #endif
 
 void SimulateKeyPress(WebContents* web_contents,
diff --git a/content/public/test/browser_test_utils.h b/content/public/test/browser_test_utils.h
index 905a078..4c15a529 100644
--- a/content/public/test/browser_test_utils.h
+++ b/content/public/test/browser_test_utils.h
@@ -192,6 +192,8 @@
 #if defined(USE_AURA)
 // Generates a TouchStart at |point|.
 void SimulateTouchPressAt(WebContents* web_contents, const gfx::Point& point);
+
+void SimulateLongPressAt(WebContents* web_contents, const gfx::Point& point);
 #endif
 
 // Taps the screen with modifires at |point|.
diff --git a/content/public/test/network_service_test_helper.cc b/content/public/test/network_service_test_helper.cc
index 24186ff..c3c4efe 100644
--- a/content/public/test/network_service_test_helper.cc
+++ b/content/public/test/network_service_test_helper.cc
@@ -12,6 +12,7 @@
 #include "base/feature_list.h"
 #include "base/logging.h"
 #include "base/process/process.h"
+#include "build/build_config.h"
 #include "content/public/common/content_features.h"
 #include "content/public/test/test_host_resolver.h"
 #include "mojo/public/cpp/bindings/binding_set.h"
@@ -22,6 +23,11 @@
 #include "services/network/public/interfaces/network_change_manager.mojom.h"
 #include "services/service_manager/sandbox/sandbox_type.h"
 
+#if defined(OS_ANDROID)
+#include "base/test/android/url_utils.h"
+#include "base/test/test_support_android.h"
+#endif
+
 namespace content {
 
 class NetworkServiceTestHelper::NetworkServiceTestImpl
@@ -87,6 +93,9 @@
       sandbox_type == service_manager::SANDBOX_TYPE_NETWORK) {
     // Register the EmbeddedTestServer's certs, so that any SSL connections to
     // it succeed. Only do this when file I/O is allowed in the current process.
+#if defined(OS_ANDROID)
+    base::InitAndroidTestPaths(base::android::GetIsolatedTestRoot());
+#endif
     net::EmbeddedTestServer::RegisterTestCerts();
 
     // Also add the QUIC test certificate.
diff --git a/content/renderer/image_capture/image_capture_frame_grabber.cc b/content/renderer/image_capture/image_capture_frame_grabber.cc
index 3a2ced3..b49d2b5 100644
--- a/content/renderer/image_capture/image_capture_frame_grabber.cc
+++ b/content/renderer/image_capture/image_capture_frame_grabber.cc
@@ -56,8 +56,7 @@
     SkImageDeliverCB callback,
     const scoped_refptr<media::VideoFrame>& frame,
     base::TimeTicks /* current_time */) {
-  DCHECK(frame->format() == media::PIXEL_FORMAT_YV12 ||
-         frame->format() == media::PIXEL_FORMAT_I420 ||
+  DCHECK(frame->format() == media::PIXEL_FORMAT_I420 ||
          frame->format() == media::PIXEL_FORMAT_I420A);
 
   if (first_frame_received_)
diff --git a/content/renderer/loader/cors_url_loader.cc b/content/renderer/loader/cors_url_loader.cc
index e76d61e6..75ee2a2 100644
--- a/content/renderer/loader/cors_url_loader.cc
+++ b/content/renderer/loader/cors_url_loader.cc
@@ -5,6 +5,7 @@
 #include "content/renderer/loader/cors_url_loader.h"
 
 #include "content/public/common/origin_util.h"
+#include "content/public/common/resource_type.h"
 #include "content/public/common/service_worker_modes.h"
 #include "third_party/WebKit/public/platform/WebCORS.h"
 #include "third_party/WebKit/public/platform/WebHTTPHeaderMap.h"
diff --git a/content/renderer/loader/cors_url_loader_unittest.cc b/content/renderer/loader/cors_url_loader_unittest.cc
index a60c52d..87943ca 100644
--- a/content/renderer/loader/cors_url_loader_unittest.cc
+++ b/content/renderer/loader/cors_url_loader_unittest.cc
@@ -8,6 +8,8 @@
 #include "base/macros.h"
 #include "base/message_loop/message_loop.h"
 #include "base/run_loop.h"
+#include "content/public/common/request_context_type.h"
+#include "content/public/common/resource_type.h"
 #include "content/public/common/url_loader.mojom.h"
 #include "content/public/common/url_loader_factory.mojom.h"
 #include "content/public/test/test_url_loader_client.h"
diff --git a/content/renderer/loader/resource_dispatcher.cc b/content/renderer/loader/resource_dispatcher.cc
index 6c668488..762eb7e 100644
--- a/content/renderer/loader/resource_dispatcher.cc
+++ b/content/renderer/loader/resource_dispatcher.cc
@@ -412,9 +412,9 @@
   // Compute a unique request_id for this renderer process.
   int request_id = MakeRequestID();
   pending_requests_[request_id] = std::make_unique<PendingRequestInfo>(
-      std::move(peer), request->resource_type, request->render_frame_id,
-      frame_origin, request->url, request->method, request->referrer,
-      request->download_to_file);
+      std::move(peer), static_cast<ResourceType>(request->resource_type),
+      request->render_frame_id, frame_origin, request->url, request->method,
+      request->referrer, request->download_to_file);
 
   scoped_refptr<base::SingleThreadTaskRunner> task_runner =
       loading_task_runner ? loading_task_runner : thread_task_runner_;
diff --git a/content/renderer/loader/web_url_loader_impl.cc b/content/renderer/loader/web_url_loader_impl.cc
index ea9a20f..220a59a 100644
--- a/content/renderer/loader/web_url_loader_impl.cc
+++ b/content/renderer/loader/web_url_loader_impl.cc
@@ -632,11 +632,11 @@
   resource_request->is_external_request = request.IsExternalRequest();
   resource_request->cors_preflight_policy = request.GetCORSPreflightPolicy();
   resource_request->service_worker_mode =
-      GetServiceWorkerModeForWebURLRequest(request);
+      static_cast<int>(GetServiceWorkerModeForWebURLRequest(request));
   resource_request->fetch_request_mode = request.GetFetchRequestMode();
   resource_request->fetch_credentials_mode = request.GetFetchCredentialsMode();
   resource_request->fetch_redirect_mode =
-      GetFetchRedirectModeForWebURLRequest(request);
+      static_cast<int>(GetFetchRedirectModeForWebURLRequest(request));
   resource_request->fetch_integrity =
       GetFetchIntegrityForWebURLRequest(request);
   resource_request->fetch_request_context_type =
@@ -658,7 +658,7 @@
   }
   resource_request->report_raw_headers = request.ReportRawHeaders();
   resource_request->previews_state =
-      static_cast<PreviewsState>(request.GetPreviewsState());
+      static_cast<int>(request.GetPreviewsState());
 
   // PlzNavigate: The network request has already been made by the browser.
   // The renderer should request a stream which contains the body of the
diff --git a/content/renderer/media/pepper_to_video_track_adapter.cc b/content/renderer/media/pepper_to_video_track_adapter.cc
index 161dd48..d6820ad0 100644
--- a/content/renderer/media/pepper_to_video_track_adapter.cc
+++ b/content/renderer/media/pepper_to_video_track_adapter.cc
@@ -163,7 +163,7 @@
       time_stamp_ns / base::Time::kNanosecondsPerMicrosecond);
 
   scoped_refptr<media::VideoFrame> new_frame =
-      frame_pool_.CreateFrame(media::PIXEL_FORMAT_YV12, frame_size,
+      frame_pool_.CreateFrame(media::PIXEL_FORMAT_I420, frame_size,
                               gfx::Rect(frame_size), frame_size, timestamp);
 
   libyuv::ARGBToI420(src_data,
diff --git a/content/renderer/media/rtc_peer_connection_handler.cc b/content/renderer/media/rtc_peer_connection_handler.cc
index 90e0173..f99ab9a 100644
--- a/content/renderer/media/rtc_peer_connection_handler.cc
+++ b/content/renderer/media/rtc_peer_connection_handler.cc
@@ -1866,11 +1866,13 @@
         track_adapter = track_adapter_map_->GetLocalTrackAdapter(webrtc_track);
         DCHECK(track_adapter);
       }
-      it = rtp_senders_
-               .insert(std::make_pair(
-                   id, std::make_unique<RTCRtpSender>(
-                           webrtc_senders[i].get(), std::move(track_adapter))))
-               .first;
+      it =
+          rtp_senders_
+              .insert(std::make_pair(
+                  id, std::make_unique<RTCRtpSender>(
+                          task_runner_, signaling_thread(), stream_adapter_map_,
+                          webrtc_senders[i].get(), std::move(track_adapter))))
+              .first;
     }
     web_senders[i] = it->second->ShallowCopy();
   }
@@ -1922,9 +1924,10 @@
   auto it = rtp_senders_
                 .insert(std::make_pair(
                     webrtc_sender_id,
-                    std::make_unique<RTCRtpSender>(std::move(webrtc_sender),
-                                                   std::move(track_adapter),
-                                                   std::move(stream_adapters))))
+                    std::make_unique<RTCRtpSender>(
+                        task_runner_, signaling_thread(), stream_adapter_map_,
+                        std::move(webrtc_sender), std::move(track_adapter),
+                        std::move(stream_adapters))))
                 .first;
   return it->second->ShallowCopy();
 }
diff --git a/content/renderer/media/user_media_client_impl_unittest.cc b/content/renderer/media/user_media_client_impl_unittest.cc
index 99f15ea..a1c3f1c 100644
--- a/content/renderer/media/user_media_client_impl_unittest.cc
+++ b/content/renderer/media/user_media_client_impl_unittest.cc
@@ -342,7 +342,6 @@
 
   MediaStreamAudioSource* CreateAudioSource(
       const MediaStreamDevice& device,
-      const blink::WebMediaConstraints& constraints,
       const MediaStreamSource::ConstraintsCallback& source_ready,
       bool* has_sw_echo_cancellation) override {
     MediaStreamAudioSource* source;
diff --git a/content/renderer/media/user_media_processor.cc b/content/renderer/media/user_media_processor.cc
index 85485d3..3c0aa50 100644
--- a/content/renderer/media/user_media_processor.cc
+++ b/content/renderer/media/user_media_processor.cc
@@ -587,7 +587,6 @@
   blink::WebVector<blink::WebMediaStreamTrack> audio_track_vector(
       audio_devices.size());
   CreateAudioTracks(audio_devices,
-                    current_request_info_->web_request().AudioConstraints(),
                     &audio_track_vector);
 
   blink::WebVector<blink::WebMediaStreamTrack> video_track_vector(
@@ -716,7 +715,6 @@
 
 blink::WebMediaStreamSource UserMediaProcessor::InitializeAudioSourceObject(
     const MediaStreamDevice& device,
-    const blink::WebMediaConstraints& constraints,
     bool* is_pending) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
@@ -744,8 +742,8 @@
       base::ThreadTaskRunnerHandle::Get(), weak_factory_.GetWeakPtr());
 
   bool has_sw_echo_cancellation = false;
-  MediaStreamAudioSource* const audio_source = CreateAudioSource(
-      device, constraints, source_ready, &has_sw_echo_cancellation);
+  MediaStreamAudioSource* const audio_source =
+      CreateAudioSource(device, source_ready, &has_sw_echo_cancellation);
   audio_source->SetStopCallback(base::Bind(
       &UserMediaProcessor::OnLocalSourceStopped, weak_factory_.GetWeakPtr()));
   source.SetExtraData(audio_source);  // Takes ownership.
@@ -760,7 +758,6 @@
 
 MediaStreamAudioSource* UserMediaProcessor::CreateAudioSource(
     const MediaStreamDevice& device,
-    const blink::WebMediaConstraints& constraints,
     const MediaStreamSource::ConstraintsCallback& source_ready,
     bool* has_sw_echo_cancellation) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
@@ -818,7 +815,6 @@
 
 void UserMediaProcessor::CreateAudioTracks(
     const MediaStreamDevices& devices,
-    const blink::WebMediaConstraints& constraints,
     blink::WebVector<blink::WebMediaStreamTrack>* webkit_tracks) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   DCHECK(current_request_info_);
@@ -839,8 +835,8 @@
 
   for (size_t i = 0; i < overridden_audio_devices.size(); ++i) {
     bool is_pending = false;
-    blink::WebMediaStreamSource source = InitializeAudioSourceObject(
-        overridden_audio_devices[i], constraints, &is_pending);
+    blink::WebMediaStreamSource source =
+        InitializeAudioSourceObject(overridden_audio_devices[i], &is_pending);
     (*webkit_tracks)[i].Initialize(source);
     current_request_info_->StartAudioTrack((*webkit_tracks)[i], is_pending);
     // At this point the source has started, and its audio parameters have been
diff --git a/content/renderer/media/user_media_processor.h b/content/renderer/media/user_media_processor.h
index 743b9333..0825ea14 100644
--- a/content/renderer/media/user_media_processor.h
+++ b/content/renderer/media/user_media_processor.h
@@ -24,7 +24,6 @@
 #include "third_party/WebKit/public/web/WebUserMediaRequest.h"
 
 namespace blink {
-class WebMediaConstraints;
 class WebMediaStream;
 class WebMediaStreamSource;
 class WebString;
@@ -127,7 +126,6 @@
   // http://crbug.com/764293
   virtual MediaStreamAudioSource* CreateAudioSource(
       const MediaStreamDevice& device,
-      const blink::WebMediaConstraints& constraints,
       const MediaStreamSource::ConstraintsCallback& source_ready,
       bool* has_sw_echo_cancellation);
   virtual MediaStreamVideoSource* CreateVideoSource(
@@ -171,7 +169,6 @@
 
   blink::WebMediaStreamSource InitializeAudioSourceObject(
       const MediaStreamDevice& device,
-      const blink::WebMediaConstraints& constraints,
       bool* is_pending);
 
   void CreateVideoTracks(
@@ -180,7 +177,6 @@
 
   void CreateAudioTracks(
       const MediaStreamDevices& devices,
-      const blink::WebMediaConstraints& constraints,
       blink::WebVector<blink::WebMediaStreamTrack>* webkit_tracks);
 
   // Callback function triggered when all native versions of the
diff --git a/content/renderer/media/webmediaplayer_ms_compositor.cc b/content/renderer/media/webmediaplayer_ms_compositor.cc
index cb0c743..55b2111 100644
--- a/content/renderer/media/webmediaplayer_ms_compositor.cc
+++ b/content/renderer/media/webmediaplayer_ms_compositor.cc
@@ -87,8 +87,7 @@
         libyuv::kRotate0, source_pixel_format);
   } else {
     DCHECK(frame->IsMappable());
-    DCHECK(frame->format() == media::PIXEL_FORMAT_YV12 ||
-           frame->format() == media::PIXEL_FORMAT_I420A ||
+    DCHECK(frame->format() == media::PIXEL_FORMAT_I420A ||
            frame->format() == media::PIXEL_FORMAT_I420);
     const gfx::Size& coded_size = frame->coded_size();
     new_frame = media::VideoFrame::CreateFrame(
diff --git a/content/renderer/media/webmediaplayer_ms_unittest.cc b/content/renderer/media/webmediaplayer_ms_unittest.cc
index f05227e..caba08f 100644
--- a/content/renderer/media/webmediaplayer_ms_unittest.cc
+++ b/content/renderer/media/webmediaplayer_ms_unittest.cc
@@ -291,7 +291,7 @@
       }
 
       auto frame = media::VideoFrame::CreateZeroInitializedFrame(
-          opaque_frame ? media::PIXEL_FORMAT_YV12 : media::PIXEL_FORMAT_I420A,
+          opaque_frame ? media::PIXEL_FORMAT_I420 : media::PIXEL_FORMAT_I420A,
           frame_size, gfx::Rect(frame_size), frame_size,
           base::TimeDelta::FromMilliseconds(token));
 
diff --git a/content/renderer/media/webrtc/media_stream_remote_video_source.cc b/content/renderer/media/webrtc/media_stream_remote_video_source.cc
index 482f7b3..4407dcf 100644
--- a/content/renderer/media/webrtc/media_stream_remote_video_source.cc
+++ b/content/renderer/media/webrtc/media_stream_remote_video_source.cc
@@ -142,7 +142,7 @@
         pixel_format = media::PIXEL_FORMAT_I444;
       } else {
         yuv_buffer = buffer->ToI420();
-        pixel_format = media::PIXEL_FORMAT_YV12;
+        pixel_format = media::PIXEL_FORMAT_I420;
       }
       // Make a shallow copy. Both |frame| and |video_frame| will share a single
       // reference counted frame buffer. Const cast and hope no one will
diff --git a/content/renderer/media/webrtc/rtc_rtp_sender.cc b/content/renderer/media/webrtc/rtc_rtp_sender.cc
index 824e0ab8..b41893d 100644
--- a/content/renderer/media/webrtc/rtc_rtp_sender.cc
+++ b/content/renderer/media/webrtc/rtc_rtp_sender.cc
@@ -8,17 +8,68 @@
 
 namespace content {
 
+namespace {
+
+// TODO(hbos): Replace WebRTCVoidRequest with something resolving promises based
+// on RTCError, as to surface both exception type and error message.
+// https://crbug.com/790007
+void OnReplaceTrackCompleted(blink::WebRTCVoidRequest request, bool result) {
+  if (result)
+    request.RequestSucceeded();
+  else
+    request.RequestFailed(blink::WebString());
+}
+
+}  // namespace
+
 class RTCRtpSender::RTCRtpSenderInternal
     : public base::RefCountedThreadSafe<RTCRtpSender::RTCRtpSenderInternal> {
  public:
   RTCRtpSenderInternal(
+      scoped_refptr<base::SingleThreadTaskRunner> main_thread,
+      scoped_refptr<base::SingleThreadTaskRunner> signaling_thread,
+      scoped_refptr<WebRtcMediaStreamAdapterMap> stream_map,
+      rtc::scoped_refptr<webrtc::RtpSenderInterface> webrtc_sender,
+      blink::WebMediaStreamTrack web_track,
+      std::vector<blink::WebMediaStream> web_streams)
+      : main_thread_(std::move(main_thread)),
+        signaling_thread_(std::move(signaling_thread)),
+        stream_map_(std::move(stream_map)),
+        webrtc_sender_(std::move(webrtc_sender)) {
+    DCHECK(main_thread_);
+    DCHECK(signaling_thread_);
+    DCHECK(stream_map_);
+    DCHECK(webrtc_sender_);
+    if (!web_track.IsNull()) {
+      track_ref_ =
+          stream_map_->track_adapter_map()->GetOrCreateLocalTrackAdapter(
+              web_track);
+    }
+    for (size_t i = 0; i < web_streams.size(); ++i) {
+      if (!web_streams[i].IsNull()) {
+        stream_refs_.push_back(
+            stream_map_->GetOrCreateLocalStreamAdapter(web_streams[i]));
+      }
+    }
+  }
+
+  RTCRtpSenderInternal(
+      scoped_refptr<base::SingleThreadTaskRunner> main_thread,
+      scoped_refptr<base::SingleThreadTaskRunner> signaling_thread,
+      scoped_refptr<WebRtcMediaStreamAdapterMap> stream_map,
       rtc::scoped_refptr<webrtc::RtpSenderInterface> webrtc_sender,
       std::unique_ptr<WebRtcMediaStreamTrackAdapterMap::AdapterRef> track_ref,
       std::vector<std::unique_ptr<WebRtcMediaStreamAdapterMap::AdapterRef>>
           stream_refs)
-      : webrtc_sender_(std::move(webrtc_sender)),
+      : main_thread_(std::move(main_thread)),
+        signaling_thread_(std::move(signaling_thread)),
+        stream_map_(std::move(stream_map)),
+        webrtc_sender_(std::move(webrtc_sender)),
         track_ref_(std::move(track_ref)),
         stream_refs_(std::move(stream_refs)) {
+    DCHECK(main_thread_);
+    DCHECK(signaling_thread_);
+    DCHECK(stream_map_);
     DCHECK(webrtc_sender_);
   }
 
@@ -40,6 +91,24 @@
     return stream_ref_copies;
   }
 
+  void ReplaceTrack(blink::WebMediaStreamTrack with_track,
+                    base::OnceCallback<void(bool)> callback) {
+    DCHECK(main_thread_->BelongsToCurrentThread());
+    std::unique_ptr<WebRtcMediaStreamTrackAdapterMap::AdapterRef> track_ref;
+    webrtc::MediaStreamTrackInterface* webrtc_track = nullptr;
+    if (!with_track.IsNull()) {
+      track_ref =
+          stream_map_->track_adapter_map()->GetOrCreateLocalTrackAdapter(
+              with_track);
+      webrtc_track = track_ref->webrtc_track();
+    }
+    signaling_thread_->PostTask(
+        FROM_HERE,
+        base::BindOnce(
+            &RTCRtpSender::RTCRtpSenderInternal::ReplaceTrackOnSignalingThread,
+            this, std::move(track_ref), webrtc_track, std::move(callback)));
+  }
+
   bool RemoveFromPeerConnection(webrtc::PeerConnectionInterface* pc) {
     if (!pc->RemoveTrack(webrtc_sender_))
       return false;
@@ -55,6 +124,34 @@
   friend class base::RefCountedThreadSafe<RTCRtpSenderInternal>;
   virtual ~RTCRtpSenderInternal() {}
 
+  // |webrtc_track| is passed as an argument because |track_ref->webrtc_track()|
+  // cannot be accessed on the signaling thread. https://crbug.com/756436
+  void ReplaceTrackOnSignalingThread(
+      std::unique_ptr<WebRtcMediaStreamTrackAdapterMap::AdapterRef> track_ref,
+      webrtc::MediaStreamTrackInterface* webrtc_track,
+      base::OnceCallback<void(bool)> callback) {
+    DCHECK(signaling_thread_->BelongsToCurrentThread());
+    bool result = webrtc_sender_->SetTrack(webrtc_track);
+    main_thread_->PostTask(
+        FROM_HERE,
+        base::BindOnce(
+            &RTCRtpSender::RTCRtpSenderInternal::ReplaceTrackCallback, this,
+            result, std::move(track_ref), std::move(callback)));
+  }
+
+  void ReplaceTrackCallback(
+      bool result,
+      std::unique_ptr<WebRtcMediaStreamTrackAdapterMap::AdapterRef> track_ref,
+      base::OnceCallback<void(bool)> callback) {
+    DCHECK(main_thread_->BelongsToCurrentThread());
+    if (result)
+      track_ref_ = std::move(track_ref);
+    std::move(callback).Run(result);
+  }
+
+  const scoped_refptr<base::SingleThreadTaskRunner> main_thread_;
+  const scoped_refptr<base::SingleThreadTaskRunner> signaling_thread_;
+  scoped_refptr<WebRtcMediaStreamAdapterMap> stream_map_;
   const rtc::scoped_refptr<webrtc::RtpSenderInterface> webrtc_sender_;
   // The track adapter is the glue between blink and webrtc layer tracks.
   // Keeping a reference to the adapter ensures it is not disposed, as is
@@ -71,20 +168,46 @@
 }
 
 RTCRtpSender::RTCRtpSender(
+    scoped_refptr<base::SingleThreadTaskRunner> main_thread,
+    scoped_refptr<base::SingleThreadTaskRunner> signaling_thread,
+    scoped_refptr<WebRtcMediaStreamAdapterMap> stream_map,
+    rtc::scoped_refptr<webrtc::RtpSenderInterface> webrtc_sender,
+    blink::WebMediaStreamTrack web_track,
+    std::vector<blink::WebMediaStream> web_streams)
+    : internal_(new RTCRtpSenderInternal(std::move(main_thread),
+                                         std::move(signaling_thread),
+                                         std::move(stream_map),
+                                         std::move(webrtc_sender),
+                                         std::move(web_track),
+                                         std::move(web_streams))) {}
+
+RTCRtpSender::RTCRtpSender(
+    scoped_refptr<base::SingleThreadTaskRunner> main_thread,
+    scoped_refptr<base::SingleThreadTaskRunner> signaling_thread,
+    scoped_refptr<WebRtcMediaStreamAdapterMap> stream_map,
     rtc::scoped_refptr<webrtc::RtpSenderInterface> webrtc_sender,
     std::unique_ptr<WebRtcMediaStreamTrackAdapterMap::AdapterRef> track_ref)
     : RTCRtpSender(
+          std::move(main_thread),
+          std::move(signaling_thread),
+          std::move(stream_map),
           std::move(webrtc_sender),
           std::move(track_ref),
           std::vector<
               std::unique_ptr<WebRtcMediaStreamAdapterMap::AdapterRef>>()) {}
 
 RTCRtpSender::RTCRtpSender(
+    scoped_refptr<base::SingleThreadTaskRunner> main_thread,
+    scoped_refptr<base::SingleThreadTaskRunner> signaling_thread,
+    scoped_refptr<WebRtcMediaStreamAdapterMap> stream_map,
     rtc::scoped_refptr<webrtc::RtpSenderInterface> webrtc_sender,
     std::unique_ptr<WebRtcMediaStreamTrackAdapterMap::AdapterRef> track_ref,
     std::vector<std::unique_ptr<WebRtcMediaStreamAdapterMap::AdapterRef>>
         stream_refs)
-    : internal_(new RTCRtpSenderInternal(std::move(webrtc_sender),
+    : internal_(new RTCRtpSenderInternal(std::move(main_thread),
+                                         std::move(signaling_thread),
+                                         std::move(stream_map),
+                                         std::move(webrtc_sender),
                                          std::move(track_ref),
                                          std::move(stream_refs))) {}
 
@@ -111,6 +234,13 @@
   return track_ref ? track_ref->web_track() : blink::WebMediaStreamTrack();
 }
 
+void RTCRtpSender::ReplaceTrack(blink::WebMediaStreamTrack with_track,
+                                blink::WebRTCVoidRequest request) {
+  internal_->ReplaceTrack(
+      std::move(with_track),
+      base::BindOnce(&OnReplaceTrackCompleted, std::move(request)));
+}
+
 webrtc::RtpSenderInterface* RTCRtpSender::webrtc_sender() const {
   return internal_->webrtc_sender();
 }
@@ -120,6 +250,11 @@
   return track_ref ? track_ref->webrtc_track() : nullptr;
 }
 
+void RTCRtpSender::ReplaceTrack(blink::WebMediaStreamTrack with_track,
+                                base::OnceCallback<void(bool)> callback) {
+  internal_->ReplaceTrack(std::move(with_track), std::move(callback));
+}
+
 bool RTCRtpSender::RemoveFromPeerConnection(
     webrtc::PeerConnectionInterface* pc) {
   return internal_->RemoveFromPeerConnection(pc);
diff --git a/content/renderer/media/webrtc/rtc_rtp_sender.h b/content/renderer/media/webrtc/rtc_rtp_sender.h
index fc794a5d..d0d9fa69 100644
--- a/content/renderer/media/webrtc/rtc_rtp_sender.h
+++ b/content/renderer/media/webrtc/rtc_rtp_sender.h
@@ -8,6 +8,7 @@
 #include <memory>
 #include <vector>
 
+#include "base/callback.h"
 #include "content/common/content_export.h"
 #include "content/renderer/media/webrtc/webrtc_media_stream_adapter_map.h"
 #include "content/renderer/media/webrtc/webrtc_media_stream_track_adapter_map.h"
@@ -26,10 +27,25 @@
  public:
   static uintptr_t getId(const webrtc::RtpSenderInterface* webrtc_sender);
 
+  RTCRtpSender(scoped_refptr<base::SingleThreadTaskRunner> main_thread,
+               scoped_refptr<base::SingleThreadTaskRunner> signaling_thread,
+               scoped_refptr<WebRtcMediaStreamAdapterMap> stream_map,
+               rtc::scoped_refptr<webrtc::RtpSenderInterface> webrtc_sender,
+               blink::WebMediaStreamTrack web_track,
+               std::vector<blink::WebMediaStream> web_streams);
+  // TODO(hbos): Remove these in favor of the above constructor that creates the
+  // corresponding adapter refs. They won't be needed after
+  // https://crbug.com/738929.
   RTCRtpSender(
+      scoped_refptr<base::SingleThreadTaskRunner> main_thread,
+      scoped_refptr<base::SingleThreadTaskRunner> signaling_thread,
+      scoped_refptr<WebRtcMediaStreamAdapterMap> stream_map,
       rtc::scoped_refptr<webrtc::RtpSenderInterface> webrtc_sender,
       std::unique_ptr<WebRtcMediaStreamTrackAdapterMap::AdapterRef> track_ref);
   RTCRtpSender(
+      scoped_refptr<base::SingleThreadTaskRunner> main_thread,
+      scoped_refptr<base::SingleThreadTaskRunner> signaling_thread,
+      scoped_refptr<WebRtcMediaStreamAdapterMap> stream_map,
       rtc::scoped_refptr<webrtc::RtpSenderInterface> webrtc_sender,
       std::unique_ptr<WebRtcMediaStreamTrackAdapterMap::AdapterRef> track_ref,
       std::vector<std::unique_ptr<WebRtcMediaStreamAdapterMap::AdapterRef>>
@@ -44,15 +60,25 @@
   // TODO(hbos): Remove in favor of constructor. https://crbug.com/790007
   std::unique_ptr<RTCRtpSender> ShallowCopy() const;
 
+  // blink::WebRTCRtpSender.
   uintptr_t Id() const override;
   blink::WebMediaStreamTrack Track() const override;
+  void ReplaceTrack(blink::WebMediaStreamTrack with_track,
+                    blink::WebRTCVoidRequest request) override;
 
   webrtc::RtpSenderInterface* webrtc_sender() const;
   const webrtc::MediaStreamTrackInterface* webrtc_track() const;
+  // The ReplaceTrack() that takes a blink::WebRTCVoidRequest is implemented on
+  // top of this, which returns the result in a callback instead. Allows doing
+  // ReplaceTrack() without having a blink::WebRTCVoidRequest, which can only be
+  // constructed inside of blink.
+  void ReplaceTrack(blink::WebMediaStreamTrack with_track,
+                    base::OnceCallback<void(bool)> callback);
   bool RemoveFromPeerConnection(webrtc::PeerConnectionInterface* pc);
 
  private:
   class RTCRtpSenderInternal;
+
   scoped_refptr<RTCRtpSenderInternal> internal_;
 };
 
diff --git a/content/renderer/media/webrtc/rtc_rtp_sender_unittest.cc b/content/renderer/media/webrtc/rtc_rtp_sender_unittest.cc
new file mode 100644
index 0000000..5574baec
--- /dev/null
+++ b/content/renderer/media/webrtc/rtc_rtp_sender_unittest.cc
@@ -0,0 +1,194 @@
+// Copyright (c) 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 "content/renderer/media/webrtc/rtc_rtp_sender.h"
+
+#include <memory>
+
+#include "base/memory/ref_counted.h"
+#include "base/message_loop/message_loop.h"
+#include "base/run_loop.h"
+#include "base/single_thread_task_runner.h"
+#include "content/child/child_process.h"
+#include "content/renderer/media/media_stream_audio_source.h"
+#include "content/renderer/media/webrtc/mock_peer_connection_dependency_factory.h"
+#include "content/renderer/media/webrtc/webrtc_media_stream_adapter_map.h"
+#include "content/renderer/media/webrtc/webrtc_media_stream_track_adapter_map.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/WebKit/public/platform/WebMediaStreamSource.h"
+#include "third_party/WebKit/public/platform/WebMediaStreamTrack.h"
+#include "third_party/WebKit/public/platform/WebRTCVoidRequest.h"
+#include "third_party/WebKit/public/platform/WebString.h"
+#include "third_party/WebKit/public/web/WebHeap.h"
+#include "third_party/webrtc/api/test/mock_rtpsender.h"
+
+using ::testing::_;
+using ::testing::Return;
+
+namespace content {
+
+class RTCRtpSenderTest : public ::testing::Test {
+ public:
+  void SetUp() override {
+    dependency_factory_.reset(new MockPeerConnectionDependencyFactory());
+    main_thread_ = base::ThreadTaskRunnerHandle::Get();
+    stream_map_ = new WebRtcMediaStreamAdapterMap(
+        dependency_factory_.get(),
+        new WebRtcMediaStreamTrackAdapterMap(dependency_factory_.get()));
+    mock_webrtc_sender_ = new rtc::RefCountedObject<webrtc::MockRtpSender>();
+  }
+
+  void TearDown() override { blink::WebHeap::CollectAllGarbageForTesting(); }
+
+  blink::WebMediaStreamTrack CreateWebTrack(const std::string& id) {
+    blink::WebMediaStreamSource web_source;
+    web_source.Initialize(
+        blink::WebString::FromUTF8(id), blink::WebMediaStreamSource::kTypeAudio,
+        blink::WebString::FromUTF8("local_audio_track"), false);
+    MediaStreamAudioSource* audio_source = new MediaStreamAudioSource(true);
+    // Takes ownership of |audio_source|.
+    web_source.SetExtraData(audio_source);
+    blink::WebMediaStreamTrack web_track;
+    web_track.Initialize(web_source.Id(), web_source);
+    audio_source->ConnectToTrack(web_track);
+    return web_track;
+  }
+
+  std::unique_ptr<RTCRtpSender> CreateSender(
+      blink::WebMediaStreamTrack web_track) {
+    return std::make_unique<RTCRtpSender>(
+        main_thread_, dependency_factory_->GetWebRtcSignalingThread(),
+        stream_map_, mock_webrtc_sender_.get(), std::move(web_track),
+        std::vector<blink::WebMediaStream>());
+  }
+
+  // Calls replaceTrack(), which is asynchronous, returning a callback that when
+  // invoked waits for (run-loops) the operation to complete and returns whether
+  // replaceTrack() was successful.
+  base::OnceCallback<bool()> ReplaceTrack(
+      blink::WebMediaStreamTrack web_track) {
+    std::unique_ptr<base::RunLoop> run_loop = std::make_unique<base::RunLoop>();
+    std::unique_ptr<bool> result_holder(new bool());
+    // On complete, |*result_holder| is set with the result of replaceTrack()
+    // and the |run_loop| quit.
+    sender_->ReplaceTrack(
+        web_track, base::BindOnce(&RTCRtpSenderTest::CallbackOnComplete,
+                                  base::Unretained(this), result_holder.get(),
+                                  run_loop.get()));
+    // When the resulting callback is invoked, waits for |run_loop| to complete
+    // and returns |*result_holder|.
+    return base::BindOnce(&RTCRtpSenderTest::RunLoopAndReturnResult,
+                          base::Unretained(this), std::move(result_holder),
+                          std::move(run_loop));
+  }
+
+ protected:
+  void CallbackOnComplete(bool* result_out,
+                          base::RunLoop* run_loop,
+                          bool result) {
+    *result_out = result;
+    run_loop->Quit();
+  }
+
+  bool RunLoopAndReturnResult(std::unique_ptr<bool> result_holder,
+                              std::unique_ptr<base::RunLoop> run_loop) {
+    run_loop->Run();
+    return *result_holder;
+  }
+
+  // Message loop and child processes is needed for task queues and threading to
+  // work, as is necessary to create tracks and adapters.
+  base::MessageLoop message_loop_;
+  ChildProcess child_process_;
+
+  std::unique_ptr<MockPeerConnectionDependencyFactory> dependency_factory_;
+  scoped_refptr<base::SingleThreadTaskRunner> main_thread_;
+  scoped_refptr<WebRtcMediaStreamAdapterMap> stream_map_;
+  rtc::scoped_refptr<webrtc::MockRtpSender> mock_webrtc_sender_;
+  std::unique_ptr<RTCRtpSender> sender_;
+};
+
+TEST_F(RTCRtpSenderTest, CreateSender) {
+  auto web_track = CreateWebTrack("track_id");
+  sender_ = CreateSender(web_track);
+  EXPECT_FALSE(sender_->Track().IsNull());
+  EXPECT_EQ(web_track.UniqueId(), sender_->Track().UniqueId());
+}
+
+TEST_F(RTCRtpSenderTest, CreateSenderWithNullTrack) {
+  blink::WebMediaStreamTrack null_track;
+  sender_ = CreateSender(null_track);
+  EXPECT_TRUE(sender_->Track().IsNull());
+}
+
+TEST_F(RTCRtpSenderTest, ReplaceTrackSetsTrack) {
+  auto web_track1 = CreateWebTrack("track1");
+  sender_ = CreateSender(web_track1);
+
+  auto web_track2 = CreateWebTrack("track2");
+  EXPECT_CALL(*mock_webrtc_sender_, SetTrack(_)).WillOnce(Return(true));
+  auto replaceTrackRunLoopAndGetResult = ReplaceTrack(web_track2);
+  EXPECT_TRUE(std::move(replaceTrackRunLoopAndGetResult).Run());
+  ASSERT_FALSE(sender_->Track().IsNull());
+  EXPECT_EQ(web_track2.UniqueId(), sender_->Track().UniqueId());
+}
+
+TEST_F(RTCRtpSenderTest, ReplaceTrackWithNullTrack) {
+  auto web_track = CreateWebTrack("track_id");
+  sender_ = CreateSender(web_track);
+
+  blink::WebMediaStreamTrack null_track;
+  EXPECT_CALL(*mock_webrtc_sender_, SetTrack(_)).WillOnce(Return(true));
+  auto replaceTrackRunLoopAndGetResult = ReplaceTrack(null_track);
+  EXPECT_TRUE(std::move(replaceTrackRunLoopAndGetResult).Run());
+  EXPECT_TRUE(sender_->Track().IsNull());
+}
+
+TEST_F(RTCRtpSenderTest, ReplaceTrackCanFail) {
+  auto web_track = CreateWebTrack("track_id");
+  sender_ = CreateSender(web_track);
+  ASSERT_FALSE(sender_->Track().IsNull());
+  EXPECT_EQ(web_track.UniqueId(), sender_->Track().UniqueId());
+
+  blink::WebMediaStreamTrack null_track;
+  EXPECT_CALL(*mock_webrtc_sender_, SetTrack(_)).WillOnce(Return(false));
+  auto replaceTrackRunLoopAndGetResult = ReplaceTrack(null_track);
+  EXPECT_FALSE(std::move(replaceTrackRunLoopAndGetResult).Run());
+  // The track should not have been set.
+  ASSERT_FALSE(sender_->Track().IsNull());
+  EXPECT_EQ(web_track.UniqueId(), sender_->Track().UniqueId());
+}
+
+TEST_F(RTCRtpSenderTest, ReplaceTrackIsNotSetSynchronously) {
+  auto web_track1 = CreateWebTrack("track1");
+  sender_ = CreateSender(web_track1);
+
+  auto web_track2 = CreateWebTrack("track2");
+  EXPECT_CALL(*mock_webrtc_sender_, SetTrack(_)).WillOnce(Return(true));
+  auto replaceTrackRunLoopAndGetResult = ReplaceTrack(web_track2);
+  // The track should not be set until the run loop has executed.
+  ASSERT_FALSE(sender_->Track().IsNull());
+  EXPECT_NE(web_track2.UniqueId(), sender_->Track().UniqueId());
+  // Wait for operation to run to ensure EXPECT_CALL is satisfied.
+  std::move(replaceTrackRunLoopAndGetResult).Run();
+}
+
+TEST_F(RTCRtpSenderTest, CopiedSenderSharesInternalStates) {
+  auto web_track = CreateWebTrack("track_id");
+  sender_ = CreateSender(web_track);
+  auto copy = std::make_unique<RTCRtpSender>(*sender_);
+  // Copy shares original's ID.
+  EXPECT_EQ(sender_->Id(), copy->Id());
+
+  blink::WebMediaStreamTrack null_track;
+  EXPECT_CALL(*mock_webrtc_sender_, SetTrack(_)).WillOnce(Return(true));
+  auto replaceTrackRunLoopAndGetResult = ReplaceTrack(null_track);
+  EXPECT_TRUE(std::move(replaceTrackRunLoopAndGetResult).Run());
+
+  // Both original and copy shows a modified state.
+  EXPECT_TRUE(sender_->Track().IsNull());
+  EXPECT_TRUE(copy->Track().IsNull());
+}
+
+}  // namespace content
diff --git a/content/renderer/media/webrtc/webrtc_video_capturer_adapter.cc b/content/renderer/media/webrtc/webrtc_video_capturer_adapter.cc
index cbcbaa82..b5eaa24 100644
--- a/content/renderer/media/webrtc/webrtc_video_capturer_adapter.cc
+++ b/content/renderer/media/webrtc/webrtc_video_capturer_adapter.cc
@@ -168,7 +168,6 @@
   TRACE_EVENT0("video", "WebRtcVideoCapturerAdapter::OnFrameCaptured");
   if (!(input_frame->IsMappable() &&
         (input_frame->format() == media::PIXEL_FORMAT_I420 ||
-         input_frame->format() == media::PIXEL_FORMAT_YV12 ||
          input_frame->format() == media::PIXEL_FORMAT_I420A)) &&
       !input_frame->HasTextures()) {
     // Since connecting sources and sinks do not check the format, we need to
diff --git a/content/renderer/media/webrtc/webrtc_video_frame_adapter.cc b/content/renderer/media/webrtc/webrtc_video_frame_adapter.cc
index d625d84..d65c73fa 100644
--- a/content/renderer/media/webrtc/webrtc_video_frame_adapter.cc
+++ b/content/renderer/media/webrtc/webrtc_video_frame_adapter.cc
@@ -72,7 +72,6 @@
       frame->format(), frame->storage_type(), frame->coded_size(),
       frame->visible_rect(), frame->natural_size()));
   DCHECK(media::PIXEL_FORMAT_I420 == frame->format() ||
-         media::PIXEL_FORMAT_YV12 == frame->format() ||
          media::PIXEL_FORMAT_I420A == frame->format());
   CHECK(reinterpret_cast<void*>(frame->data(media::VideoFrame::kYPlane)));
   CHECK(reinterpret_cast<void*>(frame->data(media::VideoFrame::kUPlane)));
diff --git a/content/renderer/media_recorder/video_track_recorder.cc b/content/renderer/media_recorder/video_track_recorder.cc
index 61e1f551..54747f1 100644
--- a/content/renderer/media_recorder/video_track_recorder.cc
+++ b/content/renderer/media_recorder/video_track_recorder.cc
@@ -202,7 +202,6 @@
     return;
 
   if (!(video_frame->format() == media::PIXEL_FORMAT_I420 ||
-        video_frame->format() == media::PIXEL_FORMAT_YV12 ||
         video_frame->format() == media::PIXEL_FORMAT_ARGB ||
         video_frame->format() == media::PIXEL_FORMAT_I420A ||
         video_frame->format() == media::PIXEL_FORMAT_NV12)) {
diff --git a/content/renderer/pepper/video_decoder_shim.cc b/content/renderer/pepper/video_decoder_shim.cc
index 8cf16fb..2550e00 100644
--- a/content/renderer/pepper/video_decoder_shim.cc
+++ b/content/renderer/pepper/video_decoder_shim.cc
@@ -410,7 +410,6 @@
     }
 
     switch (frame->format()) {
-      case media::PIXEL_FORMAT_YV12:  // 420
       case media::PIXEL_FORMAT_I420A:
       case media::PIXEL_FORMAT_I420:
         uv_height_divisor_ = 2;
@@ -895,7 +894,7 @@
     return false;
 
   media::VideoDecoderConfig video_decoder_config(
-      codec, vda_config.profile, media::PIXEL_FORMAT_YV12,
+      codec, vda_config.profile, media::PIXEL_FORMAT_I420,
       media::COLOR_SPACE_UNSPECIFIED, media::VIDEO_ROTATION_0,
       gfx::Size(32, 24),  // Small sizes that won't fail.
       gfx::Rect(32, 24), gfx::Size(32, 24),
diff --git a/content/renderer/render_frame_impl.cc b/content/renderer/render_frame_impl.cc
index 29d906e8..043ec17 100644
--- a/content/renderer/render_frame_impl.cc
+++ b/content/renderer/render_frame_impl.cc
@@ -4268,15 +4268,8 @@
 
   bool is_new_navigation = UpdateNavigationHistory(item, commit_type);
 
-  for (auto& observer : render_view_->observers_)
-    observer.DidCommitProvisionalLoad(frame_, is_new_navigation);
-  {
-    SCOPED_UMA_HISTOGRAM_TIMER("RenderFrameObservers.DidCommitProvisionalLoad");
-    for (auto& observer : observers_) {
-      observer.DidCommitProvisionalLoad(
-          is_new_navigation, navigation_state->WasWithinSameDocument());
-    }
-  }
+  NotifyObserversOfNavigationCommit(is_new_navigation,
+                                    navigation_state->WasWithinSameDocument());
 
   // Notify the MediaPermissionDispatcher that its connection will be closed
   // due to a navigation to a different document.
@@ -5327,18 +5320,11 @@
     service_manager::mojom::InterfaceProviderRequest
         remote_interface_provider_request) {
   DCHECK_EQ(frame_, frame);
-  WebDocumentLoader* document_loader = frame->GetDocumentLoader();
-  DCHECK(document_loader);
-
-  const WebURLRequest& request = document_loader->GetRequest();
-  const WebURLResponse& response = document_loader->GetResponse();
 
   DocumentState* document_state =
-      DocumentState::FromDocumentLoader(document_loader);
+      DocumentState::FromDocumentLoader(frame_->GetDocumentLoader());
   NavigationStateImpl* navigation_state =
       static_cast<NavigationStateImpl*>(document_state->navigation_state());
-  InternalDocumentStateData* internal_data =
-      InternalDocumentStateData::FromDocumentState(document_state);
 
   // Set the correct engagement level on the frame, and wipe the cached origin
   // so this will not be reused accidentally.
@@ -5355,6 +5341,35 @@
     high_media_engagement_origin_ = url::Origin();
   }
 
+  UpdateZoomLevel();
+
+  // This invocation must precede any calls to allowScripts(), allowImages(), or
+  // allowPlugins() for the new page. This ensures that when these functions
+  // send ViewHostMsg_ContentBlocked messages, those arrive after the browser
+  // process has already been informed of the provisional load committing.
+  GetFrameHost()->DidCommitProvisionalLoad(
+      MakeDidCommitProvisionalLoadParams(commit_type),
+      std::move(remote_interface_provider_request));
+
+  // If we end up reusing this WebRequest (for example, due to a #ref click),
+  // we don't want the transition type to persist.  Just clear it.
+  navigation_state->set_transition_type(ui::PAGE_TRANSITION_LINK);
+}
+
+std::unique_ptr<FrameHostMsg_DidCommitProvisionalLoad_Params>
+RenderFrameImpl::MakeDidCommitProvisionalLoadParams(
+    blink::WebHistoryCommitType commit_type) {
+  WebDocumentLoader* document_loader = frame_->GetDocumentLoader();
+  const WebURLRequest& request = document_loader->GetRequest();
+  const WebURLResponse& response = document_loader->GetResponse();
+
+  DocumentState* document_state =
+      DocumentState::FromDocumentLoader(frame_->GetDocumentLoader());
+  NavigationStateImpl* navigation_state =
+      static_cast<NavigationStateImpl*>(document_state->navigation_state());
+  InternalDocumentStateData* internal_data =
+      InternalDocumentStateData::FromDocumentState(document_state);
+
   std::unique_ptr<FrameHostMsg_DidCommitProvisionalLoad_Params> params =
       std::make_unique<FrameHostMsg_DidCommitProvisionalLoad_Params>();
   params->http_status_code = response.HttpStatusCode();
@@ -5385,17 +5400,17 @@
   // stale state around.
   params->did_create_new_entry =
       (commit_type == blink::kWebStandardCommit) ||
-      (commit_type == blink::kWebHistoryInertCommit && !frame->Parent() &&
+      (commit_type == blink::kWebHistoryInertCommit && !frame_->Parent() &&
        params->should_replace_current_entry &&
-       !params->was_within_same_document);
+       !navigation_state->WasWithinSameDocument());
 
-  WebDocument frame_document = frame->GetDocument();
+  WebDocument frame_document = frame_->GetDocument();
   // Set the origin of the frame.  This will be replicated to the corresponding
   // RenderFrameProxies in other processes.
   WebSecurityOrigin frame_origin = frame_document.GetSecurityOrigin();
   params->origin = frame_origin;
 
-  params->insecure_request_policy = frame->GetInsecureRequestPolicy();
+  params->insecure_request_policy = frame_->GetInsecureRequestPolicy();
 
   params->has_potentially_trustworthy_unique_origin =
       frame_origin.IsUnique() && frame_origin.IsPotentiallyTrustworthy();
@@ -5439,12 +5454,10 @@
                  document_loader->GetRequest().GetReferrerPolicy());
   } else {
     params->referrer = RenderViewImpl::GetReferrerFromRequest(
-        frame, document_loader->GetRequest());
+        frame_, document_loader->GetRequest());
   }
 
-  UpdateZoomLevel();
-
-  if (!frame->Parent()) {
+  if (!frame_->Parent()) {
     // Top-level navigation.
 
     // Update contents MIME type for main frame.
@@ -5474,11 +5487,13 @@
         navigation_state->request_params().should_clear_history_list;
 
     params->report_type = static_cast<FrameMsg_UILoadMetricsReportType::Value>(
-        frame->GetDocumentLoader()->GetRequest().InputPerfMetricReportPolicy());
+        frame_->GetDocumentLoader()
+            ->GetRequest()
+            .InputPerfMetricReportPolicy());
     params->ui_timestamp =
         base::TimeTicks() +
         base::TimeDelta::FromSecondsD(
-            frame->GetDocumentLoader()->GetRequest().UiStartTime());
+            frame_->GetDocumentLoader()->GetRequest().UiStartTime());
   } else {
     // Subframe navigation: the type depends on whether this navigation
     // generated a new session history entry. When they do generate a session
@@ -5509,16 +5524,7 @@
     }
   }
 
-  // This invocation must precede any calls to allowScripts(), allowImages(), or
-  // allowPlugins() for the new page. This ensures that when these functions
-  // send ViewHostMsg_ContentBlocked messages, those arrive after the browser
-  // process has already been informed of the provisional load committing.
-  GetFrameHost()->DidCommitProvisionalLoad(
-      std::move(params), std::move(remote_interface_provider_request));
-
-  // If we end up reusing this WebRequest (for example, due to a #ref click),
-  // we don't want the transition type to persist.  Just clear it.
-  navigation_state->set_transition_type(ui::PAGE_TRANSITION_LINK);
+  return params;
 }
 
 void RenderFrameImpl::UpdateZoomLevel() {
@@ -5602,6 +5608,18 @@
   return is_new_navigation;
 }
 
+void RenderFrameImpl::NotifyObserversOfNavigationCommit(bool is_new_navigation,
+                                                        bool is_same_document) {
+  for (auto& observer : render_view_->observers_)
+    observer.DidCommitProvisionalLoad(frame_, is_new_navigation);
+  {
+    SCOPED_UMA_HISTOGRAM_TIMER("RenderFrameObservers.DidCommitProvisionalLoad");
+    for (auto& observer : observers_) {
+      observer.DidCommitProvisionalLoad(is_new_navigation, is_same_document);
+    }
+  }
+}
+
 bool RenderFrameImpl::SwapIn() {
   CHECK_NE(proxy_routing_id_, MSG_ROUTING_NONE);
   CHECK(!in_frame_tree_);
diff --git a/content/renderer/render_frame_impl.h b/content/renderer/render_frame_impl.h
index 5030ef9..289acc8 100644
--- a/content/renderer/render_frame_impl.h
+++ b/content/renderer/render_frame_impl.h
@@ -1259,6 +1259,10 @@
   // Whether or not the frame is controlled by a service worker.
   bool IsControlledByServiceWorker();
 
+  // Build DidCommitProvisionalLoad_Params based on the frame internal state.
+  std::unique_ptr<FrameHostMsg_DidCommitProvisionalLoad_Params>
+  MakeDidCommitProvisionalLoadParams(blink::WebHistoryCommitType commit_type);
+
   mojom::URLLoaderFactory* custom_url_loader_factory() {
     return custom_url_loader_factory_.get();
   }
@@ -1273,6 +1277,10 @@
   bool UpdateNavigationHistory(const blink::WebHistoryItem& item,
                                blink::WebHistoryCommitType commit_type);
 
+  // Notify render_view_ observers that a commit happened.
+  void NotifyObserversOfNavigationCommit(bool is_new_navigation,
+                                         bool is_same_document);
+
   // Stores the WebLocalFrame we are associated with.  This is null from the
   // constructor until BindToFrame() is called, and it is null after
   // FrameDetached() is called until destruction (which is asynchronous in the
diff --git a/content/renderer/service_worker/service_worker_context_client.cc b/content/renderer/service_worker/service_worker_context_client.cc
index a3792e15..f78d0d8 100644
--- a/content/renderer/service_worker/service_worker_context_client.cc
+++ b/content/renderer/service_worker/service_worker_context_client.cc
@@ -206,19 +206,20 @@
                            Referrer::NetReferrerPolicyToBlinkReferrerPolicy(
                                request.referrer_policy));
   web_request->SetMode(request.fetch_request_mode);
-  web_request->SetIsMainResourceLoad(
-      ServiceWorkerUtils::IsMainResourceType(request.resource_type));
+  web_request->SetIsMainResourceLoad(ServiceWorkerUtils::IsMainResourceType(
+      static_cast<ResourceType>(request.resource_type)));
   web_request->SetCredentialsMode(request.fetch_credentials_mode);
   web_request->SetCacheMode(
       ServiceWorkerFetchRequest::GetCacheModeFromLoadFlags(request.load_flags));
-  web_request->SetRedirectMode(
-      GetBlinkFetchRedirectMode(request.fetch_redirect_mode));
-  web_request->SetRequestContext(
-      GetBlinkRequestContext(request.fetch_request_context_type));
+  web_request->SetRedirectMode(GetBlinkFetchRedirectMode(
+      static_cast<FetchRedirectMode>(request.fetch_redirect_mode)));
+  web_request->SetRequestContext(GetBlinkRequestContext(
+      static_cast<RequestContextType>(request.fetch_request_context_type)));
   web_request->SetFrameType(request.fetch_frame_type);
   // TODO(falken): Set client id. The browser needs to pass it to us.
   web_request->SetIsReload(ui::PageTransitionCoreTypeIs(
-      request.transition_type, ui::PAGE_TRANSITION_RELOAD));
+      static_cast<ui::PageTransition>(request.transition_type),
+      ui::PAGE_TRANSITION_RELOAD));
   web_request->SetIntegrity(
       blink::WebString::FromUTF8(request.fetch_integrity));
 }
diff --git a/content/renderer/service_worker/service_worker_subresource_loader.cc b/content/renderer/service_worker/service_worker_subresource_loader.cc
index f2bf7ae..bd9392c 100644
--- a/content/renderer/service_worker/service_worker_subresource_loader.cc
+++ b/content/renderer/service_worker/service_worker_subresource_loader.cc
@@ -180,8 +180,8 @@
   DCHECK_EQ(Status::kNotStarted, status_);
   status_ = Status::kStarted;
 
-  DCHECK(
-      !ServiceWorkerUtils::IsMainResourceType(resource_request.resource_type));
+  DCHECK(!ServiceWorkerUtils::IsMainResourceType(
+      static_cast<ResourceType>(resource_request.resource_type)));
 
   DCHECK(!inflight_fetch_request_);
   inflight_fetch_request_ = std::make_unique<ResourceRequest>(resource_request);
diff --git a/content/renderer/service_worker/service_worker_subresource_loader_unittest.cc b/content/renderer/service_worker/service_worker_subresource_loader_unittest.cc
index 2e2dc82..d1638422 100644
--- a/content/renderer/service_worker/service_worker_subresource_loader_unittest.cc
+++ b/content/renderer/service_worker/service_worker_subresource_loader_unittest.cc
@@ -125,7 +125,8 @@
       const ResourceRequest& request,
       mojom::ServiceWorkerFetchResponseCallbackPtr response_callback,
       DispatchFetchEventCallback callback) override {
-    EXPECT_FALSE(ServiceWorkerUtils::IsMainResourceType(request.resource_type));
+    EXPECT_FALSE(ServiceWorkerUtils::IsMainResourceType(
+        static_cast<ResourceType>(request.resource_type)));
     request_body_ = request.request_body;
 
     fetch_event_count_++;
diff --git a/content/shell/android/BUILD.gn b/content/shell/android/BUILD.gn
index d379baa..ceb0fbf5 100644
--- a/content/shell/android/BUILD.gn
+++ b/content/shell/android/BUILD.gn
@@ -14,7 +14,6 @@
   jni_package = "content/shell"
   sources = [
     "java/src/org/chromium/content_shell/Shell.java",
-    "java/src/org/chromium/content_shell/ShellLayoutTestUtils.java",
     "java/src/org/chromium/content_shell/ShellManager.java",
   ]
 }
@@ -76,7 +75,6 @@
   ]
   java_files = [
     "java/src/org/chromium/content_shell/Shell.java",
-    "java/src/org/chromium/content_shell/ShellLayoutTestUtils.java",
     "java/src/org/chromium/content_shell/ShellManager.java",
     "java/src/org/chromium/content_shell/ShellViewAndroidDelegate.java",
   ]
diff --git a/content/shell/android/java/src/org/chromium/content_shell/ShellLayoutTestUtils.java b/content/shell/android/java/src/org/chromium/content_shell/ShellLayoutTestUtils.java
deleted file mode 100644
index d308591..0000000
--- a/content/shell/android/java/src/org/chromium/content_shell/ShellLayoutTestUtils.java
+++ /dev/null
@@ -1,23 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.content_shell;
-
-import org.chromium.base.annotations.CalledByNative;
-import org.chromium.base.annotations.JNINamespace;
-import org.chromium.base.test.util.UrlUtils;
-
-/**
- * Utility methods used by content_shell for running Blink's layout tests on Android.
- */
-@JNINamespace("content")
-class ShellLayoutTestUtils {
-    /**
-     * @return The directory in which test data is stored.
-     */
-    @CalledByNative
-    private static String getIsolatedTestRoot() {
-        return UrlUtils.getIsolatedTestRoot();
-    }
-}
diff --git a/content/shell/browser/layout_test/scoped_android_configuration.cc b/content/shell/browser/layout_test/scoped_android_configuration.cc
index 69f506c..87702f4a 100644
--- a/content/shell/browser/layout_test/scoped_android_configuration.cc
+++ b/content/shell/browser/layout_test/scoped_android_configuration.cc
@@ -16,13 +16,13 @@
 #include "base/message_loop/message_loop.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/synchronization/waitable_event.h"
+#include "base/test/android/url_utils.h"
 #include "base/test/test_support_android.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/test/nested_message_pump_android.h"
 #include "content/shell/browser/layout_test/blink_test_controller.h"
 #include "content/shell/common/layout_test/layout_test_switches.h"
 #include "content/shell/common/shell_switches.h"
-#include "jni/ShellLayoutTestUtils_jni.h"
 #include "net/base/ip_address.h"
 #include "net/base/ip_endpoint.h"
 #include "net/base/net_errors.h"
@@ -129,12 +129,7 @@
 }  // namespace
 
 ScopedAndroidConfiguration::ScopedAndroidConfiguration() : sockets_() {
-  JNIEnv* env = base::android::AttachCurrentThread();
-  ScopedJavaLocalRef<jstring> jtest_data_dir =
-      Java_ShellLayoutTestUtils_getIsolatedTestRoot(env);
-  base::FilePath test_data_dir(
-      base::android::ConvertJavaStringToUTF8(env, jtest_data_dir));
-  base::InitAndroidTestPaths(test_data_dir);
+  base::InitAndroidTestPaths(base::android::GetIsolatedTestRoot());
 
   bool success =
       base::MessageLoop::InitMessagePumpForUIFactory(&CreateMessagePumpForUI);
diff --git a/content/test/BUILD.gn b/content/test/BUILD.gn
index 1897bed..ed1ac07d 100644
--- a/content/test/BUILD.gn
+++ b/content/test/BUILD.gn
@@ -999,7 +999,6 @@
     ]
     sources -= [
       "../browser/media/session/audio_focus_delegate_default_browsertest.cc",
-      "../browser/network_service_browsertest.cc",
       "../browser/network_service_restart_browsertest.cc",
       "../browser/pointer_lock_browsertest.cc",
       "../browser/pointer_lock_browsertest.h",
@@ -1789,7 +1788,10 @@
   }
 
   if (enable_library_cdms) {
-    sources += [ "../browser/media/cdm_storage_impl_unittest.cc" ]
+    sources += [
+      "../browser/media/cdm_storage_impl_unittest.cc",
+      "../browser/media/key_system_support_impl_unittest.cc",
+    ]
   }
 
   if (enable_webrtc) {
@@ -1838,6 +1840,7 @@
       "../renderer/media/webrtc/media_stream_video_webrtc_sink_unittest.cc",
       "../renderer/media/webrtc/peer_connection_dependency_factory_unittest.cc",
       "../renderer/media/webrtc/processed_local_audio_source_unittest.cc",
+      "../renderer/media/webrtc/rtc_rtp_sender_unittest.cc",
       "../renderer/media/webrtc/rtc_stats_unittest.cc",
       "../renderer/media/webrtc/stun_field_trial_unittest.cc",
       "../renderer/media/webrtc/two_keys_adapter_map_unittest.cc",
diff --git a/content/test/data/frame_tree/page_with_content_overlap_positioned_frame.html b/content/test/data/frame_tree/page_with_content_overlap_positioned_frame.html
new file mode 100644
index 0000000..af822d6
--- /dev/null
+++ b/content/test/data/frame_tree/page_with_content_overlap_positioned_frame.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+<style>
+iframe {
+  position:absolute;
+  top: 50px;
+  left: 50px;
+  width: 100px;
+  height: 100px;
+}
+
+div {
+  position: absolute;
+  top: 50px;
+  left: 50px;
+  width: 70px;
+  height: 20px;
+  background-color: red;
+  z-index: 100;
+}
+
+</style>
+<html>
+<body>
+<iframe src="/cross-site/baz.com/title1.html"></iframe>
+This page contains a positioned cross-origin iframe.
+<div>x</div>
+</body>
+</html>
diff --git a/device/geolocation/BUILD.gn b/device/geolocation/BUILD.gn
index b3673ae2..3da82acf 100644
--- a/device/geolocation/BUILD.gn
+++ b/device/geolocation/BUILD.gn
@@ -53,7 +53,6 @@
     "wifi_data_provider_manager.h",
     "wifi_data_provider_win.cc",
     "wifi_data_provider_win.h",
-    "wifi_polling_policy.cc",
     "wifi_polling_policy.h",
   ]
 
diff --git a/device/geolocation/wifi_data_provider_chromeos.cc b/device/geolocation/wifi_data_provider_chromeos.cc
index b53d30ee..b4b4f1a 100644
--- a/device/geolocation/wifi_data_provider_chromeos.cc
+++ b/device/geolocation/wifi_data_provider_chromeos.cc
@@ -36,16 +36,20 @@
 void WifiDataProviderChromeOs::StartDataProvider() {
   DCHECK(CalledOnClientThread());
 
-  if (!WifiPollingPolicy::IsInitialized())
-    WifiPollingPolicy::Initialize(CreatePollingPolicy());
-  DCHECK(WifiPollingPolicy::IsInitialized());
+  DCHECK(polling_policy_ == nullptr);
+  polling_policy_.reset(
+      new GenericWifiPollingPolicy<kDefaultPollingIntervalMilliseconds,
+                                   kNoChangePollingIntervalMilliseconds,
+                                   kTwoNoChangePollingIntervalMilliseconds,
+                                   kNoWifiPollingIntervalMilliseconds>);
 
-  ScheduleStart(WifiPollingPolicy::Get()->PollingInterval());
+  ScheduleStart();
 }
 
 void WifiDataProviderChromeOs::StopDataProvider() {
   DCHECK(CalledOnClientThread());
 
+  polling_policy_.reset();
   ScheduleStop();
 }
 
@@ -79,7 +83,7 @@
   // Schedule next scan if started (StopDataProvider could have been called
   // in between DoWifiScanTaskOnNetworkHandlerThread and this method).
   if (started_)
-    ScheduleNextScan(WifiPollingPolicy::Get()->NoWifiInterval());
+    ScheduleNextScan(polling_policy_->NoWifiInterval());
 }
 
 void WifiDataProviderChromeOs::DidWifiScanTask(const WifiData& new_data) {
@@ -89,8 +93,8 @@
   // Schedule next scan if started (StopDataProvider could have been called
   // in between DoWifiScanTaskOnNetworkHandlerThread and this method).
   if (started_) {
-    WifiPollingPolicy::Get()->UpdatePollingInterval(update_available);
-    ScheduleNextScan(WifiPollingPolicy::Get()->PollingInterval());
+    polling_policy_->UpdatePollingInterval(update_available);
+    ScheduleNextScan(polling_policy_->PollingInterval());
   }
 
   if (update_available || !is_first_scan_complete_) {
@@ -120,7 +124,7 @@
   started_ = false;
 }
 
-void WifiDataProviderChromeOs::ScheduleStart(int interval) {
+void WifiDataProviderChromeOs::ScheduleStart() {
   DCHECK(CalledOnClientThread());
   DCHECK(!started_);
   if (!NetworkHandler::IsInitialized()) {
@@ -128,12 +132,13 @@
     return;
   }
   started_ = true;
-  NetworkHandler::Get()->task_runner()->PostDelayedTask(
+  // Perform first scan ASAP regardless of the polling policy. If this scan
+  // fails we'll retry at a rate in line with the polling policy.
+  NetworkHandler::Get()->task_runner()->PostTask(
       FROM_HERE,
       base::Bind(
           &WifiDataProviderChromeOs::DoWifiScanTaskOnNetworkHandlerThread,
-          this),
-      base::TimeDelta::FromMilliseconds(interval));
+          this));
 }
 
 bool WifiDataProviderChromeOs::GetAccessPointData(
@@ -171,14 +176,6 @@
   return true;
 }
 
-std::unique_ptr<WifiPollingPolicy>
-WifiDataProviderChromeOs::CreatePollingPolicy() {
-  return std::make_unique<GenericWifiPollingPolicy<
-      kDefaultPollingIntervalMilliseconds, kNoChangePollingIntervalMilliseconds,
-      kTwoNoChangePollingIntervalMilliseconds,
-      kNoWifiPollingIntervalMilliseconds>>();
-}
-
 // static
 WifiDataProvider* WifiDataProviderManager::DefaultFactoryFunction() {
   return new WifiDataProviderChromeOs();
diff --git a/device/geolocation/wifi_data_provider_chromeos.h b/device/geolocation/wifi_data_provider_chromeos.h
index 09fcff8..f9630f6f 100644
--- a/device/geolocation/wifi_data_provider_chromeos.h
+++ b/device/geolocation/wifi_data_provider_chromeos.h
@@ -39,7 +39,7 @@
   void ScheduleNextScan(int interval);
 
   // Will schedule starting of the scanning process.
-  void ScheduleStart(int interval);
+  void ScheduleStart();
 
   // Will schedule stopping of the scanning process.
   void ScheduleStop();
@@ -47,8 +47,8 @@
   // Get access point data from chromeos.
   bool GetAccessPointData(WifiData::AccessPointDataSet* data);
 
-  // Create the policy for controlling the polling update interval.
-  std::unique_ptr<WifiPollingPolicy> CreatePollingPolicy();
+  // Controls the polling update interval. (client thread)
+  std::unique_ptr<WifiPollingPolicy> polling_policy_;
 
   // The latest wifi data. (client thread)
   WifiData wifi_data_;
diff --git a/device/geolocation/wifi_data_provider_common.cc b/device/geolocation/wifi_data_provider_common.cc
index 2343b65..0084432 100644
--- a/device/geolocation/wifi_data_provider_common.cc
+++ b/device/geolocation/wifi_data_provider_common.cc
@@ -35,15 +35,18 @@
     return;
   }
 
-  if (!WifiPollingPolicy::IsInitialized())
-    WifiPollingPolicy::Initialize(CreatePollingPolicy());
-  DCHECK(WifiPollingPolicy::IsInitialized());
+  DCHECK(!polling_policy_);
+  polling_policy_ = CreatePollingPolicy();
+  DCHECK(polling_policy_);
 
-  ScheduleNextScan(WifiPollingPolicy::Get()->PollingInterval());
+  // Perform first scan ASAP regardless of the polling policy. If this scan
+  // fails we'll retry at a rate in line with the polling policy.
+  ScheduleNextScan(0);
 }
 
 void WifiDataProviderCommon::StopDataProvider() {
   wlan_api_.reset();
+  polling_policy_.reset();
 }
 
 bool WifiDataProviderCommon::GetData(WifiData* data) {
@@ -57,12 +60,12 @@
   bool update_available = false;
   WifiData new_data;
   if (!wlan_api_->GetAccessPointData(&new_data.access_point_data)) {
-    ScheduleNextScan(WifiPollingPolicy::Get()->NoWifiInterval());
+    ScheduleNextScan(polling_policy_->NoWifiInterval());
   } else {
     update_available = wifi_data_.DiffersSignificantly(new_data);
     wifi_data_ = new_data;
-    WifiPollingPolicy::Get()->UpdatePollingInterval(update_available);
-    ScheduleNextScan(WifiPollingPolicy::Get()->PollingInterval());
+    polling_policy_->UpdatePollingInterval(update_available);
+    ScheduleNextScan(polling_policy_->PollingInterval());
   }
   if (update_available || !is_first_scan_complete_) {
     is_first_scan_complete_ = true;
diff --git a/device/geolocation/wifi_data_provider_common.h b/device/geolocation/wifi_data_provider_common.h
index ad39a54e..44a312c 100644
--- a/device/geolocation/wifi_data_provider_common.h
+++ b/device/geolocation/wifi_data_provider_common.h
@@ -72,6 +72,9 @@
   // Underlying OS wifi API.
   std::unique_ptr<WlanApiInterface> wlan_api_;
 
+  // Controls the polling update interval.
+  std::unique_ptr<WifiPollingPolicy> polling_policy_;
+
   // Holder for delayed tasks; takes care of cleanup.
   base::WeakPtrFactory<WifiDataProviderCommon> weak_factory_;
 
diff --git a/device/geolocation/wifi_data_provider_common_unittest.cc b/device/geolocation/wifi_data_provider_common_unittest.cc
index 7db568f..ec20a12 100644
--- a/device/geolocation/wifi_data_provider_common_unittest.cc
+++ b/device/geolocation/wifi_data_provider_common_unittest.cc
@@ -14,7 +14,6 @@
 #include "base/third_party/dynamic_annotations/dynamic_annotations.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "device/geolocation/wifi_data_provider_manager.h"
-#include "device/geolocation/wifi_polling_policy.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -61,8 +60,7 @@
 class WifiDataProviderCommonWithMock : public WifiDataProviderCommon {
  public:
   WifiDataProviderCommonWithMock()
-      : wlan_api_(new MockWlanApi),
-        polling_policy_(std::make_unique<MockPollingPolicy>()) {}
+      : wlan_api_(new MockWlanApi), polling_policy_(new MockPollingPolicy) {}
 
   // WifiDataProviderCommon
   std::unique_ptr<WlanApiInterface> CreateWlanApi() override {
@@ -99,7 +97,6 @@
   void TearDown() override {
     provider_->RemoveCallback(&wifi_data_callback_);
     provider_->StopDataProvider();
-    WifiPollingPolicy::Shutdown();
   }
 
  protected:
diff --git a/device/geolocation/wifi_polling_policy.cc b/device/geolocation/wifi_polling_policy.cc
deleted file mode 100644
index 01deed3..0000000
--- a/device/geolocation/wifi_polling_policy.cc
+++ /dev/null
@@ -1,38 +0,0 @@
-// Copyright 2018 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 "device/geolocation/wifi_polling_policy.h"
-
-namespace device {
-
-namespace {
-// Leaks at exit.
-WifiPollingPolicy* g_wifi_polling_policy;
-}  // namespace
-
-// static
-void WifiPollingPolicy::Initialize(std::unique_ptr<WifiPollingPolicy> policy) {
-  DCHECK(!g_wifi_polling_policy);
-  g_wifi_polling_policy = policy.release();
-}
-
-// static
-void WifiPollingPolicy::Shutdown() {
-  if (g_wifi_polling_policy)
-    delete g_wifi_polling_policy;
-  g_wifi_polling_policy = nullptr;
-}
-
-// static
-WifiPollingPolicy* WifiPollingPolicy::Get() {
-  DCHECK(g_wifi_polling_policy);
-  return g_wifi_polling_policy;
-}
-
-// static
-bool WifiPollingPolicy::IsInitialized() {
-  return g_wifi_polling_policy != nullptr;
-}
-
-}  // namespace device
diff --git a/device/geolocation/wifi_polling_policy.h b/device/geolocation/wifi_polling_policy.h
index 226b3852..0ac9203 100644
--- a/device/geolocation/wifi_polling_policy.h
+++ b/device/geolocation/wifi_polling_policy.h
@@ -5,36 +5,21 @@
 #ifndef DEVICE_GEOLOCATION_WIFI_POLLING_POLICY_H_
 #define DEVICE_GEOLOCATION_WIFI_POLLING_POLICY_H_
 
-#include <memory>
-
 #include "base/macros.h"
-#include "base/time/time.h"
-#include "device/geolocation/geolocation_export.h"
 
 namespace device {
 
 // Allows sharing and mocking of the update polling policy function.
-class DEVICE_GEOLOCATION_EXPORT WifiPollingPolicy {
+class WifiPollingPolicy {
  public:
-  virtual ~WifiPollingPolicy() = default;
-
-  // Methods for managing the single instance of WifiPollingPolicy. The WiFi
-  // policy is global so it can outlive the WifiDataProvider instance, which is
-  // shut down and destroyed when no WiFi scanning is active.
-  static void Initialize(std::unique_ptr<WifiPollingPolicy>);
-  static void Shutdown();
-  static WifiPollingPolicy* Get();
-  static bool IsInitialized();
-
+  WifiPollingPolicy() {}
+  virtual ~WifiPollingPolicy() {}
   // Calculates the new polling interval for wiFi scans, given the previous
   // interval and whether the last scan produced new results.
   virtual void UpdatePollingInterval(bool scan_results_differ) = 0;
   virtual int PollingInterval() = 0;
   virtual int NoWifiInterval() = 0;
 
- protected:
-  WifiPollingPolicy() = default;
-
  private:
   DISALLOW_COPY_AND_ASSIGN(WifiPollingPolicy);
 };
@@ -48,7 +33,6 @@
 class GenericWifiPollingPolicy : public WifiPollingPolicy {
  public:
   GenericWifiPollingPolicy() : polling_interval_(DEFAULT_INTERVAL) {}
-
   // WifiPollingPolicy
   void UpdatePollingInterval(bool scan_results_differ) override {
     if (scan_results_differ) {
@@ -61,37 +45,11 @@
       polling_interval_ = TWO_NO_CHANGE_INTERVAL;
     }
   }
-  int PollingInterval() override { return ComputeInterval(polling_interval_); }
-  int NoWifiInterval() override { return ComputeInterval(NO_WIFI_INTERVAL); }
+  int PollingInterval() override { return polling_interval_; }
+  int NoWifiInterval() override { return NO_WIFI_INTERVAL; }
 
  private:
-  int ComputeInterval(int polling_interval) {
-    base::Time now = base::Time::Now();
-
-    int64_t remaining_millis = 0;
-    if (!next_scan_.is_null()) {
-      // Compute the remaining duration of the current interval. If the interval
-      // is not yet complete, we will schedule a scan to occur once it is.
-      base::TimeDelta remaining = next_scan_ - now;
-      remaining_millis = remaining.InMilliseconds();
-    }
-
-    // If the current interval is complete (or if this is our first scan), scan
-    // now and schedule the next scan to occur at |polling_interval|
-    // milliseconds into the future.
-    if (remaining_millis <= 0) {
-      next_scan_ = now + base::TimeDelta::FromMilliseconds(polling_interval);
-      remaining_millis = 0;
-    }
-
-    return remaining_millis;
-  }
-
   int polling_interval_;
-
-  // The scheduled time of the next scan, or a null value if no scan has
-  // occurred yet.
-  base::Time next_scan_;
 };
 
 }  // namespace device
diff --git a/device/u2f/BUILD.gn b/device/u2f/BUILD.gn
index 07b8811..4c514fa2 100644
--- a/device/u2f/BUILD.gn
+++ b/device/u2f/BUILD.gn
@@ -23,6 +23,10 @@
     "public_key.h",
     "register_response_data.cc",
     "register_response_data.h",
+    "response_data.cc",
+    "response_data.h",
+    "sign_response_data.cc",
+    "sign_response_data.h",
     "u2f_apdu_command.cc",
     "u2f_apdu_command.h",
     "u2f_apdu_response.cc",
@@ -140,6 +144,19 @@
   libfuzzer_options = [ "max_len=65535" ]
 }
 
+fuzzer_test("sign_response_data_fuzzer") {
+  sources = [
+    "sign_response_data_fuzzer.cc",
+  ]
+  deps = [
+    ":u2f",
+    "//base",
+    "//net",
+  ]
+  seed_corpus = "response_data_fuzzer_corpus/"
+  libfuzzer_options = [ "max_len=65537" ]
+}
+
 is_linux_without_udev = is_linux && !use_udev
 
 source_set("test_support") {
diff --git a/device/u2f/authenticator_data.cc b/device/u2f/authenticator_data.cc
index 67c32dc..205ee63 100644
--- a/device/u2f/authenticator_data.cc
+++ b/device/u2f/authenticator_data.cc
@@ -11,19 +11,11 @@
 
 namespace device {
 
-// static
-AuthenticatorData AuthenticatorData::Create(std::string relying_party_id,
-                                            uint8_t flags,
-                                            std::vector<uint8_t> counter,
-                                            AttestedCredentialData data) {
-  return AuthenticatorData(std::move(relying_party_id), flags,
-                           std::move(counter), std::move(data));
-}
-
-AuthenticatorData::AuthenticatorData(std::string relying_party_id,
-                                     uint8_t flags,
-                                     std::vector<uint8_t> counter,
-                                     AttestedCredentialData data)
+AuthenticatorData::AuthenticatorData(
+    std::string relying_party_id,
+    uint8_t flags,
+    std::vector<uint8_t> counter,
+    base::Optional<AttestedCredentialData> data)
     : relying_party_id_(std::move(relying_party_id)),
       flags_(flags),
       counter_(std::move(counter)),
@@ -46,9 +38,12 @@
   u2f_parsing_utils::Append(&authenticator_data, rp_id_hash);
   authenticator_data.insert(authenticator_data.end(), flags_);
   u2f_parsing_utils::Append(&authenticator_data, counter_);
-  std::vector<uint8_t> attestation_bytes = attested_data_.SerializeAsBytes();
-  u2f_parsing_utils::Append(&authenticator_data, attestation_bytes);
-
+  if (attested_data_) {
+    // Attestations are returned in registration responses but not in assertion
+    // responses.
+    u2f_parsing_utils::Append(&authenticator_data,
+                              attested_data_->SerializeAsBytes());
+  }
   return authenticator_data;
 }
 
diff --git a/device/u2f/authenticator_data.h b/device/u2f/authenticator_data.h
index b39061d..c92aed6 100644
--- a/device/u2f/authenticator_data.h
+++ b/device/u2f/authenticator_data.h
@@ -10,6 +10,7 @@
 #include <vector>
 
 #include "base/macros.h"
+#include "base/optional.h"
 #include "device/u2f/attested_credential_data.h"
 
 namespace device {
@@ -22,15 +23,10 @@
     kAttestation = 1u << 6
   };
 
-  static AuthenticatorData Create(std::string relying_party_id,
-                                  uint8_t flags,
-                                  std::vector<uint8_t> counter,
-                                  AttestedCredentialData data);
-
   AuthenticatorData(std::string relying_party_id,
                     uint8_t flags,
                     std::vector<uint8_t> counter,
-                    AttestedCredentialData data);
+                    base::Optional<AttestedCredentialData> data);
 
   // Moveable.
   AuthenticatorData(AuthenticatorData&& other);
@@ -59,8 +55,7 @@
 
   // Signature counter, 32-bit unsigned big-endian integer.
   std::vector<uint8_t> counter_;
-
-  AttestedCredentialData attested_data_;
+  base::Optional<AttestedCredentialData> attested_data_;
 
   DISALLOW_COPY_AND_ASSIGN(AuthenticatorData);
 };
diff --git a/device/u2f/register_response_data.cc b/device/u2f/register_response_data.cc
index 6624663..3cc7dbca 100644
--- a/device/u2f/register_response_data.cc
+++ b/device/u2f/register_response_data.cc
@@ -6,7 +6,7 @@
 
 #include <utility>
 
-#include "base/base64url.h"
+#include "base/optional.h"
 #include "device/u2f/attestation_object.h"
 #include "device/u2f/attested_credential_data.h"
 #include "device/u2f/authenticator_data.h"
@@ -19,7 +19,7 @@
 // static
 RegisterResponseData RegisterResponseData::CreateFromU2fRegisterResponse(
     std::string relying_party_id,
-    std::vector<uint8_t> u2f_data) {
+    const std::vector<uint8_t>& u2f_data) {
   std::unique_ptr<ECPublicKey> public_key =
       ECPublicKey::ExtractFromU2fRegistrationResponse(u2f_parsing_utils::kEs256,
                                                       u2f_data);
@@ -42,12 +42,12 @@
       static_cast<uint8_t>(AuthenticatorData::Flag::kTestOfUserPresence) |
       static_cast<uint8_t>(AuthenticatorData::Flag::kAttestation);
 
-  auto authenticator_data = AuthenticatorData::Create(
-      std::move(relying_party_id), flags, std::move(counter),
-      std::move(attested_credential_data));
+  AuthenticatorData authenticator_data(std::move(relying_party_id), flags,
+                                       std::move(counter),
+                                       std::move(attested_credential_data));
 
   // Construct the attestation statement.
-  std::unique_ptr<FidoAttestationStatement> fido_attestation_statement =
+  auto fido_attestation_statement =
       FidoAttestationStatement::CreateFromU2fRegisterResponse(u2f_data);
 
   // Construct the attestation object.
@@ -63,7 +63,7 @@
 RegisterResponseData::RegisterResponseData(
     std::vector<uint8_t> credential_id,
     std::unique_ptr<AttestationObject> object)
-    : raw_id_(std::move(credential_id)),
+    : ResponseData(std::move(credential_id)),
       attestation_object_(std::move(object)) {}
 
 RegisterResponseData::RegisterResponseData(RegisterResponseData&& other) =
@@ -79,13 +79,4 @@
   return attestation_object_->SerializeToCBOREncodedBytes();
 }
 
-std::string RegisterResponseData::GetId() const {
-  std::string id;
-  base::Base64UrlEncode(
-      base::StringPiece(reinterpret_cast<const char*>(raw_id_.data()),
-                        raw_id_.size()),
-      base::Base64UrlEncodePolicy::OMIT_PADDING, &id);
-  return id;
-}
-
 }  // namespace device
diff --git a/device/u2f/register_response_data.h b/device/u2f/register_response_data.h
index 8aec955..d7e6631 100644
--- a/device/u2f/register_response_data.h
+++ b/device/u2f/register_response_data.h
@@ -11,20 +11,18 @@
 #include <vector>
 
 #include "base/macros.h"
+#include "device/u2f/response_data.h"
 
 namespace device {
 
 class AttestationObject;
 
-// See figure 2:
-// https://fidoalliance.org/specs/fido-v2.0-rd-20170927/ \
-// fido-client-to-authenticator-protocol-v2.0-rd-20170927.html#using-the- \
-// ctap2-authenticatormakecredential-command-with-ctap1-u2f-authenticators
-class RegisterResponseData {
+// See figure 2: https://goo.gl/rsgvXk
+class RegisterResponseData : public ResponseData {
  public:
   static RegisterResponseData CreateFromU2fRegisterResponse(
       std::string relying_party_id,
-      std::vector<uint8_t> u2f_data);
+      const std::vector<uint8_t>& u2f_data);
 
   RegisterResponseData();
 
@@ -37,12 +35,9 @@
 
   ~RegisterResponseData();
 
-  std::string GetId() const;
   std::vector<uint8_t> GetCBOREncodedAttestationObject() const;
-  const std::vector<uint8_t>& raw_id() const { return raw_id_; }
 
  private:
-  std::vector<uint8_t> raw_id_;
   std::unique_ptr<AttestationObject> attestation_object_;
 
   DISALLOW_COPY_AND_ASSIGN(RegisterResponseData);
diff --git a/device/u2f/response_data.cc b/device/u2f/response_data.cc
new file mode 100644
index 0000000..f3ebd523
--- /dev/null
+++ b/device/u2f/response_data.cc
@@ -0,0 +1,34 @@
+// 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 "device/u2f/response_data.h"
+
+#include <utility>
+
+#include "base/base64url.h"
+#include "base/strings/string_piece.h"
+
+namespace device {
+
+ResponseData::ResponseData() = default;
+
+ResponseData::ResponseData(std::vector<uint8_t> credential_id)
+    : raw_id_(std::move(credential_id)) {}
+
+ResponseData::ResponseData(ResponseData&& other) = default;
+
+ResponseData& ResponseData::operator=(ResponseData&& other) = default;
+
+ResponseData::~ResponseData() = default;
+
+std::string ResponseData::GetId() const {
+  std::string id;
+  base::Base64UrlEncode(
+      base::StringPiece(reinterpret_cast<const char*>(raw_id_.data()),
+                        raw_id_.size()),
+      base::Base64UrlEncodePolicy::OMIT_PADDING, &id);
+  return id;
+}
+
+}  // namespace device
diff --git a/device/u2f/response_data.h b/device/u2f/response_data.h
new file mode 100644
index 0000000..24b3ea3
--- /dev/null
+++ b/device/u2f/response_data.h
@@ -0,0 +1,42 @@
+// 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 DEVICE_U2F_RESPONSE_DATA_H_
+#define DEVICE_U2F_RESPONSE_DATA_H_
+
+#include <stdint.h>
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "base/macros.h"
+
+namespace device {
+
+// Base class for RegisterResponseData and SignResponseData.
+class ResponseData {
+ public:
+  std::string GetId() const;
+  const std::vector<uint8_t>& raw_id() const { return raw_id_; }
+
+ protected:
+  explicit ResponseData(std::vector<uint8_t> credential_id);
+
+  ResponseData();
+
+  // Moveable.
+  ResponseData(ResponseData&& other);
+  ResponseData& operator=(ResponseData&& other);
+
+  ~ResponseData();
+
+  std::vector<uint8_t> raw_id_;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(ResponseData);
+};
+
+}  // namespace device
+
+#endif  // DEVICE_U2F_RESPONSE_DATA_H_
diff --git a/device/u2f/response_data_fuzzer_corpus/sign0 b/device/u2f/response_data_fuzzer_corpus/sign0
new file mode 100644
index 0000000..41be68d
--- /dev/null
+++ b/device/u2f/response_data_fuzzer_corpus/sign0
@@ -0,0 +1 @@
+‰¯µ$‘@+tYÉò!¯æåVe…è[IMUUôj¼D{üba¥þëåŸ^Üu2˜oDi×öëªê3ûՎ¿Æ	
\ No newline at end of file
diff --git a/device/u2f/response_data_fuzzer_corpus/sign1 b/device/u2f/response_data_fuzzer_corpus/sign1
new file mode 100644
index 0000000..6d8cc24
--- /dev/null
+++ b/device/u2f/response_data_fuzzer_corpus/sign1
Binary files differ
diff --git a/device/u2f/sign_response_data.cc b/device/u2f/sign_response_data.cc
new file mode 100644
index 0000000..2d4f57385
--- /dev/null
+++ b/device/u2f/sign_response_data.cc
@@ -0,0 +1,71 @@
+// 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 "device/u2f/sign_response_data.h"
+
+#include <utility>
+
+#include "base/optional.h"
+#include "device/u2f/u2f_parsing_utils.h"
+
+namespace device {
+
+constexpr size_t kFlagIndex = 0;
+constexpr size_t kFlagLength = 1;
+constexpr size_t kCounterIndex = 1;
+constexpr size_t kCounterLength = 4;
+constexpr size_t kSignatureIndex = 5;
+
+// static
+base::Optional<SignResponseData> SignResponseData::CreateFromU2fSignResponse(
+    const std::string& relying_party_id,
+    const std::vector<uint8_t>& u2f_data,
+    const std::vector<uint8_t>& key_handle) {
+  if (key_handle.empty())
+    return base::nullopt;
+
+  std::vector<uint8_t> flags =
+      u2f_parsing_utils::Extract(u2f_data, kFlagIndex, kFlagLength);
+  if (flags.empty())
+    return base::nullopt;
+
+  // Extract the 4-byte counter following the flag byte.
+  std::vector<uint8_t> counter =
+      u2f_parsing_utils::Extract(u2f_data, kCounterIndex, kCounterLength);
+  if (counter.empty())
+    return base::nullopt;
+
+  // Construct the authenticator data.
+  AuthenticatorData authenticator_data(relying_party_id, flags[0],
+                                       std::move(counter), base::nullopt);
+
+  // Extract the signature from the remainder of the U2fResponse bytes.
+  std::vector<uint8_t> signature = u2f_parsing_utils::Extract(
+      u2f_data, kSignatureIndex, u2f_data.size() - kSignatureIndex);
+  if (signature.empty())
+    return base::nullopt;
+
+  return SignResponseData(std::move(key_handle), std::move(authenticator_data),
+                          std::move(signature));
+}
+
+SignResponseData::SignResponseData(std::vector<uint8_t> credential_id,
+                                   AuthenticatorData authenticator_data,
+                                   std::vector<uint8_t> signature)
+    : ResponseData(std::move(credential_id)),
+      authenticator_data_(std::move(authenticator_data)),
+      signature_(std::move(signature)) {}
+
+SignResponseData::SignResponseData(SignResponseData&& other) = default;
+
+SignResponseData& SignResponseData::operator=(SignResponseData&& other) =
+    default;
+
+SignResponseData::~SignResponseData() = default;
+
+std::vector<uint8_t> SignResponseData::GetAuthenticatorDataBytes() const {
+  return authenticator_data_.SerializeToByteArray();
+}
+
+}  // namespace device
diff --git a/device/u2f/sign_response_data.h b/device/u2f/sign_response_data.h
new file mode 100644
index 0000000..34ce7862
--- /dev/null
+++ b/device/u2f/sign_response_data.h
@@ -0,0 +1,49 @@
+// 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 DEVICE_U2F_SIGN_RESPONSE_DATA_H_
+#define DEVICE_U2F_SIGN_RESPONSE_DATA_H_
+
+#include <stdint.h>
+#include <string>
+#include <vector>
+
+#include "base/macros.h"
+#include "device/u2f/authenticator_data.h"
+#include "device/u2f/response_data.h"
+
+namespace device {
+
+// Corresponds to a CTAP AuthenticatorGetAssertion response.
+// See mapping from a U2F response to a CTAP response
+// at https://goo.gl/eZTacx.
+class SignResponseData : public ResponseData {
+ public:
+  static base::Optional<SignResponseData> CreateFromU2fSignResponse(
+      const std::string& relying_party_id,
+      const std::vector<uint8_t>& u2f_data,
+      const std::vector<uint8_t>& key_handle);
+
+  SignResponseData(std::vector<uint8_t> credential_id,
+                   AuthenticatorData authenticator_data,
+                   std::vector<uint8_t> signature);
+
+  SignResponseData(SignResponseData&& other);
+  SignResponseData& operator=(SignResponseData&& other);
+
+  ~SignResponseData();
+
+  std::vector<uint8_t> GetAuthenticatorDataBytes() const;
+  const std::vector<uint8_t>& signature() const { return signature_; }
+
+ private:
+  AuthenticatorData authenticator_data_;
+  std::vector<uint8_t> signature_;
+
+  DISALLOW_COPY_AND_ASSIGN(SignResponseData);
+};
+
+}  // namespace device
+
+#endif  // DEVICE_U2F_SIGN_RESPONSE_DATA_H_
diff --git a/device/u2f/sign_response_data_fuzzer.cc b/device/u2f/sign_response_data_fuzzer.cc
new file mode 100644
index 0000000..2fafa69
--- /dev/null
+++ b/device/u2f/sign_response_data_fuzzer.cc
@@ -0,0 +1,18 @@
+// 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 <stddef.h>
+#include <stdint.h>
+#include <vector>
+
+#include "base/optional.h"
+#include "device/u2f/sign_response_data.h"
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+  std::vector<uint8_t> u2f_response_data(data, data + size);
+  std::vector<uint8_t> key_handle(data, data + size);
+  auto response = device::SignResponseData::CreateFromU2fSignResponse(
+      "https://google.com", u2f_response_data, key_handle);
+  return 0;
+}
diff --git a/device/u2f/u2f_register.cc b/device/u2f/u2f_register.cc
index b41ae5fc..511fa8d 100644
--- a/device/u2f/u2f_register.cc
+++ b/device/u2f/u2f_register.cc
@@ -119,19 +119,20 @@
 void U2fRegister::OnTryDevice(bool is_duplicate_registration,
                               U2fReturnCode return_code,
                               const std::vector<uint8_t>& response_data) {
-  base::Optional<RegisterResponseData> response;
   switch (return_code) {
     case U2fReturnCode::SUCCESS:
       state_ = State::COMPLETE;
       if (is_duplicate_registration) {
-        return_code = U2fReturnCode::CONDITIONS_NOT_SATISFIED;
+        std::move(completion_callback_)
+            .Run(U2fReturnCode::CONDITIONS_NOT_SATISFIED, base::nullopt);
       } else {
         // TODO(kpaulhamus): Add fuzzers for the response parsers.
         // https://crbug.com/785957.
-        response = RegisterResponseData::CreateFromU2fRegisterResponse(
-            relying_party_id_, std::move(response_data));
+        std::move(completion_callback_)
+            .Run(U2fReturnCode::SUCCESS,
+                 RegisterResponseData::CreateFromU2fRegisterResponse(
+                     relying_party_id_, std::move(response_data)));
       }
-      std::move(completion_callback_).Run(return_code, std::move(response));
       break;
     case U2fReturnCode::CONDITIONS_NOT_SATISFIED:
       // Waiting for user touch, move on and try this device later.
diff --git a/device/u2f/u2f_register_unittest.cc b/device/u2f/u2f_register_unittest.cc
index 76a890e..c46faae 100644
--- a/device/u2f/u2f_register_unittest.cc
+++ b/device/u2f/u2f_register_unittest.cc
@@ -315,7 +315,8 @@
 };
 
 TEST_F(U2fRegisterTest, TestRegisterSuccess) {
-  std::unique_ptr<MockU2fDevice> device(std::make_unique<MockU2fDevice>());
+  auto device = std::make_unique<MockU2fDevice>();
+
   MockU2fDiscovery discovery;
 
   EXPECT_CALL(*device.get(), GetId())
@@ -342,7 +343,7 @@
 }
 
 TEST_F(U2fRegisterTest, TestDelayedSuccess) {
-  std::unique_ptr<MockU2fDevice> device(std::make_unique<MockU2fDevice>());
+  auto device = std::make_unique<MockU2fDevice>();
   MockU2fDiscovery discovery;
 
   EXPECT_CALL(*device.get(), GetId())
@@ -373,8 +374,8 @@
 
 TEST_F(U2fRegisterTest, TestMultipleDevices) {
   // Second device will have a successful touch
-  std::unique_ptr<MockU2fDevice> device0(std::make_unique<MockU2fDevice>());
-  std::unique_ptr<MockU2fDevice> device1(std::make_unique<MockU2fDevice>());
+  auto device0 = std::make_unique<MockU2fDevice>();
+  auto device1 = std::make_unique<MockU2fDevice>();
   MockU2fDiscovery discovery;
 
   EXPECT_CALL(*device0.get(), GetId())
@@ -419,7 +420,7 @@
   std::vector<uint8_t> unknown_key2(32, 0xD);
   std::vector<std::vector<uint8_t>> handles = {unknown_key0, unknown_key1,
                                                unknown_key2};
-  std::unique_ptr<MockU2fDevice> device(std::make_unique<MockU2fDevice>());
+  auto device = std::make_unique<MockU2fDevice>();
   MockU2fDiscovery discovery;
 
   EXPECT_CALL(*device.get(), GetId())
@@ -467,8 +468,8 @@
   std::vector<uint8_t> unknown_key2(32, 0xD);
   std::vector<std::vector<uint8_t>> handles = {unknown_key0, unknown_key1,
                                                unknown_key2};
-  std::unique_ptr<MockU2fDevice> device0(std::make_unique<MockU2fDevice>());
-  std::unique_ptr<MockU2fDevice> device1(std::make_unique<MockU2fDevice>());
+  auto device0 = std::make_unique<MockU2fDevice>();
+  auto device1 = std::make_unique<MockU2fDevice>();
   MockU2fDiscovery discovery;
 
   EXPECT_CALL(*device0.get(), GetId())
@@ -534,7 +535,7 @@
 
   std::vector<std::vector<uint8_t>> handles = {unknown_key0, unknown_key1,
                                                unknown_key2, duplicate_key};
-  std::unique_ptr<MockU2fDevice> device(std::make_unique<MockU2fDevice>());
+  auto device = std::make_unique<MockU2fDevice>();
   MockU2fDiscovery discovery;
 
   EXPECT_CALL(*device.get(), GetId())
@@ -583,8 +584,8 @@
   std::vector<uint8_t> duplicate_key(32, 0xA);
   std::vector<std::vector<uint8_t>> handles = {unknown_key0, unknown_key1,
                                                unknown_key2, duplicate_key};
-  std::unique_ptr<MockU2fDevice> device0(new MockU2fDevice());
-  std::unique_ptr<MockU2fDevice> device1(new MockU2fDevice());
+  auto device0 = std::make_unique<MockU2fDevice>();
+  auto device1 = std::make_unique<MockU2fDevice>();
   MockU2fDiscovery discovery;
 
   EXPECT_CALL(*device0.get(), GetId())
@@ -679,16 +680,16 @@
           u2f_parsing_utils::kEs256, GetTestRegisterResponse());
   AttestedCredentialData attested_data =
       AttestedCredentialData::CreateFromU2fRegisterResponse(
-          GetTestRegisterResponse(), std::vector<uint8_t>(16, 0) /* aaguid */,
+          GetTestRegisterResponse(), std::vector<uint8_t>(16) /* aaguid */,
           std::move(public_key));
 
-  uint8_t flags =
+  constexpr uint8_t flags =
       static_cast<uint8_t>(AuthenticatorData::Flag::kTestOfUserPresence) |
       static_cast<uint8_t>(AuthenticatorData::Flag::kAttestation);
 
-  auto authenticator_data = AuthenticatorData::Create(
-      kTestRelyingPartyId, flags, std::vector<uint8_t>(4, 0) /* counter */,
-      std::move(attested_data));
+  AuthenticatorData authenticator_data(kTestRelyingPartyId, flags,
+                                       std::vector<uint8_t>(4) /* counter */,
+                                       std::move(attested_data));
 
   EXPECT_EQ(GetTestAuthenticatorDataBytes(),
             authenticator_data.SerializeToByteArray());
@@ -701,15 +702,15 @@
           u2f_parsing_utils::kEs256, GetTestRegisterResponse());
   AttestedCredentialData attested_data =
       AttestedCredentialData::CreateFromU2fRegisterResponse(
-          GetTestRegisterResponse(), std::vector<uint8_t>(16, 0) /* aaguid */,
+          GetTestRegisterResponse(), std::vector<uint8_t>(16) /* aaguid */,
           std::move(public_key));
 
-  uint8_t flags =
+  constexpr uint8_t flags =
       static_cast<uint8_t>(AuthenticatorData::Flag::kTestOfUserPresence) |
       static_cast<uint8_t>(AuthenticatorData::Flag::kAttestation);
-  auto authenticator_data = AuthenticatorData::Create(
-      kTestRelyingPartyId, flags, std::vector<uint8_t>(4, 0) /* counter */,
-      std::move(attested_data));
+  AuthenticatorData authenticator_data(kTestRelyingPartyId, flags,
+                                       std::vector<uint8_t>(4) /* counter */,
+                                       std::move(attested_data));
 
   // Construct the attestation statement.
   std::unique_ptr<FidoAttestationStatement> fido_attestation_statement =
diff --git a/device/u2f/u2f_sign_unittest.cc b/device/u2f/u2f_sign_unittest.cc
index 912b72b..23a59ff4 100644
--- a/device/u2f/u2f_sign_unittest.cc
+++ b/device/u2f/u2f_sign_unittest.cc
@@ -4,16 +4,17 @@
 
 #include "device/u2f/u2f_sign.h"
 
-#include <list>
 #include <tuple>
 #include <utility>
 
 #include "base/run_loop.h"
 #include "base/test/scoped_task_environment.h"
-#include "base/test/test_io_thread.h"
+#include "device/u2f/authenticator_data.h"
 #include "device/u2f/mock_u2f_device.h"
 #include "device/u2f/mock_u2f_discovery.h"
+#include "device/u2f/sign_response_data.h"
 #include "device/u2f/u2f_response_test_data.h"
+#include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 using ::testing::_;
@@ -21,9 +22,75 @@
 namespace device {
 
 namespace {
+
 constexpr char kTestRelyingPartyId[] = "google.com";
+
+// Signature counter returned within the authenticator data.
+constexpr uint8_t kTestSignatureCounter[] = {0x00, 0x00, 0x00, 0x25};
+
+// Test data specific to GetAssertion/Sign.
+constexpr uint8_t kTestU2fSignResponse[] = {
+    0x01, 0x00, 0x00, 0x00, 0x25, 0x30, 0x45, 0x02, 0x21, 0x00, 0xCA,
+    0xA5, 0x3E, 0x91, 0x0D, 0xB7, 0x5E, 0xDE, 0xAF, 0x72, 0xCF, 0x9F,
+    0x6F, 0x54, 0xE5, 0x20, 0x5B, 0xBB, 0xB9, 0x2F, 0x0B, 0x9F, 0x7D,
+    0xC6, 0xF8, 0xD4, 0x7B, 0x19, 0x70, 0xED, 0xFE, 0xBC, 0x02, 0x20,
+    0x06, 0x32, 0x83, 0x65, 0x26, 0x4E, 0xBE, 0xFE, 0x35, 0x3C, 0x95,
+    0x91, 0xDF, 0xCE, 0x7D, 0x73, 0x15, 0x98, 0x64, 0xDF, 0xEA, 0xB7,
+    0x87, 0xF1, 0x5D, 0xF8, 0xA5, 0x97, 0xD0, 0x85, 0x0C, 0xA2};
+
+constexpr uint8_t kTestAssertionSignature[] = {
+    0x30, 0x45, 0x02, 0x21, 0x00, 0xCA, 0xA5, 0x3E, 0x91, 0x0D, 0xB7, 0x5E,
+    0xDE, 0xAF, 0x72, 0xCF, 0x9F, 0x6F, 0x54, 0xE5, 0x20, 0x5B, 0xBB, 0xB9,
+    0x2F, 0x0B, 0x9F, 0x7D, 0xC6, 0xF8, 0xD4, 0x7B, 0x19, 0x70, 0xED, 0xFE,
+    0xBC, 0x02, 0x20, 0x06, 0x32, 0x83, 0x65, 0x26, 0x4E, 0xBE, 0xFE, 0x35,
+    0x3C, 0x95, 0x91, 0xDF, 0xCE, 0x7D, 0x73, 0x15, 0x98, 0x64, 0xDF, 0xEA,
+    0xB7, 0x87, 0xF1, 0x5D, 0xF8, 0xA5, 0x97, 0xD0, 0x85, 0x0C, 0xA2};
+
+// The authenticator data for sign responses.
+constexpr uint8_t kTestSignAuthenticatorData[] = {
+    // clang-format off
+    // sha256 hash of kTestRelyingPartyId
+    0xD4, 0xC9, 0xD9, 0x02, 0x73, 0x26, 0x27, 0x1A, 0x89, 0xCE, 0x51,
+    0xFC, 0xAF, 0x32, 0x8E, 0xD6, 0x73, 0xF1, 0x7B, 0xE3, 0x34, 0x69,
+    0xFF, 0x97, 0x9E, 0x8A, 0xB8, 0xDD, 0x50, 0x1E, 0x66, 0x4F,
+    0x01,  // flags (TUP bit set)
+    0x00, 0x00, 0x00, 0x25  // counter
+    // clang-format on
+};
+
+std::vector<uint8_t> GetTestCredentialRawIdBytes() {
+  return std::vector<uint8_t>(std::begin(test_data::kTestCredentialRawIdBytes),
+                              std::end(test_data::kTestCredentialRawIdBytes));
 }
 
+std::vector<uint8_t> GetTestSignResponse() {
+  return std::vector<uint8_t>(std::begin(kTestU2fSignResponse),
+                              std::end(kTestU2fSignResponse));
+}
+
+std::vector<uint8_t> GetTestAuthenticatorData() {
+  return std::vector<uint8_t>(std::begin(kTestSignAuthenticatorData),
+                              std::end(kTestSignAuthenticatorData));
+}
+
+std::vector<uint8_t> GetTestAssertionSignature() {
+  return std::vector<uint8_t>(std::begin(kTestAssertionSignature),
+                              std::end(kTestAssertionSignature));
+}
+
+std::vector<uint8_t> GetTestSignatureCounter() {
+  return std::vector<uint8_t>(std::begin(kTestSignatureCounter),
+                              std::end(kTestSignatureCounter));
+}
+
+// Get a subset of the response for testing error handling.
+std::vector<uint8_t> GetTestCorruptedSignResponse(size_t length) {
+  return std::vector<uint8_t>(kTestU2fSignResponse,
+                              kTestU2fSignResponse + length);
+}
+
+}  // namespace
+
 class U2fSignTest : public testing::Test {
  public:
   U2fSignTest()
@@ -275,4 +342,57 @@
   EXPECT_TRUE(std::get<2>(response).empty());
 }
 
+TEST_F(U2fSignTest, TestAuthenticatorDataForSign) {
+  constexpr uint8_t flags =
+      static_cast<uint8_t>(AuthenticatorData::Flag::kTestOfUserPresence);
+
+  EXPECT_EQ(GetTestAuthenticatorData(),
+            AuthenticatorData(kTestRelyingPartyId, flags,
+                              GetTestSignatureCounter(), base::nullopt)
+                .SerializeToByteArray());
+}
+
+TEST_F(U2fSignTest, TestSignResponseData) {
+  base::Optional<SignResponseData> response =
+      SignResponseData::CreateFromU2fSignResponse(
+          kTestRelyingPartyId, GetTestSignResponse(),
+          GetTestCredentialRawIdBytes());
+  ASSERT_TRUE(response.has_value());
+  EXPECT_EQ(GetTestCredentialRawIdBytes(), response->raw_id());
+  EXPECT_EQ(GetTestAuthenticatorData(), response->GetAuthenticatorDataBytes());
+  EXPECT_EQ(GetTestAssertionSignature(), response->signature());
+}
+
+TEST_F(U2fSignTest, TestNullKeyHandle) {
+  base::Optional<SignResponseData> response =
+      SignResponseData::CreateFromU2fSignResponse(
+          kTestRelyingPartyId, GetTestSignResponse(), std::vector<uint8_t>());
+  EXPECT_EQ(base::nullopt, response);
+}
+
+TEST_F(U2fSignTest, TestNullResponse) {
+  base::Optional<SignResponseData> response =
+      SignResponseData::CreateFromU2fSignResponse(
+          kTestRelyingPartyId, std::vector<uint8_t>(),
+          GetTestCredentialRawIdBytes());
+  EXPECT_EQ(base::nullopt, response);
+}
+
+TEST_F(U2fSignTest, TestCorruptedCounter) {
+  // A sign response of less than 5 bytes.
+  base::Optional<SignResponseData> response =
+      SignResponseData::CreateFromU2fSignResponse(
+          kTestRelyingPartyId, GetTestCorruptedSignResponse(3),
+          GetTestCredentialRawIdBytes());
+  EXPECT_EQ(base::nullopt, response);
+}
+
+TEST_F(U2fSignTest, TestCorruptedSignature) {
+  // A sign response no more than 5 bytes.
+  base::Optional<SignResponseData> response =
+      SignResponseData::CreateFromU2fSignResponse(
+          kTestRelyingPartyId, GetTestCorruptedSignResponse(5),
+          GetTestCredentialRawIdBytes());
+  EXPECT_EQ(base::nullopt, response);
+}
 }  // namespace device
diff --git a/device/vr/android/gvr/gvr_device.cc b/device/vr/android/gvr/gvr_device.cc
index bdcb355..64b340b 100644
--- a/device/vr/android/gvr/gvr_device.cc
+++ b/device/vr/android/gvr/gvr_device.cc
@@ -126,7 +126,7 @@
 
 GvrDevice::GvrDevice() : weak_ptr_factory_(this) {
   GvrDelegateProvider* delegate_provider = GetGvrDelegateProvider();
-  if (delegate_provider->ShouldDisableGvrDevice())
+  if (!delegate_provider || delegate_provider->ShouldDisableGvrDevice())
     return;
   JNIEnv* env = base::android::AttachCurrentThread();
   non_presenting_context_.Reset(
diff --git a/extensions/browser/extension_protocols.cc b/extensions/browser/extension_protocols.cc
index 75bdf38..ca3b363 100644
--- a/extensions/browser/extension_protocols.cc
+++ b/extensions/browser/extension_protocols.cc
@@ -811,7 +811,9 @@
     const Extension* extension = registry->GetInstalledExtension(extension_id);
 
     if (!AllowExtensionResourceLoad(
-            request.url, request.resource_type, request.transition_type,
+            request.url,
+            static_cast<content::ResourceType>(request.resource_type),
+            static_cast<ui::PageTransition>(request.transition_type),
             process_host->GetID(), browser_context->IsOffTheRecord(), extension,
             util::IsIncognitoEnabled(extension_id, browser_context),
             registry->enabled_extensions(),
diff --git a/gin/BUILD.gn b/gin/BUILD.gn
index 299815b..6b3a6639 100644
--- a/gin/BUILD.gn
+++ b/gin/BUILD.gn
@@ -32,8 +32,6 @@
     "function_template.cc",
     "function_template.h",
     "gin_export.h",
-    "gin_features.cc",
-    "gin_features.h",
     "handle.h",
     "interceptor.cc",
     "interceptor.h",
diff --git a/gin/gin_features.cc b/gin/gin_features.cc
deleted file mode 100644
index 1dc57340..0000000
--- a/gin/gin_features.cc
+++ /dev/null
@@ -1,13 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "gin/gin_features.h"
-
-namespace features {
-
-// Enables extra masking and integrity checking in V8.
-const base::Feature kV8ExtraMasking{"V8ExtraMasking",
-                                    base::FEATURE_DISABLED_BY_DEFAULT};
-
-}  // namespace features
diff --git a/gin/gin_features.h b/gin/gin_features.h
deleted file mode 100644
index f779d6ec..0000000
--- a/gin/gin_features.h
+++ /dev/null
@@ -1,17 +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 GIN_FEATURES_H_
-#define GIN_FEATURES_H_
-
-#include "base/feature_list.h"
-#include "gin/gin_export.h"
-
-namespace features {
-
-GIN_EXPORT extern const base::Feature kV8ExtraMasking;
-
-}  // namespace features
-
-#endif  // GIN_FEATURES_H_
diff --git a/gin/v8_initializer.cc b/gin/v8_initializer.cc
index 292f4cb..03353be 100644
--- a/gin/v8_initializer.cc
+++ b/gin/v8_initializer.cc
@@ -25,7 +25,6 @@
 #include "base/threading/platform_thread.h"
 #include "base/time/time.h"
 #include "build/build_config.h"
-#include "gin/gin_features.h"
 
 #if defined(V8_USE_EXTERNAL_STARTUP_DATA)
 #if defined(OS_ANDROID)
@@ -232,14 +231,6 @@
 
   v8::V8::InitializePlatform(V8Platform::Get());
 
-  if (base::FeatureList::IsEnabled(features::kV8ExtraMasking)) {
-    static const char extra_masking[] = "--extra-masking";
-    v8::V8::SetFlagsFromString(extra_masking, sizeof(extra_masking) - 1);
-  } else {
-    static const char no_extra_masking[] = "--no-extra-masking";
-    v8::V8::SetFlagsFromString(no_extra_masking, sizeof(no_extra_masking) - 1);
-  }
-
   if (IsolateHolder::kStrictMode == mode) {
     static const char use_strict[] = "--use_strict";
     v8::V8::SetFlagsFromString(use_strict, sizeof(use_strict) - 1);
diff --git a/gpu/command_buffer/service/feature_info.cc b/gpu/command_buffer/service/feature_info.cc
index 5842f39..4323e81 100644
--- a/gpu/command_buffer/service/feature_info.cc
+++ b/gpu/command_buffer/service/feature_info.cc
@@ -44,11 +44,10 @@
 
 class ScopedPixelUnpackBufferOverride {
  public:
-  explicit ScopedPixelUnpackBufferOverride(
-      bool enable_es3,
-      GLuint binding_override)
+  explicit ScopedPixelUnpackBufferOverride(bool has_pixel_buffers,
+                                           GLuint binding_override)
       : orig_binding_(-1) {
-    if (enable_es3) {
+    if (has_pixel_buffers) {
       GLint orig_binding = 0;
       glGetIntegerv(GL_PIXEL_UNPACK_BUFFER_BINDING, &orig_binding);
       if (static_cast<GLuint>(orig_binding) != binding_override) {
@@ -400,7 +399,16 @@
 
   bool enable_es3 = IsWebGL2OrES3Context();
 
-  ScopedPixelUnpackBufferOverride scoped_pbo_override(enable_es3, 0);
+  // Pixel buffer bindings can be manipulated by the client if ES3 is enabled or
+  // the GL_NV_pixel_buffer_object extension is exposed by ANGLE when using the
+  // passthrough command decoder
+  bool pixel_buffers_exposed =
+      enable_es3 || gl::HasExtension(extensions, "GL_NV_pixel_buffer_object");
+
+  // Both decoders may bind pixel buffers if exposing an ES3 or WebGL 2 context
+  // and the passthrough command decoder may also bind PBOs if
+  // NV_pixel_buffer_object is exposed.
+  ScopedPixelUnpackBufferOverride scoped_pbo_override(pixel_buffers_exposed, 0);
 
   AddExtensionString("GL_ANGLE_translated_shader_source");
   AddExtensionString("GL_CHROMIUM_async_pixel_transfers");
diff --git a/gpu/command_buffer/service/test_helper.cc b/gpu/command_buffer/service/test_helper.cc
index a6b538e..5d2c6f9 100644
--- a/gpu/command_buffer/service/test_helper.cc
+++ b/gpu/command_buffer/service/test_helper.cc
@@ -517,7 +517,8 @@
       .WillOnce(Return(reinterpret_cast<const uint8_t*>(gl_renderer)))
       .RetiresOnSaturation();
 
-  if (enable_es3) {
+  if (enable_es3 ||
+      gl::HasExtension(extension_set, "GL_NV_pixel_buffer_object")) {
     EXPECT_CALL(*gl, GetIntegerv(GL_PIXEL_UNPACK_BUFFER_BINDING, _))
       .WillOnce(SetArgPointee<1>(0))
       .RetiresOnSaturation();
diff --git a/gpu/ipc/service/gpu_channel_manager.cc b/gpu/ipc/service/gpu_channel_manager.cc
index 7471b0e1..a55eb64 100644
--- a/gpu/ipc/service/gpu_channel_manager.cc
+++ b/gpu/ipc/service/gpu_channel_manager.cc
@@ -266,6 +266,10 @@
 
 void GpuChannelManager::OnApplicationStateChange(
     base::android::ApplicationState state) {
+  // TODO(ericrk): Temporarily disable the context release logic due to
+  // https://crbug.com/792120. Re-enable when the fix lands.
+  return;
+
   if (state != base::android::APPLICATION_STATE_HAS_STOPPED_ACTIVITIES ||
       !is_running_on_low_end_mode_) {
     return;
diff --git a/ios/build/bots/chromium.clang/ToTiOS.json b/ios/build/bots/chromium.clang/ToTiOS.json
index c98d03d5..ba49f729 100644
--- a/ios/build/bots/chromium.clang/ToTiOS.json
+++ b/ios/build/bots/chromium.clang/ToTiOS.json
@@ -2,7 +2,7 @@
   "comments": [
     "Clang tip-of-tree builder for iOS."
   ],
-  "xcode version": "9.0",
+  "xcode build version": "9C40b",
   "gn_args": [
     "ios_enable_code_signing=false",
     "is_component_build=false",
diff --git a/ios/build/bots/chromium.fyi/ios-device-goma-canary-clobber.json b/ios/build/bots/chromium.fyi/ios-device-goma-canary-clobber.json
index 7f7f3c7..dc04c67a 100644
--- a/ios/build/bots/chromium.fyi/ios-device-goma-canary-clobber.json
+++ b/ios/build/bots/chromium.fyi/ios-device-goma-canary-clobber.json
@@ -3,7 +3,7 @@
     "Goma canary builder for iOS.",
     "It is chromium.mac/ios-device.json + use_goma_canary, clobber."
   ],
-  "xcode version": "9.0",
+  "xcode build version": "9C40b",
   "gn_args": [
     "additional_target_cpus=[ \"arm64\" ]",
     "goma_dir=\"$(goma_dir)\"",
diff --git a/ios/build/bots/chromium.fyi/ios-simulator-cronet.json b/ios/build/bots/chromium.fyi/ios-simulator-cronet.json
index 06c5b5f..6ef6f24 100644
--- a/ios/build/bots/chromium.fyi/ios-simulator-cronet.json
+++ b/ios/build/bots/chromium.fyi/ios-simulator-cronet.json
@@ -3,7 +3,7 @@
     "Cronet tests for 32- and 64-bit iOS 9.0 simulators.",
     "Tests run on iPhone 5s (64-bit) and iPad Retina (32-bit)."
   ],
-  "xcode version": "9.0",
+  "xcode build version": "9C40b",
   "gn_args": [
     "additional_target_cpus=[\"x86\"]",
     "disable_brotli_filter=false",
@@ -26,14 +26,12 @@
     {
       "app": "cronet_unittests_ios",
       "device type": "iPhone 5s",
-      "os": "9.3",
-      "xcode version": "9.0"
+      "os": "9.3"
     },
     {
       "app": "cronet_test",
       "device type": "iPhone 5s",
-      "os": "9.3",
-      "xcode version": "9.0"
+      "os": "9.3"
     },
     {
       "app": "cronet_test",
@@ -44,20 +42,17 @@
     {
       "app": "cronet_test",
       "device type": "iPhone 5s",
-      "os": "11.0",
-      "xcode version": "9.0"
+      "os": "11.0"
     },
     {
       "app": "cronet_test",
       "device type": "iPad Air 2",
-      "os": "11.0",
-      "xcode version": "9.0"
+      "os": "11.0"
     },
     {
       "app": "cronet_test",
       "device type": "iPhone X",
-      "os": "11.0",
-      "xcode version": "9.0"
+      "os": "11.0"
     }
 
   ]
diff --git a/ios/build/bots/chromium.fyi/ios-simulator.json b/ios/build/bots/chromium.fyi/ios-simulator.json
index f9ec2e4d..2398ea6 100644
--- a/ios/build/bots/chromium.fyi/ios-simulator.json
+++ b/ios/build/bots/chromium.fyi/ios-simulator.json
@@ -2,7 +2,7 @@
   "comments": [
     "Runs tests on FYI ios-simualtor."
   ],
-  "xcode version": "9.0",
+  "xcode build version": "9C40b",
   "gn_args": [
     "additional_target_cpus=[\"x86\"]",
     "goma_dir=\"$(goma_dir)\"",
@@ -13,7 +13,7 @@
     "use_goma=true"
   ],
   "configuration": "Debug",
-  "sdk": "iphonesimulator11.0",
+  "sdk": "iphonesimulator11.2",
   "tests": [
     {
       "include": "common_tests.json",
@@ -21,8 +21,7 @@
         "--enable-features=SlimNavigationManager"
       ],
       "device type": "iPhone 6s",
-      "os": "11.0",
-      "xcode version": "9.0"
+      "os": "11.2"
     },
     {
       "app": "ios_chrome_integration_egtests",
@@ -30,8 +29,7 @@
         "--enable-features=CredentialManager"
       ],
       "device type": "iPhone 6s",
-      "os": "11.0",
-      "xcode version": "9.0",
+      "os": "11.2",
       "xctest": true
     },
     {
@@ -41,7 +39,6 @@
       ],
       "device type": "iPad Air 2",
       "os": "10.0",
-      "xcode version": "9.0",
       "xctest": true
     },
     {
@@ -50,8 +47,7 @@
         "--enable-features=SlimNavigationManager"
       ],
       "device type": "iPhone 6s",
-      "os": "11.0",
-      "xcode version": "9.0",
+      "os": "11.2",
       "xctest": true
     },
     {
@@ -60,8 +56,7 @@
         "--enable-features=SlimNavigationManager"
       ],
       "device type": "iPhone 6s",
-      "os": "11.0",
-      "xcode version": "9.0",
+      "os": "11.2",
       "xctest": true
     },
     {
@@ -70,8 +65,7 @@
         "--enable-features=SlimNavigationManager"
       ],
       "device type": "iPhone 6s",
-      "os": "11.0",
-      "xcode version": "9.0",
+      "os": "11.2",
       "xctest": true
     },
     {
@@ -80,8 +74,7 @@
         "--enable-features=SlimNavigationManager"
       ],
       "device type": "iPhone 6s",
-      "os": "11.0",
-      "xcode version": "9.0",
+      "os": "11.2",
       "xctest": true
     },
     {
@@ -90,8 +83,7 @@
         "--enable-features=SlimNavigationManager"
       ],
       "device type": "iPhone 6s",
-      "os": "11.0",
-      "xcode version": "9.0",
+      "os": "11.2",
       "xctest": true
     }
   ]
diff --git a/ios/build/bots/chromium.fyi/ios-webview.json b/ios/build/bots/chromium.fyi/ios-webview.json
index 7acbbb3..697f999c 100644
--- a/ios/build/bots/chromium.fyi/ios-webview.json
+++ b/ios/build/bots/chromium.fyi/ios-webview.json
@@ -2,7 +2,7 @@
   "comments": [
     "Run web_view tests for 64-bit iOS 9.0 simulators on FYI ios-webview."
   ],
-  "xcode version": "9.0",
+  "xcode build version": "9C40b",
   "gn_args": [
     "goma_dir=\"$(goma_dir)\"",
     "is_component_build=false",
@@ -17,56 +17,47 @@
     {
       "app": "ios_web_view_unittests",
       "device type": "iPhone 5s",
-      "os": "9.3",
-      "xcode version": "9.0"
+      "os": "9.3"
     },
     {
       "app": "ios_web_view_inttests",
       "device type": "iPhone 5s",
-      "os": "9.3",
-      "xcode version": "9.0"
+      "os": "9.3"
     },
     {
       "app": "ios_components_unittests",
       "device type": "iPhone 5s",
-      "os": "9.3",
-      "xcode version": "9.0"
+      "os": "9.3"
     },
     {
       "app": "components_unittests",
       "device type": "iPhone 5s",
-      "os": "9.3",
-      "xcode version": "9.0"
+      "os": "9.3"
     },
     {
       "app": "net_unittests",
       "device type": "iPhone 5s",
-      "os": "9.3",
-      "xcode version": "9.0"
+      "os": "9.3"
     },
     {
       "app": "ios_net_unittests",
       "device type": "iPhone 5s",
-      "os": "9.3",
-      "xcode version": "9.0"
+      "os": "9.3"
     },
     {
       "app": "ios_web_unittests",
       "device type": "iPhone 5s",
-      "os": "9.3",
-      "xcode version": "9.0"
+      "os": "9.3"
     },
     {
       "app": "ios_web_inttests",
       "device type": "iPhone 5s",
-      "os": "9.3",
-      "xcode version": "9.0"
+      "os": "9.3"
     },
     {
       "app": "ios_web_shell_egtests",
       "device type": "iPhone 5s",
       "os": "9.3",
-      "xcode version": "9.0",
       "xctest": true
     }
   ]
diff --git a/ios/build/bots/chromium.webrtc.fyi/ios-simulator.json b/ios/build/bots/chromium.webrtc.fyi/ios-simulator.json
index 79d61520..f14f50a 100644
--- a/ios/build/bots/chromium.webrtc.fyi/ios-simulator.json
+++ b/ios/build/bots/chromium.webrtc.fyi/ios-simulator.json
@@ -22,44 +22,37 @@
     {
       "include": "common_tests.json",
       "device type": "iPhone 6s Plus",
-      "os": "10.0",
-      "xcode version": "8.0"
+      "os": "10.0"
     },
     {
       "include": "common_tests.json",
       "device type": "iPhone 6s",
-      "os": "10.0",
-      "xcode version": "8.0"
+      "os": "10.0"
     },
     {
       "include": "common_tests.json",
       "device type": "iPhone 5",
-      "os": "10.0",
-      "xcode version": "8.0"
+      "os": "10.0"
     },
     {
       "include": "common_tests.json",
       "device type": "iPad Air 2",
-      "os": "10.0",
-      "xcode version": "8.0"
+      "os": "10.0"
     },
     {
       "include": "common_tests.json",
       "device type": "iPad Retina",
-      "os": "10.0",
-      "xcode version": "8.0"
+      "os": "10.0"
     },
     {
       "include": "common_tests.json",
       "device type": "iPhone 5",
-      "os": "9.0",
-      "xcode version": "8.0"
+      "os": "9.0"
     },
     {
       "include": "common_tests.json",
       "device type": "iPad Air 2",
-      "os": "9.0",
-      "xcode version": "8.0"
+      "os": "9.0"
     }
   ]
 }
diff --git a/ios/chrome/app/main_controller.mm b/ios/chrome/app/main_controller.mm
index 88495b96..894a4838 100644
--- a/ios/chrome/app/main_controller.mm
+++ b/ios/chrome/app/main_controller.mm
@@ -2444,7 +2444,7 @@
 }
 
 - (UIImage*)currentPageScreenshot {
-  UIView* lastView = self.mainViewController.view;
+  UIView* lastView = self.mainViewController.activeViewController.view;
   DCHECK(lastView);
   CGFloat scale = 0.0;
   // For screenshots of the Stack View we need to use a scale of 1.0 to avoid
diff --git a/ios/chrome/browser/feature_engagement/OWNERS b/ios/chrome/browser/feature_engagement/OWNERS
index 782b0c3..f72b1e5 100644
--- a/ios/chrome/browser/feature_engagement/OWNERS
+++ b/ios/chrome/browser/feature_engagement/OWNERS
@@ -1,5 +1,4 @@
 edchin@chromium.org
-gchatz@chromium.org
 
 # TEAM: ios-directory-owners@chromium.org
 # OS: iOS
diff --git a/ios/chrome/browser/history/history_tab_helper.h b/ios/chrome/browser/history/history_tab_helper.h
index f1d2942..0bb71017 100644
--- a/ios/chrome/browser/history/history_tab_helper.h
+++ b/ios/chrome/browser/history/history_tab_helper.h
@@ -51,6 +51,9 @@
   // web::WebStateObserver implementation.
   void DidFinishNavigation(web::WebState* web_state,
                            web::NavigationContext* navigation_context) override;
+  void PageLoaded(
+      web::WebState* web_state,
+      web::PageLoadCompletionStatus load_completion_status) override;
   void TitleWasSet(web::WebState* web_state) override;
   void WebStateDestroyed(web::WebState* web_state) override;
 
@@ -72,6 +75,11 @@
   // is set to false.
   bool delay_notification_ = false;
 
+  // The time that the current page finished loading. Only title changes within
+  // a certain time period after the page load is complete will be saved to the
+  // history system. Only applies to the main frame of the page.
+  base::TimeTicks last_load_completion_;
+
   DISALLOW_COPY_AND_ASSIGN(HistoryTabHelper);
 };
 
diff --git a/ios/chrome/browser/history/history_tab_helper.mm b/ios/chrome/browser/history/history_tab_helper.mm
index a0501e4..cd6dd6c 100644
--- a/ios/chrome/browser/history/history_tab_helper.mm
+++ b/ios/chrome/browser/history/history_tab_helper.mm
@@ -5,6 +5,7 @@
 #import "ios/chrome/browser/history/history_tab_helper.h"
 
 #include "base/memory/ptr_util.h"
+#include "components/history/core/browser/history_constants.h"
 #include "components/history/core/browser/history_service.h"
 #include "components/keyed_service/core/service_access_type.h"
 #include "components/strings/grit/components_strings.h"
@@ -168,17 +169,29 @@
   }
 }
 
+void HistoryTabHelper::PageLoaded(
+    web::WebState* web_state,
+    web::PageLoadCompletionStatus load_completion_status) {
+  last_load_completion_ = base::TimeTicks::Now();
+}
+
 void HistoryTabHelper::TitleWasSet(web::WebState* web_state) {
   DCHECK_EQ(web_state_, web_state);
   if (delay_notification_) {
     return;
   }
 
-  web::NavigationItem* last_committed_item =
-      web_state_->GetNavigationManager()->GetLastCommittedItem();
-
-  if (last_committed_item) {
-    UpdateHistoryPageTitle(*last_committed_item);
+  // Only store page titles into history if they were set while the page was
+  // loading or during a brief span after load is complete. This fixes the case
+  // where a page uses a title change to alert a user of a situation but that
+  // title change ends up saved in history.
+  if (web_state->IsLoading() ||
+      (base::TimeTicks::Now() - last_load_completion_ <
+       history::GetTitleSettingWindow())) {
+    web::NavigationItem* last_committed_item =
+        web_state_->GetNavigationManager()->GetLastCommittedItem();
+    if (last_committed_item)
+      UpdateHistoryPageTitle(*last_committed_item);
   }
 }
 
diff --git a/ios/chrome/browser/tabs/tab_unittest.mm b/ios/chrome/browser/tabs/tab_unittest.mm
index e635e523..8633b5e 100644
--- a/ios/chrome/browser/tabs/tab_unittest.mm
+++ b/ios/chrome/browser/tabs/tab_unittest.mm
@@ -228,6 +228,7 @@
     [tab_ navigationManagerImpl]->CommitPendingItem();
     web_state_impl_->UpdateHttpResponseHeaders(redirectUrl);
     web_state_impl_->OnNavigationFinished(context2.get());
+    web_state_impl_->SetIsLoading(true);
 
     base::string16 new_title = base::SysNSStringToUTF16(title);
     [tab_ navigationManager]->GetLastCommittedItem()->SetTitle(new_title);
diff --git a/ios/chrome/browser/ui/bubble/OWNERS b/ios/chrome/browser/ui/bubble/OWNERS
index 2c40cf4..31080dd 100644
--- a/ios/chrome/browser/ui/bubble/OWNERS
+++ b/ios/chrome/browser/ui/bubble/OWNERS
@@ -1,4 +1,3 @@
 edchin@chromium.org
-gchatz@chromium.org
 # TEAM: ios-directory-owners@chromium.org
 # OS: iOS
diff --git a/ios/chrome/browser/ui/location_bar/location_bar_view.h b/ios/chrome/browser/ui/location_bar/location_bar_view.h
index 5387896..088cbf1 100644
--- a/ios/chrome/browser/ui/location_bar/location_bar_view.h
+++ b/ios/chrome/browser/ui/location_bar/location_bar_view.h
@@ -54,7 +54,9 @@
 // Perform animations for expanding the omnibox. This animation can be seen on
 // an iPhone when the omnibox is focused. It involves sliding the leading button
 // out and fading its alpha.
-- (void)addExpandOmniboxAnimations:(UIViewPropertyAnimator*)animator;
+// The trailing button is faded-in in the |completionAnimator| animations.
+- (void)addExpandOmniboxAnimations:(UIViewPropertyAnimator*)animator
+                completionAnimator:(UIViewPropertyAnimator*)completionAnimator;
 
 // Perform animations for expanding the omnibox. This animation can be seen on
 // an iPhone when the omnibox is defocused. It involves sliding the leading
diff --git a/ios/chrome/browser/ui/location_bar/location_bar_view.mm b/ios/chrome/browser/ui/location_bar/location_bar_view.mm
index 3f687c81..814af54c 100644
--- a/ios/chrome/browser/ui/location_bar/location_bar_view.mm
+++ b/ios/chrome/browser/ui/location_bar/location_bar_view.mm
@@ -284,11 +284,13 @@
       }];
 }
 
-- (void)addExpandOmniboxAnimations:(UIViewPropertyAnimator*)animator {
+- (void)addExpandOmniboxAnimations:(UIViewPropertyAnimator*)animator
+                completionAnimator:(UIViewPropertyAnimator*)completionAnimator {
   // TODO(crbug.com/791455): Due to crbug.com/774121 |self.leadingButton| is
   // hidden in line 151 before the animation starts. For this reason any
   // animation we try doing on |self.leadingButton| will not be visible.
-  [self.textField addExpandOmniboxAnimations:animator];
+  [self.textField addExpandOmniboxAnimations:animator
+                          completionAnimator:completionAnimator];
 }
 
 - (void)addContractOmniboxAnimations:(UIViewPropertyAnimator*)animator {
diff --git a/ios/chrome/browser/ui/omnibox/omnibox_text_field_ios.h b/ios/chrome/browser/ui/omnibox/omnibox_text_field_ios.h
index a93cb28..9426700 100644
--- a/ios/chrome/browser/ui/omnibox/omnibox_text_field_ios.h
+++ b/ios/chrome/browser/ui/omnibox/omnibox_text_field_ios.h
@@ -82,7 +82,8 @@
 
 // New animations API, currently behind clean-toolbar flag.
 // They replace all animations above.
-- (void)addExpandOmniboxAnimations:(UIViewPropertyAnimator*)animator;
+- (void)addExpandOmniboxAnimations:(UIViewPropertyAnimator*)animator
+                completionAnimator:(UIViewPropertyAnimator*)completionAnimator;
 - (void)addContractOmniboxAnimations:(UIViewPropertyAnimator*)animator;
 
 // Initial touch on the Omnibox triggers a "pre-edit" state. The current
diff --git a/ios/chrome/browser/ui/omnibox/omnibox_text_field_ios.mm b/ios/chrome/browser/ui/omnibox/omnibox_text_field_ios.mm
index 33efcb0..f3b0a05 100644
--- a/ios/chrome/browser/ui/omnibox/omnibox_text_field_ios.mm
+++ b/ios/chrome/browser/ui/omnibox/omnibox_text_field_ios.mm
@@ -297,32 +297,20 @@
                                   [self fadeAnimationLayers]);
 }
 
-- (void)addExpandOmniboxAnimations:(UIViewPropertyAnimator*)animator {
+- (void)addExpandOmniboxAnimations:(UIViewPropertyAnimator*)animator
+                completionAnimator:(UIViewPropertyAnimator*)completionAnimator {
   // Hide the rightView button so its not visibile on its initial layout
   // while the expan animation is happening.
   self.rightView.hidden = YES;
-  self.rightView.frame = [self rightViewRectForBounds:self.bounds];
-  [animator addAnimations:^{
-    [self layoutIfNeeded];
-    [self.rightView layoutIfNeeded];
-  }];
+  self.rightView.alpha = 0;
+  self.rightView.frame = CGRectLayoutOffset(
+      [self rightViewRectForBounds:self.bounds], kToolbarButtonAnimationOffset);
 
-  [animator addCompletion:^(UIViewAnimatingPosition finalPosition) {
+  [completionAnimator addAnimations:^{
     self.rightView.hidden = NO;
-    self.rightView.alpha = 0;
-    self.rightView.frame =
-        CGRectLayoutOffset(self.rightView.frame, kToolbarButtonAnimationOffset);
-    [UIViewPropertyAnimator
-        runningPropertyAnimatorWithDuration:0.2
-                                      delay:0.1
-                                    options:UIViewAnimationOptionCurveEaseOut
-                                 animations:^{
-                                   self.rightView.alpha = 1.0;
-                                   self.rightView.frame = CGRectLayoutOffset(
-                                       self.rightView.frame,
-                                       -kToolbarButtonAnimationOffset);
-                                 }
-                                 completion:nil];
+    self.rightView.alpha = 1.0;
+    self.rightView.frame = CGRectLayoutOffset(self.rightView.frame,
+                                              -kToolbarButtonAnimationOffset);
   }];
 }
 
diff --git a/ios/chrome/browser/ui/reading_list/OWNERS b/ios/chrome/browser/ui/reading_list/OWNERS
index 8f4d804..66536df8 100644
--- a/ios/chrome/browser/ui/reading_list/OWNERS
+++ b/ios/chrome/browser/ui/reading_list/OWNERS
@@ -3,7 +3,6 @@
 olivierrobin@chromium.org
 
 per-file *badge_view*=edchin@chromium.org
-per-file *badge_view*=gchatz@chromium.org
 
 # TEAM: ios-directory-owners@chromium.org
 # OS: iOS
diff --git a/ios/chrome/browser/ui/toolbar/clean/toolbar_coordinator.mm b/ios/chrome/browser/ui/toolbar/clean/toolbar_coordinator.mm
index c3937069..c36adf4 100644
--- a/ios/chrome/browser/ui/toolbar/clean/toolbar_coordinator.mm
+++ b/ios/chrome/browser/ui/toolbar/clean/toolbar_coordinator.mm
@@ -532,12 +532,20 @@
   UIViewPropertyAnimator* animator = [[UIViewPropertyAnimator alloc]
       initWithDuration:ios::material::kDuration1
                  curve:UIViewAnimationCurveEaseInOut
-            animations:^{
-            }];
+            animations:nil];
+  UIViewPropertyAnimator* completionAnimator = [[UIViewPropertyAnimator alloc]
+      initWithDuration:ios::material::kDuration1
+                 curve:UIViewAnimationCurveEaseOut
+            animations:nil];
+  [animator addCompletion:^(UIViewAnimatingPosition finalPosition) {
+    [completionAnimator startAnimationAfterDelay:ios::material::kDuration4];
+  }];
 
   [self.locationBarCoordinator.locationBarView
-      addExpandOmniboxAnimations:animator];
-  [self.toolbarViewController addToolbarExpansionAnimations:animator];
+      addExpandOmniboxAnimations:animator
+              completionAnimator:completionAnimator];
+  [self.toolbarViewController addToolbarExpansionAnimations:animator
+                                         completionAnimator:completionAnimator];
   [animator startAnimation];
 
   if (!animated) {
diff --git a/ios/chrome/browser/ui/toolbar/clean/toolbar_view_controller.h b/ios/chrome/browser/ui/toolbar/clean/toolbar_view_controller.h
index f5998963..5c9bad04 100644
--- a/ios/chrome/browser/ui/toolbar/clean/toolbar_view_controller.h
+++ b/ios/chrome/browser/ui/toolbar/clean/toolbar_view_controller.h
@@ -51,7 +51,11 @@
 
 // Adds the toolbar expanded state animations to |animator|, and changes the
 // toolbar constraints in preparation for the animation.
-- (void)addToolbarExpansionAnimations:(UIViewPropertyAnimator*)animator;
+// Adds the toolbar post-expanded state animations (fading-in the contract
+// button) to the |completionAnimator|.
+- (void)addToolbarExpansionAnimations:(UIViewPropertyAnimator*)animator
+                   completionAnimator:
+                       (UIViewPropertyAnimator*)completionAnimator;
 // Adds the toolbar contracted state animations to |animator|, and changes the
 // toolbar constraints in preparation for the animation.
 - (void)addToolbarContractionAnimations:(UIViewPropertyAnimator*)animator;
diff --git a/ios/chrome/browser/ui/toolbar/clean/toolbar_view_controller.mm b/ios/chrome/browser/ui/toolbar/clean/toolbar_view_controller.mm
index cdbe701..d4ba662 100644
--- a/ios/chrome/browser/ui/toolbar/clean/toolbar_view_controller.mm
+++ b/ios/chrome/browser/ui/toolbar/clean/toolbar_view_controller.mm
@@ -74,7 +74,9 @@
   return self;
 }
 
-- (void)addToolbarExpansionAnimations:(UIViewPropertyAnimator*)animator {
+- (void)addToolbarExpansionAnimations:(UIViewPropertyAnimator*)animator
+                   completionAnimator:
+                       (UIViewPropertyAnimator*)completionAnimator {
   // iPad should never try to animate.
   DCHECK(!IsIPadIdiom());
   [NSLayoutConstraint
@@ -130,24 +132,6 @@
                 delayFactor:ios::material::kDuration2];
   }
 
-  // When the locationBarContainer has been expanded the Contract button will
-  // fade in.
-  void (^contractButtonAnimation)() = ^{
-    self.view.contractButton.alpha = 1;
-    [self setHorizontalTranslationOffset:0
-                                forViews:@[ self.view.contractButton ]];
-  };
-  [animator addCompletion:^(UIViewAnimatingPosition finalPosition) {
-    [self setHorizontalTranslationOffset:kToolbarButtonAnimationOffset
-                                forViews:@[ self.view.contractButton ]];
-
-    [UIViewPropertyAnimator
-        runningPropertyAnimatorWithDuration:ios::material::kDuration1
-                                      delay:ios::material::kDuration4
-                                    options:UIViewAnimationOptionCurveEaseOut
-                                 animations:contractButtonAnimation
-                                 completion:nil];
-  }];
   [animator addCompletion:^(UIViewAnimatingPosition finalPosition) {
     CGFloat borderWidth = (finalPosition == UIViewAnimatingPositionEnd)
                               ? 0
@@ -155,6 +139,16 @@
     self.view.locationBarContainer.layer.borderWidth = borderWidth;
   }];
 
+  // When the locationBarContainer has been expanded the Contract button will
+  // fade in.
+  [self setHorizontalTranslationOffset:kToolbarButtonAnimationOffset
+                              forViews:@[ self.view.contractButton ]];
+  [completionAnimator addAnimations:^{
+    self.view.contractButton.alpha = 1;
+    [self setHorizontalTranslationOffset:0
+                                forViews:@[ self.view.contractButton ]];
+  }];
+
   self.expanded = YES;
 }
 
diff --git a/ios/web/download/download_task_impl.mm b/ios/web/download/download_task_impl.mm
index a756343..d0d22c3 100644
--- a/ios/web/download/download_task_impl.mm
+++ b/ios/web/download/download_task_impl.mm
@@ -56,6 +56,9 @@
   if (!task.countOfBytesExpectedToReceive) {
     return 100;
   }
+  if (task.countOfBytesExpectedToReceive == -1) {
+    return -1;
+  }
   DCHECK_GE(task.countOfBytesExpectedToReceive, task.countOfBytesReceived);
   return 100.0 * task.countOfBytesReceived / task.countOfBytesExpectedToReceive;
 }
diff --git a/ios/web/download/download_task_impl_unittest.mm b/ios/web/download/download_task_impl_unittest.mm
index 5351b93e..3a7db43 100644
--- a/ios/web/download/download_task_impl_unittest.mm
+++ b/ios/web/download/download_task_impl_unittest.mm
@@ -231,6 +231,45 @@
   EXPECT_CALL(task_delegate_, OnTaskDestroyed(task_.get()));
 }
 
+// Tests sucessfull download of response when content length is unknown until
+// the download completes.
+TEST_F(DownloadTaskImplTest, UnknownLengthContentDownload) {
+  EXPECT_CALL(task_observer_, OnDownloadUpdated(task_.get()));
+  CRWFakeNSURLSessionTask* session_task = Start();
+  ASSERT_TRUE(session_task);
+  testing::Mock::VerifyAndClearExpectations(&task_observer_);
+
+  // The response has arrived.
+  EXPECT_CALL(task_observer_, OnDownloadUpdated(task_.get()));
+  const char kData[] = "foo";
+  session_task.countOfBytesExpectedToReceive = -1;
+  SimulateDataDownload(session_task, kData);
+  testing::Mock::VerifyAndClearExpectations(&task_observer_);
+  EXPECT_EQ(DownloadTask::State::kInProgress, task_->GetState());
+  EXPECT_FALSE(task_->IsDone());
+  EXPECT_EQ(0, task_->GetErrorCode());
+  EXPECT_EQ(-1, task_->GetTotalBytes());
+  EXPECT_EQ(-1, task_->GetPercentComplete());
+  EXPECT_EQ(kData, task_->GetResponseWriter()->AsStringWriter()->data());
+
+  // Download has finished.
+  EXPECT_CALL(task_observer_, OnDownloadUpdated(task_.get()));
+  int64_t kDataSize = strlen(kData);
+  session_task.countOfBytesExpectedToReceive = kDataSize;
+  SimulateDownloadCompletion(session_task);
+  testing::Mock::VerifyAndClearExpectations(&task_observer_);
+  ASSERT_TRUE(WaitUntilConditionOrTimeout(kWaitForDownloadTimeout, ^{
+    return task_->IsDone();
+  }));
+  EXPECT_EQ(DownloadTask::State::kComplete, task_->GetState());
+  EXPECT_EQ(0, task_->GetErrorCode());
+  EXPECT_EQ(kDataSize, task_->GetTotalBytes());
+  EXPECT_EQ(100, task_->GetPercentComplete());
+  EXPECT_EQ(kData, task_->GetResponseWriter()->AsStringWriter()->data());
+
+  EXPECT_CALL(task_delegate_, OnTaskDestroyed(task_.get()));
+}
+
 // Tests cancelling the download task.
 TEST_F(DownloadTaskImplTest, Cancelling) {
   EXPECT_CALL(task_observer_, OnDownloadUpdated(task_.get()));
diff --git a/media/base/android/BUILD.gn b/media/base/android/BUILD.gn
index 89867749..e91561f5 100644
--- a/media/base/android/BUILD.gn
+++ b/media/base/android/BUILD.gn
@@ -172,6 +172,7 @@
       "java/src/org/chromium/media/AudioManagerAndroid.java",
       "java/src/org/chromium/media/AudioRecordInput.java",
       "java/src/org/chromium/media/AudioTrackOutputStream.java",
+      "java/src/org/chromium/media/BitrateAdjuster.java",
       "java/src/org/chromium/media/CodecProfileLevelList.java",
       "java/src/org/chromium/media/HdrMetadata.java",
       "java/src/org/chromium/media/MediaCodecBridge.java",
@@ -189,8 +190,10 @@
   }
 
   junit_binary("media_base_junit_tests") {
-    java_files =
-        [ "java/src/test/org/chromium/media/AudioTrackOutputStreamTest.java" ]
+    java_files = [
+      "java/src/test/org/chromium/media/AudioTrackOutputStreamTest.java",
+      "java/src/test/org/chromium/media/BitrateAdjusterTest.java",
+    ]
     deps = [
       ":media_java",
       "//base:base_java",
diff --git a/media/base/android/java/src/org/chromium/media/BitrateAdjuster.java b/media/base/android/java/src/org/chromium/media/BitrateAdjuster.java
new file mode 100644
index 0000000..b6411cea
--- /dev/null
+++ b/media/base/android/java/src/org/chromium/media/BitrateAdjuster.java
@@ -0,0 +1,49 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.media;
+
+enum BitrateAdjuster {
+    // No adjustment - video encoder has no known bitrate problem.
+    NO_ADJUSTMENT {
+        private static final int MAXIMUM_INITIAL_FPS = 30;
+
+        @Override
+        public int getTargetBitrate(int bps, int frameRate) {
+            return bps;
+        }
+
+        @Override
+        public int getInitialFrameRate(int frameRateHint) {
+            return Math.min(frameRateHint, MAXIMUM_INITIAL_FPS);
+        }
+    },
+
+    // Framerate based bitrate adjustment is required - HW encoder does not use frame
+    // timestamps to calculate frame bitrate budget and instead is relying on initial
+    // fps configuration assuming that all frames are coming at fixed initial frame rate.
+    FRAMERATE_ADJUSTMENT {
+        private static final int BITRATE_ADJUSTMENT_FPS = 30;
+
+        @Override
+        public int getTargetBitrate(int bps, int frameRate) {
+            if (frameRate == 0) {
+                return bps;
+            }
+            return BITRATE_ADJUSTMENT_FPS * bps / frameRate;
+        }
+
+        @Override
+        public int getInitialFrameRate(int frameRateHint) {
+            return BITRATE_ADJUSTMENT_FPS;
+        }
+    };
+
+    // Gets the adjusted bitrate according to the implementation's adjustment policy.
+    public abstract int getTargetBitrate(int bps, int frameRate);
+
+    // Gets the initial frame rate of the media. The frameRateHint can be used as a default or a
+    // constraint.
+    public abstract int getInitialFrameRate(int frameRateHint);
+}
diff --git a/media/base/android/java/src/org/chromium/media/MediaCodecBridge.java b/media/base/android/java/src/org/chromium/media/MediaCodecBridge.java
index 49991285..7f768a6 100644
--- a/media/base/android/java/src/org/chromium/media/MediaCodecBridge.java
+++ b/media/base/android/java/src/org/chromium/media/MediaCodecBridge.java
@@ -18,7 +18,6 @@
 import org.chromium.base.annotations.CalledByNative;
 import org.chromium.base.annotations.JNINamespace;
 import org.chromium.base.annotations.MainDex;
-import org.chromium.media.MediaCodecUtil.BitrateAdjustmentTypes;
 import org.chromium.media.MediaCodecUtil.MimeTypes;
 
 import java.nio.ByteBuffer;
@@ -49,10 +48,6 @@
     private static final String KEY_CROP_BOTTOM = "crop-bottom";
     private static final String KEY_CROP_TOP = "crop-top";
 
-    // TODO(sanfin): Factor this and other bitrate adjustment logic to a delegate class.
-    static final int BITRATE_ADJUSTMENT_FPS = 30;
-    static final int MAXIMUM_INITIAL_FPS = 30;
-
     protected MediaCodec mMediaCodec;
 
     private ByteBuffer[] mInputBuffers;
@@ -60,7 +55,7 @@
 
     private boolean mFlushed;
     private long mLastPresentationTimeUs;
-    private BitrateAdjustmentTypes mBitrateAdjustmentType = BitrateAdjustmentTypes.NO_ADJUSTMENT;
+    private BitrateAdjuster mBitrateAdjuster;
 
     @MainDex
     private static class DequeueInputResult {
@@ -180,12 +175,12 @@
         }
     }
 
-    MediaCodecBridge(MediaCodec mediaCodec, BitrateAdjustmentTypes bitrateAdjustmentType) {
+    MediaCodecBridge(MediaCodec mediaCodec, BitrateAdjuster bitrateAdjuster) {
         assert mediaCodec != null;
         mMediaCodec = mediaCodec;
         mLastPresentationTimeUs = 0;
         mFlushed = true;
-        mBitrateAdjustmentType = bitrateAdjustmentType;
+        mBitrateAdjuster = bitrateAdjuster;
     }
 
     @CalledByNative
@@ -337,12 +332,7 @@
     @TargetApi(Build.VERSION_CODES.KITKAT)
     @CalledByNative
     private void setVideoBitrate(int bps, int frameRate) {
-        int targetBps = bps;
-        if (mBitrateAdjustmentType == BitrateAdjustmentTypes.FRAMERATE_ADJUSTMENT
-                && frameRate > 0) {
-            targetBps = BITRATE_ADJUSTMENT_FPS * bps / frameRate;
-        }
-
+        int targetBps = mBitrateAdjuster.getTargetBitrate(bps, frameRate);
         Bundle b = new Bundle();
         b.putInt(MediaCodec.PARAMETER_KEY_VIDEO_BITRATE, targetBps);
         try {
diff --git a/media/base/android/java/src/org/chromium/media/MediaCodecBridgeBuilder.java b/media/base/android/java/src/org/chromium/media/MediaCodecBridgeBuilder.java
index 8e995a3e2..ffe88f4 100644
--- a/media/base/android/java/src/org/chromium/media/MediaCodecBridgeBuilder.java
+++ b/media/base/android/java/src/org/chromium/media/MediaCodecBridgeBuilder.java
@@ -12,7 +12,6 @@
 import org.chromium.base.Log;
 import org.chromium.base.annotations.CalledByNative;
 import org.chromium.base.annotations.JNINamespace;
-import org.chromium.media.MediaCodecUtil.BitrateAdjustmentTypes;
 import org.chromium.media.MediaCodecUtil.CodecCreationInfo;
 import org.chromium.media.MediaCodecUtil.MimeTypes;
 
@@ -65,7 +64,7 @@
 
         if (info.mediaCodec == null) return null;
 
-        MediaCodecBridge bridge = new MediaCodecBridge(info.mediaCodec, info.bitrateAdjustmentType);
+        MediaCodecBridge bridge = new MediaCodecBridge(info.mediaCodec, info.bitrateAdjuster);
 
         MediaFormat format = createVideoDecoderFormat(mime, width, height);
         if (format == null) return null;
@@ -95,14 +94,7 @@
     }
 
     private static MediaFormat createVideoEncoderFormat(String mime, int width, int height,
-            int bitRate, int frameRate, int iFrameInterval, int colorFormat,
-            BitrateAdjustmentTypes bitrateAdjustmentType) {
-        if (bitrateAdjustmentType == BitrateAdjustmentTypes.FRAMERATE_ADJUSTMENT) {
-            frameRate = MediaCodecBridge.BITRATE_ADJUSTMENT_FPS;
-        } else {
-            frameRate = Math.min(frameRate, MediaCodecBridge.MAXIMUM_INITIAL_FPS);
-        }
-
+            int bitRate, int frameRate, int iFrameInterval, int colorFormat) {
         MediaFormat format = MediaFormat.createVideoFormat(mime, width, height);
         format.setInteger(MediaFormat.KEY_BIT_RATE, bitRate);
         format.setInteger(MediaFormat.KEY_FRAME_RATE, frameRate);
@@ -127,15 +119,13 @@
 
         // Create MediaCodecEncoder for H264 to meet WebRTC requirements to IDR/keyframes.
         // See https://crbug.com/761336 for more details.
-        MediaCodecBridge bridge;
-        if (mime.equals(MimeTypes.VIDEO_H264)) {
-            bridge = new MediaCodecEncoder(info.mediaCodec, info.bitrateAdjustmentType);
-        } else {
-            bridge = new MediaCodecBridge(info.mediaCodec, info.bitrateAdjustmentType);
-        }
+        MediaCodecBridge bridge = mime.equals(MimeTypes.VIDEO_H264)
+                ? new MediaCodecEncoder(info.mediaCodec, info.bitrateAdjuster)
+                : new MediaCodecBridge(info.mediaCodec, info.bitrateAdjuster);
 
-        MediaFormat format = createVideoEncoderFormat(mime, width, height, bitRate, frameRate,
-                iFrameInterval, colorFormat, info.bitrateAdjustmentType);
+        frameRate = info.bitrateAdjuster.getInitialFrameRate(frameRate);
+        MediaFormat format = createVideoEncoderFormat(
+                mime, width, height, bitRate, frameRate, iFrameInterval, colorFormat);
 
         if (!bridge.configureVideo(format, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE,
                     info.supportsAdaptivePlayback)) {
@@ -166,7 +156,7 @@
 
         if (info.mediaCodec == null) return null;
 
-        MediaCodecBridge bridge = new MediaCodecBridge(info.mediaCodec, info.bitrateAdjustmentType);
+        MediaCodecBridge bridge = new MediaCodecBridge(info.mediaCodec, info.bitrateAdjuster);
 
         MediaFormat format = createAudioFormat(mime, sampleRate, channelCount);
 
diff --git a/media/base/android/java/src/org/chromium/media/MediaCodecEncoder.java b/media/base/android/java/src/org/chromium/media/MediaCodecEncoder.java
index 26b31a6..f6d69d7 100644
--- a/media/base/android/java/src/org/chromium/media/MediaCodecEncoder.java
+++ b/media/base/android/java/src/org/chromium/media/MediaCodecEncoder.java
@@ -9,7 +9,6 @@
 
 import org.chromium.base.Log;
 import org.chromium.base.annotations.JNINamespace;
-import org.chromium.media.MediaCodecUtil.BitrateAdjustmentTypes;
 
 import java.nio.ByteBuffer;
 
@@ -29,9 +28,8 @@
     // SPS and PPS NALs (Config frame).
     private ByteBuffer mConfigData = null;
 
-    protected MediaCodecEncoder(
-            MediaCodec mediaCodec, BitrateAdjustmentTypes bitrateAdjustmentType) {
-        super(mediaCodec, bitrateAdjustmentType);
+    protected MediaCodecEncoder(MediaCodec mediaCodec, BitrateAdjuster bitrateAdjuster) {
+        super(mediaCodec, bitrateAdjuster);
     }
 
     @Override
diff --git a/media/base/android/java/src/org/chromium/media/MediaCodecUtil.java b/media/base/android/java/src/org/chromium/media/MediaCodecUtil.java
index b6340dea..42d81a6b 100644
--- a/media/base/android/java/src/org/chromium/media/MediaCodecUtil.java
+++ b/media/base/android/java/src/org/chromium/media/MediaCodecUtil.java
@@ -41,7 +41,7 @@
     public static class CodecCreationInfo {
         public MediaCodec mediaCodec;
         public boolean supportsAdaptivePlayback;
-        public BitrateAdjustmentTypes bitrateAdjustmentType = BitrateAdjustmentTypes.NO_ADJUSTMENT;
+        public BitrateAdjuster bitrateAdjuster = BitrateAdjuster.NO_ADJUSTMENT;
     }
 
     public static final class MimeTypes {
@@ -53,16 +53,6 @@
         public static final String VIDEO_VP9 = "video/x-vnd.on2.vp9";
     }
 
-    // Type of bitrate adjustment for video encoder.
-    public enum BitrateAdjustmentTypes {
-        // No adjustment - video encoder has no known bitrate problem.
-        NO_ADJUSTMENT,
-        // Framerate based bitrate adjustment is required - HW encoder does not use frame
-        // timestamps to calculate frame bitrate budget and instead is relying on initial
-        // fps configuration assuming that all frames are coming at fixed initial frame rate.
-        FRAMERATE_ADJUSTMENT,
-    }
-
     /**
      * Class to abstract platform version API differences for interacting with
      * the MediaCodecList.
@@ -506,25 +496,25 @@
     // List of supported HW encoders.
     private static enum HWEncoderProperties {
         QcomVp8(MimeTypes.VIDEO_VP8, "OMX.qcom.", Build.VERSION_CODES.KITKAT,
-                BitrateAdjustmentTypes.NO_ADJUSTMENT),
+                BitrateAdjuster.NO_ADJUSTMENT),
         QcomH264(MimeTypes.VIDEO_H264, "OMX.qcom.", Build.VERSION_CODES.KITKAT,
-                BitrateAdjustmentTypes.NO_ADJUSTMENT),
+                BitrateAdjuster.NO_ADJUSTMENT),
         ExynosVp8(MimeTypes.VIDEO_VP8, "OMX.Exynos.", Build.VERSION_CODES.M,
-                BitrateAdjustmentTypes.NO_ADJUSTMENT),
+                BitrateAdjuster.NO_ADJUSTMENT),
         ExynosH264(MimeTypes.VIDEO_H264, "OMX.Exynos.", Build.VERSION_CODES.LOLLIPOP,
-                BitrateAdjustmentTypes.FRAMERATE_ADJUSTMENT);
+                BitrateAdjuster.FRAMERATE_ADJUSTMENT);
 
         private final String mMime;
         private final String mPrefix;
         private final int mMinSDK;
-        private final BitrateAdjustmentTypes mBitrateAdjustmentType;
+        private final BitrateAdjuster mBitrateAdjuster;
 
-        private HWEncoderProperties(String mime, String prefix, int minSDK,
-                BitrateAdjustmentTypes bitrateAdjustmentType) {
+        private HWEncoderProperties(
+                String mime, String prefix, int minSDK, BitrateAdjuster bitrateAdjuster) {
             this.mMime = mime;
             this.mPrefix = prefix;
             this.mMinSDK = minSDK;
-            this.mBitrateAdjustmentType = bitrateAdjustmentType;
+            this.mBitrateAdjuster = bitrateAdjuster;
         }
 
         public String getMime() {
@@ -539,8 +529,8 @@
             return mMinSDK;
         }
 
-        public BitrateAdjustmentTypes getBitrateAdjustmentType() {
-            return mBitrateAdjustmentType;
+        public BitrateAdjuster getBitrateAdjuster() {
+            return mBitrateAdjuster;
         }
     }
 
@@ -568,7 +558,7 @@
         try {
             result.mediaCodec = MediaCodec.createEncoderByType(mime);
             result.supportsAdaptivePlayback = false;
-            result.bitrateAdjustmentType = encoderProperties.getBitrateAdjustmentType();
+            result.bitrateAdjuster = encoderProperties.getBitrateAdjuster();
         } catch (Exception e) {
             Log.e(TAG, "Failed to create MediaCodec: %s", mime, e);
         }
diff --git a/media/base/android/java/src/test/org/chromium/media/BitrateAdjusterTest.java b/media/base/android/java/src/test/org/chromium/media/BitrateAdjusterTest.java
new file mode 100644
index 0000000..72b0bd9
--- /dev/null
+++ b/media/base/android/java/src/test/org/chromium/media/BitrateAdjusterTest.java
@@ -0,0 +1,67 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.media;
+
+import static org.junit.Assert.assertEquals;
+
+import android.support.test.filters.SmallTest;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.BlockJUnit4ClassRunner;
+
+/**
+ * Tests for BitrateAdjuster, a class used to adjust the target bitrate and framerate for certain
+ * codecs in video encoders with fixed framerates.
+ */
+@RunWith(BlockJUnit4ClassRunner.class)
+public class BitrateAdjusterTest {
+    private static final int BITRATE_4_KBPS = 4000000;
+    private static final int BITRATE_8_KBPS = 8000000;
+    private static final int BITRATE_16_KBPS = 16000000;
+
+    @Test
+    @SmallTest
+    public void testNoAdjustmentDoesNotChangeTargetBitrate() {
+        assertEquals(
+                BitrateAdjuster.NO_ADJUSTMENT.getTargetBitrate(BITRATE_8_KBPS, 30), BITRATE_8_KBPS);
+        assertEquals(
+                BitrateAdjuster.NO_ADJUSTMENT.getTargetBitrate(BITRATE_8_KBPS, 15), BITRATE_8_KBPS);
+    }
+
+    @Test
+    @SmallTest
+    public void testNoAdjustmentInitialFrameRateIsClamped() {
+        assertEquals(BitrateAdjuster.NO_ADJUSTMENT.getInitialFrameRate(15), 15);
+        assertEquals(BitrateAdjuster.NO_ADJUSTMENT.getInitialFrameRate(30), 30);
+        assertEquals(BitrateAdjuster.NO_ADJUSTMENT.getInitialFrameRate(60), 30);
+    }
+
+    @Test
+    @SmallTest
+    public void testFrameRateAdjustmentAdjustsAccordingToFrameRate() {
+        assertEquals(BitrateAdjuster.FRAMERATE_ADJUSTMENT.getTargetBitrate(BITRATE_8_KBPS, 30),
+                BITRATE_8_KBPS);
+        assertEquals(BitrateAdjuster.FRAMERATE_ADJUSTMENT.getTargetBitrate(BITRATE_8_KBPS, 15),
+                BITRATE_16_KBPS);
+        assertEquals(BitrateAdjuster.FRAMERATE_ADJUSTMENT.getTargetBitrate(BITRATE_8_KBPS, 60),
+                BITRATE_4_KBPS);
+    }
+
+    @Test
+    @SmallTest
+    public void testFrameRateAdjustmentDoesNotDivideByZero() {
+        assertEquals(BitrateAdjuster.FRAMERATE_ADJUSTMENT.getTargetBitrate(BITRATE_8_KBPS, 0),
+                BITRATE_8_KBPS);
+    }
+
+    @Test
+    @SmallTest
+    public void testFrameRateAdjustmentUsesFixedInitialFrameRate() {
+        assertEquals(BitrateAdjuster.FRAMERATE_ADJUSTMENT.getInitialFrameRate(15), 30);
+        assertEquals(BitrateAdjuster.FRAMERATE_ADJUSTMENT.getInitialFrameRate(30), 30);
+        assertEquals(BitrateAdjuster.FRAMERATE_ADJUSTMENT.getInitialFrameRate(60), 30);
+    }
+}
diff --git a/media/base/fake_demuxer_stream.cc b/media/base/fake_demuxer_stream.cc
index 9008e96..963414c 100644
--- a/media/base/fake_demuxer_stream.cc
+++ b/media/base/fake_demuxer_stream.cc
@@ -156,7 +156,7 @@
 void FakeDemuxerStream::UpdateVideoDecoderConfig() {
   const gfx::Rect kVisibleRect(kStartWidth, kStartHeight);
   video_decoder_config_.Initialize(
-      kCodecVP8, VIDEO_CODEC_PROFILE_UNKNOWN, PIXEL_FORMAT_YV12,
+      kCodecVP8, VIDEO_CODEC_PROFILE_UNKNOWN, PIXEL_FORMAT_I420,
       COLOR_SPACE_UNSPECIFIED, VIDEO_ROTATION_0, next_coded_size_, kVisibleRect,
       next_coded_size_, EmptyExtraData(),
       is_encrypted_ ? AesCtrEncryptionScheme() : Unencrypted());
diff --git a/media/base/null_video_sink_unittest.cc b/media/base/null_video_sink_unittest.cc
index c21e930..2b4c5e1 100644
--- a/media/base/null_video_sink_unittest.cc
+++ b/media/base/null_video_sink_unittest.cc
@@ -42,7 +42,7 @@
 
   scoped_refptr<VideoFrame> CreateFrame(base::TimeDelta timestamp) {
     const gfx::Size natural_size(8, 8);
-    return VideoFrame::CreateFrame(PIXEL_FORMAT_YV12, natural_size,
+    return VideoFrame::CreateFrame(PIXEL_FORMAT_I420, natural_size,
                                    gfx::Rect(natural_size), natural_size,
                                    timestamp);
   }
diff --git a/media/base/test_helpers.cc b/media/base/test_helpers.cc
index 351bcc6..84aaaf0 100644
--- a/media/base/test_helpers.cc
+++ b/media/base/test_helpers.cc
@@ -133,7 +133,7 @@
   gfx::Size natural_size = coded_size;
 
   return VideoDecoderConfig(
-      codec, VIDEO_CODEC_PROFILE_UNKNOWN, PIXEL_FORMAT_YV12, COLOR_SPACE_JPEG,
+      codec, VIDEO_CODEC_PROFILE_UNKNOWN, PIXEL_FORMAT_I420, COLOR_SPACE_JPEG,
       rotation, coded_size, visible_rect, natural_size, EmptyExtraData(),
       is_encrypted ? AesCtrEncryptionScheme() : Unencrypted());
 }
diff --git a/media/base/video_decoder_config_unittest.cc b/media/base/video_decoder_config_unittest.cc
index 7094b67..4697c769 100644
--- a/media/base/video_decoder_config_unittest.cc
+++ b/media/base/video_decoder_config_unittest.cc
@@ -10,7 +10,7 @@
 
 namespace media {
 
-static const VideoPixelFormat kVideoFormat = PIXEL_FORMAT_YV12;
+static const VideoPixelFormat kVideoFormat = PIXEL_FORMAT_I420;
 static const gfx::Size kCodedSize(320, 240);
 static const gfx::Rect kVisibleRect(320, 240);
 static const gfx::Size kNaturalSize(320, 240);
diff --git a/media/base/video_frame.cc b/media/base/video_frame.cc
index 3900b25..2657df8 100644
--- a/media/base/video_frame.cc
+++ b/media/base/video_frame.cc
@@ -481,7 +481,7 @@
     uint8_t v,
     base::TimeDelta timestamp) {
   scoped_refptr<VideoFrame> frame =
-      CreateFrame(PIXEL_FORMAT_YV12, size, gfx::Rect(size), size, timestamp);
+      CreateFrame(PIXEL_FORMAT_I420, size, gfx::Rect(size), size, timestamp);
   FillYUV(frame.get(), y, u, v);
   return frame;
 }
diff --git a/media/base/video_frame_pool_unittest.cc b/media/base/video_frame_pool_unittest.cc
index 548ece9..6f56a30 100644
--- a/media/base/video_frame_pool_unittest.cc
+++ b/media/base/video_frame_pool_unittest.cc
@@ -60,25 +60,25 @@
 
 INSTANTIATE_TEST_CASE_P(,
                         VideoFramePoolTest,
-                        testing::Values(PIXEL_FORMAT_YV12,
+                        testing::Values(PIXEL_FORMAT_I420,
                                         PIXEL_FORMAT_NV12,
                                         PIXEL_FORMAT_ARGB));
 
 TEST_F(VideoFramePoolTest, SimpleFrameReuse) {
-  scoped_refptr<VideoFrame> frame = CreateFrame(PIXEL_FORMAT_YV12, 10);
+  scoped_refptr<VideoFrame> frame = CreateFrame(PIXEL_FORMAT_I420, 10);
   const uint8_t* old_y_data = frame->data(VideoFrame::kYPlane);
 
   // Clear frame reference to return the frame to the pool.
   frame = NULL;
 
   // Verify that the next frame from the pool uses the same memory.
-  scoped_refptr<VideoFrame> new_frame = CreateFrame(PIXEL_FORMAT_YV12, 20);
+  scoped_refptr<VideoFrame> new_frame = CreateFrame(PIXEL_FORMAT_I420, 20);
   EXPECT_EQ(old_y_data, new_frame->data(VideoFrame::kYPlane));
 }
 
 TEST_F(VideoFramePoolTest, SimpleFormatChange) {
-  scoped_refptr<VideoFrame> frame_a = CreateFrame(PIXEL_FORMAT_YV12, 10);
-  scoped_refptr<VideoFrame> frame_b = CreateFrame(PIXEL_FORMAT_YV12, 10);
+  scoped_refptr<VideoFrame> frame_a = CreateFrame(PIXEL_FORMAT_I420, 10);
+  scoped_refptr<VideoFrame> frame_b = CreateFrame(PIXEL_FORMAT_I420, 10);
 
   // Clear frame references to return the frames to the pool.
   frame_a = NULL;
@@ -94,7 +94,7 @@
 }
 
 TEST_F(VideoFramePoolTest, FrameValidAfterPoolDestruction) {
-  scoped_refptr<VideoFrame> frame = CreateFrame(PIXEL_FORMAT_YV12, 10);
+  scoped_refptr<VideoFrame> frame = CreateFrame(PIXEL_FORMAT_I420, 10);
 
   // Destroy the pool.
   pool_.reset();
@@ -106,8 +106,8 @@
 }
 
 TEST_F(VideoFramePoolTest, StaleFramesAreExpired) {
-  scoped_refptr<VideoFrame> frame_1 = CreateFrame(PIXEL_FORMAT_YV12, 10);
-  scoped_refptr<VideoFrame> frame_2 = CreateFrame(PIXEL_FORMAT_YV12, 10);
+  scoped_refptr<VideoFrame> frame_1 = CreateFrame(PIXEL_FORMAT_I420, 10);
+  scoped_refptr<VideoFrame> frame_2 = CreateFrame(PIXEL_FORMAT_I420, 10);
   EXPECT_NE(frame_1.get(), frame_2.get());
   CheckPoolSize(0u);
 
diff --git a/media/base/video_frame_unittest.cc b/media/base/video_frame_unittest.cc
index b601756..36d6d11 100644
--- a/media/base/video_frame_unittest.cc
+++ b/media/base/video_frame_unittest.cc
@@ -208,7 +208,7 @@
       frame->metadata()->IsTrue(VideoFrameMetadata::END_OF_STREAM));
 
   // Test |frame| properties.
-  EXPECT_EQ(PIXEL_FORMAT_YV12, frame->format());
+  EXPECT_EQ(PIXEL_FORMAT_I420, frame->format());
   EXPECT_EQ(kWidth, frame->coded_size().width());
   EXPECT_EQ(kHeight, frame->coded_size().height());
 
diff --git a/media/base/video_util_unittest.cc b/media/base/video_util_unittest.cc
index 4fdef2c..bab5b34 100644
--- a/media/base/video_util_unittest.cc
+++ b/media/base/video_util_unittest.cc
@@ -172,7 +172,7 @@
   void CreateDestinationFrame(int width, int height) {
     gfx::Size size(width, height);
     destination_frame_ = VideoFrame::CreateFrame(
-        PIXEL_FORMAT_YV12, size, gfx::Rect(size), size, base::TimeDelta());
+        PIXEL_FORMAT_I420, size, gfx::Rect(size), size, base::TimeDelta());
   }
 
  private:
@@ -481,7 +481,7 @@
   int height = 30;
   gfx::Size size(width, height);
   scoped_refptr<VideoFrame> frame(VideoFrame::CreateFrame(
-      PIXEL_FORMAT_YV12, size, gfx::Rect(size), size, base::TimeDelta()));
+      PIXEL_FORMAT_I420, size, gfx::Rect(size), size, base::TimeDelta()));
 
   for (int left_margin = 0; left_margin <= 10; left_margin += 10) {
     for (int right_margin = 0; right_margin <= 10; right_margin += 10) {
diff --git a/media/blink/multibuffer.cc b/media/blink/multibuffer.cc
index d45005a..c063336 100644
--- a/media/blink/multibuffer.cc
+++ b/media/blink/multibuffer.cc
@@ -213,7 +213,7 @@
   }
   if (!provider) {
     DCHECK(writer_index_.find(pos) == writer_index_.end());
-    writer_index_[pos] = CreateWriter(pos);
+    writer_index_[pos] = CreateWriter(pos, is_client_audio_element_);
     provider = writer_index_[pos].get();
   }
   provider->SetDeferred(false);
diff --git a/media/blink/multibuffer.h b/media/blink/multibuffer.h
index 1e959b0..be1ea23 100644
--- a/media/blink/multibuffer.h
+++ b/media/blink/multibuffer.h
@@ -288,6 +288,11 @@
   const DataMap& map() const { return data_; }
   int32_t block_size_shift() const { return block_size_shift_; }
 
+  // Setters.
+  void SetIsClientAudioElement(bool is_client_audio_element) {
+    is_client_audio_element_ = is_client_audio_element;
+  }
+
   // Callback which notifies us that a data provider has
   // some data for us. Also called when it might be appropriate
   // for a provider in a deferred state to wake up.
@@ -296,7 +301,9 @@
  protected:
   // Create a new writer at |pos| and return it.
   // Users needs to implemement this method.
-  virtual std::unique_ptr<DataProvider> CreateWriter(const BlockId& pos) = 0;
+  virtual std::unique_ptr<DataProvider> CreateWriter(
+      const BlockId& pos,
+      bool is_client_audio_element) = 0;
 
   virtual bool RangeSupported() const = 0;
 
@@ -340,6 +347,9 @@
   // log2 of block size.
   int32_t block_size_shift_;
 
+  // Is the client an audio element?
+  bool is_client_audio_element_ = false;
+
   // Stores the actual data.
   DataMap data_;
 
diff --git a/media/blink/multibuffer_data_source.cc b/media/blink/multibuffer_data_source.cc
index cddad15..45f81d8 100644
--- a/media/blink/multibuffer_data_source.cc
+++ b/media/blink/multibuffer_data_source.cc
@@ -191,6 +191,7 @@
   init_cb_ = init_cb;
 
   CreateResourceLoader(0, kPositionNotSpecified);
+  reader_->SetIsClientAudioElement(is_client_audio_element_);
 
   // We're not allowed to call Wait() if data is already available.
   if (reader_->Available()) {
diff --git a/media/blink/multibuffer_data_source.h b/media/blink/multibuffer_data_source.h
index ca080d116..43695ab 100644
--- a/media/blink/multibuffer_data_source.h
+++ b/media/blink/multibuffer_data_source.h
@@ -114,6 +114,9 @@
   bool GetSize(int64_t* size_out) override;
   bool IsStreaming() override;
   void SetBitrate(int bitrate) override;
+  void SetIsClientAudioElement(bool is_client_audio_element) {
+    is_client_audio_element_ = is_client_audio_element;
+  }
 
  protected:
   void OnRedirect(const scoped_refptr<UrlData>& destination);
@@ -246,6 +249,8 @@
 
   MediaLog* media_log_;
 
+  bool is_client_audio_element_ = false;
+
   int buffer_size_update_counter_;
 
   // Host object to report buffered byte range changes to.
diff --git a/media/blink/multibuffer_data_source_unittest.cc b/media/blink/multibuffer_data_source_unittest.cc
index 62bb9b12..8b8a911 100644
--- a/media/blink/multibuffer_data_source_unittest.cc
+++ b/media/blink/multibuffer_data_source_unittest.cc
@@ -46,7 +46,9 @@
 class TestMultiBufferDataProvider : public ResourceMultiBufferDataProvider {
  public:
   TestMultiBufferDataProvider(UrlData* url_data, MultiBuffer::BlockId pos)
-      : ResourceMultiBufferDataProvider(url_data, pos) {
+      : ResourceMultiBufferDataProvider(url_data,
+                                        pos,
+                                        false /* is_client_audio_element */) {
     CHECK(test_data_providers.insert(this).second);
   }
   ~TestMultiBufferDataProvider() override {
@@ -80,8 +82,8 @@
   explicit TestResourceMultiBuffer(UrlData* url_data, int shift)
       : ResourceMultiBuffer(url_data, shift) {}
 
-  std::unique_ptr<MultiBuffer::DataProvider> CreateWriter(
-      const BlockId& pos) override {
+  std::unique_ptr<MultiBuffer::DataProvider> CreateWriter(const BlockId& pos,
+                                                          bool) override {
     auto writer = base::MakeUnique<TestMultiBufferDataProvider>(url_data_, pos);
     writer->Start();
     return writer;
diff --git a/media/blink/multibuffer_reader.cc b/media/blink/multibuffer_reader.cc
index a22548c..2973c164 100644
--- a/media/blink/multibuffer_reader.cc
+++ b/media/blink/multibuffer_reader.cc
@@ -222,6 +222,7 @@
            << " block_ceil(end_) = " << block_ceil(end_) << " end_ = " << end_
            << " max_preload " << max_preload;
 
+  multibuffer_->SetIsClientAudioElement(is_client_audio_element_);
   if (preload_pos_ < block_ceil(end_)) {
     if (preload_pos_ < max_preload) {
       loading_ = true;
diff --git a/media/blink/multibuffer_reader.h b/media/blink/multibuffer_reader.h
index 45085260..56f648b 100644
--- a/media/blink/multibuffer_reader.h
+++ b/media/blink/multibuffer_reader.h
@@ -102,6 +102,11 @@
   int64_t preload_high() const { return preload_high_; }
   int64_t preload_low() const { return preload_low_; }
 
+  // Setters
+  void SetIsClientAudioElement(bool is_client_audio_element) {
+    is_client_audio_element_ = is_client_audio_element;
+  }
+
  private:
   friend class MultibufferDataSourceTest;
 
@@ -159,6 +164,9 @@
   // Current position in bytes.
   int64_t pos_;
 
+  // Is the client an audio element?
+  bool is_client_audio_element_ = false;
+
   // [block(pos_)..preload_pos_) are known to be in the cache.
   // preload_pos_ is only allowed to point to a filled
   // cache position if it is equal to end_ or pos_+preload_.
diff --git a/media/blink/multibuffer_unittest.cc b/media/blink/multibuffer_unittest.cc
index 9784968..9ecce0cf 100644
--- a/media/blink/multibuffer_unittest.cc
+++ b/media/blink/multibuffer_unittest.cc
@@ -190,8 +190,8 @@
   void SetRangeSupported(bool supported) { range_supported_ = supported; }
 
  protected:
-  std::unique_ptr<DataProvider> CreateWriter(
-      const MultiBufferBlockId& pos) override {
+  std::unique_ptr<DataProvider> CreateWriter(const MultiBufferBlockId& pos,
+                                             bool) override {
     DCHECK(create_ok_);
     writers_created_++;
     CHECK_LT(writers.size(), max_writers_);
diff --git a/media/blink/resource_multibuffer_data_provider.cc b/media/blink/resource_multibuffer_data_provider.cc
index 8c1c591..de6d590 100644
--- a/media/blink/resource_multibuffer_data_provider.cc
+++ b/media/blink/resource_multibuffer_data_provider.cc
@@ -54,12 +54,14 @@
 
 ResourceMultiBufferDataProvider::ResourceMultiBufferDataProvider(
     UrlData* url_data,
-    MultiBufferBlockId pos)
+    MultiBufferBlockId pos,
+    bool is_client_audio_element)
     : pos_(pos),
       url_data_(url_data),
       retries_(0),
       cors_mode_(url_data->cors_mode()),
       origin_(url_data->url().GetOrigin()),
+      is_client_audio_element_(is_client_audio_element),
       weak_factory_(this) {
   DCHECK(url_data_) << " pos = " << pos;
   DCHECK_GE(pos, 0);
@@ -78,8 +80,9 @@
 
   // Prepare the request.
   WebURLRequest request(url_data_->url());
-  // TODO(mkwst): Split this into video/audio.
-  request.SetRequestContext(WebURLRequest::kRequestContextVideo);
+  request.SetRequestContext(is_client_audio_element_
+                                ? WebURLRequest::kRequestContextAudio
+                                : WebURLRequest::kRequestContextVideo);
   request.SetHTTPHeaderField(
       WebString::FromUTF8(net::HttpRequestHeaders::kRange),
       WebString::FromUTF8(
diff --git a/media/blink/resource_multibuffer_data_provider.h b/media/blink/resource_multibuffer_data_provider.h
index a38c291..b4058207 100644
--- a/media/blink/resource_multibuffer_data_provider.h
+++ b/media/blink/resource_multibuffer_data_provider.h
@@ -33,7 +33,9 @@
   // NUmber of times we'll retry if the connection fails.
   enum { kMaxRetries = 30 };
 
-  ResourceMultiBufferDataProvider(UrlData* url_data, MultiBufferBlockId pos);
+  ResourceMultiBufferDataProvider(UrlData* url_data,
+                                  MultiBufferBlockId pos,
+                                  bool is_client_audio_element);
   ~ResourceMultiBufferDataProvider() override;
 
   // Virtual for testing purposes.
@@ -120,6 +122,9 @@
   // many bytes we need to discard before we get to the right place.
   uint64_t bytes_to_discard_ = 0;
 
+  // Is the client an audio element?
+  bool is_client_audio_element_ = false;
+
   base::WeakPtrFactory<ResourceMultiBufferDataProvider> weak_factory_;
 };
 
diff --git a/media/blink/resource_multibuffer_data_provider_unittest.cc b/media/blink/resource_multibuffer_data_provider_unittest.cc
index a948dff..b0d703b 100644
--- a/media/blink/resource_multibuffer_data_provider_unittest.cc
+++ b/media/blink/resource_multibuffer_data_provider_unittest.cc
@@ -94,7 +94,9 @@
     first_position_ = first_position;
 
     std::unique_ptr<ResourceMultiBufferDataProvider> loader(
-        new ResourceMultiBufferDataProvider(url_data_.get(), first_position_));
+        new ResourceMultiBufferDataProvider(
+            url_data_.get(), first_position_,
+            false /* is_client_audio_element */));
     loader_ = loader.get();
     url_data_->multibuffer()->AddProvider(std::move(loader));
   }
diff --git a/media/blink/url_index.cc b/media/blink/url_index.cc
index b2c7f44c..22a94b5 100644
--- a/media/blink/url_index.cc
+++ b/media/blink/url_index.cc
@@ -27,9 +27,10 @@
 ResourceMultiBuffer::~ResourceMultiBuffer() = default;
 
 std::unique_ptr<MultiBuffer::DataProvider> ResourceMultiBuffer::CreateWriter(
-    const MultiBufferBlockId& pos) {
-  auto writer =
-      base::MakeUnique<ResourceMultiBufferDataProvider>(url_data_, pos);
+    const MultiBufferBlockId& pos,
+    bool is_client_audio_element) {
+  auto writer = base::MakeUnique<ResourceMultiBufferDataProvider>(
+      url_data_, pos, is_client_audio_element);
   writer->Start();
   return writer;
 }
diff --git a/media/blink/url_index.h b/media/blink/url_index.h
index 3e71fbe..165b6187 100644
--- a/media/blink/url_index.h
+++ b/media/blink/url_index.h
@@ -38,7 +38,8 @@
 
   // MultiBuffer implementation.
   std::unique_ptr<MultiBuffer::DataProvider> CreateWriter(
-      const BlockId& pos) override;
+      const BlockId& pos,
+      bool is_client_audio_element) override;
   bool RangeSupported() const override;
   void OnEmpty() override;
 
diff --git a/media/blink/video_decode_stats_reporter_unittest.cc b/media/blink/video_decode_stats_reporter_unittest.cc
index 82b5b97..a9afd322 100644
--- a/media/blink/video_decode_stats_reporter_unittest.cc
+++ b/media/blink/video_decode_stats_reporter_unittest.cc
@@ -39,7 +39,7 @@
                                    gfx::Size natural_size) {
   gfx::Size coded_size = natural_size;
   gfx::Rect visible_rect(coded_size.width(), coded_size.height());
-  return VideoDecoderConfig(codec, profile, PIXEL_FORMAT_YV12, COLOR_SPACE_JPEG,
+  return VideoDecoderConfig(codec, profile, PIXEL_FORMAT_I420, COLOR_SPACE_JPEG,
                             VIDEO_ROTATION_0, coded_size, visible_rect,
                             natural_size, EmptyExtraData(), Unencrypted());
 }
diff --git a/media/blink/video_frame_compositor_unittest.cc b/media/blink/video_frame_compositor_unittest.cc
index cfcf9db..45fab78c 100644
--- a/media/blink/video_frame_compositor_unittest.cc
+++ b/media/blink/video_frame_compositor_unittest.cc
@@ -80,7 +80,7 @@
 
   scoped_refptr<VideoFrame> CreateOpaqueFrame() {
     gfx::Size size(8, 8);
-    return VideoFrame::CreateFrame(PIXEL_FORMAT_YV12, size, gfx::Rect(size),
+    return VideoFrame::CreateFrame(PIXEL_FORMAT_I420, size, gfx::Rect(size),
                                    size, base::TimeDelta());
   }
 
diff --git a/media/blink/webmediaplayer_impl.cc b/media/blink/webmediaplayer_impl.cc
index 1fa7c3d..ad18408 100644
--- a/media/blink/webmediaplayer_impl.cc
+++ b/media/blink/webmediaplayer_impl.cc
@@ -582,6 +582,7 @@
         media_log_.get(), &buffered_data_source_host_,
         base::Bind(&WebMediaPlayerImpl::NotifyDownloading, AsWeakPtr())));
     data_source_->SetPreload(preload_);
+    data_source_->SetIsClientAudioElement(client_->IsAudioElement());
     data_source_->Initialize(
         base::Bind(&WebMediaPlayerImpl::DataSourceInitialized, AsWeakPtr()));
   }
@@ -2539,7 +2540,7 @@
   const int64_t video_memory_usage =
       stats.video_memory_usage +
       (pipeline_metadata_.has_video && !stats.video_memory_usage
-           ? VideoFrame::AllocationSize(PIXEL_FORMAT_YV12,
+           ? VideoFrame::AllocationSize(PIXEL_FORMAT_I420,
                                         pipeline_metadata_.natural_size)
            : 0);
 
diff --git a/media/capture/content/android/screen_capture_machine_android.cc b/media/capture/content/android/screen_capture_machine_android.cc
index 969cdad..96b141c 100644
--- a/media/capture/content/android/screen_capture_machine_android.cc
+++ b/media/capture/content/android/screen_capture_machine_android.cc
@@ -51,8 +51,7 @@
     return;
   }
 
-  DCHECK(frame->format() == PIXEL_FORMAT_I420 ||
-         frame->format() == PIXEL_FORMAT_YV12);
+  DCHECK(frame->format() == PIXEL_FORMAT_I420);
 
   scoped_refptr<VideoFrame> temp_frame = frame;
   if (frame->visible_rect().width() != width ||
@@ -127,8 +126,7 @@
     return;
   }
 
-  DCHECK(frame->format() == PIXEL_FORMAT_I420 ||
-         frame->format() == PIXEL_FORMAT_YV12);
+  DCHECK(frame->format() == PIXEL_FORMAT_I420);
 
   scoped_refptr<VideoFrame> temp_frame = frame;
   if (frame->visible_rect().width() != width ||
@@ -291,8 +289,7 @@
     return;
   }
 
-  DCHECK(frame->format() == PIXEL_FORMAT_I420 ||
-         frame->format() == PIXEL_FORMAT_YV12);
+  DCHECK(frame->format() == PIXEL_FORMAT_I420);
 
   libyuv::I420Scale(
       lastFrame_->visible_data(VideoFrame::kYPlane),
diff --git a/media/capture/video/android/java/src/org/chromium/media/VideoCaptureCamera2.java b/media/capture/video/android/java/src/org/chromium/media/VideoCaptureCamera2.java
index cbad4dd..c410449a 100644
--- a/media/capture/video/android/java/src/org/chromium/media/VideoCaptureCamera2.java
+++ b/media/capture/video/android/java/src/org/chromium/media/VideoCaptureCamera2.java
@@ -185,7 +185,7 @@
         }
     };
 
-    private static final double kNanoSecondsToFps = 1.0E-9;
+    private static final double kNanosecondsPerSecond = 1000000000;
     private static final String TAG = "VideoCapture";
     private static final long PRECAPTURE_TIMEOUT_MS = 1000;
 
@@ -601,17 +601,18 @@
             for (Size size : sizes) {
                 double minFrameRate = 0.0f;
                 if (minFrameDurationAvailable) {
-                    final long minFrameDuration = streamMap.getOutputMinFrameDuration(format, size);
-                    minFrameRate = (minFrameDuration == 0)
+                    final long minFrameDurationInNanoseconds =
+                            streamMap.getOutputMinFrameDuration(format, size);
+                    minFrameRate = (minFrameDurationInNanoseconds == 0)
                             ? 0.0f
-                            : (1.0 / kNanoSecondsToFps * minFrameDuration);
+                            : (kNanosecondsPerSecond / minFrameDurationInNanoseconds);
                 } else {
                     // TODO(mcasas): find out where to get the info from in this case.
                     // Hint: perhaps using SCALER_AVAILABLE_PROCESSED_MIN_DURATIONS.
                     minFrameRate = 0.0;
                 }
                 formatList.add(new VideoCaptureFormat(
-                        size.getWidth(), size.getHeight(), (int) minFrameRate, 0));
+                        size.getWidth(), size.getHeight(), (int) minFrameRate, format));
             }
         }
         return formatList.toArray(new VideoCaptureFormat[formatList.size()]);
diff --git a/media/capture/video/android/video_capture_device_factory_android.cc b/media/capture/video/android/video_capture_device_factory_android.cc
index d9ee746..8f576f1 100644
--- a/media/capture/video/android/video_capture_device_factory_android.cc
+++ b/media/capture/video/android/video_capture_device_factory_android.cc
@@ -112,6 +112,9 @@
       case VideoCaptureDeviceAndroid::ANDROID_IMAGE_FORMAT_NV21:
         pixel_format = PIXEL_FORMAT_NV21;
         break;
+      case VideoCaptureDeviceAndroid::ANDROID_IMAGE_FORMAT_YUV_420_888:
+        pixel_format = PIXEL_FORMAT_I420;
+        break;
       default:
         // TODO(mcasas): break here and let the enumeration continue with
         // UNKNOWN pixel format because the platform doesn't know until capture,
diff --git a/media/cast/receiver/video_decoder_unittest.cc b/media/cast/receiver/video_decoder_unittest.cc
index da3d1266..a3f40c0c 100644
--- a/media/cast/receiver/video_decoder_unittest.cc
+++ b/media/cast/receiver/video_decoder_unittest.cc
@@ -78,7 +78,7 @@
 
     // Prepare a simulated VideoFrame to feed into the VideoEncoder.
     const scoped_refptr<VideoFrame> video_frame = VideoFrame::CreateFrame(
-        PIXEL_FORMAT_YV12, next_frame_size_, gfx::Rect(next_frame_size_),
+        PIXEL_FORMAT_I420, next_frame_size_, gfx::Rect(next_frame_size_),
         next_frame_size_, next_frame_timestamp_);
     const base::TimeTicks reference_time =
         base::TimeTicks::UnixEpoch() + next_frame_timestamp_;
diff --git a/media/cast/sender/vp8_quantizer_parser_unittest.cc b/media/cast/sender/vp8_quantizer_parser_unittest.cc
index 65db392..b25c668 100644
--- a/media/cast/sender/vp8_quantizer_parser_unittest.cc
+++ b/media/cast/sender/vp8_quantizer_parser_unittest.cc
@@ -46,7 +46,7 @@
   void EncodeOneFrame(SenderEncodedFrame* encoded_frame) {
     const gfx::Size frame_size = gfx::Size(kWidth, kHeight);
     const scoped_refptr<VideoFrame> video_frame = VideoFrame::CreateFrame(
-        PIXEL_FORMAT_YV12, frame_size, gfx::Rect(frame_size), frame_size,
+        PIXEL_FORMAT_I420, frame_size, gfx::Rect(frame_size), frame_size,
         next_frame_timestamp_);
     const base::TimeTicks reference_time =
         base::TimeTicks::UnixEpoch() + next_frame_timestamp_;
diff --git a/media/cast/test/fake_media_source.cc b/media/cast/test/fake_media_source.cc
index 83553bc..6ab8938 100644
--- a/media/cast/test/fake_media_source.cc
+++ b/media/cast/test/fake_media_source.cc
@@ -191,7 +191,7 @@
     } else if (av_codec->type == AVMEDIA_TYPE_VIDEO) {
       VideoPixelFormat format =
           AVPixelFormatToVideoPixelFormat(av_codec_context->pix_fmt);
-      if (format != PIXEL_FORMAT_YV12) {
+      if (format != PIXEL_FORMAT_I420) {
         LOG(ERROR) << "Cannot handle non YV12 video format: " << format;
         continue;
       }
@@ -551,7 +551,7 @@
   AVFrame* shallow_copy = av_frame_clone(frame);
   scoped_refptr<media::VideoFrame> video_frame =
       VideoFrame::WrapExternalYuvData(
-          media::PIXEL_FORMAT_YV12, size, gfx::Rect(size), size,
+          media::PIXEL_FORMAT_I420, size, gfx::Rect(size), size,
           shallow_copy->linesize[0], shallow_copy->linesize[1],
           shallow_copy->linesize[2], shallow_copy->data[0],
           shallow_copy->data[1], shallow_copy->data[2], timestamp);
diff --git a/media/cdm/simple_cdm_allocator.cc b/media/cdm/simple_cdm_allocator.cc
index 8a566ded..d0512269 100644
--- a/media/cdm/simple_cdm_allocator.cc
+++ b/media/cdm/simple_cdm_allocator.cc
@@ -30,7 +30,7 @@
     gfx::Size frame_size(Size().width, Size().height);
     scoped_refptr<media::VideoFrame> frame =
         media::VideoFrame::WrapExternalYuvData(
-            PIXEL_FORMAT_YV12, frame_size, gfx::Rect(frame_size), natural_size,
+            PIXEL_FORMAT_I420, frame_size, gfx::Rect(frame_size), natural_size,
             Stride(kYPlane), Stride(kUPlane), Stride(kVPlane),
             buffer->Data() + PlaneOffset(kYPlane),
             buffer->Data() + PlaneOffset(kUPlane),
diff --git a/media/cdm/simple_cdm_allocator_unittest.cc b/media/cdm/simple_cdm_allocator_unittest.cc
index a1520e9f..57006c0 100644
--- a/media/cdm/simple_cdm_allocator_unittest.cc
+++ b/media/cdm/simple_cdm_allocator_unittest.cc
@@ -80,7 +80,7 @@
   // For this test we need to pretend we have valid video data. So create
   // a small video frame of size 2x2.
   gfx::Size size(2, 2);
-  size_t memory_needed = VideoFrame::AllocationSize(PIXEL_FORMAT_YV12, size);
+  size_t memory_needed = VideoFrame::AllocationSize(PIXEL_FORMAT_I420, size);
 
   // Now create a VideoFrameImpl.
   std::unique_ptr<VideoFrameImpl> video_frame =
diff --git a/media/ffmpeg/ffmpeg_common.cc b/media/ffmpeg/ffmpeg_common.cc
index 2ae56120..62dea63c 100644
--- a/media/ffmpeg/ffmpeg_common.cc
+++ b/media/ffmpeg/ffmpeg_common.cc
@@ -481,21 +481,18 @@
   switch (codec) {
 #if defined(DISABLE_FFMPEG_VIDEO_DECODERS)
     case kCodecH264:
-      // TODO(dalecurtis): This is incorrect; see http://crbug.com/784627.
-      format = PIXEL_FORMAT_YV12;
+      format = PIXEL_FORMAT_I420;
       profile = H264PROFILE_BASELINE;
       break;
 #endif
     case kCodecVP8:
 #if defined(DISABLE_FFMPEG_VIDEO_DECODERS)
-      // TODO(dalecurtis): This is incorrect; see http://crbug.com/784627.
-      format = PIXEL_FORMAT_YV12;
+      format = PIXEL_FORMAT_I420;
 #endif
       profile = VP8PROFILE_ANY;
       break;
     case kCodecVP9:
-      // TODO(dalecurtis): This is incorrect; see http://crbug.com/784627.
-      format = PIXEL_FORMAT_YV12;
+      format = PIXEL_FORMAT_I420;
       profile = VP9PROFILE_PROFILE0;
       break;
     case kCodecAV1:
@@ -692,11 +689,9 @@
     case AV_PIX_FMT_YUVJ444P:
       return PIXEL_FORMAT_I444;
 
-    // TODO(dalecurtis): This is incorrect; see http://crbug.com/784627. This
-    // should actually be PIXEL_FORMAT_I420.
     case AV_PIX_FMT_YUV420P:
     case AV_PIX_FMT_YUVJ420P:
-      return PIXEL_FORMAT_YV12;
+      return PIXEL_FORMAT_I420;
 
     case AV_PIX_FMT_YUV422P:
     case AV_PIX_FMT_YUVJ422P:
@@ -734,11 +729,8 @@
 
 AVPixelFormat VideoPixelFormatToAVPixelFormat(VideoPixelFormat video_format) {
   switch (video_format) {
-    // TODO(dalecurtis): This is incorrect; see http://crbug.com/784627.
-    // FFmpeg actually has no YVU format...
-    case PIXEL_FORMAT_YV12:
+    case PIXEL_FORMAT_I420:
       return AV_PIX_FMT_YUV420P;
-
     case PIXEL_FORMAT_I422:
       return AV_PIX_FMT_YUV422P;
     case PIXEL_FORMAT_I420A:
diff --git a/media/filters/ffmpeg_demuxer_unittest.cc b/media/filters/ffmpeg_demuxer_unittest.cc
index 2026825..0eb22b6 100644
--- a/media/filters/ffmpeg_demuxer_unittest.cc
+++ b/media/filters/ffmpeg_demuxer_unittest.cc
@@ -405,7 +405,7 @@
 
   const VideoDecoderConfig& video_config = stream->video_decoder_config();
   EXPECT_EQ(kCodecVP8, video_config.codec());
-  EXPECT_EQ(PIXEL_FORMAT_YV12, video_config.format());
+  EXPECT_EQ(PIXEL_FORMAT_I420, video_config.format());
   EXPECT_EQ(320, video_config.coded_size().width());
   EXPECT_EQ(240, video_config.coded_size().height());
   EXPECT_EQ(0, video_config.visible_rect().x());
diff --git a/media/filters/ffmpeg_video_decoder.cc b/media/filters/ffmpeg_video_decoder.cc
index 0dd68944..a27dcee6 100644
--- a/media/filters/ffmpeg_video_decoder.cc
+++ b/media/filters/ffmpeg_video_decoder.cc
@@ -133,7 +133,7 @@
 
   if (format == PIXEL_FORMAT_UNKNOWN)
     return AVERROR(EINVAL);
-  DCHECK(format == PIXEL_FORMAT_YV12 || format == PIXEL_FORMAT_I422 ||
+  DCHECK(format == PIXEL_FORMAT_I420 || format == PIXEL_FORMAT_I422 ||
          format == PIXEL_FORMAT_I444 || format == PIXEL_FORMAT_YUV420P9 ||
          format == PIXEL_FORMAT_YUV420P10 || format == PIXEL_FORMAT_YUV422P9 ||
          format == PIXEL_FORMAT_YUV422P10 || format == PIXEL_FORMAT_YUV444P9 ||
diff --git a/media/filters/ffmpeg_video_decoder_unittest.cc b/media/filters/ffmpeg_video_decoder_unittest.cc
index 9366ca5..18a8ac0 100644
--- a/media/filters/ffmpeg_video_decoder_unittest.cc
+++ b/media/filters/ffmpeg_video_decoder_unittest.cc
@@ -44,7 +44,7 @@
 
 namespace media {
 
-static const VideoPixelFormat kVideoFormat = PIXEL_FORMAT_YV12;
+static const VideoPixelFormat kVideoFormat = PIXEL_FORMAT_I420;
 static const gfx::Size kCodedSize(320, 240);
 static const gfx::Rect kVisibleRect(320, 240);
 static const gfx::Size kNaturalSize(320, 240);
diff --git a/media/filters/source_buffer_state_unittest.cc b/media/filters/source_buffer_state_unittest.cc
index 90058c9..caa4dd2 100644
--- a/media/filters/source_buffer_state_unittest.cc
+++ b/media/filters/source_buffer_state_unittest.cc
@@ -36,7 +36,7 @@
   gfx::Size size(w, h);
   gfx::Rect visible_rect(size);
   return VideoDecoderConfig(codec, VIDEO_CODEC_PROFILE_UNKNOWN,
-                            PIXEL_FORMAT_YV12, COLOR_SPACE_HD_REC709,
+                            PIXEL_FORMAT_I420, COLOR_SPACE_HD_REC709,
                             VIDEO_ROTATION_0, size, visible_rect, size,
                             EmptyExtraData(), Unencrypted());
 }
diff --git a/media/filters/video_renderer_algorithm_unittest.cc b/media/filters/video_renderer_algorithm_unittest.cc
index 1ebad31..c14f6ad 100644
--- a/media/filters/video_renderer_algorithm_unittest.cc
+++ b/media/filters/video_renderer_algorithm_unittest.cc
@@ -84,7 +84,7 @@
 
   scoped_refptr<VideoFrame> CreateFrame(base::TimeDelta timestamp) {
     const gfx::Size natural_size(8, 8);
-    return frame_pool_.CreateFrame(PIXEL_FORMAT_YV12, natural_size,
+    return frame_pool_.CreateFrame(PIXEL_FORMAT_I420, natural_size,
                                    gfx::Rect(natural_size), natural_size,
                                    timestamp);
   }
diff --git a/media/filters/vpx_video_decoder.cc b/media/filters/vpx_video_decoder.cc
index 40d0ebdc..ce76322f 100644
--- a/media/filters/vpx_video_decoder.cc
+++ b/media/filters/vpx_video_decoder.cc
@@ -237,9 +237,9 @@
 
   // These are the combinations of codec-pixel format supported in principle.
   DCHECK(
-      (config.codec() == kCodecVP8 && config.format() == PIXEL_FORMAT_YV12) ||
+      (config.codec() == kCodecVP8 && config.format() == PIXEL_FORMAT_I420) ||
       (config.codec() == kCodecVP8 && config.format() == PIXEL_FORMAT_I420A) ||
-      (config.codec() == kCodecVP9 && config.format() == PIXEL_FORMAT_YV12) ||
+      (config.codec() == kCodecVP9 && config.format() == PIXEL_FORMAT_I420) ||
       (config.codec() == kCodecVP9 && config.format() == PIXEL_FORMAT_I420A) ||
       (config.codec() == kCodecVP9 && config.format() == PIXEL_FORMAT_I444));
 
@@ -506,7 +506,7 @@
   VideoPixelFormat codec_format;
   switch (vpx_image->fmt) {
     case VPX_IMG_FMT_I420:
-      codec_format = vpx_image_alpha ? PIXEL_FORMAT_I420A : PIXEL_FORMAT_YV12;
+      codec_format = vpx_image_alpha ? PIXEL_FORMAT_I420A : PIXEL_FORMAT_I420;
       break;
 
     case VPX_IMG_FMT_I444:
@@ -601,7 +601,7 @@
     return true;
   }
 
-  DCHECK(codec_format == PIXEL_FORMAT_YV12 ||
+  DCHECK(codec_format == PIXEL_FORMAT_I420 ||
          codec_format == PIXEL_FORMAT_I420A);
 
   *video_frame = frame_pool_.CreateFrame(codec_format, visible_size,
diff --git a/media/filters/vpx_video_decoder_fuzzertest.cc b/media/filters/vpx_video_decoder_fuzzertest.cc
index 0d086de..fb8b8e73 100644
--- a/media/filters/vpx_video_decoder_fuzzertest.cc
+++ b/media/filters/vpx_video_decoder_fuzzertest.cc
@@ -65,13 +65,13 @@
   VideoPixelFormat pixel_format;
   if (rng() & 1) {
     codec = kCodecVP8;
-    // PIXEL_FORMAT_YV12 disabled for kCodecVP8 on Linux.
+    // PIXEL_FORMAT_I420 disabled for kCodecVP8 on Linux.
     pixel_format = PIXEL_FORMAT_I420A;
   } else {
     codec = kCodecVP9;
     switch (rng() % 3) {
       case 0:
-        pixel_format = PIXEL_FORMAT_YV12;
+        pixel_format = PIXEL_FORMAT_I420;
         break;
       case 1:
         pixel_format = PIXEL_FORMAT_I420A;
diff --git a/media/formats/mp2t/es_parser_h264.cc b/media/formats/mp2t/es_parser_h264.cc
index 450612e..e879a1e 100644
--- a/media/formats/mp2t/es_parser_h264.cc
+++ b/media/formats/mp2t/es_parser_h264.cc
@@ -507,7 +507,7 @@
   }
 
   VideoDecoderConfig video_decoder_config(
-      kCodecH264, profile, PIXEL_FORMAT_YV12, COLOR_SPACE_HD_REC709,
+      kCodecH264, profile, PIXEL_FORMAT_I420, COLOR_SPACE_HD_REC709,
       VIDEO_ROTATION_0, coded_size.value(), visible_rect.value(), natural_size,
       EmptyExtraData(), scheme);
 
diff --git a/media/formats/mp4/mp4_stream_parser.cc b/media/formats/mp4/mp4_stream_parser.cc
index cb389ad..cc202044 100644
--- a/media/formats/mp4/mp4_stream_parser.cc
+++ b/media/formats/mp4/mp4_stream_parser.cc
@@ -471,7 +471,7 @@
           return false;
       }
       video_config.Initialize(entry.video_codec, entry.video_codec_profile,
-                              PIXEL_FORMAT_YV12, COLOR_SPACE_HD_REC709,
+                              PIXEL_FORMAT_I420, COLOR_SPACE_HD_REC709,
                               VIDEO_ROTATION_0, coded_size, visible_rect,
                               natural_size,
                               // No decoder-specific buffer needed for AVC;
diff --git a/media/formats/webm/webm_video_client.cc b/media/formats/webm/webm_video_client.cc
index faeb6a7..651b88f 100644
--- a/media/formats/webm/webm_video_client.cc
+++ b/media/formats/webm/webm_video_client.cc
@@ -78,7 +78,7 @@
   }
 
   VideoPixelFormat format =
-      (alpha_mode_ == 1) ? PIXEL_FORMAT_I420A : PIXEL_FORMAT_YV12;
+      (alpha_mode_ == 1) ? PIXEL_FORMAT_I420A : PIXEL_FORMAT_I420;
 
   if (pixel_width_ <= 0 || pixel_height_ <= 0)
     return false;
diff --git a/media/formats/webm/webm_video_client_unittest.cc b/media/formats/webm/webm_video_client_unittest.cc
index fabb6171..a8c3192 100644
--- a/media/formats/webm/webm_video_client_unittest.cc
+++ b/media/formats/webm/webm_video_client_unittest.cc
@@ -56,7 +56,7 @@
   EXPECT_TRUE(webm_video_client_.InitializeConfig(kCodecId, codec_private,
                                                   EncryptionScheme(), &config));
 
-  VideoDecoderConfig expected_config(kCodecVP9, profile, PIXEL_FORMAT_YV12,
+  VideoDecoderConfig expected_config(kCodecVP9, profile, PIXEL_FORMAT_I420,
                                      COLOR_SPACE_HD_REC709, VIDEO_ROTATION_0,
                                      kCodedSize, gfx::Rect(kCodedSize),
                                      kCodedSize, codec_private, Unencrypted());
diff --git a/media/mojo/common/mojo_shared_buffer_video_frame_unittest.cc b/media/mojo/common/mojo_shared_buffer_video_frame_unittest.cc
index 54bee34..68f463f 100644
--- a/media/mojo/common/mojo_shared_buffer_video_frame_unittest.cc
+++ b/media/mojo/common/mojo_shared_buffer_video_frame_unittest.cc
@@ -75,7 +75,7 @@
   // Some random values to use. Since we actually don't use the data inside the
   // frame, random values are fine (as long as the offsets are within the
   // memory size allocated).
-  const VideoPixelFormat format = PIXEL_FORMAT_YV12;
+  const VideoPixelFormat format = PIXEL_FORMAT_I420;
   const size_t y_offset = kWidth * 2;
   const size_t u_offset = kWidth * 3;
   const size_t v_offset = kWidth * 5;
@@ -138,7 +138,7 @@
 }
 
 TEST(MojoSharedBufferVideoFrameTest, TestDestructionCallback) {
-  const VideoPixelFormat format = PIXEL_FORMAT_YV12;
+  const VideoPixelFormat format = PIXEL_FORMAT_I420;
   const int kWidth = 32;
   const int kHeight = 18;
   const base::TimeDelta kTimestamp = base::TimeDelta::FromMicroseconds(1338);
diff --git a/media/mojo/interfaces/BUILD.gn b/media/mojo/interfaces/BUILD.gn
index b7c7aec..3a289b3 100644
--- a/media/mojo/interfaces/BUILD.gn
+++ b/media/mojo/interfaces/BUILD.gn
@@ -21,6 +21,7 @@
     "demuxer_stream.mojom",
     "interface_factory.mojom",
     "jpeg_decode_accelerator.mojom",
+    "key_system_support.mojom",
     "media_log.mojom",
     "media_metrics_provider.mojom",
     "media_service.mojom",
diff --git a/media/mojo/interfaces/key_system_support.mojom b/media/mojo/interfaces/key_system_support.mojom
new file mode 100644
index 0000000..ac46e55
--- /dev/null
+++ b/media/mojo/interfaces/key_system_support.mojom
@@ -0,0 +1,22 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+module media.mojom;
+
+import "media/mojo/interfaces/media_types.mojom";
+
+interface KeySystemSupport {
+  // Query to determine if the browser supports the key system |key_system|.
+  // If supported, |is_supported| = true and the remaining properties indicate
+  // the codecs supported and if the key system supports persistent licenses.
+  // KeySystemSupport implementation is in the browser process, as it maintains
+  // the list of installed key systems. Clients run in the renderer process.
+  // TODO(crbug.com/796725) Find a way to include profiles and levels for
+  // |supported_video_codecs|.
+  [Sync]
+  IsKeySystemSupported(string key_system)
+    => (bool is_supported,
+        array<VideoCodec> supported_video_codecs,
+        bool supports_persistent_license);
+};
diff --git a/media/mojo/interfaces/video_decoder_config_struct_traits_unittest.cc b/media/mojo/interfaces/video_decoder_config_struct_traits_unittest.cc
index e903e4604..a337d0e 100644
--- a/media/mojo/interfaces/video_decoder_config_struct_traits_unittest.cc
+++ b/media/mojo/interfaces/video_decoder_config_struct_traits_unittest.cc
@@ -25,7 +25,7 @@
   const uint8_t kExtraData[] = "config extra data";
   const std::vector<uint8_t> kExtraDataVector(
       &kExtraData[0], &kExtraData[0] + arraysize(kExtraData));
-  VideoDecoderConfig input(kCodecVP8, VP8PROFILE_ANY, PIXEL_FORMAT_YV12,
+  VideoDecoderConfig input(kCodecVP8, VP8PROFILE_ANY, PIXEL_FORMAT_I420,
                            COLOR_SPACE_UNSPECIFIED, VIDEO_ROTATION_0,
                            kCodedSize, kVisibleRect, kNaturalSize,
                            kExtraDataVector, Unencrypted());
@@ -39,7 +39,7 @@
 
 TEST(VideoDecoderConfigStructTraitsTest,
      ConvertVideoDecoderConfig_EmptyExtraData) {
-  VideoDecoderConfig input(kCodecVP8, VP8PROFILE_ANY, PIXEL_FORMAT_YV12,
+  VideoDecoderConfig input(kCodecVP8, VP8PROFILE_ANY, PIXEL_FORMAT_I420,
                            COLOR_SPACE_UNSPECIFIED, VIDEO_ROTATION_0,
                            kCodedSize, kVisibleRect, kNaturalSize,
                            EmptyExtraData(), Unencrypted());
@@ -52,7 +52,7 @@
 }
 
 TEST(VideoDecoderConfigStructTraitsTest, ConvertVideoDecoderConfig_Encrypted) {
-  VideoDecoderConfig input(kCodecVP8, VP8PROFILE_ANY, PIXEL_FORMAT_YV12,
+  VideoDecoderConfig input(kCodecVP8, VP8PROFILE_ANY, PIXEL_FORMAT_I420,
                            COLOR_SPACE_UNSPECIFIED, VIDEO_ROTATION_0,
                            kCodedSize, kVisibleRect, kNaturalSize,
                            EmptyExtraData(), AesCtrEncryptionScheme());
@@ -66,7 +66,7 @@
 
 TEST(VideoDecoderConfigStructTraitsTest,
      ConvertVideoDecoderConfig_ColorSpaceInfo) {
-  VideoDecoderConfig input(kCodecVP8, VP8PROFILE_ANY, PIXEL_FORMAT_YV12,
+  VideoDecoderConfig input(kCodecVP8, VP8PROFILE_ANY, PIXEL_FORMAT_I420,
                            COLOR_SPACE_UNSPECIFIED, VIDEO_ROTATION_0,
                            kCodedSize, kVisibleRect, kNaturalSize,
                            EmptyExtraData(), Unencrypted());
@@ -84,7 +84,7 @@
 
 TEST(VideoDecoderConfigStructTraitsTest,
      ConvertVideoDecoderConfig_HDRMetadata) {
-  VideoDecoderConfig input(kCodecVP8, VP8PROFILE_ANY, PIXEL_FORMAT_YV12,
+  VideoDecoderConfig input(kCodecVP8, VP8PROFILE_ANY, PIXEL_FORMAT_I420,
                            COLOR_SPACE_UNSPECIFIED, VIDEO_ROTATION_0,
                            kCodedSize, kVisibleRect, kNaturalSize,
                            EmptyExtraData(), Unencrypted());
@@ -126,7 +126,7 @@
 
   // Next try an non-empty invalid config. Natural size must not be zero.
   const gfx::Size kInvalidNaturalSize(0, 0);
-  input.Initialize(kCodecVP8, VP8PROFILE_ANY, PIXEL_FORMAT_YV12,
+  input.Initialize(kCodecVP8, VP8PROFILE_ANY, PIXEL_FORMAT_I420,
                    COLOR_SPACE_UNSPECIFIED, VIDEO_ROTATION_0, kCodedSize,
                    kVisibleRect, kInvalidNaturalSize, EmptyExtraData(),
                    Unencrypted());
diff --git a/media/renderers/paint_canvas_video_renderer_unittest.cc b/media/renderers/paint_canvas_video_renderer_unittest.cc
index 8fb54d1..fef7b362 100644
--- a/media/renderers/paint_canvas_video_renderer_unittest.cc
+++ b/media/renderers/paint_canvas_video_renderer_unittest.cc
@@ -128,7 +128,7 @@
       smaller_frame_(
           VideoFrame::CreateBlackFrame(gfx::Size(kWidth / 2, kHeight / 2))),
       cropped_frame_(
-          VideoFrame::CreateFrame(PIXEL_FORMAT_YV12,
+          VideoFrame::CreateFrame(PIXEL_FORMAT_I420,
                                   gfx::Size(16, 16),
                                   gfx::Rect(6, 6, 8, 6),
                                   gfx::Size(8, 6),
diff --git a/media/renderers/video_renderer_impl_unittest.cc b/media/renderers/video_renderer_impl_unittest.cc
index db092e8..57a70084 100644
--- a/media/renderers/video_renderer_impl_unittest.cc
+++ b/media/renderers/video_renderer_impl_unittest.cc
@@ -199,7 +199,7 @@
       if (base::StringToInt(token, &timestamp_in_ms)) {
         gfx::Size natural_size = TestVideoConfig::NormalCodedSize();
         scoped_refptr<VideoFrame> frame = VideoFrame::CreateFrame(
-            PIXEL_FORMAT_YV12, natural_size, gfx::Rect(natural_size),
+            PIXEL_FORMAT_I420, natural_size, gfx::Rect(natural_size),
             natural_size, base::TimeDelta::FromMilliseconds(timestamp_in_ms));
         QueueFrame(DecodeStatus::OK, frame);
         continue;
@@ -1344,19 +1344,19 @@
   gfx::Size larger_size(16, 16);
 
   QueueFrame(DecodeStatus::OK,
-             VideoFrame::CreateFrame(PIXEL_FORMAT_YV12, initial_size,
+             VideoFrame::CreateFrame(PIXEL_FORMAT_I420, initial_size,
                                      gfx::Rect(initial_size), initial_size,
                                      base::TimeDelta::FromMilliseconds(0)));
   QueueFrame(DecodeStatus::OK,
-             VideoFrame::CreateFrame(PIXEL_FORMAT_YV12, larger_size,
+             VideoFrame::CreateFrame(PIXEL_FORMAT_I420, larger_size,
                                      gfx::Rect(larger_size), larger_size,
                                      base::TimeDelta::FromMilliseconds(10)));
   QueueFrame(DecodeStatus::OK,
-             VideoFrame::CreateFrame(PIXEL_FORMAT_YV12, larger_size,
+             VideoFrame::CreateFrame(PIXEL_FORMAT_I420, larger_size,
                                      gfx::Rect(larger_size), larger_size,
                                      base::TimeDelta::FromMilliseconds(20)));
   QueueFrame(DecodeStatus::OK,
-             VideoFrame::CreateFrame(PIXEL_FORMAT_YV12, initial_size,
+             VideoFrame::CreateFrame(PIXEL_FORMAT_I420, initial_size,
                                      gfx::Rect(initial_size), initial_size,
                                      base::TimeDelta::FromMilliseconds(30)));
 
@@ -1406,7 +1406,7 @@
   Initialize();
 
   gfx::Size frame_size(8, 8);
-  VideoPixelFormat opaque_format = PIXEL_FORMAT_YV12;
+  VideoPixelFormat opaque_format = PIXEL_FORMAT_I420;
   VideoPixelFormat non_opaque_format = PIXEL_FORMAT_I420A;
 
   QueueFrame(DecodeStatus::OK,
diff --git a/media/test/pipeline_integration_test.cc b/media/test/pipeline_integration_test.cc
index 0637865..fa40ca0 100644
--- a/media/test/pipeline_integration_test.cc
+++ b/media/test/pipeline_integration_test.cc
@@ -2581,7 +2581,7 @@
   ASSERT_EQ(PIPELINE_OK, Start("bear-vp9-bt709.webm"));
   Play();
   ASSERT_TRUE(WaitUntilOnEnded());
-  EXPECT_VIDEO_FORMAT_EQ(last_video_frame_format_, PIXEL_FORMAT_YV12);
+  EXPECT_VIDEO_FORMAT_EQ(last_video_frame_format_, PIXEL_FORMAT_I420);
   EXPECT_COLOR_SPACE_EQ(last_video_frame_color_space_, COLOR_SPACE_HD_REC709);
 }
 
diff --git a/media/video/gpu_memory_buffer_video_frame_pool_unittest.cc b/media/video/gpu_memory_buffer_video_frame_pool_unittest.cc
index b8198bfa..a36f7580 100644
--- a/media/video/gpu_memory_buffer_video_frame_pool_unittest.cc
+++ b/media/video/gpu_memory_buffer_video_frame_pool_unittest.cc
@@ -106,7 +106,7 @@
 
     scoped_refptr<VideoFrame> video_frame =
         media::VideoFrame::WrapExternalYuvData(
-            media::PIXEL_FORMAT_YV12,  // format
+            media::PIXEL_FORMAT_I420,  // format
             size,                      // coded_size
             gfx::Rect(size),           // visible_rect
             size,                      // natural_size
diff --git a/net/disk_cache/simple/simple_backend_impl.cc b/net/disk_cache/simple/simple_backend_impl.cc
index 5d2ec0a..52f7600 100644
--- a/net/disk_cache/simple/simple_backend_impl.cc
+++ b/net/disk_cache/simple/simple_backend_impl.cc
@@ -20,8 +20,8 @@
 #include "base/location.h"
 #include "base/macros.h"
 #include "base/metrics/field_trial.h"
+#include "base/metrics/histogram_functions.h"
 #include "base/metrics/histogram_macros.h"
-#include "base/metrics/sparse_histogram.h"
 #include "base/single_thread_task_runner.h"
 #include "base/sys_info.h"
 #include "base/task_runner_util.h"
@@ -70,7 +70,7 @@
 
 bool g_fd_limit_histogram_has_been_populated = false;
 
-void MaybeHistogramFdLimit(net::CacheType cache_type) {
+void MaybeHistogramFdLimit() {
   if (g_fd_limit_histogram_has_been_populated)
     return;
 
@@ -96,14 +96,13 @@
   }
 #endif
 
-  SIMPLE_CACHE_UMA(ENUMERATION,
-                   "FileDescriptorLimitStatus", cache_type,
-                   fd_limit_status, FD_LIMIT_STATUS_MAX);
+  UMA_HISTOGRAM_ENUMERATION("SimpleCache.FileDescriptorLimitStatus",
+                            fd_limit_status, FD_LIMIT_STATUS_MAX);
   if (fd_limit_status == FD_LIMIT_STATUS_SUCCEEDED) {
-    SIMPLE_CACHE_UMA(SPARSE_SLOWLY,
-                     "FileDescriptorLimitSoft", cache_type, soft_fd_limit);
-    SIMPLE_CACHE_UMA(SPARSE_SLOWLY,
-                     "FileDescriptorLimitHard", cache_type, hard_fd_limit);
+    base::UmaHistogramSparse("SimpleCache.FileDescriptorLimitSoft",
+                             soft_fd_limit);
+    base::UmaHistogramSparse("SimpleCache.FileDescriptorLimitHard",
+                             hard_fd_limit);
   }
 
   g_fd_limit_histogram_has_been_populated = true;
@@ -246,7 +245,7 @@
   // backends, as default (if first call).
   if (orig_max_size_ < 0)
     orig_max_size_ = 0;
-  MaybeHistogramFdLimit(cache_type_);
+  MaybeHistogramFdLimit();
 }
 
 SimpleBackendImpl::~SimpleBackendImpl() {
diff --git a/net/disk_cache/simple/simple_histogram_macros.h b/net/disk_cache/simple/simple_histogram_macros.h
index edccfc0..fa302c3 100644
--- a/net/disk_cache/simple/simple_histogram_macros.h
+++ b/net/disk_cache/simple/simple_histogram_macros.h
@@ -6,7 +6,6 @@
 #define NET_DISK_CACHE_SIMPLE_SIMPLE_HISTOGRAM_MACROS_H_
 
 #include "base/metrics/histogram_macros.h"
-#include "base/metrics/sparse_histogram.h"
 #include "net/base/cache_type.h"
 
 // This file contains macros used to report histograms. The main issue is that
diff --git a/net/dns/dns_config_service_posix.cc b/net/dns/dns_config_service_posix.cc
index 60d6abe..c0c7725 100644
--- a/net/dns/dns_config_service_posix.cc
+++ b/net/dns/dns_config_service_posix.cc
@@ -11,7 +11,6 @@
 #include "base/files/file.h"
 #include "base/files/file_path.h"
 #include "base/files/file_path_watcher.h"
-#include "base/files/file_util.h"
 #include "base/lazy_instance.h"
 #include "base/location.h"
 #include "base/macros.h"
@@ -20,10 +19,6 @@
 #include "base/threading/scoped_blocking_call.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "base/time/time.h"
-#include "base/trace_event/memory_allocator_dump.h"
-#include "base/trace_event/memory_dump_manager.h"
-#include "base/trace_event/memory_dump_provider.h"
-#include "base/trace_event/process_memory_dump.h"
 #include "base/trace_event/trace_event.h"
 #include "build/build_config.h"
 #include "net/base/ip_address.h"
@@ -359,38 +354,15 @@
 };
 
 // A SerialWorker that reads the HOSTS file and runs Callback.
-class DnsConfigServicePosix::HostsReader
-    : public SerialWorker,
-      public base::trace_event::MemoryDumpProvider {
+class DnsConfigServicePosix::HostsReader : public SerialWorker {
  public:
   explicit HostsReader(DnsConfigServicePosix* service)
       : service_(service),
         file_path_hosts_(service->file_path_hosts_),
-        success_(false),
-        hosts_size_(0) {
-    base::trace_event::MemoryDumpManager::GetInstance()->RegisterDumpProvider(
-        this, "DnsConfigServicePosix::HostsReader",
-        base::ThreadTaskRunnerHandle::Get());
-  }
-
-  bool OnMemoryDump(const base::trace_event::MemoryDumpArgs& args,
-                    base::trace_event::ProcessMemoryDump* pmd) override {
-    base::trace_event::MemoryAllocatorDump* dump =
-        pmd->CreateAllocatorDump("net/dns_config_service_posix_hosts_reader");
-    dump->AddScalar("hosts_entry_count",
-                    base::trace_event::MemoryAllocatorDump::kUnitsObjects,
-                    hosts_.size());
-    dump->AddScalar("hosts_file_size",
-                    base::trace_event::MemoryAllocatorDump::kUnitsBytes,
-                    hosts_size_);
-    return true;
-  }
+        success_(false) {}
 
  private:
-  ~HostsReader() override {
-    base::trace_event::MemoryDumpManager::GetInstance()->UnregisterDumpProvider(
-        this);
-  }
+  ~HostsReader() override {}
 
   void DoWork() override {
     TRACE_HEAP_PROFILER_API_SCOPED_TASK_EXECUTION scoped_heap_context(
@@ -398,7 +370,7 @@
     base::TimeTicks start_time = base::TimeTicks::Now();
     base::ScopedBlockingCall scoped_blocking_call(
         base::BlockingType::MAY_BLOCK);
-    success_ = ParseHostsFile(file_path_hosts_, &hosts_, &hosts_size_);
+    success_ = ParseHostsFile(file_path_hosts_, &hosts_);
     UMA_HISTOGRAM_BOOLEAN("AsyncDNS.HostParseResult", success_);
     UMA_HISTOGRAM_TIMES("AsyncDNS.HostsParseDuration",
                         base::TimeTicks::Now() - start_time);
@@ -423,7 +395,6 @@
   // Written in DoWork, read in OnWorkFinished, no locking necessary.
   DnsHosts hosts_;
   bool success_;
-  int64_t hosts_size_;
 
   DISALLOW_COPY_AND_ASSIGN(HostsReader);
 };
diff --git a/net/dns/dns_config_service_win.cc b/net/dns/dns_config_service_win.cc
index 2152cb7d..e6c99443 100644
--- a/net/dns/dns_config_service_win.cc
+++ b/net/dns/dns_config_service_win.cc
@@ -698,8 +698,7 @@
     base::ScopedBlockingCall scoped_blocking_call(
         base::BlockingType::MAY_BLOCK);
     HostsParseWinResult result = HOSTS_PARSE_WIN_UNREADABLE_HOSTS_FILE;
-    int64_t file_size;
-    if (ParseHostsFile(path_, &hosts_, &file_size))
+    if (ParseHostsFile(path_, &hosts_))
       result = AddLocalhostEntries(&hosts_);
     success_ = (result == HOSTS_PARSE_WIN_OK);
     UMA_HISTOGRAM_ENUMERATION("AsyncDNS.HostsParseWin",
diff --git a/net/dns/dns_hosts.cc b/net/dns/dns_hosts.cc
index b9f1a27..8de7607c 100644
--- a/net/dns/dns_hosts.cc
+++ b/net/dns/dns_hosts.cc
@@ -188,9 +188,7 @@
   ParseHostsWithCommaMode(contents, dns_hosts, comma_mode);
 }
 
-bool ParseHostsFile(const base::FilePath& path,
-                    DnsHosts* dns_hosts,
-                    int64_t* file_size) {
+bool ParseHostsFile(const base::FilePath& path, DnsHosts* dns_hosts) {
   dns_hosts->clear();
   // Missing file indicates empty HOSTS.
   if (!base::PathExists(path))
@@ -213,7 +211,6 @@
     return false;
 
   ParseHosts(contents, dns_hosts);
-  *file_size = size;
   return true;
 }
 
diff --git a/net/dns/dns_hosts.h b/net/dns/dns_hosts.h
index 79f7b63e..423258b 100644
--- a/net/dns/dns_hosts.h
+++ b/net/dns/dns_hosts.h
@@ -68,8 +68,9 @@
 
 // As above but reads the file pointed to by |path|.
 bool NET_EXPORT_PRIVATE ParseHostsFile(const base::FilePath& path,
-                                       DnsHosts* dns_hosts,
-                                       int64_t* file_size);
+                                       DnsHosts* dns_hosts);
+
+
 
 }  // namespace net
 
diff --git a/net/http/http_network_transaction_unittest.cc b/net/http/http_network_transaction_unittest.cc
index 615019cc..c05e021 100644
--- a/net/http/http_network_transaction_unittest.cc
+++ b/net/http/http_network_transaction_unittest.cc
@@ -13411,7 +13411,6 @@
   };
 
   MockRead data_reads1[] = {
-    MockRead(SYNCHRONOUS, ERR_TEST_PEER_CLOSE_AFTER_NEXT_MOCK_READ),
     MockRead("HTTP/1.1 200 Connection Established\r\n\r\n"),
     MockRead(ASYNC, 0, 0),  // EOF
   };
diff --git a/net/network_error_logging/network_error_logging_service.cc b/net/network_error_logging/network_error_logging_service.cc
index 726f49f..e9d6f7b 100644
--- a/net/network_error_logging/network_error_logging_service.cc
+++ b/net/network_error_logging/network_error_logging_service.cc
@@ -197,6 +197,28 @@
                                   CreateReportBody(type_string, details));
 }
 
+void NetworkErrorLoggingService::RemoveBrowsingData(
+    const base::RepeatingCallback<bool(const GURL&)>& origin_filter) {
+  if (origin_filter.is_null()) {
+    wildcard_policies_.clear();
+    policies_.clear();
+    return;
+  }
+
+  std::vector<url::Origin> origins_to_remove;
+
+  for (auto it = policies_.begin(); it != policies_.end(); ++it) {
+    if (origin_filter.Run(it->first.GetURL()))
+      origins_to_remove.push_back(it->first);
+  }
+
+  for (auto it = origins_to_remove.begin(); it != origins_to_remove.end();
+       ++it) {
+    MaybeRemoveWildcardPolicy(*it, &policies_[*it]);
+    policies_.erase(*it);
+  }
+}
+
 void NetworkErrorLoggingService::SetTickClockForTesting(
     base::TickClock* tick_clock) {
   DCHECK(tick_clock);
diff --git a/net/network_error_logging/network_error_logging_service.h b/net/network_error_logging/network_error_logging_service.h
index 53a577f..5cefaddd8 100644
--- a/net/network_error_logging/network_error_logging_service.h
+++ b/net/network_error_logging/network_error_logging_service.h
@@ -67,6 +67,9 @@
 
   void OnNetworkError(const ErrorDetails& details) override;
 
+  void RemoveBrowsingData(
+      const base::RepeatingCallback<bool(const GURL&)>& origin_filter) override;
+
   void SetTickClockForTesting(base::TickClock* tick_clock);
 
  private:
diff --git a/net/network_error_logging/network_error_logging_service_unittest.cc b/net/network_error_logging/network_error_logging_service_unittest.cc
index 7e18097..e04a2f2 100644
--- a/net/network_error_logging/network_error_logging_service_unittest.cc
+++ b/net/network_error_logging/network_error_logging_service_unittest.cc
@@ -137,11 +137,14 @@
   const GURL kUrl_ = GURL("https://example.com/path");
   const GURL kUrlDifferentPort_ = GURL("https://example.com:4433/path");
   const GURL kUrlSubdomain_ = GURL("https://subdomain.example.com/path");
+  const GURL kUrlDifferentHost_ = GURL("https://example2.com/path");
 
   const url::Origin kOrigin_ = url::Origin::Create(kUrl_);
   const url::Origin kOriginDifferentPort_ =
       url::Origin::Create(kUrlDifferentPort_);
   const url::Origin kOriginSubdomain_ = url::Origin::Create(kUrlSubdomain_);
+  const url::Origin kOriginDifferentHost_ =
+      url::Origin::Create(kUrlDifferentHost_);
 
   const std::string kHeader_ = "{\"report-to\":\"group\",\"max-age\":86400}";
   const std::string kHeaderIncludeSubdomains_ =
@@ -286,5 +289,34 @@
   EXPECT_TRUE(reports().empty());
 }
 
+TEST_F(NetworkErrorLoggingServiceTest, RemoveAllBrowsingData) {
+  service()->OnHeader(kOrigin_, kHeader_);
+
+  service()->RemoveBrowsingData(base::RepeatingCallback<bool(const GURL&)>());
+
+  service()->OnNetworkError(MakeErrorDetails(kUrl_, ERR_CONNECTION_REFUSED));
+
+  EXPECT_TRUE(reports().empty());
+}
+
+TEST_F(NetworkErrorLoggingServiceTest, RemoveSomeBrowsingData) {
+  service()->OnHeader(kOrigin_, kHeader_);
+  service()->OnHeader(kOriginDifferentHost_, kHeader_);
+
+  service()->RemoveBrowsingData(
+      base::BindRepeating([](const GURL& origin) -> bool {
+        return origin.host() == "example.com";
+      }));
+
+  service()->OnNetworkError(MakeErrorDetails(kUrl_, ERR_CONNECTION_REFUSED));
+
+  EXPECT_TRUE(reports().empty());
+
+  service()->OnNetworkError(
+      MakeErrorDetails(kUrlDifferentHost_, ERR_CONNECTION_REFUSED));
+
+  EXPECT_EQ(1u, reports().size());
+}
+
 }  // namespace
 }  // namespace net
diff --git a/net/nqe/network_quality_estimator_test_util.cc b/net/nqe/network_quality_estimator_test_util.cc
index 68ce8c06..a5f76649 100644
--- a/net/nqe/network_quality_estimator_test_util.cc
+++ b/net/nqe/network_quality_estimator_test_util.cc
@@ -66,11 +66,11 @@
           std::move(external_estimate_provider),
           std::make_unique<NetworkQualityEstimatorParams>(variation_params),
           net_log->bound().net_log()),
+      net_log_(std::move(net_log)),
       current_network_type_(NetworkChangeNotifier::CONNECTION_UNKNOWN),
       accuracy_recording_intervals_set_(false),
       embedded_test_server_(base::FilePath(kTestFilePath)),
-      suppress_notifications_for_testing_(suppress_notifications_for_testing),
-      net_log_(std::move(net_log)) {
+      suppress_notifications_for_testing_(suppress_notifications_for_testing) {
   SetUseLocalHostRequestsForTesting(allow_local_host_requests_for_tests);
   SetUseSmallResponsesForTesting(allow_smaller_responses_for_tests);
 
@@ -89,11 +89,11 @@
     : NetworkQualityEstimator(std::unique_ptr<ExternalEstimateProvider>(),
                               std::move(params),
                               net_log->bound().net_log()),
+      net_log_(std::move(net_log)),
       current_network_type_(NetworkChangeNotifier::CONNECTION_UNKNOWN),
       accuracy_recording_intervals_set_(false),
       embedded_test_server_(base::FilePath(kTestFilePath)),
-      suppress_notifications_for_testing_(false),
-      net_log_(std::move(net_log)) {
+      suppress_notifications_for_testing_(false) {
   // Set up the embedded test server.
   EXPECT_TRUE(embedded_test_server_.Start());
 }
diff --git a/net/nqe/network_quality_estimator_test_util.h b/net/nqe/network_quality_estimator_test_util.h
index 07dd7ea0..e6cba70 100644
--- a/net/nqe/network_quality_estimator_test_util.h
+++ b/net/nqe/network_quality_estimator_test_util.h
@@ -250,6 +250,9 @@
   // id (instead of invoking platform APIs).
   nqe::internal::NetworkID GetCurrentNetworkID() const override;
 
+  // Net log provided to network quality estimator.
+  std::unique_ptr<net::BoundTestNetLog> net_log_;
+
   // If set, GetEffectiveConnectionType() and GetRecentEffectiveConnectionType()
   // would return the set values, respectively.
   base::Optional<EffectiveConnectionType> effective_connection_type_;
@@ -294,9 +297,6 @@
 
   base::Optional<size_t> transport_rtt_observation_count_last_ect_computation_;
 
-  // Net log provided to network quality estimator.
-  std::unique_ptr<net::BoundTestNetLog> net_log_;
-
   DISALLOW_COPY_AND_ASSIGN(TestNetworkQualityEstimator);
 };
 
diff --git a/net/socket/socket_test_util.cc b/net/socket/socket_test_util.cc
index 363efd7..4504b2e 100644
--- a/net/socket/socket_test_util.cc
+++ b/net/socket/socket_test_util.cc
@@ -1214,18 +1214,14 @@
 }
 
 int MockSSLClientSocket::Connect(const CompletionCallback& callback) {
-  int rv = transport_->socket()->Connect(
-      base::Bind(&ConnectCallback, base::Unretained(this), callback));
-  if (rv == OK) {
-    if (data_->connect.result == OK)
-      connected_ = true;
-    if (data_->connect.mode == ASYNC) {
-      RunCallbackAsync(callback, data_->connect.result);
-      return ERR_IO_PENDING;
-    }
-    return data_->connect.result;
+  DCHECK(transport_->socket()->IsConnected());
+  if (data_->connect.result == OK)
+    connected_ = true;
+  if (data_->connect.mode == ASYNC) {
+    RunCallbackAsync(callback, data_->connect.result);
+    return ERR_IO_PENDING;
   }
-  return rv;
+  return data_->connect.result;
 }
 
 void MockSSLClientSocket::Disconnect() {
diff --git a/net/spdy/chromium/http2_push_promise_index.cc b/net/spdy/chromium/http2_push_promise_index.cc
index 467207f8..5864823 100644
--- a/net/spdy/chromium/http2_push_promise_index.cc
+++ b/net/spdy/chromium/http2_push_promise_index.cc
@@ -94,16 +94,12 @@
   *session = nullptr;
   *stream_id = kNoPushedStreamFound;
 
-  // Do not allow cross-origin push for non-cryptographic schemes.
-  if (!url.SchemeIsCryptographic())
-    return;
-
   // Find the first entry for |url|, if such exists.
   auto it = unclaimed_pushed_streams_.lower_bound(
       UnclaimedPushedStream{url, nullptr, kNoPushedStreamFound});
 
   while (it != unclaimed_pushed_streams_.end() && it->url == url) {
-    if (it->delegate->ValidatePushedStream(key)) {
+    if (it->delegate->ValidatePushedStream(url, key)) {
       *session = it->delegate->GetWeakPtrToSession();
       *stream_id = it->stream_id;
       it->delegate->OnPushedStreamClaimed(it->url, it->stream_id);
diff --git a/net/spdy/chromium/http2_push_promise_index.h b/net/spdy/chromium/http2_push_promise_index.h
index fe70c189..09114764 100644
--- a/net/spdy/chromium/http2_push_promise_index.h
+++ b/net/spdy/chromium/http2_push_promise_index.h
@@ -33,8 +33,7 @@
 // Each SpdySessionPool owns one instance of this class.
 // SpdySession uses this class to register, unregister and query pushed streams.
 // HttpStreamFactoryImpl::Job uses this class to find a SpdySession with a
-// pushed stream matching the request, if such exists, which is only allowed for
-// requests with a cryptographic scheme.
+// pushed stream matching the request, if such exists.
 class NET_EXPORT Http2PushPromiseIndex {
  public:
   // Interface for validating pushed streams, signaling when a pushed stream is
@@ -44,8 +43,10 @@
     Delegate() {}
     virtual ~Delegate() {}
 
-    // Return true if the pushed stream can be used for a request with |key|.
-    virtual bool ValidatePushedStream(const SpdySessionKey& key) const = 0;
+    // Return true if a pushed stream with |url| can be used for a request with
+    // |key|.
+    virtual bool ValidatePushedStream(const GURL& url,
+                                      const SpdySessionKey& key) const = 0;
 
     // Called when a pushed stream is claimed.  Guaranateed to be called
     // synchronously after ValidatePushedStream() is called and returns true.
diff --git a/net/spdy/chromium/http2_push_promise_index_test.cc b/net/spdy/chromium/http2_push_promise_index_test.cc
index 21e8d6b9..1314313d 100644
--- a/net/spdy/chromium/http2_push_promise_index_test.cc
+++ b/net/spdy/chromium/http2_push_promise_index_test.cc
@@ -31,7 +31,8 @@
   TestDelegate(const SpdySessionKey& key) : key_(key) {}
   ~TestDelegate() override {}
 
-  bool ValidatePushedStream(const SpdySessionKey& key) const override {
+  bool ValidatePushedStream(const GURL& url,
+                            const SpdySessionKey& key) const override {
     return key == key_;
   }
 
@@ -50,7 +51,8 @@
   MockDelegate() = default;
   ~MockDelegate() override {}
 
-  MOCK_CONST_METHOD1(ValidatePushedStream, bool(const SpdySessionKey& key));
+  MOCK_CONST_METHOD2(ValidatePushedStream,
+                     bool(const GURL& url, const SpdySessionKey& key));
   MOCK_METHOD2(OnPushedStreamClaimed,
                void(const GURL& url, SpdyStreamId stream_id));
 
@@ -379,7 +381,8 @@
 // the appropriate arguments.
 TEST_F(Http2PushPromiseIndexTest, MatchCallsOnPushedStreamClaimed) {
   MockDelegate delegate;
-  EXPECT_CALL(delegate, ValidatePushedStream(key1_)).WillOnce(Return(true));
+  EXPECT_CALL(delegate, ValidatePushedStream(url1_, key1_))
+      .WillOnce(Return(true));
   EXPECT_CALL(delegate, OnPushedStreamClaimed(url1_, 2)).Times(1);
 
   EXPECT_TRUE(index_.RegisterUnclaimedPushedStream(url1_, 2, &delegate));
@@ -398,7 +401,8 @@
 // called.
 TEST_F(Http2PushPromiseIndexTest, MismatchDoesNotCallOnPushedStreamClaimed) {
   MockDelegate delegate;
-  EXPECT_CALL(delegate, ValidatePushedStream(key1_)).WillOnce(Return(false));
+  EXPECT_CALL(delegate, ValidatePushedStream(url1_, key1_))
+      .WillOnce(Return(false));
   EXPECT_CALL(delegate, OnPushedStreamClaimed(_, _)).Times(0);
 
   EXPECT_TRUE(index_.RegisterUnclaimedPushedStream(url1_, 2, &delegate));
diff --git a/net/spdy/chromium/spdy_session.cc b/net/spdy/chromium/spdy_session.cc
index fae4c5b9..1ca4fe2 100644
--- a/net/spdy/chromium/spdy_session.cc
+++ b/net/spdy/chromium/spdy_session.cc
@@ -57,6 +57,7 @@
 #include "net/ssl/channel_id_service.h"
 #include "net/ssl/ssl_cipher_suite_names.h"
 #include "net/ssl/ssl_connection_status_flags.h"
+#include "url/url_constants.h"
 
 namespace net {
 
@@ -1366,10 +1367,12 @@
   return false;
 }
 
-bool SpdySession::ValidatePushedStream(const SpdySessionKey& key) const {
+bool SpdySession::ValidatePushedStream(const GURL& url,
+                                       const SpdySessionKey& key) const {
   return key.proxy_server() == spdy_session_key_.proxy_server() &&
          key.privacy_mode() == spdy_session_key_.privacy_mode() &&
-         VerifyDomainAuthentication(key.host_port_pair().host());
+         (!url.SchemeIsCryptographic() ||
+          VerifyDomainAuthentication(key.host_port_pair().host()));
 }
 
 void SpdySession::OnPushedStreamClaimed(const GURL& url,
@@ -1607,6 +1610,12 @@
   }
 
   DCHECK(gurl.is_valid());
+  if (!gurl.SchemeIs(url::kHttpScheme) && !gurl.SchemeIs(url::kHttpsScheme)) {
+    EnqueueResetStreamFrame(stream_id, request_priority,
+                            ERROR_CODE_REFUSED_STREAM,
+                            "Only http and https resources can be pushed.");
+    return;
+  }
 
   // Cross-origin push validation.
   GURL associated_url(associated_it->second->GetUrlFromHeaders());
@@ -1614,15 +1623,15 @@
     if (proxy_delegate_ &&
         proxy_delegate_->IsTrustedSpdyProxy(
             ProxyServer(ProxyServer::SCHEME_HTTPS, host_port_pair()))) {
-      // Disallow pushing of HTTPS content by trusted proxy.
-      if (gurl.SchemeIs("https")) {
+      if (!gurl.SchemeIs(url::kHttpScheme)) {
         EnqueueResetStreamFrame(
             stream_id, request_priority, ERROR_CODE_REFUSED_STREAM,
-            "Cross origin HTTPS content from trusted proxy.");
+            "Only http scheme allowed for cross origin push by trusted proxy.");
         return;
       }
     } else {
-      if (!gurl.SchemeIs("https") || !associated_url.SchemeIs("https")) {
+      if (!gurl.SchemeIs(url::kHttpsScheme) ||
+          !associated_url.SchemeIs(url::kHttpsScheme)) {
         EnqueueResetStreamFrame(
             stream_id, request_priority, ERROR_CODE_REFUSED_STREAM,
             "Both pushed URL and associated URL must have https scheme.");
@@ -2944,7 +2953,7 @@
     if (origin.empty())
       return;
     const GURL gurl(origin);
-    if (!gurl.SchemeIs("https"))
+    if (!gurl.SchemeIs(url::kHttpsScheme))
       return;
     SSLInfo ssl_info;
     if (!GetSSLInfo(&ssl_info))
@@ -2961,7 +2970,7 @@
     if (it == active_streams_.end())
       return;
     const GURL& gurl(it->second->url());
-    if (!gurl.SchemeIs("https"))
+    if (!gurl.SchemeIs(url::kHttpsScheme))
       return;
     scheme_host_port = url::SchemeHostPort(gurl);
   }
diff --git a/net/spdy/chromium/spdy_session.h b/net/spdy/chromium/spdy_session.h
index 17cf4e0d..3c67133 100644
--- a/net/spdy/chromium/spdy_session.h
+++ b/net/spdy/chromium/spdy_session.h
@@ -487,7 +487,8 @@
   bool CloseOneIdleConnection() override;
 
   // Http2PushPromiseIndex::Delegate implementation:
-  bool ValidatePushedStream(const SpdySessionKey& key) const override;
+  bool ValidatePushedStream(const GURL& url,
+                            const SpdySessionKey& key) const override;
   void OnPushedStreamClaimed(const GURL& url, SpdyStreamId stream_id) override;
   base::WeakPtr<SpdySession> GetWeakPtrToSession() override;
 
diff --git a/net/url_request/network_error_logging_delegate.h b/net/url_request/network_error_logging_delegate.h
index d61ec42..26330d86 100644
--- a/net/url_request/network_error_logging_delegate.h
+++ b/net/url_request/network_error_logging_delegate.h
@@ -67,6 +67,11 @@
   //
   // |details| is the details of the network error.
   virtual void OnNetworkError(const ErrorDetails& details) = 0;
+
+  // Removes all stored data associated with any origins matching
+  // |origin_filter| (or all origins if null).
+  virtual void RemoveBrowsingData(
+      const base::RepeatingCallback<bool(const GURL&)>& origin_filter) = 0;
 };
 
 }  // namespace net
diff --git a/net/url_request/url_request_unittest.cc b/net/url_request/url_request_unittest.cc
index 5c00230..01afe00 100644
--- a/net/url_request/url_request_unittest.cc
+++ b/net/url_request/url_request_unittest.cc
@@ -7193,6 +7193,11 @@
     errors_.push_back(details);
   }
 
+  void RemoveBrowsingData(const base::RepeatingCallback<bool(const GURL&)>&
+                              origin_filter) override {
+    NOTREACHED();
+  }
+
  private:
   std::vector<Header> headers_;
   std::vector<ErrorDetails> errors_;
diff --git a/services/identity/public/cpp/identity_manager.cc b/services/identity/public/cpp/identity_manager.cc
index b756418..2f4891f 100644
--- a/services/identity/public/cpp/identity_manager.cc
+++ b/services/identity/public/cpp/identity_manager.cc
@@ -40,6 +40,18 @@
       std::move(callback));
 }
 
+void IdentityManager::RemoveAccessTokenFromCache(
+    const AccountInfo& account_info,
+    const OAuth2TokenService::ScopeSet& scopes,
+    const std::string& access_token) {
+  // Call PO2TS asynchronously to mimic the eventual interaction with the
+  // Identity Service.
+  base::SequencedTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE, base::BindOnce(&OAuth2TokenService::InvalidateAccessToken,
+                                base::Unretained(token_service_),
+                                account_info.account_id, scopes, access_token));
+}
+
 void IdentityManager::AddObserver(Observer* observer) {
   observer_list_.AddObserver(observer);
 }
diff --git a/services/identity/public/cpp/identity_manager.h b/services/identity/public/cpp/identity_manager.h
index 429623b..888418a 100644
--- a/services/identity/public/cpp/identity_manager.h
+++ b/services/identity/public/cpp/identity_manager.h
@@ -52,6 +52,14 @@
       const OAuth2TokenService::ScopeSet& scopes,
       PrimaryAccountAccessTokenFetcher::TokenCallback callback);
 
+  // If an entry exists in the Identity Service's cache corresponding to the
+  // given information, removes that entry; in this case, the next access token
+  // request for |account_id| and |scopes| will fetch a new token from the
+  // network. Otherwise, is a no-op.
+  void RemoveAccessTokenFromCache(const AccountInfo& account_info,
+                                  const OAuth2TokenService::ScopeSet& scopes,
+                                  const std::string& access_token);
+
   // Methods to register or remove observers.
   void AddObserver(Observer* observer);
   void RemoveObserver(Observer* observer);
diff --git a/services/identity/public/cpp/identity_manager_unittest.cc b/services/identity/public/cpp/identity_manager_unittest.cc
index a6f47a03..e57fc12 100644
--- a/services/identity/public/cpp/identity_manager_unittest.cc
+++ b/services/identity/public/cpp/identity_manager_unittest.cc
@@ -26,6 +26,41 @@
 const char kTestGaiaId[] = "dummyId";
 const char kTestEmail[] = "me@dummy.com";
 
+// Subclass of FakeProfileOAuth2TokenService with bespoke behavior.
+class CustomFakeProfileOAuth2TokenService
+    : public FakeProfileOAuth2TokenService {
+ public:
+  void set_on_access_token_invalidated_info(
+      std::string expected_account_id_to_invalidate,
+      std::set<std::string> expected_scopes_to_invalidate,
+      std::string expected_access_token_to_invalidate,
+      base::OnceClosure callback) {
+    expected_account_id_to_invalidate_ = expected_account_id_to_invalidate;
+    expected_scopes_to_invalidate_ = expected_scopes_to_invalidate;
+    expected_access_token_to_invalidate_ = expected_access_token_to_invalidate;
+    on_access_token_invalidated_callback_ = std::move(callback);
+  }
+
+ private:
+  // OAuth2TokenService:
+  void InvalidateAccessTokenImpl(const std::string& account_id,
+                                 const std::string& client_id,
+                                 const ScopeSet& scopes,
+                                 const std::string& access_token) override {
+    if (on_access_token_invalidated_callback_) {
+      EXPECT_EQ(expected_account_id_to_invalidate_, account_id);
+      EXPECT_EQ(expected_scopes_to_invalidate_, scopes);
+      EXPECT_EQ(expected_access_token_to_invalidate_, access_token);
+      std::move(on_access_token_invalidated_callback_).Run();
+    }
+  }
+
+  std::string expected_account_id_to_invalidate_;
+  std::set<std::string> expected_scopes_to_invalidate_;
+  std::string expected_access_token_to_invalidate_;
+  base::OnceClosure on_access_token_invalidated_callback_;
+};
+
 class TestIdentityManagerObserver : IdentityManager::Observer {
  public:
   explicit TestIdentityManagerObserver(IdentityManager* identity_manager)
@@ -109,7 +144,9 @@
   }
   AccountTrackerService* account_tracker() { return &account_tracker_; }
   SigninManagerForTest* signin_manager() { return &signin_manager_; }
-  FakeProfileOAuth2TokenService* token_service() { return &token_service_; }
+  CustomFakeProfileOAuth2TokenService* token_service() {
+    return &token_service_;
+  }
 
  private:
   base::MessageLoop message_loop_;
@@ -117,7 +154,7 @@
   AccountTrackerService account_tracker_;
   TestSigninClient signin_client_;
   SigninManagerForTest signin_manager_;
-  FakeProfileOAuth2TokenService token_service_;
+  CustomFakeProfileOAuth2TokenService token_service_;
   std::unique_ptr<IdentityManager> identity_manager_;
   std::unique_ptr<TestIdentityManagerObserver> identity_manager_observer_;
 
@@ -188,6 +225,28 @@
 }
 #endif  // !defined(OS_CHROMEOS)
 
+TEST_F(IdentityManagerTest, RemoveAccessTokenFromCache) {
+  std::set<std::string> scopes{"scope"};
+  std::string access_token = "access_token";
+
+  signin_manager()->SetAuthenticatedAccountInfo(kTestGaiaId, kTestEmail);
+  std::string account_id = signin_manager()->GetAuthenticatedAccountId();
+  token_service()->UpdateCredentials(account_id, "refresh_token");
+
+  base::RunLoop run_loop;
+  token_service()->set_on_access_token_invalidated_info(
+      account_id, scopes, access_token, run_loop.QuitClosure());
+
+  AccountInfo account_info;
+  account_info.account_id = account_id;
+  account_info.gaia = kTestGaiaId;
+  account_info.email = kTestEmail;
+  identity_manager()->RemoveAccessTokenFromCache(account_info, scopes,
+                                                 access_token);
+
+  run_loop.Run();
+}
+
 TEST_F(IdentityManagerTest, CreateAccessTokenFetcherForPrimaryAccount) {
   std::set<std::string> scopes{"scope"};
   PrimaryAccountAccessTokenFetcher::TokenCallback callback =
diff --git a/services/identity/public/cpp/primary_account_access_token_fetcher.cc b/services/identity/public/cpp/primary_account_access_token_fetcher.cc
index 27676f9..c017bff9 100644
--- a/services/identity/public/cpp/primary_account_access_token_fetcher.cc
+++ b/services/identity/public/cpp/primary_account_access_token_fetcher.cc
@@ -7,6 +7,7 @@
 #include <utility>
 
 #include "base/logging.h"
+#include "base/threading/sequenced_task_runner_handle.h"
 
 namespace identity {
 
@@ -58,7 +59,7 @@
   if (token_service_->RefreshTokenIsAvailable(
           signin_manager_->GetAuthenticatedAccountId())) {
     // Already have refresh token: Get the access token directly.
-    StartAccessTokenRequest();
+    ScheduleStartAccessTokenRequest();
     return;
   }
 
@@ -68,6 +69,15 @@
   token_service_->AddObserver(this);
 }
 
+void PrimaryAccountAccessTokenFetcher::ScheduleStartAccessTokenRequest() {
+  // Fire off the request asynchronously to mimic the asynchronous flow that
+  // will occur when this request is going through the Identity Service.
+  base::SequencedTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE,
+      base::BindOnce(&PrimaryAccountAccessTokenFetcher::StartAccessTokenRequest,
+                     base::Unretained(this)));
+}
+
 void PrimaryAccountAccessTokenFetcher::StartAccessTokenRequest() {
   // Note: We might get here even in cases where we know that there's no refresh
   // token. We're requesting an access token anyway, so that the token service
@@ -111,7 +121,7 @@
 
   waiting_for_refresh_token_ = false;
   token_service_->RemoveObserver(this);
-  StartAccessTokenRequest();
+  ScheduleStartAccessTokenRequest();
 }
 
 void PrimaryAccountAccessTokenFetcher::OnRefreshTokensLoaded() {
@@ -125,7 +135,7 @@
   // provide us with an appropriate error code.
   waiting_for_refresh_token_ = false;
   token_service_->RemoveObserver(this);
-  StartAccessTokenRequest();
+  ScheduleStartAccessTokenRequest();
 }
 
 void PrimaryAccountAccessTokenFetcher::OnGetTokenSuccess(
@@ -163,7 +173,7 @@
       token_service_->RefreshTokenIsAvailable(
           signin_manager_->GetAuthenticatedAccountId())) {
     access_token_retried_ = true;
-    StartAccessTokenRequest();
+    ScheduleStartAccessTokenRequest();
     return;
   }
 
diff --git a/services/identity/public/cpp/primary_account_access_token_fetcher.h b/services/identity/public/cpp/primary_account_access_token_fetcher.h
index 88a95f20..c841bd6 100644
--- a/services/identity/public/cpp/primary_account_access_token_fetcher.h
+++ b/services/identity/public/cpp/primary_account_access_token_fetcher.h
@@ -50,6 +50,7 @@
   void Start();
 
   void WaitForRefreshToken();
+  void ScheduleStartAccessTokenRequest();
   void StartAccessTokenRequest();
 
   // SigninManagerBase::Observer implementation.
diff --git a/services/preferences/BUILD.gn b/services/preferences/BUILD.gn
index 3e7a94d..7b1279f 100644
--- a/services/preferences/BUILD.gn
+++ b/services/preferences/BUILD.gn
@@ -64,6 +64,7 @@
     "persistent_pref_store_impl_unittest.cc",
     "pref_store_consistency_unittest.cc",
     "pref_store_impl_unittest.cc",
+    "unittest_common.cc",
   ]
   if (!is_ios) {
     sources += [ "pref_service_factory_unittest.cc" ]
diff --git a/services/preferences/persistent_pref_store_impl_unittest.cc b/services/preferences/persistent_pref_store_impl_unittest.cc
index b7ca160..549df9d7 100644
--- a/services/preferences/persistent_pref_store_impl_unittest.cc
+++ b/services/preferences/persistent_pref_store_impl_unittest.cc
@@ -15,21 +15,13 @@
 #include "mojo/public/cpp/bindings/binding_set.h"
 #include "services/preferences/public/cpp/persistent_pref_store_client.h"
 #include "services/preferences/public/interfaces/preferences.mojom.h"
+#include "services/preferences/unittest_common.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
-using testing::Invoke;
-using testing::WithoutArgs;
-
 namespace prefs {
 namespace {
 
-class PrefStoreObserverMock : public PrefStore::Observer {
- public:
-  MOCK_METHOD1(OnPrefValueChanged, void(const std::string&));
-  MOCK_METHOD1(OnInitializationCompleted, void(bool));
-};
-
 class PersistentPrefStoreMock : public InMemoryPrefStore {
  public:
   void CommitPendingWrite(base::OnceClosure callback) override {
@@ -45,19 +37,6 @@
   ~PersistentPrefStoreMock() override = default;
 };
 
-void ExpectPrefChange(PrefStore* pref_store, base::StringPiece key) {
-  PrefStoreObserverMock observer;
-  pref_store->AddObserver(&observer);
-  base::RunLoop run_loop;
-  EXPECT_CALL(observer, OnPrefValueChanged(key.as_string()))
-      .WillOnce(WithoutArgs(Invoke([&run_loop]() { run_loop.Quit(); })));
-  run_loop.Run();
-  pref_store->RemoveObserver(&observer);
-}
-
-constexpr char kKey[] = "path.to.key";
-constexpr char kOtherKey[] = "path.to.other_key";
-
 class PersistentPrefStoreImplTest : public testing::Test {
  public:
   PersistentPrefStoreImplTest() = default;
@@ -84,7 +63,7 @@
       PersistentPrefStoreImpl::ObservedPrefs observed_prefs =
           PersistentPrefStoreImpl::ObservedPrefs()) {
     if (observed_prefs.empty())
-      observed_prefs.insert({kKey, kOtherKey});
+      observed_prefs.insert({kKey, kOtherDictionaryKey});
     return base::MakeRefCounted<PersistentPrefStoreClient>(
         impl_->CreateConnection(std::move(observed_prefs)));
   }
@@ -164,11 +143,12 @@
   auto other_pref_store = CreateConnection(std::move(observed_prefs));
   EXPECT_TRUE(other_pref_store->IsInitializationComplete());
 
-  pref_store()->SetValue(kOtherKey, std::make_unique<base::Value>(123), 0);
+  pref_store()->SetValue(kOtherDictionaryKey,
+                         std::make_unique<base::Value>(123), 0);
   pref_store()->SetValue(kKey, std::make_unique<base::Value>("value"), 0);
 
   ExpectPrefChange(other_pref_store.get(), kKey);
-  EXPECT_FALSE(other_pref_store->GetValue(kOtherKey, nullptr));
+  EXPECT_FALSE(other_pref_store->GetValue(kOtherDictionaryKey, nullptr));
 }
 
 TEST_F(PersistentPrefStoreImplTest,
@@ -258,7 +238,8 @@
   CreateImpl(backing_store);
   base::RunLoop run_loop;
   EXPECT_CALL(*backing_store, SchedulePendingLossyWrites())
-      .WillOnce(WithoutArgs(Invoke([&run_loop]() { run_loop.Quit(); })));
+      .WillOnce(testing::WithoutArgs(
+          testing::Invoke([&run_loop]() { run_loop.Quit(); })));
   EXPECT_CALL(*backing_store, CommitPendingWriteMock()).Times(1);
   pref_store()->SchedulePendingLossyWrites();
   run_loop.Run();
@@ -269,7 +250,8 @@
   CreateImpl(backing_store);
   base::RunLoop run_loop;
   EXPECT_CALL(*backing_store, ClearMutableValues())
-      .WillOnce(WithoutArgs(Invoke([&run_loop]() { run_loop.Quit(); })));
+      .WillOnce(testing::WithoutArgs(
+          testing::Invoke([&run_loop]() { run_loop.Quit(); })));
   EXPECT_CALL(*backing_store, CommitPendingWriteMock()).Times(1);
   pref_store()->ClearMutableValues();
   run_loop.Run();
diff --git a/services/preferences/pref_service_factory_unittest.cc b/services/preferences/pref_service_factory_unittest.cc
index b006cfd4..71820ab0 100644
--- a/services/preferences/pref_service_factory_unittest.cc
+++ b/services/preferences/pref_service_factory_unittest.cc
@@ -25,6 +25,7 @@
 #include "services/preferences/public/cpp/pref_service_main.h"
 #include "services/preferences/public/cpp/scoped_pref_update.h"
 #include "services/preferences/public/interfaces/preferences.mojom.h"
+#include "services/preferences/unittest_common.h"
 #include "services/service_manager/public/cpp/binder_registry.h"
 #include "services/service_manager/public/cpp/service_context.h"
 #include "services/service_manager/public/cpp/service_test.h"
@@ -84,13 +85,9 @@
   base::OnceCallback<void(service_manager::Connector*)> connector_callback_;
 };
 
-constexpr int kInitialValue = 1;
-constexpr int kUpdatedValue = 2;
-constexpr char kKey[] = "some_key";
-constexpr char kOtherKey[] = "some_other_key";
-constexpr char kDictionaryKey[] = "a.dictionary.pref";
 constexpr char kInitialKey[] = "initial_key";
 constexpr char kOtherInitialKey[] = "other_initial_key";
+constexpr int kUpdatedValue = 2;
 
 class PrefServiceFactoryTest : public service_manager::test::ServiceTest {
  public:
@@ -182,7 +179,7 @@
     auto pref_registry = base::MakeRefCounted<PrefRegistrySimple>();
     pref_registry->RegisterIntegerPref(kKey, kInitialValue,
                                        PrefRegistry::PUBLIC);
-    pref_registry->RegisterIntegerPref(kOtherKey, kInitialValue,
+    pref_registry->RegisterIntegerPref(kOtherDictionaryKey, kInitialValue,
                                        PrefRegistry::PUBLIC);
     pref_registry->RegisterDictionaryPref(kDictionaryKey, PrefRegistry::PUBLIC);
     pref_registry->RegisterForeignPref(kInitialKey);
@@ -193,7 +190,7 @@
   scoped_refptr<PrefRegistrySimple> CreateDefaultForeignPrefRegistry() {
     auto pref_registry = base::MakeRefCounted<PrefRegistrySimple>();
     pref_registry->RegisterForeignPref(kKey);
-    pref_registry->RegisterForeignPref(kOtherKey);
+    pref_registry->RegisterForeignPref(kOtherDictionaryKey);
     pref_registry->RegisterForeignPref(kDictionaryKey);
     return pref_registry;
   }
@@ -307,10 +304,10 @@
     auto pref_registry = base::MakeRefCounted<PrefRegistrySimple>();
     pref_registry->RegisterIntegerPref(kKey, kInitialValue,
                                        PrefRegistry::PUBLIC);
-    pref_registry->RegisterForeignPref(kOtherKey);
+    pref_registry->RegisterForeignPref(kOtherDictionaryKey);
     auto pref_registry2 = base::MakeRefCounted<PrefRegistrySimple>();
     pref_registry2->RegisterForeignPref(kKey);
-    pref_registry2->RegisterIntegerPref(kOtherKey, kInitialValue,
+    pref_registry2->RegisterIntegerPref(kOtherDictionaryKey, kInitialValue,
                                         PrefRegistry::PUBLIC);
     CreateAsync(std::move(pref_registry), connector(), done_closure,
                 &pref_service);
@@ -321,8 +318,8 @@
 
   EXPECT_EQ(kInitialValue, pref_service->GetInteger(kKey));
   EXPECT_EQ(kInitialValue, pref_service2->GetInteger(kKey));
-  EXPECT_EQ(kInitialValue, pref_service->GetInteger(kOtherKey));
-  EXPECT_EQ(kInitialValue, pref_service2->GetInteger(kOtherKey));
+  EXPECT_EQ(kInitialValue, pref_service->GetInteger(kOtherDictionaryKey));
+  EXPECT_EQ(kInitialValue, pref_service2->GetInteger(kOtherDictionaryKey));
 }
 
 // Check that read-only pref store changes are observed.
@@ -357,8 +354,8 @@
   // This update is needed to check that the change to kKey has propagated even
   // though we will not observe it change.
   below_user_prefs_pref_store()->SetValue(
-      kOtherKey, std::make_unique<base::Value>(kUpdatedValue), 0);
-  WaitForPrefChange(pref_service.get(), kOtherKey);
+      kOtherDictionaryKey, std::make_unique<base::Value>(kUpdatedValue), 0);
+  WaitForPrefChange(pref_service.get(), kOtherDictionaryKey);
   EXPECT_EQ(kInitialValue, pref_service->GetInteger(kKey));
 }
 
diff --git a/services/preferences/pref_store_consistency_unittest.cc b/services/preferences/pref_store_consistency_unittest.cc
index 6a1ad23..9dcddaf2 100644
--- a/services/preferences/pref_store_consistency_unittest.cc
+++ b/services/preferences/pref_store_consistency_unittest.cc
@@ -21,16 +21,14 @@
 #include "services/preferences/public/cpp/persistent_pref_store_client.h"
 #include "services/preferences/public/cpp/scoped_pref_update.h"
 #include "services/preferences/public/interfaces/preferences.mojom.h"
+#include "services/preferences/unittest_common.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace prefs {
 namespace {
 
-constexpr int kInitialValue = 1;
-constexpr char kKey[] = "key";
 constexpr char kChildKey[] = "child";
-constexpr char kOtherKey[] = "other_key";
-constexpr char kDictionaryKey[] = "a.dictionary.pref";
+constexpr char kOtherDictionaryKey[] = "other_key";
 
 void DoNothingHandleReadError(PersistentPrefStore::PrefReadError error) {}
 
@@ -58,7 +56,7 @@
   explicit PrefServiceConnection(PersistentPrefStoreImpl* pref_store)
       : observer_binding_(this), pref_store_binding_(this) {
     auto connection = pref_store->CreateConnection({
-        kKey, kOtherKey, kDictionaryKey,
+        kKey, kOtherDictionaryKey, kDictionaryKey,
     });
     observer_binding_.Bind(
         std::move(connection->pref_store_connection->observer));
@@ -72,7 +70,7 @@
     auto pref_notifier = std::make_unique<PrefNotifierImpl>();
     auto pref_registry = base::MakeRefCounted<PrefRegistrySimple>();
     pref_registry->RegisterIntegerPref(kKey, kInitialValue);
-    pref_registry->RegisterIntegerPref(kOtherKey, kInitialValue);
+    pref_registry->RegisterIntegerPref(kOtherDictionaryKey, kInitialValue);
     pref_registry->RegisterDictionaryPref(kDictionaryKey);
     auto pref_value_store = std::make_unique<PrefValueStore>(
         nullptr, nullptr, nullptr, nullptr, pref_store_client_.get(), nullptr,
@@ -296,7 +294,7 @@
   }
   {
     ScopedDictionaryPrefUpdate update(&pref_service2, kDictionaryKey);
-    update->SetInteger(kOtherKey, 3);
+    update->SetInteger(kOtherDictionaryKey, 3);
   }
 
   connection->ForwardWrites(1);
@@ -309,7 +307,7 @@
   two_dict.SetInteger(kKey, 2);
   base::DictionaryValue expected_dict;
   expected_dict.SetInteger(kKey, 2);
-  expected_dict.SetInteger(kOtherKey, 3);
+  expected_dict.SetInteger(kOtherDictionaryKey, 3);
 
   connection->ForwardUpdates(1);
   EXPECT_EQ(two_dict, *pref_service.GetDictionary(kDictionaryKey));
@@ -339,7 +337,7 @@
     update->SetInteger(kKey, 4);
     update->Clear();
     update->SetInteger(kKey, 2);
-    update->SetInteger(kOtherKey, 4);
+    update->SetInteger(kOtherDictionaryKey, 4);
   }
   {
     ScopedDictionaryPrefUpdate update(&pref_service2, kDictionaryKey);
@@ -354,7 +352,7 @@
 
   base::DictionaryValue two_and_four_dict;
   two_and_four_dict.SetInteger(kKey, 2);
-  two_and_four_dict.SetInteger(kOtherKey, 4);
+  two_and_four_dict.SetInteger(kOtherDictionaryKey, 4);
   base::DictionaryValue three_dict;
   three_dict.SetInteger(kKey, 3);
   three_dict.SetDictionary(kDictionaryKey,
@@ -363,7 +361,7 @@
   five_dict.SetKey(kKey, base::Value(5));
   base::DictionaryValue expected_dict;
   expected_dict.SetInteger(kKey, 3);
-  expected_dict.SetInteger(kOtherKey, 4);
+  expected_dict.SetInteger(kOtherDictionaryKey, 4);
 
   connection->ForwardUpdates(1);
   EXPECT_EQ(two_and_four_dict, *pref_service.GetDictionary(kDictionaryKey));
@@ -486,7 +484,7 @@
 
 TEST_F(PersistentPrefStoreConsistencyTest, DeleteParentThenWriteChild) {
   auto initial_value = std::make_unique<base::DictionaryValue>();
-  initial_value->SetInteger(kOtherKey, 5);
+  initial_value->SetInteger(kOtherDictionaryKey, 5);
   pref_store()->SetValue(kDictionaryKey, std::move(initial_value), 0);
   auto connection = CreateConnection();
   auto connection2 = CreateConnection();
@@ -506,7 +504,7 @@
 
   base::DictionaryValue intermediate_dict;
   intermediate_dict.SetInteger(kKey, 3);
-  intermediate_dict.SetInteger(kOtherKey, 5);
+  intermediate_dict.SetInteger(kOtherDictionaryKey, 5);
 
   base::DictionaryValue expected_dict;
   expected_dict.SetInteger(kKey, 3);
@@ -537,7 +535,7 @@
     update->SetInteger(kKey, 1);
     update->Clear();
     update->SetInteger(kKey, 2);
-    update->SetInteger(kOtherKey, 4);
+    update->SetInteger(kOtherDictionaryKey, 4);
   }
   {
     ScopedDictionaryPrefUpdate update(&pref_service2, kDictionaryKey);
@@ -553,10 +551,10 @@
 
   base::DictionaryValue two_and_four_dict;
   two_and_four_dict.SetInteger(kKey, 2);
-  two_and_four_dict.SetInteger(kOtherKey, 4);
+  two_and_four_dict.SetInteger(kOtherDictionaryKey, 4);
   base::DictionaryValue empty_dict;
   base::DictionaryValue expected_dict;
-  expected_dict.SetInteger(kOtherKey, 4);
+  expected_dict.SetInteger(kOtherDictionaryKey, 4);
 
   connection->ForwardUpdates(1);
   EXPECT_EQ(two_and_four_dict, *pref_service.GetDictionary(kDictionaryKey));
@@ -589,7 +587,7 @@
     update->SetInteger(kKey, 4);
     update->Clear();
     update->SetInteger(kKey, 2);
-    update->SetInteger(kOtherKey, 4);
+    update->SetInteger(kOtherDictionaryKey, 4);
   }
   {
     ScopedDictionaryPrefUpdate update(&pref_service2, kDictionaryKey);
@@ -606,7 +604,7 @@
   base::DictionaryValue empty_dict;
   base::DictionaryValue expected_dict;
   expected_dict.SetInteger(kKey, 2);
-  expected_dict.SetInteger(kOtherKey, 4);
+  expected_dict.SetInteger(kOtherDictionaryKey, 4);
 
   connection->ForwardUpdates(1);
   EXPECT_EQ(expected_dict, *pref_service.GetDictionary(kDictionaryKey));
@@ -622,7 +620,7 @@
 
 TEST_F(PersistentPrefStoreConsistencyTest, ReplaceParentThenWriteChild) {
   auto initial_value = std::make_unique<base::DictionaryValue>();
-  initial_value->SetPath({kKey, kOtherKey}, base::Value(5));
+  initial_value->SetPath({kKey, kOtherDictionaryKey}, base::Value(5));
   pref_store()->SetValue(kDictionaryKey, std::move(initial_value), 0);
   auto connection = CreateConnection();
   auto connection2 = CreateConnection();
@@ -647,7 +645,7 @@
   simple_dict.SetInteger(kKey, 1);
   base::DictionaryValue nested_dict;
   nested_dict.SetPath({kKey, kChildKey}, base::Value(2));
-  nested_dict.SetPath({kKey, kOtherKey}, base::Value(5));
+  nested_dict.SetPath({kKey, kOtherDictionaryKey}, base::Value(5));
   base::DictionaryValue expected_dict;
   expected_dict.SetPath({kKey, kChildKey}, base::Value(2));
 
@@ -715,7 +713,7 @@
     auto nested_dict =
         update->SetDictionary(kKey, std::make_unique<base::DictionaryValue>());
     nested_dict->SetInteger(kChildKey, 2);
-    nested_dict->SetInteger(kOtherKey, 4);
+    nested_dict->SetInteger(kOtherDictionaryKey, 4);
   }
   {
     ScopedDictionaryPrefUpdate update(&pref_service2, kDictionaryKey);
@@ -730,7 +728,7 @@
 
   base::DictionaryValue two_and_four_dict;
   two_and_four_dict.SetPath({kKey, kChildKey}, base::Value(2));
-  two_and_four_dict.SetPath({kKey, kOtherKey}, base::Value(4));
+  two_and_four_dict.SetPath({kKey, kOtherDictionaryKey}, base::Value(4));
   base::DictionaryValue three_dict;
   three_dict.SetPath({kKey, kChildKey}, base::Value(3));
   base::Value expected_dict = two_and_four_dict.Clone();
@@ -768,7 +766,7 @@
     auto nested_dict =
         update->SetDictionary(kKey, std::make_unique<base::DictionaryValue>());
     nested_dict->SetInteger(kChildKey, 2);
-    nested_dict->SetInteger(kOtherKey, 4);
+    nested_dict->SetInteger(kOtherDictionaryKey, 4);
   }
   {
     ScopedDictionaryPrefUpdate update(&pref_service2, kDictionaryKey);
@@ -783,7 +781,7 @@
 
   base::DictionaryValue expected_dict;
   expected_dict.SetPath({kKey, kChildKey}, base::Value(2));
-  expected_dict.SetPath({kKey, kOtherKey}, base::Value(4));
+  expected_dict.SetPath({kKey, kOtherDictionaryKey}, base::Value(4));
   base::DictionaryValue three_dict;
   three_dict.SetPath({kKey, kChildKey}, base::Value(3));
 
@@ -802,7 +800,7 @@
 TEST_F(PersistentPrefStoreConsistencyTest,
        DeleteParentThenWriteChildThenDeleteParent) {
   auto initial_value = std::make_unique<base::DictionaryValue>();
-  initial_value->SetInteger(kOtherKey, 5);
+  initial_value->SetInteger(kOtherDictionaryKey, 5);
   pref_store()->SetValue(kDictionaryKey, std::move(initial_value), 0);
   auto connection = CreateConnection();
   auto connection2 = CreateConnection();
@@ -822,7 +820,7 @@
 
   base::DictionaryValue intermediate_dict;
   intermediate_dict.SetInteger(kKey, 3);
-  intermediate_dict.SetInteger(kOtherKey, 5);
+  intermediate_dict.SetInteger(kOtherDictionaryKey, 5);
 
   base::DictionaryValue expected_dict;
   expected_dict.SetInteger(kKey, 3);
@@ -855,7 +853,7 @@
 TEST_F(PersistentPrefStoreConsistencyTest,
        NestedDeleteParentThenWriteChildThenDeleteChild) {
   auto initial_value = std::make_unique<base::DictionaryValue>();
-  initial_value->SetPath({kKey, kOtherKey}, base::Value(5));
+  initial_value->SetPath({kKey, kOtherDictionaryKey}, base::Value(5));
   pref_store()->SetValue(kDictionaryKey, std::move(initial_value), 0);
   auto connection = CreateConnection();
   auto connection2 = CreateConnection();
@@ -878,7 +876,7 @@
 
   base::DictionaryValue intermediate_dict;
   intermediate_dict.SetPath({kKey, kChildKey}, base::Value(3));
-  intermediate_dict.SetPath({kKey, kOtherKey}, base::Value(5));
+  intermediate_dict.SetPath({kKey, kOtherDictionaryKey}, base::Value(5));
 
   base::DictionaryValue expected_dict;
   expected_dict.SetPath({kKey, kChildKey}, base::Value(3));
diff --git a/services/preferences/pref_store_impl_unittest.cc b/services/preferences/pref_store_impl_unittest.cc
index eb0b7c8..aeabab9 100644
--- a/services/preferences/pref_store_impl_unittest.cc
+++ b/services/preferences/pref_store_impl_unittest.cc
@@ -15,21 +15,13 @@
 #include "mojo/public/cpp/bindings/binding_set.h"
 #include "services/preferences/public/cpp/pref_store_client.h"
 #include "services/preferences/public/interfaces/preferences.mojom.h"
+#include "services/preferences/unittest_common.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
-using testing::Invoke;
-using testing::WithoutArgs;
-
 namespace prefs {
 namespace {
 
-class PrefStoreObserverMock : public PrefStore::Observer {
- public:
-  MOCK_METHOD1(OnPrefValueChanged, void(const std::string&));
-  MOCK_METHOD1(OnInitializationCompleted, void(bool));
-};
-
 class MockPrefStore : public ValueMapPrefStore {
  public:
   bool IsInitializationComplete() const override {
@@ -72,26 +64,14 @@
   base::ObserverList<PrefStore::Observer, true> observers_;
 };
 
-constexpr char kKey[] = "path.to.key";
-constexpr char kOtherKey[] = "path.to.other_key";
-
 void ExpectInitializationComplete(PrefStore* pref_store, bool success) {
   PrefStoreObserverMock observer;
   pref_store->AddObserver(&observer);
   base::RunLoop run_loop;
   EXPECT_CALL(observer, OnPrefValueChanged("")).Times(0);
   EXPECT_CALL(observer, OnInitializationCompleted(success))
-      .WillOnce(WithoutArgs(Invoke([&run_loop]() { run_loop.Quit(); })));
-  run_loop.Run();
-  pref_store->RemoveObserver(&observer);
-}
-
-void ExpectPrefChange(PrefStore* pref_store, base::StringPiece key) {
-  PrefStoreObserverMock observer;
-  pref_store->AddObserver(&observer);
-  base::RunLoop run_loop;
-  EXPECT_CALL(observer, OnPrefValueChanged(key.as_string()))
-      .WillOnce(WithoutArgs(Invoke([&run_loop]() { run_loop.Quit(); })));
+      .WillOnce(testing::WithoutArgs(
+          testing::Invoke([&run_loop]() { run_loop.Quit(); })));
   run_loop.Run();
   pref_store->RemoveObserver(&observer);
 }
@@ -114,7 +94,8 @@
     impl_ = std::make_unique<PrefStoreImpl>(std::move(backing_pref_store));
 
     if (observed_prefs.empty())
-      observed_prefs.insert(observed_prefs.end(), {kKey, kOtherKey});
+      observed_prefs.insert(observed_prefs.end(),
+                            {kDictionaryKey, kOtherDictionaryKey});
     pref_store_ = base::MakeRefCounted<PrefStoreClient>(
         impl_->AddObserver(observed_prefs));
   }
@@ -133,7 +114,8 @@
 
 TEST_F(PrefStoreImplTest, InitializationSuccess) {
   auto backing_pref_store = base::MakeRefCounted<MockPrefStore>();
-  backing_pref_store->SetValue(kKey, std::make_unique<base::Value>("value"), 0);
+  backing_pref_store->SetValue(kDictionaryKey,
+                               std::make_unique<base::Value>("value"), 0);
   CreateImpl(backing_pref_store);
   EXPECT_FALSE(pref_store()->IsInitializationComplete());
 
@@ -144,7 +126,8 @@
 
 TEST_F(PrefStoreImplTest, InitializationFailure) {
   auto backing_pref_store = base::MakeRefCounted<MockPrefStore>();
-  backing_pref_store->SetValue(kKey, std::make_unique<base::Value>("value"), 0);
+  backing_pref_store->SetValue(kDictionaryKey,
+                               std::make_unique<base::Value>("value"), 0);
   CreateImpl(backing_pref_store);
   EXPECT_FALSE(pref_store()->IsInitializationComplete());
 
@@ -161,7 +144,7 @@
   EXPECT_FALSE(pref_store()->IsInitializationComplete());
 
   const base::Value value("value");
-  backing_pref_store->SetValue(kKey, value.CreateDeepCopy(), 0);
+  backing_pref_store->SetValue(kDictionaryKey, value.CreateDeepCopy(), 0);
   backing_pref_store->CompleteInitialization(true);
 
   // The update occurs before initialization has completed, so should not
@@ -171,30 +154,30 @@
   EXPECT_TRUE(pref_store()->IsInitializationComplete());
 
   const base::Value* output = nullptr;
-  ASSERT_TRUE(pref_store()->GetValue(kKey, &output));
+  ASSERT_TRUE(pref_store()->GetValue(kDictionaryKey, &output));
   EXPECT_TRUE(value.Equals(output));
 }
 
 TEST_F(PrefStoreImplTest, InitialValue) {
   auto backing_pref_store = base::MakeRefCounted<ValueMapPrefStore>();
   const base::Value value("value");
-  backing_pref_store->SetValue(kKey, value.CreateDeepCopy(), 0);
+  backing_pref_store->SetValue(kDictionaryKey, value.CreateDeepCopy(), 0);
   CreateImpl(backing_pref_store);
   ASSERT_TRUE(pref_store()->IsInitializationComplete());
   const base::Value* output = nullptr;
-  ASSERT_TRUE(pref_store()->GetValue(kKey, &output));
+  ASSERT_TRUE(pref_store()->GetValue(kDictionaryKey, &output));
   EXPECT_TRUE(value.Equals(output));
 }
 
 TEST_F(PrefStoreImplTest, InitialValueWithoutPathExpansion) {
   auto backing_pref_store = base::MakeRefCounted<ValueMapPrefStore>();
   base::DictionaryValue dict;
-  dict.SetKey(kKey, base::Value("value"));
-  backing_pref_store->SetValue(kKey, dict.CreateDeepCopy(), 0);
+  dict.SetKey(kDictionaryKey, base::Value("value"));
+  backing_pref_store->SetValue(kDictionaryKey, dict.CreateDeepCopy(), 0);
   CreateImpl(backing_pref_store);
   ASSERT_TRUE(pref_store()->IsInitializationComplete());
   const base::Value* output = nullptr;
-  ASSERT_TRUE(pref_store()->GetValue(kKey, &output));
+  ASSERT_TRUE(pref_store()->GetValue(kDictionaryKey, &output));
   EXPECT_TRUE(dict.Equals(output));
 }
 
@@ -204,25 +187,26 @@
   ASSERT_TRUE(pref_store()->IsInitializationComplete());
 
   const base::Value value("value");
-  backing_pref_store->SetValue(kKey, value.CreateDeepCopy(), 0);
+  backing_pref_store->SetValue(kDictionaryKey, value.CreateDeepCopy(), 0);
 
-  ExpectPrefChange(pref_store(), kKey);
+  ExpectPrefChange(pref_store(), kDictionaryKey);
   const base::Value* output = nullptr;
-  ASSERT_TRUE(pref_store()->GetValue(kKey, &output));
+  ASSERT_TRUE(pref_store()->GetValue(kDictionaryKey, &output));
   EXPECT_TRUE(value.Equals(output));
 }
 
 TEST_F(PrefStoreImplTest, WriteToUnregisteredPrefNotObservedByClient) {
   auto backing_pref_store = base::MakeRefCounted<ValueMapPrefStore>();
-  CreateImpl(backing_pref_store, {kKey});
+  CreateImpl(backing_pref_store, {kDictionaryKey});
   ASSERT_TRUE(pref_store()->IsInitializationComplete());
 
-  backing_pref_store->SetValue(kOtherKey, std::make_unique<base::Value>(123),
-                               0);
-  backing_pref_store->SetValue(kKey, std::make_unique<base::Value>("value"), 0);
+  backing_pref_store->SetValue(kOtherDictionaryKey,
+                               std::make_unique<base::Value>(123), 0);
+  backing_pref_store->SetValue(kDictionaryKey,
+                               std::make_unique<base::Value>("value"), 0);
 
-  ExpectPrefChange(pref_store(), kKey);
-  EXPECT_FALSE(pref_store()->GetValue(kOtherKey, nullptr));
+  ExpectPrefChange(pref_store(), kDictionaryKey);
+  EXPECT_FALSE(pref_store()->GetValue(kOtherDictionaryKey, nullptr));
 }
 
 TEST_F(PrefStoreImplTest, WriteWithoutPathExpansionObservedByClient) {
@@ -231,71 +215,72 @@
   ASSERT_TRUE(pref_store()->IsInitializationComplete());
 
   base::DictionaryValue dict;
-  dict.SetKey(kKey, base::Value("value"));
-  backing_pref_store->SetValue(kKey, dict.CreateDeepCopy(), 0);
+  dict.SetKey(kDictionaryKey, base::Value("value"));
+  backing_pref_store->SetValue(kDictionaryKey, dict.CreateDeepCopy(), 0);
 
-  ExpectPrefChange(pref_store(), kKey);
+  ExpectPrefChange(pref_store(), kDictionaryKey);
   const base::Value* output = nullptr;
-  ASSERT_TRUE(pref_store()->GetValue(kKey, &output));
+  ASSERT_TRUE(pref_store()->GetValue(kDictionaryKey, &output));
   EXPECT_TRUE(dict.Equals(output));
 }
 
 TEST_F(PrefStoreImplTest, RemoveObservedByClient) {
   auto backing_pref_store = base::MakeRefCounted<ValueMapPrefStore>();
   const base::Value value("value");
-  backing_pref_store->SetValue(kKey, value.CreateDeepCopy(), 0);
+  backing_pref_store->SetValue(kDictionaryKey, value.CreateDeepCopy(), 0);
   CreateImpl(backing_pref_store);
   ASSERT_TRUE(pref_store()->IsInitializationComplete());
 
   const base::Value* output = nullptr;
-  ASSERT_TRUE(pref_store()->GetValue(kKey, &output));
+  ASSERT_TRUE(pref_store()->GetValue(kDictionaryKey, &output));
   EXPECT_TRUE(value.Equals(output));
-  backing_pref_store->RemoveValue(kKey, 0);
+  backing_pref_store->RemoveValue(kDictionaryKey, 0);
 
   // This should be a no-op and shouldn't trigger a notification for the other
   // client.
-  backing_pref_store->RemoveValue(kKey, 0);
+  backing_pref_store->RemoveValue(kDictionaryKey, 0);
 
-  ExpectPrefChange(pref_store(), kKey);
-  EXPECT_FALSE(pref_store()->GetValue(kKey, &output));
+  ExpectPrefChange(pref_store(), kDictionaryKey);
+  EXPECT_FALSE(pref_store()->GetValue(kDictionaryKey, &output));
 }
 
 TEST_F(PrefStoreImplTest, RemoveOfUnregisteredPrefNotObservedByClient) {
   auto backing_pref_store = base::MakeRefCounted<ValueMapPrefStore>();
   const base::Value value("value");
-  backing_pref_store->SetValue(kKey, value.CreateDeepCopy(), 0);
-  backing_pref_store->SetValue(kOtherKey, value.CreateDeepCopy(), 0);
-  CreateImpl(backing_pref_store, {kKey});
+  backing_pref_store->SetValue(kDictionaryKey, value.CreateDeepCopy(), 0);
+  backing_pref_store->SetValue(kOtherDictionaryKey, value.CreateDeepCopy(), 0);
+  CreateImpl(backing_pref_store, {kDictionaryKey});
   ASSERT_TRUE(pref_store()->IsInitializationComplete());
 
-  backing_pref_store->RemoveValue(kOtherKey, 0);
-  backing_pref_store->RemoveValue(kKey, 0);
+  backing_pref_store->RemoveValue(kOtherDictionaryKey, 0);
+  backing_pref_store->RemoveValue(kDictionaryKey, 0);
 
-  ExpectPrefChange(pref_store(), kKey);
+  ExpectPrefChange(pref_store(), kDictionaryKey);
 }
 
 TEST_F(PrefStoreImplTest, RemoveWithoutPathExpansionObservedByOtherClient) {
   auto backing_pref_store = base::MakeRefCounted<ValueMapPrefStore>();
   base::DictionaryValue dict;
-  dict.SetKey(kKey, base::Value("value"));
-  backing_pref_store->SetValue(kKey, dict.CreateDeepCopy(), 0);
+  dict.SetKey(kDictionaryKey, base::Value("value"));
+  backing_pref_store->SetValue(kDictionaryKey, dict.CreateDeepCopy(), 0);
   CreateImpl(backing_pref_store);
   ASSERT_TRUE(pref_store()->IsInitializationComplete());
 
   const base::Value* output = nullptr;
-  ASSERT_TRUE(pref_store()->GetValue(kKey, &output));
+  ASSERT_TRUE(pref_store()->GetValue(kDictionaryKey, &output));
   EXPECT_TRUE(dict.Equals(output));
 
   base::Value* mutable_value = nullptr;
-  dict.SetKey(kKey, base::Value("value"));
-  ASSERT_TRUE(backing_pref_store->GetMutableValue(kKey, &mutable_value));
+  dict.SetKey(kDictionaryKey, base::Value("value"));
+  ASSERT_TRUE(
+      backing_pref_store->GetMutableValue(kDictionaryKey, &mutable_value));
   base::DictionaryValue* mutable_dict = nullptr;
   ASSERT_TRUE(mutable_value->GetAsDictionary(&mutable_dict));
-  mutable_dict->RemoveWithoutPathExpansion(kKey, nullptr);
-  backing_pref_store->ReportValueChanged(kKey, 0);
+  mutable_dict->RemoveWithoutPathExpansion(kDictionaryKey, nullptr);
+  backing_pref_store->ReportValueChanged(kDictionaryKey, 0);
 
-  ExpectPrefChange(pref_store(), kKey);
-  ASSERT_TRUE(pref_store()->GetValue(kKey, &output));
+  ExpectPrefChange(pref_store(), kDictionaryKey);
+  ASSERT_TRUE(pref_store()->GetValue(kDictionaryKey, &output));
   const base::DictionaryValue* dict_value = nullptr;
   ASSERT_TRUE(output->GetAsDictionary(&dict_value));
   EXPECT_TRUE(dict_value->empty());
diff --git a/services/preferences/unittest_common.cc b/services/preferences/unittest_common.cc
new file mode 100644
index 0000000..2dd246de
--- /dev/null
+++ b/services/preferences/unittest_common.cc
@@ -0,0 +1,23 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "services/preferences/unittest_common.h"
+
+namespace prefs {
+
+PrefStoreObserverMock::PrefStoreObserverMock() {}
+PrefStoreObserverMock::~PrefStoreObserverMock() {}
+
+void ExpectPrefChange(PrefStore* pref_store, base::StringPiece key) {
+  PrefStoreObserverMock observer;
+  pref_store->AddObserver(&observer);
+  base::RunLoop run_loop;
+  EXPECT_CALL(observer, OnPrefValueChanged(key.as_string()))
+      .WillOnce(testing::WithoutArgs(
+          testing::Invoke([&run_loop]() { run_loop.Quit(); })));
+  run_loop.Run();
+  pref_store->RemoveObserver(&observer);
+}
+
+}  // namespace prefs
diff --git a/services/preferences/unittest_common.h b/services/preferences/unittest_common.h
new file mode 100644
index 0000000..1237252
--- /dev/null
+++ b/services/preferences/unittest_common.h
@@ -0,0 +1,35 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SERVICES_PREFERENCES_UNITTEST_COMMON_H_
+#define SERVICES_PREFERENCES_UNITTEST_COMMON_H_
+
+#include "base/run_loop.h"
+#include "base/strings/string_piece.h"
+#include "components/prefs/pref_store.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace prefs {
+
+constexpr int kInitialValue = 1;
+constexpr char kKey[] = "some_key";
+constexpr char kDictionaryKey[] = "a.dictionary.pref";
+constexpr char kOtherDictionaryKey[] = "another.dictionary.pref";
+
+class PrefStoreObserverMock : public PrefStore::Observer {
+ public:
+  PrefStoreObserverMock();
+  ~PrefStoreObserverMock();
+  MOCK_METHOD1(OnPrefValueChanged, void(const std::string&));
+  MOCK_METHOD1(OnInitializationCompleted, void(bool));
+};
+
+// Runs a nested runloop until the value of |key| changes in |pref_store|
+// and then returns.
+void ExpectPrefChange(PrefStore* pref_store, base::StringPiece key);
+
+}  // namespace prefs
+
+#endif  // SERVICES_PREFERENCES_UNITTEST_COMMON_H_
diff --git a/services/service_manager/sandbox/mac/BUILD.gn b/services/service_manager/sandbox/mac/BUILD.gn
index 7a7b814..2e4a309 100644
--- a/services/service_manager/sandbox/mac/BUILD.gn
+++ b/services/service_manager/sandbox/mac/BUILD.gn
@@ -9,6 +9,7 @@
     "common.sb",
     "common_v2.sb",
     "gpu.sb",
+    "gpu_v2.sb",
     "nacl_loader.sb",
     "ppapi.sb",
     "ppapi_v2.sb",
diff --git a/services/service_manager/sandbox/mac/gpu_v2.sb b/services/service_manager/sandbox/mac/gpu_v2.sb
new file mode 100644
index 0000000..593b49d
--- /dev/null
+++ b/services/service_manager/sandbox/mac/gpu_v2.sb
@@ -0,0 +1,35 @@
+; Copyright 2017 The Chromium Authors. All rights reserved.
+; Use of this source code is governed by a BSD-style license that can be
+; found in the LICENSE file.
+
+; --- The contents of common.sb implicitly included here. ---
+
+; Allow communication between the GPU process and the UI server.
+(allow mach-lookup
+  (global-name "com.apple.cvmsServ")
+  (global-name "com.apple.tsm.uiserver")
+  (global-name "com.apple.windowserver.active"))
+
+; Needed for WebGL - crbug.com/75343
+(allow iokit-open
+  (iokit-connection "IOAccelerator")
+  (iokit-user-client-class "AGPMClient")
+  (iokit-user-client-class "AppleGraphicsControlClient")
+  (iokit-user-client-class "AppleMGPUPowerControlClient")
+  (iokit-user-client-class "IOAccelerationUserClient")
+  (iokit-user-client-class "IOFramebufferSharedUserClient")
+  (iokit-user-client-class "IOHIDParamUserClient")
+  (iokit-user-client-class "IOSurfaceRootUserClient")
+  (iokit-user-client-class "IOSurfaceSendRight"))
+  (iokit-user-client-class "RootDomainUserClient")
+
+; https://crbug.com/515280
+(if (>= os-version 1011)
+  (allow file-read* (subpath "/System/Library/Extensions")))
+
+; Needed for VideoToolbox usage - https://crbug.com/767037
+(if (= os-version 1013)
+  (allow mach-lookup (global-name "com.apple.coremedia.videodecoder")))
+
+(if (> os-version 1009)
+  (allow sysctl-read (sysctl-name "hw.model")))
diff --git a/skia/config/SkUserConfig.h b/skia/config/SkUserConfig.h
index 48933f5..e13e51b 100644
--- a/skia/config/SkUserConfig.h
+++ b/skia/config/SkUserConfig.h
@@ -224,6 +224,10 @@
 #define SK_SUPPORT_LEGACY_SMALLRECT_AA
 #endif
 
+#ifndef SK_SUPPORT_LEGACY_RECTMAKELARGEST
+#define SK_SUPPORT_LEGACY_RECTMAKELARGEST
+#endif
+
 #ifndef SK_SUPPORT_LEGACY_TILED_BITMAPS
 #define SK_SUPPORT_LEGACY_TILED_BITMAPS
 #endif
@@ -237,9 +241,6 @@
 #define SK_SUPPORT_LEGACY_DASH_CULL_PATH
 #endif
 
-#ifndef SK_SUPPORT_LEGACY_CONTAINED_IN_CLIP
-#define SK_SUPPORT_LEGACY_CONTAINED_IN_CLIP
-#endif
 
 #ifndef SK_SUPPORT_LEGACY_2PT_CONICAL
 #define SK_SUPPORT_LEGACY_2PT_CONICAL
diff --git a/storage/browser/BUILD.gn b/storage/browser/BUILD.gn
index 96d34f61..92d7d5fd 100644
--- a/storage/browser/BUILD.gn
+++ b/storage/browser/BUILD.gn
@@ -38,6 +38,8 @@
     "blob/blob_url_request_job.h",
     "blob/blob_url_request_job_factory.cc",
     "blob/blob_url_request_job_factory.h",
+    "blob/blob_url_store_impl.cc",
+    "blob/blob_url_store_impl.h",
     "blob/mojo_blob_reader.cc",
     "blob/mojo_blob_reader.h",
     "blob/scoped_file.cc",
@@ -249,6 +251,7 @@
     "blob/blob_storage_registry_unittest.cc",
     "blob/blob_transport_request_builder_unittest.cc",
     "blob/blob_transport_strategy_unittest.cc",
+    "blob/blob_url_store_impl_unittest.cc",
     "database/database_quota_client_unittest.cc",
     "database/database_tracker_unittest.cc",
     "database/database_util_unittest.cc",
@@ -314,6 +317,8 @@
     "test/async_file_test_helper.h",
     "test/fileapi_test_file_set.cc",
     "test/fileapi_test_file_set.h",
+    "test/mock_blob_registry_delegate.cc",
+    "test/mock_blob_registry_delegate.h",
     "test/mock_blob_url_request_context.cc",
     "test/mock_blob_url_request_context.h",
     "test/mock_bytes_provider.cc",
diff --git a/storage/browser/blob/blob_registry_impl.cc b/storage/browser/blob/blob_registry_impl.cc
index aeac552..b681c11 100644
--- a/storage/browser/blob/blob_registry_impl.cc
+++ b/storage/browser/blob/blob_registry_impl.cc
@@ -6,11 +6,13 @@
 
 #include "base/barrier_closure.h"
 #include "base/callback_helpers.h"
+#include "mojo/public/cpp/bindings/strong_associated_binding.h"
 #include "mojo/public/cpp/bindings/strong_binding.h"
 #include "storage/browser/blob/blob_data_builder.h"
 #include "storage/browser/blob/blob_impl.h"
 #include "storage/browser/blob/blob_storage_context.h"
 #include "storage/browser/blob/blob_transport_strategy.h"
+#include "storage/browser/blob/blob_url_store_impl.h"
 
 namespace storage {
 
@@ -18,32 +20,6 @@
 
 using MemoryStrategy = BlobMemoryController::Strategy;
 
-class BlobURLHandleImpl final : public blink::mojom::BlobURLHandle {
- public:
-  static blink::mojom::BlobURLHandlePtr Create(
-      base::WeakPtr<BlobStorageContext> context,
-      const GURL& url) {
-    blink::mojom::BlobURLHandlePtr ptr;
-    mojo::MakeStrongBinding(
-        base::WrapUnique(new BlobURLHandleImpl(std::move(context), url)),
-        mojo::MakeRequest(&ptr));
-    return ptr;
-  }
-
-  ~BlobURLHandleImpl() override {
-    if (context_)
-      context_->RevokePublicBlobURL(url_);
-  }
-
- private:
-  BlobURLHandleImpl(base::WeakPtr<BlobStorageContext> context, const GURL& url)
-      : context_(std::move(context)), url_(url) {}
-
-  base::WeakPtr<BlobStorageContext> context_;
-  const GURL url_;
-  DISALLOW_COPY_AND_ASSIGN(BlobURLHandleImpl);
-};
-
 }  // namespace
 
 class BlobRegistryImpl::BlobUnderConstruction {
@@ -579,32 +555,17 @@
   std::move(callback).Run();
 }
 
-void BlobRegistryImpl::RegisterURL(blink::mojom::BlobPtr blob,
-                                   const GURL& url,
-                                   RegisterURLCallback callback) {
+void BlobRegistryImpl::URLStoreForOrigin(
+    const url::Origin& origin,
+    blink::mojom::BlobURLStoreAssociatedRequest request) {
+  // TODO(mek): Pass origin on to BlobURLStoreImpl so it can use it to generate
+  // Blob URLs, and verify at this point that the renderer can create URLs for
+  // that origin.
   Delegate* delegate = bindings_.dispatch_context().get();
   DCHECK(delegate);
-  if (!url.SchemeIsBlob() || !delegate->CanCommitURL(url)) {
-    bindings_.ReportBadMessage(
-        "Invalid Blob URL passed to BlobRegistry::RegisterURL");
-    return;
-  }
-
-  blink::mojom::Blob* blob_ptr = blob.get();
-  blob_ptr->GetInternalUUID(base::BindOnce(
-      &BlobRegistryImpl::RegisterURLWithUUID, weak_ptr_factory_.GetWeakPtr(),
-      url, std::move(blob), std::move(callback)));
-}
-
-void BlobRegistryImpl::RegisterURLWithUUID(const GURL& url,
-                                           blink::mojom::BlobPtr blob,
-                                           RegisterURLCallback callback,
-                                           const std::string& uuid) {
-  // |blob| is unused, but is passed here to be kept alive until
-  // RegisterBlobURL increments the refcount of it via the uuid.
-  if (context_)
-    context_->RegisterPublicBlobURL(url, uuid);
-  std::move(callback).Run(BlobURLHandleImpl::Create(context_, url));
+  mojo::MakeStrongAssociatedBinding(
+      std::make_unique<BlobURLStoreImpl>(context_, delegate),
+      std::move(request));
 }
 
 }  // namespace storage
diff --git a/storage/browser/blob/blob_registry_impl.h b/storage/browser/blob/blob_registry_impl.h
index d302f4d9..46cb970 100644
--- a/storage/browser/blob/blob_registry_impl.h
+++ b/storage/browser/blob/blob_registry_impl.h
@@ -45,20 +45,15 @@
                        const std::string& uuid,
                        GetBlobFromUUIDCallback callback) override;
 
-  void RegisterURL(blink::mojom::BlobPtr blob,
-                   const GURL& url,
-                   RegisterURLCallback callback) override;
+  void URLStoreForOrigin(
+      const url::Origin& origin,
+      blink::mojom::BlobURLStoreAssociatedRequest url_store) override;
 
   size_t BlobsUnderConstructionForTesting() const {
     return blobs_under_construction_.size();
   }
 
  private:
-  void RegisterURLWithUUID(const GURL& url,
-                           blink::mojom::BlobPtr blob,
-                           RegisterURLCallback callback,
-                           const std::string& uuid);
-
   class BlobUnderConstruction;
 
   base::WeakPtr<BlobStorageContext> context_;
diff --git a/storage/browser/blob/blob_registry_impl_unittest.cc b/storage/browser/blob/blob_registry_impl_unittest.cc
index a4ee408..cee4293 100644
--- a/storage/browser/blob/blob_registry_impl_unittest.cc
+++ b/storage/browser/blob/blob_registry_impl_unittest.cc
@@ -16,6 +16,7 @@
 #include "storage/browser/blob/blob_data_builder.h"
 #include "storage/browser/blob/blob_data_handle.h"
 #include "storage/browser/blob/blob_storage_context.h"
+#include "storage/browser/test/mock_blob_registry_delegate.h"
 #include "storage/browser/test/mock_bytes_provider.h"
 #include "storage/browser/test/mock_special_storage_policy.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -62,24 +63,6 @@
   std::string uuid_;
 };
 
-class MockDelegate : public BlobRegistryImpl::Delegate {
- public:
-  MockDelegate() = default;
-  ~MockDelegate() override = default;
-
-  bool CanReadFile(const base::FilePath& file) override {
-    return can_read_file_result;
-  }
-  bool CanReadFileSystemFile(const FileSystemURL& url) override {
-    return can_read_file_system_file_result;
-  }
-  bool CanCommitURL(const GURL& url) override { return can_commit_url_result; }
-
-  bool can_read_file_result = true;
-  bool can_read_file_system_file_result = true;
-  bool can_commit_url_result = true;
-};
-
 void BindBytesProvider(std::unique_ptr<MockBytesProvider> impl,
                        blink::mojom::BytesProviderRequest request) {
   mojo::MakeStrongBinding(std::move(impl), std::move(request));
@@ -107,7 +90,7 @@
                           std::vector<std::string>(), nullptr));
     registry_impl_ = base::MakeUnique<BlobRegistryImpl>(context_->AsWeakPtr(),
                                                         file_system_context_);
-    auto delegate = base::MakeUnique<MockDelegate>();
+    auto delegate = base::MakeUnique<MockBlobRegistryDelegate>();
     delegate_ptr_ = delegate.get();
     registry_impl_->Bind(MakeRequest(&registry_), std::move(delegate));
 
@@ -205,23 +188,6 @@
     return registry_impl_->BlobsUnderConstructionForTesting();
   }
 
-  void RegisterURL(blink::mojom::BlobPtr blob,
-                   const GURL& url,
-                   blink::mojom::BlobURLHandlePtr* url_handle_out) {
-    base::RunLoop loop;
-    registry_->RegisterURL(
-        std::move(blob), url,
-        base::Bind(
-            [](base::Closure quit_closure,
-               blink::mojom::BlobURLHandlePtr* url_handle_out,
-               blink::mojom::BlobURLHandlePtr url_handle) {
-              *url_handle_out = std::move(url_handle);
-              quit_closure.Run();
-            },
-            loop.QuitClosure(), url_handle_out));
-    loop.Run();
-  }
-
  protected:
   base::ScopedTempDir data_dir_;
   base::test::ScopedTaskEnvironment scoped_task_environment_;
@@ -229,7 +195,7 @@
   scoped_refptr<storage::FileSystemContext> file_system_context_;
   std::unique_ptr<BlobRegistryImpl> registry_impl_;
   blink::mojom::BlobRegistryPtr registry_;
-  MockDelegate* delegate_ptr_;
+  MockBlobRegistryDelegate* delegate_ptr_;
   scoped_refptr<base::SequencedTaskRunner> bytes_provider_runner_;
 
   size_t reply_request_count_ = 0;
@@ -1015,42 +981,4 @@
   EXPECT_EQ(0u, BlobsUnderConstruction());
 }
 
-TEST_F(BlobRegistryImplTest, PublicBlobUrls) {
-  const std::string kId = "id";
-  std::unique_ptr<BlobDataHandle> handle =
-      CreateBlobFromString(kId, "hello world");
-
-  blink::mojom::BlobPtr blob;
-  registry_->GetBlobFromUUID(MakeRequest(&blob), kId);
-  EXPECT_EQ(kId, UUIDFromBlob(blob.get()));
-  EXPECT_FALSE(blob.encountered_error());
-
-  // Now register a url for that blob.
-  const GURL kUrl("blob:id");
-  blink::mojom::BlobURLHandlePtr url_handle;
-  RegisterURL(std::move(blob), kUrl, &url_handle);
-
-  std::unique_ptr<BlobDataHandle> blob_data_handle =
-      context_->GetBlobDataFromPublicURL(kUrl);
-  ASSERT_TRUE(blob_data_handle.get());
-  EXPECT_EQ(kId, blob_data_handle->uuid());
-
-  handle.reset();
-  base::RunLoop().RunUntilIdle();
-
-  // The url registration should keep the blob alive even after
-  // explicit references are dropped.
-  blob_data_handle = context_->GetBlobDataFromPublicURL(kUrl);
-  EXPECT_TRUE(blob_data_handle);
-  blob_data_handle.reset();
-
-  // Finally drop the URL handle.
-  url_handle.reset();
-  base::RunLoop().RunUntilIdle();
-
-  blob_data_handle = context_->GetBlobDataFromPublicURL(kUrl);
-  EXPECT_FALSE(blob_data_handle.get());
-  EXPECT_FALSE(context_->registry().HasEntry(kId));
-}
-
 }  // namespace storage
diff --git a/storage/browser/blob/blob_url_store_impl.cc b/storage/browser/blob/blob_url_store_impl.cc
new file mode 100644
index 0000000..cc55a09b
--- /dev/null
+++ b/storage/browser/blob/blob_url_store_impl.cc
@@ -0,0 +1,71 @@
+// 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 "storage/browser/blob/blob_url_store_impl.h"
+
+#include "storage/browser/blob/blob_impl.h"
+#include "storage/browser/blob/blob_storage_context.h"
+
+namespace storage {
+
+BlobURLStoreImpl::BlobURLStoreImpl(base::WeakPtr<BlobStorageContext> context,
+                                   BlobRegistryImpl::Delegate* delegate)
+    : context_(std::move(context)),
+      delegate_(delegate),
+      weak_ptr_factory_(this) {}
+
+BlobURLStoreImpl::~BlobURLStoreImpl() {
+  if (context_) {
+    for (const auto& url : urls_)
+      context_->RevokePublicBlobURL(url);
+  }
+}
+
+void BlobURLStoreImpl::Register(blink::mojom::BlobPtr blob,
+                                const GURL& url,
+                                RegisterCallback callback) {
+  if (!url.SchemeIsBlob() || !delegate_->CanCommitURL(url)) {
+    mojo::ReportBadMessage("Invalid Blob URL passed to BlobURLStore::Register");
+    std::move(callback).Run();
+    return;
+  }
+
+  blink::mojom::Blob* blob_ptr = blob.get();
+  blob_ptr->GetInternalUUID(base::BindOnce(
+      &BlobURLStoreImpl::RegisterWithUUID, weak_ptr_factory_.GetWeakPtr(),
+      std::move(blob), url, std::move(callback)));
+}
+
+void BlobURLStoreImpl::Revoke(const GURL& url) {
+  if (context_)
+    context_->RevokePublicBlobURL(url);
+  urls_.erase(url);
+}
+
+void BlobURLStoreImpl::Resolve(const GURL& url, ResolveCallback callback) {
+  if (!context_) {
+    std::move(callback).Run(nullptr);
+    return;
+  }
+  blink::mojom::BlobPtr blob;
+  std::unique_ptr<BlobDataHandle> blob_handle =
+      context_->GetBlobDataFromPublicURL(url);
+  if (blob_handle)
+    BlobImpl::Create(std::move(blob_handle), MakeRequest(&blob));
+  std::move(callback).Run(std::move(blob));
+}
+
+void BlobURLStoreImpl::RegisterWithUUID(blink::mojom::BlobPtr blob,
+                                        const GURL& url,
+                                        RegisterCallback callback,
+                                        const std::string& uuid) {
+  // |blob| is unused, but is passed here to be kept alive until
+  // RegisterPublicBlobURL increments the refcount of it via the uuid.
+  if (context_)
+    context_->RegisterPublicBlobURL(url, uuid);
+  urls_.insert(url);
+  std::move(callback).Run();
+}
+
+}  // namespace storage
diff --git a/storage/browser/blob/blob_url_store_impl.h b/storage/browser/blob/blob_url_store_impl.h
new file mode 100644
index 0000000..d4186bf
--- /dev/null
+++ b/storage/browser/blob/blob_url_store_impl.h
@@ -0,0 +1,46 @@
+// 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 STORAGE_BROWSER_BLOB_BLOB_URL_STORE_IMPL_H_
+#define STORAGE_BROWSER_BLOB_BLOB_URL_STORE_IMPL_H_
+
+#include <memory>
+#include "storage/browser/blob/blob_registry_impl.h"
+#include "storage/browser/storage_browser_export.h"
+#include "third_party/WebKit/common/blob/blob_url_store.mojom.h"
+
+namespace storage {
+
+class BlobStorageContext;
+
+class STORAGE_EXPORT BlobURLStoreImpl : public blink::mojom::BlobURLStore {
+ public:
+  BlobURLStoreImpl(base::WeakPtr<BlobStorageContext> context,
+                   BlobRegistryImpl::Delegate* delegate);
+  ~BlobURLStoreImpl() override;
+
+  void Register(blink::mojom::BlobPtr blob,
+                const GURL& url,
+                RegisterCallback callback) override;
+  void Revoke(const GURL& url) override;
+  void Resolve(const GURL& url, ResolveCallback callback) override;
+
+ private:
+  void RegisterWithUUID(blink::mojom::BlobPtr blob,
+                        const GURL& url,
+                        RegisterCallback callback,
+                        const std::string& uuid);
+
+  base::WeakPtr<BlobStorageContext> context_;
+  BlobRegistryImpl::Delegate* delegate_;
+
+  std::set<GURL> urls_;
+
+  base::WeakPtrFactory<BlobURLStoreImpl> weak_ptr_factory_;
+  DISALLOW_COPY_AND_ASSIGN(BlobURLStoreImpl);
+};
+
+}  // namespace storage
+
+#endif  // STORAGE_BROWSER_BLOB_BLOB_URL_STORE_IMPL_H_
diff --git a/storage/browser/blob/blob_url_store_impl_unittest.cc b/storage/browser/blob/blob_url_store_impl_unittest.cc
new file mode 100644
index 0000000..f6cac5a3
--- /dev/null
+++ b/storage/browser/blob/blob_url_store_impl_unittest.cc
@@ -0,0 +1,195 @@
+// 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 "storage/browser/blob/blob_url_store_impl.h"
+
+#include "base/test/scoped_task_environment.h"
+#include "mojo/edk/embedder/embedder.h"
+#include "mojo/public/cpp/bindings/strong_binding.h"
+#include "storage/browser/blob/blob_data_builder.h"
+#include "storage/browser/blob/blob_impl.h"
+#include "storage/browser/blob/blob_storage_context.h"
+#include "storage/browser/test/mock_blob_registry_delegate.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using blink::mojom::BlobPtr;
+using blink::mojom::BlobURLStore;
+using blink::mojom::BlobURLStorePtr;
+
+namespace storage {
+
+class BlobURLStoreImplTest : public testing::Test {
+ public:
+  void SetUp() override {
+    context_ = std::make_unique<BlobStorageContext>();
+
+    mojo::edk::SetDefaultProcessErrorCallback(base::BindRepeating(
+        &BlobURLStoreImplTest::OnBadMessage, base::Unretained(this)));
+  }
+
+  void TearDown() override {
+    mojo::edk::SetDefaultProcessErrorCallback(
+        mojo::edk::ProcessErrorCallback());
+  }
+
+  void OnBadMessage(const std::string& error) {
+    bad_messages_.push_back(error);
+  }
+
+  BlobPtr CreateBlobFromString(const std::string& uuid,
+                               const std::string& contents) {
+    BlobDataBuilder builder(uuid);
+    builder.set_content_type("text/plain");
+    builder.AppendData(contents);
+    BlobPtr blob;
+    BlobImpl::Create(context_->AddFinishedBlob(builder), MakeRequest(&blob));
+    return blob;
+  }
+
+  std::string UUIDFromBlob(blink::mojom::Blob* blob) {
+    base::RunLoop loop;
+    std::string received_uuid;
+    blob->GetInternalUUID(base::BindOnce(
+        [](base::OnceClosure quit_closure, std::string* uuid_out,
+           const std::string& uuid) {
+          *uuid_out = uuid;
+          std::move(quit_closure).Run();
+        },
+        loop.QuitClosure(), &received_uuid));
+    loop.Run();
+    return received_uuid;
+  }
+
+  BlobURLStorePtr CreateURLStore() {
+    BlobURLStorePtr result;
+    mojo::MakeStrongBinding(
+        std::make_unique<BlobURLStoreImpl>(context_->AsWeakPtr(), &delegate_),
+        MakeRequest(&result));
+    return result;
+  }
+
+  void RegisterURL(BlobURLStore* store, BlobPtr blob, const GURL& url) {
+    base::RunLoop loop;
+    store->Register(std::move(blob), url, loop.QuitClosure());
+    loop.Run();
+  }
+
+  BlobPtr ResolveURL(BlobURLStore* store, const GURL& url) {
+    BlobPtr result;
+    base::RunLoop loop;
+    store->Resolve(kValidUrl, base::BindOnce(
+                                  [](base::OnceClosure done, BlobPtr* blob_out,
+                                     BlobPtr blob) {
+                                    *blob_out = std::move(blob);
+                                    std::move(done).Run();
+                                  },
+                                  loop.QuitClosure(), &result));
+    loop.Run();
+    return result;
+  }
+
+  const std::string kId = "id";
+  const GURL kValidUrl = GURL("blob:id");
+  const GURL kInvalidUrl = GURL("bolb:id");
+
+ protected:
+  base::test::ScopedTaskEnvironment scoped_task_environment_;
+  std::unique_ptr<BlobStorageContext> context_;
+  MockBlobRegistryDelegate delegate_;
+  std::vector<std::string> bad_messages_;
+};
+
+TEST_F(BlobURLStoreImplTest, BasicRegisterRevoke) {
+  BlobPtr blob = CreateBlobFromString(kId, "hello world");
+
+  // Register a URL and make sure the URL keeps the blob alive.
+  BlobURLStoreImpl url_store(context_->AsWeakPtr(), &delegate_);
+  RegisterURL(&url_store, std::move(blob), kValidUrl);
+
+  std::unique_ptr<BlobDataHandle> blob_data_handle =
+      context_->GetBlobDataFromPublicURL(kValidUrl);
+  ASSERT_TRUE(blob_data_handle);
+  EXPECT_EQ(kId, blob_data_handle->uuid());
+  blob_data_handle = nullptr;
+
+  // Revoke the URL.
+  url_store.Revoke(kValidUrl);
+  blob_data_handle = context_->GetBlobDataFromPublicURL(kValidUrl);
+  EXPECT_FALSE(blob_data_handle);
+
+  base::RunLoop().RunUntilIdle();
+  EXPECT_FALSE(context_->registry().HasEntry(kId));
+}
+
+TEST_F(BlobURLStoreImplTest, RegisterInvalidScheme) {
+  BlobPtr blob = CreateBlobFromString(kId, "hello world");
+
+  BlobURLStorePtr url_store = CreateURLStore();
+  RegisterURL(url_store.get(), std::move(blob), kInvalidUrl);
+  EXPECT_FALSE(context_->GetBlobDataFromPublicURL(kInvalidUrl));
+  EXPECT_EQ(1u, bad_messages_.size());
+}
+
+TEST_F(BlobURLStoreImplTest, RegisterCantCommit) {
+  BlobPtr blob = CreateBlobFromString(kId, "hello world");
+
+  delegate_.can_commit_url_result = false;
+
+  BlobURLStorePtr url_store = CreateURLStore();
+  RegisterURL(url_store.get(), std::move(blob), kValidUrl);
+  EXPECT_FALSE(context_->GetBlobDataFromPublicURL(kValidUrl));
+  EXPECT_EQ(1u, bad_messages_.size());
+}
+
+TEST_F(BlobURLStoreImplTest, ImplicitRevoke) {
+  const GURL kValidUrl2("blob:id2");
+  BlobPtr blob = CreateBlobFromString(kId, "hello world");
+  BlobPtr blob2;
+  blob->Clone(MakeRequest(&blob2));
+
+  auto url_store =
+      std::make_unique<BlobURLStoreImpl>(context_->AsWeakPtr(), &delegate_);
+  RegisterURL(url_store.get(), std::move(blob), kValidUrl);
+  EXPECT_TRUE(context_->GetBlobDataFromPublicURL(kValidUrl));
+  RegisterURL(url_store.get(), std::move(blob2), kValidUrl2);
+  EXPECT_TRUE(context_->GetBlobDataFromPublicURL(kValidUrl2));
+
+  // Destroy URL Store, should revoke URLs.
+  url_store = nullptr;
+  EXPECT_FALSE(context_->GetBlobDataFromPublicURL(kValidUrl));
+  EXPECT_FALSE(context_->GetBlobDataFromPublicURL(kValidUrl2));
+}
+
+TEST_F(BlobURLStoreImplTest, RevokeThroughDifferentURLStore) {
+  BlobPtr blob = CreateBlobFromString(kId, "hello world");
+
+  BlobURLStoreImpl url_store1(context_->AsWeakPtr(), &delegate_);
+  BlobURLStoreImpl url_store2(context_->AsWeakPtr(), &delegate_);
+
+  RegisterURL(&url_store1, std::move(blob), kValidUrl);
+  EXPECT_TRUE(context_->GetBlobDataFromPublicURL(kValidUrl));
+
+  url_store2.Revoke(kValidUrl);
+  EXPECT_FALSE(context_->GetBlobDataFromPublicURL(kValidUrl));
+}
+
+TEST_F(BlobURLStoreImplTest, Resolve) {
+  BlobPtr blob = CreateBlobFromString(kId, "hello world");
+
+  BlobURLStoreImpl url_store(context_->AsWeakPtr(), &delegate_);
+  RegisterURL(&url_store, std::move(blob), kValidUrl);
+
+  blob = ResolveURL(&url_store, kValidUrl);
+  ASSERT_TRUE(blob);
+  EXPECT_EQ(kId, UUIDFromBlob(blob.get()));
+}
+
+TEST_F(BlobURLStoreImplTest, ResolveNonExistentURL) {
+  BlobURLStoreImpl url_store(context_->AsWeakPtr(), &delegate_);
+
+  BlobPtr blob = ResolveURL(&url_store, kValidUrl);
+  EXPECT_FALSE(blob);
+}
+
+}  // namespace storage
diff --git a/storage/browser/test/mock_blob_registry_delegate.cc b/storage/browser/test/mock_blob_registry_delegate.cc
new file mode 100644
index 0000000..54489261
--- /dev/null
+++ b/storage/browser/test/mock_blob_registry_delegate.cc
@@ -0,0 +1,19 @@
+// 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 "storage/browser/test/mock_blob_registry_delegate.h"
+
+namespace storage {
+
+bool MockBlobRegistryDelegate::CanReadFile(const base::FilePath& file) {
+  return can_read_file_result;
+}
+bool MockBlobRegistryDelegate::CanReadFileSystemFile(const FileSystemURL& url) {
+  return can_read_file_system_file_result;
+}
+bool MockBlobRegistryDelegate::CanCommitURL(const GURL& url) {
+  return can_commit_url_result;
+}
+
+}  // namespace storage
diff --git a/storage/browser/test/mock_blob_registry_delegate.h b/storage/browser/test/mock_blob_registry_delegate.h
new file mode 100644
index 0000000..db68558fe
--- /dev/null
+++ b/storage/browser/test/mock_blob_registry_delegate.h
@@ -0,0 +1,28 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef STORAGE_BROWSER_TEST_MOCK_BLOB_REGISTRY_DELEGATE_H_
+#define STORAGE_BROWSER_TEST_MOCK_BLOB_REGISTRY_DELEGATE_H_
+
+#include "storage/browser/blob/blob_registry_impl.h"
+
+namespace storage {
+
+class MockBlobRegistryDelegate : public BlobRegistryImpl::Delegate {
+ public:
+  MockBlobRegistryDelegate() = default;
+  ~MockBlobRegistryDelegate() override = default;
+
+  bool CanReadFile(const base::FilePath& file) override;
+  bool CanReadFileSystemFile(const FileSystemURL& url) override;
+  bool CanCommitURL(const GURL& url) override;
+
+  bool can_read_file_result = true;
+  bool can_read_file_system_file_result = true;
+  bool can_commit_url_result = true;
+};
+
+}  // namespace storage
+
+#endif  // STORAGE_BROWSER_TEST_MOCK_BLOB_REGISTRY_DELEGATE_H_
diff --git a/testing/buildbot/chromium.fyi.json b/testing/buildbot/chromium.fyi.json
index 4fb4ed9..9bc03b4 100644
--- a/testing/buildbot/chromium.fyi.json
+++ b/testing/buildbot/chromium.fyi.json
@@ -4171,6 +4171,17 @@
     "gtest_tests": [
       {
         "args": [
+          "--enable-surface-synchronization"
+        ],
+        "name": "surface_sync_browser_tests",
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "shards": 5
+        },
+        "test": "browser_tests"
+      },
+      {
+        "args": [
           "--enable-viz",
           "--test-launcher-filter-file=../../testing/buildbot/filters/viz.browser_tests.filter"
         ],
@@ -4183,6 +4194,17 @@
       },
       {
         "args": [
+          "--enable-surface-synchronization"
+        ],
+        "name": "surface_sync_content_browsertests",
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "shards": 2
+        },
+        "test": "content_browsertests"
+      },
+      {
+        "args": [
           "--enable-viz",
           "--test-launcher-filter-file=../../testing/buildbot/filters/mojo.fyi.viz.content_browsertests.filter"
         ],
@@ -4464,6 +4486,17 @@
       },
       {
         "args": [
+          "--enable-surface-synchronization"
+        ],
+        "name": "surface_sync_browser_tests",
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "shards": 5
+        },
+        "test": "browser_tests"
+      },
+      {
+        "args": [
           "--enable-viz",
           "--test-launcher-filter-file=../../testing/buildbot/filters/viz.browser_tests.filter"
         ],
@@ -4487,6 +4520,17 @@
       },
       {
         "args": [
+          "--enable-surface-synchronization"
+        ],
+        "name": "surface_sync_content_browsertests",
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "shards": 2
+        },
+        "test": "content_browsertests"
+      },
+      {
+        "args": [
           "--enable-viz",
           "--test-launcher-filter-file=../../testing/buildbot/filters/mojo.fyi.viz.content_browsertests.filter"
         ],
@@ -4627,6 +4671,17 @@
     "gtest_tests": [
       {
         "args": [
+          "--enable-surface-synchronization"
+        ],
+        "name": "surface_sync_browser_tests",
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "shards": 5
+        },
+        "test": "browser_tests"
+      },
+      {
+        "args": [
           "--enable-viz",
           "--test-launcher-filter-file=../../testing/buildbot/filters/viz.browser_tests.filter"
         ],
@@ -4639,6 +4694,17 @@
       },
       {
         "args": [
+          "--enable-surface-synchronization"
+        ],
+        "name": "surface_sync_content_browsertests",
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "shards": 2
+        },
+        "test": "content_browsertests"
+      },
+      {
+        "args": [
           "--enable-viz",
           "--test-launcher-filter-file=../../testing/buildbot/filters/mojo.fyi.viz.content_browsertests.filter"
         ],
diff --git a/testing/buildbot/filters/mojo.fyi.network_browser_tests.filter b/testing/buildbot/filters/mojo.fyi.network_browser_tests.filter
index b64053c..e309668d 100644
--- a/testing/buildbot/filters/mojo.fyi.network_browser_tests.filter
+++ b/testing/buildbot/filters/mojo.fyi.network_browser_tests.filter
@@ -284,7 +284,6 @@
 -DnsProbeBrowserTest.OtherErrorWithCorrectionsFailure
 -DnsProbeBrowserTest.OtherErrorWithCorrectionsSuccess
 -DownloadExtensionTest.DownloadExtensionTest_Download_FileSystemURL
--DownloadExtensionTest.DownloadExtensionTest_Download_Headers_Fail
 -DownloadExtensionTest.DownloadExtensionTest_Download_InterruptAndResume
 -DownloadExtensionTest.DownloadExtensionTest_Download_InvalidURLs
 -DownloadExtensionTest.DownloadExtensionTest_Download_Post_Get
diff --git a/testing/buildbot/filters/viz.content_browsertests.filter b/testing/buildbot/filters/viz.content_browsertests.filter
index 44539ad..96ee975 100644
--- a/testing/buildbot/filters/viz.content_browsertests.filter
+++ b/testing/buildbot/filters/viz.content_browsertests.filter
@@ -49,6 +49,7 @@
 -SitePerProcessBrowserTest.HitTestNestedFrames
 -SitePerProcessBrowserTest.NavigateCrashedSubframeToSameSite
 -SitePerProcessBrowserTest.NestedSurfaceHitTestTest
+-SitePerProcessBrowserTest.OverlapSurfaceHitTestTest
 -SitePerProcessBrowserTest.PopupMenuTest
 -SitePerProcessBrowserTest.RootConsumesScrollDuringOverscrollGesture
 -SitePerProcessBrowserTest.ScrollBubblingFromNestedOOPIFTest
diff --git a/testing/buildbot/filters/viz.content_unittests.filter b/testing/buildbot/filters/viz.content_unittests.filter
index a27159f7..aaf772d0 100644
--- a/testing/buildbot/filters/viz.content_unittests.filter
+++ b/testing/buildbot/filters/viz.content_unittests.filter
@@ -11,6 +11,7 @@
 -RenderWidgetHostViewAuraSurfaceSynchronizationTest.DiscardDelegatedFrames
 -RenderWidgetHostViewAuraSurfaceSynchronizationTest.DropFallbackWhenHidden
 -RenderWidgetHostViewAuraSurfaceSynchronizationTest.SurfaceChanges
+-RenderWidgetHostViewAuraTest.BackgroundColorMatchesCompositorFrame
 -RenderWidgetHostViewAuraTest.DelegatedFrameGutter
 -RenderWidgetHostViewAuraTest.DiscardDelegatedFrames
 -RenderWidgetHostViewAuraTest.DiscardDelegatedFramesWithLocking
diff --git a/testing/buildbot/test_suites.pyl b/testing/buildbot/test_suites.pyl
index 7d647212..bee0333 100644
--- a/testing/buildbot/test_suites.pyl
+++ b/testing/buildbot/test_suites.pyl
@@ -1671,6 +1671,24 @@
   },
 
   'viz_fyi_gtests': {
+    'surface_sync_browser_tests': {
+      'args': [
+        '--enable-surface-synchronization',
+      ],
+      'swarming': {
+        'shards': 5,
+      },
+      'test': 'browser_tests',
+    },
+    'surface_sync_content_browsertests': {
+      'args': [
+        '--enable-surface-synchronization',
+      ],
+      'swarming': {
+        'shards': 2,
+      },
+      'test': 'content_browsertests',
+    },
     'viz_browser_tests': {
       'args': [
         '--enable-viz',
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json
index 78030c9..f931a965 100644
--- a/testing/variations/fieldtrial_testing_config.json
+++ b/testing/variations/fieldtrial_testing_config.json
@@ -1090,21 +1090,6 @@
             ]
         }
     ],
-    "DataReductionProxySiteBreakdown": [
-        {
-            "platforms": [
-                "android"
-            ],
-            "experiments": [
-                {
-                    "name": "Enabled",
-                    "enable_features": [
-                        "DataReductionProxySiteBreakdown"
-                    ]
-                }
-            ]
-        }
-    ],
     "DecoupleTranslateLanguage": [
         {
             "platforms": [
@@ -1227,6 +1212,21 @@
             ]
         }
     ],
+    "DownloadHomeMoreButton": [
+        {
+            "platforms": [
+                "android"
+            ],
+            "experiments": [
+                {
+                    "name": "Enabled",
+                    "params": {
+                        "show_more_button": "true"
+                    }
+                }
+            ]
+        }
+    ],
     "DownloadableStrings": [
         {
             "platforms": [
@@ -2963,25 +2963,6 @@
             ]
         }
     ],
-    "S13nSafeBrowsingParallelUrlCheck": [
-        {
-            "platforms": [
-                "android",
-                "chromeos",
-                "linux",
-                "mac",
-                "win"
-            ],
-            "experiments": [
-                {
-                    "name": "CanaryDev_Enabled",
-                    "enable_features": [
-                        "S13nSafeBrowsingParallelUrlCheck"
-                    ]
-                }
-            ]
-        }
-    ],
     "SRTExperimentalEngineTrial": [
         {
             "platforms": [
@@ -3675,11 +3656,12 @@
             ],
             "experiments": [
                 {
-                    "name": "Enforcement20170329",
+                    "name": "Enforcement20180102",
                     "params": {
-                        "translate-ranker-model-url": "https://www.gstatic.com/chrome/intelligence/assist/ranker/models/translate/2017/03/translate_ranker_model_20170329.pb.bin"
+                        "translate-ranker-model-url": "https://www.gstatic.com/chrome/intelligence/assist/ranker/models/translate/translate_ranker_autoblacklist_20180102.model"
                     },
                     "enable_features": [
+                        "TranslateRankerAutoBlacklistOverride",
                         "TranslateRankerEnforcement",
                         "TranslateRankerQuery"
                     ]
diff --git a/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG b/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG
index b4198121..3f85cae 100644
--- a/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG
+++ b/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG
@@ -3622,6 +3622,7 @@
 crbug.com/591099 fast/borders/rtl-border-01.html [ Failure ]
 crbug.com/591099 fast/borders/rtl-border-02.html [ Failure ]
 crbug.com/591099 fast/borders/rtl-border-03.html [ Failure ]
+crbug.com/591099 fast/borders/rtl-border-04.html [ Failure ]
 crbug.com/591099 fast/borders/rtl-border-05.html [ Failure ]
 crbug.com/714962 fast/borders/table-borders.html [ Failure ]
 crbug.com/591099 fast/box-decoration-break/box-decoration-break-rendering.html [ Failure ]
@@ -4162,6 +4163,7 @@
 crbug.com/591099 fast/css3-text/css3-text-decoration/text-underline-position/text-underline-position-under.html [ Failure ]
 crbug.com/591099 fast/css3-text/css3-text-indent/negative-text-indent-leading-out-of-flow-text-align-left-and-right.html [ Failure ]
 crbug.com/591099 fast/css3-text/css3-text-indent/negative-text-indent-leading-out-of-flow.html [ Failure ]
+crbug.com/591099 fast/css3-text/css3-text-indent/text-indent-each-line-hanging.html [ Failure ]
 crbug.com/591099 fast/css3-text/css3-text-indent/text-indent-leading-out-of-flow.html [ Failure ]
 crbug.com/591099 fast/css3-text/css3-text-indent/text-indent-out-of-flow-each-line-hanging.html [ Failure ]
 crbug.com/591099 fast/css3-text/css3-text-justify/text-justify-distribute.html [ Failure ]
@@ -6363,6 +6365,8 @@
 crbug.com/591099 fast/text/whitespace/reattach-before-pseudo-slot-fallback-whitespace.html [ Failure ]
 crbug.com/591099 fast/text/whitespace/reattach-before-pseudo.html [ Failure ]
 crbug.com/591099 fast/text/whitespace/reattach-slotted-whitespace.html [ Failure ]
+crbug.com/636993 fast/text/whitespace/text-align-justify-and-whitespace-pre.html [ Failure ]
+crbug.com/591099 fast/text/whitespace/whitespace-in-pre.html [ Failure ]
 crbug.com/591099 fast/text/writing-root-with-overflow-clip-baseline.html [ Crash ]
 crbug.com/591099 fast/text/zero-width-characters-complex-script.html [ Failure ]
 crbug.com/591099 fast/text/zero-width-characters.html [ Failure ]
diff --git a/third_party/WebKit/LayoutTests/FlagExpectations/enable-features=NetworkService b/third_party/WebKit/LayoutTests/FlagExpectations/enable-features=NetworkService
index 0a7b6d3..7698268 100644
--- a/third_party/WebKit/LayoutTests/FlagExpectations/enable-features=NetworkService
+++ b/third_party/WebKit/LayoutTests/FlagExpectations/enable-features=NetworkService
@@ -18,6 +18,9 @@
 Bug(none) external/wpt/css/cssom-view/scrollingElement.html [ Failure Timeout Crash ]
 Bug(none) external/wpt/css/css-fonts/font-display/font-display.html [ Failure Timeout ]
 Bug(none) external/wpt/fetch/api/cors/cors-cookies.any.html [ Failure Pass ]
+Bug(none) external/wpt/fetch/api/request/destination/fetch-destination-iframe.https.html [ Failure ]
+Bug(none) external/wpt/fetch/api/request/destination/fetch-destination-no-load-event.https.html [ Timeout ]
+Bug(none) external/wpt/fetch/api/request/destination/fetch-destination-worker.https.html [ Timeout ]
 Bug(none) external/wpt/html/browsers/history/the-location-interface/location-protocol-setter-non-broken-weird.html [ Failure Timeout Failure ]
 Bug(none) external/wpt/html/browsers/offline/appcache/workers/appcache-worker.html [ Timeout ]
 Bug(none) external/wpt/html/semantics/embedded-content/the-iframe-element/iframe-load-event.html [ Crash Failure Timeout ]
@@ -69,6 +72,7 @@
 Bug(none) external/wpt/websockets/cookies/002.html [ Failure ]
 Bug(none) external/wpt/websockets/cookies/003.html [ Failure ]
 Bug(none) external/wpt/websockets/cookies/006.html?wss [ Crash ]
+Bug(none) external/wpt/websockets/opening-handshake/003.html?wss [ Pass Timeout ]
 Bug(none) fast/dom/Range/surround-contents-font-face-crash.svg [ Timeout ]
 Bug(none) fast/dom/split-cdata.xml [ Timeout ]
 
diff --git a/third_party/WebKit/LayoutTests/TestExpectations b/third_party/WebKit/LayoutTests/TestExpectations
index c3f17b0..1a9b4bc 100644
--- a/third_party/WebKit/LayoutTests/TestExpectations
+++ b/third_party/WebKit/LayoutTests/TestExpectations
@@ -1471,6 +1471,7 @@
 crbug.com/613672 [ Mac ] external/wpt/pointerevents/pointerevent_touch-action-inherit_child-none_touch-manual.html  [ Skip ]
 crbug.com/613672 [ Mac ] external/wpt/pointerevents/pointerevent_touch-action-inherit_child-pan-x-child-pan-y_touch-manual.html  [ Skip ]
 crbug.com/613672 [ Mac ] external/wpt/pointerevents/pointerevent_touch-action-inherit_child-auto-child-none_touch-manual.html  [ Skip ]
+crbug.com/613672 [ Mac ] external/wpt/pointerevents/pointerevent_fractional_coordinates-manual.html  [ Skip ]
 crbug.com/613672 [ Mac ] fast/events/synthetic-events/tap-on-scaled-screen.html  [ Skip ]
 crbug.com/613672 [ Mac ] virtual/scalefactor150/fast/events/synthetic-events/tap-on-scaled-screen.html  [ Skip ]
 crbug.com/613672 [ Mac ] virtual/mouseevent_fractional/fast/events/pointerevents/multi-pointer-event-in-slop-region.html [ Skip ]
@@ -3543,9 +3544,6 @@
 crbug.com/797138 external/wpt/credential-management/federatedcredential-framed-get.sub.https.html [ Crash ]
 crbug.com/797138 external/wpt/credential-management/passwordcredential-framed-get.sub.https.html [ Crash ]
 
-# Pixel values changes insignificantly due to using a different SkMatrix method to compute texture coords
-crbug.com/799666 virtual/gpu/fast/canvas/canvas-imageSmoothingEnabled-patterns.html [ NeedsManualRebaseline ]
-
 # Sheriff failures 2018-01-02
 crbug.com/798527 [ Linux ] virtual/spv175/compositing/gestures/gesture-tapHighlight-with-box-shadow.html [ Pass Failure ]
 crbug.com/798592 [ Win7 ] virtual/threaded/http/tests/devtools/tracing/timeline-style/timeline-recalculate-styles.js [ Pass Failure ]
diff --git a/third_party/WebKit/LayoutTests/bluetooth/service/getCharacteristics/characteristics-not-found.html b/third_party/WebKit/LayoutTests/bluetooth/service/getCharacteristics/characteristics-not-found.html
deleted file mode 100644
index 9ba8ad7..0000000
--- a/third_party/WebKit/LayoutTests/bluetooth/service/getCharacteristics/characteristics-not-found.html
+++ /dev/null
@@ -1,16 +0,0 @@
-<!DOCTYPE html>
-<script src="../../../resources/testharness.js"></script>
-<script src="../../../resources/testharnessreport.js"></script>
-<script src="../../../resources/testdriver.js"></script>
-<script src="../../../resources/testdriver-vendor.js"></script>
-<script src="../../../external/wpt/bluetooth/resources/bluetooth-helpers.js"></script>
-<script>
-'use strict';
-bluetooth_test(() => {
-  return getEmptyHealthThermometerService()
-    .then(({service}) => assert_promise_rejects_with_message(
-      service.getCharacteristics(),
-      new DOMException('No Characteristics found in service.',
-                       'NotFoundError')))
-}, 'Request for absent characteristics. Reject with NotFoundError.');
-</script>
diff --git a/third_party/WebKit/LayoutTests/css3/blending/background-blend-mode-crossfade-image-gradient-expected.png b/third_party/WebKit/LayoutTests/css3/blending/background-blend-mode-crossfade-image-gradient-expected.png
index c311df0..43d24dae 100644
--- a/third_party/WebKit/LayoutTests/css3/blending/background-blend-mode-crossfade-image-gradient-expected.png
+++ b/third_party/WebKit/LayoutTests/css3/blending/background-blend-mode-crossfade-image-gradient-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST.json b/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST.json
index 3ed31346..2a733acd 100644
--- a/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST.json
+++ b/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST.json
@@ -136901,6 +136901,11 @@
      {}
     ]
    ],
+   "html/semantics/embedded-content/media-elements/track/track-element/track-cue-negative-timestamp-expected.txt": [
+    [
+     {}
+    ]
+   ],
    "html/semantics/embedded-content/media-elements/track/track-element/track-cue-order-expected.txt": [
     [
      {}
@@ -181633,6 +181638,18 @@
      {}
     ]
    ],
+   "html/semantics/embedded-content/media-elements/track/track-element/track-change-event.html": [
+    [
+     "/html/semantics/embedded-content/media-elements/track/track-element/track-change-event.html",
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/media-elements/track/track-element/track-css-cue-pseudo-class.html": [
+    [
+     "/html/semantics/embedded-content/media-elements/track/track-element/track-css-cue-pseudo-class.html",
+     {}
+    ]
+   ],
    "html/semantics/embedded-content/media-elements/track/track-element/track-cue-empty.html": [
     [
      "/html/semantics/embedded-content/media-elements/track/track-element/track-cue-empty.html",
@@ -181657,12 +181674,24 @@
      {}
     ]
    ],
+   "html/semantics/embedded-content/media-elements/track/track-element/track-cue-negative-timestamp.html": [
+    [
+     "/html/semantics/embedded-content/media-elements/track/track-element/track-cue-negative-timestamp.html",
+     {}
+    ]
+   ],
    "html/semantics/embedded-content/media-elements/track/track-element/track-cue-order.html": [
     [
      "/html/semantics/embedded-content/media-elements/track/track-element/track-cue-order.html",
      {}
     ]
    ],
+   "html/semantics/embedded-content/media-elements/track/track-element/track-cue-rendering-empty-cue.html": [
+    [
+     "/html/semantics/embedded-content/media-elements/track/track-element/track-cue-rendering-empty-cue.html",
+     {}
+    ]
+   ],
    "html/semantics/embedded-content/media-elements/track/track-element/track-cues-missed.html": [
     [
      "/html/semantics/embedded-content/media-elements/track/track-element/track-cues-missed.html",
@@ -181693,6 +181722,18 @@
      {}
     ]
    ],
+   "html/semantics/embedded-content/media-elements/track/track-element/track-default-attribute.html": [
+    [
+     "/html/semantics/embedded-content/media-elements/track/track-element/track-default-attribute.html",
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/media-elements/track/track-element/track-delete-during-setup.html": [
+    [
+     "/html/semantics/embedded-content/media-elements/track/track-element/track-delete-during-setup.html",
+     {}
+    ]
+   ],
    "html/semantics/embedded-content/media-elements/track/track-element/track-disabled-addcue.html": [
     [
      "/html/semantics/embedded-content/media-elements/track/track-element/track-disabled-addcue.html",
@@ -182023,6 +182064,12 @@
      {}
     ]
    ],
+   "html/semantics/embedded-content/media-elements/track/track-element/vtt-cue-float-precision.html": [
+    [
+     "/html/semantics/embedded-content/media-elements/track/track-element/vtt-cue-float-precision.html",
+     {}
+    ]
+   ],
    "html/semantics/embedded-content/media-elements/user-interface/muted.html": [
     [
      "/html/semantics/embedded-content/media-elements/user-interface/muted.html",
@@ -228879,7 +228926,7 @@
    "testharness"
   ],
   "2dcontext/imagebitmap/createImageBitmap-invalid-args.html": [
-   "59b291fb7cd47850077637d7ed92ca81e95b89e3",
+   "0f8e0a2a9099ac869e2435dfe018bc1fb65ec71f",
    "testharness"
   ],
   "2dcontext/imagebitmap/createImageBitmap-sizeOverflow.html": [
@@ -254487,15 +254534,15 @@
    "reftest"
   ],
   "css/css-display/display-contents-before-after-001.html": [
-   "c2aaba86d809355c03e007d4a0d1f470fad080eb",
+   "af7af78d4636ad5bbb33360a0392a8ae684650d7",
    "reftest"
   ],
   "css/css-display/display-contents-before-after-002.html": [
-   "ab66821c508ced9656c769ff2647c7f9d57e4b15",
+   "9979124cc0512f1e110f9e5e091666da19f3eff5",
    "reftest"
   ],
   "css/css-display/display-contents-before-after-003.html": [
-   "2c15d52fdcb0ef9de97beb7bff8fdd2a733f1d67",
+   "5267b8dbd01301385fd76f6938f3ef2e7af0f2a1",
    "reftest"
   ],
   "css/css-display/display-contents-block-001.html": [
@@ -254511,7 +254558,7 @@
    "reftest"
   ],
   "css/css-display/display-contents-button.html": [
-   "31f559d839f47e4034910ecf9224cccb3d44cac4",
+   "b00b06641c653af5ab91a6156a726ff2d4ea9b00",
    "reftest"
   ],
   "css/css-display/display-contents-computed-style.html": [
@@ -254611,7 +254658,7 @@
    "reftest"
   ],
   "css/css-display/display-contents-fieldset.html": [
-   "5532214fa9e6d5b8a6423701760204f96efd65fe",
+   "353abc0ce5abe98a1678fbd5832bf16a0d8b5094",
    "reftest"
   ],
   "css/css-display/display-contents-first-letter-001.html": [
@@ -254707,7 +254754,7 @@
    "support"
   ],
   "css/css-display/display-contents-pass-ref.html": [
-   "f9d1eaa996cfe84ba9600383bd6c38d179fcbe91",
+   "d6212621df87df9426ddb29b936703ace2813888",
    "support"
   ],
   "css/css-display/display-contents-state-change-001-ref.html": [
@@ -254743,7 +254790,7 @@
    "reftest"
   ],
   "css/css-display/display-contents-td-001.html": [
-   "95db05421f7ca48ed528db9fa2c23cfd5ccbac97",
+   "073573175b4ef24f0ba26ae7456e161f775a7d40",
    "reftest"
   ],
   "css/css-display/display-contents-text-inherit-ref.html": [
@@ -254771,7 +254818,7 @@
    "reftest"
   ],
   "css/css-display/display-contents-unusual-html-elements-none.html": [
-   "dc354fb4f1896f655186cf57dd100f475a4ce5f0",
+   "5ed492f5aadedcd3e46d0a578d357d033e316351",
    "reftest"
   ],
   "css/css-display/display-flow-root-001-ref.html": [
@@ -314054,6 +314101,14 @@
    "f7576ff332cac04a4e2b663b6fdd40aef154b6b5",
    "testharness"
   ],
+  "html/semantics/embedded-content/media-elements/track/track-element/track-change-event.html": [
+   "16684e6cccc9f825a6a15875322c4143954664be",
+   "testharness"
+  ],
+  "html/semantics/embedded-content/media-elements/track/track-element/track-css-cue-pseudo-class.html": [
+   "2ce3f40f1d63b1cf934d2dffc95c984c81d47a69",
+   "testharness"
+  ],
   "html/semantics/embedded-content/media-elements/track/track-element/track-cue-empty.html": [
    "8836253fa3f97ff0b8b4c7af2078f667d2bd0738",
    "testharness"
@@ -314070,6 +314125,14 @@
    "c8ab03c7d84d150befa8152e552d99e889ce4ec0",
    "testharness"
   ],
+  "html/semantics/embedded-content/media-elements/track/track-element/track-cue-negative-timestamp-expected.txt": [
+   "25316c89373c90fa0a2f520d171a92cb48dc5c6d",
+   "support"
+  ],
+  "html/semantics/embedded-content/media-elements/track/track-element/track-cue-negative-timestamp.html": [
+   "ac23d5be03b500a264d3bf919d88396e318b4e89",
+   "testharness"
+  ],
   "html/semantics/embedded-content/media-elements/track/track-element/track-cue-order-expected.txt": [
    "2bb2fdf21fd4ec2c82315e6dcf1759f6f84e37c4",
    "support"
@@ -314078,6 +314141,10 @@
    "eeab6b02e728aea21878cf72664929766be057b7",
    "testharness"
   ],
+  "html/semantics/embedded-content/media-elements/track/track-element/track-cue-rendering-empty-cue.html": [
+   "688c592e8fc4b4dbc2d7d6ea16e17380c13f440a",
+   "testharness"
+  ],
   "html/semantics/embedded-content/media-elements/track/track-element/track-cues-missed.html": [
    "a87ad9da0dad43e1b68183feeabce59a5c864087",
    "testharness"
@@ -314102,6 +314169,14 @@
    "e9c8849350512b1247543939ee0e529947e47c2d",
    "testharness"
   ],
+  "html/semantics/embedded-content/media-elements/track/track-element/track-default-attribute.html": [
+   "47a04910cd1db3c2d9aa2cfd4f330067a77d6f0e",
+   "testharness"
+  ],
+  "html/semantics/embedded-content/media-elements/track/track-element/track-delete-during-setup.html": [
+   "9b2dc966c2ed4ab5c3673826c9c92970c794b235",
+   "testharness"
+  ],
   "html/semantics/embedded-content/media-elements/track/track-element/track-disabled-addcue.html": [
    "50932e2a3ce52440fa5e3af935f11120267bc4dd",
    "testharness"
@@ -314326,6 +314401,10 @@
    "c016678eb1f14aad834d4e6e3bbca1818760284a",
    "testharness"
   ],
+  "html/semantics/embedded-content/media-elements/track/track-element/vtt-cue-float-precision.html": [
+   "a88eecf0d2fb4e3c6a79ea81f22f13e023361d81",
+   "testharness"
+  ],
   "html/semantics/embedded-content/media-elements/user-interface/muted.html": [
    "74deefbbc4b8f96ff4856db1c32c6428183cc040",
    "testharness"
@@ -319751,7 +319830,7 @@
    "support"
   ],
   "html/semantics/tabular-data/the-table-element/caption-methods.html": [
-   "86605a4059ee7f25c555de2ad7f721beb566b2df",
+   "a9340862c368c99492ab20e1e743362dd7f0525a",
    "testharness"
   ],
   "html/semantics/tabular-data/the-table-element/contains.json": [
diff --git a/third_party/WebKit/LayoutTests/external/wpt/2dcontext/imagebitmap/createImageBitmap-invalid-args.html b/third_party/WebKit/LayoutTests/external/wpt/2dcontext/imagebitmap/createImageBitmap-invalid-args.html
index 922597d..1fe71856 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/2dcontext/imagebitmap/createImageBitmap-invalid-args.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/2dcontext/imagebitmap/createImageBitmap-invalid-args.html
@@ -46,8 +46,7 @@
 
 testCases = [
   {
-    description: 'createImageBitmap with a <sourceType> source and sw set to ' +
-        '0 rejects with a RangeError.',
+    description: 'createImageBitmap with a <sourceType> source and sw set to 0',
     promiseTestFunction:
       (source, t) => {
         return promise_rejects(t, new RangeError(),
@@ -55,8 +54,7 @@
       }
   },
   {
-    description: 'createImageBitmap with a <sourceType> source and sh set to ' +
-        '0 rejects with a RangeError.',
+    description: 'createImageBitmap with a <sourceType> source and sh set to 0',
     promiseTestFunction:
       (source, t) => {
         return promise_rejects(t, new RangeError(),
@@ -66,10 +64,11 @@
   {
     // This case is not explicitly documented in the specification for
     // createImageBitmap, but it is expected that internal failures cause
+    // InvalidStateError.
     //
+    // Note: https://bugs.chromium.org/p/chromium/issues/detail?id=799025
     description: 'createImageBitmap with a <sourceType> source and oversized ' +
-        '(unallocatable) crop region rejects with an InvalidStateError ' +
-        'DOMException.',
+        '(unallocatable) crop region',
     promiseTestFunction:
       (source, t) => {
         return promise_rejects(t, new DOMException('', 'InvalidStateError'),
@@ -93,61 +92,61 @@
 
 promise_test( t => {
   return promise_rejects(t, new TypeError(), createImageBitmap(undefined));
-}, "createImageBitmap with undefined image source rejects with a TypeError.");
+}, "createImageBitmap with undefined image source.");
 
 promise_test( t => {
   return promise_rejects(t, new TypeError(), createImageBitmap(null));
-}, "createImageBitmap with null image source rejects with a TypeError.");
+}, "createImageBitmap with null image source.");
 
 promise_test( t => {
   return promise_rejects(t, "InvalidStateError",
     createImageBitmap(new Image()));
-}, "createImageBitmap with empty image source rejects with a InvalidStateError.");
+}, "createImageBitmap with empty image source.");
 
 promise_test( t => {
   return promise_rejects(t, "InvalidStateError",
     createImageBitmap(document.createElement('video')));
-}, "createImageBitmap with empty video source rejects with a InvalidStateError.");
+}, "createImageBitmap with empty video source.");
 
 promise_test( t => {
   return makeOversizedCanvas().then(canvas => {
     return promise_rejects(t, "InvalidStateError",
         createImageBitmap(canvas));
   });
-}, "createImageBitmap with an oversized canvas source rejects with a RangeError.");
+}, "createImageBitmap with an oversized canvas source.");
 
 promise_test( t => {
   return makeOversizedOffscreenCanvas().then(offscreenCanvas => {
     return promise_rejects(t, "InvalidStateError",
         createImageBitmap(offscreenCanvas));
   });
-}, "createImageBitmap with an invalid OffscreenCanvas source rejects with a RangeError.");
+}, "createImageBitmap with an invalid OffscreenCanvas source.");
 
 promise_test( t => {
   return makeInvalidBlob().then(blob => {
     return promise_rejects(t, "InvalidStateError",
         createImageBitmap(blob));
   });
-}, "createImageBitmap with an undecodable blob source rejects with an InvalidStateError.");
+}, "createImageBitmap with an undecodable blob source.");
 
 promise_test( t => {
   return makeBrokenImage().then(image => {
     return promise_rejects(t, "InvalidStateError",
         createImageBitmap(image));
   });
-}, "createImageBitmap with a broken image source rejects with an InvalidStateError.");
+}, "createImageBitmap with a broken image source.");
 
 promise_test( t => {
   return makeAvailableButBrokenImage().then(image => {
     return promise_rejects(t, "InvalidStateError",
         createImageBitmap(image));
   });
-}, "createImageBitmap with an available but undecodable image source rejects with an InvalidStateError.");
+}, "createImageBitmap with an available but undecodable image source.");
 
 promise_test( t => {
   return makeImageBitmap().then(bitmap => {
     bitmap.close()
     return promise_rejects(t, "InvalidStateError", createImageBitmap(bitmap));
   });
-}, "createImageBitmap with a closed ImageBitmap rejects with an InvalidStateError.");
+}, "createImageBitmap with a closed ImageBitmap.");
 </script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/bluetooth/resources/bluetooth-helpers.js b/third_party/WebKit/LayoutTests/external/wpt/bluetooth/resources/bluetooth-helpers.js
index 3f3ff5218..851f647 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/bluetooth/resources/bluetooth-helpers.js
+++ b/third_party/WebKit/LayoutTests/external/wpt/bluetooth/resources/bluetooth-helpers.js
@@ -52,8 +52,8 @@
       // problem for the new tests that do not use setBluetoothFakeAdapter().
       // TODO(crbug.com/569709): Remove once setBluetoothFakeAdapter is no
       // longer used.
-      .then(() => setBluetoothFakeAdapter ? setBluetoothFakeAdapter('')
-                                          : undefined);
+      .then(() => typeof setBluetoothFakeAdapter === 'undefined' ?
+          undefined : setBluetoothFakeAdapter(''));
 }
 
 
diff --git a/third_party/WebKit/LayoutTests/bluetooth/service/getCharacteristic/characteristic-found.html b/third_party/WebKit/LayoutTests/external/wpt/bluetooth/service/getCharacteristic/characteristic-found.https.html
similarity index 73%
rename from third_party/WebKit/LayoutTests/bluetooth/service/getCharacteristic/characteristic-found.html
rename to third_party/WebKit/LayoutTests/external/wpt/bluetooth/service/getCharacteristic/characteristic-found.https.html
index 08ed8b8..9cf34c20 100644
--- a/third_party/WebKit/LayoutTests/bluetooth/service/getCharacteristic/characteristic-found.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/bluetooth/service/getCharacteristic/characteristic-found.https.html
@@ -1,9 +1,9 @@
 <!DOCTYPE html>
-<script src="../../../resources/testharness.js"></script>
-<script src="../../../resources/testharnessreport.js"></script>
-<script src="../../../resources/testdriver.js"></script>
-<script src="../../../resources/testdriver-vendor.js"></script>
-<script src="../../../external/wpt/bluetooth/resources/bluetooth-helpers.js"></script>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver-vendor.js"></script>
+<script src="/bluetooth/resources/bluetooth-helpers.js"></script>
 <script>
 'use strict';
 bluetooth_test(() => {
diff --git a/third_party/WebKit/LayoutTests/bluetooth/service/getCharacteristics/blocklisted-characteristics.html b/third_party/WebKit/LayoutTests/external/wpt/bluetooth/service/getCharacteristics/blocklisted-characteristics.https.html
similarity index 61%
rename from third_party/WebKit/LayoutTests/bluetooth/service/getCharacteristics/blocklisted-characteristics.html
rename to third_party/WebKit/LayoutTests/external/wpt/bluetooth/service/getCharacteristics/blocklisted-characteristics.https.html
index 0b810fa..48c3c28 100644
--- a/third_party/WebKit/LayoutTests/bluetooth/service/getCharacteristics/blocklisted-characteristics.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/bluetooth/service/getCharacteristics/blocklisted-characteristics.https.html
@@ -1,9 +1,9 @@
 <!DOCTYPE html>
-<script src="../../../resources/testharness.js"></script>
-<script src="../../../resources/testharnessreport.js"></script>
-<script src="../../../resources/testdriver.js"></script>
-<script src="../../../resources/testdriver-vendor.js"></script>
-<script src="../../../external/wpt/bluetooth/resources/bluetooth-helpers.js"></script>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver-vendor.js"></script>
+<script src="/bluetooth/resources/bluetooth-helpers.js"></script>
 <script>
 'use strict';
 bluetooth_test(() => {
diff --git a/third_party/WebKit/LayoutTests/bluetooth/service/getCharacteristics/characteristics-found-with-uuid.html b/third_party/WebKit/LayoutTests/external/wpt/bluetooth/service/getCharacteristics/characteristics-found-with-uuid.https.html
similarity index 84%
rename from third_party/WebKit/LayoutTests/bluetooth/service/getCharacteristics/characteristics-found-with-uuid.html
rename to third_party/WebKit/LayoutTests/external/wpt/bluetooth/service/getCharacteristics/characteristics-found-with-uuid.https.html
index d68dc63b..868476a8 100644
--- a/third_party/WebKit/LayoutTests/bluetooth/service/getCharacteristics/characteristics-found-with-uuid.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/bluetooth/service/getCharacteristics/characteristics-found-with-uuid.https.html
@@ -1,9 +1,9 @@
 <!DOCTYPE html>
-<script src="../../../resources/testharness.js"></script>
-<script src="../../../resources/testharnessreport.js"></script>
-<script src="../../../resources/testdriver.js"></script>
-<script src="../../../resources/testdriver-vendor.js"></script>
-<script src="../../../external/wpt/bluetooth/resources/bluetooth-helpers.js"></script>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver-vendor.js"></script>
+<script src="/bluetooth/resources/bluetooth-helpers.js"></script>
 <script>
 'use strict';
 bluetooth_test(() => {
diff --git a/third_party/WebKit/LayoutTests/bluetooth/service/getCharacteristics/characteristics-found.html b/third_party/WebKit/LayoutTests/external/wpt/bluetooth/service/getCharacteristics/characteristics-found.https.html
similarity index 84%
rename from third_party/WebKit/LayoutTests/bluetooth/service/getCharacteristics/characteristics-found.html
rename to third_party/WebKit/LayoutTests/external/wpt/bluetooth/service/getCharacteristics/characteristics-found.https.html
index d870479..b1b0fb4e 100644
--- a/third_party/WebKit/LayoutTests/bluetooth/service/getCharacteristics/characteristics-found.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/bluetooth/service/getCharacteristics/characteristics-found.https.html
@@ -1,9 +1,9 @@
 <!DOCTYPE html>
-<script src="../../../resources/testharness.js"></script>
-<script src="../../../resources/testharnessreport.js"></script>
-<script src="../../../resources/testdriver.js"></script>
-<script src="../../../resources/testdriver-vendor.js"></script>
-<script src="../../../external/wpt/bluetooth/resources/bluetooth-helpers.js"></script>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver-vendor.js"></script>
+<script src="/bluetooth/resources/bluetooth-helpers.js"></script>
 <script>
 'use strict';
 bluetooth_test(() => {
diff --git a/third_party/WebKit/LayoutTests/external/wpt/bluetooth/service/getCharacteristics/characteristics-not-found.https.html b/third_party/WebKit/LayoutTests/external/wpt/bluetooth/service/getCharacteristics/characteristics-not-found.https.html
new file mode 100644
index 0000000..f9c8efbf
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/bluetooth/service/getCharacteristics/characteristics-not-found.https.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver-vendor.js"></script>
+<script src="/bluetooth/resources/bluetooth-helpers.js"></script>
+<script>
+'use strict';
+bluetooth_test(() => {
+  return getEmptyHealthThermometerService()
+    .then(({service}) => assert_promise_rejects_with_message(
+      service.getCharacteristics(),
+      new DOMException('No Characteristics found in service.',
+                       'NotFoundError')))
+}, 'Request for absent characteristics. Reject with NotFoundError.');
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-display/display-contents-before-after-001.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-display/display-contents-before-after-001.html
index e6272da..65fc9fe 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/css-display/display-contents-before-after-001.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-display/display-contents-before-after-001.html
@@ -5,6 +5,8 @@
 <link rel="help" href="https://drafts.csswg.org/css-display-3/#valdef-display-contents">
 <link rel="match" href="display-contents-pass-ref.html">
 <style>
+    /* Disable kerning because kerning may differ for different node tree. */
+    html { font-kerning: none; font-feature-settings: "kern" off; }
     div { display: contents }
     .p::before { content: "P" }
     .a::before { content: "A" }
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-display/display-contents-before-after-002.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-display/display-contents-before-after-002.html
index 4c5947f..5860a73c 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/css-display/display-contents-before-after-002.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-display/display-contents-before-after-002.html
@@ -5,6 +5,8 @@
 <link rel="help" href="https://drafts.csswg.org/css-display-3/#valdef-display-contents">
 <link rel="match" href="display-contents-pass-ref.html">
 <style>
+    /* Disable kerning because kerning may differ for different node tree. */
+    html { font-kerning: none; font-feature-settings: "kern" off; }
     div::before {
         display: contents;
         border: 100px solid red;
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-display/display-contents-before-after-003.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-display/display-contents-before-after-003.html
index 772ad44..30451426 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/css-display/display-contents-before-after-003.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-display/display-contents-before-after-003.html
@@ -5,6 +5,8 @@
 <link rel="help" href="https://drafts.csswg.org/css-display-3/#valdef-display-contents">
 <link rel="match" href="display-contents-pass-ref.html">
 <style>
+    /* Disable kerning because kerning may differ for different node tree. */
+    html { font-kerning: none; font-feature-settings: "kern" off; }
     .flex { display: inline-flex; flex-direction: column }
     .flex::before { display: contents; content: "A" }
     .flex::after { display: contents; content: "S" }
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-display/display-contents-button.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-display/display-contents-button.html
index c166583..3711972 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/css-display/display-contents-button.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-display/display-contents-button.html
@@ -5,8 +5,11 @@
 <link rel="help" href="https://drafts.csswg.org/css-display/#unbox-html">
 <link rel="match" href="display-contents-pass-ref.html">
 <style>
+  /* Disable kerning because kerning may differ for different node tree. */
+  html { font-kerning: none; font-feature-settings: "kern" off; }
   button {
     all: initial;
+    font-kerning: none; font-feature-settings: "kern" off;
     border: 10px solid red;
     display: contents;
   }
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-display/display-contents-fieldset.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-display/display-contents-fieldset.html
index 5dcd343..f38a376 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/css-display/display-contents-fieldset.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-display/display-contents-fieldset.html
@@ -5,6 +5,8 @@
 <link rel="help" href="https://drafts.csswg.org/css-display/#unbox-html">
 <link rel="match" href="display-contents-pass-ref.html">
 <style>
+  /* Disable kerning because kerning may differ for different node tree. */
+  html { font-kerning: none; font-feature-settings: "kern" off; }
   fieldset, legend {
     all: initial;
     border: 10px solid red;
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-display/display-contents-pass-ref.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-display/display-contents-pass-ref.html
index de26e6d..82321b9 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/css-display/display-contents-pass-ref.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-display/display-contents-pass-ref.html
@@ -2,5 +2,9 @@
 <meta charset="utf-8">
 <title>CSS Reftest Reference</title>
 <link rel="author" title="Rune Lillesveen" href="mailto:rune@opera.com">
+<style>
+/* Disable kerning because kerning may differ for different node tree. */
+html { font-kerning: none; font-feature-settings: "kern" off; }
+</style>
 <p>You should see the word PASS below.</p>
-P<span>A</span>S<span>S</span>
+PASS
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-display/display-contents-td-001.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-display/display-contents-td-001.html
index 9867c0d..5585024a 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/css-display/display-contents-td-001.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-display/display-contents-td-001.html
@@ -5,6 +5,8 @@
 <link rel="help" href="https://drafts.csswg.org/css-display-3/#valdef-display-contents">
 <link rel="match" href="display-contents-pass-ref.html">
 <style>
+    /* Disable kerning because kerning may differ for different node tree. */
+    html { font-kerning: none; font-feature-settings: "kern" off; }
     td {
         display: contents;
         padding-right: 3em
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-display/display-contents-unusual-html-elements-none.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-display/display-contents-unusual-html-elements-none.html
index 403ff5c..53f5f9e5 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/css-display/display-contents-unusual-html-elements-none.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-display/display-contents-unusual-html-elements-none.html
@@ -5,6 +5,8 @@
 <link rel="help" href="https://drafts.csswg.org/css-display/#unbox-html">
 <link rel="match" href="display-contents-pass-ref.html">
 <style>
+  /* Disable kerning because kerning may differ for different node tree. */
+  html { font-kerning: none; font-feature-settings: "kern" off; }
   body { overflow: hidden }
   br, wbr, meter, progress, canvas, embed, object, audio, iframe, img, video,
   input, textarea, select {
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-multicol/multicol-fill-balance-002.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-multicol/multicol-fill-balance-002.html
new file mode 100644
index 0000000..fb6004d
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-multicol/multicol-fill-balance-002.html
@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<title>CSS Multi-column Layout Test: Balancing with more forced breaks than columns</title>
+<link rel="author" title="Morten Stenshorne" href="mstensho@chromium.org">
+<link rel="help" href="https://www.w3.org/TR/css-multicol-1/#cf" title="7.1. column-fill">
+<link rel="match" href="../reference/ref-filled-green-100px-square-only.html">
+<meta name="assert" content="This multicol container will create overflowing columns, no matter what, due to forced break. Don't overstretch.">
+<p>Test passes if there is a filled green square.</p>
+<div style="columns:2; column-gap:0; width:100px; background:green;">
+  <div style="height:100px;"></div>
+  <div style="break-before:column; height:90px;"></div>
+  <div style="break-before:column; height:10px;"></div>
+</div>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/encoding/big5-encoder-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/encoding/big5-encoder-expected.txt
new file mode 100644
index 0000000..af399bc
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/encoding/big5-encoder-expected.txt
@@ -0,0 +1,16 @@
+This is a testharness.js-based test.
+PASS big5 encoder: very basic
+FAIL big5 encoder: Highest-pointer BMP character excluded from encoder assert_equals: expected "X&%2340614;X" but got "X%26%2340614%3BX"
+FAIL big5 encoder: Highest-pointer character excluded from encoder assert_equals: expected "X&%23156267;X" but got "X%26%23156267%3BX"
+PASS big5 encoder: Lowest-pointer character included in encoder
+PASS big5 encoder: Euro; the highest-pointer character before a range of 30 unmapped pointers
+PASS big5 encoder: The lowest-pointer character after the range of 30 unmapped pointers
+PASS big5 encoder: The highest-pointer character before a range of 41 unmapped pointers
+PASS big5 encoder: The lowest-pointer character after the range of 41 unmapped pointers
+PASS big5 encoder: The last character in the index
+FAIL big5 encoder: The canonical BMP test character that is not in the index assert_equals: expected "X&%239731;X" but got "X%26%239731%3BX"
+FAIL big5 encoder: The canonical astral test character that is not in the index assert_equals: expected "X&%23128169;X" but got "X%26%23128169%3BX"
+PASS big5 encoder: A Plane 2 character whose low 16 bits match a BMP character that has a lower pointer
+PASS big5 encoder: A duplicate-mapped code point that prefers the highest pointer in the encoder
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/encoding/gbk-encoder-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/encoding/gbk-encoder-expected.txt
new file mode 100644
index 0000000..c4b35d1
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/encoding/gbk-encoder-expected.txt
@@ -0,0 +1,9 @@
+This is a testharness.js-based test.
+PASS gbk encoder: very basic
+PASS gbk encoder: Euro
+PASS gbk encoder: character
+PASS gbk encoder: PUA
+PASS gbk encoder: PUA #2
+FAIL gbk encoder: poo assert_equals: expected "&%23128169;" but got "%26%23128169%3B"
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/fetch/api/request/destination/fetch-destination.https-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/fetch/api/request/destination/fetch-destination.https-expected.txt
deleted file mode 100644
index b787d8df..0000000
--- a/third_party/WebKit/LayoutTests/external/wpt/fetch/api/request/destination/fetch-destination.https-expected.txt
+++ /dev/null
@@ -1,28 +0,0 @@
-This is a testharness.js-based test.
-PASS Initialize global state
-PASS HTMLImageElement fetches with an "image" Request.destination
-PASS HTMLImageElement with srcset attribute fetches with an "image" Request.destination
-PASS HTMLImageElement with a HTMLPictureElement parent attribute fetches with an "image" Request.destination
-PASS SVGImageElement fetches with an "image" Request.destination
-PASS fetch() fetches with an empty string Request.destination
-PASS XMLHttpRequest() fetches with an empty string Request.destination
-PASS EventSource() fetches with an empty string Request.destination
-FAIL HTMLAudioElement fetches with an "audio" Request.destination assert_unreached: Fetch errored. Reached unreachable code
-PASS HTMLVideoElement fetches with a "video" Request.destination
-PASS HTMLScriptElement fetches with a "script" Request.destination
-PASS HTMLLinkElement with rel=stylesheet fetches with a "style" Request.destination
-PASS HTMLLinkElement with rel=preload and as=fetch fetches with an empty string Request.destination
-PASS HTMLLinkElement with rel=preload and as=style fetches with a "style" Request.destination
-PASS HTMLLinkElement with rel=preload and as=script fetches with a "script" Request.destination
-PASS HTMLLinkElement with rel=preload and as=font fetches with a "font" Request.destination
-PASS HTMLLinkElement with rel=preload and as=image fetches with a "image" Request.destination
-FAIL HTMLLinkElement with rel=preload and as=audio fetches with a "audio" Request.destination assert_unreached: Fetch errored. Reached unreachable code
-PASS HTMLLinkElement with rel=preload and as=video fetches with a "video" Request.destination
-PASS HTMLLinkElement with rel=preload and as=track fetches with a "track" Request.destination
-PASS HTMLLinkElement with rel=preload and as=document fetches with a "document" Request.destination
-PASS HTMLLinkElement with rel=preload and as=worker fetches with a "worker" Request.destination
-PASS HTMLLinkElement with rel=preload and as=sharedworker fetches with a "sharedworker" Request.destination
-PASS HTMLLinkElement with rel=preload and as=xslt fetches with a "xslt" Request.destination
-PASS HTMLLinkElement with rel=preload and as=manifest fetches with a "manifest" Request.destination
-Harness: the test ran to completion.
-
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/track/track-element/track-change-event.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/track/track-element/track-change-event.html
new file mode 100644
index 0000000..679412647
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/track/track-element/track-change-event.html
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<title>A 'change' event is fired when a TextTrack's mode changes</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+async_test(function(t) {
+    var video = document.createElement('video');
+    var track = video.addTextTrack('subtitles', 'test', 'en');
+
+    // addTextTrack() defaults to "hidden", so settings
+    // mode to "showing" should trigger a "change" event.
+    track.mode = 'showing';
+    assert_equals(video.textTracks.length, 1);
+
+    video.textTracks.onchange = t.step_func_done(function() {
+        assert_equals(event.target, video.textTracks);
+        assert_true(event instanceof Event, 'instanceof');
+        assert_not_exists(event, 'track');
+    });
+});
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/track/track-element/track-css-cue-pseudo-class.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/track/track-element/track-css-cue-pseudo-class.html
new file mode 100644
index 0000000..d18f8b5
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/track/track-element/track-css-cue-pseudo-class.html
@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<style>
+:cue { color: red; }
+:cue(i) { color: red; }
+</style>
+<script>
+test(function() {
+  assert_equals(document.styleSheets[0].cssRules.length, 0);
+}, ":cue pseudo-class is not supported and dropped during parsing");
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/track/track-element/track-cue-negative-timestamp-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/track/track-element/track-cue-negative-timestamp-expected.txt
new file mode 100644
index 0000000..ed1f12e
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/track/track-element/track-cue-negative-timestamp-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL Negative timestamps assert_equals: expected 5 but got 4
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/track/track-element/track-cue-negative-timestamp.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/track/track-element/track-cue-negative-timestamp.html
new file mode 100644
index 0000000..c63d5506
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/track/track-element/track-cue-negative-timestamp.html
@@ -0,0 +1,34 @@
+<!DOCTYPE html>
+<title>Negative timestamps</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<video>
+    <track src="resources/settings.vtt" default>
+    <script>
+    async_test(function(t) {
+        var testTrack = document.querySelector("track");
+
+        testTrack.onload = t.step_func_done(function() {
+            assert_equals(testTrack.track.cues.length, 4);
+            // Add cue with negative startTime.
+            var cue = new VTTCue(-3439332606, 3.4, "Sausage?");
+            testTrack.track.addCue(cue);
+            assert_equals(testTrack.track.cues.length, 5);
+
+            // Add cue with negative startTime and negative endTime.
+            cue = new VTTCue(-110, -3.4, "Pepperoni?");
+            testTrack.track.addCue(cue);
+            assert_equals(testTrack.track.cues.length, 6);
+
+            // Set startTime and endTime to negative values.
+            var testCue = testTrack.track.cues[2];
+            assert_equals(testCue.startTime, 0);
+            testCue.startTime = -5;
+            assert_equals(testCue.startTime, -5);
+            assert_equals(testCue.endTime, 30.5);
+            testCue.endTime = -3439332606;
+            assert_equals(testCue.endTime, -3439332606);
+        });
+    });
+    </script>
+</video>
\ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/track/track-element/track-cue-rendering-empty-cue.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/track/track-element/track-cue-rendering-empty-cue.html
new file mode 100644
index 0000000..427189f
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/track/track-element/track-cue-rendering-empty-cue.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<title>Empty cues</title>
+<script src="/common/media.js"></script>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+async_test(function(t) {
+    var video = document.createElement("video");
+    video.src = getVideoURI("/media/test");
+    video.addTextTrack("captions", "regular captions track", "en");
+    video.textTracks[0].addCue(new VTTCue(0, 4, ""));
+
+    video.onplaying = t.step_func_done();
+    video.play();
+});
+</script>
\ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/track/track-element/track-default-attribute.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/track/track-element/track-default-attribute.html
new file mode 100644
index 0000000..3e8c547
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/track/track-element/track-default-attribute.html
@@ -0,0 +1,26 @@
+<!DOCTYPE html>
+<title>A track with the "default" attribute loads automatically</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<video>
+  <track kind="captions" src="resources/default-styles.vtt">
+  <track kind="captions" src="resources/metadata-area.vtt">
+  <track kind="captions" src="resources/webvtt-file.vtt" id="default" default>
+  <script>
+  async_test(function(t) {
+    var timer = null;
+    var tracks = document.querySelectorAll("track");
+    for (var track of tracks) {
+      track.onload = t.step_func(function() {
+        assert_equals(event.target.readyState, HTMLTrackElement.LOADED);
+        assert_equals(event.target.id, "default");
+        assert_true(event.target.default);
+        // End the test after a brief pause so we allow other tracks to load if they will.
+        if (timer)
+          clearTimeout(timer);
+        timer = t.step_timeout(t.step_func_done(), 200);
+      });
+    }
+  });
+  </script>
+</video>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/track/track-element/track-delete-during-setup.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/track/track-element/track-delete-during-setup.html
new file mode 100644
index 0000000..ce9f7333
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/track/track-element/track-delete-during-setup.html
@@ -0,0 +1,29 @@
+<!DOCTYPE html>
+<title>Track deletion during setup</title>
+<script src="/common/media.js"></script>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<video>
+    <track src="resources/metadata.vtt">
+</video>
+<script>
+async_test(function(t) {
+    var video = document.querySelector("video");
+    var track = document.querySelector("track");
+    t.step_timeout(function() {
+        video.parentNode.removeChild(video);
+    }, 61);
+
+    track.onload = t.step_func(function() {
+        var track2 = document.createElement("track");
+        video.appendChild(track2);
+        t.step_timeout(t.step_func_done(), 100);
+    });
+
+    assert_equals(track.readyState, HTMLTrackElement.NONE);
+    assert_equals(track.track.mode, "disabled");
+    track.track.mode = "hidden";
+
+    video.src = getVideoURI("/media/test");
+});
+</script>
diff --git a/third_party/WebKit/LayoutTests/media/track/vtt-cue-float-precision.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/track/track-element/vtt-cue-float-precision.html
similarity index 88%
rename from third_party/WebKit/LayoutTests/media/track/vtt-cue-float-precision.html
rename to third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/track/track-element/vtt-cue-float-precision.html
index 39b4d57..9cb58242 100644
--- a/third_party/WebKit/LayoutTests/media/track/vtt-cue-float-precision.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/track/track-element/vtt-cue-float-precision.html
@@ -1,7 +1,7 @@
 <!doctype html>
 <title>Float precision of VTTCue attributes line, position and size</title>
-<script src=../../resources/testharness.js></script>
-<script src=../../resources/testharnessreport.js></script>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
 <div id=log></div>
 <script>
 test(function() {
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/tabular-data/the-table-element/caption-methods.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/tabular-data/the-table-element/caption-methods.html
index 0f576ce..ec95eab 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/tabular-data/the-table-element/caption-methods.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/tabular-data/the-table-element/caption-methods.html
@@ -55,6 +55,33 @@
     </tr>
     </tbody>
   </table>
+  <table id="table10" style="display:none">
+    <tbody>
+    <tr>
+      <td>cell</td>
+      <td>cell</td>
+    </tr>
+    </tbody>
+    <caption>caption 10</caption>
+  </table>
+  <table id="table11" style="display:none">
+    <caption id="caption11">caption 11</caption>
+  </table>
+  <table id="table12" style="display:none">
+    <caption>caption 1</caption>
+    <caption>caption 2</caption>
+  </table>
+  <table id="table13" style="display:none">
+  </table>
+  <table id="table14" style="display:none">
+    <tbody>
+    <tr>
+      <td>cell</td>
+      <td>cell</td>
+    </tr>
+    </tbody>
+    <caption id="caption14">caption 14</caption>
+  </table>
   <script>
     test(function () {
       var table0 = document.getElementById('table0');
@@ -158,6 +185,92 @@
         table9.caption = caption;
       });
     }, "Assigning a foreign caption to table.caption")
+
+    test(function() {
+      var table = document.createElement("table");
+      var caption = document.createElement("caption");
+      caption.innerHTML = "new caption";
+      table.caption = caption;
+
+      assert_equals(caption.parentNode, table);
+      assert_equals(table.firstChild, caption);
+      assert_equals(table.caption.innerHTML, "new caption");
+    }, "Set table.caption when the table doesn't already have a caption")
+
+    test(function() {
+      var table10 = document.getElementById("table10");
+      var caption = document.createElement("caption");
+      caption.innerHTML = "new caption";
+      table10.caption = caption;
+
+      assert_equals(caption.parentNode, table10);
+      assert_equals(table10.firstChild, caption);
+      assert_equals(table10.caption.innerHTML, "new caption");
+
+      var captions = table10.getElementsByTagName('caption');
+      assert_equals(captions.length, 1);
+    }, "Set table.caption when the table has a caption child but with other siblings before it")
+
+    test(function() {
+      var table11 = document.getElementById("table11");
+      var caption = document.createElement("caption");
+      caption.innerHTML = "new caption";
+      table11.caption = caption;
+
+      assert_equals(caption.parentNode, table11);
+      assert_equals(table11.firstChild, caption);
+      assert_equals(table11.caption.innerHTML, "new caption");
+
+      var captions = table11.getElementsByTagName('caption');
+      assert_equals(captions.length, 1);
+    }, "Set table.caption when the table has a caption descendant")
+
+    test(function() {
+      var table12 = document.getElementById("table12");
+      var caption = document.createElement("caption");
+      caption.innerHTML = "new caption";
+      table12.caption = caption;
+
+      assert_equals(caption.parentNode, table12);
+      assert_equals(table12.firstChild, caption);
+      assert_equals(table12.caption.innerHTML, "new caption");
+
+      var captions = table12.getElementsByTagName('caption');
+      assert_equals(captions.length, 2);
+      assert_equals(captions[0].innerHTML, "new caption");
+      assert_equals(captions[1].innerHTML, "caption 2");
+    }, "Set table.caption when the table has two caption children")
+
+    promise_test(async t => {
+      var table13 = document.getElementById("table13");
+      var iframe = document.createElement("iframe");
+      iframe.srcdoc = '<table><caption id="caption13">caption 13</caption></table>';
+      document.body.appendChild(iframe);
+
+      var iframeWatcher = new EventWatcher(t, iframe, "load");
+      await iframeWatcher.wait_for("load");
+      var caption = iframe.contentWindow.document.getElementById("caption13");
+      table13.caption = caption;
+
+      assert_equals(caption.parentNode, table13);
+      assert_equals(table13.firstChild, caption);
+      assert_equals(table13.caption.innerHTML, "caption 13");
+
+      var captions = table13.getElementsByTagName('caption');
+      assert_equals(captions.length, 1);
+    }, "Assigning a caption has a different owner document to table.caption")
+
+    test(function() {
+      var table14 = document.getElementById("table14");
+      var caption = document.getElementById("caption14");
+      table14.caption = caption;
+
+      assert_equals(caption.parentNode, table14);
+      assert_equals(table14.firstChild, caption);
+
+      var captions = table14.getElementsByTagName('caption');
+      assert_equals(captions.length, 1);
+    }, "Assigning the caption already in the table to table.caption")
   </script>
 </body>
 </html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/navigator/device-memory.https.any.js b/third_party/WebKit/LayoutTests/external/wpt/navigator/device-memory.https.any.js
new file mode 100644
index 0000000..8f81ffc
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/navigator/device-memory.https.any.js
@@ -0,0 +1,8 @@
+test(function() {
+    assert_equals(typeof navigator.deviceMemory, "number",
+        "navigator.deviceMemory returns a number");
+    assert_true(navigator.deviceMemory >= 0,
+        "navigator.deviceMemory returns a positive value");
+    assert_true([0.25, 0.5, 1, 2, 4, 8].includes(navigator.deviceMemory),
+        "navigator.deviceMemory returns a power of 2 between 0.25 and 8");
+}, "navigator.deviceMemory is a positive number, a power of 2, between 0.25 and 8");
\ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/external/wpt/pointerevents/pointerevent_fractional_coordinates-manual.html b/third_party/WebKit/LayoutTests/external/wpt/pointerevents/pointerevent_fractional_coordinates-manual.html
new file mode 100644
index 0000000..e0e2fdcd
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/pointerevents/pointerevent_fractional_coordinates-manual.html
@@ -0,0 +1,98 @@
+<!doctype html>
+<html>
+    <head>
+        <title>Pointer Events coordinates can have fractional value<</title>
+        <meta name="viewport" content="width=device-width">
+        <link rel="stylesheet" type="text/css" href="pointerevent_styles.css">
+        <script src="/resources/testharness.js"></script>
+        <script src="/resources/testharnessreport.js"></script>
+        <script type="text/javascript" src="pointerevent_support.js"></script>
+        <style>
+            #innerFrame {
+                transform: scale(5);
+                width: 60px;
+                height: 60px;
+                margin-left: 120px;
+                margin-top: 120px;
+                border: 0.01px solid black;
+            }
+        </style>
+        <script>
+            var eventList = [
+                  "pointerdown",
+                  "pointerup",
+                  "pointermove",
+                  "pointerover",
+                  "pointerout",
+                  "pointerenter",
+                  "pointerleave"];
+            var eventsRecieved = {};
+            var clickedTargetList = [];
+
+            function resetTestState() {
+                eventsRecieved = {};
+                clickedTargetList = [];
+                ['s1', 's2', 's3'].forEach(function(id){
+                    var target = document.getElementById('innerFrame').contentDocument.getElementById(id);
+                    target.style.background = "black"
+                });
+            }
+
+            function checkPointerEventCoordinates(event) {
+              if (event.clientX != Math.floor(event.clientX) || event.clientY != Math.floor(event.clientY))
+                eventsRecieved[event.type] = true;
+            }
+
+            function run() {
+                var test_pointerEvent = setup_pointerevent_test("pointerevent events in capturing", ALL_POINTERS);
+                var innerFrame = document.getElementById('innerFrame');
+                var innerDocument = innerFrame.contentDocument;
+                ['s1', 's2', 's3'].forEach(function(id){
+                    var target = innerDocument.getElementById(id);
+                    eventList.forEach(function(eventName) {
+                        on_event(target, eventName, checkPointerEventCoordinates);
+                    });
+
+                    on_event(target, "click", function (event) {
+                      if (!(event.target.id in clickedTargetList)) {
+                          clickedTargetList.push(event.target.id);
+                          event.target.style.background = "red"
+                      }
+                      if (clickedTargetList.length == 3) {
+                          test(function () {
+                              if (Object.keys(eventsRecieved).length != eventList.length){
+                                  eventList.forEach(function(eventName){
+                                     assert_true(eventName in eventsRecieved, eventName + " should have fractional coordinates");
+                                  });
+                              }
+                          }, expectedPointerType);
+                          test_pointerEvent.done();
+                      }
+                    });
+                });
+            }
+        </script>
+    </head>
+    <body onload="run()">
+        <h1>Pointer Events coordinates support fractional value</h1>
+        <h2 id="pointerTypeDescription"></h2>
+        <h4>
+            Test Description: This test checks pointer events has fractional client coordinates
+            <ol>
+                 <li>Move your pointer over one black square</li>
+                 <li>Press down the pointer (i.e. press left button with mouse or touch the screen with finger or pen).</li>
+                 <li>Release the pointer.</li>
+                 <li>Move to next black square and repreat 2 and 3</li>
+            </ol>
+
+            Test passes if pointer events has fractional coordinates.
+        </h4>
+        <iframe id=innerFrame src="resources/pointerevent_fractional_coordinates-iframe.html"></iframe>
+        <div id="complete-notice">
+            <p>The following pointer types were detected: <span id="pointertype-log"></span>.</p>
+            <p>Refresh the page to run the tests again with a different pointer type.</p>
+        </div>
+        <div id="log"></div>
+    </body>
+</html>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/pointerevents/resources/pointerevent_fractional_coordinates-iframe.html b/third_party/WebKit/LayoutTests/external/wpt/pointerevents/resources/pointerevent_fractional_coordinates-iframe.html
new file mode 100644
index 0000000..5245a3f
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/pointerevents/resources/pointerevent_fractional_coordinates-iframe.html
@@ -0,0 +1,32 @@
+<!doctype html>
+<html>
+    <head>
+        <meta name="viewport" content="width=device-width">
+        <link rel="stylesheet" type="text/css" href="../pointerevent_styles.css">
+    </head>
+    <style>
+        .square {
+            width: 3px;
+            height:3px;
+            background: black;
+            cursor: pointer;
+        }
+        #s1 {
+            top: 10px;
+            left: 10px;
+        }
+        #s2 {
+            top: 30px;
+            left: 50px;
+        }
+        #s3 {
+            top: 50px;
+            left: 30px;
+        }
+    </style>
+    <body>
+        <div id="s1" class="square"></div>
+        <div id="s2" class="square"></div>
+        <div id="s3" class="square"></div>
+    </body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/xhr/open-url-encoding-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/xhr/open-url-encoding-expected.txt
new file mode 100644
index 0000000..ba9f4c4f
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/xhr/open-url-encoding-expected.txt
@@ -0,0 +1,5 @@
+This is a testharness.js-based test.
+PASS percent encode characters
+FAIL lone surrogate assert_equals: expected "&%2365533;" but got "%26%2365533%3B"
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt_automation/pointerevents/pointerevent_fractional_coordinates-manual-automation.js b/third_party/WebKit/LayoutTests/external/wpt_automation/pointerevents/pointerevent_fractional_coordinates-manual-automation.js
new file mode 100644
index 0000000..367733c
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt_automation/pointerevents/pointerevent_fractional_coordinates-manual-automation.js
@@ -0,0 +1,58 @@
+importAutomationScript('/pointerevents/pointerevent_common_input.js');
+const scale = 5;
+const width = 3;
+const height = 3;
+function inject_input() {
+  return testInputType("mouse").then(function() {
+    return testInputType("touch");
+  }).then(function() {
+    return testInputType("pen");
+  });
+}
+
+function testInputType(inputSource) {
+  var targetFrame = document.querySelector('#innerFrame');
+  var frameRect = targetFrame.getBoundingClientRect();
+  frameLeft = frameRect.left;
+  frameTop = frameRect.top;
+
+  target = [{x: 10, y: 10}, {x: 30, y: 50}, {x: 50, y: 30}]
+  xPosition = []
+  yPosition = []
+  for (var i = 0; i < target.length; i++) {
+    xPosition.push((target[i].x + width / 2.0) * scale + frameLeft);
+    yPosition.push((target[i].y + height / 2.0) * scale + frameTop);
+  }
+  return sendInputAt(inputSource, xPosition[0], yPosition[0]).then(function() {
+    return sendInputAt(inputSource, xPosition[1], yPosition[1]);
+  }).then(function() {
+    return sendInputAt(inputSource, xPosition[2], yPosition[2]);
+  });
+
+}
+
+function sendInputAt(inputSource, xPosition, yPosition) {
+  if (inputSource == "touch") {
+    pointerActions = [{name: 'pointerDown', x: xPosition, y: yPosition},
+                      {name: 'pointerMove', x: xPosition + 1, y: yPosition + 1},
+                      {name: 'pointerUp'}]
+  }
+  else {
+    pointerActions = [{name: 'pointerMove', x: xPosition, y: yPosition},
+                      {name: 'pointerDown', x: xPosition, y: yPosition},
+                      {name: 'pointerUp'}]
+  }
+
+  return new Promise(function(resolve, reject) {
+    if (window.chrome && chrome.gpuBenchmarking) {
+      chrome.gpuBenchmarking.pointerActionSequence(
+          [{
+            source: inputSource,
+            actions: pointerActions
+          }],
+          resolve);
+    } else {
+      reject();
+    }
+  });
+}
diff --git a/third_party/WebKit/LayoutTests/fast/backgrounds/size/contain-and-cover-zoomed-expected.png b/third_party/WebKit/LayoutTests/fast/backgrounds/size/contain-and-cover-zoomed-expected.png
index ce608f7..d5610a8 100644
--- a/third_party/WebKit/LayoutTests/fast/backgrounds/size/contain-and-cover-zoomed-expected.png
+++ b/third_party/WebKit/LayoutTests/fast/backgrounds/size/contain-and-cover-zoomed-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/fast/block/block-image-becomes-float-expected.html b/third_party/WebKit/LayoutTests/fast/block/block-image-becomes-float-expected.html
index 7ad8ebb..029fa941 100644
--- a/third_party/WebKit/LayoutTests/fast/block/block-image-becomes-float-expected.html
+++ b/third_party/WebKit/LayoutTests/fast/block/block-image-becomes-float-expected.html
@@ -1,3 +1,7 @@
 <!DOCTYPE html>
+<style>
+/* Disable kerning because kerning may differ for different node tree. */
+html { font-kerning: none; }
+</style>
 <p>The word "PASS" should be seen below.</p>
 <div style="margin-left:10em;">P<span></span>ASS</div>
diff --git a/third_party/WebKit/LayoutTests/fast/block/block-image-becomes-float.html b/third_party/WebKit/LayoutTests/fast/block/block-image-becomes-float.html
index b22cad9a..4cb7b4a 100644
--- a/third_party/WebKit/LayoutTests/fast/block/block-image-becomes-float.html
+++ b/third_party/WebKit/LayoutTests/fast/block/block-image-becomes-float.html
@@ -1,5 +1,7 @@
 <!DOCTYPE html>
 <style>
+    /* Disable kerning because kerning may differ for different node tree. */
+    html { font-kerning: none; }
     #elm { display:block; width:10em; height:10em; visibility:hidden; }
 </style>
 <p>The word "PASS" should be seen below.</p>
diff --git a/third_party/WebKit/LayoutTests/fast/dom/navigator-deviceMemory.https-expected.txt b/third_party/WebKit/LayoutTests/fast/dom/navigator-deviceMemory.https-expected.txt
deleted file mode 100644
index 7c94b3b4..0000000
--- a/third_party/WebKit/LayoutTests/fast/dom/navigator-deviceMemory.https-expected.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-Tests for navigator.deviceMemory:
-
-navigator.deviceMemory should be a positive value: true
-navigator.deviceMemory should have only the most 2 significant bits are set in MB: true
diff --git a/third_party/WebKit/LayoutTests/fast/dom/navigator-deviceMemory.https.html b/third_party/WebKit/LayoutTests/fast/dom/navigator-deviceMemory.https.html
deleted file mode 100644
index 1081831..0000000
--- a/third_party/WebKit/LayoutTests/fast/dom/navigator-deviceMemory.https.html
+++ /dev/null
@@ -1,18 +0,0 @@
-<html>
-<body>
-<p>Tests for <a href="https://github.com/w3c/device-memory#the-web-exposed-api">navigator.deviceMemory</a>:</p>
-<script>
-    if (window.testRunner)
-        testRunner.dumpAsText();
-
-    var deviceMemory = navigator.deviceMemory;
-
-    document.write("navigator.deviceMemory should be a positive value: " + (deviceMemory >= 0) + "<br>");
-    var deviceMemoryInMB = deviceMemory * 1024.0;
-    while ((deviceMemoryInMB % 2) == 0) {
-      deviceMemoryInMB = deviceMemoryInMB / 2;
-    }
-    document.write("navigator.deviceMemory should have only the most 2 significant bits are set in MB: " + (deviceMemoryInMB < 4));
-</script>
-</body>
-</html>
diff --git a/third_party/WebKit/LayoutTests/fast/inline/do-not-detach-whitespace-with-out-of-flow-siblings-inside-inline-parent-expected.html b/third_party/WebKit/LayoutTests/fast/inline/do-not-detach-whitespace-with-out-of-flow-siblings-inside-inline-parent-expected.html
index 8398f3c9..bcfc0f61 100644
--- a/third_party/WebKit/LayoutTests/fast/inline/do-not-detach-whitespace-with-out-of-flow-siblings-inside-inline-parent-expected.html
+++ b/third_party/WebKit/LayoutTests/fast/inline/do-not-detach-whitespace-with-out-of-flow-siblings-inside-inline-parent-expected.html
@@ -1,4 +1,8 @@
 <!DOCTYPE html>
+<style>
+/* Disable kerning because kerning may differ for different node tree. */
+html { font-kerning: none; }
+</style>
 <body>
 <span>
     <span>A</span>
diff --git a/third_party/WebKit/LayoutTests/fast/inline/do-not-detach-whitespace-with-out-of-flow-siblings-inside-inline-parent.html b/third_party/WebKit/LayoutTests/fast/inline/do-not-detach-whitespace-with-out-of-flow-siblings-inside-inline-parent.html
index 57ece17..43c7dd31 100644
--- a/third_party/WebKit/LayoutTests/fast/inline/do-not-detach-whitespace-with-out-of-flow-siblings-inside-inline-parent.html
+++ b/third_party/WebKit/LayoutTests/fast/inline/do-not-detach-whitespace-with-out-of-flow-siblings-inside-inline-parent.html
@@ -1,4 +1,8 @@
 <!DOCTYPE html>
+<style>
+/* Disable kerning because kerning may differ for different node tree. */
+html { font-kerning: none; }
+</style>
 <body>
 <span>
     <span id="A">A</span>
diff --git a/third_party/WebKit/LayoutTests/fast/url/query-expected.txt b/third_party/WebKit/LayoutTests/fast/url/query-expected.txt
index 54e43826..e4816a5 100644
--- a/third_party/WebKit/LayoutTests/fast/url/query-expected.txt
+++ b/third_party/WebKit/LayoutTests/fast/url/query-expected.txt
@@ -7,8 +7,8 @@
 PASS canonicalize('http://www.example.com/?as?df') is 'http://www.example.com/?as?df'
 PASS canonicalize('http://www.example.com/?\x02hello bye') is 'http://www.example.com/?%02hello%7F%20bye'
 PASS canonicalize('http://www.example.com/?%40%41123') is 'http://www.example.com/?%40%41123'
-PASS canonicalize('http://www.example.com/?q=你好') is 'http://www.example.com/?q=&%2320320;&%2322909;'
-PASS canonicalize('http://www.example.com/?q=\ud800\ud800') is 'http://www.example.com/?q=&%2355296;&%2355296;'
+PASS canonicalize('http://www.example.com/?q=你好') is 'http://www.example.com/?q=%26%2320320%3B%26%2322909%3B'
+PASS canonicalize('http://www.example.com/?q=\ud800\ud800') is 'http://www.example.com/?q=%26%2355296%3B%26%2355296%3B'
 PASS canonicalize('http://www.example.com/?q=<asdf>') is 'http://www.example.com/?q=%3Casdf%3E'
 PASS canonicalize('http://www.example.com/?q="asdf"') is 'http://www.example.com/?q=%22asdf%22'
 PASS successfullyParsed is true
diff --git a/third_party/WebKit/LayoutTests/fast/url/script-tests/query.js b/third_party/WebKit/LayoutTests/fast/url/script-tests/query.js
index 0f3c153..dcb6028 100644
--- a/third_party/WebKit/LayoutTests/fast/url/script-tests/query.js
+++ b/third_party/WebKit/LayoutTests/fast/url/script-tests/query.js
@@ -12,9 +12,9 @@
   ["\\x02hello\x7f bye", "%02hello%7F%20bye"],
   ["%40%41123", "%40%41123"],
   // Chinese input/output
-  ["q=\u4F60\u597D", "q=&%2320320;&%2322909;"],
+  ["q=\u4F60\u597D", "q=%26%2320320%3B%26%2322909%3B"],
   // Invalid UTF-8/16 input should be replaced with invalid characters.
-  ["q=\\ud800\\ud800", "q=&%2355296;&%2355296;"],
+  ["q=\\ud800\\ud800", "q=%26%2355296%3B%26%2355296%3B"],
   // Don't allow < or > because sometimes they are used for XSS if the
   // URL is echoed in content. Firefox does this, IE doesn't.
   ["q=<asdf>", "q=%3Casdf%3E"],
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/mixedContent/insecure-audio-video-in-main-frame-expected.txt b/third_party/WebKit/LayoutTests/http/tests/security/mixedContent/insecure-audio-video-in-main-frame-expected.txt
index c0c088a8..0dfdd42 100644
--- a/third_party/WebKit/LayoutTests/http/tests/security/mixedContent/insecure-audio-video-in-main-frame-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/security/mixedContent/insecure-audio-video-in-main-frame-expected.txt
@@ -1,3 +1,3 @@
-CONSOLE WARNING: Mixed Content: The page at 'https://127.0.0.1:8443/security/mixedContent/resources/frame-with-insecure-audio-video.html' was loaded over HTTPS, but requested an insecure video 'http://example.test:8080/resources/test.mp4'. This content should also be served over HTTPS.
+CONSOLE WARNING: Mixed Content: The page at 'https://127.0.0.1:8443/security/mixedContent/resources/frame-with-insecure-audio-video.html' was loaded over HTTPS, but requested an insecure audio file 'http://example.test:8080/resources/test.mp4'. This content should also be served over HTTPS.
 CONSOLE WARNING: Mixed Content: The page at 'https://127.0.0.1:8443/security/mixedContent/resources/frame-with-insecure-audio-video.html' was loaded over HTTPS, but requested an insecure video 'http://example.test:8080/resources/test.mp4'. This content should also be served over HTTPS.
 This test opens a window that loads insecure HTML5 audio and video. We should trigger a mixed content callback because the main frame in the window is HTTPS but is displaying insecure content.
diff --git a/third_party/WebKit/LayoutTests/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt b/third_party/WebKit/LayoutTests/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt
index 36fe8d6f..73fa9a2 100644
--- a/third_party/WebKit/LayoutTests/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt
@@ -2560,6 +2560,7 @@
     getter appVersion
     getter budget
     getter connection
+    getter deviceMemory
     getter hardwareConcurrency
     getter locks
     getter onLine
diff --git a/third_party/WebKit/LayoutTests/http/tests/uri/escaped-entity-expected.txt b/third_party/WebKit/LayoutTests/http/tests/uri/escaped-entity-expected.txt
index 6ac700b..251d339 100644
--- a/third_party/WebKit/LayoutTests/http/tests/uri/escaped-entity-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/uri/escaped-entity-expected.txt
@@ -2,9 +2,9 @@
 
 Note that this exact page won't work in IE or Firefox. Firefox seems to always use UTF-8 for local files, and IE actually preserves the Unicode in the URL when we get it from JS, so we don't know what would get sent over the wire. However, both browsers will send %26%231758%3B over HTTP for the query.
 
-"/uri/intercept/print/script.js?&%231758;" (no target charset specified, should be Big5)
-"/uri/intercept/print/script.js?&%231758;" (Big5 specified)
+"/uri/intercept/print/script.js?%26%231758%3B" (no target charset specified, should be Big5)
+"/uri/intercept/print/script.js?%26%231758%3B" (Big5 specified)
 Show the source attribute of the scripts.
-"http://127.0.0.1:8000/uri/intercept/print/script.js?&%231758;"
-"http://127.0.0.1:8000/uri/intercept/print/script.js?&%231758;"
+"http://127.0.0.1:8000/uri/intercept/print/script.js?%26%231758%3B"
+"http://127.0.0.1:8000/uri/intercept/print/script.js?%26%231758%3B"
 
diff --git a/third_party/WebKit/LayoutTests/media/track/track-change-event.html b/third_party/WebKit/LayoutTests/media/track/track-change-event.html
deleted file mode 100644
index f08f6ef..0000000
--- a/third_party/WebKit/LayoutTests/media/track/track-change-event.html
+++ /dev/null
@@ -1,21 +0,0 @@
-<!DOCTYPE html>
-<title>Tests that the 'change' event is fired when a TextTrack's mode changes.</title>
-<script src="../../resources/testharness.js"></script>
-<script src="../../resources/testharnessreport.js"></script>
-<script>
-async_test(function(t) {
-    var video = document.createElement('video');
-    var track = video.addTextTrack('subtitles', 'test', 'en');
-
-    // addTextTrack() defaults to "hidden", so "showing"
-    // should trigger a "change" event.
-    track.mode = 'showing';
-    assert_equals(video.textTracks.length, 1);
-
-    video.textTracks.onchange = t.step_func_done(function() {
-        assert_equals(event.target, video.textTracks);
-        assert_true(event instanceof Event, 'instanceof');
-        assert_equals(event.track, undefined);
-    });
-});
-</script>
diff --git a/third_party/WebKit/LayoutTests/media/track/track-css-cue-pseudo-class.html b/third_party/WebKit/LayoutTests/media/track/track-css-cue-pseudo-class.html
deleted file mode 100644
index bea7ab1..0000000
--- a/third_party/WebKit/LayoutTests/media/track/track-css-cue-pseudo-class.html
+++ /dev/null
@@ -1,12 +0,0 @@
-<!DOCTYPE html>
-<script src="../../resources/testharness.js"></script>
-<script src="../../resources/testharnessreport.js"></script>
-<style>
-:cue { color: red; }
-:cue(i) { color: red; }
-</style>
-<script>
-test(function() {
-  assert_equals(document.styleSheets[0].rules.length, 0);
-}, ":cue pseudo-class is not supported and dropped during parsing");
-</script>
diff --git a/third_party/WebKit/LayoutTests/media/track/track-cue-negative-timestamp.html b/third_party/WebKit/LayoutTests/media/track/track-cue-negative-timestamp.html
deleted file mode 100644
index 05fa383c..0000000
--- a/third_party/WebKit/LayoutTests/media/track/track-cue-negative-timestamp.html
+++ /dev/null
@@ -1,34 +0,0 @@
-<!DOCTYPE html>
-<title>Tests negative timestamps.</title>
-<script src="../../resources/testharness.js"></script>
-<script src="../../resources/testharnessreport.js"></script>
-<video>
-    <track id="testTrack" src="captions-webvtt/tc013-settings.vtt" default>
-</video>
-<script>
-async_test(function(t) {
-    var track = document.querySelector("track");
-
-    track.onload = t.step_func_done(function() {
-        // Test that cues with negative startTime are not added.
-        assert_equals(testTrack.track.cues.length, 4);
-        textCue = new VTTCue(-3439332606, 3.4, "Sausage?");
-        testTrack.track.addCue(textCue);
-        assert_equals(testTrack.track.cues.length, 4);
-
-        // Test that cues with negative startTime and negative endTime are not added.
-        assert_equals(testTrack.track.cues.length, 4);
-        textCue = new VTTCue(-110, -3.4, "Pepperoni?");
-        testTrack.track.addCue(textCue);
-        assert_equals(testTrack.track.cues.length, 4);
-
-        // Test that setting startTime and endTime to negative values does not affect the value.
-        assert_equals(testTrack.track.cues[3].startTime, 121);
-        testTrack.track.cues[3].startTime = -5;
-        assert_equals(testTrack.track.cues[3].startTime, 121);
-        assert_equals(testTrack.track.cues[3].endTime, 361200.5);
-        testTrack.track.cues[3].endTime = -3439332606;
-        assert_equals(testTrack.track.cues[3].endTime, 361200.5);
-    });
-});
-</script>
\ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/media/track/track-cue-rendering-empty-cue-crash.html b/third_party/WebKit/LayoutTests/media/track/track-cue-rendering-empty-cue-crash.html
deleted file mode 100644
index 2f29c82a..0000000
--- a/third_party/WebKit/LayoutTests/media/track/track-cue-rendering-empty-cue-crash.html
+++ /dev/null
@@ -1,14 +0,0 @@
-<!DOCTYPE html>
-<title>Tests that having empty cues does not crash the browser.</title>
-<script src="../media-file.js"></script>
-<script src="../../resources/testharness.js"></script>
-<script src="../../resources/testharnessreport.js"></script>
-<script>
-test(function() {
-    var video = document.createElement("video");
-    video.src = findMediaFile("video", "../content/test");
-    video.addTextTrack("captions", "regular captions track", "en");
-    video.textTracks[0].addCue(new VTTCue(0, 4, ""));
-    video.play();
-});
-</script>
\ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/media/track/track-default-attribute.html b/third_party/WebKit/LayoutTests/media/track/track-default-attribute.html
deleted file mode 100644
index 6e30d04..0000000
--- a/third_party/WebKit/LayoutTests/media/track/track-default-attribute.html
+++ /dev/null
@@ -1,26 +0,0 @@
-<!DOCTYPE html>
-<title>Tests that a track with the "default" attribute loads automatically.</title>
-<script src="../../resources/testharness.js"></script>
-<script src="../../resources/testharnessreport.js"></script>
-<video>
-  <track kind="captions" src="captions-webvtt/tc005-default-styles.vtt">
-  <track kind="captions" src="captions-webvtt/tc005-metadata-area.vtt">
-  <track default kind="captions" src="captions-webvtt/tc004-webvtt-file.vtt" id="default">
-  <script>
-  async_test(function(t) {
-    var timer = null;
-    var tracks = document.querySelectorAll("track");
-    for (var track of tracks) {
-      track.onload = t.step_func(function() {
-        assert_equals(event.target.readyState, HTMLTrackElement.LOADED);
-        assert_equals(event.target.id, "default");
-        assert_true(event.target.default);
-        // End the test after a brief pause so we allow other tracks to load if they will.
-        if (timer)
-          clearTimeout(timer);
-        timer = t.step_timeout(t.step_func_done(), 200);
-      });
-    }
-  });
-  </script>
-</video>
diff --git a/third_party/WebKit/LayoutTests/media/track/track-delete-during-setup.html b/third_party/WebKit/LayoutTests/media/track/track-delete-during-setup.html
deleted file mode 100644
index 93e5763..0000000
--- a/third_party/WebKit/LayoutTests/media/track/track-delete-during-setup.html
+++ /dev/null
@@ -1,29 +0,0 @@
-<!DOCTYPE html>
-<title>Tests track deletion during setup.</title>
-<script src="../../resources/testharness.js"></script>
-<script src="../../resources/testharnessreport.js"></script>
-<script src="../media-file.js"></script>
-<video>
-    <track src="captions-webvtt/metadata.vtt">
-</video>
-<script>
-async_test(function(t) {
-    var video = document.querySelector("video");
-    var track = document.querySelector("track");
-    setTimeout(function() {
-        video.parentNode.removeChild(video);
-    }, 61);
-
-    track.onload = t.step_func(function() {
-        var track2 = document.createElement("track");
-        video.appendChild(track2);
-        setTimeout(function() { t.done(); }, 100);
-    });
-
-    assert_equals(track.readyState, HTMLTrackElement.NONE);
-    assert_equals(track.track.mode, "disabled");
-    track.track.mode = "hidden";
-
-    video.src = findMediaFile("video", "../content/test");
-});
-</script>
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/gradients/list-item-gradient-expected.png b/third_party/WebKit/LayoutTests/platform/linux/fast/gradients/list-item-gradient-expected.png
index 1ff439c..5368a89 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/fast/gradients/list-item-gradient-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/fast/gradients/list-item-gradient-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/css3/masking/mask-repeat-space-border-expected.png b/third_party/WebKit/LayoutTests/platform/mac/css3/masking/mask-repeat-space-border-expected.png
index f5dca37..625f491 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/css3/masking/mask-repeat-space-border-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/css3/masking/mask-repeat-space-border-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/gradients/list-item-gradient-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/gradients/list-item-gradient-expected.png
index 08bb7ff..ab08c211 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/fast/gradients/list-item-gradient-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/fast/gradients/list-item-gradient-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/gradients/unprefixed-list-item-gradient-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/gradients/unprefixed-list-item-gradient-expected.png
index b8c3d38b6..82a6ee9 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/fast/gradients/unprefixed-list-item-gradient-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/fast/gradients/unprefixed-list-item-gradient-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/images/color-profile-background-image-cross-fade-expected.png b/third_party/WebKit/LayoutTests/platform/mac/images/color-profile-background-image-cross-fade-expected.png
index 5827ab7d..730f5689 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/images/color-profile-background-image-cross-fade-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/images/color-profile-background-image-cross-fade-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/images/color-profile-background-image-cross-fade-png-expected.png b/third_party/WebKit/LayoutTests/platform/mac/images/color-profile-background-image-cross-fade-png-expected.png
index 5827ab7d..730f5689 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/images/color-profile-background-image-cross-fade-png-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/images/color-profile-background-image-cross-fade-png-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/images/cross-fade-background-size-expected.png b/third_party/WebKit/LayoutTests/platform/mac/images/cross-fade-background-size-expected.png
index 3359ed2..3f6fe1a 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/images/cross-fade-background-size-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/images/cross-fade-background-size-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/zoom/page/zoom-background-images-expected.png b/third_party/WebKit/LayoutTests/platform/mac/svg/zoom/page/zoom-background-images-expected.png
index c7dbfe1a..1811f35 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/svg/zoom/page/zoom-background-images-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/zoom/page/zoom-background-images-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/color-profile-background-image-cross-fade-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/color-profile-background-image-cross-fade-expected.png
index 2f53777e3..b98803b 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/color-profile-background-image-cross-fade-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/color-profile-background-image-cross-fade-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/color-profile-background-image-cross-fade-png-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/color-profile-background-image-cross-fade-png-expected.png
index 2f53777e3..b98803b 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/color-profile-background-image-cross-fade-png-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/color-profile-background-image-cross-fade-png-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/cross-fade-background-size-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/cross-fade-background-size-expected.png
index 900c4f1b..e94caa5 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/cross-fade-background-size-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/exotic-color-space/images/cross-fade-background-size-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/color-profile-background-image-cross-fade-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/color-profile-background-image-cross-fade-expected.png
index e519e09..104254f 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/color-profile-background-image-cross-fade-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/color-profile-background-image-cross-fade-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/color-profile-background-image-cross-fade-png-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/color-profile-background-image-cross-fade-png-expected.png
index e519e09..104254f 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/color-profile-background-image-cross-fade-png-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/color-profile-background-image-cross-fade-png-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/cross-fade-background-size-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/cross-fade-background-size-expected.png
index e138bc81..d303706 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/cross-fade-background-size-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/cross-fade-background-size-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/virtual/gpu/fast/canvas/canvas-imageSmoothingEnabled-patterns-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu/fast/canvas/canvas-imageSmoothingEnabled-patterns-expected.png
similarity index 71%
rename from third_party/WebKit/LayoutTests/virtual/gpu/fast/canvas/canvas-imageSmoothingEnabled-patterns-expected.png
rename to third_party/WebKit/LayoutTests/platform/mac/virtual/gpu/fast/canvas/canvas-imageSmoothingEnabled-patterns-expected.png
index f76cc2c..dbc24cee 100644
--- a/third_party/WebKit/LayoutTests/virtual/gpu/fast/canvas/canvas-imageSmoothingEnabled-patterns-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu/fast/canvas/canvas-imageSmoothingEnabled-patterns-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/stable/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/virtual/stable/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt
index 0a7a8e3..9e2e034 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/stable/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/stable/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt
@@ -692,10 +692,18 @@
     getter responseEnd
     getter responseStart
     getter secureConnectionStart
+    getter serverTiming
     getter transferSize
     getter workerStart
     method constructor
     method toJSON
+interface PerformanceServerTiming
+    attribute @@toStringTag
+    getter description
+    getter duration
+    getter name
+    method constructor
+    method toJSON
 interface PermissionStatus : EventTarget
     attribute @@toStringTag
     getter onchange
@@ -974,6 +982,7 @@
     getter appVersion
     getter budget
     getter connection
+    getter deviceMemory
     getter hardwareConcurrency
     getter onLine
     getter permissions
diff --git a/third_party/WebKit/LayoutTests/platform/win/css3/masking/mask-repeat-space-border-expected.png b/third_party/WebKit/LayoutTests/platform/win/css3/masking/mask-repeat-space-border-expected.png
index 914bb61c3..787c9792 100644
--- a/third_party/WebKit/LayoutTests/platform/win/css3/masking/mask-repeat-space-border-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/css3/masking/mask-repeat-space-border-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/gradients/list-item-gradient-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/gradients/list-item-gradient-expected.png
index a98d211..5540f24 100644
--- a/third_party/WebKit/LayoutTests/platform/win/fast/gradients/list-item-gradient-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/fast/gradients/list-item-gradient-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/gradients/unprefixed-list-item-gradient-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/gradients/unprefixed-list-item-gradient-expected.png
index dc0ad38..82da0cf 100644
--- a/third_party/WebKit/LayoutTests/platform/win/fast/gradients/unprefixed-list-item-gradient-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/fast/gradients/unprefixed-list-item-gradient-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/images/color-profile-background-image-cross-fade-expected.png b/third_party/WebKit/LayoutTests/platform/win/images/color-profile-background-image-cross-fade-expected.png
index 3e8bf73..462ff19 100644
--- a/third_party/WebKit/LayoutTests/platform/win/images/color-profile-background-image-cross-fade-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/images/color-profile-background-image-cross-fade-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/images/color-profile-background-image-cross-fade-png-expected.png b/third_party/WebKit/LayoutTests/platform/win/images/color-profile-background-image-cross-fade-png-expected.png
index 3e8bf73..462ff19 100644
--- a/third_party/WebKit/LayoutTests/platform/win/images/color-profile-background-image-cross-fade-png-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/images/color-profile-background-image-cross-fade-png-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/images/cross-fade-background-size-expected.png b/third_party/WebKit/LayoutTests/platform/win/images/cross-fade-background-size-expected.png
index af34a7c..f848fabd 100644
--- a/third_party/WebKit/LayoutTests/platform/win/images/cross-fade-background-size-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/images/cross-fade-background-size-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/zoom/page/zoom-background-images-expected.png b/third_party/WebKit/LayoutTests/platform/win/svg/zoom/page/zoom-background-images-expected.png
index 3826f98f..89f7974 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/zoom/page/zoom-background-images-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/zoom/page/zoom-background-images-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/color-profile-background-image-cross-fade-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/color-profile-background-image-cross-fade-expected.png
index cccbc596..548cff8 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/color-profile-background-image-cross-fade-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/color-profile-background-image-cross-fade-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/color-profile-background-image-cross-fade-png-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/color-profile-background-image-cross-fade-png-expected.png
index cccbc596..548cff8 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/color-profile-background-image-cross-fade-png-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/color-profile-background-image-cross-fade-png-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/cross-fade-background-size-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/cross-fade-background-size-expected.png
index 4938ff85..78d3e32 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/cross-fade-background-size-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/exotic-color-space/images/cross-fade-background-size-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/gpu-rasterization/images/color-profile-background-image-cross-fade-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/gpu-rasterization/images/color-profile-background-image-cross-fade-expected.png
index 4211633..c9ba0f3 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/gpu-rasterization/images/color-profile-background-image-cross-fade-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/gpu-rasterization/images/color-profile-background-image-cross-fade-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/gpu-rasterization/images/color-profile-background-image-cross-fade-png-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/gpu-rasterization/images/color-profile-background-image-cross-fade-png-expected.png
index 4211633..c9ba0f3 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/gpu-rasterization/images/color-profile-background-image-cross-fade-png-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/gpu-rasterization/images/color-profile-background-image-cross-fade-png-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/gpu-rasterization/images/cross-fade-background-size-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/gpu-rasterization/images/cross-fade-background-size-expected.png
index 0123a81..378f700 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/gpu-rasterization/images/cross-fade-background-size-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/gpu-rasterization/images/cross-fade-background-size-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/gpu/fast/canvas/canvas-imageSmoothingEnabled-patterns-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/gpu/fast/canvas/canvas-imageSmoothingEnabled-patterns-expected.png
index 1a5c0b5..ccb72df 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/gpu/fast/canvas/canvas-imageSmoothingEnabled-patterns-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/gpu/fast/canvas/canvas-imageSmoothingEnabled-patterns-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/svg/css/background-non-integer-viewbox.html b/third_party/WebKit/LayoutTests/svg/css/background-non-integer-viewbox.html
index dff2d88..ab050b0 100644
--- a/third_party/WebKit/LayoutTests/svg/css/background-non-integer-viewbox.html
+++ b/third_party/WebKit/LayoutTests/svg/css/background-non-integer-viewbox.html
@@ -63,7 +63,7 @@
     width: 600px;
     top: 0;
     height: 127px; /* We're only interested in the 128:th row. */
-    background-color: blue;
+    background-color: rgb(0,0,255);
 }
 </style>
 <div id="t1"></div>
diff --git a/third_party/WebKit/LayoutTests/virtual/stable/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt b/third_party/WebKit/LayoutTests/virtual/stable/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt
index 0a7a8e3..9e2e034 100644
--- a/third_party/WebKit/LayoutTests/virtual/stable/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt
+++ b/third_party/WebKit/LayoutTests/virtual/stable/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt
@@ -692,10 +692,18 @@
     getter responseEnd
     getter responseStart
     getter secureConnectionStart
+    getter serverTiming
     getter transferSize
     getter workerStart
     method constructor
     method toJSON
+interface PerformanceServerTiming
+    attribute @@toStringTag
+    getter description
+    getter duration
+    getter name
+    method constructor
+    method toJSON
 interface PermissionStatus : EventTarget
     attribute @@toStringTag
     getter onchange
@@ -974,6 +982,7 @@
     getter appVersion
     getter budget
     getter connection
+    getter deviceMemory
     getter hardwareConcurrency
     getter onLine
     getter permissions
diff --git a/third_party/WebKit/LayoutTests/virtual/stable/webexposed/global-interface-listing-dedicated-worker-expected.txt b/third_party/WebKit/LayoutTests/virtual/stable/webexposed/global-interface-listing-dedicated-worker-expected.txt
index f81c0491..11306722 100644
--- a/third_party/WebKit/LayoutTests/virtual/stable/webexposed/global-interface-listing-dedicated-worker-expected.txt
+++ b/third_party/WebKit/LayoutTests/virtual/stable/webexposed/global-interface-listing-dedicated-worker-expected.txt
@@ -667,10 +667,18 @@
 [Worker]     getter responseEnd
 [Worker]     getter responseStart
 [Worker]     getter secureConnectionStart
+[Worker]     getter serverTiming
 [Worker]     getter transferSize
 [Worker]     getter workerStart
 [Worker]     method constructor
 [Worker]     method toJSON
+[Worker] interface PerformanceServerTiming
+[Worker]     attribute @@toStringTag
+[Worker]     getter description
+[Worker]     getter duration
+[Worker]     getter name
+[Worker]     method constructor
+[Worker]     method toJSON
 [Worker] interface PermissionStatus : EventTarget
 [Worker]     attribute @@toStringTag
 [Worker]     getter onchange
@@ -931,6 +939,7 @@
 [Worker]     getter appVersion
 [Worker]     getter budget
 [Worker]     getter connection
+[Worker]     getter deviceMemory
 [Worker]     getter hardwareConcurrency
 [Worker]     getter onLine
 [Worker]     getter permissions
diff --git a/third_party/WebKit/LayoutTests/virtual/stable/webexposed/global-interface-listing-expected.txt b/third_party/WebKit/LayoutTests/virtual/stable/webexposed/global-interface-listing-expected.txt
index e7211df..342e410 100644
--- a/third_party/WebKit/LayoutTests/virtual/stable/webexposed/global-interface-listing-expected.txt
+++ b/third_party/WebKit/LayoutTests/virtual/stable/webexposed/global-interface-listing-expected.txt
@@ -4100,10 +4100,18 @@
     getter responseEnd
     getter responseStart
     getter secureConnectionStart
+    getter serverTiming
     getter transferSize
     getter workerStart
     method constructor
     method toJSON
+interface PerformanceServerTiming
+    attribute @@toStringTag
+    getter description
+    getter duration
+    getter name
+    method constructor
+    method toJSON
 interface PerformanceTiming
     attribute @@toStringTag
     getter connectEnd
diff --git a/third_party/WebKit/LayoutTests/virtual/stable/webexposed/global-interface-listing-shared-worker-expected.txt b/third_party/WebKit/LayoutTests/virtual/stable/webexposed/global-interface-listing-shared-worker-expected.txt
index 8e5d8a78..3dd720fb 100644
--- a/third_party/WebKit/LayoutTests/virtual/stable/webexposed/global-interface-listing-shared-worker-expected.txt
+++ b/third_party/WebKit/LayoutTests/virtual/stable/webexposed/global-interface-listing-shared-worker-expected.txt
@@ -662,10 +662,18 @@
 [Worker]     getter responseEnd
 [Worker]     getter responseStart
 [Worker]     getter secureConnectionStart
+[Worker]     getter serverTiming
 [Worker]     getter transferSize
 [Worker]     getter workerStart
 [Worker]     method constructor
 [Worker]     method toJSON
+[Worker] interface PerformanceServerTiming
+[Worker]     attribute @@toStringTag
+[Worker]     getter description
+[Worker]     getter duration
+[Worker]     getter name
+[Worker]     method constructor
+[Worker]     method toJSON
 [Worker] interface PermissionStatus : EventTarget
 [Worker]     attribute @@toStringTag
 [Worker]     getter onchange
@@ -931,6 +939,7 @@
 [Worker]     getter appVersion
 [Worker]     getter budget
 [Worker]     getter connection
+[Worker]     getter deviceMemory
 [Worker]     getter hardwareConcurrency
 [Worker]     getter onLine
 [Worker]     getter permissions
diff --git a/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-dedicated-worker-expected.txt b/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-dedicated-worker-expected.txt
index 0d14ec5b..3a38d61 100644
--- a/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-dedicated-worker-expected.txt
+++ b/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-dedicated-worker-expected.txt
@@ -2463,6 +2463,7 @@
 [Worker]     getter appVersion
 [Worker]     getter budget
 [Worker]     getter connection
+[Worker]     getter deviceMemory
 [Worker]     getter hardwareConcurrency
 [Worker]     getter locks
 [Worker]     getter onLine
diff --git a/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt b/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt
index 5e13b0e..1543687 100644
--- a/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt
+++ b/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt
@@ -8904,7 +8904,6 @@
     method getTransformTo
 interface XRDevice : EventTarget
     attribute @@toStringTag
-    getter deviceName
     getter external
     method constructor
     method requestSession
diff --git a/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-shared-worker-expected.txt b/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-shared-worker-expected.txt
index 77e9bc39..5732bd6 100644
--- a/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-shared-worker-expected.txt
+++ b/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-shared-worker-expected.txt
@@ -2463,6 +2463,7 @@
 [Worker]     getter appVersion
 [Worker]     getter budget
 [Worker]     getter connection
+[Worker]     getter deviceMemory
 [Worker]     getter hardwareConcurrency
 [Worker]     getter locks
 [Worker]     getter onLine
diff --git a/third_party/WebKit/LayoutTests/xr/requestDevice_one_device.html b/third_party/WebKit/LayoutTests/xr/requestDevice_one_device.html
index 051085d..61f6b86 100644
--- a/third_party/WebKit/LayoutTests/xr/requestDevice_one_device.html
+++ b/third_party/WebKit/LayoutTests/xr/requestDevice_one_device.html
@@ -13,7 +13,6 @@
   return navigator.xr.requestDevice().then( (device) => {
     t.step( () => {
       assert_true(device != null);
-      assert_equals(device.deviceName, 'Google, Inc. Daydream View');
       assert_false(device.external);
     }, "requestDevice returned correct results");
   }, (err) => {
diff --git a/third_party/WebKit/LayoutTests/xr/requestDevice_two_devices.html b/third_party/WebKit/LayoutTests/xr/requestDevice_two_devices.html
index fae89f0..279a9ef 100644
--- a/third_party/WebKit/LayoutTests/xr/requestDevice_two_devices.html
+++ b/third_party/WebKit/LayoutTests/xr/requestDevice_two_devices.html
@@ -18,7 +18,6 @@
     }, "requestDevice returned result");
 
     t.step( () => {
-      assert_equals(device.deviceName, 'Google, Inc. Daydream View');
       assert_false(device.external);
     }, "Attribute for device is correct");
   }, (err) => {
diff --git a/third_party/WebKit/Source/bindings/core/v8/IDLTypes.h b/third_party/WebKit/Source/bindings/core/v8/IDLTypes.h
index eb533c7..6aec285 100644
--- a/third_party/WebKit/Source/bindings/core/v8/IDLTypes.h
+++ b/third_party/WebKit/Source/bindings/core/v8/IDLTypes.h
@@ -9,7 +9,6 @@
 #include "bindings/core/v8/IDLTypesBase.h"
 #include "bindings/core/v8/NativeValueTraits.h"
 #include "bindings/core/v8/V8BindingForCore.h"
-#include "core/CoreExport.h"
 #include "platform/heap/Handle.h"
 #include "platform/wtf/Optional.h"
 #include "platform/wtf/TypeTraits.h"
diff --git a/third_party/WebKit/Source/bindings/core/v8/V8BindingForCore.h b/third_party/WebKit/Source/bindings/core/v8/V8BindingForCore.h
index 3f3de5e..a120e78d 100644
--- a/third_party/WebKit/Source/bindings/core/v8/V8BindingForCore.h
+++ b/third_party/WebKit/Source/bindings/core/v8/V8BindingForCore.h
@@ -447,17 +447,6 @@
   }
 };
 
-template <>
-struct NativeValueTraits<v8::Local<v8::Value>>
-    : public NativeValueTraitsBase<v8::Local<v8::Value>> {
-  static inline v8::Local<v8::Value> NativeValue(
-      v8::Isolate* isolate,
-      v8::Local<v8::Value> value,
-      ExceptionState& exception_state) {
-    return value;
-  }
-};
-
 CORE_EXPORT v8::Isolate* ToIsolate(ExecutionContext*);
 CORE_EXPORT v8::Isolate* ToIsolate(LocalFrame*);
 
diff --git a/third_party/WebKit/Source/bindings/core/v8/serialization/SerializedScriptValue.cpp b/third_party/WebKit/Source/bindings/core/v8/serialization/SerializedScriptValue.cpp
index 4f43868..c8fbe34d 100644
--- a/third_party/WebKit/Source/bindings/core/v8/serialization/SerializedScriptValue.cpp
+++ b/third_party/WebKit/Source/bindings/core/v8/serialization/SerializedScriptValue.cpp
@@ -403,15 +403,16 @@
   if (value.IsEmpty() || value->IsUndefined())
     return true;
 
-  Vector<v8::Local<v8::Value>> transferable_array =
-      NativeValueTraits<IDLSequence<v8::Local<v8::Value>>>::NativeValue(
-          isolate, value, exception_state);
+  Vector<ScriptValue> transferable_array =
+      NativeValueTraits<IDLSequence<ScriptValue>>::NativeValue(isolate, value,
+                                                               exception_state);
   if (exception_state.HadException())
     return false;
 
   // Validate the passed array of transferables.
   uint32_t i = 0;
-  for (const auto& transferable_object : transferable_array) {
+  for (const auto& script_value : transferable_array) {
+    v8::Local<v8::Value> transferable_object = script_value.V8Value();
     // Validation of non-null objects, per HTML5 spec 10.3.3.
     if (IsUndefinedOrNull(transferable_object)) {
       exception_state.ThrowTypeError(
diff --git a/third_party/WebKit/Source/bindings/templates/methods.cpp.tmpl b/third_party/WebKit/Source/bindings/templates/methods.cpp.tmpl
index 7c272cd..0bdd0a0c 100644
--- a/third_party/WebKit/Source/bindings/templates/methods.cpp.tmpl
+++ b/third_party/WebKit/Source/bindings/templates/methods.cpp.tmpl
@@ -530,9 +530,7 @@
   {% endif %}
   V8PerContextData* contextData = scriptState->PerContextData();
   if (contextData && contextData->ActivityLogger()) {
-    ExceptionState exceptionState(info.GetIsolate(), ExceptionState::kExecutionContext, "{{interface_name}}", "{{method.name}}");
-    Vector<v8::Local<v8::Value>> loggerArgs = ToImplArguments<Vector<v8::Local<v8::Value>>>(info, 0, exceptionState);
-    contextData->ActivityLogger()->LogMethod("{{interface_name}}.{{method.name}}", info.Length(), loggerArgs.data());
+    contextData->ActivityLogger()->LogMethod("{{interface_name}}.{{method.name}}", info);
   }
   {% endif %}
   {% if method.is_custom %}
diff --git a/third_party/WebKit/Source/bindings/tests/results/core/V8TestObject.cpp b/third_party/WebKit/Source/bindings/tests/results/core/V8TestObject.cpp
index a210a9a59..7baa155 100644
--- a/third_party/WebKit/Source/bindings/tests/results/core/V8TestObject.cpp
+++ b/third_party/WebKit/Source/bindings/tests/results/core/V8TestObject.cpp
@@ -12587,9 +12587,7 @@
   ScriptState* scriptState = ScriptState::ForRelevantRealm(info);
   V8PerContextData* contextData = scriptState->PerContextData();
   if (contextData && contextData->ActivityLogger()) {
-    ExceptionState exceptionState(info.GetIsolate(), ExceptionState::kExecutionContext, "TestObject", "activityLoggingAccessForAllWorldsMethod");
-    Vector<v8::Local<v8::Value>> loggerArgs = ToImplArguments<Vector<v8::Local<v8::Value>>>(info, 0, exceptionState);
-    contextData->ActivityLogger()->LogMethod("TestObject.activityLoggingAccessForAllWorldsMethod", info.Length(), loggerArgs.data());
+    contextData->ActivityLogger()->LogMethod("TestObject.activityLoggingAccessForAllWorldsMethod", info);
   }
   TestObjectV8Internal::activityLoggingAccessForAllWorldsMethodMethod(info);
 }
@@ -12819,9 +12817,7 @@
   ScriptState* scriptState = ScriptState::ForRelevantRealm(info);
   V8PerContextData* contextData = scriptState->PerContextData();
   if (contextData && contextData->ActivityLogger()) {
-    ExceptionState exceptionState(info.GetIsolate(), ExceptionState::kExecutionContext, "TestObject", "activityLoggingForAllWorldsPerWorldBindingsVoidMethod");
-    Vector<v8::Local<v8::Value>> loggerArgs = ToImplArguments<Vector<v8::Local<v8::Value>>>(info, 0, exceptionState);
-    contextData->ActivityLogger()->LogMethod("TestObject.activityLoggingForAllWorldsPerWorldBindingsVoidMethod", info.Length(), loggerArgs.data());
+    contextData->ActivityLogger()->LogMethod("TestObject.activityLoggingForAllWorldsPerWorldBindingsVoidMethod", info);
   }
   TestObjectV8Internal::activityLoggingForAllWorldsPerWorldBindingsVoidMethodMethod(info);
 }
@@ -12832,9 +12828,7 @@
   ScriptState* scriptState = ScriptState::ForRelevantRealm(info);
   V8PerContextData* contextData = scriptState->PerContextData();
   if (contextData && contextData->ActivityLogger()) {
-    ExceptionState exceptionState(info.GetIsolate(), ExceptionState::kExecutionContext, "TestObject", "activityLoggingForAllWorldsPerWorldBindingsVoidMethod");
-    Vector<v8::Local<v8::Value>> loggerArgs = ToImplArguments<Vector<v8::Local<v8::Value>>>(info, 0, exceptionState);
-    contextData->ActivityLogger()->LogMethod("TestObject.activityLoggingForAllWorldsPerWorldBindingsVoidMethod", info.Length(), loggerArgs.data());
+    contextData->ActivityLogger()->LogMethod("TestObject.activityLoggingForAllWorldsPerWorldBindingsVoidMethod", info);
   }
   TestObjectV8Internal::activityLoggingForAllWorldsPerWorldBindingsVoidMethodMethodForMainWorld(info);
 }
@@ -12845,9 +12839,7 @@
   ScriptState* scriptState = ScriptState::ForRelevantRealm(info);
   V8PerContextData* contextData = scriptState->PerContextData();
   if (contextData && contextData->ActivityLogger()) {
-    ExceptionState exceptionState(info.GetIsolate(), ExceptionState::kExecutionContext, "TestObject", "activityLoggingForIsolatedWorldsPerWorldBindingsVoidMethod");
-    Vector<v8::Local<v8::Value>> loggerArgs = ToImplArguments<Vector<v8::Local<v8::Value>>>(info, 0, exceptionState);
-    contextData->ActivityLogger()->LogMethod("TestObject.activityLoggingForIsolatedWorldsPerWorldBindingsVoidMethod", info.Length(), loggerArgs.data());
+    contextData->ActivityLogger()->LogMethod("TestObject.activityLoggingForIsolatedWorldsPerWorldBindingsVoidMethod", info);
   }
   TestObjectV8Internal::activityLoggingForIsolatedWorldsPerWorldBindingsVoidMethodMethod(info);
 }
diff --git a/third_party/WebKit/Source/core/core_idl_files.gni b/third_party/WebKit/Source/core/core_idl_files.gni
index f289ea2..ab99313 100644
--- a/third_party/WebKit/Source/core/core_idl_files.gni
+++ b/third_party/WebKit/Source/core/core_idl_files.gni
@@ -500,6 +500,7 @@
                     "frame/NavigatorAutomationInformation.idl",
                     "frame/NavigatorConcurrentHardware.idl",
                     "frame/NavigatorCookies.idl",
+                    "frame/NavigatorDeviceMemory.idl",
                     "frame/NavigatorID.idl",
                     "frame/NavigatorLanguage.idl",
                     "frame/NavigatorOnLine.idl",
diff --git a/third_party/WebKit/Source/core/css/CSSCrossfadeValue.cpp b/third_party/WebKit/Source/core/css/CSSCrossfadeValue.cpp
index ca97874..9d3c77e 100644
--- a/third_party/WebKit/Source/core/css/CSSCrossfadeValue.cpp
+++ b/third_party/WebKit/Source/core/css/CSSCrossfadeValue.cpp
@@ -151,24 +151,26 @@
   return CSSCrossfadeValue::Create(from_value, to_value, percentage_value_);
 }
 
-IntSize CSSCrossfadeValue::FixedSize(const Document& document,
-                                     const FloatSize& default_object_size) {
+FloatSize CSSCrossfadeValue::FixedSize(const Document& document,
+                                       const FloatSize& default_object_size) {
   Image* from_image = RenderableImageForCSSValue(from_value_.Get(), document);
   Image* to_image = RenderableImageForCSSValue(to_value_.Get(), document);
 
   if (!from_image || !to_image)
-    return IntSize();
+    return FloatSize();
 
-  IntSize from_image_size = from_image->Size();
-  IntSize to_image_size = to_image->Size();
+  FloatSize from_image_size(from_image->Size());
+  FloatSize to_image_size(to_image->Size());
 
-  if (from_image->IsSVGImage())
-    from_image_size = RoundedIntSize(
-        ToSVGImage(from_image)->ConcreteObjectSize(default_object_size));
+  if (from_image->IsSVGImage()) {
+    from_image_size =
+        ToSVGImage(from_image)->ConcreteObjectSize(default_object_size);
+  }
 
-  if (to_image->IsSVGImage())
-    to_image_size = RoundedIntSize(
-        ToSVGImage(to_image)->ConcreteObjectSize(default_object_size));
+  if (to_image->IsSVGImage()) {
+    to_image_size =
+        ToSVGImage(to_image)->ConcreteObjectSize(default_object_size);
+  }
 
   // Rounding issues can cause transitions between images of equal size to
   // return a different fixed size; avoid performing the interpolation if the
@@ -179,10 +181,10 @@
   float percentage = percentage_value_->GetFloatValue();
   float inverse_percentage = 1 - percentage;
 
-  return IntSize(from_image_size.Width() * inverse_percentage +
-                     to_image_size.Width() * percentage,
-                 from_image_size.Height() * inverse_percentage +
-                     to_image_size.Height() * percentage);
+  return FloatSize(from_image_size.Width() * inverse_percentage +
+                       to_image_size.Width() * percentage,
+                   from_image_size.Height() * inverse_percentage +
+                       to_image_size.Height() * percentage);
 }
 
 bool CSSCrossfadeValue::IsPending() const {
@@ -224,7 +226,7 @@
     const ImageResourceObserver& client,
     const Document& document,
     const ComputedStyle&,
-    const IntSize& size) {
+    const LayoutSize& size) {
   if (size.IsEmpty())
     return nullptr;
 
@@ -247,7 +249,7 @@
 
   return CrossfadeGeneratedImage::Create(
       from_image_ref, to_image_ref, percentage_value_->GetFloatValue(),
-      FixedSize(document, FloatSize(size)), size);
+      FixedSize(document, FloatSize(size)), FloatSize(size));
 }
 
 void CSSCrossfadeValue::CrossfadeChanged(
diff --git a/third_party/WebKit/Source/core/css/CSSCrossfadeValue.h b/third_party/WebKit/Source/core/css/CSSCrossfadeValue.h
index e563e82..41929673 100644
--- a/third_party/WebKit/Source/core/css/CSSCrossfadeValue.h
+++ b/third_party/WebKit/Source/core/css/CSSCrossfadeValue.h
@@ -57,9 +57,9 @@
   scoped_refptr<Image> GetImage(const ImageResourceObserver&,
                                 const Document&,
                                 const ComputedStyle&,
-                                const IntSize& container_size);
+                                const LayoutSize& container_size);
   bool IsFixedSize() const { return true; }
-  IntSize FixedSize(const Document&, const FloatSize&);
+  FloatSize FixedSize(const Document&, const FloatSize&);
 
   bool IsPending() const;
   bool KnownToBeOpaque(const Document&, const ComputedStyle&) const;
diff --git a/third_party/WebKit/Source/core/css/CSSGradientValue.cpp b/third_party/WebKit/Source/core/css/CSSGradientValue.cpp
index 4ea74cc..2a79f30 100644
--- a/third_party/WebKit/Source/core/css/CSSGradientValue.cpp
+++ b/third_party/WebKit/Source/core/css/CSSGradientValue.cpp
@@ -107,7 +107,7 @@
     const ImageResourceObserver& client,
     const Document& document,
     const ComputedStyle& style,
-    const IntSize& size) {
+    const LayoutSize& size) {
   if (size.IsEmpty())
     return nullptr;
 
@@ -151,7 +151,7 @@
   }
 
   scoped_refptr<Image> new_image =
-      GradientGeneratedImage::Create(gradient, size);
+      GradientGeneratedImage::Create(gradient, FloatSize(size));
   if (is_cacheable_)
     PutImage(size, new_image);
 
@@ -635,11 +635,12 @@
 
 static float PositionFromValue(const CSSValue* value,
                                const CSSToLengthConversionData& conversion_data,
-                               const IntSize& size,
+                               const LayoutSize& size,
                                bool is_horizontal) {
-  int origin = 0;
+  float origin = 0;
   int sign = 1;
-  int edge_distance = is_horizontal ? size.Width() : size.Height();
+  float edge_distance =
+      is_horizontal ? size.Width().ToFloat() : size.Height().ToFloat();
 
   // In this case the center of the gradient is given relative to an edge in the
   // form of: [ top | bottom | right | left ] [ <percentage> | <length> ].
@@ -700,7 +701,7 @@
     const CSSValue* horizontal,
     const CSSValue* vertical,
     const CSSToLengthConversionData& conversion_data,
-    const IntSize& size) {
+    const LayoutSize& size) {
   FloatPoint result;
 
   if (horizontal)
@@ -808,7 +809,7 @@
 // Compute the endpoints so that a gradient of the given angle covers a box of
 // the given size.
 static void EndPointsFromAngle(float angle_deg,
-                               const IntSize& size,
+                               const LayoutSize& size,
                                FloatPoint& first_point,
                                FloatPoint& second_point,
                                CSSGradientType type) {
@@ -880,7 +881,7 @@
 
 scoped_refptr<Gradient> CSSLinearGradientValue::CreateGradient(
     const CSSToLengthConversionData& conversion_data,
-    const IntSize& size,
+    const LayoutSize& size,
     const LayoutObject& object) {
   DCHECK(!size.IsEmpty());
 
@@ -1246,7 +1247,7 @@
 
 scoped_refptr<Gradient> CSSRadialGradientValue::CreateGradient(
     const CSSToLengthConversionData& conversion_data,
-    const IntSize& size,
+    const LayoutSize& size,
     const LayoutObject& object) {
   DCHECK(!size.IsEmpty());
 
@@ -1422,7 +1423,7 @@
 
 scoped_refptr<Gradient> CSSConicGradientValue::CreateGradient(
     const CSSToLengthConversionData& conversion_data,
-    const IntSize& size,
+    const LayoutSize& size,
     const LayoutObject& object) {
   DCHECK(!size.IsEmpty());
 
diff --git a/third_party/WebKit/Source/core/css/CSSGradientValue.h b/third_party/WebKit/Source/core/css/CSSGradientValue.h
index 7a41930..47ee780 100644
--- a/third_party/WebKit/Source/core/css/CSSGradientValue.h
+++ b/third_party/WebKit/Source/core/css/CSSGradientValue.h
@@ -96,7 +96,7 @@
   scoped_refptr<Image> GetImage(const ImageResourceObserver&,
                                 const Document&,
                                 const ComputedStyle&,
-                                const IntSize&);
+                                const LayoutSize&);
 
   void AddStop(const CSSGradientColorStop& stop) {
     stops_.push_back(stop);
@@ -110,7 +110,7 @@
   CSSGradientType GradientType() const { return gradient_type_; }
 
   bool IsFixedSize() const { return false; }
-  IntSize FixedSize(const Document&) const { return IntSize(); }
+  FloatSize FixedSize(const Document&) const { return FloatSize(); }
 
   bool IsPending() const { return false; }
   bool KnownToBeOpaque(const Document&, const ComputedStyle&) const;
@@ -170,7 +170,7 @@
 
   // Create the gradient for a given size.
   scoped_refptr<Gradient> CreateGradient(const CSSToLengthConversionData&,
-                                         const IntSize&,
+                                         const LayoutSize&,
                                          const LayoutObject&);
 
   bool Equals(const CSSLinearGradientValue&) const;
@@ -243,7 +243,7 @@
 
   // Create the gradient for a given size.
   scoped_refptr<Gradient> CreateGradient(const CSSToLengthConversionData&,
-                                         const IntSize&,
+                                         const LayoutSize&,
                                          const LayoutObject&);
 
   bool Equals(const CSSRadialGradientValue&) const;
@@ -309,7 +309,7 @@
 
   // Create the gradient for a given size.
   scoped_refptr<Gradient> CreateGradient(const CSSToLengthConversionData&,
-                                         const IntSize&,
+                                         const LayoutSize&,
                                          const LayoutObject&);
 
   bool Equals(const CSSConicGradientValue&) const;
diff --git a/third_party/WebKit/Source/core/css/CSSImageGeneratorValue.cpp b/third_party/WebKit/Source/core/css/CSSImageGeneratorValue.cpp
index 8894b4c0..0d490078 100644
--- a/third_party/WebKit/Source/core/css/CSSImageGeneratorValue.cpp
+++ b/third_party/WebKit/Source/core/css/CSSImageGeneratorValue.cpp
@@ -44,7 +44,7 @@
 CSSImageGeneratorValue::~CSSImageGeneratorValue() = default;
 
 void CSSImageGeneratorValue::AddClient(const ImageResourceObserver* client,
-                                       const IntSize& size) {
+                                       const LayoutSize& size) {
   DCHECK(client);
   if (clients_.IsEmpty()) {
     DCHECK(!keep_alive_);
@@ -74,9 +74,9 @@
   ClientSizeCountMap::iterator it = clients_.find(client);
   SECURITY_DCHECK(it != clients_.end());
 
-  IntSize removed_image_size;
+  LayoutSize removed_image_size;
   SizeAndCount& size_count = it->value;
-  IntSize size = size_count.size;
+  LayoutSize size = size_count.size;
   if (!size.IsEmpty()) {
     sizes_.erase(size);
     if (!sizes_.Contains(size))
@@ -95,11 +95,11 @@
 Image* CSSImageGeneratorValue::GetImage(const ImageResourceObserver* client,
                                         const Document&,
                                         const ComputedStyle&,
-                                        const IntSize& size) {
+                                        const LayoutSize& size) {
   ClientSizeCountMap::iterator it = clients_.find(client);
   if (it != clients_.end()) {
     SizeAndCount& size_count = it->value;
-    IntSize old_size = size_count.size;
+    LayoutSize old_size = size_count.size;
     if (old_size != size) {
       RemoveClient(client);
       AddClient(client, size);
@@ -114,7 +114,7 @@
   return images_.at(size);
 }
 
-void CSSImageGeneratorValue::PutImage(const IntSize& size,
+void CSSImageGeneratorValue::PutImage(const LayoutSize& size,
                                       scoped_refptr<Image> image) {
   images_.insert(size, std::move(image));
 }
@@ -123,7 +123,7 @@
     const ImageResourceObserver& client,
     const Document& document,
     const ComputedStyle& style,
-    const IntSize& container_size) {
+    const LayoutSize& container_size) {
   switch (GetClassType()) {
     case kCrossfadeClass:
       return ToCSSCrossfadeValue(this)->GetImage(client, document, style,
@@ -164,7 +164,7 @@
   return false;
 }
 
-IntSize CSSImageGeneratorValue::FixedSize(
+FloatSize CSSImageGeneratorValue::FixedSize(
     const Document& document,
     const FloatSize& default_object_size) {
   switch (GetClassType()) {
@@ -182,7 +182,7 @@
     default:
       NOTREACHED();
   }
-  return IntSize();
+  return FloatSize();
 }
 
 bool CSSImageGeneratorValue::IsPending() const {
diff --git a/third_party/WebKit/Source/core/css/CSSImageGeneratorValue.h b/third_party/WebKit/Source/core/css/CSSImageGeneratorValue.h
index 2e51fb39..12ea3741d 100644
--- a/third_party/WebKit/Source/core/css/CSSImageGeneratorValue.h
+++ b/third_party/WebKit/Source/core/css/CSSImageGeneratorValue.h
@@ -29,7 +29,7 @@
 #include "base/memory/scoped_refptr.h"
 #include "core/CoreExport.h"
 #include "core/css/CSSValue.h"
-#include "platform/geometry/IntSizeHash.h"
+#include "platform/geometry/LayoutSizeHash.h"
 #include "platform/heap/SelfKeepAlive.h"
 #include "platform/wtf/HashCountedSet.h"
 
@@ -43,10 +43,10 @@
 
 struct SizeAndCount {
   DISALLOW_NEW();
-  SizeAndCount(IntSize new_size = IntSize(), int new_count = 0)
+  SizeAndCount(LayoutSize new_size = LayoutSize(), int new_count = 0)
       : size(new_size), count(new_count) {}
 
-  IntSize size;
+  LayoutSize size;
   int count;
 };
 
@@ -56,16 +56,16 @@
  public:
   ~CSSImageGeneratorValue();
 
-  void AddClient(const ImageResourceObserver*, const IntSize&);
+  void AddClient(const ImageResourceObserver*, const LayoutSize&);
   void RemoveClient(const ImageResourceObserver*);
   // The |container_size| is the container size with subpixel snapping.
   scoped_refptr<Image> GetImage(const ImageResourceObserver&,
                                 const Document&,
                                 const ComputedStyle&,
-                                const IntSize& container_size);
+                                const LayoutSize& container_size);
 
   bool IsFixedSize() const;
-  IntSize FixedSize(const Document&, const FloatSize& default_object_size);
+  FloatSize FixedSize(const Document&, const FloatSize& default_object_size);
 
   bool IsPending() const;
   bool KnownToBeOpaque(const Document&, const ComputedStyle&) const;
@@ -84,15 +84,15 @@
   Image* GetImage(const ImageResourceObserver*,
                   const Document&,
                   const ComputedStyle&,
-                  const IntSize&);
-  void PutImage(const IntSize&, scoped_refptr<Image>);
+                  const LayoutSize&);
+  void PutImage(const LayoutSize&, scoped_refptr<Image>);
   const ClientSizeCountMap& Clients() const { return clients_; }
 
-  HashCountedSet<IntSize>
+  HashCountedSet<LayoutSize>
       sizes_;  // A count of how many times a given image size is in use.
   ClientSizeCountMap
       clients_;  // A map from LayoutObjects (with entry count) to image sizes.
-  HashMap<IntSize, scoped_refptr<Image>>
+  HashMap<LayoutSize, scoped_refptr<Image>>
       images_;  // A cache of Image objects by image size.
 
   // TODO(Oilpan): when/if we can make the layoutObject point directly to the
diff --git a/third_party/WebKit/Source/core/css/CSSPaintValue.cpp b/third_party/WebKit/Source/core/css/CSSPaintValue.cpp
index 34c9c9e6..85933ca 100644
--- a/third_party/WebKit/Source/core/css/CSSPaintValue.cpp
+++ b/third_party/WebKit/Source/core/css/CSSPaintValue.cpp
@@ -47,7 +47,7 @@
     const ImageResourceObserver& client,
     const Document& document,
     const ComputedStyle&,
-    const IntSize& container_size) {
+    const LayoutSize& container_size) {
   if (!generator_) {
     generator_ = CSSPaintImageGenerator::Create(
         GetName(), document, paint_image_generator_observer_);
@@ -56,7 +56,8 @@
   if (!ParseInputArguments(document))
     return nullptr;
 
-  return generator_->Paint(client, container_size, parsed_input_arguments_);
+  return generator_->Paint(client, RoundedIntSize(container_size),
+                           parsed_input_arguments_);
 }
 
 bool CSSPaintValue::ParseInputArguments(const Document& document) {
diff --git a/third_party/WebKit/Source/core/css/CSSPaintValue.h b/third_party/WebKit/Source/core/css/CSSPaintValue.h
index 307e7a98..f3b2820b 100644
--- a/third_party/WebKit/Source/core/css/CSSPaintValue.h
+++ b/third_party/WebKit/Source/core/css/CSSPaintValue.h
@@ -37,9 +37,9 @@
   scoped_refptr<Image> GetImage(const ImageResourceObserver&,
                                 const Document&,
                                 const ComputedStyle&,
-                                const IntSize& container_size);
+                                const LayoutSize& container_size);
   bool IsFixedSize() const { return false; }
-  IntSize FixedSize(const Document&) { return IntSize(); }
+  FloatSize FixedSize(const Document&) { return FloatSize(); }
 
   bool IsPending() const { return true; }
   bool KnownToBeOpaque(const Document&, const ComputedStyle&) const;
diff --git a/third_party/WebKit/Source/core/css/CSSProperties.json5 b/third_party/WebKit/Source/core/css/CSSProperties.json5
index 349bc34..dab5ff7 100644
--- a/third_party/WebKit/Source/core/css/CSSProperties.json5
+++ b/third_party/WebKit/Source/core/css/CSSProperties.json5
@@ -718,17 +718,17 @@
     },
     {
       name: "background-attachment",
-      property_methods: ["ParseSingleValue"],
+      property_methods: ["ParseSingleValue", "CSSValueFromComputedStyleInternal"],
       custom_apply_functions_all: true,
     },
     {
       name: "background-blend-mode",
-      property_methods: ["ParseSingleValue"],
+      property_methods: ["ParseSingleValue", "CSSValueFromComputedStyleInternal"],
       custom_apply_functions_all: true,
     },
     {
       name: "background-clip",
-      property_methods: ["ParseSingleValue"],
+      property_methods: ["ParseSingleValue", "CSSValueFromComputedStyleInternal"],
       custom_apply_functions_all: true,
     },
     {
@@ -753,18 +753,18 @@
     },
     {
       name: "background-origin",
-      property_methods: ["ParseSingleValue"],
+      property_methods: ["ParseSingleValue", "CSSValueFromComputedStyleInternal"],
       custom_apply_functions_all: true,
     },
     {
       name: "background-position-x",
-      property_methods: ["ParseSingleValue"],
+      property_methods: ["ParseSingleValue", "CSSValueFromComputedStyleInternal"],
       interpolable: true,
       custom_apply_functions_all: true,
     },
     {
       name: "background-position-y",
-      property_methods: ["ParseSingleValue"],
+      property_methods: ["ParseSingleValue", "CSSValueFromComputedStyleInternal"],
       interpolable: true,
       custom_apply_functions_all: true,
     },
@@ -861,24 +861,24 @@
     },
     {
       name: "border-image-outset",
-      property_methods: ["ParseSingleValue"],
+      property_methods: ["ParseSingleValue", "CSSValueFromComputedStyleInternal"],
       interpolable: true,
       custom_apply_functions_all: true,
     },
     {
       name: "border-image-repeat",
-      property_methods: ["ParseSingleValue"],
+      property_methods: ["ParseSingleValue", "CSSValueFromComputedStyleInternal"],
       custom_apply_functions_all: true,
     },
     {
       name: "border-image-slice",
-      property_methods: ["ParseSingleValue"],
+      property_methods: ["ParseSingleValue", "CSSValueFromComputedStyleInternal"],
       interpolable: true,
       custom_apply_functions_all: true,
     },
     {
       name: "border-image-source",
-      property_methods: ["ParseSingleValue"],
+      property_methods: ["ParseSingleValue", "CSSValueFromComputedStyleInternal"],
       interpolable: true,
       keywords: ["none"],
       typedom_types: ["Image"],
@@ -886,7 +886,7 @@
     },
     {
       name: "border-image-width",
-      property_methods: ["ParseSingleValue"],
+      property_methods: ["ParseSingleValue", "CSSValueFromComputedStyleInternal"],
       interpolable: true,
       custom_apply_functions_all: true,
     },
@@ -1720,7 +1720,7 @@
     },
     {
       name: "marker-end",
-      property_methods: ["ParseSingleValue"],
+      property_methods: ["ParseSingleValue", "CSSValueFromComputedStyleInternal"],
       inherited: true,
       svg: true,
       name_for_methods: "MarkerEndResource",
@@ -1728,7 +1728,7 @@
     },
     {
       name: "marker-mid",
-      property_methods: ["ParseSingleValue"],
+      property_methods: ["ParseSingleValue", "CSSValueFromComputedStyleInternal"],
       inherited: true,
       svg: true,
       name_for_methods: "MarkerMidResource",
@@ -1736,7 +1736,7 @@
     },
     {
       name: "marker-start",
-      property_methods: ["ParseSingleValue"],
+      property_methods: ["ParseSingleValue", "CSSValueFromComputedStyleInternal"],
       inherited: true,
       svg: true,
       name_for_methods: "MarkerStartResource",
@@ -1744,14 +1744,14 @@
     },
     {
       name: "mask",
-      property_methods: ["ParseSingleValue"],
+      property_methods: ["ParseSingleValue", "CSSValueFromComputedStyleInternal"],
       svg: true,
       name_for_methods: "MaskerResource",
       converter: "ConvertFragmentIdentifier",
     },
     {
       name: "mask-source-type",
-      property_methods: ["ParseSingleValue"],
+      property_methods: ["ParseSingleValue", "CSSValueFromComputedStyleInternal"],
       runtime_flag: "CSSMaskSourceType",
       custom_apply_functions_all: true,
     },
@@ -2878,7 +2878,7 @@
     },
     {
       name: "-webkit-border-image",
-      property_methods: ["ParseSingleValue"],
+      property_methods: ["ParseSingleValue", "CSSValueFromComputedStyleInternal"],
       custom_apply_functions_value: true,
     },
     {
@@ -2971,7 +2971,7 @@
     },
     {
       name: "-webkit-box-reflect",
-      property_methods: ["ParseSingleValue"],
+      property_methods: ["ParseSingleValue", "CSSValueFromComputedStyleInternal"],
       field_group: "*",
       field_template: "pointer",
       include_paths: ["core/style/StyleReflection.h"],
@@ -3141,41 +3141,41 @@
     },
     {
       name: "-webkit-mask-box-image-outset",
-      property_methods: ["ParseSingleValue"],
+      property_methods: ["ParseSingleValue", "CSSValueFromComputedStyleInternal"],
       interpolable: true,
       custom_apply_functions_all: true,
     },
     {
       name: "-webkit-mask-box-image-repeat",
-      property_methods: ["ParseSingleValue"],
+      property_methods: ["ParseSingleValue", "CSSValueFromComputedStyleInternal"],
       custom_apply_functions_all: true,
     },
     {
       name: "-webkit-mask-box-image-slice",
-      property_methods: ["ParseSingleValue"],
+      property_methods: ["ParseSingleValue", "CSSValueFromComputedStyleInternal"],
       interpolable: true,
       custom_apply_functions_all: true,
     },
     {
       name: "-webkit-mask-box-image-source",
-      property_methods: ["ParseSingleValue"],
+      property_methods: ["ParseSingleValue", "CSSValueFromComputedStyleInternal"],
       interpolable: true,
       custom_apply_functions_value: true,
     },
     {
       name: "-webkit-mask-box-image-width",
-      property_methods: ["ParseSingleValue"],
+      property_methods: ["ParseSingleValue", "CSSValueFromComputedStyleInternal"],
       interpolable: true,
       custom_apply_functions_all: true,
     },
     {
       name: "-webkit-mask-clip",
-      property_methods: ["ParseSingleValue"],
+      property_methods: ["ParseSingleValue", "CSSValueFromComputedStyleInternal"],
       custom_apply_functions_all: true,
     },
     {
       name: "-webkit-mask-composite",
-      property_methods: ["ParseSingleValue"],
+      property_methods: ["ParseSingleValue", "CSSValueFromComputedStyleInternal"],
       custom_apply_functions_all: true,
     },
     {
@@ -3186,18 +3186,18 @@
     },
     {
       name: "-webkit-mask-origin",
-      property_methods: ["ParseSingleValue"],
+      property_methods: ["ParseSingleValue", "CSSValueFromComputedStyleInternal"],
       custom_apply_functions_all: true,
     },
     {
       name: "-webkit-mask-position-x",
-      property_methods: ["ParseSingleValue"],
+      property_methods: ["ParseSingleValue", "CSSValueFromComputedStyleInternal"],
       interpolable: true,
       custom_apply_functions_all: true,
     },
     {
       name: "-webkit-mask-position-y",
-      property_methods: ["ParseSingleValue"],
+      property_methods: ["ParseSingleValue", "CSSValueFromComputedStyleInternal"],
       interpolable: true,
       custom_apply_functions_all: true,
     },
@@ -3846,7 +3846,7 @@
         "border-image-source", "border-image-slice", "border-image-width",
         "border-image-outset", "border-image-repeat"
       ],
-      property_methods: ["ParseShorthand"],
+      property_methods: ["ParseShorthand", "CSSValueFromComputedStyleInternal"],
     },
     {
       name: "border-left",
@@ -4192,7 +4192,7 @@
         "-webkit-mask-box-image-width", "-webkit-mask-box-image-outset",
         "-webkit-mask-box-image-repeat"
       ],
-      property_methods: ["ParseShorthand"],
+      property_methods: ["ParseShorthand", "CSSValueFromComputedStyleInternal"],
     },
     {
       name: "-webkit-mask-position",
diff --git a/third_party/WebKit/Source/core/css/ComputedStyleCSSValueMapping.cpp b/third_party/WebKit/Source/core/css/ComputedStyleCSSValueMapping.cpp
index 3059a6e6..7502643d 100644
--- a/third_party/WebKit/Source/core/css/ComputedStyleCSSValueMapping.cpp
+++ b/third_party/WebKit/Source/core/css/ComputedStyleCSSValueMapping.cpp
@@ -31,8 +31,6 @@
 #include "core/animation/css/CSSTransitionData.h"
 #include "core/css/BasicShapeFunctions.h"
 #include "core/css/CSSBasicShapeValues.h"
-#include "core/css/CSSBorderImage.h"
-#include "core/css/CSSBorderImageSliceValue.h"
 #include "core/css/CSSColorValue.h"
 #include "core/css/CSSCounterValue.h"
 #include "core/css/CSSCursorImageValue.h"
@@ -51,7 +49,6 @@
 #include "core/css/CSSPrimitiveValue.h"
 #include "core/css/CSSPrimitiveValueMappings.h"
 #include "core/css/CSSQuadValue.h"
-#include "core/css/CSSReflectValue.h"
 #include "core/css/CSSShadowValue.h"
 #include "core/css/CSSStringValue.h"
 #include "core/css/CSSTimingFunctionValue.h"
@@ -100,19 +97,6 @@
   return CSSValue::Create(length, style.EffectiveZoom());
 }
 
-static CSSValue* ValueForFillSourceType(EMaskSourceType type) {
-  switch (type) {
-    case EMaskSourceType::kAlpha:
-      return CSSIdentifierValue::Create(CSSValueAlpha);
-    case EMaskSourceType::kLuminance:
-      return CSSIdentifierValue::Create(CSSValueLuminance);
-  }
-
-  NOTREACHED();
-
-  return nullptr;
-}
-
 static CSSValue* ValueForPositionOffset(const ComputedStyle& style,
                                         const CSSProperty& property,
                                         const LayoutObject* layout_object) {
@@ -232,206 +216,6 @@
   return ComputedStyleUtils::ZoomAdjustedPixelValueForLength(offset, style);
 }
 
-static cssvalue::CSSBorderImageSliceValue* ValueForNinePieceImageSlice(
-    const NinePieceImage& image) {
-  // Create the slices.
-  CSSPrimitiveValue* top = nullptr;
-  CSSPrimitiveValue* right = nullptr;
-  CSSPrimitiveValue* bottom = nullptr;
-  CSSPrimitiveValue* left = nullptr;
-
-  // TODO(alancutter): Make this code aware of calc lengths.
-  if (image.ImageSlices().Top().IsPercentOrCalc())
-    top = CSSPrimitiveValue::Create(image.ImageSlices().Top().Value(),
-                                    CSSPrimitiveValue::UnitType::kPercentage);
-  else
-    top = CSSPrimitiveValue::Create(image.ImageSlices().Top().Value(),
-                                    CSSPrimitiveValue::UnitType::kNumber);
-
-  if (image.ImageSlices().Right() == image.ImageSlices().Top() &&
-      image.ImageSlices().Bottom() == image.ImageSlices().Top() &&
-      image.ImageSlices().Left() == image.ImageSlices().Top()) {
-    right = top;
-    bottom = top;
-    left = top;
-  } else {
-    if (image.ImageSlices().Right().IsPercentOrCalc())
-      right =
-          CSSPrimitiveValue::Create(image.ImageSlices().Right().Value(),
-                                    CSSPrimitiveValue::UnitType::kPercentage);
-    else
-      right = CSSPrimitiveValue::Create(image.ImageSlices().Right().Value(),
-                                        CSSPrimitiveValue::UnitType::kNumber);
-
-    if (image.ImageSlices().Bottom() == image.ImageSlices().Top() &&
-        image.ImageSlices().Right() == image.ImageSlices().Left()) {
-      bottom = top;
-      left = right;
-    } else {
-      if (image.ImageSlices().Bottom().IsPercentOrCalc())
-        bottom =
-            CSSPrimitiveValue::Create(image.ImageSlices().Bottom().Value(),
-                                      CSSPrimitiveValue::UnitType::kPercentage);
-      else
-        bottom =
-            CSSPrimitiveValue::Create(image.ImageSlices().Bottom().Value(),
-                                      CSSPrimitiveValue::UnitType::kNumber);
-
-      if (image.ImageSlices().Left() == image.ImageSlices().Right()) {
-        left = right;
-      } else {
-        if (image.ImageSlices().Left().IsPercentOrCalc())
-          left = CSSPrimitiveValue::Create(
-              image.ImageSlices().Left().Value(),
-              CSSPrimitiveValue::UnitType::kPercentage);
-        else
-          left =
-              CSSPrimitiveValue::Create(image.ImageSlices().Left().Value(),
-                                        CSSPrimitiveValue::UnitType::kNumber);
-      }
-    }
-  }
-
-  return CSSBorderImageSliceValue::Create(
-      CSSQuadValue::Create(top, right, bottom, left,
-                           CSSQuadValue::kSerializeAsQuad),
-      image.Fill());
-}
-
-static CSSValue* ValueForBorderImageLength(
-    const BorderImageLength& border_image_length,
-    const ComputedStyle& style) {
-  if (border_image_length.IsNumber())
-    return CSSPrimitiveValue::Create(border_image_length.Number(),
-                                     CSSPrimitiveValue::UnitType::kNumber);
-  return CSSValue::Create(border_image_length.length(), style.EffectiveZoom());
-}
-
-static CSSQuadValue* ValueForNinePieceImageQuad(const BorderImageLengthBox& box,
-                                                const ComputedStyle& style) {
-  // Create the slices.
-  CSSValue* top = nullptr;
-  CSSValue* right = nullptr;
-  CSSValue* bottom = nullptr;
-  CSSValue* left = nullptr;
-
-  top = ValueForBorderImageLength(box.Top(), style);
-
-  if (box.Right() == box.Top() && box.Bottom() == box.Top() &&
-      box.Left() == box.Top()) {
-    right = top;
-    bottom = top;
-    left = top;
-  } else {
-    right = ValueForBorderImageLength(box.Right(), style);
-
-    if (box.Bottom() == box.Top() && box.Right() == box.Left()) {
-      bottom = top;
-      left = right;
-    } else {
-      bottom = ValueForBorderImageLength(box.Bottom(), style);
-
-      if (box.Left() == box.Right())
-        left = right;
-      else
-        left = ValueForBorderImageLength(box.Left(), style);
-    }
-  }
-  return CSSQuadValue::Create(top, right, bottom, left,
-                              CSSQuadValue::kSerializeAsQuad);
-}
-
-static CSSValueID ValueForRepeatRule(int rule) {
-  switch (rule) {
-    case kRepeatImageRule:
-      return CSSValueRepeat;
-    case kRoundImageRule:
-      return CSSValueRound;
-    case kSpaceImageRule:
-      return CSSValueSpace;
-    default:
-      return CSSValueStretch;
-  }
-}
-
-static CSSValue* ValueForNinePieceImageRepeat(const NinePieceImage& image) {
-  CSSIdentifierValue* horizontal_repeat = nullptr;
-  CSSIdentifierValue* vertical_repeat = nullptr;
-
-  horizontal_repeat =
-      CSSIdentifierValue::Create(ValueForRepeatRule(image.HorizontalRule()));
-  if (image.HorizontalRule() == image.VerticalRule()) {
-    vertical_repeat = horizontal_repeat;
-  } else {
-    vertical_repeat =
-        CSSIdentifierValue::Create(ValueForRepeatRule(image.VerticalRule()));
-  }
-  return CSSValuePair::Create(horizontal_repeat, vertical_repeat,
-                              CSSValuePair::kDropIdenticalValues);
-}
-
-static CSSValue* ValueForNinePieceImage(const NinePieceImage& image,
-                                        const ComputedStyle& style) {
-  if (!image.HasImage())
-    return CSSIdentifierValue::Create(CSSValueNone);
-
-  // Image first.
-  CSSValue* image_value = nullptr;
-  if (image.GetImage())
-    image_value = image.GetImage()->ComputedCSSValue();
-
-  // Create the image slice.
-  cssvalue::CSSBorderImageSliceValue* image_slices =
-      ValueForNinePieceImageSlice(image);
-
-  // Create the border area slices.
-  CSSValue* border_slices =
-      ValueForNinePieceImageQuad(image.BorderSlices(), style);
-
-  // Create the border outset.
-  CSSValue* outset = ValueForNinePieceImageQuad(image.Outset(), style);
-
-  // Create the repeat rules.
-  CSSValue* repeat = ValueForNinePieceImageRepeat(image);
-
-  return CreateBorderImageValue(image_value, image_slices, border_slices,
-                                outset, repeat);
-}
-
-static CSSValue* ValueForReflection(const StyleReflection* reflection,
-                                    const ComputedStyle& style) {
-  if (!reflection)
-    return CSSIdentifierValue::Create(CSSValueNone);
-
-  CSSPrimitiveValue* offset = nullptr;
-  // TODO(alancutter): Make this work correctly for calc lengths.
-  if (reflection->Offset().IsPercentOrCalc())
-    offset =
-        CSSPrimitiveValue::Create(reflection->Offset().Percent(),
-                                  CSSPrimitiveValue::UnitType::kPercentage);
-  else
-    offset = ZoomAdjustedPixelValue(reflection->Offset().Value(), style);
-
-  CSSIdentifierValue* direction = nullptr;
-  switch (reflection->Direction()) {
-    case kReflectionBelow:
-      direction = CSSIdentifierValue::Create(CSSValueBelow);
-      break;
-    case kReflectionAbove:
-      direction = CSSIdentifierValue::Create(CSSValueAbove);
-      break;
-    case kReflectionLeft:
-      direction = CSSIdentifierValue::Create(CSSValueLeft);
-      break;
-    case kReflectionRight:
-      direction = CSSIdentifierValue::Create(CSSValueRight);
-      break;
-  }
-
-  return CSSReflectValue::Create(
-      direction, offset, ValueForNinePieceImage(reflection->Mask(), style));
-}
-
 static CSSValueList* ValueForItemPositionWithOverflowAlignment(
     const StyleSelfAlignmentData& data) {
   CSSValueList* result = CSSValueList::CreateSpaceSeparated();
@@ -1778,11 +1562,6 @@
   return CSSColorValue::Create(color.Rgb());
 }
 
-static inline AtomicString SerializeAsFragmentIdentifier(
-    const AtomicString& resource) {
-  return "#" + resource;
-}
-
 CSSValue* ComputedStyleCSSValueMapping::ValueForShadowData(
     const ShadowData& shadow,
     const ComputedStyle& style,
@@ -2145,74 +1924,6 @@
       style.Direction(), style.GetWritingMode());
 
   switch (resolved_property.PropertyID()) {
-    case CSSPropertyMaskSourceType: {
-      CSSValueList* list = CSSValueList::CreateCommaSeparated();
-      for (const FillLayer* curr_layer = &style.MaskLayers(); curr_layer;
-           curr_layer = curr_layer->Next())
-        list->Append(*ValueForFillSourceType(curr_layer->MaskSourceType()));
-      return list;
-    }
-    case CSSPropertyWebkitMaskComposite: {
-      CSSValueList* list = CSSValueList::CreateCommaSeparated();
-      const FillLayer* curr_layer =
-          resolved_property.IDEquals(CSSPropertyWebkitMaskComposite)
-              ? &style.MaskLayers()
-              : &style.BackgroundLayers();
-      for (; curr_layer; curr_layer = curr_layer->Next())
-        list->Append(*CSSIdentifierValue::Create(curr_layer->Composite()));
-      return list;
-    }
-    case CSSPropertyBackgroundAttachment: {
-      CSSValueList* list = CSSValueList::CreateCommaSeparated();
-      for (const FillLayer* curr_layer = &style.BackgroundLayers(); curr_layer;
-           curr_layer = curr_layer->Next())
-        list->Append(*CSSIdentifierValue::Create(curr_layer->Attachment()));
-      return list;
-    }
-    case CSSPropertyBackgroundClip:
-    case CSSPropertyBackgroundOrigin:
-    case CSSPropertyWebkitMaskClip:
-    case CSSPropertyWebkitMaskOrigin: {
-      bool is_clip = resolved_property.IDEquals(CSSPropertyBackgroundClip) ||
-                     resolved_property.IDEquals(CSSPropertyWebkitMaskClip);
-      CSSValueList* list = CSSValueList::CreateCommaSeparated();
-      const FillLayer* curr_layer =
-          (resolved_property.IDEquals(CSSPropertyWebkitMaskClip) ||
-           resolved_property.IDEquals(CSSPropertyWebkitMaskOrigin))
-              ? &style.MaskLayers()
-              : &style.BackgroundLayers();
-      for (; curr_layer; curr_layer = curr_layer->Next()) {
-        EFillBox box = is_clip ? curr_layer->Clip() : curr_layer->Origin();
-        list->Append(*CSSIdentifierValue::Create(box));
-      }
-      return list;
-    }
-    case CSSPropertyBackgroundPositionX:
-    case CSSPropertyWebkitMaskPositionX: {
-      CSSValueList* list = CSSValueList::CreateCommaSeparated();
-      const FillLayer* curr_layer =
-          resolved_property.IDEquals(CSSPropertyWebkitMaskPositionX)
-              ? &style.MaskLayers()
-              : &style.BackgroundLayers();
-      for (; curr_layer; curr_layer = curr_layer->Next()) {
-        list->Append(*ComputedStyleUtils::ZoomAdjustedPixelValueForLength(
-            curr_layer->PositionX(), style));
-      }
-      return list;
-    }
-    case CSSPropertyBackgroundPositionY:
-    case CSSPropertyWebkitMaskPositionY: {
-      CSSValueList* list = CSSValueList::CreateCommaSeparated();
-      const FillLayer* curr_layer =
-          resolved_property.IDEquals(CSSPropertyWebkitMaskPositionY)
-              ? &style.MaskLayers()
-              : &style.BackgroundLayers();
-      for (; curr_layer; curr_layer = curr_layer->Next()) {
-        list->Append(*ComputedStyleUtils::ZoomAdjustedPixelValueForLength(
-            curr_layer->PositionY(), style));
-      }
-      return list;
-    }
     case CSSPropertyBorderCollapse:
       if (style.BorderCollapse() == EBorderCollapse::kCollapse)
         return CSSIdentifierValue::Create(CSSValueCollapse);
@@ -2225,10 +1936,6 @@
           *ZoomAdjustedPixelValue(style.VerticalBorderSpacing(), style));
       return list;
     }
-    case CSSPropertyBorderImageSource:
-      if (style.BorderImageSource())
-        return style.BorderImageSource()->ComputedCSSValue();
-      return CSSIdentifierValue::Create(CSSValueNone);
     case CSSPropertyBottom:
       return ValueForPositionOffset(style, resolved_property, layout_object);
     case CSSPropertyWebkitBoxDecorationBreak:
@@ -2244,8 +1951,6 @@
     case CSSPropertyWebkitBoxOrdinalGroup:
       return CSSPrimitiveValue::Create(style.BoxOrdinalGroup(),
                                        CSSPrimitiveValue::UnitType::kNumber);
-    case CSSPropertyWebkitBoxReflect:
-      return ValueForReflection(style.BoxReflect(), style);
     case CSSPropertyBoxShadow:
       return ValueForShadowList(style.BoxShadow(), style, true);
     case CSSPropertyColumnCount:
@@ -2959,32 +2664,6 @@
       list->Append(*CSSIdentifierValue::Create(CSSValueRunning));
       return list;
     }
-    case CSSPropertyWebkitBorderImage:
-      return ValueForNinePieceImage(style.BorderImage(), style);
-    case CSSPropertyBorderImageOutset:
-      return ValueForNinePieceImageQuad(style.BorderImage().Outset(), style);
-    case CSSPropertyBorderImageRepeat:
-      return ValueForNinePieceImageRepeat(style.BorderImage());
-    case CSSPropertyBorderImageSlice:
-      return ValueForNinePieceImageSlice(style.BorderImage());
-    case CSSPropertyBorderImageWidth:
-      return ValueForNinePieceImageQuad(style.BorderImage().BorderSlices(),
-                                        style);
-    case CSSPropertyWebkitMaskBoxImage:
-      return ValueForNinePieceImage(style.MaskBoxImage(), style);
-    case CSSPropertyWebkitMaskBoxImageOutset:
-      return ValueForNinePieceImageQuad(style.MaskBoxImage().Outset(), style);
-    case CSSPropertyWebkitMaskBoxImageRepeat:
-      return ValueForNinePieceImageRepeat(style.MaskBoxImage());
-    case CSSPropertyWebkitMaskBoxImageSlice:
-      return ValueForNinePieceImageSlice(style.MaskBoxImage());
-    case CSSPropertyWebkitMaskBoxImageWidth:
-      return ValueForNinePieceImageQuad(style.MaskBoxImage().BorderSlices(),
-                                        style);
-    case CSSPropertyWebkitMaskBoxImageSource:
-      if (style.MaskBoxImageSource())
-        return style.MaskBoxImageSource()->ComputedCSSValue();
-      return CSSIdentifierValue::Create(CSSValueNone);
     case CSSPropertyPerspective:
       if (!style.HasPerspective())
         return CSSIdentifierValue::Create(CSSValueNone);
@@ -3139,14 +2818,6 @@
       return ValueForFilter(style, style.Filter());
     case CSSPropertyBackdropFilter:
       return ValueForFilter(style, style.BackdropFilter());
-
-    case CSSPropertyBackgroundBlendMode: {
-      CSSValueList* list = CSSValueList::CreateCommaSeparated();
-      for (const FillLayer* curr_layer = &style.BackgroundLayers(); curr_layer;
-           curr_layer = curr_layer->Next())
-        list->Append(*CSSIdentifierValue::Create(curr_layer->BlendMode()));
-      return list;
-    }
     case CSSPropertyBorder: {
       const CSSValue* value =
           Get(GetCSSPropertyBorderTop(), style, layout_object, styled_node,
@@ -3173,8 +2844,6 @@
       return ValuesForShorthandProperty(borderLeftShorthand(), style,
                                         layout_object, styled_node,
                                         allow_visited_style);
-    case CSSPropertyBorderImage:
-      return ValueForNinePieceImage(style.BorderImage(), style);
     case CSSPropertyBorderRadius:
       return ValueForBorderRadiusShorthand(style);
     case CSSPropertyBorderRight:
@@ -3278,30 +2947,10 @@
     case CSSPropertyStrokeOpacity:
       return CSSPrimitiveValue::Create(svg_style.StrokeOpacity(),
                                        CSSPrimitiveValue::UnitType::kNumber);
-    case CSSPropertyMask:
-      if (!svg_style.MaskerResource().IsEmpty())
-        return CSSURIValue::Create(
-            SerializeAsFragmentIdentifier(svg_style.MaskerResource()));
-      return CSSIdentifierValue::Create(CSSValueNone);
     case CSSPropertyFill:
       return AdjustSVGPaintForCurrentColor(
           svg_style.FillPaintType(), svg_style.FillPaintUri(),
           svg_style.FillPaintColor(), style.GetColor());
-    case CSSPropertyMarkerEnd:
-      if (!svg_style.MarkerEndResource().IsEmpty())
-        return CSSURIValue::Create(
-            SerializeAsFragmentIdentifier(svg_style.MarkerEndResource()));
-      return CSSIdentifierValue::Create(CSSValueNone);
-    case CSSPropertyMarkerMid:
-      if (!svg_style.MarkerMidResource().IsEmpty())
-        return CSSURIValue::Create(
-            SerializeAsFragmentIdentifier(svg_style.MarkerMidResource()));
-      return CSSIdentifierValue::Create(CSSValueNone);
-    case CSSPropertyMarkerStart:
-      if (!svg_style.MarkerStartResource().IsEmpty())
-        return CSSURIValue::Create(
-            SerializeAsFragmentIdentifier(svg_style.MarkerStartResource()));
-      return CSSIdentifierValue::Create(CSSValueNone);
     case CSSPropertyStroke:
       return AdjustSVGPaintForCurrentColor(
           svg_style.StrokePaintType(), svg_style.StrokePaintUri(),
diff --git a/third_party/WebKit/Source/core/css/properties/ComputedStyleUtils.cpp b/third_party/WebKit/Source/core/css/properties/ComputedStyleUtils.cpp
index f03358ce..4993a1e 100644
--- a/third_party/WebKit/Source/core/css/properties/ComputedStyleUtils.cpp
+++ b/third_party/WebKit/Source/core/css/properties/ComputedStyleUtils.cpp
@@ -4,10 +4,15 @@
 
 #include "core/css/properties/ComputedStyleUtils.h"
 
+#include "core/css/CSSBorderImage.h"
+#include "core/css/CSSBorderImageSliceValue.h"
 #include "core/css/CSSColorValue.h"
 #include "core/css/CSSIdentifierValue.h"
 #include "core/css/CSSPrimitiveValueMappings.h"
+#include "core/css/CSSQuadValue.h"
+#include "core/css/CSSReflectValue.h"
 #include "core/css/CSSValue.h"
+#include "core/css/CSSValuePair.h"
 #include "core/css/StyleColor.h"
 #include "core/css/ZoomAdjustedPixelValue.h"
 
@@ -101,16 +106,16 @@
     position_list->Append(
         *CSSIdentifierValue::Create(layer.BackgroundXOrigin()));
   }
-  position_list->Append(*ComputedStyleUtils::ZoomAdjustedPixelValueForLength(
-      layer.PositionX(), style));
+  position_list->Append(
+      *ZoomAdjustedPixelValueForLength(layer.PositionX(), style));
   if (layer.IsBackgroundYOriginSet()) {
     DCHECK(property.IDEquals(CSSPropertyBackgroundPosition) ||
            property.IDEquals(CSSPropertyWebkitMaskPosition));
     position_list->Append(
         *CSSIdentifierValue::Create(layer.BackgroundYOrigin()));
   }
-  position_list->Append(*ComputedStyleUtils::ZoomAdjustedPixelValueForLength(
-      layer.PositionY(), style));
+  position_list->Append(
+      *ZoomAdjustedPixelValueForLength(layer.PositionY(), style));
   return position_list;
 }
 
@@ -192,4 +197,236 @@
   return list;
 }
 
+const CSSValue* ComputedStyleUtils::BackgroundPositionXOrWebkitMaskPositionX(
+    const ComputedStyle& style,
+    const FillLayer* curr_layer) {
+  CSSValueList* list = CSSValueList::CreateCommaSeparated();
+  for (; curr_layer; curr_layer = curr_layer->Next()) {
+    list->Append(
+        *ZoomAdjustedPixelValueForLength(curr_layer->PositionX(), style));
+  }
+  return list;
+}
+
+const CSSValue* ComputedStyleUtils::BackgroundPositionYOrWebkitMaskPositionY(
+    const ComputedStyle& style,
+    const FillLayer* curr_layer) {
+  CSSValueList* list = CSSValueList::CreateCommaSeparated();
+  for (; curr_layer; curr_layer = curr_layer->Next()) {
+    list->Append(
+        *ZoomAdjustedPixelValueForLength(curr_layer->PositionY(), style));
+  }
+  return list;
+}
+
+cssvalue::CSSBorderImageSliceValue*
+ComputedStyleUtils::ValueForNinePieceImageSlice(const NinePieceImage& image) {
+  // Create the slices.
+  CSSPrimitiveValue* top = nullptr;
+  CSSPrimitiveValue* right = nullptr;
+  CSSPrimitiveValue* bottom = nullptr;
+  CSSPrimitiveValue* left = nullptr;
+
+  // TODO(alancutter): Make this code aware of calc lengths.
+  if (image.ImageSlices().Top().IsPercentOrCalc()) {
+    top = CSSPrimitiveValue::Create(image.ImageSlices().Top().Value(),
+                                    CSSPrimitiveValue::UnitType::kPercentage);
+  } else {
+    top = CSSPrimitiveValue::Create(image.ImageSlices().Top().Value(),
+                                    CSSPrimitiveValue::UnitType::kNumber);
+  }
+
+  if (image.ImageSlices().Right() == image.ImageSlices().Top() &&
+      image.ImageSlices().Bottom() == image.ImageSlices().Top() &&
+      image.ImageSlices().Left() == image.ImageSlices().Top()) {
+    right = top;
+    bottom = top;
+    left = top;
+  } else {
+    if (image.ImageSlices().Right().IsPercentOrCalc()) {
+      right =
+          CSSPrimitiveValue::Create(image.ImageSlices().Right().Value(),
+                                    CSSPrimitiveValue::UnitType::kPercentage);
+    } else {
+      right = CSSPrimitiveValue::Create(image.ImageSlices().Right().Value(),
+                                        CSSPrimitiveValue::UnitType::kNumber);
+    }
+
+    if (image.ImageSlices().Bottom() == image.ImageSlices().Top() &&
+        image.ImageSlices().Right() == image.ImageSlices().Left()) {
+      bottom = top;
+      left = right;
+    } else {
+      if (image.ImageSlices().Bottom().IsPercentOrCalc()) {
+        bottom =
+            CSSPrimitiveValue::Create(image.ImageSlices().Bottom().Value(),
+                                      CSSPrimitiveValue::UnitType::kPercentage);
+      } else {
+        bottom =
+            CSSPrimitiveValue::Create(image.ImageSlices().Bottom().Value(),
+                                      CSSPrimitiveValue::UnitType::kNumber);
+      }
+
+      if (image.ImageSlices().Left() == image.ImageSlices().Right()) {
+        left = right;
+      } else {
+        if (image.ImageSlices().Left().IsPercentOrCalc()) {
+          left = CSSPrimitiveValue::Create(
+              image.ImageSlices().Left().Value(),
+              CSSPrimitiveValue::UnitType::kPercentage);
+        } else {
+          left =
+              CSSPrimitiveValue::Create(image.ImageSlices().Left().Value(),
+                                        CSSPrimitiveValue::UnitType::kNumber);
+        }
+      }
+    }
+  }
+
+  return CSSBorderImageSliceValue::Create(
+      CSSQuadValue::Create(top, right, bottom, left,
+                           CSSQuadValue::kSerializeAsQuad),
+      image.Fill());
+}
+
+CSSValue* ValueForBorderImageLength(
+    const BorderImageLength& border_image_length,
+    const ComputedStyle& style) {
+  if (border_image_length.IsNumber()) {
+    return CSSPrimitiveValue::Create(border_image_length.Number(),
+                                     CSSPrimitiveValue::UnitType::kNumber);
+  }
+  return CSSValue::Create(border_image_length.length(), style.EffectiveZoom());
+}
+
+CSSQuadValue* ComputedStyleUtils::ValueForNinePieceImageQuad(
+    const BorderImageLengthBox& box,
+    const ComputedStyle& style) {
+  // Create the slices.
+  CSSValue* top = nullptr;
+  CSSValue* right = nullptr;
+  CSSValue* bottom = nullptr;
+  CSSValue* left = nullptr;
+
+  top = ValueForBorderImageLength(box.Top(), style);
+
+  if (box.Right() == box.Top() && box.Bottom() == box.Top() &&
+      box.Left() == box.Top()) {
+    right = top;
+    bottom = top;
+    left = top;
+  } else {
+    right = ValueForBorderImageLength(box.Right(), style);
+
+    if (box.Bottom() == box.Top() && box.Right() == box.Left()) {
+      bottom = top;
+      left = right;
+    } else {
+      bottom = ValueForBorderImageLength(box.Bottom(), style);
+
+      if (box.Left() == box.Right())
+        left = right;
+      else
+        left = ValueForBorderImageLength(box.Left(), style);
+    }
+  }
+  return CSSQuadValue::Create(top, right, bottom, left,
+                              CSSQuadValue::kSerializeAsQuad);
+}
+
+CSSValueID ValueForRepeatRule(int rule) {
+  switch (rule) {
+    case kRepeatImageRule:
+      return CSSValueRepeat;
+    case kRoundImageRule:
+      return CSSValueRound;
+    case kSpaceImageRule:
+      return CSSValueSpace;
+    default:
+      return CSSValueStretch;
+  }
+}
+
+CSSValue* ComputedStyleUtils::ValueForNinePieceImageRepeat(
+    const NinePieceImage& image) {
+  CSSIdentifierValue* horizontal_repeat = nullptr;
+  CSSIdentifierValue* vertical_repeat = nullptr;
+
+  horizontal_repeat =
+      CSSIdentifierValue::Create(ValueForRepeatRule(image.HorizontalRule()));
+  if (image.HorizontalRule() == image.VerticalRule()) {
+    vertical_repeat = horizontal_repeat;
+  } else {
+    vertical_repeat =
+        CSSIdentifierValue::Create(ValueForRepeatRule(image.VerticalRule()));
+  }
+  return CSSValuePair::Create(horizontal_repeat, vertical_repeat,
+                              CSSValuePair::kDropIdenticalValues);
+}
+
+CSSValue* ComputedStyleUtils::ValueForNinePieceImage(
+    const NinePieceImage& image,
+    const ComputedStyle& style) {
+  if (!image.HasImage())
+    return CSSIdentifierValue::Create(CSSValueNone);
+
+  // Image first.
+  CSSValue* image_value = nullptr;
+  if (image.GetImage())
+    image_value = image.GetImage()->ComputedCSSValue();
+
+  // Create the image slice.
+  cssvalue::CSSBorderImageSliceValue* image_slices =
+      ValueForNinePieceImageSlice(image);
+
+  // Create the border area slices.
+  CSSValue* border_slices =
+      ValueForNinePieceImageQuad(image.BorderSlices(), style);
+
+  // Create the border outset.
+  CSSValue* outset = ValueForNinePieceImageQuad(image.Outset(), style);
+
+  // Create the repeat rules.
+  CSSValue* repeat = ValueForNinePieceImageRepeat(image);
+
+  return CreateBorderImageValue(image_value, image_slices, border_slices,
+                                outset, repeat);
+}
+
+CSSValue* ComputedStyleUtils::ValueForReflection(
+    const StyleReflection* reflection,
+    const ComputedStyle& style) {
+  if (!reflection)
+    return CSSIdentifierValue::Create(CSSValueNone);
+
+  CSSPrimitiveValue* offset = nullptr;
+  // TODO(alancutter): Make this work correctly for calc lengths.
+  if (reflection->Offset().IsPercentOrCalc()) {
+    offset =
+        CSSPrimitiveValue::Create(reflection->Offset().Percent(),
+                                  CSSPrimitiveValue::UnitType::kPercentage);
+  } else {
+    offset = ZoomAdjustedPixelValue(reflection->Offset().Value(), style);
+  }
+
+  CSSIdentifierValue* direction = nullptr;
+  switch (reflection->Direction()) {
+    case kReflectionBelow:
+      direction = CSSIdentifierValue::Create(CSSValueBelow);
+      break;
+    case kReflectionAbove:
+      direction = CSSIdentifierValue::Create(CSSValueAbove);
+      break;
+    case kReflectionLeft:
+      direction = CSSIdentifierValue::Create(CSSValueLeft);
+      break;
+    case kReflectionRight:
+      direction = CSSIdentifierValue::Create(CSSValueRight);
+      break;
+  }
+
+  return CSSReflectValue::Create(
+      direction, offset, ValueForNinePieceImage(reflection->Mask(), style));
+}
+
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/css/properties/ComputedStyleUtils.h b/third_party/WebKit/Source/core/css/properties/ComputedStyleUtils.h
index 10d7c73..f73bb74 100644
--- a/third_party/WebKit/Source/core/css/properties/ComputedStyleUtils.h
+++ b/third_party/WebKit/Source/core/css/properties/ComputedStyleUtils.h
@@ -5,6 +5,7 @@
 #ifndef ComputedStyleUtils_h
 #define ComputedStyleUtils_h
 
+#include "core/css/CSSBorderImageSliceValue.h"
 #include "core/css/CSSValueList.h"
 #include "core/style/ComputedStyle.h"
 #include "core/style/ComputedStyleConstants.h"
@@ -12,6 +13,8 @@
 
 namespace blink {
 
+using namespace cssvalue;
+
 class ComputedStyle;
 class CSSValue;
 class StyleColor;
@@ -20,6 +23,10 @@
   STATIC_ONLY(ComputedStyleUtils);
 
  public:
+  static inline AtomicString SerializeAsFragmentIdentifier(
+      const AtomicString& resource) {
+    return "#" + resource;
+  }
   static CSSValue* CurrentColorOrValidColor(const ComputedStyle&,
                                             const StyleColor&);
   static const blink::Color BorderSideColor(const ComputedStyle&,
@@ -48,6 +55,21 @@
       const CSSProperty&,
       const ComputedStyle&,
       const FillLayer*);
+  static const CSSValue* BackgroundPositionXOrWebkitMaskPositionX(
+      const ComputedStyle&,
+      const FillLayer*);
+  static const CSSValue* BackgroundPositionYOrWebkitMaskPositionY(
+      const ComputedStyle&,
+      const FillLayer*);
+  static cssvalue::CSSBorderImageSliceValue* ValueForNinePieceImageSlice(
+      const NinePieceImage&);
+  static CSSQuadValue* ValueForNinePieceImageQuad(const BorderImageLengthBox&,
+                                                  const ComputedStyle&);
+  static CSSValue* ValueForNinePieceImageRepeat(const NinePieceImage&);
+  static CSSValue* ValueForNinePieceImage(const NinePieceImage&,
+                                          const ComputedStyle&);
+  static CSSValue* ValueForReflection(const StyleReflection*,
+                                      const ComputedStyle&);
 };
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/css/properties/longhands/BackgroundAttachmentCustom.cpp b/third_party/WebKit/Source/core/css/properties/longhands/BackgroundAttachmentCustom.cpp
index f9c294f..626888a 100644
--- a/third_party/WebKit/Source/core/css/properties/longhands/BackgroundAttachmentCustom.cpp
+++ b/third_party/WebKit/Source/core/css/properties/longhands/BackgroundAttachmentCustom.cpp
@@ -5,6 +5,7 @@
 #include "core/css/properties/longhands/BackgroundAttachment.h"
 
 #include "core/css/properties/CSSParsingUtils.h"
+#include "core/style/ComputedStyle.h"
 
 namespace blink {
 namespace CSSLonghand {
@@ -17,5 +18,18 @@
       CSSParsingUtils::ConsumeBackgroundAttachment, range);
 }
 
+const CSSValue* BackgroundAttachment::CSSValueFromComputedStyleInternal(
+    const ComputedStyle& style,
+    const SVGComputedStyle&,
+    const LayoutObject*,
+    Node*,
+    bool allow_visited_style) const {
+  CSSValueList* list = CSSValueList::CreateCommaSeparated();
+  for (const FillLayer* curr_layer = &style.BackgroundLayers(); curr_layer;
+       curr_layer = curr_layer->Next())
+    list->Append(*CSSIdentifierValue::Create(curr_layer->Attachment()));
+  return list;
+}
+
 }  // namespace CSSLonghand
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/css/properties/longhands/BackgroundBlendModeCustom.cpp b/third_party/WebKit/Source/core/css/properties/longhands/BackgroundBlendModeCustom.cpp
index 5456e7f1..515eb16 100644
--- a/third_party/WebKit/Source/core/css/properties/longhands/BackgroundBlendModeCustom.cpp
+++ b/third_party/WebKit/Source/core/css/properties/longhands/BackgroundBlendModeCustom.cpp
@@ -5,6 +5,7 @@
 #include "core/css/properties/longhands/BackgroundBlendMode.h"
 
 #include "core/css/properties/CSSParsingUtils.h"
+#include "core/style/ComputedStyle.h"
 
 namespace blink {
 namespace CSSLonghand {
@@ -17,5 +18,18 @@
       CSSParsingUtils::ConsumeBackgroundBlendMode, range);
 }
 
+const CSSValue* BackgroundBlendMode::CSSValueFromComputedStyleInternal(
+    const ComputedStyle& style,
+    const SVGComputedStyle&,
+    const LayoutObject*,
+    Node*,
+    bool allow_visited_style) const {
+  CSSValueList* list = CSSValueList::CreateCommaSeparated();
+  for (const FillLayer* curr_layer = &style.BackgroundLayers(); curr_layer;
+       curr_layer = curr_layer->Next())
+    list->Append(*CSSIdentifierValue::Create(curr_layer->BlendMode()));
+  return list;
+}
+
 }  // namespace CSSLonghand
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/css/properties/longhands/BackgroundClipCustom.cpp b/third_party/WebKit/Source/core/css/properties/longhands/BackgroundClipCustom.cpp
index d964c3a..64102b7 100644
--- a/third_party/WebKit/Source/core/css/properties/longhands/BackgroundClipCustom.cpp
+++ b/third_party/WebKit/Source/core/css/properties/longhands/BackgroundClipCustom.cpp
@@ -5,6 +5,7 @@
 #include "core/css/properties/longhands/BackgroundClip.h"
 
 #include "core/css/properties/CSSParsingUtils.h"
+#include "core/style/ComputedStyle.h"
 
 namespace blink {
 namespace CSSLonghand {
@@ -16,5 +17,20 @@
   return CSSParsingUtils::ParseBackgroundBox(range, local_context);
 }
 
+const CSSValue* BackgroundClip::CSSValueFromComputedStyleInternal(
+    const ComputedStyle& style,
+    const SVGComputedStyle&,
+    const LayoutObject*,
+    Node*,
+    bool allow_visited_style) const {
+  CSSValueList* list = CSSValueList::CreateCommaSeparated();
+  const FillLayer* curr_layer = &style.BackgroundLayers();
+  for (; curr_layer; curr_layer = curr_layer->Next()) {
+    EFillBox box = curr_layer->Clip();
+    list->Append(*CSSIdentifierValue::Create(box));
+  }
+  return list;
+}
+
 }  // namespace CSSLonghand
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/css/properties/longhands/BackgroundOriginCustom.cpp b/third_party/WebKit/Source/core/css/properties/longhands/BackgroundOriginCustom.cpp
index 7844995..9b50b17 100644
--- a/third_party/WebKit/Source/core/css/properties/longhands/BackgroundOriginCustom.cpp
+++ b/third_party/WebKit/Source/core/css/properties/longhands/BackgroundOriginCustom.cpp
@@ -5,6 +5,7 @@
 #include "core/css/properties/longhands/BackgroundOrigin.h"
 
 #include "core/css/properties/CSSParsingUtils.h"
+#include "core/style/ComputedStyle.h"
 
 namespace blink {
 namespace CSSLonghand {
@@ -16,5 +17,20 @@
   return CSSParsingUtils::ParseBackgroundBox(range, local_context);
 }
 
+const CSSValue* BackgroundOrigin::CSSValueFromComputedStyleInternal(
+    const ComputedStyle& style,
+    const SVGComputedStyle&,
+    const LayoutObject*,
+    Node*,
+    bool allow_visited_style) const {
+  CSSValueList* list = CSSValueList::CreateCommaSeparated();
+  const FillLayer* curr_layer = &style.BackgroundLayers();
+  for (; curr_layer; curr_layer = curr_layer->Next()) {
+    EFillBox box = curr_layer->Origin();
+    list->Append(*CSSIdentifierValue::Create(box));
+  }
+  return list;
+}
+
 }  // namespace CSSLonghand
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/css/properties/longhands/BackgroundPositionXCustom.cpp b/third_party/WebKit/Source/core/css/properties/longhands/BackgroundPositionXCustom.cpp
index 877954d..4207eb3 100644
--- a/third_party/WebKit/Source/core/css/properties/longhands/BackgroundPositionXCustom.cpp
+++ b/third_party/WebKit/Source/core/css/properties/longhands/BackgroundPositionXCustom.cpp
@@ -7,6 +7,8 @@
 #include "core/css/parser/CSSParserContext.h"
 #include "core/css/parser/CSSPropertyParserHelpers.h"
 #include "core/css/properties/CSSParsingUtils.h"
+#include "core/css/properties/ComputedStyleUtils.h"
+#include "core/style/ComputedStyle.h"
 
 namespace blink {
 namespace CSSLonghand {
@@ -20,5 +22,16 @@
       range, context.Mode());
 }
 
+const CSSValue* BackgroundPositionX::CSSValueFromComputedStyleInternal(
+    const ComputedStyle& style,
+    const SVGComputedStyle&,
+    const LayoutObject*,
+    Node*,
+    bool allow_visited_style) const {
+  const FillLayer* curr_layer = &style.BackgroundLayers();
+  return ComputedStyleUtils::BackgroundPositionXOrWebkitMaskPositionX(
+      style, curr_layer);
+}
+
 }  // namespace CSSLonghand
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/css/properties/longhands/BackgroundPositionYCustom.cpp b/third_party/WebKit/Source/core/css/properties/longhands/BackgroundPositionYCustom.cpp
index f2f0348..f84eda6 100644
--- a/third_party/WebKit/Source/core/css/properties/longhands/BackgroundPositionYCustom.cpp
+++ b/third_party/WebKit/Source/core/css/properties/longhands/BackgroundPositionYCustom.cpp
@@ -7,6 +7,8 @@
 #include "core/css/parser/CSSParserContext.h"
 #include "core/css/parser/CSSPropertyParserHelpers.h"
 #include "core/css/properties/CSSParsingUtils.h"
+#include "core/css/properties/ComputedStyleUtils.h"
+#include "core/style/ComputedStyle.h"
 
 namespace blink {
 namespace CSSLonghand {
@@ -20,5 +22,16 @@
       range, context.Mode());
 }
 
+const CSSValue* BackgroundPositionY::CSSValueFromComputedStyleInternal(
+    const ComputedStyle& style,
+    const SVGComputedStyle&,
+    const LayoutObject*,
+    Node*,
+    bool allow_visited_style) const {
+  const FillLayer* curr_layer = &style.BackgroundLayers();
+  return ComputedStyleUtils::BackgroundPositionYOrWebkitMaskPositionY(
+      style, curr_layer);
+}
+
 }  // namespace CSSLonghand
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/css/properties/longhands/BorderImageOutsetCustom.cpp b/third_party/WebKit/Source/core/css/properties/longhands/BorderImageOutsetCustom.cpp
index f4f9ccf..db76ebb 100644
--- a/third_party/WebKit/Source/core/css/properties/longhands/BorderImageOutsetCustom.cpp
+++ b/third_party/WebKit/Source/core/css/properties/longhands/BorderImageOutsetCustom.cpp
@@ -5,6 +5,8 @@
 #include "core/css/properties/longhands/BorderImageOutset.h"
 
 #include "core/css/properties/CSSParsingUtils.h"
+#include "core/css/properties/ComputedStyleUtils.h"
+#include "core/style/ComputedStyle.h"
 
 namespace blink {
 namespace CSSLonghand {
@@ -16,5 +18,15 @@
   return CSSParsingUtils::ConsumeBorderImageOutset(range);
 }
 
+const CSSValue* BorderImageOutset::CSSValueFromComputedStyleInternal(
+    const ComputedStyle& style,
+    const SVGComputedStyle&,
+    const LayoutObject*,
+    Node*,
+    bool allow_visited_style) const {
+  return ComputedStyleUtils::ValueForNinePieceImageQuad(
+      style.BorderImage().Outset(), style);
+}
+
 }  // namespace CSSLonghand
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/css/properties/longhands/BorderImageRepeatCustom.cpp b/third_party/WebKit/Source/core/css/properties/longhands/BorderImageRepeatCustom.cpp
index c971548e..1324e090 100644
--- a/third_party/WebKit/Source/core/css/properties/longhands/BorderImageRepeatCustom.cpp
+++ b/third_party/WebKit/Source/core/css/properties/longhands/BorderImageRepeatCustom.cpp
@@ -5,6 +5,8 @@
 #include "core/css/properties/longhands/BorderImageRepeat.h"
 
 #include "core/css/properties/CSSParsingUtils.h"
+#include "core/css/properties/ComputedStyleUtils.h"
+#include "core/style/ComputedStyle.h"
 
 namespace blink {
 namespace CSSLonghand {
@@ -16,5 +18,14 @@
   return CSSParsingUtils::ConsumeBorderImageRepeat(range);
 }
 
+const CSSValue* BorderImageRepeat::CSSValueFromComputedStyleInternal(
+    const ComputedStyle& style,
+    const SVGComputedStyle&,
+    const LayoutObject*,
+    Node*,
+    bool allow_visited_style) const {
+  return ComputedStyleUtils::ValueForNinePieceImageRepeat(style.BorderImage());
+}
+
 }  // namespace CSSLonghand
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/css/properties/longhands/BorderImageSliceCustom.cpp b/third_party/WebKit/Source/core/css/properties/longhands/BorderImageSliceCustom.cpp
index 66bee1d5..1bcfba0 100644
--- a/third_party/WebKit/Source/core/css/properties/longhands/BorderImageSliceCustom.cpp
+++ b/third_party/WebKit/Source/core/css/properties/longhands/BorderImageSliceCustom.cpp
@@ -5,6 +5,8 @@
 #include "core/css/properties/longhands/BorderImageSlice.h"
 
 #include "core/css/properties/CSSParsingUtils.h"
+#include "core/css/properties/ComputedStyleUtils.h"
+#include "core/style/ComputedStyle.h"
 
 namespace blink {
 namespace CSSLonghand {
@@ -17,5 +19,14 @@
       range, CSSParsingUtils::DefaultFill::kNoFill);
 }
 
+const CSSValue* BorderImageSlice::CSSValueFromComputedStyleInternal(
+    const ComputedStyle& style,
+    const SVGComputedStyle&,
+    const LayoutObject*,
+    Node*,
+    bool allow_visited_style) const {
+  return ComputedStyleUtils::ValueForNinePieceImageSlice(style.BorderImage());
+}
+
 }  // namespace CSSLonghand
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/css/properties/longhands/BorderImageSourceCustom.cpp b/third_party/WebKit/Source/core/css/properties/longhands/BorderImageSourceCustom.cpp
index 517a777..e0e1ffd6 100644
--- a/third_party/WebKit/Source/core/css/properties/longhands/BorderImageSourceCustom.cpp
+++ b/third_party/WebKit/Source/core/css/properties/longhands/BorderImageSourceCustom.cpp
@@ -5,6 +5,8 @@
 #include "core/css/properties/longhands/BorderImageSource.h"
 
 #include "core/css/parser/CSSPropertyParserHelpers.h"
+#include "core/css/properties/ComputedStyleUtils.h"
+#include "core/style/ComputedStyle.h"
 
 namespace blink {
 
@@ -19,5 +21,16 @@
   return CSSPropertyParserHelpers::ConsumeImageOrNone(range, &context);
 }
 
+const CSSValue* BorderImageSource::CSSValueFromComputedStyleInternal(
+    const ComputedStyle& style,
+    const SVGComputedStyle&,
+    const LayoutObject*,
+    Node*,
+    bool allow_visited_style) const {
+  if (style.BorderImageSource())
+    return style.BorderImageSource()->ComputedCSSValue();
+  return CSSIdentifierValue::Create(CSSValueNone);
+}
+
 }  // namespace CSSLonghand
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/css/properties/longhands/BorderImageWidthCustom.cpp b/third_party/WebKit/Source/core/css/properties/longhands/BorderImageWidthCustom.cpp
index ff2586d4..9378217 100644
--- a/third_party/WebKit/Source/core/css/properties/longhands/BorderImageWidthCustom.cpp
+++ b/third_party/WebKit/Source/core/css/properties/longhands/BorderImageWidthCustom.cpp
@@ -5,6 +5,8 @@
 #include "core/css/properties/longhands/BorderImageWidth.h"
 
 #include "core/css/properties/CSSParsingUtils.h"
+#include "core/css/properties/ComputedStyleUtils.h"
+#include "core/style/ComputedStyle.h"
 
 namespace blink {
 namespace CSSLonghand {
@@ -16,5 +18,15 @@
   return CSSParsingUtils::ConsumeBorderImageWidth(range);
 }
 
+const CSSValue* BorderImageWidth::CSSValueFromComputedStyleInternal(
+    const ComputedStyle& style,
+    const SVGComputedStyle&,
+    const LayoutObject*,
+    Node*,
+    bool allow_visited_style) const {
+  return ComputedStyleUtils::ValueForNinePieceImageQuad(
+      style.BorderImage().BorderSlices(), style);
+}
+
 }  // namespace CSSLonghand
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/css/properties/longhands/MarkerEndCustom.cpp b/third_party/WebKit/Source/core/css/properties/longhands/MarkerEndCustom.cpp
index 3741a02..0f1127df 100644
--- a/third_party/WebKit/Source/core/css/properties/longhands/MarkerEndCustom.cpp
+++ b/third_party/WebKit/Source/core/css/properties/longhands/MarkerEndCustom.cpp
@@ -7,6 +7,8 @@
 #include "core/css/CSSURIValue.h"
 #include "core/css/parser/CSSParserTokenRange.h"
 #include "core/css/parser/CSSPropertyParserHelpers.h"
+#include "core/css/properties/ComputedStyleUtils.h"
+#include "core/style/ComputedStyle.h"
 
 namespace blink {
 namespace CSSLonghand {
@@ -20,5 +22,19 @@
   return CSSPropertyParserHelpers::ConsumeUrl(range, &context);
 }
 
+const CSSValue* MarkerEnd::CSSValueFromComputedStyleInternal(
+    const ComputedStyle& style,
+    const SVGComputedStyle& svg_style,
+    const LayoutObject*,
+    Node*,
+    bool allow_visited_style) const {
+  if (!svg_style.MarkerEndResource().IsEmpty()) {
+    return CSSURIValue::Create(
+        ComputedStyleUtils::SerializeAsFragmentIdentifier(
+            svg_style.MarkerEndResource()));
+  }
+  return CSSIdentifierValue::Create(CSSValueNone);
+}
+
 }  // namespace CSSLonghand
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/css/properties/longhands/MarkerMidCustom.cpp b/third_party/WebKit/Source/core/css/properties/longhands/MarkerMidCustom.cpp
index 038218c..e93d9d90 100644
--- a/third_party/WebKit/Source/core/css/properties/longhands/MarkerMidCustom.cpp
+++ b/third_party/WebKit/Source/core/css/properties/longhands/MarkerMidCustom.cpp
@@ -7,6 +7,8 @@
 #include "core/css/CSSURIValue.h"
 #include "core/css/parser/CSSParserTokenRange.h"
 #include "core/css/parser/CSSPropertyParserHelpers.h"
+#include "core/css/properties/ComputedStyleUtils.h"
+#include "core/style/ComputedStyle.h"
 
 namespace blink {
 namespace CSSLonghand {
@@ -20,5 +22,19 @@
   return CSSPropertyParserHelpers::ConsumeUrl(range, &context);
 }
 
+const CSSValue* MarkerMid::CSSValueFromComputedStyleInternal(
+    const ComputedStyle& style,
+    const SVGComputedStyle& svg_style,
+    const LayoutObject*,
+    Node*,
+    bool allow_visited_style) const {
+  if (!svg_style.MarkerMidResource().IsEmpty()) {
+    return CSSURIValue::Create(
+        ComputedStyleUtils::SerializeAsFragmentIdentifier(
+            svg_style.MarkerMidResource()));
+  }
+  return CSSIdentifierValue::Create(CSSValueNone);
+}
+
 }  // namespace CSSLonghand
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/css/properties/longhands/MarkerStartCustom.cpp b/third_party/WebKit/Source/core/css/properties/longhands/MarkerStartCustom.cpp
index ccaea50..940be8ee 100644
--- a/third_party/WebKit/Source/core/css/properties/longhands/MarkerStartCustom.cpp
+++ b/third_party/WebKit/Source/core/css/properties/longhands/MarkerStartCustom.cpp
@@ -7,6 +7,8 @@
 #include "core/css/CSSURIValue.h"
 #include "core/css/parser/CSSParserTokenRange.h"
 #include "core/css/parser/CSSPropertyParserHelpers.h"
+#include "core/css/properties/ComputedStyleUtils.h"
+#include "core/style/ComputedStyle.h"
 
 namespace blink {
 namespace CSSLonghand {
@@ -20,5 +22,19 @@
   return CSSPropertyParserHelpers::ConsumeUrl(range, &context);
 }
 
+const CSSValue* MarkerStart::CSSValueFromComputedStyleInternal(
+    const ComputedStyle& style,
+    const SVGComputedStyle& svg_style,
+    const LayoutObject*,
+    Node*,
+    bool allow_visited_style) const {
+  if (!svg_style.MarkerStartResource().IsEmpty()) {
+    return CSSURIValue::Create(
+        ComputedStyleUtils::SerializeAsFragmentIdentifier(
+            svg_style.MarkerStartResource()));
+  }
+  return CSSIdentifierValue::Create(CSSValueNone);
+}
+
 }  // namespace CSSLonghand
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/css/properties/longhands/MaskCustom.cpp b/third_party/WebKit/Source/core/css/properties/longhands/MaskCustom.cpp
index 323272e..82961d4 100644
--- a/third_party/WebKit/Source/core/css/properties/longhands/MaskCustom.cpp
+++ b/third_party/WebKit/Source/core/css/properties/longhands/MaskCustom.cpp
@@ -7,6 +7,8 @@
 #include "core/css/CSSURIValue.h"
 #include "core/css/parser/CSSParserTokenRange.h"
 #include "core/css/parser/CSSPropertyParserHelpers.h"
+#include "core/css/properties/ComputedStyleUtils.h"
+#include "core/style/ComputedStyle.h"
 
 namespace blink {
 namespace CSSLonghand {
@@ -19,5 +21,19 @@
   return CSSPropertyParserHelpers::ConsumeUrl(range, &context);
 }
 
+const CSSValue* Mask::CSSValueFromComputedStyleInternal(
+    const ComputedStyle& style,
+    const SVGComputedStyle& svg_style,
+    const LayoutObject*,
+    Node*,
+    bool allow_visited_style) const {
+  if (!svg_style.MaskerResource().IsEmpty()) {
+    return CSSURIValue::Create(
+        ComputedStyleUtils::SerializeAsFragmentIdentifier(
+            svg_style.MaskerResource()));
+  }
+  return CSSIdentifierValue::Create(CSSValueNone);
+}
+
 }  // namespace CSSLonghand
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/css/properties/longhands/MaskSourceTypeCustom.cpp b/third_party/WebKit/Source/core/css/properties/longhands/MaskSourceTypeCustom.cpp
index f3f455d..225bc26 100644
--- a/third_party/WebKit/Source/core/css/properties/longhands/MaskSourceTypeCustom.cpp
+++ b/third_party/WebKit/Source/core/css/properties/longhands/MaskSourceTypeCustom.cpp
@@ -5,6 +5,7 @@
 #include "core/css/properties/longhands/MaskSourceType.h"
 
 #include "core/css/properties/CSSParsingUtils.h"
+#include "core/style/ComputedStyle.h"
 
 namespace blink {
 namespace CSSLonghand {
@@ -17,5 +18,29 @@
       CSSParsingUtils::ConsumeMaskSourceType, range);
 }
 
+static CSSValue* ValueForFillSourceType(EMaskSourceType type) {
+  switch (type) {
+    case EMaskSourceType::kAlpha:
+      return CSSIdentifierValue::Create(CSSValueAlpha);
+    case EMaskSourceType::kLuminance:
+      return CSSIdentifierValue::Create(CSSValueLuminance);
+  }
+  NOTREACHED();
+  return nullptr;
+}
+
+const CSSValue* MaskSourceType::CSSValueFromComputedStyleInternal(
+    const ComputedStyle& style,
+    const SVGComputedStyle&,
+    const LayoutObject*,
+    Node*,
+    bool allow_visited_style) const {
+  CSSValueList* list = CSSValueList::CreateCommaSeparated();
+  for (const FillLayer* curr_layer = &style.MaskLayers(); curr_layer;
+       curr_layer = curr_layer->Next())
+    list->Append(*ValueForFillSourceType(curr_layer->MaskSourceType()));
+  return list;
+}
+
 }  // namespace CSSLonghand
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/css/properties/longhands/WebkitBorderImageCustom.cpp b/third_party/WebKit/Source/core/css/properties/longhands/WebkitBorderImageCustom.cpp
index fedd761c..b1361175 100644
--- a/third_party/WebKit/Source/core/css/properties/longhands/WebkitBorderImageCustom.cpp
+++ b/third_party/WebKit/Source/core/css/properties/longhands/WebkitBorderImageCustom.cpp
@@ -5,6 +5,8 @@
 #include "core/css/properties/longhands/WebkitBorderImage.h"
 
 #include "core/css/properties/CSSParsingUtils.h"
+#include "core/css/properties/ComputedStyleUtils.h"
+#include "core/style/ComputedStyle.h"
 
 namespace blink {
 namespace CSSLonghand {
@@ -16,5 +18,14 @@
   return CSSParsingUtils::ConsumeWebkitBorderImage(range, context);
 }
 
+const CSSValue* WebkitBorderImage::CSSValueFromComputedStyleInternal(
+    const ComputedStyle& style,
+    const SVGComputedStyle&,
+    const LayoutObject*,
+    Node*,
+    bool allow_visited_style) const {
+  return ComputedStyleUtils::ValueForNinePieceImage(style.BorderImage(), style);
+}
+
 }  // namespace CSSLonghand
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/css/properties/longhands/WebkitBoxReflectCustom.cpp b/third_party/WebKit/Source/core/css/properties/longhands/WebkitBoxReflectCustom.cpp
index a953783..52d349e8 100644
--- a/third_party/WebKit/Source/core/css/properties/longhands/WebkitBoxReflectCustom.cpp
+++ b/third_party/WebKit/Source/core/css/properties/longhands/WebkitBoxReflectCustom.cpp
@@ -9,6 +9,8 @@
 #include "core/css/parser/CSSParserContext.h"
 #include "core/css/parser/CSSPropertyParserHelpers.h"
 #include "core/css/properties/CSSParsingUtils.h"
+#include "core/css/properties/ComputedStyleUtils.h"
+#include "core/style/ComputedStyle.h"
 
 namespace blink {
 namespace {
@@ -50,5 +52,14 @@
   return ConsumeReflect(range, context);
 }
 
+const CSSValue* WebkitBoxReflect::CSSValueFromComputedStyleInternal(
+    const ComputedStyle& style,
+    const SVGComputedStyle&,
+    const LayoutObject*,
+    Node*,
+    bool allow_visited_style) const {
+  return ComputedStyleUtils::ValueForReflection(style.BoxReflect(), style);
+}
+
 }  // namespace CSSLonghand
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/css/properties/longhands/WebkitMaskBoxImageOutsetCustom.cpp b/third_party/WebKit/Source/core/css/properties/longhands/WebkitMaskBoxImageOutsetCustom.cpp
index 569e776..a66380a 100644
--- a/third_party/WebKit/Source/core/css/properties/longhands/WebkitMaskBoxImageOutsetCustom.cpp
+++ b/third_party/WebKit/Source/core/css/properties/longhands/WebkitMaskBoxImageOutsetCustom.cpp
@@ -5,6 +5,8 @@
 #include "core/css/properties/longhands/WebkitMaskBoxImageOutset.h"
 
 #include "core/css/properties/CSSParsingUtils.h"
+#include "core/css/properties/ComputedStyleUtils.h"
+#include "core/style/ComputedStyle.h"
 
 namespace blink {
 namespace CSSLonghand {
@@ -16,5 +18,15 @@
   return CSSParsingUtils::ConsumeBorderImageOutset(range);
 }
 
+const CSSValue* WebkitMaskBoxImageOutset::CSSValueFromComputedStyleInternal(
+    const ComputedStyle& style,
+    const SVGComputedStyle&,
+    const LayoutObject*,
+    Node*,
+    bool allow_visited_style) const {
+  return ComputedStyleUtils::ValueForNinePieceImageQuad(
+      style.MaskBoxImage().Outset(), style);
+}
+
 }  // namespace CSSLonghand
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/css/properties/longhands/WebkitMaskBoxImageRepeatCustom.cpp b/third_party/WebKit/Source/core/css/properties/longhands/WebkitMaskBoxImageRepeatCustom.cpp
index 06e0cb7..b3dab6c 100644
--- a/third_party/WebKit/Source/core/css/properties/longhands/WebkitMaskBoxImageRepeatCustom.cpp
+++ b/third_party/WebKit/Source/core/css/properties/longhands/WebkitMaskBoxImageRepeatCustom.cpp
@@ -5,6 +5,8 @@
 #include "core/css/properties/longhands/WebkitMaskBoxImageRepeat.h"
 
 #include "core/css/properties/CSSParsingUtils.h"
+#include "core/css/properties/ComputedStyleUtils.h"
+#include "core/style/ComputedStyle.h"
 
 namespace blink {
 namespace CSSLonghand {
@@ -16,5 +18,14 @@
   return CSSParsingUtils::ConsumeBorderImageRepeat(range);
 }
 
+const CSSValue* WebkitMaskBoxImageRepeat::CSSValueFromComputedStyleInternal(
+    const ComputedStyle& style,
+    const SVGComputedStyle&,
+    const LayoutObject*,
+    Node*,
+    bool allow_visited_style) const {
+  return ComputedStyleUtils::ValueForNinePieceImageRepeat(style.MaskBoxImage());
+}
+
 }  // namespace CSSLonghand
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/css/properties/longhands/WebkitMaskBoxImageSliceCustom.cpp b/third_party/WebKit/Source/core/css/properties/longhands/WebkitMaskBoxImageSliceCustom.cpp
index 066db924..7f4f552 100644
--- a/third_party/WebKit/Source/core/css/properties/longhands/WebkitMaskBoxImageSliceCustom.cpp
+++ b/third_party/WebKit/Source/core/css/properties/longhands/WebkitMaskBoxImageSliceCustom.cpp
@@ -5,6 +5,8 @@
 #include "core/css/properties/longhands/WebkitMaskBoxImageSlice.h"
 
 #include "core/css/properties/CSSParsingUtils.h"
+#include "core/css/properties/ComputedStyleUtils.h"
+#include "core/style/ComputedStyle.h"
 
 namespace blink {
 namespace CSSLonghand {
@@ -17,5 +19,14 @@
       range, CSSParsingUtils::DefaultFill::kNoFill);
 }
 
+const CSSValue* WebkitMaskBoxImageSlice::CSSValueFromComputedStyleInternal(
+    const ComputedStyle& style,
+    const SVGComputedStyle&,
+    const LayoutObject*,
+    Node*,
+    bool allow_visited_style) const {
+  return ComputedStyleUtils::ValueForNinePieceImageSlice(style.MaskBoxImage());
+}
+
 }  // namespace CSSLonghand
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/css/properties/longhands/WebkitMaskBoxImageSourceCustom.cpp b/third_party/WebKit/Source/core/css/properties/longhands/WebkitMaskBoxImageSourceCustom.cpp
index 28da535..a033e5c 100644
--- a/third_party/WebKit/Source/core/css/properties/longhands/WebkitMaskBoxImageSourceCustom.cpp
+++ b/third_party/WebKit/Source/core/css/properties/longhands/WebkitMaskBoxImageSourceCustom.cpp
@@ -5,6 +5,7 @@
 #include "core/css/properties/longhands/WebkitMaskBoxImageSource.h"
 
 #include "core/css/parser/CSSPropertyParserHelpers.h"
+#include "core/style/ComputedStyle.h"
 
 namespace blink {
 
@@ -19,5 +20,16 @@
   return CSSPropertyParserHelpers::ConsumeImageOrNone(range, &context);
 }
 
+const CSSValue* WebkitMaskBoxImageSource::CSSValueFromComputedStyleInternal(
+    const ComputedStyle& style,
+    const SVGComputedStyle&,
+    const LayoutObject*,
+    Node*,
+    bool allow_visited_style) const {
+  if (style.MaskBoxImageSource())
+    return style.MaskBoxImageSource()->ComputedCSSValue();
+  return CSSIdentifierValue::Create(CSSValueNone);
+}
+
 }  // namespace CSSLonghand
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/css/properties/longhands/WebkitMaskBoxImageWidthCustom.cpp b/third_party/WebKit/Source/core/css/properties/longhands/WebkitMaskBoxImageWidthCustom.cpp
index 89e73cae..926b58b4 100644
--- a/third_party/WebKit/Source/core/css/properties/longhands/WebkitMaskBoxImageWidthCustom.cpp
+++ b/third_party/WebKit/Source/core/css/properties/longhands/WebkitMaskBoxImageWidthCustom.cpp
@@ -5,6 +5,8 @@
 #include "core/css/properties/longhands/WebkitMaskBoxImageWidth.h"
 
 #include "core/css/properties/CSSParsingUtils.h"
+#include "core/css/properties/ComputedStyleUtils.h"
+#include "core/style/ComputedStyle.h"
 
 namespace blink {
 namespace CSSLonghand {
@@ -16,5 +18,15 @@
   return CSSParsingUtils::ConsumeBorderImageWidth(range);
 }
 
+const CSSValue* WebkitMaskBoxImageWidth::CSSValueFromComputedStyleInternal(
+    const ComputedStyle& style,
+    const SVGComputedStyle&,
+    const LayoutObject*,
+    Node*,
+    bool allow_visited_style) const {
+  return ComputedStyleUtils::ValueForNinePieceImageQuad(
+      style.MaskBoxImage().BorderSlices(), style);
+}
+
 }  // namespace CSSLonghand
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/css/properties/longhands/WebkitMaskClipCustom.cpp b/third_party/WebKit/Source/core/css/properties/longhands/WebkitMaskClipCustom.cpp
index 7be5f667..96cc0707 100644
--- a/third_party/WebKit/Source/core/css/properties/longhands/WebkitMaskClipCustom.cpp
+++ b/third_party/WebKit/Source/core/css/properties/longhands/WebkitMaskClipCustom.cpp
@@ -7,6 +7,7 @@
 #include "core/css/parser/CSSParserContext.h"
 #include "core/css/parser/CSSPropertyParserHelpers.h"
 #include "core/css/properties/CSSParsingUtils.h"
+#include "core/style/ComputedStyle.h"
 
 namespace blink {
 namespace CSSLonghand {
@@ -20,5 +21,20 @@
       CSSParsingUtils::AllowTextValue::kAllow);
 }
 
+const CSSValue* WebkitMaskClip::CSSValueFromComputedStyleInternal(
+    const ComputedStyle& style,
+    const SVGComputedStyle&,
+    const LayoutObject*,
+    Node*,
+    bool allow_visited_style) const {
+  CSSValueList* list = CSSValueList::CreateCommaSeparated();
+  const FillLayer* curr_layer = &style.MaskLayers();
+  for (; curr_layer; curr_layer = curr_layer->Next()) {
+    EFillBox box = curr_layer->Clip();
+    list->Append(*CSSIdentifierValue::Create(box));
+  }
+  return list;
+}
+
 }  // namespace CSSLonghand
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/css/properties/longhands/WebkitMaskCompositeCustom.cpp b/third_party/WebKit/Source/core/css/properties/longhands/WebkitMaskCompositeCustom.cpp
index e6ffa050..bbddf25b 100644
--- a/third_party/WebKit/Source/core/css/properties/longhands/WebkitMaskCompositeCustom.cpp
+++ b/third_party/WebKit/Source/core/css/properties/longhands/WebkitMaskCompositeCustom.cpp
@@ -5,6 +5,7 @@
 #include "core/css/properties/longhands/WebkitMaskComposite.h"
 
 #include "core/css/properties/CSSParsingUtils.h"
+#include "core/style/ComputedStyle.h"
 
 namespace blink {
 namespace CSSLonghand {
@@ -17,5 +18,18 @@
       CSSParsingUtils::ConsumeBackgroundComposite, range);
 }
 
+const CSSValue* WebkitMaskComposite::CSSValueFromComputedStyleInternal(
+    const ComputedStyle& style,
+    const SVGComputedStyle&,
+    const LayoutObject*,
+    Node*,
+    bool allow_visited_style) const {
+  CSSValueList* list = CSSValueList::CreateCommaSeparated();
+  const FillLayer* curr_layer = &style.MaskLayers();
+  for (; curr_layer; curr_layer = curr_layer->Next())
+    list->Append(*CSSIdentifierValue::Create(curr_layer->Composite()));
+  return list;
+}
+
 }  // namespace CSSLonghand
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/css/properties/longhands/WebkitMaskOriginCustom.cpp b/third_party/WebKit/Source/core/css/properties/longhands/WebkitMaskOriginCustom.cpp
index 43fb653..af8f815 100644
--- a/third_party/WebKit/Source/core/css/properties/longhands/WebkitMaskOriginCustom.cpp
+++ b/third_party/WebKit/Source/core/css/properties/longhands/WebkitMaskOriginCustom.cpp
@@ -7,6 +7,7 @@
 #include "core/css/parser/CSSParserContext.h"
 #include "core/css/parser/CSSPropertyParserHelpers.h"
 #include "core/css/properties/CSSParsingUtils.h"
+#include "core/style/ComputedStyle.h"
 
 namespace blink {
 namespace CSSLonghand {
@@ -20,5 +21,20 @@
       CSSParsingUtils::AllowTextValue::kForbid);
 }
 
+const CSSValue* WebkitMaskOrigin::CSSValueFromComputedStyleInternal(
+    const ComputedStyle& style,
+    const SVGComputedStyle&,
+    const LayoutObject*,
+    Node*,
+    bool allow_visited_style) const {
+  CSSValueList* list = CSSValueList::CreateCommaSeparated();
+  const FillLayer* curr_layer = &style.MaskLayers();
+  for (; curr_layer; curr_layer = curr_layer->Next()) {
+    EFillBox box = curr_layer->Origin();
+    list->Append(*CSSIdentifierValue::Create(box));
+  }
+  return list;
+}
+
 }  // namespace CSSLonghand
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/css/properties/longhands/WebkitMaskPositionXCustom.cpp b/third_party/WebKit/Source/core/css/properties/longhands/WebkitMaskPositionXCustom.cpp
index 06ac674..9f8671e 100644
--- a/third_party/WebKit/Source/core/css/properties/longhands/WebkitMaskPositionXCustom.cpp
+++ b/third_party/WebKit/Source/core/css/properties/longhands/WebkitMaskPositionXCustom.cpp
@@ -7,6 +7,8 @@
 #include "core/css/parser/CSSParserContext.h"
 #include "core/css/parser/CSSPropertyParserHelpers.h"
 #include "core/css/properties/CSSParsingUtils.h"
+#include "core/css/properties/ComputedStyleUtils.h"
+#include "core/style/ComputedStyle.h"
 
 namespace blink {
 namespace CSSLonghand {
@@ -20,5 +22,16 @@
       range, context.Mode());
 }
 
+const CSSValue* WebkitMaskPositionX::CSSValueFromComputedStyleInternal(
+    const ComputedStyle& style,
+    const SVGComputedStyle&,
+    const LayoutObject*,
+    Node*,
+    bool allow_visited_style) const {
+  const FillLayer* curr_layer = &style.MaskLayers();
+  return ComputedStyleUtils::BackgroundPositionXOrWebkitMaskPositionX(
+      style, curr_layer);
+}
+
 }  // namespace CSSLonghand
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/css/properties/longhands/WebkitMaskPositionYCustom.cpp b/third_party/WebKit/Source/core/css/properties/longhands/WebkitMaskPositionYCustom.cpp
index 493ac4e..6d3fb4b1 100644
--- a/third_party/WebKit/Source/core/css/properties/longhands/WebkitMaskPositionYCustom.cpp
+++ b/third_party/WebKit/Source/core/css/properties/longhands/WebkitMaskPositionYCustom.cpp
@@ -7,6 +7,8 @@
 #include "core/css/parser/CSSParserContext.h"
 #include "core/css/parser/CSSPropertyParserHelpers.h"
 #include "core/css/properties/CSSParsingUtils.h"
+#include "core/css/properties/ComputedStyleUtils.h"
+#include "core/style/ComputedStyle.h"
 
 namespace blink {
 namespace CSSLonghand {
@@ -20,5 +22,16 @@
       range, context.Mode());
 }
 
+const CSSValue* WebkitMaskPositionY::CSSValueFromComputedStyleInternal(
+    const ComputedStyle& style,
+    const SVGComputedStyle&,
+    const LayoutObject*,
+    Node*,
+    bool allow_visited_style) const {
+  const FillLayer* curr_layer = &style.MaskLayers();
+  return ComputedStyleUtils::BackgroundPositionYOrWebkitMaskPositionY(
+      style, curr_layer);
+}
+
 }  // namespace CSSLonghand
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/css/properties/shorthands/BorderImageCustom.cpp b/third_party/WebKit/Source/core/css/properties/shorthands/BorderImageCustom.cpp
index 7edbc168..26369e0b 100644
--- a/third_party/WebKit/Source/core/css/properties/shorthands/BorderImageCustom.cpp
+++ b/third_party/WebKit/Source/core/css/properties/shorthands/BorderImageCustom.cpp
@@ -8,6 +8,8 @@
 #include "core/css/parser/CSSParserContext.h"
 #include "core/css/parser/CSSPropertyParserHelpers.h"
 #include "core/css/properties/CSSParsingUtils.h"
+#include "core/css/properties/ComputedStyleUtils.h"
+#include "core/style/ComputedStyle.h"
 
 namespace blink {
 namespace CSSShorthand {
@@ -54,5 +56,14 @@
   return true;
 }
 
+const CSSValue* BorderImage::CSSValueFromComputedStyleInternal(
+    const ComputedStyle& style,
+    const SVGComputedStyle&,
+    const LayoutObject*,
+    Node*,
+    bool allow_visited_style) const {
+  return ComputedStyleUtils::ValueForNinePieceImage(style.BorderImage(), style);
+}
+
 }  // namespace CSSShorthand
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/css/properties/shorthands/WebkitMaskBoxImageCustom.cpp b/third_party/WebKit/Source/core/css/properties/shorthands/WebkitMaskBoxImageCustom.cpp
index bd5177cc..b414226 100644
--- a/third_party/WebKit/Source/core/css/properties/shorthands/WebkitMaskBoxImageCustom.cpp
+++ b/third_party/WebKit/Source/core/css/properties/shorthands/WebkitMaskBoxImageCustom.cpp
@@ -8,6 +8,8 @@
 #include "core/css/parser/CSSParserContext.h"
 #include "core/css/parser/CSSPropertyParserHelpers.h"
 #include "core/css/properties/CSSParsingUtils.h"
+#include "core/css/properties/ComputedStyleUtils.h"
+#include "core/style/ComputedStyle.h"
 
 namespace blink {
 namespace CSSShorthand {
@@ -54,5 +56,15 @@
   return true;
 }
 
+const CSSValue* WebkitMaskBoxImage::CSSValueFromComputedStyleInternal(
+    const ComputedStyle& style,
+    const SVGComputedStyle&,
+    const LayoutObject*,
+    Node*,
+    bool allow_visited_style) const {
+  return ComputedStyleUtils::ValueForNinePieceImage(style.MaskBoxImage(),
+                                                    style);
+}
+
 }  // namespace CSSShorthand
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/dom/ContainerNode.cpp b/third_party/WebKit/Source/core/dom/ContainerNode.cpp
index 18ee0c7..c4214efc 100644
--- a/third_party/WebKit/Source/core/dom/ContainerNode.cpp
+++ b/third_party/WebKit/Source/core/dom/ContainerNode.cpp
@@ -1649,7 +1649,8 @@
   if (!GetDocument().ShouldInvalidateNodeListCaches(attr_name))
     return;
 
-  GetDocument().InvalidateNodeListCaches(attr_name);
+  if (isConnected())
+    GetDocument().InvalidateNodeListCaches(attr_name);
 
   for (ContainerNode* node = this; node; node = node->parentNode()) {
     if (NodeListsNodeData* lists = node->NodeLists())
diff --git a/third_party/WebKit/Source/core/fileapi/Blob.cpp b/third_party/WebKit/Source/core/fileapi/Blob.cpp
index 60ec891..e48329f6 100644
--- a/third_party/WebKit/Source/core/fileapi/Blob.cpp
+++ b/third_party/WebKit/Source/core/fileapi/Blob.cpp
@@ -193,6 +193,10 @@
   return BlobURLRegistry::Registry();
 }
 
+mojom::blink::BlobPtr Blob::AsMojoBlob() {
+  return blob_data_handle_->CloneBlobPtr();
+}
+
 // static
 String Blob::NormalizeType(const String& type) {
   if (type.IsNull())
diff --git a/third_party/WebKit/Source/core/fileapi/Blob.h b/third_party/WebKit/Source/core/fileapi/Blob.h
index 52b96ae..2e6fd23 100644
--- a/third_party/WebKit/Source/core/fileapi/Blob.h
+++ b/third_party/WebKit/Source/core/fileapi/Blob.h
@@ -112,6 +112,7 @@
 
   // URLRegistrable to support PublicURLs.
   URLRegistry& Registry() const final;
+  mojom::blink::BlobPtr AsMojoBlob() final;
 
   // ImageBitmapSource implementation
   bool IsBlob() const override { return true; }
diff --git a/third_party/WebKit/Source/core/frame/BUILD.gn b/third_party/WebKit/Source/core/frame/BUILD.gn
index 6f3c8e12..8bfc619 100644
--- a/third_party/WebKit/Source/core/frame/BUILD.gn
+++ b/third_party/WebKit/Source/core/frame/BUILD.gn
@@ -75,6 +75,8 @@
     "Navigator.h",
     "NavigatorConcurrentHardware.cpp",
     "NavigatorConcurrentHardware.h",
+    "NavigatorDeviceMemory.cpp",
+    "NavigatorDeviceMemory.h",
     "NavigatorID.cpp",
     "NavigatorID.h",
     "NavigatorLanguage.cpp",
diff --git a/third_party/WebKit/Source/core/frame/Navigator.cpp b/third_party/WebKit/Source/core/frame/Navigator.cpp
index 250b74e..7f1b8df1 100644
--- a/third_party/WebKit/Source/core/frame/Navigator.cpp
+++ b/third_party/WebKit/Source/core/frame/Navigator.cpp
@@ -34,7 +34,6 @@
 #include "core/page/Page.h"
 #include "platform/Language.h"
 #include "platform/MemoryCoordinator.h"
-#include "third_party/WebKit/common/device_memory/approximated_device_memory.h"
 
 namespace blink {
 
@@ -52,10 +51,6 @@
   return "Google Inc.";
 }
 
-float Navigator::deviceMemory() const {
-  return ApproximatedDeviceMemory::GetApproximatedDeviceMemory();
-}
-
 String Navigator::vendorSub() const {
   return "";
 }
diff --git a/third_party/WebKit/Source/core/frame/Navigator.h b/third_party/WebKit/Source/core/frame/Navigator.h
index ec6c7abf..e9130bd8 100644
--- a/third_party/WebKit/Source/core/frame/Navigator.h
+++ b/third_party/WebKit/Source/core/frame/Navigator.h
@@ -23,6 +23,7 @@
 #include "core/CoreExport.h"
 #include "core/dom/ContextLifecycleObserver.h"
 #include "core/frame/NavigatorConcurrentHardware.h"
+#include "core/frame/NavigatorDeviceMemory.h"
 #include "core/frame/NavigatorID.h"
 #include "core/frame/NavigatorLanguage.h"
 #include "core/frame/NavigatorOnLine.h"
@@ -37,6 +38,7 @@
 
 class CORE_EXPORT Navigator final : public ScriptWrappable,
                                     public NavigatorConcurrentHardware,
+                                    public NavigatorDeviceMemory,
                                     public NavigatorID,
                                     public NavigatorLanguage,
                                     public NavigatorOnLine,
@@ -53,7 +55,6 @@
 
   bool webdriver() const { return true; }
 
-  float deviceMemory() const;
   String productSub() const;
   String vendor() const;
   String vendorSub() const;
diff --git a/third_party/WebKit/Source/core/frame/Navigator.idl b/third_party/WebKit/Source/core/frame/Navigator.idl
index 622910d..7126b21 100644
--- a/third_party/WebKit/Source/core/frame/Navigator.idl
+++ b/third_party/WebKit/Source/core/frame/Navigator.idl
@@ -30,13 +30,11 @@
     [MeasureAs=NavigatorProductSub] readonly attribute DOMString productSub;
     // https://www.w3.org/Bugs/Public/show_bug.cgi?id=27786
     [MeasureAs=NavigatorVendor] readonly attribute DOMString vendor;
-    // https://github.com/w3c/device-memory#the-web-exposed-api
-    [MeasureAs=NavigatorDeviceMemory,RuntimeEnabled=NavigatorDeviceMemory,SecureContext]
-    readonly attribute float deviceMemory;
 };
 
 Navigator implements NavigatorConcurrentHardware;
 Navigator implements NavigatorCookies;
+Navigator implements NavigatorDeviceMemory;
 Navigator implements NavigatorID;
 Navigator implements NavigatorLanguage;
 Navigator implements NavigatorOnLine;
diff --git a/third_party/WebKit/Source/core/frame/NavigatorDeviceMemory.cpp b/third_party/WebKit/Source/core/frame/NavigatorDeviceMemory.cpp
new file mode 100644
index 0000000..fe66333
--- /dev/null
+++ b/third_party/WebKit/Source/core/frame/NavigatorDeviceMemory.cpp
@@ -0,0 +1,15 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "core/frame/NavigatorDeviceMemory.h"
+
+#include "third_party/WebKit/common/device_memory/approximated_device_memory.h"
+
+namespace blink {
+
+float NavigatorDeviceMemory::deviceMemory() const {
+  return ApproximatedDeviceMemory::GetApproximatedDeviceMemory();
+}
+
+}  // namespace blink
diff --git a/third_party/WebKit/Source/core/frame/NavigatorDeviceMemory.h b/third_party/WebKit/Source/core/frame/NavigatorDeviceMemory.h
new file mode 100644
index 0000000..2326711
--- /dev/null
+++ b/third_party/WebKit/Source/core/frame/NavigatorDeviceMemory.h
@@ -0,0 +1,19 @@
+// Copyright 2018 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 NavigatorDeviceMemory_h
+#define NavigatorDeviceMemory_h
+
+#include "core/CoreExport.h"
+
+namespace blink {
+
+class CORE_EXPORT NavigatorDeviceMemory {
+ public:
+  float deviceMemory() const;
+};
+
+}  // namespace blink
+
+#endif  // NavigatorDeviceMemory_h
diff --git a/third_party/WebKit/Source/core/frame/NavigatorDeviceMemory.idl b/third_party/WebKit/Source/core/frame/NavigatorDeviceMemory.idl
new file mode 100644
index 0000000..a0c717c
--- /dev/null
+++ b/third_party/WebKit/Source/core/frame/NavigatorDeviceMemory.idl
@@ -0,0 +1,13 @@
+// Copyright 2018 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.
+
+// https://github.com/w3c/device-memory#the-web-exposed-api
+
+[
+    NoInterfaceObject,
+    Exposed=(Window,Worker)
+] interface NavigatorDeviceMemory {
+    [MeasureAs=NavigatorDeviceMemory,RuntimeEnabled=NavigatorDeviceMemory,SecureContext]
+    readonly attribute float deviceMemory;
+};
diff --git a/third_party/WebKit/Source/core/html/PublicURLManager.cpp b/third_party/WebKit/Source/core/html/PublicURLManager.cpp
index 3da5260..19212ff 100644
--- a/third_party/WebKit/Source/core/html/PublicURLManager.cpp
+++ b/third_party/WebKit/Source/core/html/PublicURLManager.cpp
@@ -27,7 +27,9 @@
 #include "core/html/PublicURLManager.h"
 
 #include "core/html/URLRegistry.h"
+#include "platform/blob/BlobData.h"
 #include "platform/blob/BlobURL.h"
+#include "platform/runtime_enabled_features.h"
 #include "platform/weborigin/KURL.h"
 #include "platform/wtf/Vector.h"
 #include "platform/wtf/text/StringHash.h"
@@ -43,14 +45,25 @@
 PublicURLManager::PublicURLManager(ExecutionContext* context)
     : ContextLifecycleObserver(context), is_stopped_(false) {}
 
-String PublicURLManager::RegisterURL(ExecutionContext* context,
-                                     URLRegistrable* registrable) {
-  SecurityOrigin* origin = context->GetMutableSecurityOrigin();
+String PublicURLManager::RegisterURL(URLRegistrable* registrable) {
+  if (is_stopped_)
+    return String();
+
+  SecurityOrigin* origin = GetExecutionContext()->GetMutableSecurityOrigin();
   const KURL& url = BlobURL::CreatePublicURL(origin);
   DCHECK(!url.IsEmpty());
   const String& url_string = url.GetString();
 
-  if (!is_stopped_) {
+  mojom::blink::BlobPtr blob;
+  if (RuntimeEnabledFeatures::MojoBlobURLsEnabled())
+    blob = registrable->AsMojoBlob();
+  if (blob) {
+    if (!url_store_) {
+      BlobDataHandle::GetBlobRegistry()->URLStoreForOrigin(
+          origin, MakeRequest(&url_store_));
+    }
+    url_store_->Register(std::move(blob), url);
+  } else {
     URLRegistry* registry = &registrable->Registry();
     registry->RegisterURL(origin, url, registrable);
     url_to_registry_.insert(url_string, registry);
@@ -60,6 +73,13 @@
 }
 
 void PublicURLManager::Revoke(const KURL& url) {
+  if (RuntimeEnabledFeatures::MojoBlobURLsEnabled() && !is_stopped_) {
+    if (!url_store_) {
+      BlobDataHandle::GetBlobRegistry()->URLStoreForOrigin(
+          GetExecutionContext()->GetSecurityOrigin(), MakeRequest(&url_store_));
+    }
+    url_store_->Revoke(url);
+  }
   auto it = url_to_registry_.find(url.GetString());
   if (it == url_to_registry_.end())
     return;
@@ -76,6 +96,8 @@
     url_registry.value->UnregisterURL(KURL(url_registry.key));
 
   url_to_registry_.clear();
+
+  url_store_.reset();
 }
 
 void PublicURLManager::Trace(blink::Visitor* visitor) {
diff --git a/third_party/WebKit/Source/core/html/PublicURLManager.h b/third_party/WebKit/Source/core/html/PublicURLManager.h
index 65a0d0a..5be8b3b9 100644
--- a/third_party/WebKit/Source/core/html/PublicURLManager.h
+++ b/third_party/WebKit/Source/core/html/PublicURLManager.h
@@ -31,6 +31,7 @@
 #include "platform/wtf/HashMap.h"
 #include "platform/wtf/HashSet.h"
 #include "platform/wtf/text/WTFString.h"
+#include "third_party/WebKit/common/blob/blob_url_store.mojom-blink.h"
 
 namespace blink {
 
@@ -50,7 +51,7 @@
   // Generates a new Blob URL and registers the URLRegistrable to the
   // corresponding URLRegistry with the Blob URL. Returns the serialization
   // of the Blob URL.
-  String RegisterURL(ExecutionContext*, URLRegistrable*);
+  String RegisterURL(URLRegistrable*);
   // Revokes the given URL.
   void Revoke(const KURL&);
 
@@ -68,6 +69,8 @@
   URLToRegistryMap url_to_registry_;
 
   bool is_stopped_;
+
+  mojom::blink::BlobURLStoreAssociatedPtr url_store_;
 };
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/html/URLRegistry.h b/third_party/WebKit/Source/core/html/URLRegistry.h
index 87e420f7..83ffb72d 100644
--- a/third_party/WebKit/Source/core/html/URLRegistry.h
+++ b/third_party/WebKit/Source/core/html/URLRegistry.h
@@ -33,6 +33,7 @@
 
 #include "core/CoreExport.h"
 #include "platform/wtf/text/WTFString.h"
+#include "third_party/WebKit/common/blob/blob.mojom-blink.h"
 
 namespace blink {
 
@@ -44,6 +45,7 @@
  public:
   virtual ~URLRegistrable() {}
   virtual URLRegistry& Registry() const = 0;
+  virtual mojom::blink::BlobPtr AsMojoBlob() { return nullptr; }
 };
 
 class CORE_EXPORT URLRegistry {
diff --git a/third_party/WebKit/Source/core/html/canvas/ImageElementBase.cpp b/third_party/WebKit/Source/core/html/canvas/ImageElementBase.cpp
index 8cd3a37..80c3645 100644
--- a/third_party/WebKit/Source/core/html/canvas/ImageElementBase.cpp
+++ b/third_party/WebKit/Source/core/html/canvas/ImageElementBase.cpp
@@ -60,8 +60,8 @@
   if (source_image->IsSVGImage()) {
     UseCounter::Count(GetElement().GetDocument(), WebFeature::kSVGInCanvas2D);
     SVGImage* svg_image = ToSVGImage(source_image.get());
-    IntSize image_size =
-        RoundedIntSize(svg_image->ConcreteObjectSize(default_object_size));
+    LayoutSize image_size =
+        RoundedLayoutSize(svg_image->ConcreteObjectSize(default_object_size));
     source_image = SVGImageForContainer::Create(
         svg_image, image_size, 1,
         GetElement().GetDocument().CompleteURL(GetElement().ImageSourceURL()));
diff --git a/third_party/WebKit/Source/core/html/media/HTMLVideoElement.cpp b/third_party/WebKit/Source/core/html/media/HTMLVideoElement.cpp
index 88b7971..e0d4906 100644
--- a/third_party/WebKit/Source/core/html/media/HTMLVideoElement.cpp
+++ b/third_party/WebKit/Source/core/html/media/HTMLVideoElement.cpp
@@ -44,8 +44,8 @@
 #include "core/layout/LayoutImage.h"
 #include "core/layout/LayoutVideo.h"
 #include "platform/Histogram.h"
+#include "platform/graphics/CanvasResourceProvider.h"
 #include "platform/graphics/GraphicsContext.h"
-#include "platform/graphics/ImageBuffer.h"
 #include "platform/graphics/gpu/Extensions3DUtil.h"
 #include "platform/runtime_enabled_features.h"
 #include "public/platform/WebCanvas.h"
@@ -451,17 +451,18 @@
 
   IntSize intrinsic_size(videoWidth(), videoHeight());
   // FIXME: Not sure if we dhould we be doing anything with the AccelerationHint
-  // argument here?
-  std::unique_ptr<ImageBuffer> image_buffer =
-      ImageBuffer::Create(intrinsic_size);
-  if (!image_buffer) {
+  // argument here? Currently we use unacceleration mode.
+  std::unique_ptr<CanvasResourceProvider> resource_provider =
+      CanvasResourceProvider::Create(
+          intrinsic_size, CanvasResourceProvider::kSoftwareResourceUsage);
+  if (!resource_provider) {
     *status = kInvalidSourceImageStatus;
     return nullptr;
   }
 
-  PaintCurrentFrame(image_buffer->Canvas(),
+  PaintCurrentFrame(resource_provider->Canvas(),
                     IntRect(IntPoint(0, 0), intrinsic_size), nullptr);
-  scoped_refptr<Image> snapshot = image_buffer->NewImageSnapshot();
+  scoped_refptr<Image> snapshot = resource_provider->Snapshot();
   if (!snapshot) {
     *status = kInvalidSourceImageStatus;
     return nullptr;
diff --git a/third_party/WebKit/Source/core/html/parser/HTMLPreloadScannerTest.cpp b/third_party/WebKit/Source/core/html/parser/HTMLPreloadScannerTest.cpp
index eec73a95..f50b666 100644
--- a/third_party/WebKit/Source/core/html/parser/HTMLPreloadScannerTest.cpp
+++ b/third_party/WebKit/Source/core/html/parser/HTMLPreloadScannerTest.cpp
@@ -913,7 +913,7 @@
        "<link rel=preload href=bla as=font type='font/bla'>", nullptr,
        "http://example.test/", Resource::kFont, 0},
       {"http://example.test", "<link rel=preload href=bla as=video>", "bla",
-       "http://example.test/", Resource::kMedia, 0},
+       "http://example.test/", Resource::kVideo, 0},
       {"http://example.test", "<link rel=preload href=bla as=track>", "bla",
        "http://example.test/", Resource::kTextTrack, 0},
       {"http://example.test",
diff --git a/third_party/WebKit/Source/core/imagebitmap/ImageBitmap.cpp b/third_party/WebKit/Source/core/imagebitmap/ImageBitmap.cpp
index 5299c3c..194ee6ed 100644
--- a/third_party/WebKit/Source/core/imagebitmap/ImageBitmap.cpp
+++ b/third_party/WebKit/Source/core/imagebitmap/ImageBitmap.cpp
@@ -12,7 +12,7 @@
 #include "core/offscreencanvas/OffscreenCanvas.h"
 #include "platform/CrossThreadFunctional.h"
 #include "platform/graphics/CanvasColorParams.h"
-#include "platform/graphics/UnacceleratedStaticBitmapImage.h"
+#include "platform/graphics/CanvasResourceProvider.h"
 #include "platform/graphics/skia/SkiaUtils.h"
 #include "platform/image-decoders/ImageDecoder.h"
 #include "platform/threading/BackgroundTaskRunner.h"
@@ -510,17 +510,18 @@
   if (DstBufferSizeHasOverflow(parsed_options))
     return;
 
-  std::unique_ptr<ImageBuffer> buffer =
-      ImageBuffer::Create(IntSize(video->videoWidth(), video->videoHeight()),
-                          kDoNotInitializeImagePixels);
-  if (!buffer)
+  std::unique_ptr<CanvasResourceProvider> resource_provider =
+      CanvasResourceProvider::Create(
+          IntSize(video->videoWidth(), video->videoHeight()),
+          CanvasResourceProvider::kSoftwareResourceUsage);
+  if (!resource_provider)
     return;
 
   video->PaintCurrentFrame(
-      buffer->Canvas(),
+      resource_provider->Canvas(),
       IntRect(IntPoint(), IntSize(video->videoWidth(), video->videoHeight())),
       nullptr);
-  scoped_refptr<StaticBitmapImage> input = buffer->NewImageSnapshot();
+  scoped_refptr<StaticBitmapImage> input = resource_provider->Snapshot();
   image_ = CropImageAndApplyColorSpaceConversion(input, parsed_options);
   if (!image_)
     return;
diff --git a/third_party/WebKit/Source/core/inspector/InspectorPageAgent.cpp b/third_party/WebKit/Source/core/inspector/InspectorPageAgent.cpp
index 95709ba2..ce94001 100644
--- a/third_party/WebKit/Source/core/inspector/InspectorPageAgent.cpp
+++ b/third_party/WebKit/Source/core/inspector/InspectorPageAgent.cpp
@@ -413,7 +413,8 @@
       return InspectorPageAgent::kImageResource;
     case Resource::kFont:
       return InspectorPageAgent::kFontResource;
-    case Resource::kMedia:
+    case Resource::kAudio:
+    case Resource::kVideo:
       return InspectorPageAgent::kMediaResource;
     case Resource::kManifest:
       return InspectorPageAgent::kManifestResource;
diff --git a/third_party/WebKit/Source/core/layout/LayoutImage.cpp b/third_party/WebKit/Source/core/layout/LayoutImage.cpp
index 3e0cc70..8dababa8 100644
--- a/third_party/WebKit/Source/core/layout/LayoutImage.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutImage.cpp
@@ -137,7 +137,7 @@
     CanDeferInvalidation defer) {
   LayoutSize old_intrinsic_size = IntrinsicSize();
   LayoutSize new_intrinsic_size =
-      image_resource_->ImageSize(Style()->EffectiveZoom());
+      RoundedLayoutSize(image_resource_->ImageSize(Style()->EffectiveZoom()));
   UpdateIntrinsicSizeIfNeeded(new_intrinsic_size);
 
   // In the case of generated image content using :before/:after/content, we
diff --git a/third_party/WebKit/Source/core/layout/LayoutImageResource.cpp b/third_party/WebKit/Source/core/layout/LayoutImageResource.cpp
index 55c48c3..9e0be1926 100644
--- a/third_party/WebKit/Source/core/layout/LayoutImageResource.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutImageResource.cpp
@@ -92,19 +92,20 @@
   return cached_image_ && cached_image_->GetImage()->HasRelativeSize();
 }
 
-LayoutSize LayoutImageResource::ImageSize(float multiplier) const {
+FloatSize LayoutImageResource::ImageSize(float multiplier) const {
   if (!cached_image_)
-    return LayoutSize();
-  LayoutSize size(cached_image_->IntrinsicSize(
+    return FloatSize();
+  FloatSize size(cached_image_->IntrinsicSize(
       LayoutObject::ShouldRespectImageOrientation(layout_object_)));
   if (multiplier != 1 && !ImageHasRelativeSize()) {
     // Don't let images that have a width/height >= 1 shrink below 1 when
     // zoomed.
-    LayoutSize minimum_size(
-        size.Width() > LayoutUnit() ? LayoutUnit(1) : LayoutUnit(),
-        size.Height() > LayoutUnit() ? LayoutUnit(1) : LayoutUnit());
+    FloatSize minimum_size(size.Width() > 0 ? 1 : 0, size.Height() > 0 ? 1 : 0);
     size.Scale(multiplier);
-    size.ClampToMinimumSize(minimum_size);
+    if (size.Width() < minimum_size.Width())
+      size.SetWidth(minimum_size.Width());
+    if (size.Height() < minimum_size.Height())
+      size.SetHeight(minimum_size.Height());
   }
   if (layout_object_ && layout_object_->IsLayoutImage() && size.Width() &&
       size.Height())
@@ -136,7 +137,7 @@
 }
 
 scoped_refptr<Image> LayoutImageResource::GetImage(
-    const IntSize& container_size) const {
+    const LayoutSize& container_size) const {
   if (!cached_image_)
     return Image::NullImage();
 
diff --git a/third_party/WebKit/Source/core/layout/LayoutImageResource.h b/third_party/WebKit/Source/core/layout/LayoutImageResource.h
index 4d95894e..09cc5ab 100644
--- a/third_party/WebKit/Source/core/layout/LayoutImageResource.h
+++ b/third_party/WebKit/Source/core/layout/LayoutImageResource.h
@@ -53,7 +53,7 @@
   void ResetAnimation();
   bool MaybeAnimated() const;
 
-  virtual scoped_refptr<Image> GetImage(const IntSize&) const;
+  virtual scoped_refptr<Image> GetImage(const LayoutSize&) const;
   virtual bool ErrorOccurred() const {
     return cached_image_ && cached_image_->ErrorOccurred();
   }
@@ -64,7 +64,7 @@
 
   virtual bool ImageHasRelativeSize() const;
 
-  virtual LayoutSize ImageSize(float multiplier) const;
+  virtual FloatSize ImageSize(float multiplier) const;
 
   virtual WrappedImagePtr ImagePtr() const { return cached_image_.Get(); }
 
diff --git a/third_party/WebKit/Source/core/layout/LayoutImageResourceStyleImage.cpp b/third_party/WebKit/Source/core/layout/LayoutImageResourceStyleImage.cpp
index b8419f52..62e0995 100644
--- a/third_party/WebKit/Source/core/layout/LayoutImageResourceStyleImage.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutImageResourceStyleImage.cpp
@@ -59,7 +59,7 @@
 }
 
 scoped_refptr<Image> LayoutImageResourceStyleImage::GetImage(
-    const IntSize& size) const {
+    const LayoutSize& size) const {
   // Generated content may trigger calls to image() while we're still pending,
   // don't assert but gracefully exit.
   if (style_image_->IsPendingImage())
@@ -68,7 +68,7 @@
                                 layout_object_->StyleRef(), size);
 }
 
-LayoutSize LayoutImageResourceStyleImage::ImageSize(float multiplier) const {
+FloatSize LayoutImageResourceStyleImage::ImageSize(float multiplier) const {
   // TODO(davve): Find out the correct default object size in this context.
   return style_image_->ImageSize(layout_object_->GetDocument(), multiplier,
                                  LayoutSize(LayoutReplaced::kDefaultWidth,
diff --git a/third_party/WebKit/Source/core/layout/LayoutImageResourceStyleImage.h b/third_party/WebKit/Source/core/layout/LayoutImageResourceStyleImage.h
index 0d0e863..74a3766 100644
--- a/third_party/WebKit/Source/core/layout/LayoutImageResourceStyleImage.h
+++ b/third_party/WebKit/Source/core/layout/LayoutImageResourceStyleImage.h
@@ -46,13 +46,13 @@
   void Shutdown() override;
 
   bool HasImage() const override { return true; }
-  scoped_refptr<Image> GetImage(const IntSize&) const override;
+  scoped_refptr<Image> GetImage(const LayoutSize&) const override;
   bool ErrorOccurred() const override { return style_image_->ErrorOccurred(); }
 
   bool ImageHasRelativeSize() const override {
     return style_image_->ImageHasRelativeSize();
   }
-  LayoutSize ImageSize(float multiplier) const override;
+  FloatSize ImageSize(float multiplier) const override;
   WrappedImagePtr ImagePtr() const override { return style_image_->Data(); }
 
   void Trace(blink::Visitor*) override;
diff --git a/third_party/WebKit/Source/core/layout/LayoutListMarker.cpp b/third_party/WebKit/Source/core/layout/LayoutListMarker.cpp
index c6597dd..1caffac6 100644
--- a/third_party/WebKit/Source/core/layout/LayoutListMarker.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutListMarker.cpp
@@ -75,8 +75,9 @@
   // marker box.
   LayoutUnit bullet_width =
       font_data->GetFontMetrics().Ascent() / LayoutUnit(2);
-  return image_->ImageSize(GetDocument(), Style()->EffectiveZoom(),
-                           LayoutSize(bullet_width, bullet_width));
+  return RoundedLayoutSize(
+      image_->ImageSize(GetDocument(), Style()->EffectiveZoom(),
+                        LayoutSize(bullet_width, bullet_width)));
 }
 
 void LayoutListMarker::StyleWillChange(StyleDifference diff,
@@ -474,13 +475,11 @@
          Style()->ListStylePosition() == EListStylePosition::kInside;
 }
 
-IntRect LayoutListMarker::GetRelativeMarkerRect() const {
-  if (IsImage()) {
-    IntSize image_size = FlooredIntSize(ImageBulletSize());
-    return IntRect(0, 0, image_size.Width(), image_size.Height());
-  }
+LayoutRect LayoutListMarker::GetRelativeMarkerRect() const {
+  if (IsImage())
+    return LayoutRect(LayoutPoint(), ImageBulletSize());
 
-  IntRect relative_rect;
+  LayoutRect relative_rect;
   const SimpleFontData* font_data = Style()->GetFont().PrimaryFont();
   DCHECK(font_data);
   if (!font_data)
@@ -488,26 +487,27 @@
 
   switch (GetListStyleCategory()) {
     case ListStyleCategory::kNone:
-      return IntRect();
+      return LayoutRect();
     case ListStyleCategory::kSymbol: {
       // TODO(wkorman): Review and clean up/document the calculations below.
       // http://crbug.com/543193
       const FontMetrics& font_metrics = font_data->GetFontMetrics();
       int ascent = font_metrics.Ascent();
       int bullet_width = (ascent * 2 / 3 + 1) / 2;
-      relative_rect = IntRect(1, 3 * (ascent - ascent * 2 / 3) / 2,
-                              bullet_width, bullet_width);
+      relative_rect = LayoutRect(1, 3 * (ascent - ascent * 2 / 3) / 2,
+                                 bullet_width, bullet_width);
     } break;
     case ListStyleCategory::kLanguage:
-      relative_rect = IntRect(0, 0, GetWidthOfTextWithSuffix().ToInt(),
-                              font_data->GetFontMetrics().Height());
+      relative_rect =
+          LayoutRect(LayoutUnit(), LayoutUnit(), GetWidthOfTextWithSuffix(),
+                     LayoutUnit(font_data->GetFontMetrics().Height()));
       break;
   }
 
   if (!Style()->IsHorizontalWritingMode()) {
     relative_rect = relative_rect.TransposedRect();
-    relative_rect.SetX(
-        (Size().Width() - relative_rect.X() - relative_rect.Width()).ToInt());
+    relative_rect.SetX(Size().Width() - relative_rect.X() -
+                       relative_rect.Width());
   }
 
   return relative_rect;
diff --git a/third_party/WebKit/Source/core/layout/LayoutListMarker.h b/third_party/WebKit/Source/core/layout/LayoutListMarker.h
index 8fc5a72c..83e2af14 100644
--- a/third_party/WebKit/Source/core/layout/LayoutListMarker.h
+++ b/third_party/WebKit/Source/core/layout/LayoutListMarker.h
@@ -66,7 +66,7 @@
       bool is_image,
       LayoutUnit marker_inline_size);
 
-  IntRect GetRelativeMarkerRect() const;
+  LayoutRect GetRelativeMarkerRect() const;
   LayoutRect LocalSelectionRect() const final;
   bool IsImage() const override;
   const StyleImage* GetImage() const { return image_.Get(); }
diff --git a/third_party/WebKit/Source/core/layout/ScrollbarsTest.cpp b/third_party/WebKit/Source/core/layout/ScrollbarsTest.cpp
index 0831f6a..a4db838 100644
--- a/third_party/WebKit/Source/core/layout/ScrollbarsTest.cpp
+++ b/third_party/WebKit/Source/core/layout/ScrollbarsTest.cpp
@@ -976,104 +976,9 @@
   Compositor().BeginFrame();
 }
 
-// Make sure native scrollbar can change by Emulator.
-// Disable on Android since Android always enable OverlayScrollbar.
-// TODO(https://crbug.com/795645): This test is failing on the ChromeOS bot.
-#if defined(OS_ANDROID) || defined(OS_CHROMEOS)
-TEST_P(ScrollbarsTest, DISABLED_NativeScrollbarChangeToMobileByEmulator) {
-#else
-TEST_P(ScrollbarsTest, NativeScrollbarChangeToMobileByEmulator) {
-#endif
-  ScopedOverlayScrollbarsForTest overlay_scrollbars(false);
-  ScrollbarTheme::SetMockScrollbarsEnabled(false);
-  WebView().Resize(WebSize(200, 200));
-
-  SimRequest request("https://example.com/test.html", "text/html");
-  LoadURL("https://example.com/test.html");
-  request.Complete(R"HTML(
-    <!DOCTYPE html>
-    <style type='text/css'>
-    body {
-      height: 10000px;
-      margin: 0;
-    }
-    #d1 {
-      height: 200px;
-      width: 200px;
-      overflow: auto;
-    }
-    #d2 {
-      height: 2000px;
-    }
-    </style>
-    <div id='d1'>
-      <div id='d2'/>
-    </div>
-  )HTML");
-
-  Compositor().BeginFrame();
-
-  Document& document = GetDocument();
-
-  ScrollableArea* root_scrollable =
-      document.View()->LayoutViewportScrollableArea();
-
-  Element* div = document.getElementById("d1");
-
-  ScrollableArea* div_scrollable =
-      ToLayoutBox(div->GetLayoutObject())->GetScrollableArea();
-
-  VisualViewport& viewport = WebView().GetPage()->GetVisualViewport();
-
-  DCHECK(root_scrollable->VerticalScrollbar());
-  DCHECK(!root_scrollable->VerticalScrollbar()->IsCustomScrollbar());
-  DCHECK(!root_scrollable->VerticalScrollbar()->IsOverlayScrollbar());
-  DCHECK(!root_scrollable->VerticalScrollbar()->GetTheme().IsMockTheme());
-
-  DCHECK(!viewport.LayerForHorizontalScrollbar()->Parent());
-
-  DCHECK(div_scrollable->VerticalScrollbar());
-  DCHECK(!div_scrollable->VerticalScrollbar()->IsCustomScrollbar());
-  DCHECK(!div_scrollable->VerticalScrollbar()->IsOverlayScrollbar());
-  DCHECK(!div_scrollable->VerticalScrollbar()->GetTheme().IsMockTheme());
-
-  // Turn on mobile emulator.
-  WebDeviceEmulationParams params;
-  params.screen_position = WebDeviceEmulationParams::kMobile;
-  WebView().EnableDeviceEmulation(params);
-
-  // For root Scrollbar, mobile emulator will change them to page VisualViewport
-  // scrollbar layer.
-  EXPECT_TRUE(viewport.LayerForHorizontalScrollbar()->Parent());
-
-  // Ensure div scrollbar also change to mobile overlay theme.
-  EXPECT_TRUE(div_scrollable->VerticalScrollbar()->IsOverlayScrollbar());
-
-  ScrollbarThemeOverlay& theme =
-      (ScrollbarThemeOverlay&)div_scrollable->VerticalScrollbar()->GetTheme();
-  EXPECT_TRUE(theme.IsMobileTheme());
-
-  // Turn off mobile emulator.
-  WebView().DisableDeviceEmulation();
-
-  EXPECT_TRUE(root_scrollable->VerticalScrollbar());
-  EXPECT_FALSE(root_scrollable->VerticalScrollbar()->IsCustomScrollbar());
-  EXPECT_FALSE(root_scrollable->VerticalScrollbar()->IsOverlayScrollbar());
-  EXPECT_FALSE(root_scrollable->VerticalScrollbar()->GetTheme().IsMockTheme());
-
-  DCHECK(!viewport.LayerForHorizontalScrollbar()->Parent());
-
-  EXPECT_TRUE(div_scrollable->VerticalScrollbar());
-  EXPECT_FALSE(div_scrollable->VerticalScrollbar()->IsCustomScrollbar());
-  EXPECT_FALSE(div_scrollable->VerticalScrollbar()->IsOverlayScrollbar());
-  EXPECT_FALSE(div_scrollable->VerticalScrollbar()->GetTheme().IsMockTheme());
-}
-
 // Make sure root custom scrollbar can change by Emulator but div custom
 // scrollbar not.
 TEST_P(ScrollbarsTest, CustomScrollbarChangeToMobileByEmulator) {
-  ScopedOverlayScrollbarsForTest overlay_scrollbars(false);
-  ScrollbarTheme::SetMockScrollbarsEnabled(false);
   WebView().Resize(WebSize(200, 200));
 
   SimRequest request("https://example.com/test.html", "text/html");
@@ -1158,8 +1063,6 @@
 
 // Ensure custom scrollbar recreate when style owner change,
 TEST_P(ScrollbarsTest, CustomScrollbarWhenStyleOwnerChange) {
-  ScopedOverlayScrollbarsForTest overlay_scrollbars(false);
-  ScrollbarTheme::SetMockScrollbarsEnabled(false);
   WebView().Resize(WebSize(200, 200));
 
   SimRequest request("https://example.com/test.html", "text/html");
@@ -1361,6 +1264,104 @@
 // Test both overlay and non-overlay scrollbars.
 INSTANTIATE_TEST_CASE_P(All, ScrollbarAppearanceTest, ::testing::Bool());
 
+// Make sure native scrollbar can change by Emulator.
+// Disable on Android since Android always enable OverlayScrollbar.
+#if defined(OS_ANDROID)
+TEST_P(ScrollbarAppearanceTest,
+       DISABLED_NativeScrollbarChangeToMobileByEmulator) {
+#else
+TEST_P(ScrollbarAppearanceTest, NativeScrollbarChangeToMobileByEmulator) {
+#endif
+  ScopedTestingPlatformSupport<ScrollbarTestingPlatformSupport> platform;
+  bool use_overlay_scrollbar = GetParam();
+
+  WebView().Resize(WebSize(200, 200));
+
+  SimRequest request("https://example.com/test.html", "text/html");
+  LoadURL("https://example.com/test.html");
+  request.Complete(R"HTML(
+    <!DOCTYPE html>
+    <style type='text/css'>
+    body {
+      height: 10000px;
+      margin: 0;
+    }
+    #d1 {
+      height: 200px;
+      width: 200px;
+      overflow: auto;
+    }
+    #d2 {
+      height: 2000px;
+    }
+    </style>
+    <div id='d1'>
+      <div id='d2'/>
+    </div>
+  )HTML");
+
+  Compositor().BeginFrame();
+
+  Document& document = GetDocument();
+
+  ScrollableArea* root_scrollable =
+      document.View()->LayoutViewportScrollableArea();
+
+  Element* div = document.getElementById("d1");
+
+  ScrollableArea* div_scrollable =
+      ToLayoutBox(div->GetLayoutObject())->GetScrollableArea();
+
+  VisualViewport& viewport = WebView().GetPage()->GetVisualViewport();
+
+  DCHECK(root_scrollable->VerticalScrollbar());
+  DCHECK(!root_scrollable->VerticalScrollbar()->IsCustomScrollbar());
+  DCHECK_EQ(use_overlay_scrollbar,
+            root_scrollable->VerticalScrollbar()->IsOverlayScrollbar());
+  DCHECK(!root_scrollable->VerticalScrollbar()->GetTheme().IsMockTheme());
+
+  DCHECK(!viewport.LayerForHorizontalScrollbar()->Parent());
+
+  DCHECK(div_scrollable->VerticalScrollbar());
+  DCHECK(!div_scrollable->VerticalScrollbar()->IsCustomScrollbar());
+  DCHECK_EQ(use_overlay_scrollbar,
+            div_scrollable->VerticalScrollbar()->IsOverlayScrollbar());
+  DCHECK(!div_scrollable->VerticalScrollbar()->GetTheme().IsMockTheme());
+
+  // Turn on mobile emulator.
+  WebDeviceEmulationParams params;
+  params.screen_position = WebDeviceEmulationParams::kMobile;
+  WebView().EnableDeviceEmulation(params);
+
+  // For root Scrollbar, mobile emulator will change them to page VisualViewport
+  // scrollbar layer.
+  EXPECT_TRUE(viewport.LayerForHorizontalScrollbar()->Parent());
+
+  // Ensure div scrollbar also change to mobile overlay theme.
+  EXPECT_TRUE(div_scrollable->VerticalScrollbar()->IsOverlayScrollbar());
+
+  ScrollbarThemeOverlay& theme =
+      (ScrollbarThemeOverlay&)div_scrollable->VerticalScrollbar()->GetTheme();
+  EXPECT_TRUE(theme.IsMobileTheme());
+
+  // Turn off mobile emulator.
+  WebView().DisableDeviceEmulation();
+
+  EXPECT_TRUE(root_scrollable->VerticalScrollbar());
+  EXPECT_FALSE(root_scrollable->VerticalScrollbar()->IsCustomScrollbar());
+  DCHECK_EQ(use_overlay_scrollbar,
+            root_scrollable->VerticalScrollbar()->IsOverlayScrollbar());
+  EXPECT_FALSE(root_scrollable->VerticalScrollbar()->GetTheme().IsMockTheme());
+
+  DCHECK(!viewport.LayerForHorizontalScrollbar()->Parent());
+
+  EXPECT_TRUE(div_scrollable->VerticalScrollbar());
+  EXPECT_FALSE(div_scrollable->VerticalScrollbar()->IsCustomScrollbar());
+  DCHECK_EQ(use_overlay_scrollbar,
+            div_scrollable->VerticalScrollbar()->IsOverlayScrollbar());
+  EXPECT_FALSE(div_scrollable->VerticalScrollbar()->GetTheme().IsMockTheme());
+}
+
 #if !defined(OS_MACOSX)
 // Ensure that the minimum length for a scrollbar thumb comes from the
 // WebThemeEngine. Note, Mac scrollbars differ from all other platforms so this
diff --git a/third_party/WebKit/Source/core/layout/ng/inline/ng_inline_item_result.h b/third_party/WebKit/Source/core/layout/ng/inline/ng_inline_item_result.h
index c8d83a5..f8c2286 100644
--- a/third_party/WebKit/Source/core/layout/ng/inline/ng_inline_item_result.h
+++ b/third_party/WebKit/Source/core/layout/ng/inline/ng_inline_item_result.h
@@ -75,13 +75,9 @@
   // Used only during line breaking.
   bool can_break_after = false;
 
-  // True if this item contains only trailing spaces.
-  // Trailing spaces are measured differently that they are split from other
-  // text items.
-  // Used only when 'white-space: pre-wrap', because collapsible spaces are
-  // removed, and if 'pre', trailing spaces are not different from other
-  // characters.
-  bool has_only_trailing_spaces = false;
+  // Has spaces that hangs beyond the end margin.
+  // Set only for text items.
+  bool has_hanging_spaces = false;
 
   // End effects for text items.
   // The effects are included in |shape_result|, but not in text content.
@@ -148,9 +144,11 @@
                         LayoutUnit available_width,
                         LayoutUnit width);
 
-  // Start text offset of this line.
+  // Start/end text offset of this line.
   unsigned StartOffset() const { return start_offset_; }
+  unsigned EndOffset() const { return end_offset_; }
   void SetStartOffset(unsigned offset) { start_offset_ = offset; }
+  void SetEndOffset(unsigned offset) { end_offset_ = offset; }
 
   // The base direction of this line for the bidi algorithm.
   TextDirection BaseDirection() const { return base_direction_; }
@@ -178,6 +176,7 @@
   LayoutUnit text_indent_;
 
   unsigned start_offset_;
+  unsigned end_offset_;
 
   TextDirection base_direction_ = TextDirection::kLtr;
 
diff --git a/third_party/WebKit/Source/core/layout/ng/inline/ng_inline_layout_algorithm.cc b/third_party/WebKit/Source/core/layout/ng/inline/ng_inline_layout_algorithm.cc
index e97751fd..2d2251d 100644
--- a/third_party/WebKit/Source/core/layout/ng/inline/ng_inline_layout_algorithm.cc
+++ b/third_party/WebKit/Source/core/layout/ng/inline/ng_inline_layout_algorithm.cc
@@ -44,35 +44,6 @@
          item_result.needs_box_when_empty;
 }
 
-// Represents a data struct that are needed for 'text-align' and justifications.
-struct NGLineAlign {
-  STACK_ALLOCATED();
-  NGLineAlign(const NGLineInfo&);
-  NGLineAlign() = delete;
-
-  LayoutUnit space;
-  unsigned end_offset;
-};
-
-NGLineAlign::NGLineAlign(const NGLineInfo& line_info) {
-  space = line_info.AvailableWidth() - line_info.Width();
-
-  // Eliminate trailing spaces from the alignment space.
-  const NGInlineItemResults& item_results = line_info.Results();
-  for (auto it = item_results.rbegin(); it != item_results.rend(); ++it) {
-    const NGInlineItemResult& item_result = *it;
-    if (!item_result.has_only_trailing_spaces) {
-      end_offset = item_result.end_offset;
-      return;
-    }
-    space += item_result.inline_size;
-  }
-
-  // An empty line, or only trailing spaces.
-  DCHECK_EQ(space, line_info.AvailableWidth());
-  end_offset = line_info.StartOffset();
-}
-
 }  // namespace
 
 NGInlineLayoutAlgorithm::NGInlineLayoutAlgorithm(
@@ -247,11 +218,10 @@
 
   // Other 'text-align' values than 'justify' move line boxes as a whole, but
   // indivisual items do not change their relative position to the line box.
-  if (text_align != ETextAlign::kJustify)
-    line_bfc_offset.line_offset += OffsetForTextAlign(*line_info, text_align);
-
-  if (IsLtr(line_info->BaseDirection()))
-    line_bfc_offset.line_offset += line_info->TextIndent();
+  if (text_align != ETextAlign::kJustify) {
+    ApplyTextAlign(*line_info, text_align, &line_bfc_offset.line_offset,
+                   inline_size);
+  }
 
   if (list_marker_index.has_value()) {
     NGListLayoutAlgorithm::SetListMarkerPosition(
@@ -413,13 +383,17 @@
 // Justify the line. This changes the size of items by adding spacing.
 // Returns false if justification failed and should fall back to start-aligned.
 bool NGInlineLayoutAlgorithm::ApplyJustify(NGLineInfo* line_info) {
-  NGLineAlign align(*line_info);
-  if (align.space <= 0)
+  LayoutUnit inline_size;
+  LayoutUnit available_width = line_info->AvailableWidth();
+  if (line_info->LineEndShapeResult())
+    available_width -= line_info->LineEndShapeResult()->SnappedWidth();
+  LayoutUnit expansion = available_width - line_info->Width();
+  if (expansion <= 0)
     return false;  // no expansion is needed.
 
   // Construct the line text to compute spacing for.
   String line_text =
-      Node().Text(line_info->StartOffset(), align.end_offset).ToString();
+      Node().Text(line_info->StartOffset(), line_info->EndOffset()).ToString();
 
   // Append a hyphen if the last word is hyphenated. The hyphen is in
   // |ShapeResult|, but not in text. |ShapeResultSpacing| needs the text that
@@ -430,14 +404,12 @@
 
   // Compute the spacing to justify.
   ShapeResultSpacing<String> spacing(line_text);
-  spacing.SetExpansion(align.space, line_info->BaseDirection(),
+  spacing.SetExpansion(expansion, line_info->BaseDirection(),
                        line_info->LineStyle().GetTextJustify());
   if (!spacing.HasExpansion())
     return false;  // no expansion opportunities exist.
 
   for (NGInlineItemResult& item_result : line_info->Results()) {
-    if (item_result.has_only_trailing_spaces)
-      break;
     if (item_result.shape_result) {
       // Mutate the existing shape result if only used here, if not create a
       // copy.
@@ -463,41 +435,42 @@
   return true;
 }
 
-// Compute the offset to shift the line box for the 'text-align' property.
-LayoutUnit NGInlineLayoutAlgorithm::OffsetForTextAlign(
-    const NGLineInfo& line_info,
-    ETextAlign text_align) const {
+void NGInlineLayoutAlgorithm::ApplyTextAlign(const NGLineInfo& line_info,
+                                             ETextAlign text_align,
+                                             LayoutUnit* line_left,
+                                             LayoutUnit inline_size) {
   bool is_base_ltr = IsLtr(line_info.BaseDirection());
+  LayoutUnit available_width = line_info.AvailableWidth();
   while (true) {
     switch (text_align) {
       case ETextAlign::kLeft:
-      case ETextAlign::kWebkitLeft: {
+      case ETextAlign::kWebkitLeft:
         // The direction of the block should determine what happens with wide
         // lines. In particular with RTL blocks, wide lines should still spill
         // out to the left.
-        if (is_base_ltr)
-          return LayoutUnit();
-        NGLineAlign align(line_info);
-        return align.space.ClampPositiveToZero();
-      }
+        if (!is_base_ltr && inline_size > available_width)
+          *line_left -= inline_size - available_width;
+        return;
       case ETextAlign::kRight:
-      case ETextAlign::kWebkitRight: {
+      case ETextAlign::kWebkitRight:
         // Wide lines spill out of the block based off direction.
         // So even if text-align is right, if direction is LTR, wide lines
         // should overflow out of the right side of the block.
-        NGLineAlign align(line_info);
-        if (align.space > 0 || !is_base_ltr)
-          return align.space;
-        return LayoutUnit();
-      }
+        if (inline_size < available_width || !is_base_ltr)
+          *line_left += available_width - inline_size;
+        return;
       case ETextAlign::kCenter:
-      case ETextAlign::kWebkitCenter: {
-        NGLineAlign align(line_info);
-        if (is_base_ltr || align.space > 0)
-          return (align.space / 2).ClampNegativeToZero();
-        // In RTL, wide lines should spill out to the left, same as kRight.
-        return align.space;
-      }
+      case ETextAlign::kWebkitCenter:
+        if (is_base_ltr) {
+          *line_left +=
+              std::max((available_width - inline_size) / 2, LayoutUnit());
+        } else if (inline_size <= available_width) {
+          *line_left += (available_width - inline_size) / 2;
+        } else {
+          // In RTL, wide lines should spill out to the left, same as kRight.
+          *line_left += available_width - inline_size;
+        }
+        return;
       case ETextAlign::kStart:
         text_align = is_base_ltr ? ETextAlign::kLeft : ETextAlign::kRight;
         continue;
@@ -507,10 +480,10 @@
       case ETextAlign::kJustify:
         // Justification is applied in earlier phase, see PlaceItems().
         NOTREACHED();
-        return LayoutUnit();
+        return;
     }
     NOTREACHED();
-    return LayoutUnit();
+    return;
   }
 }
 
diff --git a/third_party/WebKit/Source/core/layout/ng/inline/ng_inline_layout_algorithm.h b/third_party/WebKit/Source/core/layout/ng/inline/ng_inline_layout_algorithm.h
index f473ee76..4064780 100644
--- a/third_party/WebKit/Source/core/layout/ng/inline/ng_inline_layout_algorithm.h
+++ b/third_party/WebKit/Source/core/layout/ng/inline/ng_inline_layout_algorithm.h
@@ -74,7 +74,10 @@
                        NGInlineItemResult*,
                        const NGLineInfo&);
 
-  LayoutUnit OffsetForTextAlign(const NGLineInfo&, ETextAlign) const;
+  void ApplyTextAlign(const NGLineInfo&,
+                      ETextAlign,
+                      LayoutUnit* line_left,
+                      LayoutUnit inline_size);
   bool ApplyJustify(NGLineInfo*);
 
   LayoutUnit ComputeContentSize(const NGLineInfo&,
diff --git a/third_party/WebKit/Source/core/layout/ng/inline/ng_line_breaker.cc b/third_party/WebKit/Source/core/layout/ng/inline/ng_line_breaker.cc
index 4534d7d3..af34d8b 100644
--- a/third_party/WebKit/Source/core/layout/ng/inline/ng_line_breaker.cc
+++ b/third_party/WebKit/Source/core/layout/ng/inline/ng_line_breaker.cc
@@ -18,22 +18,6 @@
 
 namespace blink {
 
-namespace {
-
-// CSS-defined white space characters, excluding the newline character.
-// In most cases, the line breaker consider break opportunities are before
-// spaces because it handles trailing spaces differently from other normal
-// characters, but breaking before newline characters is not desired.
-inline bool IsBreakableSpace(UChar c) {
-  return c == kSpaceCharacter || c == kTabulationCharacter;
-}
-
-inline bool CanBreakAfterLast(const NGInlineItemResults& item_results) {
-  return !item_results.IsEmpty() && item_results.back().can_break_after;
-}
-
-}  // namespace
-
 NGLineBreaker::NGLineBreaker(
     NGInlineNode node,
     NGLineBreakerMode mode,
@@ -55,8 +39,6 @@
       handled_floats_end_item_index_(handled_float_index),
       base_direction_(node_.BaseDirection()),
       in_line_height_quirks_mode_(node.InLineHeightQuirksMode()) {
-  break_iterator_.SetBreakSpace(BreakSpaceType::kBeforeSpaceRun);
-
   if (break_token) {
     current_style_ = break_token->Style();
     item_index_ = break_token->ItemIndex();
@@ -67,26 +49,10 @@
   }
 }
 
-inline NGInlineItemResult* NGLineBreaker::AddItem(
-    const NGInlineItem& item,
-    unsigned end_offset,
-    NGInlineItemResults* item_results) {
-  DCHECK_LE(end_offset, item.EndOffset());
-  item_results->push_back(
-      NGInlineItemResult(&item, item_index_, offset_, end_offset));
-  return &item_results->back();
-}
-
-inline NGInlineItemResult* NGLineBreaker::AddItem(
-    const NGInlineItem& item,
-    NGInlineItemResults* item_results) {
-  return AddItem(item, item.EndOffset(), item_results);
-}
-
-inline void NGLineBreaker::ComputeCanBreakAfter(
-    NGInlineItemResult* item_result) const {
-  item_result->can_break_after =
-      auto_wrap_ && break_iterator_.IsBreakable(item_result->end_offset);
+inline NGLineBreaker::LineBreakState NGLineBreaker::ToLineBreakState(
+    const NGInlineItemResult& item_result) {
+  return item_result.can_break_after ? LineBreakState::kIsBreakable
+                                     : LineBreakState::kNotBreakable;
 }
 
 // @return if this is the "first formatted line".
@@ -139,7 +105,6 @@
   //   <p>...<span>....</span></p>
   // When the line wraps in <span>, the 2nd line needs to start with the style
   // of the <span>.
-  override_break_anywhere_ = false;
   SetCurrentStyle(current_style_ ? *current_style_ : line_info->LineStyle());
   ComputeBaseDirection();
   line_info->SetBaseDirection(base_direction_);
@@ -163,6 +128,13 @@
 
   PrepareNextLine(opportunity, line_info);
   BreakLine(line_info);
+  line_info->SetEndOffset(offset_);
+
+  // TODO(kojii): When editing, or caret is enabled, trailing spaces at wrap
+  // point should not be removed. For other cases, we can a) remove, b) leave
+  // characters without glyphs, or c) leave both characters and glyphs without
+  // measuring. Need to decide which one works the best.
+  SkipCollapsibleWhitespaces();
 
   if (line_info->Results().IsEmpty())
     return false;
@@ -185,82 +157,71 @@
   NGInlineItemResults* item_results = &line_info->Results();
   const Vector<NGInlineItem>& items =
       node_.Items(line_info->UseFirstLineStyle());
-  LineBreakState state = LineBreakState::kContinue;
-  while (state != LineBreakState::kDone) {
-    // Check overflow even if |item_index_| is at the end of the block, because
-    // the last item of the block may have caused overflow. In that case,
-    // |HandleOverflow| will rewind |item_index_|.
-    if (state == LineBreakState::kContinue && auto_wrap_ && !line_.CanFit()) {
-      state = HandleOverflow(line_info);
-    }
+  LineBreakState state = LineBreakState::kNotBreakable;
 
-    // If we reach at the end of the block, this is the last line.
-    DCHECK_LE(item_index_, items.size());
-    if (item_index_ == items.size()) {
-      line_info->SetIsLastLine(true);
-      return;
-    }
-
-    // Handle trailable items first. These items may not be break before.
-    // They (or part of them) may also overhang the available width.
-    const NGInlineItem& item = items[item_index_];
-    if (item.Type() == NGInlineItem::kText) {
-      state = HandleText(item, state, line_info);
+  while (item_index_ < items.size()) {
 #if DCHECK_IS_ON()
-      if (!item_results->IsEmpty())
-        item_results->back().CheckConsistency();
+    if (!item_results->IsEmpty() && (state == LineBreakState::kIsBreakable ||
+                                     state == LineBreakState::kNotBreakable)) {
+      DCHECK_EQ(item_results->back().can_break_after,
+                state == LineBreakState::kIsBreakable);
+    }
 #endif
-      continue;
-    }
+
+    // CloseTag prohibits to break before.
+    const NGInlineItem& item = items[item_index_];
     if (item.Type() == NGInlineItem::kCloseTag) {
-      HandleCloseTag(item, item_results);
-      continue;
-    }
-    if (item.Type() == NGInlineItem::kControl) {
-      state = HandleControlItem(item, state, line_info);
-      continue;
-    }
-    if (item.Type() == NGInlineItem::kBidiControl) {
-      state = HandleBidiControlItem(item, state, line_info);
+      state = HandleCloseTag(item, item_results);
       continue;
     }
 
-    // Items after this point are not trailable. Break at the earliest break
-    // opportunity if we're trailing.
-    if (state == LineBreakState::kTrailing &&
-        CanBreakAfterLast(*item_results)) {
+    if (state == LineBreakState::kBreakAfterTrailings) {
       line_info->SetIsLastLine(false);
       return;
     }
+    if (state == LineBreakState::kIsBreakable && !line_.CanFit())
+      return HandleOverflow(line_info);
 
-    if (item.Type() == NGInlineItem::kAtomicInline) {
-      HandleAtomicInline(item, line_info);
+    item_results->push_back(
+        NGInlineItemResult(&item, item_index_, offset_, item.EndOffset()));
+    NGInlineItemResult* item_result = &item_results->back();
+    if (item.Type() == NGInlineItem::kText) {
+      state = HandleText(line_info, item, item_result);
+#if DCHECK_IS_ON()
+      item_result->CheckConsistency();
+#endif
+    } else if (item.Type() == NGInlineItem::kAtomicInline) {
+      state = HandleAtomicInline(item, item_result, *line_info);
+    } else if (item.Type() == NGInlineItem::kControl) {
+      state = HandleControlItem(item, item_result);
+      if (state == LineBreakState::kForcedBreak) {
+        line_.is_after_forced_break = true;
+        line_info->SetIsLastLine(true);
+        return;
+      }
     } else if (item.Type() == NGInlineItem::kOpenTag) {
-      HandleOpenTag(item, AddItem(item, item_results));
+      HandleOpenTag(item, item_result);
+      state = LineBreakState::kNotBreakable;
     } else if (item.Type() == NGInlineItem::kFloating) {
-      HandleFloat(item, AddItem(item, item_results));
-    } else if (item.Type() == NGInlineItem::kOutOfFlowPositioned) {
-      DCHECK_EQ(item.Length(), 0u);
-      AddItem(item, item_results);
-      MoveToNextOf(item);
+      state = HandleFloat(item, item_result);
     } else if (item.Length()) {
-      NOTREACHED();
       // For other items with text (e.g., bidi controls), use their text to
       // determine the break opportunity.
-      NGInlineItemResult* item_result = AddItem(item, item_results);
       item_result->can_break_after =
           break_iterator_.IsBreakable(item_result->end_offset);
-      MoveToNextOf(item);
-    } else if (item.Type() == NGInlineItem::kListMarker) {
-      line_.should_create_line_box = true;
-      NGInlineItemResult* item_result = AddItem(item, item_results);
-      DCHECK(!item_result->can_break_after);
+      state = ToLineBreakState(*item_result);
       MoveToNextOf(item);
     } else {
-      NOTREACHED();
+      if (item.Type() == NGInlineItem::kListMarker)
+        line_.should_create_line_box = true;
+      DCHECK(!item_result->can_break_after);
+      state = LineBreakState::kNotBreakable;
       MoveToNextOf(item);
     }
   }
+  if (!line_.CanFit())
+    return HandleOverflow(line_info);
+  line_info->SetIsLastLine(true);
 }
 
 // Re-compute the current position from NGInlineItemResults.
@@ -277,6 +238,17 @@
   LayoutUnit bfc_line_offset = line_.line_left_bfc_offset;
   LayoutUnit available_width = line_.AvailableWidth();
 
+  // Indenting should move the current position to compute the size of
+  // tabulations. Since it is computed and stored in NGInlineItemResult,
+  // adjust the positoin of the line box to simplify placing items.
+  if (LayoutUnit text_indent = line_info->TextIndent()) {
+    // Move the line box by indent. Negative indents are ink overflow, let the
+    // line box overflow from the container box.
+    if (IsLtr(line_info->BaseDirection()))
+      bfc_line_offset += text_indent;
+    available_width -= text_indent;
+  }
+
   // Negative margins can make the position negative, but the inline size is
   // always positive or 0.
   line_info->SetLineBfcOffset({bfc_line_offset, bfc_block_offset_},
@@ -284,21 +256,30 @@
                               line_.position.ClampNegativeToZero());
 }
 
+bool NGLineBreaker::IsFirstBreakOpportunity(unsigned offset,
+                                            const NGLineInfo& line_info) const {
+  return break_iterator_.NextBreakOpportunity(line_info.StartOffset() + 1) >=
+         offset;
+}
+
+NGLineBreaker::LineBreakState NGLineBreaker::ComputeIsBreakableAfter(
+    NGInlineItemResult* item_result) const {
+  if (auto_wrap_ && break_iterator_.IsBreakable(item_result->end_offset)) {
+    item_result->can_break_after = true;
+    return LineBreakState::kIsBreakable;
+  }
+  DCHECK(!item_result->can_break_after);
+  return LineBreakState::kNotBreakable;
+}
+
 NGLineBreaker::LineBreakState NGLineBreaker::HandleText(
+    NGLineInfo* line_info,
     const NGInlineItem& item,
-    LineBreakState state,
-    NGLineInfo* line_info) {
+    NGInlineItemResult* item_result) {
   DCHECK_EQ(item.Type(), NGInlineItem::kText);
   DCHECK(item.TextShapeResult());
-  NGInlineItemResults* item_results = &line_info->Results();
-
-  // If we're trailing, only trailing spaces can be included in this line.
-  if (state == LineBreakState::kTrailing && CanBreakAfterLast(*item_results)) {
-    return HandleTrailingSpaces(item, line_info);
-  }
-
   line_.should_create_line_box = true;
-  NGInlineItemResult* item_result = AddItem(item, item_results);
+
   LayoutUnit available_width = line_.AvailableWidth();
 
   // If the start offset is at the item boundary, try to add the entire item.
@@ -309,10 +290,9 @@
     if (!auto_wrap_ || next_position <= available_width) {
       item_result->shape_result = item.TextShapeResult();
       item_result->may_break_inside = auto_wrap_;
-      ComputeCanBreakAfter(item_result);
       line_.position = next_position;
       MoveToNextOf(item);
-      return state;
+      return ComputeIsBreakableAfter(item_result);
     }
   }
 
@@ -323,22 +303,25 @@
     bool is_overflow = next_position > available_width;
     line_.position = next_position;
     item_result->may_break_inside = !is_overflow;
-    MoveToNextOf(*item_result);
+    if (item_result->end_offset < item.EndOffset())
+      offset_ = item_result->end_offset;
+    else
+      MoveToNextOf(item);
+    if (item_result->end_offset < item.EndOffset() ||
+        item_result->has_hanging_spaces) {
+      // The break point found. If it fits, break this line after including
+      // trailing objects (end margins etc.)
+      if (!is_overflow)
+        return LineBreakState::kBreakAfterTrailings;
 
-    if (!is_overflow || state == LineBreakState::kTrailing) {
-      if (item_result->end_offset < item.EndOffset()) {
-        // The break point found, and text follows. Break here.
-        HandleTrailingSpaces(item, line_info);
-        line_info->SetIsLastLine(false);
-        return LineBreakState::kDone;
-      }
-
-      // The break point found, but items that prohibit breaking before them may
-      // follow. Continue looking next items.
-      return state;
+      // If overflow, proceed to the possible break point before start
+      // rewinding. TODO(kojii): This could be more efficient if we knew there
+      // was a break opportunity and that rewind will succeed.
+      return LineBreakState::kIsBreakable;
     }
 
-    return HandleOverflow(line_info);
+    DCHECK(is_overflow || item_result->start_offset != item.StartOffset());
+    return ToLineBreakState(*item_result);
   }
 
   // Add the rest of the item if !auto_wrap.
@@ -351,7 +334,7 @@
   item_result->can_break_after = false;
   line_.position += item_result->inline_size;
   MoveToNextOf(item);
-  return state;
+  return LineBreakState::kNotBreakable;
 }
 
 void NGLineBreaker::BreakText(NGInlineItemResult* item_result,
@@ -377,13 +360,36 @@
   scoped_refptr<ShapeResult> shape_result =
       breaker.ShapeLine(item_result->start_offset, available_width, &result);
   DCHECK_GT(shape_result->NumCharacters(), 0u);
-  if (result.is_hyphenated) {
-    AppendHyphen(*item.Style(), line_info);
-    // TODO(kojii): Implement when adding a hyphen caused overflow.
-    // crbug.com/714962: Should be removed when switched to NGPaint.
-    item_result->text_end_effect = NGTextEndEffect::kHyphen;
+  if (result.has_hanging_spaces) {
+    item_result->has_hanging_spaces = true;
+    // Hanging spaces do not expand min-content. Handle them simliar to visual
+    // overflow. Some details are different, but it's the closest behavior.
+    item_result->inline_size = available_width;
+    DCHECK(!result.is_hyphenated);
+  } else {
+    item_result->inline_size =
+        shape_result->SnappedWidth().ClampNegativeToZero();
+
+    // If overflow and no break opportunities exist, and if 'word-wrap:
+    // break-word', try to break at every grapheme cluster boundary.
+    if (item_result->inline_size > available_width && break_if_overflow_ &&
+        break_iterator_.BreakType() == LineBreakType::kNormal &&
+        IsFirstBreakOpportunity(result.break_offset, *line_info)) {
+      break_iterator_.SetBreakType(LineBreakType::kBreakCharacter);
+      BreakText(item_result, item, available_width, line_info);
+      break_iterator_.SetBreakType(LineBreakType::kNormal);
+      return;
+    }
+
+    if (result.is_hyphenated) {
+      AppendHyphen(*item.Style(), line_info);
+      item_result->inline_size =
+          shape_result->SnappedWidth().ClampNegativeToZero();
+      // TODO(kojii): Implement when adding a hyphen caused overflow.
+      // crbug.com/714962: Should be removed when switched to NGPaint.
+      item_result->text_end_effect = NGTextEndEffect::kHyphen;
+    }
   }
-  item_result->inline_size = shape_result->SnappedWidth().ClampNegativeToZero();
   item_result->end_offset = result.break_offset;
   item_result->shape_result = std::move(shape_result);
   DCHECK_GT(item_result->end_offset, item_result->start_offset);
@@ -405,55 +411,6 @@
   }
 }
 
-NGLineBreaker::LineBreakState NGLineBreaker::HandleTrailingSpaces(
-    const NGInlineItem& item,
-    NGLineInfo* line_info) {
-  DCHECK_EQ(item.Type(), NGInlineItem::kText);
-  DCHECK_LT(offset_, item.EndOffset());
-  const String& text = Text();
-  NGInlineItemResults* item_results = &line_info->Results();
-  DCHECK(item.Style());
-  const ComputedStyle& style = *item.Style();
-  if (style.CollapseWhiteSpace()) {
-    if (text[offset_] != kSpaceCharacter)
-      return LineBreakState::kDone;
-
-    // Skipping one whitespace removes all collapsible spaces because
-    // collapsible spaces are collapsed to single space in NGInlineItemBuilder.
-    offset_++;
-
-    // Make the last item breakable after, even if it was nowrap.
-    DCHECK(!item_results->IsEmpty());
-    item_results->back().can_break_after = true;
-  } else {
-    // Find the end of the run of space characters in this item.
-    // Other white space characters (e.g., tab) are not included in this item.
-    DCHECK(style.BreakOnlyAfterWhiteSpace());
-    unsigned end = offset_;
-    while (end < item.EndOffset() && text[end] == kSpaceCharacter)
-      end++;
-    if (end == offset_)
-      return LineBreakState::kDone;
-
-    NGInlineItemResult* item_result = AddItem(item, end, item_results);
-    item_result->has_only_trailing_spaces = true;
-    item_result->shape_result = item.TextShapeResult()->SubRange(offset_, end);
-    item_result->inline_size = item_result->shape_result->SnappedWidth();
-    line_.position += item_result->inline_size;
-    item_result->can_break_after =
-        end < text.length() && !IsBreakableSpace(text[end]);
-    offset_ = end;
-  }
-
-  // If non-space characters follow, the line is done.
-  // Otherwise keep checking next items for the break point.
-  DCHECK_LE(offset_, item.EndOffset());
-  if (offset_ < item.EndOffset())
-    return LineBreakState::kDone;
-  item_index_++;
-  return LineBreakState::kTrailing;
-}
-
 void NGLineBreaker::AppendHyphen(const ComputedStyle& style,
                                  NGLineInfo* line_info) {
   TextDirection direction = style.Direction();
@@ -462,7 +419,6 @@
   HarfBuzzShaper shaper(hyphen_string.Characters16(), hyphen_string.length());
   scoped_refptr<ShapeResult> hyphen_result =
       shaper.Shape(&style.GetFont(), direction);
-  line_.position += hyphen_result->SnappedWidth();
   line_info->SetLineEndShapeResult(std::move(hyphen_result), &style);
 }
 
@@ -470,94 +426,48 @@
 // layout, but do not need shaping/painting.
 NGLineBreaker::LineBreakState NGLineBreaker::HandleControlItem(
     const NGInlineItem& item,
-    LineBreakState state,
-    NGLineInfo* line_info) {
+    NGInlineItemResult* item_result) {
   DCHECK_EQ(item.Length(), 1u);
   line_.should_create_line_box = true;
 
-  UChar character = Text()[item.StartOffset()];
+  UChar character = node_.Text()[item.StartOffset()];
   switch (character) {
-    case kNewlineCharacter: {
-      NGInlineItemResult* item_result = AddItem(item, &line_info->Results());
-      item_result->has_only_trailing_spaces = true;
-      line_.is_after_forced_break = true;
-      line_info->SetIsLastLine(true);
-      state = LineBreakState::kDone;
-      break;
-    }
+    case kNewlineCharacter:
+      MoveToNextOf(item);
+      return LineBreakState::kForcedBreak;
     case kTabulationCharacter: {
-      NGInlineItemResult* item_result = AddItem(item, &line_info->Results());
       DCHECK(item.Style());
       const ComputedStyle& style = *item.Style();
       const Font& font = style.GetFont();
       item_result->inline_size =
           font.TabWidth(style.GetTabSize(), line_.position);
       line_.position += item_result->inline_size;
-      item_result->has_only_trailing_spaces =
-          state == LineBreakState::kTrailing;
-      ComputeCanBreakAfter(item_result);
-      break;
-    }
-    case kZeroWidthSpaceCharacter: {
-      // <wbr> tag creates break opportunities regardless of auto_wrap.
-      NGInlineItemResult* item_result = AddItem(item, &line_info->Results());
-      item_result->can_break_after = true;
-      break;
-    }
-    default:
-      NOTREACHED();
-      break;
-  }
-  MoveToNextOf(item);
-  return state;
-}
-
-NGLineBreaker::LineBreakState NGLineBreaker::HandleBidiControlItem(
-    const NGInlineItem& item,
-    LineBreakState state,
-    NGLineInfo* line_info) {
-  DCHECK_EQ(item.Length(), 1u);
-  NGInlineItemResults* item_results = &line_info->Results();
-
-  // Bidi control characters have enter/exit semantics. Handle "enter"
-  // characters simialr to open-tag, while "exit" (pop) characters similar to
-  // close-tag.
-  UChar character = Text()[item.StartOffset()];
-  bool is_pop = character == kPopDirectionalIsolateCharacter ||
-                character == kPopDirectionalFormattingCharacter;
-  if (is_pop) {
-    if (!item_results->IsEmpty()) {
-      NGInlineItemResult* item_result = AddItem(item, item_results);
-      NGInlineItemResult* last = &(*item_results)[item_results->size() - 2];
-      item_result->can_break_after = last->can_break_after;
-      last->can_break_after = false;
-    } else {
-      AddItem(item, item_results);
-    }
-  } else {
-    if (state == LineBreakState::kTrailing &&
-        CanBreakAfterLast(*item_results)) {
-      line_info->SetIsLastLine(false);
       MoveToNextOf(item);
-      return LineBreakState::kDone;
+      // TODO(kojii): Implement break around the tab character.
+      item_result->can_break_after = true;
+      return LineBreakState::kIsBreakable;
     }
-    NGInlineItemResult* item_result = AddItem(item, item_results);
-    DCHECK(!item_result->can_break_after);
+    case kZeroWidthSpaceCharacter:
+      // <wbr> tag creates break opportunities regardless of auto_wrap.
+      MoveToNextOf(item);
+      item_result->can_break_after = true;
+      return LineBreakState::kIsBreakable;
   }
-  MoveToNextOf(item);
-  return state;
+  NOTREACHED();
+  item_result->can_break_after = true;
+  return LineBreakState::kIsBreakable;
 }
 
-void NGLineBreaker::HandleAtomicInline(const NGInlineItem& item,
-                                       NGLineInfo* line_info) {
+NGLineBreaker::LineBreakState NGLineBreaker::HandleAtomicInline(
+    const NGInlineItem& item,
+    NGInlineItemResult* item_result,
+    const NGLineInfo& line_info) {
   DCHECK_EQ(item.Type(), NGInlineItem::kAtomicInline);
   line_.should_create_line_box = true;
 
-  NGInlineItemResult* item_result = AddItem(item, &line_info->Results());
   item_result->layout_result =
       NGBlockNode(ToLayoutBox(item.GetLayoutObject()))
-          .LayoutAtomicInline(constraint_space_,
-                              line_info->UseFirstLineStyle());
+          .LayoutAtomicInline(constraint_space_, line_info.UseFirstLineStyle());
   DCHECK(item_result->layout_result->PhysicalFragment());
 
   item_result->inline_size =
@@ -571,8 +481,8 @@
   item_result->inline_size += item_result->margins.InlineSum();
 
   line_.position += item_result->inline_size;
-  ComputeCanBreakAfter(item_result);
   MoveToNextOf(item);
+  return ComputeIsBreakableAfter(item_result);
 }
 
 // Performs layout and positions a float.
@@ -591,8 +501,9 @@
 // in the document.
 //
 // TODO(glebl): Add the support of clearance for inline floats.
-void NGLineBreaker::HandleFloat(const NGInlineItem& item,
-                                NGInlineItemResult* item_result) {
+NGLineBreaker::LineBreakState NGLineBreaker::HandleFloat(
+    const NGInlineItem& item,
+    NGInlineItemResult* item_result) {
   // When rewind occurs, an item may be handled multiple times.
   // Since floats are put into a separate list, avoid handling same floats
   // twice.
@@ -602,10 +513,10 @@
   // Additionally, we need to skip floats if we're retrying a line after a
   // fragmentainer break. In that case the floats associated with this line will
   // already have been processed.
-  ComputeCanBreakAfter(item_result);
-  MoveToNextOf(item);
-  if (item_index_ <= handled_floats_end_item_index_ || ignore_floats_)
-    return;
+  if (item_index_ < handled_floats_end_item_index_ || ignore_floats_) {
+    MoveToNextOf(item);
+    return ComputeIsBreakableAfter(item_result);
+  }
 
   NGBlockNode node(ToLayoutBox(item.GetLayoutObject()));
 
@@ -674,6 +585,9 @@
     DCHECK_GE(line_.line_right_bfc_offset, LayoutUnit());
     DCHECK_GE(line_.AvailableWidth(), LayoutUnit());
   }
+
+  MoveToNextOf(item);
+  return ComputeIsBreakableAfter(item_result);
 }
 
 void NGLineBreaker::HandleOpenTag(const NGInlineItem& item,
@@ -715,9 +629,13 @@
   MoveToNextOf(item);
 }
 
-void NGLineBreaker::HandleCloseTag(const NGInlineItem& item,
-                                   NGInlineItemResults* item_results) {
-  NGInlineItemResult* item_result = AddItem(item, item_results);
+NGLineBreaker::LineBreakState NGLineBreaker::HandleCloseTag(
+    const NGInlineItem& item,
+    NGInlineItemResults* item_results) {
+  item_results->push_back(
+      NGInlineItemResult(&item, item_index_, offset_, item.EndOffset()));
+  NGInlineItemResult* item_result = &item_results->back();
+
   item_result->needs_box_when_empty = false;
   item_result->has_edge = item.HasEndEdge();
   if (item_result->has_edge) {
@@ -750,37 +668,23 @@
     if (was_auto_wrap == auto_wrap_) {
       item_result->can_break_after = last->can_break_after;
       last->can_break_after = false;
-      return;
+      return ToLineBreakState(*item_result);
     }
     last->can_break_after = false;
-    if (!was_auto_wrap) {
-      DCHECK(auto_wrap_);
-      // When auto-wrap starts after no-wrap, the boundary is not allowed to
-      // wrap. However, when space characters follow the boundary, there should
-      // be a break opportunity after the space. The break_iterator cannot
-      // compute this because it considers break opportunities are before a run
-      // of spaces.
-      const String& text = node_.Text();
-      if (offset_ < text.length() && IsBreakableSpace(text[offset_])) {
-        item_result->can_break_after = true;
-        return;
-      }
-    }
   }
-  ComputeCanBreakAfter(item_result);
+  return ComputeIsBreakableAfter(item_result);
 }
 
 // Handles when the last item overflows.
 // At this point, item_results does not fit into the current line, and there
 // are no break opportunities in item_results.back().
-NGLineBreaker::LineBreakState NGLineBreaker::HandleOverflow(
-    NGLineInfo* line_info) {
-  return HandleOverflow(line_info, line_.AvailableWidth());
+void NGLineBreaker::HandleOverflow(NGLineInfo* line_info) {
+  HandleOverflow(line_info, line_.AvailableWidth(), false);
 }
 
-NGLineBreaker::LineBreakState NGLineBreaker::HandleOverflow(
-    NGLineInfo* line_info,
-    LayoutUnit available_width) {
+void NGLineBreaker::HandleOverflow(NGLineInfo* line_info,
+                                   LayoutUnit available_width,
+                                   bool force_break_anywhere) {
   NGInlineItemResults* item_results = &line_info->Results();
   LayoutUnit width_to_rewind = line_.position - available_width;
   DCHECK_GT(width_to_rewind, 0);
@@ -796,8 +700,7 @@
     if (i < item_results->size() - 1 && item_result->can_break_after) {
       if (width_to_rewind <= 0) {
         line_.position = available_width + width_to_rewind;
-        Rewind(line_info, i + 1);
-        return LineBreakState::kTrailing;
+        return Rewind(line_info, i + 1);
       }
       break_before = i + 1;
     }
@@ -808,40 +711,31 @@
     DCHECK(item_result->item);
     const NGInlineItem& item = *item_result->item;
     if (item.Type() == NGInlineItem::kText && next_width_to_rewind < 0 &&
-        (item_result->may_break_inside || override_break_anywhere_)) {
+        (item_result->may_break_inside || force_break_anywhere)) {
       // When the text fits but its right margin does not, the break point
       // must not be at the end.
       LayoutUnit item_available_width =
           std::min(-next_width_to_rewind, item_result->inline_size - 1);
       SetCurrentStyle(*item.Style());
+      if (force_break_anywhere)
+        break_iterator_.SetBreakType(LineBreakType::kBreakCharacter);
       BreakText(item_result, item, item_available_width, line_info);
 #if DCHECK_IS_ON()
       item_result->CheckConsistency();
 #endif
       if (item_result->inline_size <= item_available_width) {
-        DCHECK(item_result->end_offset < item.EndOffset());
+        DCHECK(item_result->end_offset < item.EndOffset() ||
+               (item_result->end_offset == item.EndOffset() &&
+                item_result->has_hanging_spaces));
         DCHECK(item_result->can_break_after);
         DCHECK_LE(i + 1, item_results->size());
         if (i + 1 == item_results->size()) {
-          // If this is the last item, adjust states to accomodate the change.
           line_.position =
               available_width + next_width_to_rewind + item_result->inline_size;
-          if (line_info->LineEndShapeResult()) {
-            line_.position -= line_info->LineEndShapeResult()->SnappedWidth();
-            line_info->SetLineEndShapeResult(nullptr, nullptr);
-          }
-#if DCHECK_IS_ON()
-          LayoutUnit position_fast = line_.position;
-          UpdatePosition(line_info->Results());
-          DCHECK_EQ(line_.position, position_fast);
-#endif
-          item_index_ = item_result->item_index;
-          offset_ = item_result->end_offset;
-          node_.AssertOffset(item_index_, offset_);
         } else {
           Rewind(line_info, i + 1);
         }
-        return LineBreakState::kTrailing;
+        return;
       }
     }
 
@@ -850,21 +744,12 @@
 
   // Reaching here means that the rewind point was not found.
 
-  if (break_anywhere_if_overflow_ && !override_break_anywhere_) {
-    override_break_anywhere_ = true;
-    break_iterator_.SetBreakType(LineBreakType::kBreakCharacter);
-    Rewind(line_info, 0);
-    return LineBreakState::kContinue;
-  }
-
   // Let this line overflow.
   // If there was a break opporunity, the overflow should stop there.
-  if (break_before) {
-    Rewind(line_info, break_before);
-    return LineBreakState::kTrailing;
-  }
+  if (break_before)
+    return Rewind(line_info, break_before);
 
-  return LineBreakState::kTrailing;
+  line_info->SetIsLastLine(item_index_ >= node_.Items().size());
 }
 
 void NGLineBreaker::Rewind(NGLineInfo* line_info, unsigned new_end) {
@@ -888,7 +773,7 @@
   // re-layout atomic inlines.
   item_results->Shrink(new_end);
 
-  line_info->SetLineEndShapeResult(nullptr, nullptr);
+  line_info->SetIsLastLine(false);
   UpdatePosition(line_info->Results());
 }
 
@@ -910,10 +795,8 @@
   // anywhere'.
   unsigned saved_item_index = item_index_;
   unsigned saved_offset = offset_;
-  override_break_anywhere_ = true;
-  break_iterator_.SetBreakType(LineBreakType::kBreakCharacter);
   HandleOverflow(line_info,
-                 line_.AvailableWidth() - shape_result->SnappedWidth());
+                 line_.AvailableWidth() - shape_result->SnappedWidth(), true);
 
   // Restore item_index/offset to before HandleOverflow().
   item_index_ = saved_item_index;
@@ -933,7 +816,6 @@
   // The ellipsis should appear at the logical end of the line.
   // This is stored seprately from other results so that it can be appended
   // after bidi reorder.
-  line_.position += shape_result->SnappedWidth();
   line_info->SetLineEndShapeResult(std::move(shape_result), style);
 }
 
@@ -945,29 +827,27 @@
   if (auto_wrap_) {
     break_iterator_.SetLocale(style.LocaleForLineBreakIterator());
 
-    if (UNLIKELY(override_break_anywhere_)) {
-      break_iterator_.SetBreakType(LineBreakType::kBreakCharacter);
-    } else {
-      switch (style.WordBreak()) {
-        case EWordBreak::kNormal:
-          break_anywhere_if_overflow_ =
-              style.OverflowWrap() == EOverflowWrap::kBreakWord;
-          break_iterator_.SetBreakType(LineBreakType::kNormal);
-          break;
-        case EWordBreak::kBreakAll:
-          break_anywhere_if_overflow_ = false;
-          break_iterator_.SetBreakType(LineBreakType::kBreakAll);
-          break;
-        case EWordBreak::kBreakWord:
-          break_anywhere_if_overflow_ = true;
-          break_iterator_.SetBreakType(LineBreakType::kNormal);
-          break;
-        case EWordBreak::kKeepAll:
-          break_anywhere_if_overflow_ = false;
-          break_iterator_.SetBreakType(LineBreakType::kKeepAll);
-          break;
-      }
+    switch (style.WordBreak()) {
+      case EWordBreak::kNormal:
+        break_if_overflow_ = style.OverflowWrap() == EOverflowWrap::kBreakWord;
+        break_iterator_.SetBreakType(LineBreakType::kNormal);
+        break;
+      case EWordBreak::kBreakAll:
+        break_if_overflow_ = false;
+        break_iterator_.SetBreakType(LineBreakType::kBreakAll);
+        break;
+      case EWordBreak::kBreakWord:
+        break_if_overflow_ = true;
+        break_iterator_.SetBreakType(LineBreakType::kNormal);
+        break;
+      case EWordBreak::kKeepAll:
+        break_if_overflow_ = false;
+        break_iterator_.SetBreakType(LineBreakType::kKeepAll);
+        break;
     }
+    break_iterator_.SetBreakSpace(style.BreakOnlyAfterWhiteSpace()
+                                      ? BreakSpaceType::kAfter
+                                      : BreakSpaceType::kBeforeSpace);
 
     enable_soft_hyphen_ = style.GetHyphens() != Hyphens::kNone;
     hyphenation_ = style.GetHyphenation();
@@ -989,6 +869,24 @@
     item_index_++;
 }
 
+void NGLineBreaker::SkipCollapsibleWhitespaces() {
+  const Vector<NGInlineItem>& items = node_.Items();
+  if (item_index_ >= items.size())
+    return;
+  const NGInlineItem& item = items[item_index_];
+  if (item.Type() != NGInlineItem::kText || !item.Style()->CollapseWhiteSpace())
+    return;
+
+  DCHECK_LT(offset_, item.EndOffset());
+  if (node_.Text()[offset_] == kSpaceCharacter) {
+    // Skip one whitespace. Collapsible spaces are collapsed to single space in
+    // NGInlineItemBuilder, so this removes all collapsible spaces.
+    offset_++;
+    if (offset_ == item.EndOffset())
+      item_index_++;
+  }
+}
+
 scoped_refptr<NGInlineBreakToken> NGLineBreaker::CreateBreakToken(
     std::unique_ptr<const NGInlineLayoutStateStack> state_stack) const {
   const Vector<NGInlineItem>& items = node_.Items();
diff --git a/third_party/WebKit/Source/core/layout/ng/inline/ng_line_breaker.h b/third_party/WebKit/Source/core/layout/ng/inline/ng_line_breaker.h
index 54ee143..b7da0da 100644
--- a/third_party/WebKit/Source/core/layout/ng/inline/ng_line_breaker.h
+++ b/third_party/WebKit/Source/core/layout/ng/inline/ng_line_breaker.h
@@ -87,13 +87,6 @@
     }
   };
 
-  const String& Text() const { return break_iterator_.GetString(); }
-  NGInlineItemResult* AddItem(const NGInlineItem&,
-                              unsigned end_offset,
-                              NGInlineItemResults*);
-  NGInlineItemResult* AddItem(const NGInlineItem&, NGInlineItemResults*);
-  void ComputeCanBreakAfter(NGInlineItemResult*) const;
-
   void BreakLine(NGLineInfo*);
 
   void PrepareNextLine(const NGLayoutOpportunity&, NGLineInfo*);
@@ -102,48 +95,50 @@
   void ComputeLineLocation(NGLineInfo*) const;
 
   enum class LineBreakState {
-    // The line breaking is complete.
-    kDone,
-
-    // Should complete the line at the earliest possible point.
-    // Trailing spaces, <br>, or close tags should be included to the line even
-    // when it is overflowing.
-    kTrailing,
-
-    // The initial state. Looking for items to break the line.
-    kContinue,
+    // The current position is not breakable.
+    kNotBreakable,
+    // The current position is breakable.
+    kIsBreakable,
+    // Break by including trailing items (CloseTag).
+    kBreakAfterTrailings,
+    // Break immediately.
+    kForcedBreak
   };
 
-  LineBreakState HandleText(const NGInlineItem&, LineBreakState, NGLineInfo*);
+  LineBreakState HandleText(NGLineInfo*,
+                            const NGInlineItem&,
+                            NGInlineItemResult*);
   void BreakText(NGInlineItemResult*,
                  const NGInlineItem&,
                  LayoutUnit available_width,
                  NGLineInfo*);
-  LineBreakState HandleTrailingSpaces(const NGInlineItem&, NGLineInfo*);
-  void AppendHyphen(const ComputedStyle&, NGLineInfo*);
+  static void AppendHyphen(const ComputedStyle&, NGLineInfo*);
 
-  LineBreakState HandleControlItem(const NGInlineItem&,
-                                   LineBreakState,
-                                   NGLineInfo*);
-  LineBreakState HandleBidiControlItem(const NGInlineItem&,
-                                       LineBreakState,
-                                       NGLineInfo*);
-  void HandleAtomicInline(const NGInlineItem&, NGLineInfo*);
-  void HandleFloat(const NGInlineItem&, NGInlineItemResult*);
+  LineBreakState HandleControlItem(const NGInlineItem&, NGInlineItemResult*);
+  LineBreakState HandleAtomicInline(const NGInlineItem&,
+                                    NGInlineItemResult*,
+                                    const NGLineInfo&);
+  LineBreakState HandleFloat(const NGInlineItem&, NGInlineItemResult*);
 
   void HandleOpenTag(const NGInlineItem&, NGInlineItemResult*);
-  void HandleCloseTag(const NGInlineItem&, NGInlineItemResults*);
+  LineBreakState HandleCloseTag(const NGInlineItem&, NGInlineItemResults*);
 
-  LineBreakState HandleOverflow(NGLineInfo*);
-  LineBreakState HandleOverflow(NGLineInfo*, LayoutUnit available_width);
+  void HandleOverflow(NGLineInfo*);
+  void HandleOverflow(NGLineInfo*,
+                      LayoutUnit available_width,
+                      bool force_break_anywhere);
   void Rewind(NGLineInfo*, unsigned new_end);
 
   void TruncateOverflowingText(NGLineInfo*);
 
   void SetCurrentStyle(const ComputedStyle&);
+  bool IsFirstBreakOpportunity(unsigned, const NGLineInfo&) const;
+  static LineBreakState ToLineBreakState(const NGInlineItemResult&);
+  LineBreakState ComputeIsBreakableAfter(NGInlineItemResult*) const;
 
   void MoveToNextOf(const NGInlineItem&);
   void MoveToNextOf(const NGInlineItemResult&);
+  void SkipCollapsibleWhitespaces();
 
   bool IsFirstFormattedLine() const;
   void ComputeBaseDirection();
@@ -179,11 +174,7 @@
   bool auto_wrap_ = false;
 
   // True when current box has 'word-break/word-wrap: break-word'.
-  bool break_anywhere_if_overflow_ = false;
-
-  // Force LineBreakType::kBreakCharacter by ignoring the current style.
-  // Set to find grapheme cluster boundaries for 'break-word' after overflow.
-  bool override_break_anywhere_ = false;
+  bool break_if_overflow_ = false;
 
   // True when breaking at soft hyphens (U+00AD) is allowed.
   bool enable_soft_hyphen_ = true;
diff --git a/third_party/WebKit/Source/core/layout/ng/ng_block_layout_algorithm.cc b/third_party/WebKit/Source/core/layout/ng/ng_block_layout_algorithm.cc
index 381f832..eb1d675 100644
--- a/third_party/WebKit/Source/core/layout/ng/ng_block_layout_algorithm.cc
+++ b/third_party/WebKit/Source/core/layout/ng/ng_block_layout_algorithm.cc
@@ -1405,13 +1405,6 @@
     return fragment.BlockSize() > space_left ? SoftBreak : NoBreak;
   }
 
-  // If the block offset is past the fragmentainer boundary (or exactly at the
-  // boundary), no part of the fragment is going to fit in the current
-  // fragmentainer. Fragments may be pushed past the fragmentainer boundary by
-  // margins.
-  if (space_left <= LayoutUnit())
-    return SoftBreak;
-
   EBreakBetween break_before = JoinFragmentainerBreakValues(
       child.Style().BreakBefore(), layout_result.InitialBreakBefore());
   EBreakBetween break_between =
@@ -1423,6 +1416,13 @@
       return ForcedBreak;
   }
 
+  // If the block offset is past the fragmentainer boundary (or exactly at the
+  // boundary), no part of the fragment is going to fit in the current
+  // fragmentainer. Fragments may be pushed past the fragmentainer boundary by
+  // margins.
+  if (space_left <= LayoutUnit())
+    return SoftBreak;
+
   const auto* token = physical_fragment.BreakToken();
   if (!token || token->IsFinished())
     return NoBreak;
diff --git a/third_party/WebKit/Source/core/layout/shapes/ShapeOutsideInfo.cpp b/third_party/WebKit/Source/core/layout/shapes/ShapeOutsideInfo.cpp
index bc2cedd..f9472889 100644
--- a/third_party/WebKit/Source/core/layout/shapes/ShapeOutsideInfo.cpp
+++ b/third_party/WebKit/Source/core/layout/shapes/ShapeOutsideInfo.cpp
@@ -136,9 +136,9 @@
     WritingMode writing_mode,
     float margin) const {
   DCHECK(!style_image->IsPendingImage());
-  const LayoutSize& image_size = style_image->ImageSize(
+  const LayoutSize& image_size = RoundedLayoutSize(style_image->ImageSize(
       layout_box_.GetDocument(), layout_box_.Style()->EffectiveZoom(),
-      reference_box_logical_size_);
+      reference_box_logical_size_));
 
   const LayoutRect& margin_rect =
       GetShapeImageMarginRect(layout_box_, reference_box_logical_size_);
@@ -149,7 +149,7 @@
 
   scoped_refptr<Image> image =
       style_image->GetImage(layout_box_, layout_box_.GetDocument(),
-                            layout_box_.StyleRef(), FlooredIntSize(image_size));
+                            layout_box_.StyleRef(), image_size);
 
   return Shape::CreateRasterShape(image.get(), shape_image_threshold,
                                   image_rect, margin_rect, writing_mode,
diff --git a/third_party/WebKit/Source/core/loader/BaseFetchContext.cpp b/third_party/WebKit/Source/core/loader/BaseFetchContext.cpp
index be322cf..6907098 100644
--- a/third_party/WebKit/Source/core/loader/BaseFetchContext.cpp
+++ b/third_party/WebKit/Source/core/loader/BaseFetchContext.cpp
@@ -192,7 +192,8 @@
     case Resource::kLinkPrefetch:
     case Resource::kTextTrack:
     case Resource::kImportResource:
-    case Resource::kMedia:
+    case Resource::kAudio:
+    case Resource::kVideo:
     case Resource::kManifest:
     case Resource::kMock:
       // By default these types of resources can be loaded from any origin.
diff --git a/third_party/WebKit/Source/core/loader/DocumentLoader.cpp b/third_party/WebKit/Source/core/loader/DocumentLoader.cpp
index f014b84..8793a985 100644
--- a/third_party/WebKit/Source/core/loader/DocumentLoader.cpp
+++ b/third_party/WebKit/Source/core/loader/DocumentLoader.cpp
@@ -216,7 +216,8 @@
     case Resource::kFont:
       resource = FontResource::Fetch(params, Fetcher(), nullptr);
       break;
-    case Resource::kMedia:
+    case Resource::kAudio:
+    case Resource::kVideo:
       resource = RawResource::FetchMedia(params, Fetcher(), nullptr);
       break;
     case Resource::kTextTrack:
diff --git a/third_party/WebKit/Source/core/loader/LinkLoader.cpp b/third_party/WebKit/Source/core/loader/LinkLoader.cpp
index 49d9abfb..5506ef9 100644
--- a/third_party/WebKit/Source/core/loader/LinkLoader.cpp
+++ b/third_party/WebKit/Source/core/loader/LinkLoader.cpp
@@ -262,9 +262,9 @@
   } else if (as == "style") {
     return Resource::kCSSStyleSheet;
   } else if (as == "video") {
-    return Resource::kMedia;
+    return Resource::kVideo;
   } else if (as == "audio") {
-    return Resource::kMedia;
+    return Resource::kAudio;
   } else if (as == "track") {
     return Resource::kTextTrack;
   } else if (as == "font") {
@@ -292,7 +292,8 @@
       return MIMETypeRegistry::IsSupportedStyleSheetMIMEType(mime_type);
     case Resource::kFont:
       return MIMETypeRegistry::IsSupportedFontMIMEType(mime_type);
-    case Resource::kMedia:
+    case Resource::kAudio:
+    case Resource::kVideo:
       return MIMETypeRegistry::IsSupportedMediaMIMEType(mime_type, String());
     case Resource::kTextTrack:
       return MIMETypeRegistry::IsSupportedTextTrackMIMEType(mime_type);
diff --git a/third_party/WebKit/Source/core/loader/LinkLoaderTest.cpp b/third_party/WebKit/Source/core/loader/LinkLoaderTest.cpp
index 3638f3e..5a2e163 100644
--- a/third_party/WebKit/Source/core/loader/LinkLoaderTest.cpp
+++ b/third_party/WebKit/Source/core/loader/LinkLoaderTest.cpp
@@ -168,7 +168,7 @@
     // TODO(yoav): It doesn't seem like the audio context is ever used. That
     // should probably be fixed (or we can consolidate audio and video).
     {"http://example.test/cat.wav", "audio", "", "", "", kReferrerPolicyDefault,
-     ResourceLoadPriority::kLow, WebURLRequest::kRequestContextVideo, nullptr,
+     ResourceLoadPriority::kLow, WebURLRequest::kRequestContextAudio, nullptr,
      true, true, kReferrerPolicyDefault},
     {"http://example.test/cat.mp4", "video", "", "", "", kReferrerPolicyDefault,
      ResourceLoadPriority::kLow, WebURLRequest::kRequestContextVideo, nullptr,
@@ -226,11 +226,11 @@
      kReferrerPolicyDefault},
     {"http://example.test/cat.wav", "audio", "audio/wav", "", "",
      kReferrerPolicyDefault, ResourceLoadPriority::kLow,
-     WebURLRequest::kRequestContextVideo, nullptr, true, true,
+     WebURLRequest::kRequestContextAudio, nullptr, true, true,
      kReferrerPolicyDefault},
     {"http://example.test/cat.wav", "audio", "audio/mp57", "", "",
      kReferrerPolicyDefault, ResourceLoadPriority::kUnresolved,
-     WebURLRequest::kRequestContextVideo, nullptr, false, false,
+     WebURLRequest::kRequestContextAudio, nullptr, false, false,
      kReferrerPolicyDefault},
     {"http://example.test/cat.webm", "video", "video/webm", "", "",
      kReferrerPolicyDefault, ResourceLoadPriority::kLow,
diff --git a/third_party/WebKit/Source/core/page/DragController.cpp b/third_party/WebKit/Source/core/page/DragController.cpp
index 2d81e5c6..d349b2a 100644
--- a/third_party/WebKit/Source/core/page/DragController.cpp
+++ b/third_party/WebKit/Source/core/page/DragController.cpp
@@ -1050,7 +1050,7 @@
   if (image->IsSVGImage()) {
     KURL url = element->GetDocument().CompleteURL(element->ImageSourceURL());
     svg_image = SVGImageForContainer::Create(
-        ToSVGImage(image), image_element_size_in_pixels, 1, url);
+        ToSVGImage(image), LayoutSize(image_element_size_in_pixels), 1, url);
     image = svg_image.get();
   }
 
diff --git a/third_party/WebKit/Source/core/paint/BackgroundImageGeometry.cpp b/third_party/WebKit/Source/core/paint/BackgroundImageGeometry.cpp
index dddb1d5..6cd4d23 100644
--- a/third_party/WebKit/Source/core/paint/BackgroundImageGeometry.cpp
+++ b/third_party/WebKit/Source/core/paint/BackgroundImageGeometry.cpp
@@ -63,8 +63,8 @@
   StyleImage* image = fill_layer.GetImage();
   EFillSizeType type = fill_layer.Size().type;
 
-  LayoutSize image_intrinsic_size = image->ImageSize(
-      obj.GetDocument(), obj.Style()->EffectiveZoom(), positioning_area_size);
+  LayoutSize image_intrinsic_size(image->ImageSize(
+      obj.GetDocument(), obj.Style()->EffectiveZoom(), positioning_area_size));
   switch (type) {
     case EFillSizeType::kSizeLength: {
       LayoutSize tile_size(positioning_area_size);
diff --git a/third_party/WebKit/Source/core/paint/BoxPainterBase.cpp b/third_party/WebKit/Source/core/paint/BoxPainterBase.cpp
index 38f630a..e16fd0ac 100644
--- a/third_party/WebKit/Source/core/paint/BoxPainterBase.cpp
+++ b/third_party/WebKit/Source/core/paint/BoxPainterBase.cpp
@@ -543,9 +543,9 @@
     geometry.Calculate(paint_info.PaintContainer(), paint_info.phase,
                        paint_info.GetGlobalPaintFlags(), bg_layer,
                        scrolled_paint_rect);
-    image = info.image->GetImage(
-        geometry.ImageClient(), geometry.ImageDocument(), geometry.ImageStyle(),
-        FlooredIntSize(geometry.TileSize()));
+    image =
+        info.image->GetImage(geometry.ImageClient(), geometry.ImageDocument(),
+                             geometry.ImageStyle(), geometry.TileSize());
     interpolation_quality_context.emplace(
         context, geometry.ImageStyle().GetInterpolationQuality());
 
diff --git a/third_party/WebKit/Source/core/paint/ImagePainter.cpp b/third_party/WebKit/Source/core/paint/ImagePainter.cpp
index 9f1b1e4..bbd8df0 100644
--- a/third_party/WebKit/Source/core/paint/ImagePainter.cpp
+++ b/third_party/WebKit/Source/core/paint/ImagePainter.cpp
@@ -150,8 +150,8 @@
   if (pixel_snapped_dest_rect.IsEmpty())
     return;
 
-  scoped_refptr<Image> image =
-      layout_image_.ImageResource()->GetImage(pixel_snapped_dest_rect.Size());
+  scoped_refptr<Image> image = layout_image_.ImageResource()->GetImage(
+      LayoutSize(pixel_snapped_dest_rect.Size()));
   if (!image || image->IsNull())
     return;
 
diff --git a/third_party/WebKit/Source/core/paint/ListMarkerPainter.cpp b/third_party/WebKit/Source/core/paint/ListMarkerPainter.cpp
index 7609784..c8c04be 100644
--- a/third_party/WebKit/Source/core/paint/ListMarkerPainter.cpp
+++ b/third_party/WebKit/Source/core/paint/ListMarkerPainter.cpp
@@ -69,8 +69,8 @@
 
   LayoutRect box(box_origin, layout_list_marker_.Size());
 
-  IntRect marker = layout_list_marker_.GetRelativeMarkerRect();
-  marker.MoveBy(RoundedIntPoint(box_origin));
+  LayoutRect marker = layout_list_marker_.GetRelativeMarkerRect();
+  marker.MoveBy(box_origin);
 
   GraphicsContext& context = local_paint_info.context;
 
@@ -82,7 +82,7 @@
             ->GetImage(layout_list_marker_, layout_list_marker_.GetDocument(),
                        layout_list_marker_.StyleRef(), marker.Size())
             .get(),
-        Image::kSyncDecode, marker);
+        Image::kSyncDecode, FloatRect(marker));
     if (layout_list_marker_.GetSelectionState() != SelectionState::kNone) {
       LayoutRect sel_rect = layout_list_marker_.LocalSelectionRect();
       sel_rect.MoveBy(box_origin);
@@ -113,7 +113,7 @@
   const EListStyleType list_style =
       layout_list_marker_.Style()->ListStyleType();
   if (style_category == LayoutListMarker::ListStyleCategory::kSymbol) {
-    PaintSymbol(context, color, marker, list_style);
+    PaintSymbol(context, color, PixelSnappedIntRect(marker), list_style);
     return;
   }
 
@@ -126,7 +126,7 @@
 
   GraphicsContextStateSaver state_saver(context, false);
   if (!layout_list_marker_.Style()->IsHorizontalWritingMode()) {
-    marker.MoveBy(RoundedIntPoint(-box_origin));
+    marker.MoveBy(-box_origin);
     marker = marker.TransposedRect();
     marker.MoveBy(
         IntPoint(RoundToInt(box.X()),
@@ -138,12 +138,13 @@
   }
 
   TextRunPaintInfo text_run_paint_info(text_run);
-  text_run_paint_info.bounds = marker;
+  text_run_paint_info.bounds = EnclosingIntRect(marker);
   const SimpleFontData* font_data =
       layout_list_marker_.Style()->GetFont().PrimaryFont();
-  IntPoint text_origin = IntPoint(
-      marker.X(),
-      marker.Y() + (font_data ? font_data->GetFontMetrics().Ascent() : 0));
+  IntPoint text_origin =
+      IntPoint(marker.X().Round(),
+               marker.Y().Round() +
+                   (font_data ? font_data->GetFontMetrics().Ascent() : 0));
 
   // Text is not arbitrary. We can judge whether it's RTL from the first
   // character, and we only need to handle the direction RightToLeft for now.
@@ -167,7 +168,7 @@
       ConstructTextRun(font, suffix_str, 2, layout_list_marker_.StyleRef(),
                        layout_list_marker_.Style()->Direction());
   TextRunPaintInfo suffix_run_info(suffix_run);
-  suffix_run_info.bounds = marker;
+  suffix_run_info.bounds = EnclosingIntRect(marker);
 
   if (layout_list_marker_.Style()->IsLeftToRightDirection()) {
     context.DrawText(font, text_run_paint_info, text_origin);
diff --git a/third_party/WebKit/Source/core/paint/NinePieceImagePainter.cpp b/third_party/WebKit/Source/core/paint/NinePieceImagePainter.cpp
index 4f0864f..2453326 100644
--- a/third_party/WebKit/Source/core/paint/NinePieceImagePainter.cpp
+++ b/third_party/WebKit/Source/core/paint/NinePieceImagePainter.cpp
@@ -94,7 +94,7 @@
   IntSize image_size = RoundedIntSize(
       style_image->ImageSize(document, 1, border_image_rect.Size()));
   scoped_refptr<Image> image =
-      style_image->GetImage(observer, document, style, image_size);
+      style_image->GetImage(observer, document, style, LayoutSize(image_size));
 
   TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"), "PaintImage",
                "data",
diff --git a/third_party/WebKit/Source/core/paint/SVGImagePainter.cpp b/third_party/WebKit/Source/core/paint/SVGImagePainter.cpp
index cde88a3..cf5cc7e 100644
--- a/third_party/WebKit/Source/core/paint/SVGImagePainter.cpp
+++ b/third_party/WebKit/Source/core/paint/SVGImagePainter.cpp
@@ -66,7 +66,8 @@
   if (image_viewport_size.IsEmpty())
     return;
 
-  scoped_refptr<Image> image = image_resource->GetImage(image_viewport_size);
+  scoped_refptr<Image> image =
+      image_resource->GetImage(LayoutSize(image_viewport_size));
   FloatRect dest_rect = layout_svg_image_.ObjectBoundingBox();
   FloatRect src_rect(0, 0, image->width(), image->height());
 
diff --git a/third_party/WebKit/Source/core/style/StyleFetchedImage.cpp b/third_party/WebKit/Source/core/style/StyleFetchedImage.cpp
index 96cd3de..d6278bb 100644
--- a/third_party/WebKit/Source/core/style/StyleFetchedImage.cpp
+++ b/third_party/WebKit/Source/core/style/StyleFetchedImage.cpp
@@ -79,7 +79,7 @@
   return image_->ErrorOccurred();
 }
 
-LayoutSize StyleFetchedImage::ImageSize(
+FloatSize StyleFetchedImage::ImageSize(
     const Document&,
     float multiplier,
     const LayoutSize& default_object_size) const {
@@ -93,7 +93,7 @@
   // border-image, etc.)
   //
   // https://drafts.csswg.org/css-images-3/#the-image-orientation
-  LayoutSize size(image_->IntrinsicSize(kDoNotRespectImageOrientation));
+  FloatSize size(image_->IntrinsicSize(kDoNotRespectImageOrientation));
   return ApplyZoom(size, multiplier);
 }
 
@@ -130,7 +130,7 @@
     const ImageResourceObserver&,
     const Document&,
     const ComputedStyle& style,
-    const IntSize& container_size) const {
+    const LayoutSize& container_size) const {
   Image* image = image_->GetImage();
   if (!image->IsSVGImage())
     return image;
diff --git a/third_party/WebKit/Source/core/style/StyleFetchedImage.h b/third_party/WebKit/Source/core/style/StyleFetchedImage.h
index 26cd41a..ca737ba 100644
--- a/third_party/WebKit/Source/core/style/StyleFetchedImage.h
+++ b/third_party/WebKit/Source/core/style/StyleFetchedImage.h
@@ -54,19 +54,20 @@
   bool CanRender() const override;
   bool IsLoaded() const override;
   bool ErrorOccurred() const override;
-  LayoutSize ImageSize(const Document&,
-                       float multiplier,
-                       const LayoutSize& default_object_size) const override;
+  FloatSize ImageSize(const Document&,
+                      float multiplier,
+                      const LayoutSize& default_object_size) const override;
   bool ImageHasRelativeSize() const override;
   bool UsesImageContainerSize() const override;
   void AddClient(ImageResourceObserver*) override;
   void RemoveClient(ImageResourceObserver*) override;
   void ImageNotifyFinished(ImageResourceContent*) override;
   String DebugName() const override { return "StyleFetchedImage"; }
-  scoped_refptr<Image> GetImage(const ImageResourceObserver&,
-                                const Document&,
-                                const ComputedStyle&,
-                                const IntSize& container_size) const override;
+  scoped_refptr<Image> GetImage(
+      const ImageResourceObserver&,
+      const Document&,
+      const ComputedStyle&,
+      const LayoutSize& container_size) const override;
   bool KnownToBeOpaque(const Document&, const ComputedStyle&) const override;
   ImageResourceContent* CachedImage() const override;
 
diff --git a/third_party/WebKit/Source/core/style/StyleFetchedImageSet.cpp b/third_party/WebKit/Source/core/style/StyleFetchedImageSet.cpp
index fdc9333..8ec4889 100644
--- a/third_party/WebKit/Source/core/style/StyleFetchedImageSet.cpp
+++ b/third_party/WebKit/Source/core/style/StyleFetchedImageSet.cpp
@@ -80,7 +80,7 @@
   return best_fit_image_->ErrorOccurred();
 }
 
-LayoutSize StyleFetchedImageSet::ImageSize(
+FloatSize StyleFetchedImageSet::ImageSize(
     const Document&,
     float multiplier,
     const LayoutSize& default_object_size) const {
@@ -94,9 +94,9 @@
   // border-image, etc.)
   //
   // https://drafts.csswg.org/css-images-3/#the-image-orientation
-  LayoutSize natural_size(
+  FloatSize natural_size(
       best_fit_image_->IntrinsicSize(kDoNotRespectImageOrientation));
-  LayoutSize scaled_image_size(ApplyZoom(natural_size, multiplier));
+  FloatSize scaled_image_size(ApplyZoom(natural_size, multiplier));
   scaled_image_size.Scale(1 / image_scale_factor_);
   return scaled_image_size;
 }
@@ -121,7 +121,7 @@
     const ImageResourceObserver&,
     const Document&,
     const ComputedStyle& style,
-    const IntSize& container_size) const {
+    const LayoutSize& container_size) const {
   Image* image = best_fit_image_->GetImage();
   if (!image->IsSVGImage())
     return image;
diff --git a/third_party/WebKit/Source/core/style/StyleFetchedImageSet.h b/third_party/WebKit/Source/core/style/StyleFetchedImageSet.h
index 1e64a211..013d6670 100644
--- a/third_party/WebKit/Source/core/style/StyleFetchedImageSet.h
+++ b/third_party/WebKit/Source/core/style/StyleFetchedImageSet.h
@@ -65,17 +65,18 @@
   bool CanRender() const override;
   bool IsLoaded() const override;
   bool ErrorOccurred() const override;
-  LayoutSize ImageSize(const Document&,
-                       float multiplier,
-                       const LayoutSize& default_object_size) const override;
+  FloatSize ImageSize(const Document&,
+                      float multiplier,
+                      const LayoutSize& default_object_size) const override;
   bool ImageHasRelativeSize() const override;
   bool UsesImageContainerSize() const override;
   void AddClient(ImageResourceObserver*) override;
   void RemoveClient(ImageResourceObserver*) override;
-  scoped_refptr<Image> GetImage(const ImageResourceObserver&,
-                                const Document&,
-                                const ComputedStyle&,
-                                const IntSize& container_size) const override;
+  scoped_refptr<Image> GetImage(
+      const ImageResourceObserver&,
+      const Document&,
+      const ComputedStyle&,
+      const LayoutSize& container_size) const override;
   float ImageScaleFactor() const override { return image_scale_factor_; }
   bool KnownToBeOpaque(const Document&, const ComputedStyle&) const override;
   ImageResourceContent* CachedImage() const override;
diff --git a/third_party/WebKit/Source/core/style/StyleGeneratedImage.cpp b/third_party/WebKit/Source/core/style/StyleGeneratedImage.cpp
index 649d2ec..37c27fff 100644
--- a/third_party/WebKit/Source/core/style/StyleGeneratedImage.cpp
+++ b/third_party/WebKit/Source/core/style/StyleGeneratedImage.cpp
@@ -45,23 +45,23 @@
   return image_generator_value_->ValueWithURLsMadeAbsolute();
 }
 
-LayoutSize StyleGeneratedImage::ImageSize(
+FloatSize StyleGeneratedImage::ImageSize(
     const Document& document,
     float multiplier,
     const LayoutSize& default_object_size) const {
   if (fixed_size_) {
     FloatSize unzoomed_default_object_size(default_object_size);
     unzoomed_default_object_size.Scale(1 / multiplier);
-    return ApplyZoom(LayoutSize(image_generator_value_->FixedSize(
+    return ApplyZoom(FloatSize(image_generator_value_->FixedSize(
                          document, unzoomed_default_object_size)),
                      multiplier);
   }
 
-  return default_object_size;
+  return FloatSize(default_object_size);
 }
 
 void StyleGeneratedImage::AddClient(ImageResourceObserver* observer) {
-  image_generator_value_->AddClient(observer, IntSize());
+  image_generator_value_->AddClient(observer, LayoutSize());
 }
 
 void StyleGeneratedImage::RemoveClient(ImageResourceObserver* observer) {
@@ -72,7 +72,7 @@
     const ImageResourceObserver& observer,
     const Document& document,
     const ComputedStyle& style,
-    const IntSize& container_size) const {
+    const LayoutSize& container_size) const {
   return image_generator_value_->GetImage(observer, document, style,
                                           container_size);
 }
diff --git a/third_party/WebKit/Source/core/style/StyleGeneratedImage.h b/third_party/WebKit/Source/core/style/StyleGeneratedImage.h
index 9cbe1e02..e340e8d 100644
--- a/third_party/WebKit/Source/core/style/StyleGeneratedImage.h
+++ b/third_party/WebKit/Source/core/style/StyleGeneratedImage.h
@@ -47,18 +47,19 @@
   CSSValue* CssValue() const override;
   CSSValue* ComputedCSSValue() const override;
 
-  LayoutSize ImageSize(const Document&,
-                       float multiplier,
-                       const LayoutSize& default_object_size) const override;
+  FloatSize ImageSize(const Document&,
+                      float multiplier,
+                      const LayoutSize& default_object_size) const override;
   bool ImageHasRelativeSize() const override { return !fixed_size_; }
   bool UsesImageContainerSize() const override { return !fixed_size_; }
   void AddClient(ImageResourceObserver*) override;
   void RemoveClient(ImageResourceObserver*) override;
-  // The |container_size| is the container size with subpixel snapping
-  scoped_refptr<Image> GetImage(const ImageResourceObserver&,
-                                const Document&,
-                                const ComputedStyle&,
-                                const IntSize& container_size) const override;
+  // The |container_size| is the container size
+  scoped_refptr<Image> GetImage(
+      const ImageResourceObserver&,
+      const Document&,
+      const ComputedStyle&,
+      const LayoutSize& container_size) const override;
   bool KnownToBeOpaque(const Document&, const ComputedStyle&) const override;
 
   virtual void Trace(blink::Visitor*);
diff --git a/third_party/WebKit/Source/core/style/StyleImage.cpp b/third_party/WebKit/Source/core/style/StyleImage.cpp
index bd1c465..8e37235 100644
--- a/third_party/WebKit/Source/core/style/StyleImage.cpp
+++ b/third_party/WebKit/Source/core/style/StyleImage.cpp
@@ -10,33 +10,34 @@
 
 namespace blink {
 
-LayoutSize StyleImage::ApplyZoom(const LayoutSize& size,
-                                 float multiplier) const {
+FloatSize StyleImage::ApplyZoom(const FloatSize& size, float multiplier) const {
   if (multiplier == 1.0f || ImageHasRelativeSize())
     return size;
 
-  LayoutUnit width(size.Width() * multiplier);
-  LayoutUnit height(size.Height() * multiplier);
+  float width = size.Width() * multiplier;
+  float height = size.Height() * multiplier;
 
   // Don't let images that have a width/height >= 1 shrink below 1 when zoomed.
-  if (size.Width() > LayoutUnit())
-    width = std::max(LayoutUnit(1), width);
+  if (size.Width() > 0)
+    width = std::max(1.0f, width);
 
-  if (size.Height() > LayoutUnit())
-    height = std::max(LayoutUnit(1), height);
+  if (size.Height() > 0)
+    height = std::max(1.0f, height);
 
-  return LayoutSize(width, height);
+  return FloatSize(width, height);
 }
 
-LayoutSize StyleImage::ImageSizeForSVGImage(
+FloatSize StyleImage::ImageSizeForSVGImage(
     SVGImage* svg_image,
     float multiplier,
     const LayoutSize& default_object_size) const {
   FloatSize unzoomed_default_object_size(default_object_size);
   unzoomed_default_object_size.Scale(1 / multiplier);
-  LayoutSize image_size(RoundedIntSize(
-      svg_image->ConcreteObjectSize(unzoomed_default_object_size)));
-  return ApplyZoom(image_size, multiplier);
+  // FIXME(schenney): Remove this rounding hack once background image
+  // geometry is converted to handle rounding downstream.
+  return FloatSize(RoundedIntSize(
+      ApplyZoom(svg_image->ConcreteObjectSize(unzoomed_default_object_size),
+                multiplier)));
 }
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/style/StyleImage.h b/third_party/WebKit/Source/core/style/StyleImage.h
index e4414491..344c1a2 100644
--- a/third_party/WebKit/Source/core/style/StyleImage.h
+++ b/third_party/WebKit/Source/core/style/StyleImage.h
@@ -32,7 +32,6 @@
 
 class CSSValue;
 class ImageResourceContent;
-class IntSize;
 class LayoutSize;
 class SVGImage;
 class Document;
@@ -74,7 +73,9 @@
   virtual bool ErrorOccurred() const { return false; }
 
   // Determine the concrete object size of this <image>, scaled by multiplier,
-  // using the specified default object size.
+  // using the specified default object size. Return value as a FloatSize
+  // because we want integer sizes to remain integers when zoomed and then
+  // unzoomed. That is, (size * multiplier) / multiplier == size.
   //
   // The default object size is context dependent, see for instance the
   // "Examples of CSS Object Sizing" section of the CSS images specification.
@@ -83,9 +84,9 @@
   // The |default_object_size| is assumed to be in the effective zoom level
   // given by multiplier, i.e. if multiplier is 1 the |default_object_size| is
   // not zoomed.
-  virtual LayoutSize ImageSize(const Document&,
-                               float multiplier,
-                               const LayoutSize& default_object_size) const = 0;
+  virtual FloatSize ImageSize(const Document&,
+                              float multiplier,
+                              const LayoutSize& default_object_size) const = 0;
 
   // The <image> does not have any intrinsic dimensions.
   virtual bool ImageHasRelativeSize() const = 0;
@@ -107,7 +108,7 @@
       const ImageResourceObserver&,
       const Document&,
       const ComputedStyle&,
-      const IntSize& container_size) const = 0;
+      const LayoutSize& container_size) const = 0;
 
   // Opaque handle representing the underlying value of this <image>.
   virtual WrappedImagePtr Data() const = 0;
@@ -150,10 +151,10 @@
   bool is_invalid_image_ : 1;
   bool is_paint_image_ : 1;
 
-  LayoutSize ApplyZoom(const LayoutSize&, float multiplier) const;
-  LayoutSize ImageSizeForSVGImage(SVGImage*,
-                                  float multiplier,
-                                  const LayoutSize& default_object_size) const;
+  FloatSize ApplyZoom(const FloatSize&, float multiplier) const;
+  FloatSize ImageSizeForSVGImage(SVGImage*,
+                                 float multiplier,
+                                 const LayoutSize& default_object_size) const;
 };
 
 #define DEFINE_STYLE_IMAGE_TYPE_CASTS(thisType, function)                   \
diff --git a/third_party/WebKit/Source/core/style/StyleInvalidImage.h b/third_party/WebKit/Source/core/style/StyleInvalidImage.h
index b6b7b18..ab9aba0 100644
--- a/third_party/WebKit/Source/core/style/StyleInvalidImage.h
+++ b/third_party/WebKit/Source/core/style/StyleInvalidImage.h
@@ -30,19 +30,20 @@
   CSSValue* ComputedCSSValue() const override { return CssValue(); }
   bool CanRender() const override { return false; }
 
-  LayoutSize ImageSize(const Document&,
-                       float /*multiplier*/,
-                       const LayoutSize& /*defaultObjectSize*/) const override {
-    return LayoutSize();
+  FloatSize ImageSize(const Document&,
+                      float /*multiplier*/,
+                      const LayoutSize& /*defaultObjectSize*/) const override {
+    return FloatSize();
   }
   bool ImageHasRelativeSize() const override { return false; }
   bool UsesImageContainerSize() const override { return false; }
   void AddClient(ImageResourceObserver*) override {}
   void RemoveClient(ImageResourceObserver*) override {}
-  scoped_refptr<Image> GetImage(const ImageResourceObserver&,
-                                const Document&,
-                                const ComputedStyle&,
-                                const IntSize& container_size) const override {
+  scoped_refptr<Image> GetImage(
+      const ImageResourceObserver&,
+      const Document&,
+      const ComputedStyle&,
+      const LayoutSize& container_size) const override {
     return nullptr;
   }
   bool KnownToBeOpaque(const Document&, const ComputedStyle&) const override {
diff --git a/third_party/WebKit/Source/core/style/StylePendingImage.h b/third_party/WebKit/Source/core/style/StylePendingImage.h
index b7741680..9d1dd7a 100644
--- a/third_party/WebKit/Source/core/style/StylePendingImage.h
+++ b/third_party/WebKit/Source/core/style/StylePendingImage.h
@@ -72,19 +72,20 @@
                                      : nullptr;
   }
 
-  LayoutSize ImageSize(const Document&,
-                       float /*multiplier*/,
-                       const LayoutSize& /*defaultObjectSize*/) const override {
-    return LayoutSize();
+  FloatSize ImageSize(const Document&,
+                      float /*multiplier*/,
+                      const LayoutSize& /*defaultObjectSize*/) const override {
+    return FloatSize();
   }
   bool ImageHasRelativeSize() const override { return false; }
   bool UsesImageContainerSize() const override { return false; }
   void AddClient(ImageResourceObserver*) override {}
   void RemoveClient(ImageResourceObserver*) override {}
-  scoped_refptr<Image> GetImage(const ImageResourceObserver&,
-                                const Document&,
-                                const ComputedStyle&,
-                                const IntSize& container_size) const override {
+  scoped_refptr<Image> GetImage(
+      const ImageResourceObserver&,
+      const Document&,
+      const ComputedStyle&,
+      const LayoutSize& container_size) const override {
     NOTREACHED();
     return nullptr;
   }
diff --git a/third_party/WebKit/Source/core/svg/graphics/SVGImageForContainer.h b/third_party/WebKit/Source/core/svg/graphics/SVGImageForContainer.h
index 87f80cd..877661d 100644
--- a/third_party/WebKit/Source/core/svg/graphics/SVGImageForContainer.h
+++ b/third_party/WebKit/Source/core/svg/graphics/SVGImageForContainer.h
@@ -60,7 +60,7 @@
  public:
   static scoped_refptr<SVGImageForContainer> Create(
       SVGImage* image,
-      const IntSize& container_size,
+      const LayoutSize& container_size,
       float zoom,
       const KURL& url) {
     FloatSize container_size_without_zoom(container_size);
diff --git a/third_party/WebKit/Source/core/url/DOMURL.cpp b/third_party/WebKit/Source/core/url/DOMURL.cpp
index ecdb238..0f009651 100644
--- a/third_party/WebKit/Source/core/url/DOMURL.cpp
+++ b/third_party/WebKit/Source/core/url/DOMURL.cpp
@@ -79,8 +79,7 @@
 
 String DOMURL::CreatePublicURL(ExecutionContext* execution_context,
                                URLRegistrable* registrable) {
-  return execution_context->GetPublicURLManager().RegisterURL(execution_context,
-                                                              registrable);
+  return execution_context->GetPublicURLManager().RegisterURL(registrable);
 }
 
 URLSearchParams* DOMURL::searchParams() {
diff --git a/third_party/WebKit/Source/core/workers/WorkerNavigator.h b/third_party/WebKit/Source/core/workers/WorkerNavigator.h
index 780037b..a74443c 100644
--- a/third_party/WebKit/Source/core/workers/WorkerNavigator.h
+++ b/third_party/WebKit/Source/core/workers/WorkerNavigator.h
@@ -28,6 +28,7 @@
 
 #include "core/CoreExport.h"
 #include "core/frame/NavigatorConcurrentHardware.h"
+#include "core/frame/NavigatorDeviceMemory.h"
 #include "core/frame/NavigatorID.h"
 #include "core/frame/NavigatorOnLine.h"
 #include "platform/Supplementable.h"
@@ -40,6 +41,7 @@
 class CORE_EXPORT WorkerNavigator final
     : public ScriptWrappable,
       public NavigatorConcurrentHardware,
+      public NavigatorDeviceMemory,
       public NavigatorID,
       public NavigatorOnLine,
       public Supplementable<WorkerNavigator> {
diff --git a/third_party/WebKit/Source/core/workers/WorkerNavigator.idl b/third_party/WebKit/Source/core/workers/WorkerNavigator.idl
index 1d9c714..ee7b34b 100644
--- a/third_party/WebKit/Source/core/workers/WorkerNavigator.idl
+++ b/third_party/WebKit/Source/core/workers/WorkerNavigator.idl
@@ -34,6 +34,7 @@
 };
 
 WorkerNavigator implements NavigatorConcurrentHardware;
+WorkerNavigator implements NavigatorDeviceMemory;
 WorkerNavigator implements NavigatorID;
 // TODO(foolip): WorkerNavigator implements NavigatorLanguage;
 WorkerNavigator implements NavigatorOnLine;
diff --git a/third_party/WebKit/Source/devtools/front_end/persistence/module.json b/third_party/WebKit/Source/devtools/front_end/persistence/module.json
index 88ec30e..1115870d 100644
--- a/third_party/WebKit/Source/devtools/front_end/persistence/module.json
+++ b/third_party/WebKit/Source/devtools/front_end/persistence/module.json
@@ -20,7 +20,6 @@
             "title": "Enable Local Overrides",
             "settingName": "persistenceNetworkOverridesEnabled",
             "settingType": "boolean",
-            "storageType": "session",
             "defaultValue": false,
             "tags": "interception, override, network, rewrite, request",
             "options": [
diff --git a/third_party/WebKit/Source/modules/cachestorage/CacheTest.cpp b/third_party/WebKit/Source/modules/cachestorage/CacheTest.cpp
index 2b0dac7e..0f11f52 100644
--- a/third_party/WebKit/Source/modules/cachestorage/CacheTest.cpp
+++ b/third_party/WebKit/Source/modules/cachestorage/CacheTest.cpp
@@ -28,7 +28,7 @@
 #include "core/fetch/Response.h"
 #include "core/fetch/ResponseInit.h"
 #include "core/frame/Frame.h"
-#include "core/testing/DummyPageHolder.h"
+#include "core/testing/PageTestBase.h"
 #include "public/platform/WebURLResponse.h"
 #include "public/platform/modules/cache_storage/cache_storage.mojom-blink.h"
 #include "public/platform/modules/serviceworker/WebServiceWorkerCache.h"
@@ -239,9 +239,9 @@
       : ErrorWebCacheForTests(CacheStorageError::kErrorNotImplemented) {}
 };
 
-class CacheStorageTest : public ::testing::Test {
+class CacheStorageTest : public PageTestBase {
  public:
-  CacheStorageTest() : page_(DummyPageHolder::Create(IntSize(1, 1))) {}
+  void SetUp() override { PageTestBase::SetUp(IntSize(1, 1)); }
 
   Cache* CreateCache(ScopedFetcherForTests* fetcher,
                      WebServiceWorkerCache* web_cache) {
@@ -249,7 +249,7 @@
   }
 
   ScriptState* GetScriptState() {
-    return ToScriptStateForMainWorld(page_->GetDocument().GetFrame());
+    return ToScriptStateForMainWorld(GetDocument().GetFrame());
   }
   ExecutionContext* GetExecutionContext() {
     return ExecutionContext::From(GetScriptState());
@@ -338,9 +338,6 @@
 
     ScriptValue* value_;
   };
-
-  // Lifetime is that of the text fixture.
-  std::unique_ptr<DummyPageHolder> page_;
 };
 
 RequestInfo StringToRequestInfo(const String& value) {
diff --git a/third_party/WebKit/Source/modules/canvas/offscreencanvas/OffscreenCanvasTest.cpp b/third_party/WebKit/Source/modules/canvas/offscreencanvas/OffscreenCanvasTest.cpp
index d1419d80..81d23a3 100644
--- a/third_party/WebKit/Source/modules/canvas/offscreencanvas/OffscreenCanvasTest.cpp
+++ b/third_party/WebKit/Source/modules/canvas/offscreencanvas/OffscreenCanvasTest.cpp
@@ -8,7 +8,7 @@
 #include "core/html/HTMLCanvasElement.h"
 #include "core/loader/EmptyClients.h"
 #include "core/offscreencanvas/OffscreenCanvas.h"
-#include "core/testing/DummyPageHolder.h"
+#include "core/testing/PageTestBase.h"
 #include "modules/canvas/htmlcanvas/HTMLCanvasElementModule.h"
 #include "modules/canvas/offscreencanvas2d/OffscreenCanvasRenderingContext2D.h"
 #include "platform/graphics/gpu/SharedGpuContext.h"
@@ -23,14 +23,12 @@
 
 namespace blink {
 
-class OffscreenCanvasTest : public ::testing::Test {
+class OffscreenCanvasTest : public PageTestBase {
  protected:
   OffscreenCanvasTest();
   void SetUp() override;
   void TearDown() override;
 
-  DummyPageHolder& Page() const { return *dummy_page_holder_; }
-  Document& GetDocument() const { return *document_; }
   HTMLCanvasElement& CanvasElement() const { return *canvas_element_; }
   OffscreenCanvas& OSCanvas() const { return *offscreen_canvas_; }
   OffscreenCanvasFrameDispatcher* Dispatcher() const {
@@ -45,8 +43,6 @@
   }
 
  private:
-  std::unique_ptr<DummyPageHolder> dummy_page_holder_;
-  Persistent<Document> document_;
   Persistent<HTMLCanvasElement> canvas_element_;
   Persistent<OffscreenCanvas> offscreen_canvas_;
   Persistent<OffscreenCanvasRenderingContext2D> context_;
@@ -67,19 +63,15 @@
       WTF::BindRepeating(factory, WTF::Unretained(&gl_)));
   Page::PageClients page_clients;
   FillWithEmptyClients(page_clients);
-  dummy_page_holder_ =
-      DummyPageHolder::Create(IntSize(800, 600), &page_clients);
-  document_ = &dummy_page_holder_->GetDocument();
-  document_->documentElement()->SetInnerHTMLFromString(
-      "<body><canvas id='c'></canvas></body>");
-  document_->View()->UpdateAllLifecyclePhases();
-  canvas_element_ = ToHTMLCanvasElement(document_->getElementById("c"));
+  PageTestBase::SetupPageWithClients(&page_clients);
+  SetHtmlInnerHTML("<body><canvas id='c'></canvas></body>");
+  canvas_element_ = ToHTMLCanvasElement(GetElementById("c"));
   DummyExceptionStateForTesting exception_state;
   offscreen_canvas_ = HTMLCanvasElementModule::transferControlToOffscreen(
       *canvas_element_, exception_state);
   CanvasContextCreationAttributes attrs;
   context_ = static_cast<OffscreenCanvasRenderingContext2D*>(
-      offscreen_canvas_->GetCanvasRenderingContext(document_, String("2d"),
+      offscreen_canvas_->GetCanvasRenderingContext(&GetDocument(), String("2d"),
                                                    attrs));
 }
 
@@ -112,14 +104,12 @@
   EXPECT_FALSE(Dispatcher()->IsAnimationSuspended());
 
   // Change visibility to hidden -> animation should be suspended
-  Page().GetPage().SetVisibilityState(mojom::PageVisibilityState::kHidden,
-                                      false);
+  GetPage().SetVisibilityState(mojom::PageVisibilityState::kHidden, false);
   platform()->RunUntilIdle();
   EXPECT_TRUE(Dispatcher()->IsAnimationSuspended());
 
   // Change visibility to visible -> animation should resume
-  Page().GetPage().SetVisibilityState(mojom::PageVisibilityState::kVisible,
-                                      false);
+  GetPage().SetVisibilityState(mojom::PageVisibilityState::kVisible, false);
   platform()->RunUntilIdle();
   EXPECT_FALSE(Dispatcher()->IsAnimationSuspended());
 }
diff --git a/third_party/WebKit/Source/modules/credentialmanager/PasswordCredentialTest.cpp b/third_party/WebKit/Source/modules/credentialmanager/PasswordCredentialTest.cpp
index c349ac0..5c29995 100644
--- a/third_party/WebKit/Source/modules/credentialmanager/PasswordCredentialTest.cpp
+++ b/third_party/WebKit/Source/modules/credentialmanager/PasswordCredentialTest.cpp
@@ -12,20 +12,15 @@
 #include "core/html/forms/FormController.h"
 #include "core/html/forms/FormData.h"
 #include "core/html/forms/HTMLFormElement.h"
-#include "core/testing/DummyPageHolder.h"
+#include "core/testing/PageTestBase.h"
 #include "platform/wtf/text/StringBuilder.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace blink {
 
-class PasswordCredentialTest : public ::testing::Test {
+class PasswordCredentialTest : public PageTestBase {
  protected:
-  void SetUp() override {
-    dummy_page_holder_ = DummyPageHolder::Create();
-    document_ = &dummy_page_holder_->GetDocument();
-  }
-
-  Document& GetDocument() const { return *document_; }
+  void SetUp() override { PageTestBase::SetUp(IntSize()); }
 
   HTMLFormElement* PopulateForm(const char* enctype, const char* html) {
     StringBuilder b;
@@ -34,17 +29,11 @@
     b.Append("'>");
     b.Append(html);
     b.Append("</form></body></html>");
-    GetDocument().documentElement()->SetInnerHTMLFromString(b.ToString());
-    GetDocument().View()->UpdateAllLifecyclePhases();
-    HTMLFormElement* form =
-        ToHTMLFormElement(GetDocument().getElementById("theForm"));
+    SetHtmlInnerHTML(b.ToString().Utf8().data());
+    HTMLFormElement* form = ToHTMLFormElement(GetElementById("theForm"));
     EXPECT_NE(nullptr, form);
     return form;
   }
-
- private:
-  std::unique_ptr<DummyPageHolder> dummy_page_holder_;
-  Persistent<Document> document_;
 };
 
 TEST_F(PasswordCredentialTest, CreateFromMultipartForm) {
diff --git a/third_party/WebKit/Source/modules/csspaint/CSSPaintDefinition.cpp b/third_party/WebKit/Source/modules/csspaint/CSSPaintDefinition.cpp
index f19c9ac..d1656c17 100644
--- a/third_party/WebKit/Source/modules/csspaint/CSSPaintDefinition.cpp
+++ b/third_party/WebKit/Source/modules/csspaint/CSSPaintDefinition.cpp
@@ -126,7 +126,7 @@
   }
 
   return PaintGeneratedImage::Create(rendering_context->GetRecord(),
-                                     container_size);
+                                     FloatSize(container_size));
 }
 
 void CSSPaintDefinition::MaybeCreatePaintInstance() {
diff --git a/third_party/WebKit/Source/modules/csspaint/PaintWorkletTest.cpp b/third_party/WebKit/Source/modules/csspaint/PaintWorkletTest.cpp
index adb9694..3f11f04 100644
--- a/third_party/WebKit/Source/modules/csspaint/PaintWorkletTest.cpp
+++ b/third_party/WebKit/Source/modules/csspaint/PaintWorkletTest.cpp
@@ -9,7 +9,7 @@
 #include "bindings/core/v8/V8GCController.h"
 #include "bindings/core/v8/WorkerOrWorkletScriptController.h"
 #include "core/frame/LocalFrame.h"
-#include "core/testing/DummyPageHolder.h"
+#include "core/testing/PageTestBase.h"
 #include "modules/csspaint/CSSPaintDefinition.h"
 #include "modules/csspaint/PaintWorkletGlobalScope.h"
 #include "modules/csspaint/PaintWorkletGlobalScopeProxy.h"
@@ -38,13 +38,12 @@
   size_t paints_to_switch_;
 };
 
-class PaintWorkletTest : public ::testing::Test {
+class PaintWorkletTest : public PageTestBase {
  public:
-  PaintWorkletTest() : page_(DummyPageHolder::Create()) {}
-
   void SetUp() override {
+    PageTestBase::SetUp(IntSize());
     test_paint_worklet_ =
-        new TestPaintWorklet(page_->GetDocument().domWindow()->GetFrame());
+        new TestPaintWorklet(GetDocument().domWindow()->GetFrame());
     proxy_ = test_paint_worklet_->CreateGlobalScope();
   }
 
@@ -89,13 +88,11 @@
   }
 
   void Terminate() {
-    page_.reset();
     proxy_->TerminateWorkletGlobalScope();
     proxy_ = nullptr;
   }
 
  private:
-  std::unique_ptr<DummyPageHolder> page_;
   Persistent<WorkletGlobalScopeProxy> proxy_;
   Persistent<TestPaintWorklet> test_paint_worklet_;
 };
diff --git a/third_party/WebKit/Source/modules/media_controls/MediaControlsRotateToFullscreenDelegate.cpp b/third_party/WebKit/Source/modules/media_controls/MediaControlsRotateToFullscreenDelegate.cpp
index 70da76bce..05c845c5 100644
--- a/third_party/WebKit/Source/modules/media_controls/MediaControlsRotateToFullscreenDelegate.cpp
+++ b/third_party/WebKit/Source/modules/media_controls/MediaControlsRotateToFullscreenDelegate.cpp
@@ -58,8 +58,11 @@
 
   // TODO(795286): device orientation now requires a v8::Context in the stack so
   // we are creating one so the event pump starts running.
-  ScriptState::Scope scope(
-      ToScriptStateForMainWorld(video_element_->GetDocument().GetFrame()));
+  LocalFrame* frame = video_element_->GetDocument().GetFrame();
+  if (!frame)
+    return;
+
+  ScriptState::Scope scope(ToScriptStateForMainWorld(frame));
   dom_window->addEventListener(EventTypeNames::deviceorientation, this, false);
 }
 
diff --git a/third_party/WebKit/Source/modules/serviceworkers/ServiceWorkerContainerTest.cpp b/third_party/WebKit/Source/modules/serviceworkers/ServiceWorkerContainerTest.cpp
index 92fcc29..00157ce 100644
--- a/third_party/WebKit/Source/modules/serviceworkers/ServiceWorkerContainerTest.cpp
+++ b/third_party/WebKit/Source/modules/serviceworkers/ServiceWorkerContainerTest.cpp
@@ -18,7 +18,7 @@
 #include "core/dom/Document.h"
 #include "core/dom/ExecutionContext.h"
 #include "core/page/FocusController.h"
-#include "core/testing/DummyPageHolder.h"
+#include "core/testing/PageTestBase.h"
 #include "modules/serviceworkers/NavigatorServiceWorker.h"
 #include "modules/serviceworkers/ServiceWorkerContainerClient.h"
 #include "platform/bindings/ScriptState.h"
@@ -145,41 +145,38 @@
   }
 };
 
-class ServiceWorkerContainerTest : public ::testing::Test {
+class ServiceWorkerContainerTest : public PageTestBase {
  protected:
-  ServiceWorkerContainerTest() : page_(DummyPageHolder::Create()) {}
+  void SetUp() override { PageTestBase::SetUp(IntSize()); }
 
   ~ServiceWorkerContainerTest() override {
-    page_.reset();
     V8GCController::CollectAllGarbageForTesting(GetIsolate());
   }
 
-  ExecutionContext* GetExecutionContext() { return &(page_->GetDocument()); }
+  ExecutionContext* GetExecutionContext() { return &GetDocument(); }
   NavigatorServiceWorker* GetNavigatorServiceWorker() {
-    return NavigatorServiceWorker::From(page_->GetDocument());
+    return NavigatorServiceWorker::From(GetDocument());
   }
   v8::Isolate* GetIsolate() { return v8::Isolate::GetCurrent(); }
   ScriptState* GetScriptState() {
-    return ToScriptStateForMainWorld(page_->GetDocument().GetFrame());
+    return ToScriptStateForMainWorld(GetDocument().GetFrame());
   }
 
   void Provide(std::unique_ptr<WebServiceWorkerProvider> provider) {
     Supplement<Document>::ProvideTo(
-        page_->GetDocument(), ServiceWorkerContainerClient::SupplementName(),
-        new ServiceWorkerContainerClient(page_->GetDocument(),
-                                         std::move(provider)));
+        GetDocument(), ServiceWorkerContainerClient::SupplementName(),
+        new ServiceWorkerContainerClient(GetDocument(), std::move(provider)));
   }
 
   void SetPageURL(const String& url) {
     // For URL completion.
-    page_->GetDocument().SetURL(KURL(NullURL(), url));
+    GetDocument().SetURL(KURL(NullURL(), url));
 
     // The basis for security checks.
-    page_->GetDocument().SetSecurityOrigin(
-        SecurityOrigin::CreateFromString(url));
+    GetDocument().SetSecurityOrigin(SecurityOrigin::CreateFromString(url));
 
     if (url.StartsWith("https://") || url.StartsWith("http://localhost/")) {
-      page_->GetDocument().SetSecureContextStateForTesting(
+      GetDocument().SetSecureContextStateForTesting(
           SecureContextState::kSecure);
     }
   }
@@ -212,9 +209,6 @@
         container->getRegistration(GetScriptState(), document_url);
     ExpectRejected(GetScriptState(), promise, value_test);
   }
-
- private:
-  std::unique_ptr<DummyPageHolder> page_;
 };
 
 TEST_F(ServiceWorkerContainerTest, Register_NonSecureOriginIsRejected) {
diff --git a/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.cpp b/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.cpp
index e992690..26a11e4c 100644
--- a/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.cpp
+++ b/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.cpp
@@ -94,8 +94,8 @@
 #include "platform/bindings/V8BindingMacros.h"
 #include "platform/geometry/IntSize.h"
 #include "platform/graphics/AcceleratedStaticBitmapImage.h"
+#include "platform/graphics/CanvasResourceProvider.h"
 #include "platform/graphics/GraphicsContext.h"
-#include "platform/graphics/UnacceleratedImageBufferSurface.h"
 #include "platform/graphics/gpu/AcceleratedImageBufferSurface.h"
 #include "platform/graphics/gpu/SharedGpuContext.h"
 #include "platform/runtime_enabled_features.h"
@@ -4561,25 +4561,25 @@
   DCHECK(image);
 
   IntSize size(width, height);
-  ImageBuffer* buf = generated_image_cache_.GetImageBuffer(size);
-  if (!buf) {
+  CanvasResourceProvider* resource_provider =
+      generated_image_cache_.GetCanvasResourceProvider(size);
+  if (!resource_provider) {
     SynthesizeGLError(GL_OUT_OF_MEMORY, function_name, "out of memory");
     return nullptr;
   }
 
   if (!image->CurrentFrameKnownToBeOpaque())
-    buf->Canvas()->clear(SK_ColorTRANSPARENT);
+    resource_provider->Canvas()->clear(SK_ColorTRANSPARENT);
 
   IntRect src_rect(IntPoint(), image->Size());
   IntRect dest_rect(0, 0, size.Width(), size.Height());
   PaintFlags flags;
   // TODO(ccameron): WebGL should produce sRGB images.
   // https://crbug.com/672299
-  image->Draw(buf->Canvas(), flags, dest_rect, src_rect,
+  image->Draw(resource_provider->Canvas(), flags, dest_rect, src_rect,
               kDoNotRespectImageOrientation,
               Image::kDoNotClampImageToSourceRect, Image::kSyncDecode);
-  return buf->NewImageSnapshot(kPreferNoAcceleration,
-                               kSnapshotReasonWebGLDrawImageIntoBuffer);
+  return resource_provider->Snapshot();
 }
 
 WebGLTexture* WebGLRenderingContextBase::ValidateTexImageBinding(
@@ -5212,15 +5212,16 @@
                       "video visible size is empty");
     return nullptr;
   }
-  ImageBuffer* buf = generated_image_cache_.GetImageBuffer(visible_size);
-  if (!buf) {
+  CanvasResourceProvider* resource_provider =
+      generated_image_cache_.GetCanvasResourceProvider(visible_size);
+  if (!resource_provider) {
     SynthesizeGLError(GL_OUT_OF_MEMORY, "texImage2D", "out of memory");
     return nullptr;
   }
   IntRect dest_rect(0, 0, visible_size.Width(), visible_size.Height());
-  video->PaintCurrentFrame(buf->Canvas(), dest_rect, nullptr,
+  video->PaintCurrentFrame(resource_provider->Canvas(), dest_rect, nullptr,
                            already_uploaded_id, out_metadata);
-  return buf->NewImageSnapshot();
+  return resource_provider->Snapshot();
 }
 
 void WebGLRenderingContextBase::TexImageHelperHTMLVideoElement(
@@ -7600,38 +7601,42 @@
   return text;
 }
 
-WebGLRenderingContextBase::LRUImageBufferCache::LRUImageBufferCache(
-    int capacity)
-    : buffers_(WrapArrayUnique(new std::unique_ptr<ImageBuffer>[capacity])),
+WebGLRenderingContextBase::LRUCanvasResourceProviderCache::
+    LRUCanvasResourceProviderCache(int capacity)
+    : resource_providers_(WrapArrayUnique(
+          new std::unique_ptr<CanvasResourceProvider>[capacity])),
       capacity_(capacity) {}
 
-ImageBuffer* WebGLRenderingContextBase::LRUImageBufferCache::GetImageBuffer(
-    const IntSize& size) {
+CanvasResourceProvider* WebGLRenderingContextBase::
+    LRUCanvasResourceProviderCache::GetCanvasResourceProvider(
+        const IntSize& size) {
   int i;
   for (i = 0; i < capacity_; ++i) {
-    ImageBuffer* buf = buffers_[i].get();
-    if (!buf)
+    CanvasResourceProvider* resource_provider = resource_providers_[i].get();
+    if (!resource_provider)
       break;
-    if (buf->Size() != size)
+    if (resource_provider->Size() != size)
       continue;
     BubbleToFront(i);
-    return buf;
+    return resource_provider;
   }
 
-  std::unique_ptr<ImageBuffer> temp(ImageBuffer::Create(size));
+  std::unique_ptr<CanvasResourceProvider> temp(CanvasResourceProvider::Create(
+      size, CanvasResourceProvider::kSoftwareResourceUsage));
   if (!temp)
     return nullptr;
   i = std::min(capacity_ - 1, i);
-  buffers_[i] = std::move(temp);
+  resource_providers_[i] = std::move(temp);
 
-  ImageBuffer* buf = buffers_[i].get();
+  CanvasResourceProvider* resource_provider = resource_providers_[i].get();
   BubbleToFront(i);
-  return buf;
+  return resource_provider;
 }
 
-void WebGLRenderingContextBase::LRUImageBufferCache::BubbleToFront(int idx) {
+void WebGLRenderingContextBase::LRUCanvasResourceProviderCache::BubbleToFront(
+    int idx) {
   for (int i = idx; i > 0; --i)
-    buffers_[i].swap(buffers_[i - 1]);
+    resource_providers_[i].swap(resource_providers_[i - 1]);
 }
 
 namespace {
diff --git a/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.h b/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.h
index 63c70fe..0d5b02f4 100644
--- a/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.h
+++ b/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.h
@@ -45,7 +45,6 @@
 #include "platform/bindings/ScriptState.h"
 #include "platform/bindings/ScriptWrappable.h"
 #include "platform/bindings/ScriptWrappableVisitor.h"
-#include "platform/graphics/ImageBuffer.h"
 #include "platform/graphics/gpu/DrawingBuffer.h"
 #include "platform/graphics/gpu/Extensions3DUtil.h"
 #include "platform/graphics/gpu/WebGLImageConversion.h"
@@ -67,6 +66,7 @@
 
 namespace blink {
 
+class CanvasResourceProvider;
 class EXTDisjointTimerQuery;
 class EXTDisjointTimerQueryWebGL2;
 class ExceptionState;
@@ -74,7 +74,6 @@
 class HTMLImageElement;
 class HTMLVideoElement;
 class ImageBitmap;
-class ImageBuffer;
 class ImageData;
 class IntSize;
 class OESVertexArrayObject;
@@ -743,19 +742,20 @@
 
   Vector<GLenum> compressed_texture_formats_;
 
-  // Fixed-size cache of reusable image buffers for video texImage2D calls.
-  class LRUImageBufferCache {
+  // Fixed-size cache of reusable resource providers for video texImage2D calls.
+  class LRUCanvasResourceProviderCache {
    public:
-    LRUImageBufferCache(int capacity);
+    LRUCanvasResourceProviderCache(int capacity);
     // The pointer returned is owned by the image buffer map.
-    ImageBuffer* GetImageBuffer(const IntSize&);
+    CanvasResourceProvider* GetCanvasResourceProvider(const IntSize&);
 
    private:
     void BubbleToFront(int idx);
-    std::unique_ptr<std::unique_ptr<ImageBuffer>[]> buffers_;
+    std::unique_ptr<std::unique_ptr<CanvasResourceProvider>[]>
+        resource_providers_;
     int capacity_;
   };
-  LRUImageBufferCache generated_image_cache_;
+  LRUCanvasResourceProviderCache generated_image_cache_;
 
   GLint max_texture_size_;
   GLint max_cube_map_texture_size_;
diff --git a/third_party/WebKit/Source/modules/xr/XRDevice.cpp b/third_party/WebKit/Source/modules/xr/XRDevice.cpp
index d0cc1be6..3a772598 100644
--- a/third_party/WebKit/Source/modules/xr/XRDevice.cpp
+++ b/third_party/WebKit/Source/modules/xr/XRDevice.cpp
@@ -157,7 +157,6 @@
 void XRDevice::SetXRDisplayInfo(
     device::mojom::blink::VRDisplayInfoPtr display_info) {
   display_info_ = std::move(display_info);
-  device_name_ = display_info_->displayName;
   is_external_ = display_info_->capabilities->hasExternalDisplay;
   supports_exclusive_ = (display_info_->capabilities->canPresent);
 }
diff --git a/third_party/WebKit/Source/modules/xr/XRDevice.h b/third_party/WebKit/Source/modules/xr/XRDevice.h
index 1a856e8..169af58 100644
--- a/third_party/WebKit/Source/modules/xr/XRDevice.h
+++ b/third_party/WebKit/Source/modules/xr/XRDevice.h
@@ -31,7 +31,6 @@
            device::mojom::blink::VRDisplayInfoPtr);
   XR* xr() const { return xr_; }
 
-  const String& deviceName() const { return device_name_; }
   bool external() const { return is_external_; }
 
   ScriptPromise supportsSession(ScriptState*,
@@ -75,7 +74,6 @@
 
   Member<XR> xr_;
   Member<XRFrameProvider> frame_provider_;
-  String device_name_;
   bool is_external_;
   bool supports_exclusive_;
 
diff --git a/third_party/WebKit/Source/modules/xr/XRDevice.idl b/third_party/WebKit/Source/modules/xr/XRDevice.idl
index d96ffb698..084b106 100644
--- a/third_party/WebKit/Source/modules/xr/XRDevice.idl
+++ b/third_party/WebKit/Source/modules/xr/XRDevice.idl
@@ -7,7 +7,6 @@
     SecureContext,
     RuntimeEnabled=WebXR
 ] interface XRDevice : EventTarget {
-  readonly attribute DOMString deviceName;
   readonly attribute boolean external;
 
   [CallWith=ScriptState] Promise supportsSession([PermissiveDictionaryConversion] optional XRSessionCreationOptions options);
diff --git a/third_party/WebKit/Source/platform/BUILD.gn b/third_party/WebKit/Source/platform/BUILD.gn
index 88f33f3..30e5706 100644
--- a/third_party/WebKit/Source/platform/BUILD.gn
+++ b/third_party/WebKit/Source/platform/BUILD.gn
@@ -876,7 +876,6 @@
     "geometry/IntRectOutsets.h",
     "geometry/IntSize.cpp",
     "geometry/IntSize.h",
-    "geometry/IntSizeHash.h",
     "geometry/LayoutPoint.cpp",
     "geometry/LayoutPoint.h",
     "geometry/LayoutRect.cpp",
@@ -885,6 +884,7 @@
     "geometry/LayoutRectOutsets.h",
     "geometry/LayoutSize.cpp",
     "geometry/LayoutSize.h",
+    "geometry/LayoutSizeHash.h",
     "geometry/Region.cpp",
     "geometry/Region.h",
     "geometry/TransformState.cpp",
diff --git a/third_party/WebKit/Source/platform/DragImage.cpp b/third_party/WebKit/Source/platform/DragImage.cpp
index ac0a927e..3a4a452 100644
--- a/third_party/WebKit/Source/platform/DragImage.cpp
+++ b/third_party/WebKit/Source/platform/DragImage.cpp
@@ -36,9 +36,9 @@
 #include "platform/geometry/FloatRect.h"
 #include "platform/geometry/IntPoint.h"
 #include "platform/graphics/BitmapImage.h"
+#include "platform/graphics/CanvasResourceProvider.h"
 #include "platform/graphics/Color.h"
 #include "platform/graphics/GraphicsContext.h"
-#include "platform/graphics/ImageBuffer.h"
 #include "platform/graphics/StaticBitmapImage.h"
 #include "platform/graphics/paint/DrawingRecorder.h"
 #include "platform/runtime_enabled_features.h"
@@ -256,11 +256,13 @@
   // fill the background
   IntSize scaled_image_size = image_size;
   scaled_image_size.Scale(device_scale_factor);
-  std::unique_ptr<ImageBuffer> buffer(ImageBuffer::Create(scaled_image_size));
-  if (!buffer)
+  std::unique_ptr<CanvasResourceProvider> resource_provider(
+      CanvasResourceProvider::Create(
+          scaled_image_size, CanvasResourceProvider::kSoftwareResourceUsage));
+  if (!resource_provider)
     return nullptr;
 
-  buffer->Canvas()->scale(device_scale_factor, device_scale_factor);
+  resource_provider->Canvas()->scale(device_scale_factor, device_scale_factor);
 
   const float kDragLabelRadius = 5;
 
@@ -271,7 +273,7 @@
   SkRRect rrect;
   rrect.setRectXY(SkRect::MakeWH(image_size.Width(), image_size.Height()),
                   kDragLabelRadius, kDragLabelRadius);
-  buffer->Canvas()->drawRRect(rrect, background_paint);
+  resource_provider->Canvas()->drawRRect(rrect, background_paint);
 
   // Draw the text
   PaintFlags text_paint;
@@ -285,8 +287,8 @@
         image_size.Height() -
             (kLabelBorderYOffset + url_font_data->GetFontMetrics().Descent()));
     TextRun text_run(url_string);
-    url_font.DrawText(buffer->Canvas(), TextRunPaintInfo(text_run), text_pos,
-                      device_scale_factor, text_paint);
+    url_font.DrawText(resource_provider->Canvas(), TextRunPaintInfo(text_run),
+                      text_pos, device_scale_factor, text_paint);
   }
 
   if (clip_label_string)
@@ -305,11 +307,12 @@
     int available_width = image_size.Width() - kDragLabelBorderX * 2;
     text_pos.SetX(available_width - ceilf(text_width));
   }
-  label_font.DrawBidiText(buffer->Canvas(), TextRunPaintInfo(text_run),
-                          FloatPoint(text_pos), Font::kDoNotPaintIfFontNotReady,
-                          device_scale_factor, text_paint);
+  label_font.DrawBidiText(resource_provider->Canvas(),
+                          TextRunPaintInfo(text_run), FloatPoint(text_pos),
+                          Font::kDoNotPaintIfFontNotReady, device_scale_factor,
+                          text_paint);
 
-  scoped_refptr<StaticBitmapImage> image = buffer->NewImageSnapshot();
+  scoped_refptr<StaticBitmapImage> image = resource_provider->Snapshot();
   return DragImage::Create(image.get(), kDoNotRespectImageOrientation,
                            device_scale_factor);
 }
diff --git a/third_party/WebKit/Source/platform/WebVectorTest.cpp b/third_party/WebKit/Source/platform/WebVectorTest.cpp
index 93bdf818..2c6b74b 100644
--- a/third_party/WebKit/Source/platform/WebVectorTest.cpp
+++ b/third_party/WebKit/Source/platform/WebVectorTest.cpp
@@ -151,6 +151,28 @@
     EXPECT_EQ(i, vector[i]);
 }
 
+TEST(WebVectorTest, ResizeToSameSize) {
+  WebVector<int> vector;
+  vector.reserve(10);
+  for (int i = 0; i < 10; ++i)
+    vector.emplace_back(i);
+  vector.resize(10);
+  ASSERT_EQ(10U, vector.size());
+  for (int i = 0; i < 10; ++i)
+    EXPECT_EQ(i, vector[i]);
+}
+
+TEST(WebVectorTest, ResizeShrink) {
+  WebVector<int> vector;
+  vector.reserve(10);
+  for (int i = 0; i < 10; ++i)
+    vector.emplace_back(i);
+  vector.resize(5);
+  ASSERT_EQ(5U, vector.size());
+  for (int i = 0; i < 5; ++i)
+    EXPECT_EQ(i, vector[i]);
+}
+
 namespace {
 
 // Used to ensure that WebVector supports types without a default constructor.
diff --git a/third_party/WebKit/Source/platform/bindings/V8DOMActivityLogger.cpp b/third_party/WebKit/Source/platform/bindings/V8DOMActivityLogger.cpp
index 37c9302..83b808e 100644
--- a/third_party/WebKit/Source/platform/bindings/V8DOMActivityLogger.cpp
+++ b/third_party/WebKit/Source/platform/bindings/V8DOMActivityLogger.cpp
@@ -33,6 +33,18 @@
   return map;
 }
 
+void V8DOMActivityLogger::LogMethod(const char* api_name,
+                                    v8::FunctionCallbackInfo<v8::Value> info) {
+  DCHECK(static_cast<size_t>(info.Length()) <=
+         Vector<v8::Local<v8::Value>>::MaxCapacity());
+  Vector<v8::Local<v8::Value>> loggerArgs;
+  loggerArgs.ReserveInitialCapacity(info.Length());
+  for (int i = 0; i < info.Length(); ++i) {
+    loggerArgs.UncheckedAppend(info[i]);
+  }
+  LogMethod(api_name, info.Length(), loggerArgs.data());
+}
+
 void V8DOMActivityLogger::SetActivityLogger(
     int world_id,
     const String& extension_id,
diff --git a/third_party/WebKit/Source/platform/bindings/V8DOMActivityLogger.h b/third_party/WebKit/Source/platform/bindings/V8DOMActivityLogger.h
index 4a64ad3e..fe28de55 100644
--- a/third_party/WebKit/Source/platform/bindings/V8DOMActivityLogger.h
+++ b/third_party/WebKit/Source/platform/bindings/V8DOMActivityLogger.h
@@ -57,6 +57,8 @@
                         int argc,
                         const String* argv) {}
 
+  void LogMethod(const char* api_name, v8::FunctionCallbackInfo<v8::Value>);
+
   // Associates a logger with the world identified by worldId (worlId may be 0
   // identifying the main world) and extension ID. Extension ID is used to
   // identify a logger for main world only (worldId == 0). If the world is not
diff --git a/third_party/WebKit/Source/platform/blob/BlobData.cpp b/third_party/WebKit/Source/platform/blob/BlobData.cpp
index 575ba18c..5b22560 100644
--- a/third_party/WebKit/Source/platform/blob/BlobData.cpp
+++ b/third_party/WebKit/Source/platform/blob/BlobData.cpp
@@ -450,12 +450,6 @@
   return blob_clone;
 }
 
-// static
-void BlobDataHandle::SetBlobRegistryForTesting(
-    mojom::blink::BlobRegistry* registry) {
-  g_blob_registry_for_testing = registry;
-}
-
 void BlobDataHandle::ReadAll(mojo::ScopedDataPipeProducerHandle pipe,
                              mojom::blink::BlobReaderClientPtr client) {
   MutexLocker locker(blob_info_mutex_);
@@ -476,4 +470,15 @@
   blob_info_ = blob.PassInterface();
 }
 
+// static
+mojom::blink::BlobRegistry* BlobDataHandle::GetBlobRegistry() {
+  return GetThreadSpecificRegistry();
+}
+
+// static
+void BlobDataHandle::SetBlobRegistryForTesting(
+    mojom::blink::BlobRegistry* registry) {
+  g_blob_registry_for_testing = registry;
+}
+
 }  // namespace blink
diff --git a/third_party/WebKit/Source/platform/blob/BlobData.h b/third_party/WebKit/Source/platform/blob/BlobData.h
index 3bc5602..1b24adf5 100644
--- a/third_party/WebKit/Source/platform/blob/BlobData.h
+++ b/third_party/WebKit/Source/platform/blob/BlobData.h
@@ -264,8 +264,6 @@
 
   mojom::blink::BlobPtr CloneBlobPtr();
 
-  static void SetBlobRegistryForTesting(mojom::blink::BlobRegistry*);
-
   void ReadAll(mojo::ScopedDataPipeProducerHandle,
                mojom::blink::BlobReaderClientPtr);
   void ReadRange(uint64_t offset,
@@ -273,6 +271,9 @@
                  mojo::ScopedDataPipeProducerHandle,
                  mojom::blink::BlobReaderClientPtr);
 
+  static mojom::blink::BlobRegistry* GetBlobRegistry();
+  static void SetBlobRegistryForTesting(mojom::blink::BlobRegistry*);
+
  private:
   BlobDataHandle();
   BlobDataHandle(std::unique_ptr<BlobData>, long long size);
diff --git a/third_party/WebKit/Source/platform/blob/BlobDataTest.cpp b/third_party/WebKit/Source/platform/blob/BlobDataTest.cpp
index 1786b04..f54f6959 100644
--- a/third_party/WebKit/Source/platform/blob/BlobDataTest.cpp
+++ b/third_party/WebKit/Source/platform/blob/BlobDataTest.cpp
@@ -114,9 +114,9 @@
     std::move(callback).Run();
   }
 
-  void RegisterURL(BlobPtr blob,
-                   const KURL& url,
-                   RegisterURLCallback callback) override {
+  void URLStoreForOrigin(
+      const scoped_refptr<const SecurityOrigin>& origin,
+      mojom::blink::BlobURLStoreAssociatedRequest request) override {
     NOTREACHED();
   }
 
diff --git a/third_party/WebKit/Source/platform/fonts/shaping/ShapingLineBreaker.cpp b/third_party/WebKit/Source/platform/fonts/shaping/ShapingLineBreaker.cpp
index 0f8cd57..6ed7065 100644
--- a/third_party/WebKit/Source/platform/fonts/shaping/ShapingLineBreaker.cpp
+++ b/third_party/WebKit/Source/platform/fonts/shaping/ShapingLineBreaker.cpp
@@ -34,6 +34,10 @@
 
 namespace {
 
+inline bool IsHangableSpace(UChar ch) {
+  return ch == kSpaceCharacter || ch == kTabulationCharacter;
+}
+
 // ShapingLineBreaker computes using visual positions. This function flips
 // logical advance to visual, or vice versa.
 LayoutUnit FlipRtl(LayoutUnit value, TextDirection direction) {
@@ -117,11 +121,11 @@
   unsigned previous_break_opportunity =
       break_iterator_->PreviousBreakOpportunity(offset, start);
   unsigned word_start = previous_break_opportunity;
-  // Skip the leading spaces of this word because the break iterator breaks
-  // before spaces.
-  while (word_start < text.length() &&
-         LazyLineBreakIterator::IsBreakableSpace(text[word_start]))
-    word_start++;
+  if (break_iterator_->BreakSpace() != BreakSpaceType::kAfter) {
+    while (word_start < text.length() &&
+           LazyLineBreakIterator::IsBreakableSpace(text[word_start]))
+      word_start++;
+  }
   if (offset >= word_start &&
       ShouldHyphenate(text, previous_break_opportunity, word_end)) {
     unsigned prefix_length = Hyphenate(offset, word_start, word_end, backwards);
@@ -223,6 +227,7 @@
   DCHECK_GE(start, range_start);
   DCHECK_LT(start, range_end);
   result_out->is_hyphenated = false;
+  result_out->has_hanging_spaces = false;
   const String& text = GetText();
 
   // The start position in the original shape results.
@@ -251,18 +256,30 @@
   // comparing floats. See ShapeLineZeroAvailableWidth on Linux/Mac.
   candidate_break = std::max(candidate_break, start);
 
-  unsigned break_opportunity = PreviousBreakOpportunity(
-      candidate_break, start, &result_out->is_hyphenated);
-  if (break_opportunity <= start) {
-    break_opportunity =
-        NextBreakOpportunity(std::max(candidate_break, start + 1), start,
-                             &result_out->is_hyphenated);
-    // |range_end| may not be a break opportunity, but this function cannot
-    // measure beyond it.
+  unsigned break_opportunity;
+  if (break_iterator_->BreakSpace() == BreakSpaceType::kAfter &&
+      IsHangableSpace(text[candidate_break])) {
+    // If BreakAfterSpace, allow spaces to hang over the available space.
+    result_out->has_hanging_spaces = true;
+    break_opportunity = break_iterator_->NextBreakOpportunity(candidate_break);
     if (break_opportunity >= range_end) {
       result_out->break_offset = range_end;
       return ShapeToEnd(start, start_position, range_end);
     }
+  } else {
+    break_opportunity = PreviousBreakOpportunity(candidate_break, start,
+                                                 &result_out->is_hyphenated);
+    if (break_opportunity <= start) {
+      break_opportunity =
+          NextBreakOpportunity(std::max(candidate_break, start + 1), start,
+                               &result_out->is_hyphenated);
+      // |range_end| may not be a break opportunity, but this function cannot
+      // measure beyond it.
+      if (break_opportunity >= range_end) {
+        result_out->break_offset = range_end;
+        return ShapeToEnd(start, start_position, range_end);
+      }
+    }
   }
   DCHECK_GT(break_opportunity, start);
 
diff --git a/third_party/WebKit/Source/platform/fonts/shaping/ShapingLineBreaker.h b/third_party/WebKit/Source/platform/fonts/shaping/ShapingLineBreaker.h
index d17ebfd..d091274 100644
--- a/third_party/WebKit/Source/platform/fonts/shaping/ShapingLineBreaker.h
+++ b/third_party/WebKit/Source/platform/fonts/shaping/ShapingLineBreaker.h
@@ -54,6 +54,11 @@
     // The hyphen glyph is not included in the |ShapeResult|, and that appending
     // a hyphen glyph may overflow the specified available space.
     bool is_hyphenated;
+
+    // True if trailing spaces hang over the given |available_space|.
+    // False when the result does not have trailing spaces, or trailing spaces
+    // do not hang.
+    bool has_hanging_spaces;
   };
 
   // Shapes a line of text by finding a valid and appropriate break opportunity
diff --git a/third_party/WebKit/Source/platform/geometry/IntSizeHash.h b/third_party/WebKit/Source/platform/geometry/LayoutSizeHash.h
similarity index 69%
rename from third_party/WebKit/Source/platform/geometry/IntSizeHash.h
rename to third_party/WebKit/Source/platform/geometry/LayoutSizeHash.h
index d39ac49..bed648f 100644
--- a/third_party/WebKit/Source/platform/geometry/IntSizeHash.h
+++ b/third_party/WebKit/Source/platform/geometry/LayoutSizeHash.h
@@ -17,10 +17,10 @@
  * Boston, MA 02110-1301, USA.
  *
  */
-#ifndef IntSizeHash_h
-#define IntSizeHash_h
+#ifndef LayoutSizeHash_h
+#define LayoutSizeHash_h
 
-#include "platform/geometry/IntSize.h"
+#include "platform/geometry/LayoutSize.h"
 #include "platform/wtf/Allocator.h"
 #include "platform/wtf/HashMap.h"
 #include "platform/wtf/HashSet.h"
@@ -28,14 +28,14 @@
 namespace WTF {
 
 template <>
-struct DefaultHash<blink::IntSize> {
+struct DefaultHash<blink::LayoutSize> {
   STATIC_ONLY(DefaultHash);
   struct Hash {
     STATIC_ONLY(Hash);
-    static unsigned GetHash(const blink::IntSize& key) {
-      return HashInts(key.Width(), key.Height());
+    static unsigned GetHash(const blink::LayoutSize& key) {
+      return HashInts(key.Width().RawValue(), key.Height().RawValue());
     }
-    static bool Equal(const blink::IntSize& a, const blink::IntSize& b) {
+    static bool Equal(const blink::LayoutSize& a, const blink::LayoutSize& b) {
       return a == b;
     }
     static const bool safe_to_compare_to_empty_or_deleted = true;
@@ -43,13 +43,13 @@
 };
 
 template <>
-struct HashTraits<blink::IntSize> : GenericHashTraits<blink::IntSize> {
+struct HashTraits<blink::LayoutSize> : GenericHashTraits<blink::LayoutSize> {
   STATIC_ONLY(HashTraits);
   static const bool kEmptyValueIsZero = true;
-  static void ConstructDeletedValue(blink::IntSize& slot, bool) {
-    new (NotNull, &slot) blink::IntSize(-1, -1);
+  static void ConstructDeletedValue(blink::LayoutSize& slot, bool) {
+    slot = blink::LayoutSize(-1, -1);
   }
-  static bool IsDeletedValue(const blink::IntSize& value) {
+  static bool IsDeletedValue(const blink::LayoutSize& value) {
     return value.Width() == -1 && value.Height() == -1;
   }
 };
diff --git a/third_party/WebKit/Source/platform/graphics/Canvas2DLayerBridge.cpp b/third_party/WebKit/Source/platform/graphics/Canvas2DLayerBridge.cpp
index 9b2ece8..05d0740 100644
--- a/third_party/WebKit/Source/platform/graphics/Canvas2DLayerBridge.cpp
+++ b/third_party/WebKit/Source/platform/graphics/Canvas2DLayerBridge.cpp
@@ -277,8 +277,8 @@
           : CanvasResourceProvider::kSoftwareCompositedResourceUsage;
 
   resource_provider_ = CanvasResourceProvider::Create(
-      Size(), msaa_sample_count_, color_params_, usage,
-      SharedGpuContext::ContextProviderWrapper());
+      Size(), usage, SharedGpuContext::ContextProviderWrapper(),
+      msaa_sample_count_, color_params_);
 
   if (resource_provider_) {
     // Always save an initial frame, to support resetting the top level matrix
@@ -596,9 +596,9 @@
   if (shared_gl && shared_gl->GetGraphicsResetStatusKHR() == GL_NO_ERROR) {
     std::unique_ptr<CanvasResourceProvider> resource_provider =
         CanvasResourceProvider::Create(
-            Size(), msaa_sample_count_, color_params_,
-            CanvasResourceProvider::kAcceleratedCompositedResourceUsage,
-            std::move(context_provider_wrapper));
+            Size(), CanvasResourceProvider::kAcceleratedCompositedResourceUsage,
+            std::move(context_provider_wrapper), msaa_sample_count_,
+            color_params_);
 
     if (!resource_provider)
       ReportResourceProviderCreationFailure();
diff --git a/third_party/WebKit/Source/platform/graphics/CanvasResourceProvider.cpp b/third_party/WebKit/Source/platform/graphics/CanvasResourceProvider.cpp
index 87c9cbf..023235fd 100644
--- a/third_party/WebKit/Source/platform/graphics/CanvasResourceProvider.cpp
+++ b/third_party/WebKit/Source/platform/graphics/CanvasResourceProvider.cpp
@@ -218,11 +218,10 @@
 
 std::unique_ptr<CanvasResourceProvider> CanvasResourceProvider::Create(
     const IntSize& size,
-    unsigned msaa_sample_count,
-    const CanvasColorParams& colorParams,
     ResourceUsage usage,
-    base::WeakPtr<WebGraphicsContext3DProviderWrapper>
-        context_provider_wrapper) {
+    base::WeakPtr<WebGraphicsContext3DProviderWrapper> context_provider_wrapper,
+    unsigned msaa_sample_count,
+    const CanvasColorParams& colorParams) {
   const ResourceType* resource_type_fallback_list = nullptr;
   size_t list_length = 0;
 
diff --git a/third_party/WebKit/Source/platform/graphics/CanvasResourceProvider.h b/third_party/WebKit/Source/platform/graphics/CanvasResourceProvider.h
index 13ee4074..553ccf2 100644
--- a/third_party/WebKit/Source/platform/graphics/CanvasResourceProvider.h
+++ b/third_party/WebKit/Source/platform/graphics/CanvasResourceProvider.h
@@ -65,10 +65,10 @@
 
   static std::unique_ptr<CanvasResourceProvider> Create(
       const IntSize&,
-      unsigned msaa_sample_count,
-      const CanvasColorParams&,
       ResourceUsage,
-      base::WeakPtr<WebGraphicsContext3DProviderWrapper> = nullptr);
+      base::WeakPtr<WebGraphicsContext3DProviderWrapper> = nullptr,
+      unsigned msaa_sample_count = 0,
+      const CanvasColorParams& = CanvasColorParams());
 
   // Use this method for capturing a frame that is intended to be displayed via
   // the compositor. Cases that need to acquire a snaptshot that is not destined
diff --git a/third_party/WebKit/Source/platform/graphics/CrossfadeGeneratedImage.cpp b/third_party/WebKit/Source/platform/graphics/CrossfadeGeneratedImage.cpp
index 5dff2d4..f1d4c84 100644
--- a/third_party/WebKit/Source/platform/graphics/CrossfadeGeneratedImage.cpp
+++ b/third_party/WebKit/Source/platform/graphics/CrossfadeGeneratedImage.cpp
@@ -34,8 +34,8 @@
     scoped_refptr<Image> from_image,
     scoped_refptr<Image> to_image,
     float percentage,
-    IntSize crossfade_size,
-    const IntSize& size)
+    FloatSize crossfade_size,
+    const FloatSize& size)
     : GeneratedImage(size),
       from_image_(std::move(from_image)),
       to_image_(std::move(to_image)),
@@ -48,7 +48,7 @@
                                             ImageDecodingMode decode_mode) {
   FloatRect from_image_rect(FloatPoint(), FloatSize(from_image_->Size()));
   FloatRect to_image_rect(FloatPoint(), FloatSize(to_image_->Size()));
-  FloatRect dest_rect((FloatPoint()), FloatSize(crossfade_size_));
+  FloatRect dest_rect((FloatPoint()), crossfade_size_);
 
   // TODO(junov): The various effects encoded into paint should probably be
   // applied here instead of inside the layer.  This probably faulty behavior
@@ -108,7 +108,7 @@
   PaintFlags flags = context.FillFlags();
   flags.setBlendMode(SkBlendMode::kSrcOver);
   flags.setAntiAlias(context.ShouldAntialias());
-  FloatRect dest_rect((FloatPoint()), FloatSize(crossfade_size_));
+  FloatRect dest_rect((FloatPoint()), crossfade_size_);
   flags.setFilterQuality(
       context.ComputeFilterQuality(this, dest_rect, src_rect));
   DrawCrossfade(context.Canvas(), flags, kClampImageToSourceRect, kSyncDecode);
diff --git a/third_party/WebKit/Source/platform/graphics/CrossfadeGeneratedImage.h b/third_party/WebKit/Source/platform/graphics/CrossfadeGeneratedImage.h
index c4e63307..ee04eb9 100644
--- a/third_party/WebKit/Source/platform/graphics/CrossfadeGeneratedImage.h
+++ b/third_party/WebKit/Source/platform/graphics/CrossfadeGeneratedImage.h
@@ -40,8 +40,8 @@
       scoped_refptr<Image> from_image,
       scoped_refptr<Image> to_image,
       float percentage,
-      IntSize crossfade_size,
-      const IntSize& size) {
+      FloatSize crossfade_size,
+      const FloatSize& size) {
     return base::AdoptRef(
         new CrossfadeGeneratedImage(std::move(from_image), std::move(to_image),
                                     percentage, crossfade_size, size));
@@ -50,7 +50,7 @@
   bool UsesContainerSize() const override { return false; }
   bool HasRelativeSize() const override { return false; }
 
-  IntSize Size() const override { return crossfade_size_; }
+  IntSize Size() const override { return FlooredIntSize(crossfade_size_); }
 
  protected:
   void Draw(PaintCanvas*,
@@ -65,8 +65,8 @@
   CrossfadeGeneratedImage(scoped_refptr<Image> from_image,
                           scoped_refptr<Image> to_image,
                           float percentage,
-                          IntSize crossfade_size,
-                          const IntSize&);
+                          FloatSize crossfade_size,
+                          const FloatSize&);
 
  private:
   void DrawCrossfade(PaintCanvas*,
@@ -78,7 +78,7 @@
   scoped_refptr<Image> to_image_;
 
   float percentage_;
-  IntSize crossfade_size_;
+  FloatSize crossfade_size_;
 };
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/platform/graphics/GeneratedImage.h b/third_party/WebKit/Source/platform/graphics/GeneratedImage.h
index bf806d19..cb77604e 100644
--- a/third_party/WebKit/Source/platform/graphics/GeneratedImage.h
+++ b/third_party/WebKit/Source/platform/graphics/GeneratedImage.h
@@ -26,7 +26,7 @@
 #ifndef GeneratedImage_h
 #define GeneratedImage_h
 
-#include "platform/geometry/IntSize.h"
+#include "platform/geometry/LayoutSize.h"
 #include "platform/graphics/Image.h"
 #include "third_party/skia/include/core/SkRefCnt.h"
 
@@ -39,7 +39,7 @@
   bool UsesContainerSize() const override { return true; }
   bool HasRelativeSize() const override { return true; }
 
-  IntSize Size() const override { return size_; }
+  IntSize Size() const override { return RoundedIntSize(size_); }
 
   // Assume that generated content has no decoded data we need to worry about
   void DestroyDecodedData() override {}
@@ -61,11 +61,11 @@
     return false;
   }
 
-  GeneratedImage(const IntSize& size) : size_(size) {}
+  GeneratedImage(const FloatSize& size) : size_(size) {}
 
   virtual void DrawTile(GraphicsContext&, const FloatRect&) = 0;
 
-  IntSize size_;
+  FloatSize size_;
 };
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/platform/graphics/GradientGeneratedImage.cpp b/third_party/WebKit/Source/platform/graphics/GradientGeneratedImage.cpp
index f0962ea..8891bf4 100644
--- a/third_party/WebKit/Source/platform/graphics/GradientGeneratedImage.cpp
+++ b/third_party/WebKit/Source/platform/graphics/GradientGeneratedImage.cpp
@@ -40,7 +40,7 @@
                                   ImageDecodingMode) {
   SkRect visible_src_rect = src_rect;
   if (!visible_src_rect.intersect(
-          SkRect::MakeIWH(size_.Width(), size_.Height())))
+          SkRect::MakeWH(size_.Width(), size_.Height())))
     return;
 
   const SkMatrix transform =
diff --git a/third_party/WebKit/Source/platform/graphics/GradientGeneratedImage.h b/third_party/WebKit/Source/platform/graphics/GradientGeneratedImage.h
index 59498ce5..18e92fc 100644
--- a/third_party/WebKit/Source/platform/graphics/GradientGeneratedImage.h
+++ b/third_party/WebKit/Source/platform/graphics/GradientGeneratedImage.h
@@ -32,13 +32,11 @@
 
 namespace blink {
 
-class IntSize;
-
 class PLATFORM_EXPORT GradientGeneratedImage final : public GeneratedImage {
  public:
   static scoped_refptr<GradientGeneratedImage> Create(
       scoped_refptr<Gradient> generator,
-      const IntSize& size) {
+      const FloatSize& size) {
     return base::AdoptRef(
         new GradientGeneratedImage(std::move(generator), size));
   }
@@ -57,7 +55,8 @@
             ImageDecodingMode) override;
   void DrawTile(GraphicsContext&, const FloatRect&) override;
 
-  GradientGeneratedImage(scoped_refptr<Gradient> generator, const IntSize& size)
+  GradientGeneratedImage(scoped_refptr<Gradient> generator,
+                         const FloatSize& size)
       : GeneratedImage(size), gradient_(std::move(generator)) {}
 
   scoped_refptr<Gradient> gradient_;
diff --git a/third_party/WebKit/Source/platform/graphics/ImageBuffer.cpp b/third_party/WebKit/Source/platform/graphics/ImageBuffer.cpp
index 58915ae..5c443b7 100644
--- a/third_party/WebKit/Source/platform/graphics/ImageBuffer.cpp
+++ b/third_party/WebKit/Source/platform/graphics/ImageBuffer.cpp
@@ -58,19 +58,6 @@
   return WTF::WrapUnique(new ImageBuffer(std::move(surface)));
 }
 
-std::unique_ptr<ImageBuffer> ImageBuffer::Create(
-    const IntSize& size,
-    ImageInitializationMode initialization_mode,
-    const CanvasColorParams& color_params) {
-  std::unique_ptr<ImageBufferSurface> surface(
-      WTF::WrapUnique(new UnacceleratedImageBufferSurface(
-          size, initialization_mode, color_params)));
-
-  if (!surface->IsValid())
-    return nullptr;
-  return WTF::WrapUnique(new ImageBuffer(std::move(surface)));
-}
-
 ImageBuffer::ImageBuffer(std::unique_ptr<ImageBufferSurface> surface)
     : weak_ptr_factory_(this),
       surface_(std::move(surface)) {
diff --git a/third_party/WebKit/Source/platform/graphics/ImageBuffer.h b/third_party/WebKit/Source/platform/graphics/ImageBuffer.h
index f73b3ce..8fbf021 100644
--- a/third_party/WebKit/Source/platform/graphics/ImageBuffer.h
+++ b/third_party/WebKit/Source/platform/graphics/ImageBuffer.h
@@ -56,10 +56,6 @@
 
  public:
   static std::unique_ptr<ImageBuffer> Create(
-      const IntSize&,
-      ImageInitializationMode = kInitializeImagePixels,
-      const CanvasColorParams& = CanvasColorParams());
-  static std::unique_ptr<ImageBuffer> Create(
       std::unique_ptr<ImageBufferSurface>);
 
   virtual ~ImageBuffer();
diff --git a/third_party/WebKit/Source/platform/graphics/PaintGeneratedImage.h b/third_party/WebKit/Source/platform/graphics/PaintGeneratedImage.h
index 022bb1a..c4ac09d5 100644
--- a/third_party/WebKit/Source/platform/graphics/PaintGeneratedImage.h
+++ b/third_party/WebKit/Source/platform/graphics/PaintGeneratedImage.h
@@ -15,7 +15,7 @@
 class PLATFORM_EXPORT PaintGeneratedImage : public GeneratedImage {
  public:
   static scoped_refptr<PaintGeneratedImage> Create(sk_sp<PaintRecord> record,
-                                                   const IntSize& size) {
+                                                   const FloatSize& size) {
     return base::AdoptRef(new PaintGeneratedImage(std::move(record), size));
   }
   ~PaintGeneratedImage() override {}
@@ -30,7 +30,7 @@
             ImageDecodingMode) override;
   void DrawTile(GraphicsContext&, const FloatRect&) final;
 
-  PaintGeneratedImage(sk_sp<PaintRecord> record, const IntSize& size)
+  PaintGeneratedImage(sk_sp<PaintRecord> record, const FloatSize& size)
       : GeneratedImage(size), record_(std::move(record)) {}
 
   sk_sp<PaintRecord> record_;
diff --git a/third_party/WebKit/Source/platform/loader/fetch/RawResource.cpp b/third_party/WebKit/Source/platform/loader/fetch/RawResource.cpp
index 3d636fc..bea8f48 100644
--- a/third_party/WebKit/Source/platform/loader/fetch/RawResource.cpp
+++ b/third_party/WebKit/Source/platform/loader/fetch/RawResource.cpp
@@ -97,12 +97,14 @@
                                      RawResourceClient* client) {
   DCHECK_EQ(params.GetResourceRequest().GetFrameType(),
             network::mojom::RequestContextFrameType::kNone);
-  DCHECK(params.GetResourceRequest().GetRequestContext() ==
-             WebURLRequest::kRequestContextAudio ||
-         params.GetResourceRequest().GetRequestContext() ==
-             WebURLRequest::kRequestContextVideo);
-  return ToRawResource(fetcher->RequestResource(
-      params, RawResourceFactory(Resource::kMedia), client));
+  auto context = params.GetResourceRequest().GetRequestContext();
+  DCHECK(context == WebURLRequest::kRequestContextAudio ||
+         context == WebURLRequest::kRequestContextVideo);
+  Resource::Type type = (context == WebURLRequest::kRequestContextAudio)
+                            ? Resource::kAudio
+                            : Resource::kVideo;
+  return ToRawResource(
+      fetcher->RequestResource(params, RawResourceFactory(type), client));
 }
 
 RawResource* RawResource::FetchTextTrack(FetchParameters& params,
diff --git a/third_party/WebKit/Source/platform/loader/fetch/RawResource.h b/third_party/WebKit/Source/platform/loader/fetch/RawResource.h
index 31646e0..605245e8 100644
--- a/third_party/WebKit/Source/platform/loader/fetch/RawResource.h
+++ b/third_party/WebKit/Source/platform/loader/fetch/RawResource.h
@@ -121,8 +121,9 @@
 inline bool IsRawResource(const Resource& resource) {
   Resource::Type type = resource.GetType();
   return type == Resource::kMainResource || type == Resource::kRaw ||
-         type == Resource::kTextTrack || type == Resource::kMedia ||
-         type == Resource::kManifest || type == Resource::kImportResource;
+         type == Resource::kTextTrack || type == Resource::kAudio ||
+         type == Resource::kVideo || type == Resource::kManifest ||
+         type == Resource::kImportResource;
 }
 inline RawResource* ToRawResource(Resource* resource) {
   SECURITY_DCHECK(!resource || IsRawResource(*resource));
diff --git a/third_party/WebKit/Source/platform/loader/fetch/Resource.cpp b/third_party/WebKit/Source/platform/loader/fetch/Resource.cpp
index 477adb8..226d35d 100644
--- a/third_party/WebKit/Source/platform/loader/fetch/Resource.cpp
+++ b/third_party/WebKit/Source/platform/loader/fetch/Resource.cpp
@@ -1219,8 +1219,10 @@
       return "Text track";
     case Resource::kImportResource:
       return "Imported resource";
-    case Resource::kMedia:
-      return "Media";
+    case Resource::kAudio:
+      return "Audio";
+    case Resource::kVideo:
+      return "Video";
     case Resource::kManifest:
       return "Manifest";
     case Resource::kMock:
@@ -1248,7 +1250,8 @@
     case Resource::kRaw:
     case Resource::kLinkPrefetch:
     case Resource::kTextTrack:
-    case Resource::kMedia:
+    case Resource::kAudio:
+    case Resource::kVideo:
     case Resource::kManifest:
     case Resource::kMock:
       return false;
diff --git a/third_party/WebKit/Source/platform/loader/fetch/Resource.h b/third_party/WebKit/Source/platform/loader/fetch/Resource.h
index bd703a48..9f71669 100644
--- a/third_party/WebKit/Source/platform/loader/fetch/Resource.h
+++ b/third_party/WebKit/Source/platform/loader/fetch/Resource.h
@@ -89,7 +89,8 @@
     kLinkPrefetch,
     kTextTrack,
     kImportResource,
-    kMedia,  // Audio or video file requested by a HTML5 media element
+    kAudio,
+    kVideo,
     kManifest,
     kMock  // Only for testing
   };
diff --git a/third_party/WebKit/Source/platform/loader/fetch/ResourceFetcher.cpp b/third_party/WebKit/Source/platform/loader/fetch/ResourceFetcher.cpp
index 7dd62ea..a0d5026 100644
--- a/third_party/WebKit/Source/platform/loader/fetch/ResourceFetcher.cpp
+++ b/third_party/WebKit/Source/platform/loader/fetch/ResourceFetcher.cpp
@@ -88,7 +88,8 @@
     DEFINE_SINGLE_RESOURCE_HISTOGRAM(prefix, LinkPrefetch)   \
     DEFINE_SINGLE_RESOURCE_HISTOGRAM(prefix, MainResource)   \
     DEFINE_SINGLE_RESOURCE_HISTOGRAM(prefix, Manifest)       \
-    DEFINE_SINGLE_RESOURCE_HISTOGRAM(prefix, Media)          \
+    DEFINE_SINGLE_RESOURCE_HISTOGRAM(prefix, Audio)          \
+    DEFINE_SINGLE_RESOURCE_HISTOGRAM(prefix, Video)          \
     DEFINE_SINGLE_RESOURCE_HISTOGRAM(prefix, Mock)           \
     DEFINE_SINGLE_RESOURCE_HISTOGRAM(prefix, Raw)            \
     DEFINE_SINGLE_RESOURCE_HISTOGRAM(prefix, Script)         \
@@ -131,7 +132,8 @@
       return ResourceLoadPriority::kMedium;
     case Resource::kImage:
     case Resource::kTextTrack:
-    case Resource::kMedia:
+    case Resource::kAudio:
+    case Resource::kVideo:
     case Resource::kSVGDocument:
       // Also async scripts (set explicitly in loadPriority)
       return ResourceLoadPriority::kLow;
@@ -261,7 +263,9 @@
       return WebURLRequest::kRequestContextTrack;
     case Resource::kSVGDocument:
       return WebURLRequest::kRequestContextImage;
-    case Resource::kMedia:  // TODO: Split this.
+    case Resource::kAudio:
+      return WebURLRequest::kRequestContextAudio;
+    case Resource::kVideo:
       return WebURLRequest::kRequestContextVideo;
     case Resource::kManifest:
       return WebURLRequest::kRequestContextManifest;
@@ -1643,7 +1647,8 @@
         fonts++;
         font_misses += miss_count;
         break;
-      case Resource::kMedia:
+      case Resource::kAudio:
+      case Resource::kVideo:
         medias++;
         media_misses += miss_count;
         break;
diff --git a/third_party/WebKit/Source/platform/runtime_enabled_features.json5 b/third_party/WebKit/Source/platform/runtime_enabled_features.json5
index 31addf85..67b6bec0 100644
--- a/third_party/WebKit/Source/platform/runtime_enabled_features.json5
+++ b/third_party/WebKit/Source/platform/runtime_enabled_features.json5
@@ -649,6 +649,9 @@
       name: "MojoBlobs",
     },
     {
+      name: "MojoBlobURLs",
+    },
+    {
       name: "MojoJS",
       status: "test",
     },
@@ -945,7 +948,7 @@
     },
     {
       name: "ServerTiming",
-      status: "experimental",
+      status: "stable",
     },
     {
       name: "ServiceWorkerScriptFullCodeCache",
diff --git a/third_party/WebKit/Source/platform/text/TextBreakIterator.cpp b/third_party/WebKit/Source/platform/text/TextBreakIterator.cpp
index 21f027728..be2765c 100644
--- a/third_party/WebKit/Source/platform/text/TextBreakIterator.cpp
+++ b/third_party/WebKit/Source/platform/text/TextBreakIterator.cpp
@@ -277,19 +277,23 @@
 
     is_space = IsBreakableSpace(ch);
     switch (break_space) {
-      case BreakSpaceType::kBeforeEverySpace:
+      case BreakSpaceType::kBefore:
         if (is_space)
           return i;
         break;
-      case BreakSpaceType::kBeforeSpaceRun:
-        // Theoritically, preserved newline characters are different from space
-        // and tab characters. The difference is not implemented because the
-        // LayoutNG line breaker handles preserved newline characters by itself.
-        if (is_space) {
-          if (!is_last_space)
-            return i;
+      case BreakSpaceType::kBeforeSpace:
+        if (ch == kSpaceCharacter)
+          return i;
+        if (is_space)
           continue;
-        }
+        if (is_last_space && last_ch != kSpaceCharacter)
+          return i;
+        break;
+      case BreakSpaceType::kAfter:
+        if (is_space)
+          continue;
+        if (is_last_space)
+          return i;
         break;
     }
 
@@ -325,8 +329,20 @@
           }
         }
       }
-      if (i == next_break && !is_last_space)
-        return i;
+      if (i == next_break) {
+        switch (break_space) {
+          case BreakSpaceType::kBefore:
+            if (!is_last_space)
+              return i;
+            break;
+          case BreakSpaceType::kBeforeSpace:
+            if (last_ch != kSpaceCharacter)
+              return i;
+            break;
+          case BreakSpaceType::kAfter:
+            return i;
+        }
+      }
     }
   }
 
@@ -338,16 +354,19 @@
     int pos,
     const CharacterType* str) const {
   switch (break_space_) {
-    case BreakSpaceType::kBeforeEverySpace:
+    case BreakSpaceType::kBefore:
       return NextBreakablePosition<CharacterType, lineBreakType,
-                                   BreakSpaceType::kBeforeEverySpace>(pos, str);
-    case BreakSpaceType::kBeforeSpaceRun:
+                                   BreakSpaceType::kBefore>(pos, str);
+    case BreakSpaceType::kBeforeSpace:
       return NextBreakablePosition<CharacterType, lineBreakType,
-                                   BreakSpaceType::kBeforeSpaceRun>(pos, str);
+                                   BreakSpaceType::kBeforeSpace>(pos, str);
+    case BreakSpaceType::kAfter:
+      return NextBreakablePosition<CharacterType, lineBreakType,
+                                   BreakSpaceType::kAfter>(pos, str);
   }
   NOTREACHED();
   return NextBreakablePosition<CharacterType, lineBreakType,
-                               BreakSpaceType::kBeforeEverySpace>(pos, str);
+                               BreakSpaceType::kBefore>(pos, str);
 }
 
 template <LineBreakType lineBreakType>
@@ -419,10 +438,12 @@
 
 std::ostream& operator<<(std::ostream& ostream, BreakSpaceType break_space) {
   switch (break_space) {
-    case BreakSpaceType::kBeforeEverySpace:
-      return ostream << "kBeforeEverySpace";
-    case BreakSpaceType::kBeforeSpaceRun:
-      return ostream << "kBeforeSpaceRun";
+    case BreakSpaceType::kBefore:
+      return ostream << "Before";
+    case BreakSpaceType::kBeforeSpace:
+      return ostream << "BeforeSpace";
+    case BreakSpaceType::kAfter:
+      return ostream << "After";
   }
   NOTREACHED();
   return ostream << "BreakSpaceType::" << static_cast<int>(break_space);
diff --git a/third_party/WebKit/Source/platform/text/TextBreakIterator.h b/third_party/WebKit/Source/platform/text/TextBreakIterator.h
index d65682a7..10c0fa53 100644
--- a/third_party/WebKit/Source/platform/text/TextBreakIterator.h
+++ b/third_party/WebKit/Source/platform/text/TextBreakIterator.h
@@ -93,23 +93,22 @@
 // Determines break opportunities around collapsible space characters (space,
 // newline, and tabulation characters.)
 enum class BreakSpaceType {
-  // Break before every collapsible space character.
+  // Break before collapsible space characters.
   // This is a specialized optimization for CSS, where leading/trailing spaces
   // in each line are removed, and thus breaking before spaces can save
   // computing hanging spaces.
-  // Callers are expected to handle spaces by themselves. Because a run of
-  // spaces can include different types of spaces, break opportunity is given
-  // for every space character.
-  // Pre-LayoutNG line breaker uses this type.
-  kBeforeEverySpace,
+  kBefore,
 
-  // Break before a run of white space characters.
-  // This is for CSS line breaking as in |kBeforeEverySpace|, but when
-  // whitespace collapsing is already applied to the target string. In this
-  // case, a run of white spaces are preserved spaces. There should not be break
-  // opportunities between white spaces.
-  // LayoutNG line breaker uses this type.
-  kBeforeSpaceRun,
+  // Break before space characters, but after newline and tabulation characters.
+  // This is for CSS line breaking as in |kBefore|, but when whitespace
+  // collapsing is already applied to the target string.
+  kBeforeSpace,
+
+  // Break after collapsible space characters.
+  // When 'white-space:pre-wrap', or when in editing, leaging/trailing spaces
+  // need to be preserved, and that the |kBefore| optimization cannot work.
+  // This mode is compatible with UAX#14/ICU. http://unicode.org/reports/tr14/
+  kAfter,
 };
 
 PLATFORM_EXPORT std::ostream& operator<<(std::ostream&, LineBreakType);
@@ -295,7 +294,7 @@
   mutable const UChar* cached_prior_context_;
   mutable unsigned cached_prior_context_length_;
   LineBreakType break_type_;
-  BreakSpaceType break_space_ = BreakSpaceType::kBeforeEverySpace;
+  BreakSpaceType break_space_ = BreakSpaceType::kBefore;
 };
 
 // Iterates over "extended grapheme clusters", as defined in UAX #29.
diff --git a/third_party/WebKit/Source/platform/text/TextBreakIteratorTest.cpp b/third_party/WebKit/Source/platform/text/TextBreakIteratorTest.cpp
index 4711fe0..d75c0c6 100644
--- a/third_party/WebKit/Source/platform/text/TextBreakIteratorTest.cpp
+++ b/third_party/WebKit/Source/platform/text/TextBreakIteratorTest.cpp
@@ -17,10 +17,9 @@
   }
 
   // The expected break positions must be specified UTF-16 character boundaries.
-  void MatchLineBreaks(
-      LineBreakType line_break_type,
-      const Vector<int> expected_break_positions,
-      BreakSpaceType break_space = BreakSpaceType::kBeforeEverySpace) {
+  void MatchLineBreaks(LineBreakType line_break_type,
+                       const Vector<int> expected_break_positions,
+                       BreakSpaceType break_space = BreakSpaceType::kBefore) {
     if (test_string_.Is8Bit()) {
       test_string_ = String::Make16BitFrom8BitSource(test_string_.Characters8(),
                                                      test_string_.length());
@@ -99,22 +98,25 @@
 TEST_F(TextBreakIteratorTest, Basic) {
   SetTestString("a b  c");
   MatchLineBreaks(LineBreakType::kNormal, {1, 3, 4, 6});
-  MatchLineBreaks(LineBreakType::kNormal, {1, 3, 6},
-                  BreakSpaceType::kBeforeSpaceRun);
+  MatchLineBreaks(LineBreakType::kNormal, {1, 3, 4, 6},
+                  BreakSpaceType::kBeforeSpace);
+  MatchLineBreaks(LineBreakType::kNormal, {2, 5, 6}, BreakSpaceType::kAfter);
 }
 
 TEST_F(TextBreakIteratorTest, Newline) {
-  SetTestString("a\nb\n\nc\n d");
-  MatchLineBreaks(LineBreakType::kNormal, {1, 3, 4, 6, 7, 9});
-  MatchLineBreaks(LineBreakType::kNormal, {1, 3, 6, 9},
-                  BreakSpaceType::kBeforeSpaceRun);
+  SetTestString("a\nb\n\nc");
+  MatchLineBreaks(LineBreakType::kNormal, {1, 3, 4, 6});
+  MatchLineBreaks(LineBreakType::kNormal, {2, 5, 6},
+                  BreakSpaceType::kBeforeSpace);
+  MatchLineBreaks(LineBreakType::kNormal, {2, 5, 6}, BreakSpaceType::kAfter);
 }
 
 TEST_F(TextBreakIteratorTest, Tab) {
   SetTestString("a\tb\t\tc");
   MatchLineBreaks(LineBreakType::kNormal, {1, 3, 4, 6});
-  MatchLineBreaks(LineBreakType::kNormal, {1, 3, 6},
-                  BreakSpaceType::kBeforeSpaceRun);
+  MatchLineBreaks(LineBreakType::kNormal, {2, 5, 6},
+                  BreakSpaceType::kBeforeSpace);
+  MatchLineBreaks(LineBreakType::kNormal, {2, 5, 6}, BreakSpaceType::kAfter);
 }
 
 TEST_F(TextBreakIteratorTest, LatinPunctuation) {
@@ -123,6 +125,9 @@
   MatchLineBreaks(LineBreakType::kBreakAll, {2, 4, 6, 8});
   MatchLineBreaks(LineBreakType::kBreakCharacter, {1, 2, 3, 4, 5, 6, 7, 8});
   MatchLineBreaks(LineBreakType::kKeepAll, {4, 8});
+  MatchLineBreaks(LineBreakType::kNormal, {5, 8}, BreakSpaceType::kAfter);
+  MatchLineBreaks(LineBreakType::kBreakAll, {2, 5, 6, 8},
+                  BreakSpaceType::kAfter);
 }
 
 TEST_F(TextBreakIteratorTest, Chinese) {
@@ -131,6 +136,10 @@
   MatchLineBreaks(LineBreakType::kBreakAll, {1, 2, 3, 4, 5});
   MatchLineBreaks(LineBreakType::kBreakCharacter, {1, 2, 3, 4, 5});
   MatchLineBreaks(LineBreakType::kKeepAll, {5});
+  MatchLineBreaks(LineBreakType::kNormal, {1, 2, 3, 4, 5},
+                  BreakSpaceType::kAfter);
+  MatchLineBreaks(LineBreakType::kBreakAll, {1, 2, 3, 4, 5},
+                  BreakSpaceType::kAfter);
 }
 
 TEST_F(TextBreakIteratorTest, ChineseMixed) {
@@ -140,6 +149,10 @@
   MatchLineBreaks(LineBreakType::kBreakCharacter,
                   {1, 2, 3, 4, 5, 6, 7, 8, 9, 10});
   MatchLineBreaks(LineBreakType::kKeepAll, {1, 4, 9, 10});
+  MatchLineBreaks(LineBreakType::kNormal, {1, 4, 5, 7, 9, 10},
+                  BreakSpaceType::kAfter);
+  MatchLineBreaks(LineBreakType::kBreakAll, {1, 4, 5, 6, 7, 9, 10},
+                  BreakSpaceType::kAfter);
 }
 
 TEST_F(TextBreakIteratorTest, ChineseSpaces) {
@@ -149,8 +162,12 @@
   MatchLineBreaks(LineBreakType::kBreakCharacter,
                   {1, 2, 3, 4, 5, 6, 7, 8, 9, 10});
   MatchLineBreaks(LineBreakType::kKeepAll, {1, 2, 4, 5, 7, 8, 10});
-  MatchLineBreaks(LineBreakType::kNormal, {1, 4, 7, 10},
-                  BreakSpaceType::kBeforeSpaceRun);
+  MatchLineBreaks(LineBreakType::kNormal, {1, 2, 4, 5, 7, 8, 10},
+                  BreakSpaceType::kBeforeSpace);
+  MatchLineBreaks(LineBreakType::kNormal, {3, 6, 9, 10},
+                  BreakSpaceType::kAfter);
+  MatchLineBreaks(LineBreakType::kBreakAll, {3, 6, 9, 10},
+                  BreakSpaceType::kAfter);
 }
 
 TEST_F(TextBreakIteratorTest, KeepEmojiZWJFamilyIsolate) {
@@ -159,6 +176,8 @@
   MatchLineBreaks(LineBreakType::kBreakAll, {11});
   MatchLineBreaks(LineBreakType::kBreakCharacter, {11});
   MatchLineBreaks(LineBreakType::kKeepAll, {11});
+  MatchLineBreaks(LineBreakType::kNormal, {11}, BreakSpaceType::kAfter);
+  MatchLineBreaks(LineBreakType::kBreakAll, {11}, BreakSpaceType::kAfter);
 }
 
 TEST_F(TextBreakIteratorTest, KeepEmojiModifierSequenceIsolate) {
@@ -167,6 +186,8 @@
   MatchLineBreaks(LineBreakType::kBreakAll, {3});
   MatchLineBreaks(LineBreakType::kBreakCharacter, {3});
   MatchLineBreaks(LineBreakType::kKeepAll, {3});
+  MatchLineBreaks(LineBreakType::kNormal, {3}, BreakSpaceType::kAfter);
+  MatchLineBreaks(LineBreakType::kBreakAll, {3}, BreakSpaceType::kAfter);
 }
 
 TEST_F(TextBreakIteratorTest, KeepEmojiZWJSequence) {
@@ -177,6 +198,9 @@
   MatchLineBreaks(LineBreakType::kBreakCharacter,
                   {1, 2, 3, 4, 15, 16, 17, 18, 19});
   MatchLineBreaks(LineBreakType::kKeepAll, {3, 15, 19});
+  MatchLineBreaks(LineBreakType::kNormal, {4, 16, 19}, BreakSpaceType::kAfter);
+  MatchLineBreaks(LineBreakType::kBreakAll, {1, 2, 4, 16, 17, 18, 19},
+                  BreakSpaceType::kAfter);
 }
 
 TEST_F(TextBreakIteratorTest, KeepEmojiModifierSequence) {
@@ -186,6 +210,9 @@
   MatchLineBreaks(LineBreakType::kBreakCharacter,
                   {1, 2, 3, 4, 7, 8, 9, 10, 11});
   MatchLineBreaks(LineBreakType::kKeepAll, {3, 7, 11});
+  MatchLineBreaks(LineBreakType::kNormal, {4, 8, 11}, BreakSpaceType::kAfter);
+  MatchLineBreaks(LineBreakType::kBreakAll, {1, 2, 4, 8, 9, 10, 11},
+                  BreakSpaceType::kAfter);
 }
 
 TEST_F(TextBreakIteratorTest, NextBreakOpportunityAtEnd) {
diff --git a/third_party/WebKit/Source/platform/wtf/text/TextCodec.cpp b/third_party/WebKit/Source/platform/wtf/text/TextCodec.cpp
index 67ddf59..ddcafffe 100644
--- a/third_party/WebKit/Source/platform/wtf/text/TextCodec.cpp
+++ b/third_party/WebKit/Source/platform/wtf/text/TextCodec.cpp
@@ -42,9 +42,10 @@
                code_point);
       return static_cast<int>(strlen(replacement));
     case kURLEncodedEntitiesForUnencodables:
-      snprintf(replacement, sizeof(UnencodableReplacementArray), "&%%23%u;",
-               code_point);
+      snprintf(replacement, sizeof(UnencodableReplacementArray),
+               "%%26%%23%u%%3B", code_point);
       return static_cast<int>(strlen(replacement));
+
     case kCSSEncodedEntitiesForUnencodables:
       snprintf(replacement, sizeof(UnencodableReplacementArray), "\\%x ",
                code_point);
diff --git a/third_party/WebKit/Source/platform/wtf/text/TextCodec.h b/third_party/WebKit/Source/platform/wtf/text/TextCodec.h
index f18c149..dddd7d74 100644
--- a/third_party/WebKit/Source/platform/wtf/text/TextCodec.h
+++ b/third_party/WebKit/Source/platform/wtf/text/TextCodec.h
@@ -46,7 +46,7 @@
 
   // Encodes the character as en entity as above, but escaped
   // non-alphanumeric characters. This is used in URLs.
-  // For example, U+6DE would be "&%231758;".
+  // For example, U+6DE would be "%26%231758%3B".
   kURLEncodedEntitiesForUnencodables,
 
   // Encodes the character as a CSS entity.  For example U+06DE
diff --git a/third_party/WebKit/Source/platform/wtf/text/TextCodecTest.cpp b/third_party/WebKit/Source/platform/wtf/text/TextCodecTest.cpp
index d9cf9bfe..21a7249 100644
--- a/third_party/WebKit/Source/platform/wtf/text/TextCodecTest.cpp
+++ b/third_party/WebKit/Source/platform/wtf/text/TextCodecTest.cpp
@@ -49,9 +49,9 @@
   UnencodableReplacementArray replacement;
   int size = TextCodec::GetUnencodableReplacement(
       0xE003, kURLEncodedEntitiesForUnencodables, replacement);
-  EXPECT_EQ(size, 10);
-  EXPECT_EQ(std::string(replacement), "&%2357347;");
-  EXPECT_EQ(replacement[10], 0);
+  EXPECT_EQ(size, 14);
+  EXPECT_EQ(std::string(replacement), "%26%2357347%3B");
+  EXPECT_EQ(replacement[14], 0);
 }
 
 TEST(TextCodec, CSSEntityEncoding) {
diff --git a/third_party/WebKit/common/BUILD.gn b/third_party/WebKit/common/BUILD.gn
index 56344951..4daa094 100644
--- a/third_party/WebKit/common/BUILD.gn
+++ b/third_party/WebKit/common/BUILD.gn
@@ -111,6 +111,7 @@
   sources = [
     "blob/blob.mojom",
     "blob/blob_registry.mojom",
+    "blob/blob_url_store.mojom",
     "clipboard/clipboard.mojom",
     "color_chooser/color_chooser.mojom",
     "feature_policy/feature_policy.mojom",
diff --git a/third_party/WebKit/common/blob/blob_registry.mojom b/third_party/WebKit/common/blob/blob_registry.mojom
index f84a0fb..67c9359 100644
--- a/third_party/WebKit/common/blob/blob_registry.mojom
+++ b/third_party/WebKit/common/blob/blob_registry.mojom
@@ -8,14 +8,10 @@
 import "mojo/common/file_path.mojom";
 import "mojo/common/time.mojom";
 import "third_party/WebKit/common/blob/blob.mojom";
+import "third_party/WebKit/common/blob/blob_url_store.mojom";
+import "url/mojo/origin.mojom";
 import "url/mojo/url.mojom";
 
-// An opaque handle passed from the browser process to a child process to
-// manage the lifetime of the returned Blob URL. The URL is revoked when
-// this handle is dropped.
-interface BlobURLHandle {
-};
-
 // This interface is the primary access point from renderer to the browser's blob system.
 // This interface provides methods to register new blobs and get references to existing blobs.
 interface BlobRegistry {
@@ -26,15 +22,14 @@
                   string content_type, string content_disposition,
                   array<DataElement> elements) => ();
 
-  // Registers a public Blob URL with the blob registry.
-  // TODO(kinuko,mek): This should probably create and return a new blob: URL rather
-  // than letting the caller in the renderer provide one.
-  [Sync] RegisterURL(blink.mojom.Blob blob, url.mojom.Url url) => (BlobURLHandle url_handle);
-
   // Returns a reference to an existing blob. Should not be used by new code,
   // is only exposed to make converting existing blob using code easier.
   // TODO(mek): Remove when crbug.com/740744 is resolved.
   [Sync] GetBlobFromUUID(Blob& blob, string uuid) => ();
+
+  // Returns a BlobURLStore for a specific origin.
+  URLStoreForOrigin(url.mojom.Origin origin,
+                    associated blink.mojom.BlobURLStore& url_store);
 };
 
 // A blob is built up of elements of various types.
diff --git a/third_party/WebKit/common/blob/blob_url_store.mojom b/third_party/WebKit/common/blob/blob_url_store.mojom
new file mode 100644
index 0000000..161834d
--- /dev/null
+++ b/third_party/WebKit/common/blob/blob_url_store.mojom
@@ -0,0 +1,24 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+module blink.mojom;
+
+import "third_party/WebKit/common/blob/blob.mojom";
+import "url/mojo/url.mojom";
+
+// This interface is implemented by the browser to give renderers the ability to
+// create and revoke blob URLs. BlobRegistry exposes a method get a instance of
+// this interface for a particular origin.
+interface BlobURLStore {
+  // Registers a public Blob URL. When the connection to the BlobURLStore closes
+  // all URLs registered through it will be revoked.
+  // TODO(kinuko,mek): This should probably create and return a new blob: URL rather
+  // than letting the caller in the renderer provide one.
+  [Sync] Register(blink.mojom.Blob blob, url.mojom.Url url) => ();
+
+  // Revokes a public Blob URL.
+  Revoke(url.mojom.Url url);
+
+  // Resolves a public Blob URL.
+  Resolve(url.mojom.Url url) => (blink.mojom.Blob? blob);
+};
diff --git a/third_party/WebKit/public/platform/WebRTCRtpSender.h b/third_party/WebKit/public/platform/WebRTCRtpSender.h
index 7ae72de..25adba1 100644
--- a/third_party/WebKit/public/platform/WebRTCRtpSender.h
+++ b/third_party/WebKit/public/platform/WebRTCRtpSender.h
@@ -6,6 +6,7 @@
 #define WebRTCRtpSender_h
 
 #include "WebCommon.h"
+#include "WebRTCVoidRequest.h"
 #include "WebString.h"
 
 namespace blink {
@@ -25,6 +26,10 @@
   // allowed to be reused after a sender is destroyed.
   virtual uintptr_t Id() const = 0;
   virtual WebMediaStreamTrack Track() const = 0;
+  // TODO(hbos): Replace WebRTCVoidRequest by something resolving promises based
+  // on RTCError, as to surface both exception type and error message.
+  // https://crbug.com/790007
+  virtual void ReplaceTrack(WebMediaStreamTrack, WebRTCVoidRequest) = 0;
 };
 
 }  // namespace blink
diff --git a/third_party/WebKit/public/platform/WebVector.h b/third_party/WebKit/public/platform/WebVector.h
index d21fa2c..f7fd92a 100644
--- a/third_party/WebKit/public/platform/WebVector.h
+++ b/third_party/WebKit/public/platform/WebVector.h
@@ -132,6 +132,10 @@
   }
 
   size_t size() const { return data_.size(); }
+  void resize(size_t new_size) {
+    DCHECK_LE(new_size, data_.capacity());
+    data_.resize(new_size);
+  }
   bool empty() const { return data_.empty(); }
   // TODO(slangley): Remove all uses of IsEmpty.
   bool IsEmpty() const { return empty(); }
diff --git a/third_party/WebKit/public/web/android/DEPS b/third_party/WebKit/public/web/android/DEPS
deleted file mode 100644
index 6a8ad02c..0000000
--- a/third_party/WebKit/public/web/android/DEPS
+++ /dev/null
@@ -1,3 +0,0 @@
-include_rules = [
-    "+..",
-]
diff --git a/third_party/android_crazy_linker/OWNERS b/third_party/android_crazy_linker/OWNERS
index 7623bd9..0fda8e0b 100644
--- a/third_party/android_crazy_linker/OWNERS
+++ b/third_party/android_crazy_linker/OWNERS
@@ -1,2 +1,2 @@
+digit@chromium.org
 rmcilroy@chromium.org
-simonb@chromium.org
diff --git a/third_party/libvpx/README.chromium b/third_party/libvpx/README.chromium
index 37f8e05..a8e8b1a 100644
--- a/third_party/libvpx/README.chromium
+++ b/third_party/libvpx/README.chromium
@@ -5,9 +5,9 @@
 License File: source/libvpx/LICENSE
 Security Critical: yes
 
-Date: Thursday December 21 2017
+Date: Friday January 05 2018
 Branch: master
-Commit: 8a4336ed2edea09b67f49828df1f8c526a85a7a6
+Commit: bed28a55f593efd3a71a3a9d05cf8bb25d15fa44
 
 Description:
 Contains the sources used to compile libvpx binaries used by Google Chrome and
diff --git a/third_party/libvpx/source/config/vpx_version.h b/third_party/libvpx/source/config/vpx_version.h
index 6518a40..ede1b94 100644
--- a/third_party/libvpx/source/config/vpx_version.h
+++ b/third_party/libvpx/source/config/vpx_version.h
@@ -2,7 +2,7 @@
 #define VERSION_MAJOR  1
 #define VERSION_MINOR  6
 #define VERSION_PATCH  1
-#define VERSION_EXTRA  "1473-g8a4336ed2"
+#define VERSION_EXTRA  "1477-gbed28a55f"
 #define VERSION_PACKED ((VERSION_MAJOR<<16)|(VERSION_MINOR<<8)|(VERSION_PATCH))
-#define VERSION_STRING_NOSP "v1.6.1-1473-g8a4336ed2"
-#define VERSION_STRING      " v1.6.1-1473-g8a4336ed2"
+#define VERSION_STRING_NOSP "v1.6.1-1477-gbed28a55f"
+#define VERSION_STRING      " v1.6.1-1477-gbed28a55f"
diff --git a/tools/chrome_proxy/webdriver/lite_page.py b/tools/chrome_proxy/webdriver/lite_page.py
index 2e7a52a..5e9ee73 100644
--- a/tools/chrome_proxy/webdriver/lite_page.py
+++ b/tools/chrome_proxy/webdriver/lite_page.py
@@ -265,20 +265,34 @@
 
       # This page is long and has many media resources.
       test_driver.LoadURL('http://check.googlezip.net/metrics/index.html')
+      time.sleep(2)
 
-      # Verify that a Lite Page response for the main frame was seen.
       lite_page_responses = 0
+      btf_response = 0
+      image_responses = 0
       for response in test_driver.GetHTTPResponses():
-        # Check main frame for Lite Page response.
+        # Verify that a Lite Page response for the main frame was seen.
         if response.url.endswith('html'):
           if (self.checkLitePageResponse(response)):
              lite_page_responses = lite_page_responses + 1
+        # Keep track of BTF responses.
+        if response.url.startswith("http://googleweblight.com/b"):
+          btf_response = btf_response + 1
+        # Keep track of image responses.
+        if response.url.startswith("data:image"):
+          image_responses = image_responses + 1
+        # Some video requests don't go through Flywheel.
         if 'content-type' in response.response_headers and ('video/mp4'
             in response.response_headers['content-type']):
           continue
         # Make sure non-video requests are proxied.
         self.assertHasChromeProxyViaHeader(response)
+        # Make sure there are no 4XX or 5xx status codes.
+        self.assertLess(response.status, 400)
+
       self.assertEqual(1, lite_page_responses)
+      self.assertEqual(1, btf_response)
+      self.assertGreater(1, image_responses)
 
   # Lo-Fi fallback is not supported without the
   # DataReductionProxyDecidesTransform feature. Check that no Lo-Fi response
diff --git a/tools/code_coverage/coverage.py b/tools/code_coverage/coverage.py
index faab150..a8a6a37 100755
--- a/tools/code_coverage/coverage.py
+++ b/tools/code_coverage/coverage.py
@@ -162,6 +162,7 @@
 
     self._css_absolute_path = css_absolute_path
     self._table_entries = []
+    self._total_entry = {}
     template_dir = os.path.join(
         os.path.dirname(os.path.realpath(__file__)), 'html_templates')
 
@@ -176,27 +177,43 @@
 
     The link to be added is assumed to be an entry in this directory.
     """
-    table_entry = {
-        'href':
-            html_report_path,
-        'name':
-            name,
-        'is_dir':
-            os.path.basename(html_report_path) ==
-            DIRECTORY_COVERAGE_HTML_REPORT_NAME
-    }
+    table_entry = self._CreateTableEntryFromCoverageSummary(
+        summary, html_report_path, name,
+        os.path.basename(html_report_path) ==
+        DIRECTORY_COVERAGE_HTML_REPORT_NAME)
+    self._table_entries.append(table_entry)
+
+  def CreateTotalsEntry(self, summary):
+    """Creates an entry corresponds to the 'TOTALS' row in the html report."""
+    self._total_entry = self._CreateTableEntryFromCoverageSummary(summary)
+
+  def _CreateTableEntryFromCoverageSummary(self,
+                                           summary,
+                                           href=None,
+                                           name=None,
+                                           is_dir=None):
+    """Creates an entry to display in the html report."""
+    entry = {}
     summary_dict = summary.Get()
-    for feature in summary_dict.keys():
+    for feature in summary_dict:
       percentage = round((float(summary_dict[feature]['covered']
                                ) / summary_dict[feature]['total']) * 100, 2)
       color_class = self._GetColorClass(percentage)
-      table_entry[feature] = {
+      entry[feature] = {
           'total': summary_dict[feature]['total'],
           'covered': summary_dict[feature]['covered'],
           'percentage': percentage,
           'color_class': color_class
       }
-    self._table_entries.append(table_entry)
+
+    if href != None:
+      entry['href'] = href
+    if name != None:
+      entry['name'] = name
+    if is_dir != None:
+      entry['is_dir'] = is_dir
+
+    return entry
 
   def _GetColorClass(self, percentage):
     """Returns the css color class based on coverage percentage."""
@@ -231,7 +248,8 @@
     css_path = os.path.join(OUTPUT_DIR, os.extsep.join(['style', 'css']))
     html_header = self._header_template.render(
         css_path=os.path.relpath(css_path, os.path.dirname(output_path)))
-    html_table = self._table_template.render(entries=self._table_entries)
+    html_table = self._table_template.render(
+        entries=self._table_entries, total_entry=self._total_entry)
     html_footer = self._footer_template.render()
 
     with open(output_path, 'w') as html_file:
@@ -401,6 +419,7 @@
           entry_html_report_relative_path, os.path.basename(entry_path),
           per_file_coverage_summary[entry_path])
 
+  html_generator.CreateTotalsEntry(per_directory_coverage_summary[dir_path])
   html_generator.WriteHtmlCoverageReport(html_report_path)
 
 
diff --git a/tools/code_coverage/html_templates/table.html b/tools/code_coverage/html_templates/table.html
index ae12b269..9c9da22 100644
--- a/tools/code_coverage/html_templates/table.html
+++ b/tools/code_coverage/html_templates/table.html
@@ -1,24 +1,34 @@
 <table>
   <tr>
-    <td class='column-entry-left'>Path</td>
-    <td class='column-entry'>Line Coverage</td>
-    <td class='column-entry'>Function Coverage</td>
-    <td class='column-entry'>Region Coverage</td>
+    <td class="column-entry-left">Path</td>
+    <td class="column-entry">Line Coverage</td>
+    <td class="column-entry">Function Coverage</td>
+    <td class="column-entry">Region Coverage</td>
   </tr>
   {% for entry in entries %}
-  <tr class='light-row'>
+  <tr class="light-row">
     <td>
-      {% if entry['is_dir'] == True %}
-        <pre><a href='{{ entry.href }}'>{{ entry.name }}/</a></pre>
+      {% if entry["is_dir"] == True %}
+        <pre><a href='{{ entry["href"] }}'>{{ entry["name"] }}/</a></pre>
       {% else %}
-        <pre><a href='{{ entry.href }}'>{{ entry.name }}</a></pre>
+        <pre><a href='{{ entry["href"] }}'>{{ entry["name"] }}</a></pre>
       {% endif %}
     </td>
-    {% for feature in ('lines', 'functions', 'regions') %}
+    {% for feature in ("lines", "functions", "regions") %}
     <td class='column-entry-{{ entry[feature]["color_class"] }}'>
       <pre> {{ entry[feature]["percentage"] }}% ({{ entry[feature]["covered"] }}/{{ entry[feature]["total"] }})</pre>
     </td>
     {% endfor %}
   </tr>
   {% endfor %}
+  <tr class="light-row">
+    <td>
+      <pre><b>TOTALS</b></pre>
+    </td>
+    {% for feature in ("lines", "functions", "regions") %}
+    <td class='column-entry-{{ total_entry[feature]["color_class"] }}'>
+      <pre><b>{{ total_entry[feature]["percentage"] }}% ({{ total_entry[feature]["covered"] }}/{{ total_entry[feature]["total"] }})</b></pre>
+    </td>
+    {% endfor %}
+  </tr>
 </table>
\ No newline at end of file
diff --git a/tools/gn/analyzer.cc b/tools/gn/analyzer.cc
index fd01759..36c8d49 100644
--- a/tools/gn/analyzer.cc
+++ b/tools/gn/analyzer.cc
@@ -15,18 +15,16 @@
 #include "base/strings/string_util.h"
 #include "base/values.h"
 #include "tools/gn/builder.h"
+#include "tools/gn/config.h"
 #include "tools/gn/deps_iterator.h"
 #include "tools/gn/err.h"
 #include "tools/gn/filesystem_utils.h"
 #include "tools/gn/loader.h"
 #include "tools/gn/location.h"
+#include "tools/gn/pool.h"
 #include "tools/gn/source_file.h"
 #include "tools/gn/target.h"
 
-using LabelSet = Analyzer::LabelSet;
-using SourceFileSet = Analyzer::SourceFileSet;
-using TargetSet = Analyzer::TargetSet;
-
 namespace {
 
 struct Inputs {
@@ -34,40 +32,30 @@
   std::vector<Label> compile_vec;
   std::vector<Label> test_vec;
   bool compile_included_all = false;
-  SourceFileSet source_files;
-  LabelSet compile_labels;
-  LabelSet test_labels;
+  std::set<const SourceFile*> source_files;
+  std::set<Label> compile_labels;
+  std::set<Label> test_labels;
 };
 
 struct Outputs {
   std::string status;
   std::string error;
   bool compile_includes_all = false;
-  LabelSet compile_labels;
-  LabelSet test_labels;
-  LabelSet invalid_labels;
+  std::set<Label> compile_labels;
+  std::set<Label> test_labels;
+  std::set<Label> invalid_labels;
 };
 
-LabelSet LabelsFor(const TargetSet& targets) {
-  LabelSet labels;
+std::set<Label> LabelsFor(const std::set<const Target*>& targets) {
+  std::set<Label> labels;
   for (auto* target : targets)
     labels.insert(target->label());
   return labels;
 }
 
-bool AnyBuildFilesWereModified(const SourceFileSet& source_files) {
-  for (auto* file : source_files) {
-    if (base::EndsWith(file->value(), ".gn", base::CompareCase::SENSITIVE) ||
-        base::EndsWith(file->value(), ".gni", base::CompareCase::SENSITIVE) ||
-        base::EndsWith(file->value(), "build/vs_toolchain.py",
-                       base::CompareCase::SENSITIVE))
-      return true;
-  }
-  return false;
-}
-
-TargetSet Intersect(const TargetSet& l, const TargetSet& r) {
-  TargetSet result;
+std::set<const Target*> Intersect(const std::set<const Target*>& l,
+                                  const std::set<const Target*>& r) {
+  std::set<const Target*> result;
   std::set_intersection(l.begin(), l.end(), r.begin(), r.end(),
                         std::inserter(result, result.begin()));
   return result;
@@ -109,7 +97,7 @@
 void WriteLabels(const Label& default_toolchain,
                  base::DictionaryValue& dict,
                  const std::string& key,
-                 const LabelSet& labels) {
+                 const std::set<Label>& labels) {
   std::vector<std::string> strings;
   auto value = std::make_unique<base::ListValue>();
   for (const auto l : labels)
@@ -224,17 +212,45 @@
 
 }  // namespace
 
-Analyzer::Analyzer(const Builder& builder)
-    : all_targets_(builder.GetAllResolvedTargets()),
-      default_toolchain_(builder.loader()->GetDefaultToolchain()) {
-  for (const auto* target : all_targets_) {
-    labels_to_targets_[target->label()] = target;
-    for (const auto& dep_pair : target->GetDeps(Target::DEPS_ALL))
-      dep_map_.insert(std::make_pair(dep_pair.ptr, target));
-  }
-  for (const auto* target : all_targets_) {
-    if (dep_map_.find(target) == dep_map_.end())
-      roots_.insert(target);
+Analyzer::Analyzer(const Builder& builder,
+                   const SourceFile& build_config_file,
+                   const SourceFile& dot_file,
+                   const std::set<SourceFile>& build_args_dependency_files)
+    : all_items_(builder.GetAllResolvedItems()),
+      default_toolchain_(builder.loader()->GetDefaultToolchain()),
+      build_config_file_(build_config_file),
+      dot_file_(dot_file),
+      build_args_dependency_files_(build_args_dependency_files) {
+  for (const auto* item : all_items_) {
+    labels_to_items_[item->label()] = item;
+
+    // Fill dep_map_.
+    if (item->AsTarget()) {
+      for (const auto& dep_target_pair :
+           item->AsTarget()->GetDeps(Target::DEPS_ALL))
+        dep_map_.insert(std::make_pair(dep_target_pair.ptr, item));
+
+      for (const auto& dep_config_pair : item->AsTarget()->configs())
+        dep_map_.insert(std::make_pair(dep_config_pair.ptr, item));
+
+      dep_map_.insert(std::make_pair(item->AsTarget()->toolchain(), item));
+
+      if (item->AsTarget()->output_type() == Target::ACTION ||
+          item->AsTarget()->output_type() == Target::ACTION_FOREACH) {
+        const LabelPtrPair<Pool>& pool =
+            item->AsTarget()->action_values().pool();
+        if (pool.ptr)
+          dep_map_.insert(std::make_pair(pool.ptr, item));
+      }
+    } else if (item->AsConfig()) {
+      for (const auto& dep_config_pair : item->AsConfig()->configs())
+        dep_map_.insert(std::make_pair(dep_config_pair.ptr, item));
+    } else if (item->AsToolchain()) {
+      for (const auto& dep_pair : item->AsToolchain()->deps())
+        dep_map_.insert(std::make_pair(dep_pair.ptr, item));
+    } else {
+      DCHECK(item->AsPool());
+    }
   }
 }
 
@@ -250,7 +266,7 @@
     return OutputsToJSON(outputs, default_toolchain_, err);
   }
 
-  LabelSet invalid_labels;
+  std::set<Label> invalid_labels;
   for (const auto& label : InvalidLabels(inputs.compile_labels))
     invalid_labels.insert(label);
   for (const auto& label : InvalidLabels(inputs.test_labels))
@@ -261,12 +277,7 @@
     return OutputsToJSON(outputs, default_toolchain_, err);
   }
 
-  // TODO(crbug.com/555273): We can do smarter things when we detect changes
-  // to build files. For example, if all of the ninja files are unchanged,
-  // we know that we can ignore changes to .gn* files. Also, for most .gn
-  // files, we can treat a change as simply affecting every target, config,
-  // or toolchain defined in that file.
-  if (AnyBuildFilesWereModified(inputs.source_files)) {
+  if (WereMainGNFilesModified(inputs.source_files)) {
     outputs.status = "Found dependency (all)";
     if (inputs.compile_included_all) {
       outputs.compile_includes_all = true;
@@ -280,22 +291,45 @@
     return OutputsToJSON(outputs, default_toolchain_, err);
   }
 
-  TargetSet affected_targets = AllAffectedTargets(inputs.source_files);
+  std::set<const Item*> affected_items =
+      GetAllAffectedItems(inputs.source_files);
+  std::set<const Target*> affected_targets;
+  for (const Item* affected_item : affected_items) {
+    // Only handles targets in the default toolchain.
+    // TODO(crbug.com/667989): Expand analyzer to non-default toolchains when
+    // the bug is fixed.
+    if (affected_item->AsTarget() &&
+        affected_item->label().GetToolchainLabel() == default_toolchain_)
+      affected_targets.insert(affected_item->AsTarget());
+  }
+
   if (affected_targets.empty()) {
     outputs.status = "No dependency";
     return OutputsToJSON(outputs, default_toolchain_, err);
   }
 
-  TargetSet compile_targets = TargetsFor(inputs.compile_labels);
-  if (inputs.compile_included_all) {
-    for (auto* root : roots_)
-      compile_targets.insert(root);
+  std::set<const Target*> root_targets;
+  for (const auto* item : all_items_) {
+    if (item->AsTarget() && dep_map_.find(item) == dep_map_.end())
+      root_targets.insert(item->AsTarget());
   }
-  TargetSet filtered_targets = Filter(compile_targets);
+
+  std::set<const Target*> compile_targets = TargetsFor(inputs.compile_labels);
+  if (inputs.compile_included_all) {
+    for (auto* root_target : root_targets)
+      compile_targets.insert(root_target);
+  }
+  std::set<const Target*> filtered_targets = Filter(compile_targets);
   outputs.compile_labels =
       LabelsFor(Intersect(filtered_targets, affected_targets));
 
-  TargetSet test_targets = TargetsFor(inputs.test_labels);
+  // If every target is affected, simply compile All instead of listing all
+  // the targets to make the output easier to read.
+  if (inputs.compile_included_all &&
+      outputs.compile_labels.size() == filtered_targets.size())
+    outputs.compile_includes_all = true;
+
+  std::set<const Target*> test_targets = TargetsFor(inputs.test_labels);
   outputs.test_labels = LabelsFor(Intersect(test_targets, affected_targets));
 
   if (outputs.compile_labels.empty() && outputs.test_labels.empty())
@@ -305,47 +339,53 @@
   return OutputsToJSON(outputs, default_toolchain_, err);
 }
 
-TargetSet Analyzer::AllAffectedTargets(
-    const SourceFileSet& source_files) const {
-  TargetSet direct_matches;
+std::set<const Item*> Analyzer::GetAllAffectedItems(
+    const std::set<const SourceFile*>& source_files) const {
+  std::set<const Item*> directly_affected_items;
   for (auto* source_file : source_files)
-    AddTargetsDirectlyReferringToFileTo(source_file, &direct_matches);
-  TargetSet all_matches;
-  for (auto* match : direct_matches)
-    AddAllRefsTo(match, &all_matches);
-  return all_matches;
+    AddItemsDirectlyReferringToFile(source_file, &directly_affected_items);
+
+  std::set<const Item*> all_affected_items;
+  for (auto* affected_item : directly_affected_items)
+    AddAllItemsReferringToItem(affected_item, &all_affected_items);
+
+  return all_affected_items;
 }
 
-LabelSet Analyzer::InvalidLabels(const LabelSet& labels) const {
-  LabelSet invalid_labels;
+std::set<Label> Analyzer::InvalidLabels(const std::set<Label>& labels) const {
+  std::set<Label> invalid_labels;
   for (const Label& label : labels) {
-    if (labels_to_targets_.find(label) == labels_to_targets_.end())
+    if (labels_to_items_.find(label) == labels_to_items_.end())
       invalid_labels.insert(label);
   }
   return invalid_labels;
 }
 
-TargetSet Analyzer::TargetsFor(const LabelSet& labels) const {
-  TargetSet targets;
+std::set<const Target*> Analyzer::TargetsFor(
+    const std::set<Label>& labels) const {
+  std::set<const Target*> targets;
   for (const auto& label : labels) {
-    auto it = labels_to_targets_.find(label);
-    if (it != labels_to_targets_.end())
-      targets.insert(it->second);
+    auto it = labels_to_items_.find(label);
+    if (it != labels_to_items_.end()) {
+      DCHECK(it->second->AsTarget());
+      targets.insert(it->second->AsTarget());
+    }
   }
   return targets;
 }
 
-TargetSet Analyzer::Filter(const TargetSet& targets) const {
-  TargetSet seen;
-  TargetSet filtered;
+std::set<const Target*> Analyzer::Filter(
+    const std::set<const Target*>& targets) const {
+  std::set<const Target*> seen;
+  std::set<const Target*> filtered;
   for (const auto* target : targets)
     FilterTarget(target, &seen, &filtered);
   return filtered;
 }
 
 void Analyzer::FilterTarget(const Target* target,
-                            TargetSet* seen,
-                            TargetSet* filtered) const {
+                            std::set<const Target*>* seen,
+                            std::set<const Target*>* filtered) const {
   if (seen->find(target) == seen->end()) {
     seen->insert(target);
     if (target->output_type() != Target::GROUP) {
@@ -357,8 +397,17 @@
   }
 }
 
-bool Analyzer::TargetRefersToFile(const Target* target,
-                                  const SourceFile* file) const {
+bool Analyzer::ItemRefersToFile(const Item* item,
+                                const SourceFile* file) const {
+  for (const auto& cur_file : item->build_dependency_files()) {
+    if (cur_file == *file)
+      return true;
+  }
+
+  if (!item->AsTarget())
+    return false;
+
+  const Target* target = item->AsTarget();
   for (const auto& cur_file : target->sources()) {
     if (cur_file == *file)
       return true;
@@ -391,23 +440,44 @@
   return false;
 }
 
-void Analyzer::AddTargetsDirectlyReferringToFileTo(const SourceFile* file,
-                                                   TargetSet* matches) const {
-  for (auto* target : all_targets_) {
-    // Only handles targets in the default toolchain.
-    if ((target->label().GetToolchainLabel() == default_toolchain_) &&
-        TargetRefersToFile(target, file))
-      matches->insert(target);
+void Analyzer::AddItemsDirectlyReferringToFile(
+    const SourceFile* file,
+    std::set<const Item*>* directly_affected_items) const {
+  for (const auto* item : all_items_) {
+    if (ItemRefersToFile(item, file))
+      directly_affected_items->insert(item);
   }
 }
 
-void Analyzer::AddAllRefsTo(const Target* target, TargetSet* results) const {
-  if (results->find(target) != results->end())
-    return;  // Already found this target.
-  results->insert(target);
+void Analyzer::AddAllItemsReferringToItem(
+    const Item* item,
+    std::set<const Item*>* all_affected_items) const {
+  if (all_affected_items->find(item) != all_affected_items->end())
+    return;  // Already found this item.
 
-  auto dep_begin = dep_map_.lower_bound(target);
-  auto dep_end = dep_map_.upper_bound(target);
-  for (auto cur_dep = dep_begin; cur_dep != dep_end; cur_dep++)
-    AddAllRefsTo(cur_dep->second, results);
+  all_affected_items->insert(item);
+
+  auto dep_begin = dep_map_.lower_bound(item);
+  auto dep_end = dep_map_.upper_bound(item);
+  for (auto cur_dep = dep_begin; cur_dep != dep_end; ++cur_dep)
+    AddAllItemsReferringToItem(cur_dep->second, all_affected_items);
+}
+
+bool Analyzer::WereMainGNFilesModified(
+    const std::set<const SourceFile*>& modified_files) const {
+  for (const auto* file : modified_files) {
+    if (*file == dot_file_)
+      return true;
+
+    if (*file == build_config_file_)
+      return true;
+
+    for (const auto& build_args_dependency_file :
+         build_args_dependency_files_) {
+      if (*file == build_args_dependency_file)
+        return true;
+    }
+  }
+
+  return false;
 }
diff --git a/tools/gn/analyzer.h b/tools/gn/analyzer.h
index 130ebe9..01be0e4 100644
--- a/tools/gn/analyzer.h
+++ b/tools/gn/analyzer.h
@@ -10,9 +10,9 @@
 #include <vector>
 
 #include "tools/gn/builder.h"
+#include "tools/gn/item.h"
 #include "tools/gn/label.h"
 #include "tools/gn/source_file.h"
-#include "tools/gn/target.h"
 
 // An Analyzer can answer questions about a build graph. It is used
 // to answer queries for the `refs` and `analyze` commands, where we
@@ -20,11 +20,10 @@
 // from just a single Target.
 class Analyzer {
  public:
-  using LabelSet = std::set<Label>;
-  using SourceFileSet = std::set<const SourceFile*>;
-  using TargetSet = std::set<const Target*>;
-
-  explicit Analyzer(const Builder& builder);
+  Analyzer(const Builder& builder,
+           const SourceFile& build_config_file,
+           const SourceFile& dot_file,
+           const std::set<SourceFile>& build_args_dependency_files);
   ~Analyzer();
 
   // Figures out from a Buider and a JSON-formatted string containing lists
@@ -35,20 +34,17 @@
   std::string Analyze(const std::string& input, Err* err) const;
 
  private:
-  // Returns the roots of the build graph: the set of targets that
-  // no other target depends on.
-  TargetSet& roots() { return roots_; };
-
-  // Returns the set of all targets that might be affected, directly or
+  // Returns the set of all items that might be affected, directly or
   // indirectly, by modifications to the given source files.
-  TargetSet AllAffectedTargets(const SourceFileSet& source_files) const;
+  std::set<const Item*> GetAllAffectedItems(
+      const std::set<const SourceFile*>& source_files) const;
 
   // Returns the set of labels that do not refer to objects in the graph.
-  LabelSet InvalidLabels(const LabelSet& labels) const;
+  std::set<Label> InvalidLabels(const std::set<Label>& labels) const;
 
   // Returns the set of all targets that have a label in the given set.
   // Invalid (or missing) labels will be ignored.
-  TargetSet TargetsFor(const LabelSet& labels) const;
+  std::set<const Target*> TargetsFor(const std::set<Label>& labels) const;
 
   // Returns a filtered set of the given targets, meaning that for each of the
   // given targets,
@@ -70,26 +66,39 @@
   // ones).
   //
   // This filtering behavior is also known as "pruning" the list of targets.
-  TargetSet Filter(const TargetSet& targets) const;
+  std::set<const Target*> Filter(const std::set<const Target*>& targets) const;
 
   // Filter an individual target and adds the results to filtered
   // (see Filter(), above).
-  void FilterTarget(const Target*, TargetSet* seen, TargetSet* filtered) const;
+  void FilterTarget(const Target*,
+                    std::set<const Target*>* seen,
+                    std::set<const Target*>* filtered) const;
 
-  bool TargetRefersToFile(const Target* target, const SourceFile* file) const;
+  bool ItemRefersToFile(const Item* item, const SourceFile* file) const;
 
-  void AddTargetsDirectlyReferringToFileTo(const SourceFile* file,
-                                           TargetSet* matches) const;
+  void AddItemsDirectlyReferringToFile(
+      const SourceFile* file,
+      std::set<const Item*>* affected_items) const;
 
-  void AddAllRefsTo(const Target* target, TargetSet* matches) const;
+  void AddAllItemsReferringToItem(const Item* item,
+                                  std::set<const Item*>* affected_items) const;
 
-  std::vector<const Target*> all_targets_;
-  std::map<const Label, const Target*> labels_to_targets_;
+  // Main GN files stand for files whose context are used globally to execute
+  // every other build files, this list includes dot file, build config file,
+  // build args files etc.
+  bool WereMainGNFilesModified(
+      const std::set<const SourceFile*>& modified_files) const;
+
+  std::vector<const Item*> all_items_;
+  std::map<Label, const Item*> labels_to_items_;
   Label default_toolchain_;
-  std::set<const Target*> roots_;
 
-  // Maps targets to the list of targets that depend on them.
-  std::multimap<const Target*, const Target*> dep_map_;
+  // Maps items to the list of items that depend on them.
+  std::multimap<const Item*, const Item*> dep_map_;
+
+  const SourceFile build_config_file_;
+  const SourceFile dot_file_;
+  const std::set<SourceFile> build_args_dependency_files_;
 };
 
 #endif  // TOOLS_GN_ANALYZER_H_
diff --git a/tools/gn/analyzer_unittest.cc b/tools/gn/analyzer_unittest.cc
index a15c40e..5c299d12 100644
--- a/tools/gn/analyzer_unittest.cc
+++ b/tools/gn/analyzer_unittest.cc
@@ -6,9 +6,15 @@
 #include "testing/gtest/include/gtest/gtest.h"
 #include "tools/gn/build_settings.h"
 #include "tools/gn/builder.h"
+#include "tools/gn/config.h"
 #include "tools/gn/loader.h"
+#include "tools/gn/pool.h"
 #include "tools/gn/settings.h"
 #include "tools/gn/source_file.h"
+#include "tools/gn/substitution_list.h"
+#include "tools/gn/target.h"
+#include "tools/gn/tool.h"
+#include "tools/gn/toolchain.h"
 
 namespace gn_analyzer_unittest {
 
@@ -44,60 +50,38 @@
     tc_name_ = settings_.toolchain_label().name();
   }
 
-  Target* MakeTarget(const std::string dir,
-                     const std::string name,
-                     Target::OutputType type,
-                     const std::vector<std::string>& sources,
-                     const std::vector<Target*>& deps) {
-    Label lbl(SourceDir(dir), name, tc_dir_, tc_name_);
-    Target* target = new Target(&settings_, lbl);
-    target->set_output_type(type);
-    for (const auto& s : sources)
-      target->sources().push_back(SourceFile(s));
-    for (const auto* d : deps)
-      target->public_deps().push_back(LabelTargetPair(d));
-    builder_.ItemDefined(std::unique_ptr<Item>(target));
+  // Ownership of the target will be transfered to the builder, so no leaks.
+  Target* MakeTarget(const std::string& dir, const std::string& name) {
+    Label label(SourceDir(dir), name, tc_dir_, tc_name_);
+    Target* target = new Target(&settings_, label);
+
     return target;
   }
 
-  void AddSource(Target* a, std::string path) {}
+  // Ownership of the config will be transfered to the builder, so no leaks.
+  Config* MakeConfig(const std::string& dir, const std::string& name) {
+    Label label(SourceDir(dir), name, tc_dir_, tc_name_);
+    Config* config = new Config(&settings_, label);
 
-  void AddDep(Target* a, Target* b) {}
-
-  void SetUpABasicBuildGraph() {
-    std::vector<std::string> no_sources;
-    std::vector<Target*> no_deps;
-
-    // All of the targets below are owned by the builder, so none of them
-    // get leaked.
-
-    // Ignore the returned target since nothing depends on it.
-    MakeTarget("//", "a", Target::EXECUTABLE, {"//a.cc"}, no_deps);
-
-    Target* b =
-        MakeTarget("//d", "b", Target::SOURCE_SET, {"//d/b.cc"}, no_deps);
-
-    Target* b_unittests = MakeTarget("//d", "b_unittests", Target::EXECUTABLE,
-                                     {"//d/b_unittest.cc"}, {b});
-
-    Target* c = MakeTarget("//d", "c", Target::EXECUTABLE, {"//d/c.cc"}, {b});
-
-    Target* b_unittests_and_c =
-        MakeTarget("//d", "b_unittests_and_c", Target::GROUP, no_sources,
-                   {b_unittests, c});
-
-    Target* e =
-        MakeTarget("//d", "e", Target::EXECUTABLE, {"//d/e.cc"}, no_deps);
-
-    // Also ignore this returned target since nothing depends on it.
-    MakeTarget("//d", "d", Target::GROUP, no_sources, {b_unittests_and_c, e});
+    return config;
   }
 
-  void RunBasicTest(const std::string& input,
-                    const std::string& expected_output) {
-    SetUpABasicBuildGraph();
+  // Ownership of the pool will be transfered to the builder, so no leaks.
+  Pool* MakePool(const std::string& dir, const std::string& name) {
+    Label label(SourceDir(dir), name, tc_dir_, tc_name_);
+    Pool* pool = new Pool(&settings_, label);
+
+    return pool;
+  }
+
+  void RunAnalyzerTest(const std::string& input,
+                       const std::string& expected_output) {
+    Analyzer analyzer(builder_, SourceFile("//build/config/BUILDCONFIG.gn"),
+                      SourceFile("//.gn"),
+                      {SourceFile("//out/debug/args.gn"),
+                       SourceFile("//build/default_args.gn")});
     Err err;
-    std::string actual_output = Analyzer(builder_).Analyze(input, &err);
+    std::string actual_output = analyzer.Analyze(input, &err);
     EXPECT_EQ(err.has_error(), false);
     EXPECT_EQ(expected_output, actual_output);
   }
@@ -111,40 +95,387 @@
   std::string tc_name_;
 };
 
-TEST_F(AnalyzerTest, AllWasPruned) {
-  RunBasicTest(
+// Tests that a target is marked as affected if its sources are modified.
+TEST_F(AnalyzerTest, TargetRefersToSources) {
+  Target* t = MakeTarget("//dir", "target_name");
+  builder_.ItemDefined(std::unique_ptr<Item>(t));
+  RunAnalyzerTest(
       R"({
-        "files": [ "//d/b.cc" ],
-        "additional_compile_targets": [ "all" ],
-        "test_targets": [ ]
-      })",
+       "files": [ "//dir/file_name.cc" ],
+       "additional_compile_targets": [ "all" ],
+       "test_targets": [ "//dir:target_name" ]
+       })",
       "{"
-      R"("compile_targets":["//d:b_unittests","//d:c"],)"
-      R"("status":"Found dependency",)"
+      R"("compile_targets":[],)"
+      R"/("status":"No dependency",)/"
+      R"("test_targets":[])"
+      "}");
+
+  t->sources().push_back(SourceFile("//dir/file_name.cc"));
+  RunAnalyzerTest(
+      R"({
+       "files": [ "//dir/file_name.cc" ],
+       "additional_compile_targets": [ "all" ],
+       "test_targets": [ "//dir:target_name" ]
+       })",
+      "{"
+      R"("compile_targets":["all"],)"
+      R"/("status":"Found dependency",)/"
+      R"("test_targets":["//dir:target_name"])"
+      "}");
+}
+
+// Tests that a target is marked as affected if its public headers are modified.
+TEST_F(AnalyzerTest, TargetRefersToPublicHeaders) {
+  Target* t = MakeTarget("//dir", "target_name");
+  builder_.ItemDefined(std::unique_ptr<Item>(t));
+  RunAnalyzerTest(
+      R"({
+       "files": [ "//dir/header_name.h" ],
+       "additional_compile_targets": [ "all" ],
+       "test_targets": [ "//dir:target_name" ]
+       })",
+      "{"
+      R"("compile_targets":[],)"
+      R"/("status":"No dependency",)/"
+      R"("test_targets":[])"
+      "}");
+
+  t->public_headers().push_back(SourceFile("//dir/header_name.h"));
+  RunAnalyzerTest(
+      R"({
+       "files": [ "//dir/header_name.h" ],
+       "additional_compile_targets": [ "all" ],
+       "test_targets": [ "//dir:target_name" ]
+       })",
+      "{"
+      R"("compile_targets":["all"],)"
+      R"/("status":"Found dependency",)/"
+      R"("test_targets":["//dir:target_name"])"
+      "}");
+}
+
+// Tests that a target is marked as affected if its inputs are modified.
+TEST_F(AnalyzerTest, TargetRefersToInputs) {
+  Target* t = MakeTarget("//dir", "target_name");
+  builder_.ItemDefined(std::unique_ptr<Item>(t));
+  RunAnalyzerTest(
+      R"({
+       "files": [ "//dir/extra_input.cc" ],
+       "additional_compile_targets": [ "all" ],
+       "test_targets": [ "//dir:target_name" ]
+       })",
+      "{"
+      R"("compile_targets":[],)"
+      R"/("status":"No dependency",)/"
+      R"("test_targets":[])"
+      "}");
+
+  t->inputs().push_back(SourceFile("//dir/extra_input.cc"));
+  RunAnalyzerTest(
+      R"({
+       "files": [ "//dir/extra_input.cc" ],
+       "additional_compile_targets": [ "all" ],
+       "test_targets": [ "//dir:target_name" ]
+       })",
+      "{"
+      R"("compile_targets":["all"],)"
+      R"/("status":"Found dependency",)/"
+      R"("test_targets":["//dir:target_name"])"
+      "}");
+}
+
+// Tests that a target is marked as affected if its data are modified.
+TEST_F(AnalyzerTest, TargetRefersToData) {
+  Target* t = MakeTarget("//dir", "target_name");
+  builder_.ItemDefined(std::unique_ptr<Item>(t));
+  RunAnalyzerTest(
+      R"({
+       "files": [ "//dir/data.html" ],
+       "additional_compile_targets": [ "all" ],
+       "test_targets": [ "//dir:target_name" ]
+       })",
+      "{"
+      R"("compile_targets":[],)"
+      R"/("status":"No dependency",)/"
+      R"("test_targets":[])"
+      "}");
+
+  t->data().push_back("//dir/data.html");
+  RunAnalyzerTest(
+      R"({
+       "files": [ "//dir/data.html" ],
+       "additional_compile_targets": [ "all" ],
+       "test_targets": [ "//dir:target_name" ]
+       })",
+      "{"
+      R"("compile_targets":["all"],)"
+      R"/("status":"Found dependency",)/"
+      R"("test_targets":["//dir:target_name"])"
+      "}");
+}
+
+// Tests that a target is marked as affected if the target is an action and its
+// action script is modified.
+TEST_F(AnalyzerTest, TargetRefersToActionScript) {
+  Target* t = MakeTarget("//dir", "target_name");
+  builder_.ItemDefined(std::unique_ptr<Item>(t));
+  t->set_output_type(Target::ACTION);
+  RunAnalyzerTest(
+      R"({
+       "files": [ "//dir/script.py" ],
+       "additional_compile_targets": [ "all" ],
+       "test_targets": [ "//dir:target_name" ]
+       })",
+      "{"
+      R"("compile_targets":[],)"
+      R"/("status":"No dependency",)/"
+      R"("test_targets":[])"
+      "}");
+
+  t->action_values().set_script(SourceFile("//dir/script.py"));
+  RunAnalyzerTest(
+      R"({
+       "files": [ "//dir/script.py" ],
+       "additional_compile_targets": [ "all" ],
+       "test_targets": [ "//dir:target_name" ]
+       })",
+      "{"
+      R"("compile_targets":["all"],)"
+      R"/("status":"Found dependency",)/"
+      R"("test_targets":["//dir:target_name"])"
+      "}");
+}
+
+// Tests that a target is marked as affected if its build dependency files are
+// modified.
+TEST_F(AnalyzerTest, TargetRefersToBuildDependencyFiles) {
+  Target* t = MakeTarget("//dir", "target_name");
+  builder_.ItemDefined(std::unique_ptr<Item>(t));
+  RunAnalyzerTest(
+      R"({
+       "files": [ "//dir/BUILD.gn" ],
+       "additional_compile_targets": [ "all" ],
+       "test_targets": [ "//dir:target_name" ]
+       })",
+      "{"
+      R"("compile_targets":[],)"
+      R"/("status":"No dependency",)/"
+      R"("test_targets":[])"
+      "}");
+
+  t->build_dependency_files().insert(SourceFile("//dir/BUILD.gn"));
+  RunAnalyzerTest(
+      R"({
+       "files": [ "//dir/BUILD.gn" ],
+       "additional_compile_targets": [ "all" ],
+       "test_targets": [ "//dir:target_name" ]
+       })",
+      "{"
+      R"("compile_targets":["all"],)"
+      R"/("status":"Found dependency",)/"
+      R"("test_targets":["//dir:target_name"])"
+      "}");
+}
+
+// Tests that if a target is marked as affected, then it propagates to dependent
+// test_targets.
+TEST_F(AnalyzerTest, AffectedTargetpropagatesToDependentTargets) {
+  Target* t1 = MakeTarget("//dir", "target_name1");
+  Target* t2 = MakeTarget("//dir", "target_name2");
+  Target* t3 = MakeTarget("//dir", "target_name3");
+  t1->private_deps().push_back(LabelTargetPair(t2));
+  t2->private_deps().push_back(LabelTargetPair(t3));
+  builder_.ItemDefined(std::unique_ptr<Item>(t1));
+  builder_.ItemDefined(std::unique_ptr<Item>(t2));
+  builder_.ItemDefined(std::unique_ptr<Item>(t3));
+
+  RunAnalyzerTest(
+      R"({
+       "files": [ "//dir/BUILD.gn" ],
+       "additional_compile_targets": [ "all" ],
+       "test_targets": [ "//dir:target_name1", "//dir:target_name2" ]
+       })",
+      "{"
+      R"("compile_targets":[],)"
+      R"/("status":"No dependency",)/"
+      R"("test_targets":[])"
+      "}");
+
+  t3->build_dependency_files().insert(SourceFile("//dir/BUILD.gn"));
+  RunAnalyzerTest(
+      R"({
+       "files": [ "//dir/BUILD.gn" ],
+       "additional_compile_targets": [ "all" ],
+       "test_targets": [ "//dir:target_name1", "//dir:target_name2" ]
+       })",
+      "{"
+      R"("compile_targets":["all"],)"
+      R"/("status":"Found dependency",)/"
+      R"("test_targets":["//dir:target_name1","//dir:target_name2"])"
+      "}");
+}
+
+// Tests that if a config is marked as affected, then it propagates to dependent
+// test_targets.
+TEST_F(AnalyzerTest, AffectedConfigpropagatesToDependentTargets) {
+  Config* c = MakeConfig("//dir", "config_name");
+  Target* t = MakeTarget("//dir", "target_name");
+  t->configs().push_back(LabelConfigPair(c));
+  builder_.ItemDefined(std::unique_ptr<Item>(t));
+  builder_.ItemDefined(std::unique_ptr<Item>(c));
+  RunAnalyzerTest(
+      R"({
+       "files": [ "//dir/BUILD.gn" ],
+       "additional_compile_targets": [ "all" ],
+       "test_targets": [ "//dir:target_name" ]
+       })",
+      "{"
+      R"("compile_targets":[],)"
+      R"/("status":"No dependency",)/"
+      R"("test_targets":[])"
+      "}");
+
+  c->build_dependency_files().insert(SourceFile("//dir/BUILD.gn"));
+  RunAnalyzerTest(
+      R"({
+       "files": [ "//dir/BUILD.gn" ],
+       "additional_compile_targets": [ "all" ],
+       "test_targets": [ "//dir:target_name" ]
+       })",
+      "{"
+      R"("compile_targets":["all"],)"
+      R"/("status":"Found dependency",)/"
+      R"("test_targets":["//dir:target_name"])"
+      "}");
+}
+
+// Tests that if toolchain is marked as affected, then it propagates to
+// dependent test_targets.
+TEST_F(AnalyzerTest, AffectedToolchainpropagatesToDependentTargets) {
+  Target* target = MakeTarget("//dir", "target_name");
+  target->set_output_type(Target::EXECUTABLE);
+  Toolchain* toolchain = new Toolchain(&settings_, settings_.toolchain_label());
+
+  // The tool is not used anywhere, but is required to construct the dependency
+  // between a target and the toolchain.
+  std::unique_ptr<Tool> fake_tool(new Tool());
+  fake_tool->set_outputs(
+      SubstitutionList::MakeForTest("//out/debug/output.txt"));
+  toolchain->SetTool(Toolchain::TYPE_LINK, std::move(fake_tool));
+  builder_.ItemDefined(std::unique_ptr<Item>(target));
+  builder_.ItemDefined(std::unique_ptr<Item>(toolchain));
+
+  RunAnalyzerTest(
+      R"({
+         "files": [ "//tc/BUILD.gn" ],
+         "additional_compile_targets": [ "all" ],
+         "test_targets": [ "//dir:target_name" ]
+         })",
+      "{"
+      R"("compile_targets":[],)"
+      R"/("status":"No dependency",)/"
+      R"("test_targets":[])"
+      "}");
+
+  toolchain->build_dependency_files().insert(SourceFile("//tc/BUILD.gn"));
+  RunAnalyzerTest(
+      R"({
+       "files": [ "//tc/BUILD.gn" ],
+       "additional_compile_targets": [ "all" ],
+       "test_targets": [ "//dir:target_name" ]
+       })",
+      "{"
+      R"("compile_targets":["all"],)"
+      R"/("status":"Found dependency",)/"
+      R"("test_targets":["//dir:target_name"])"
+      "}");
+}
+
+// Tests that if a pool is marked as affected, then it propagates to dependent
+// targets.
+TEST_F(AnalyzerTest, AffectedPoolpropagatesToDependentTargets) {
+  Target* t = MakeTarget("//dir", "target_name");
+  t->set_output_type(Target::ACTION);
+  Pool* p = MakePool("//dir", "pool_name");
+  t->action_values().set_pool(LabelPtrPair<Pool>(p));
+
+  builder_.ItemDefined(std::unique_ptr<Item>(t));
+  builder_.ItemDefined(std::unique_ptr<Item>(p));
+
+  RunAnalyzerTest(
+      R"({
+       "files": [ "//dir/BUILD.gn" ],
+       "additional_compile_targets": [ "all" ],
+       "test_targets": [ "//dir:target_name" ]
+       })",
+      "{"
+      R"("compile_targets":[],)"
+      R"/("status":"No dependency",)/"
+      R"("test_targets":[])"
+      "}");
+
+  p->build_dependency_files().insert(SourceFile("//dir/BUILD.gn"));
+  RunAnalyzerTest(
+      R"({
+       "files": [ "//dir/BUILD.gn" ],
+       "additional_compile_targets": [ "all" ],
+       "test_targets": [ "//dir:target_name" ]
+       })",
+      "{"
+      R"("compile_targets":["all"],)"
+      R"/("status":"Found dependency",)/"
+      R"("test_targets":["//dir:target_name"])"
+      "}");
+}
+
+// Tests that when dependency was found, the "compile_targets" in the output is
+// not "all".
+TEST_F(AnalyzerTest, CompileTargetsAllWasPruned) {
+  Target* t1 = MakeTarget("//dir", "target_name1");
+  Target* t2 = MakeTarget("//dir", "target_name2");
+  builder_.ItemDefined(std::unique_ptr<Item>(t1));
+  builder_.ItemDefined(std::unique_ptr<Item>(t2));
+  t2->build_dependency_files().insert(SourceFile("//dir/BUILD.gn"));
+
+  RunAnalyzerTest(
+      R"({
+       "files": [ "//dir/BUILD.gn" ],
+       "additional_compile_targets": [ "all" ],
+       "test_targets": []
+       })",
+      "{"
+      R"("compile_targets":["//dir:target_name2"],)"
+      R"/("status":"Found dependency",)/"
       R"("test_targets":[])"
       "}");
 }
 
+// Tests that output is "No dependency" when no dependency is found.
 TEST_F(AnalyzerTest, NoDependency) {
-  RunBasicTest(
+  Target* t = MakeTarget("//dir", "target_name");
+  builder_.ItemDefined(std::unique_ptr<Item>(t));
+
+  RunAnalyzerTest(
       R"({
-        "files":[ "//missing.cc" ],
-        "additional_compile_targets": [ "all" ],
-        "test_targets": [ "//:a" ]
-      })",
+       "files": [ "//dir/BUILD.gn" ],
+       "additional_compile_targets": [ "all" ],
+       "test_targets": []
+       })",
       "{"
       R"("compile_targets":[],)"
-      R"("status":"No dependency",)"
+      R"/("status":"No dependency",)/"
       R"("test_targets":[])"
       "}");
 }
 
+// Tests that output is "No dependency" when no files or targets are provided.
 TEST_F(AnalyzerTest, NoFilesNoTargets) {
-  RunBasicTest(
+  RunAnalyzerTest(
       R"({
-        "files": [],
-        "additional_compile_targets": [],
-        "test_targets": []
+       "files": [],
+       "additional_compile_targets": [],
+       "test_targets": []
       })",
       "{"
       R"("compile_targets":[],)"
@@ -153,26 +484,14 @@
       "}");
 }
 
-TEST_F(AnalyzerTest, OneTestTargetModified) {
-  RunBasicTest(
-      R"({
-        "files": [ "//a.cc" ],
-        "additional_compile_targets": [],
-        "test_targets": [ "//:a" ]
-      })",
-      "{"
-      R"("compile_targets":[],)"
-      R"("status":"Found dependency",)"
-      R"("test_targets":["//:a"])"
-      "}");
-}
-
+// Tests that output displays proper error message when given files aren't
+// source-absolute or absolute path.
 TEST_F(AnalyzerTest, FilesArentSourceAbsolute) {
-  RunBasicTest(
+  RunAnalyzerTest(
       R"({
-        "files": [ "a.cc" ],
-        "additional_compile_targets": [],
-        "test_targets": [ "//:a" ]
+       "files": [ "a.cc" ],
+       "additional_compile_targets": [],
+       "test_targets": [ "//dir:target_name" ]
       })",
       "{"
       R"("error":)"
@@ -181,12 +500,13 @@
       "}");
 }
 
+// Tests that output displays proper error message when input is illy-formed.
 TEST_F(AnalyzerTest, WrongInputFields) {
-  RunBasicTest(
+  RunAnalyzerTest(
       R"({
-        "files": [ "//a.cc" ],
-        "compile_targets": [],
-        "test_targets": [ "//:a" ]
+       "files": [ "//a.cc" ],
+       "compile_targets": [],
+       "test_targets": [ "//dir:target_name" ]
       })",
       "{"
       R"("error":)"
@@ -196,37 +516,59 @@
       "}");
 }
 
-TEST_F(AnalyzerTest, BuildFilesWereModified) {
-  // This tests that if a build file is modified, we bail out early with
-  // "Found dependency (all)" error since we can't handle changes to
-  // build files yet (crbug.com/555273).
-  RunBasicTest(
+// Bails out early with "Found dependency (all)" if dot file is modified.
+TEST_F(AnalyzerTest, DotFileWasModified) {
+  Target* t = MakeTarget("//dir", "target_name");
+  builder_.ItemDefined(std::unique_ptr<Item>(t));
+
+  RunAnalyzerTest(
       R"({
-        "files": [ "//a.cc", "//BUILD.gn" ],
-        "additional_compile_targets": [],
-        "test_targets": [ "//:a" ]
+       "files": [ "//.gn" ],
+       "additional_compile_targets": [],
+       "test_targets": [ "//dir:target_name" ]
       })",
       "{"
-      R"("compile_targets":["//:a"],)"
+      R"("compile_targets":["//dir:target_name"],)"
       R"/("status":"Found dependency (all)",)/"
-      R"("test_targets":["//:a"])"
+      R"("test_targets":["//dir:target_name"])"
       "}");
 }
 
-TEST_F(AnalyzerTest, BuildFilesWereModifiedAndCompilingAll) {
-  // This tests that if a build file is modified, we bail out early with
-  // "Found dependency (all)" error since we can't handle changes to
-  // build files yet (crbug.com/555273).
-  RunBasicTest(
+// Bails out early with "Found dependency (all)" if master build config file is
+// modified.
+TEST_F(AnalyzerTest, BuildConfigFileWasModified) {
+  Target* t = MakeTarget("//dir", "target_name");
+  builder_.ItemDefined(std::unique_ptr<Item>(t));
+
+  RunAnalyzerTest(
       R"({
-        "files": [ "//a.cc", "//BUILD.gn" ],
-        "additional_compile_targets": [ "all" ],
-        "test_targets": [ "//:a" ]
+       "files": [ "//build/config/BUILDCONFIG.gn" ],
+       "additional_compile_targets": [],
+       "test_targets": [ "//dir:target_name" ]
       })",
       "{"
-      R"("compile_targets":["all"],)"
+      R"("compile_targets":["//dir:target_name"],)"
       R"/("status":"Found dependency (all)",)/"
-      R"("test_targets":["//:a"])"
+      R"("test_targets":["//dir:target_name"])"
+      "}");
+}
+
+// Bails out early with "Found dependency (all)" if a build args dependency file
+// is modified.
+TEST_F(AnalyzerTest, BuildArgsDependencyFileWasModified) {
+  Target* t = MakeTarget("//dir", "target_name");
+  builder_.ItemDefined(std::unique_ptr<Item>(t));
+
+  RunAnalyzerTest(
+      R"({
+       "files": [ "//build/default_args.gn" ],
+       "additional_compile_targets": [],
+       "test_targets": [ "//dir:target_name" ]
+      })",
+      "{"
+      R"("compile_targets":["//dir:target_name"],)"
+      R"/("status":"Found dependency (all)",)/"
+      R"("test_targets":["//dir:target_name"])"
       "}");
 }
 
diff --git a/tools/gn/args.cc b/tools/gn/args.cc
index 4a0c1375..a53eb490 100644
--- a/tools/gn/args.cc
+++ b/tools/gn/args.cc
@@ -6,6 +6,7 @@
 
 #include "base/sys_info.h"
 #include "build/build_config.h"
+#include "tools/gn/source_file.h"
 #include "tools/gn/string_utils.h"
 #include "tools/gn/variables.h"
 
diff --git a/tools/gn/args.h b/tools/gn/args.h
index 2ae4bc1..cbac794 100644
--- a/tools/gn/args.h
+++ b/tools/gn/args.h
@@ -6,6 +6,7 @@
 #define TOOLS_GN_ARGS_H_
 
 #include <map>
+#include <set>
 
 #include "base/containers/hash_tables.h"
 #include "base/macros.h"
@@ -13,6 +14,7 @@
 #include "tools/gn/scope.h"
 
 class Err;
+class SourceFile;
 
 extern const char kBuildArgs_Help[];
 
@@ -82,6 +84,17 @@
   // map instead of a hash map so the arguements are sorted alphabetically.
   ValueWithOverrideMap GetAllArguments() const;
 
+  // Returns the set of build files that may affect the build arguments, please
+  // refer to Scope for how this is determined.
+  const std::set<SourceFile>& build_args_dependency_files() const {
+    return build_args_dependency_files_;
+  }
+
+  void set_build_args_dependency_files(
+      const std::set<SourceFile>& build_args_dependency_files) {
+    build_args_dependency_files_ = build_args_dependency_files;
+  }
+
  private:
   using ArgumentsPerToolchain =
       base::hash_map<const Settings*, Scope::KeyValueMap>;
@@ -126,6 +139,8 @@
   // we see an argument declaration.
   mutable ArgumentsPerToolchain toolchain_overrides_;
 
+  std::set<SourceFile> build_args_dependency_files_;
+
   DISALLOW_ASSIGN(Args);
 };
 
diff --git a/tools/gn/builder.cc b/tools/gn/builder.cc
index c81cc79..4b464af 100644
--- a/tools/gn/builder.cc
+++ b/tools/gn/builder.cc
@@ -138,6 +138,19 @@
   return result;
 }
 
+std::vector<const Item*> Builder::GetAllResolvedItems() const {
+  std::vector<const Item*> result;
+  result.reserve(records_.size());
+  for (const auto& record : records_) {
+    if (record.second->type() != BuilderRecord::ITEM_UNKNOWN &&
+        record.second->should_generate() && record.second->item()) {
+      result.push_back(record.second->item());
+    }
+  }
+
+  return result;
+}
+
 std::vector<const Target*> Builder::GetAllResolvedTargets() const {
   std::vector<const Target*> result;
   result.reserve(records_.size());
diff --git a/tools/gn/builder.h b/tools/gn/builder.h
index d46bbd1..27a1fb3 100644
--- a/tools/gn/builder.h
+++ b/tools/gn/builder.h
@@ -45,6 +45,9 @@
 
   std::vector<const BuilderRecord*> GetAllRecords() const;
 
+  // Returns items which should be generated and which are defined.
+  std::vector<const Item*> GetAllResolvedItems() const;
+
   // Returns targets which should be generated and which are defined.
   std::vector<const Target*> GetAllResolvedTargets() const;
 
diff --git a/tools/gn/command_analyze.cc b/tools/gn/command_analyze.cc
index 6fd5823..9aa698b3c 100644
--- a/tools/gn/command_analyze.cc
+++ b/tools/gn/command_analyze.cc
@@ -110,10 +110,12 @@
   if (!setup->DoSetup(args[0], false) || !setup->Run())
     return 1;
 
-  Analyzer analyzer(setup->builder());
-
   Err err;
-  std::string output = Analyzer(setup->builder()).Analyze(input, &err);
+  Analyzer analyzer(
+      setup->builder(), setup->build_settings().build_config_file(),
+      setup->GetDotFile(),
+      setup->build_settings().build_args().build_args_dependency_files());
+  std::string output = analyzer.Analyze(input, &err);
   if (err.has_error()) {
     err.PrintToStdout();
     return 1;
diff --git a/tools/gn/item.h b/tools/gn/item.h
index 9195b5e..f2e7c065 100644
--- a/tools/gn/item.h
+++ b/tools/gn/item.h
@@ -61,6 +61,10 @@
     return build_dependency_files_;
   }
 
+  std::set<SourceFile>& build_dependency_files() {
+    return build_dependency_files_;
+  }
+
   // Called when this item is resolved, meaning it and all of its dependents
   // have no unresolved deps. Returns true on success. Sets the error and
   // returns false on failure.
@@ -69,7 +73,7 @@
  private:
   const Settings* settings_;
   Label label_;
-  const std::set<SourceFile> build_dependency_files_;
+  std::set<SourceFile> build_dependency_files_;
   const ParseNode* defined_from_;
 
   Visibility visibility_;
diff --git a/tools/gn/setup.cc b/tools/gn/setup.cc
index 9bb0b71..36b6ec5 100644
--- a/tools/gn/setup.cc
+++ b/tools/gn/setup.cc
@@ -488,6 +488,8 @@
   Scope::KeyValueMap overrides;
   arg_scope.GetCurrentScopeValues(&overrides);
   build_settings_.build_args().AddArgOverrides(overrides);
+  build_settings_.build_args().set_build_args_dependency_files(
+      arg_scope.build_dependency_files());
   return true;
 }
 
diff --git a/tools/gn/setup.h b/tools/gn/setup.h
index 68a8f0b3..68f86c7b 100644
--- a/tools/gn/setup.h
+++ b/tools/gn/setup.h
@@ -85,6 +85,8 @@
   Builder& builder() { return builder_; }
   LoaderImpl* loader() { return loader_.get(); }
 
+  const SourceFile& GetDotFile() const { return dotfile_input_file_->name(); }
+
   // Name of the file in the root build directory that contains the build
   // arguements.
   static const char kBuildArgFileName[];
diff --git a/tools/gn/source_file.h b/tools/gn/source_file.h
index 87fd590..06bbd11 100644
--- a/tools/gn/source_file.h
+++ b/tools/gn/source_file.h
@@ -27,6 +27,7 @@
 
   // Takes a known absolute source file. Always begins in a slash.
   explicit SourceFile(const base::StringPiece& p);
+  SourceFile(const SourceFile& other) = default;
 
   // Constructs from the given string by swapping in the contents of the given
   // value. The value will be the empty string after this call.
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index b5b6395..d4fc023 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -25221,7 +25221,6 @@
   <int value="-918618075" label="enable-service-worker"/>
   <int value="-914210146" label="enable-web-based-signin"/>
   <int value="-912456561" label="MidiManagerWinrt:enabled"/>
-  <int value="-909641013" label="DataReductionProxySiteBreakdown:enabled"/>
   <int value="-908421850" label="PointerEvent:enabled"/>
   <int value="-907234795" label="NewAudioRenderingMixingStrategy:disabled"/>
   <int value="-899393472" label="enable-new-app-menu-icon"/>
@@ -25797,7 +25796,6 @@
   <int value="637452937" label="ChromeHomeSurvey:enabled"/>
   <int value="643725031" label="disable-touch-feedback"/>
   <int value="644189071" label="PermissionsBlacklist:enabled"/>
-  <int value="644674603" label="DataReductionProxySiteBreakdown:disabled"/>
   <int value="646252875" label="ReadItLaterInMenu:enabled"/>
   <int value="646738320" label="disable-gesture-editing"/>
   <int value="649111851" label="MidiManagerCros:enabled"/>
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index 7f029a4..c5293b5 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -30565,6 +30565,15 @@
   </summary>
 </histogram>
 
+<histogram name="InstantTethering.HotspotUsageDuration" units="ms">
+  <owner>hansberry@chromium.org</owner>
+  <summary>
+    The duration of time between the start and end of a Tether connection.
+    Timing starts when the device connects to the Wi-Fi hotspot and ends when
+    the device becomes disconnected from the Wi-Fi hotspot.
+  </summary>
+</histogram>
+
 <histogram
     name="InstantTethering.Performance.AdvertisementToConnectionDuration"
     units="ms">
@@ -81374,7 +81383,7 @@
   <summary>Time spent selecting entries for eviction.</summary>
 </histogram>
 
-<histogram base="true" name="SimpleCache.FileDescriptorLimitHard">
+<histogram name="SimpleCache.FileDescriptorLimitHard" units="file descriptors">
   <owner>morlovich@chromium.org</owner>
   <summary>
     The maximum limit of how many file descriptors a process can open.  Emitted
@@ -81383,7 +81392,7 @@
   </summary>
 </histogram>
 
-<histogram base="true" name="SimpleCache.FileDescriptorLimitSoft">
+<histogram name="SimpleCache.FileDescriptorLimitSoft" units="file descriptors">
   <owner>morlovich@chromium.org</owner>
   <summary>
     The current limit of how many file descriptors a process can open.  Emitted
@@ -81392,7 +81401,7 @@
   </summary>
 </histogram>
 
-<histogram base="true" name="SimpleCache.FileDescriptorLimitStatus"
+<histogram name="SimpleCache.FileDescriptorLimitStatus"
     enum="SimpleCache.FileDescriptorLimitStatus">
   <owner>morlovich@chromium.org</owner>
   <summary>
@@ -84170,6 +84179,19 @@
 </histogram>
 
 <histogram name="Startup.BrowserMessageLoopStartTimeFromMainEntry2" units="ms">
+  <obsolete>
+    Deprecated 2018-01 in favor of
+    Startup.BrowserMessageLoopStartTimeFromMainEntry3 which does not involve a
+    conversion from Time to TimeTicks.
+  </obsolete>
+  <owner>fdoray@chromium.org</owner>
+  <owner>gab@chromium.org</owner>
+  <summary>
+    Time from main entry to the start of the main thread's message loop.
+  </summary>
+</histogram>
+
+<histogram name="Startup.BrowserMessageLoopStartTimeFromMainEntry3" units="ms">
   <owner>fdoray@chromium.org</owner>
   <owner>gab@chromium.org</owner>
   <summary>
@@ -100787,9 +100809,21 @@
   <affected-histogram name="SimpleCache.Eviction.SizeWhenDone2"/>
   <affected-histogram name="SimpleCache.Eviction.TimeToDone"/>
   <affected-histogram name="SimpleCache.Eviction.TimeToSelectEntries"/>
-  <affected-histogram name="SimpleCache.FileDescriptorLimitHard"/>
-  <affected-histogram name="SimpleCache.FileDescriptorLimitSoft"/>
-  <affected-histogram name="SimpleCache.FileDescriptorLimitStatus"/>
+  <affected-histogram name="SimpleCache.FileDescriptorLimitHard">
+    <obsolete>
+      Removed January 2018, as the limit is independent of the backend type.
+    </obsolete>
+  </affected-histogram>
+  <affected-histogram name="SimpleCache.FileDescriptorLimitSoft">
+    <obsolete>
+      Removed January 2018, as the limit is independent of the backend type.
+    </obsolete>
+  </affected-histogram>
+  <affected-histogram name="SimpleCache.FileDescriptorLimitStatus">
+    <obsolete>
+      Removed January 2018, as the limit is independent of the backend type.
+    </obsolete>
+  </affected-histogram>
   <affected-histogram name="SimpleCache.GlobalOpenEntryCount"/>
   <affected-histogram name="SimpleCache.HeaderSize"/>
   <affected-histogram name="SimpleCache.HeaderSizeChange"/>
@@ -109353,6 +109387,7 @@
   <affected-histogram name="Startup.BrowserMessageLoopStartTime"/>
   <affected-histogram name="Startup.BrowserMessageLoopStartTimeFromMainEntry"/>
   <affected-histogram name="Startup.BrowserMessageLoopStartTimeFromMainEntry2"/>
+  <affected-histogram name="Startup.BrowserMessageLoopStartTimeFromMainEntry3"/>
   <affected-histogram name="Startup.BrowserOpenTabs"/>
   <affected-histogram name="Startup.BrowserWindowDisplay"/>
   <affected-histogram name="Startup.FirstWebContents.MainFrameLoad2"/>
@@ -110158,6 +110193,7 @@
   <affected-histogram
       name="Startup.BrowserMessageLoopStartTimeFromMainEntry.FirstRun2"/>
   <affected-histogram name="Startup.BrowserMessageLoopStartTimeFromMainEntry2"/>
+  <affected-histogram name="Startup.BrowserMessageLoopStartTimeFromMainEntry3"/>
   <affected-histogram name="Startup.BrowserOpenTabs"/>
   <affected-histogram name="Startup.BrowserWindow.FirstPaint"/>
   <affected-histogram name="Startup.BrowserWindow.FirstPaint.CompositingEnded"/>
diff --git a/tools/perf/expectations.config b/tools/perf/expectations.config
index 71947ef9..404fd8fa 100644
--- a/tools/perf/expectations.config
+++ b/tools/perf/expectations.config
@@ -186,7 +186,6 @@
 crbug.com/673775 [ Win ] system_health.common_desktop/browse:search:google [ Skip ]
 crbug.com/773393 [ Win ] system_health.common_desktop/browse:media:tumblr [ Skip ]
 crbug.com/799106 [ Win ] system_health.common_desktop/browse:media:flickr_infinite_scroll [ Skip ]
-crbug.com/799122 [ Mac ] system_health.common_desktop/load:media:youtube [ Skip ]
 
 # Benchmark: system_health.common_mobile
 [ Android_Webview ] system_health.common_mobile/browse:chrome:omnibox [ Skip ]
@@ -284,7 +283,8 @@
 crbug.com/798465 [ Win ] v8.browsing_desktop-future/browse:news:flipboard [ Skip ]
 
 # Benchmark: v8.browsing_mobile
-crbug.com/788797 [ Cherry_Mobile_Android_One ] v8.browsing_mobile/* [ Skip ]
+crbug.com/788797 [ Cherry_Mobile_Android_One ] v8.browsing_mobile/browse:social:facebook_infinite_scroll [ Skip ]
+crbug.com/788797 [ Cherry_Mobile_Android_One ] v8.browsing_mobile/browse:social:pinterest_infinite_scroll [ Skip ]
 crbug.com/768472 [ Cherry_Mobile_Android_One ] v8.browsing_mobile/browse:shopping:lazada [ Skip ]
 crbug.com/714650 [ Android ] v8.browsing_mobile/browse:news:globo [ Skip ]
 crbug.com/767970 [ Cherry_Mobile_Android_One ] v8.browsing_mobile/browse:tech:discourse_infinite_scroll [ Skip ]
diff --git a/tools/traffic_annotation/README.md b/tools/traffic_annotation/README.md
index f7ce4f6..48ae6e7 100644
--- a/tools/traffic_annotation/README.md
+++ b/tools/traffic_annotation/README.md
@@ -96,5 +96,5 @@
 and cc the people listed in OWNERS; they'll be on the hook to rebuild and
 re-enable the test.
 
-CLANG_REVISION = '318667'
-LASTCHANGE=d182c05f302ad2e7dddca9dba88a453913a3a8c6-refs/heads/master@{#525631}
+CLANG_REVISION = '317263'
+LASTCHANGE=9bbd081d6401276e8173cf0e33b9f93cba1c1b01-refs/heads/master@{#517774}
diff --git a/tools/traffic_annotation/bin/linux64/traffic_annotation_auditor.sha1 b/tools/traffic_annotation/bin/linux64/traffic_annotation_auditor.sha1
index 8489ab7..a2ccbd7 100644
--- a/tools/traffic_annotation/bin/linux64/traffic_annotation_auditor.sha1
+++ b/tools/traffic_annotation/bin/linux64/traffic_annotation_auditor.sha1
@@ -1 +1 @@
-d301c9e7449eea6cb1d347d0cdef599515fea344
\ No newline at end of file
+72ab0535dfab803324e56f2942a6695f1c1cae70
\ No newline at end of file
diff --git a/tools/traffic_annotation/scripts/check_annotations.py b/tools/traffic_annotation/scripts/check_annotations.py
index 9c93fca..9b2d042 100755
--- a/tools/traffic_annotation/scripts/check_annotations.py
+++ b/tools/traffic_annotation/scripts/check_annotations.py
@@ -17,8 +17,12 @@
 # If this test starts failing, please set TEST_IS_ENABLED to "False" and file a
 # bug to get this reenabled, and cc the people listed in
 # //tools/traffic_annotation/OWNERS.
-TEST_IS_ENABLED = sys.platform != 'win32'
 
+# TODO(crbug.com/788035) - this test currently takes up to 20 minutes to
+# execute even on linux_chromium_rel_ng; we need to figure out how to make
+# it be much faster before enabling it anywhere in the CQ.
+# TEST_IS_ENABLED = sys.platform != 'win32'
+TEST_IS_ENABLED = False
 
 
 class NetworkTrafficAnnotationChecker():
diff --git a/ui/android/event_forwarder.cc b/ui/android/event_forwarder.cc
index be38432..dd63f7b 100644
--- a/ui/android/event_forwarder.cc
+++ b/ui/android/event_forwarder.cc
@@ -8,6 +8,7 @@
 #include "base/metrics/histogram_macros.h"
 #include "jni/EventForwarder_jni.h"
 #include "ui/android/view_android.h"
+#include "ui/android/window_android.h"
 #include "ui/base/ui_base_switches_util.h"
 #include "ui/events/android/drag_event_android.h"
 #include "ui/events/android/gesture_event_android.h"
@@ -40,6 +41,12 @@
   return ScopedJavaLocalRef<jobject>(java_obj_);
 }
 
+ScopedJavaLocalRef<jobject> EventForwarder::GetJavaWindowAndroid(
+    JNIEnv* env,
+    const JavaParamRef<jobject>& obj) {
+  return view_->GetWindowAndroid()->GetJavaObject();
+}
+
 jboolean EventForwarder::OnTouchEvent(JNIEnv* env,
                                       const JavaParamRef<jobject>& obj,
                                       const JavaParamRef<jobject>& motion_event,
diff --git a/ui/android/event_forwarder.h b/ui/android/event_forwarder.h
index f2604aa..5081190 100644
--- a/ui/android/event_forwarder.h
+++ b/ui/android/event_forwarder.h
@@ -15,6 +15,10 @@
  public:
   ~EventForwarder();
 
+  base::android::ScopedJavaLocalRef<jobject> GetJavaWindowAndroid(
+      JNIEnv* env,
+      const base::android::JavaParamRef<jobject>& obj);
+
   jboolean OnTouchEvent(
       JNIEnv* env,
       const base::android::JavaParamRef<jobject>& obj,
diff --git a/ui/android/java/src/org/chromium/ui/base/EventForwarder.java b/ui/android/java/src/org/chromium/ui/base/EventForwarder.java
index db24a0e..35925e4 100644
--- a/ui/android/java/src/org/chromium/ui/base/EventForwarder.java
+++ b/ui/android/java/src/org/chromium/ui/base/EventForwarder.java
@@ -46,6 +46,12 @@
         mNativeEventForwarder = 0;
     }
 
+    // Returns the scaling being applied to the event's source. Typically only used for VR when
+    // drawing Android UI to a texture.
+    private float getEventSourceScaling() {
+        return nativeGetJavaWindowAndroid(mNativeEventForwarder).getDisplay().getAndroidUIScaling();
+    }
+
     /**
      * @see View#onTouchEvent(MotionEvent)
      */
@@ -120,16 +126,21 @@
                 }
             }
 
+            float secondPointerX = pointerCount > 1 ? event.getX(1) : 0;
+            float secondPointerY = pointerCount > 1 ? event.getY(1) : 0;
+
+            float scale = getEventSourceScaling();
+
             final boolean consumed = nativeOnTouchEvent(mNativeEventForwarder, event,
                     oldestEventTime, eventAction, pointerCount, event.getHistorySize(),
-                    event.getActionIndex(), event.getX(), event.getY(),
-                    pointerCount > 1 ? event.getX(1) : 0, pointerCount > 1 ? event.getY(1) : 0,
-                    event.getPointerId(0), pointerCount > 1 ? event.getPointerId(1) : -1,
-                    touchMajor[0], touchMajor[1], touchMinor[0], touchMinor[1],
+                    event.getActionIndex(), event.getX() / scale, event.getY() / scale,
+                    secondPointerX / scale, secondPointerY / scale, event.getPointerId(0),
+                    pointerCount > 1 ? event.getPointerId(1) : -1, touchMajor[0] / scale,
+                    touchMajor[1] / scale, touchMinor[0] / scale, touchMinor[1] / scale,
                     event.getOrientation(), pointerCount > 1 ? event.getOrientation(1) : 0,
                     event.getAxisValue(MotionEvent.AXIS_TILT),
                     pointerCount > 1 ? event.getAxisValue(MotionEvent.AXIS_TILT, 1) : 0,
-                    event.getRawX(), event.getRawY(), event.getToolType(0),
+                    event.getRawX() / scale, event.getRawY() / scale, event.getToolType(0),
                     pointerCount > 1 ? event.getToolType(1) : MotionEvent.TOOL_TYPE_UNKNOWN,
                     event.getButtonState(), event.getMetaState(), isTouchHandleEvent);
 
@@ -215,9 +226,10 @@
             // behaving device, so mLastMouseButtonState is only nonzero on a buggy one.
             if (eventAction == MotionEvent.ACTION_HOVER_ENTER) {
                 if (mLastMouseButtonState == MotionEvent.BUTTON_PRIMARY) {
+                    float scale = getEventSourceScaling();
                     nativeOnMouseEvent(mNativeEventForwarder, event.getEventTime(),
-                            MotionEvent.ACTION_BUTTON_RELEASE, offsetEvent.getX(),
-                            offsetEvent.getY(), event.getPointerId(0), event.getPressure(0),
+                            MotionEvent.ACTION_BUTTON_RELEASE, offsetEvent.getX() / scale,
+                            offsetEvent.getY() / scale, event.getPointerId(0), event.getPressure(0),
                             event.getOrientation(0), event.getAxisValue(MotionEvent.AXIS_TILT, 0),
                             MotionEvent.BUTTON_PRIMARY, event.getButtonState(),
                             event.getMetaState(), event.getToolType(0));
@@ -243,8 +255,10 @@
                 return true;
             }
 
+            float scale = getEventSourceScaling();
+
             nativeOnMouseEvent(mNativeEventForwarder, event.getEventTime(), eventAction,
-                    offsetEvent.getX(), offsetEvent.getY(), event.getPointerId(0),
+                    offsetEvent.getX() / scale, offsetEvent.getY() / scale, event.getPointerId(0),
                     event.getPressure(0), event.getOrientation(0),
                     event.getAxisValue(MotionEvent.AXIS_TILT, 0), getMouseEventActionButton(event),
                     event.getButtonState(), event.getMetaState(), event.getToolType(0));
@@ -265,7 +279,9 @@
     public boolean onMouseWheelEvent(
             long timeMs, float x, float y, float ticksX, float ticksY, float pixelsPerTick) {
         assert mNativeEventForwarder != 0;
-        nativeOnMouseWheelEvent(mNativeEventForwarder, timeMs, x, y, ticksX, ticksY, pixelsPerTick);
+        float scale = getEventSourceScaling();
+        nativeOnMouseWheelEvent(
+                mNativeEventForwarder, timeMs, x / scale, y / scale, ticksX, ticksY, pixelsPerTick);
         return true;
     }
 
@@ -312,8 +328,11 @@
         int screenX = x + locationOnScreen[0];
         int screenY = y + locationOnScreen[1];
 
-        nativeOnDragEvent(mNativeEventForwarder, event.getAction(), x, y, screenX, screenY,
-                mimeTypes, content.toString());
+        float scale = getEventSourceScaling();
+
+        nativeOnDragEvent(mNativeEventForwarder, event.getAction(), (int) (x / scale),
+                (int) (y / scale), (int) (screenX / scale), (int) (screenY / scale), mimeTypes,
+                content.toString());
         return true;
     }
 
@@ -330,6 +349,7 @@
         return nativeOnGestureEvent(mNativeEventForwarder, type, timeMs, delta);
     }
 
+    private native WindowAndroid nativeGetJavaWindowAndroid(long nativeEventForwarder);
     // All touch events (including flings, scrolls etc) accept coordinates in physical pixels.
     private native boolean nativeOnTouchEvent(long nativeEventForwarder, MotionEvent event,
             long timeMs, int action, int pointerCount, int historySize, int actionIndex, float x0,
diff --git a/ui/android/java/src/org/chromium/ui/display/DisplayAndroid.java b/ui/android/java/src/org/chromium/ui/display/DisplayAndroid.java
index 28a6082..4ea7379 100644
--- a/ui/android/java/src/org/chromium/ui/display/DisplayAndroid.java
+++ b/ui/android/java/src/org/chromium/ui/display/DisplayAndroid.java
@@ -133,6 +133,26 @@
     }
 
     /**
+     * You probably do not want to use this function.
+     *
+     * In VR, there's a mismatch between the dip scale reported by getDipScale and the dip scale
+     * Android UI is rendered with (in order for VR to control the size of the WebContents).
+     * This means that Android UI may need to be scaled when it's drawn to a texture in VR, which
+     * means that values in units of pixels (like input event locations) also need to be scaled
+     * when being passed to WebContents (and vice versa).
+     *
+     * This function should only be used on the boundaries between Android UI and the rest of Chrome
+     * when doing things like scaling sizes/positions.
+     *
+     * Note: This function is not available through the native display::Display.
+     *
+     * @return The scaling factor of Android UI in this display.
+     */
+    public float getAndroidUIScaling() {
+        return 1.0f;
+    }
+
+    /**
      * @return Number of bits per pixel.
      */
     /* package */ int getBitsPerPixel() {
diff --git a/ui/android/java/src/org/chromium/ui/display/VirtualDisplayAndroid.java b/ui/android/java/src/org/chromium/ui/display/VirtualDisplayAndroid.java
index 740087de..a5d4635 100644
--- a/ui/android/java/src/org/chromium/ui/display/VirtualDisplayAndroid.java
+++ b/ui/android/java/src/org/chromium/ui/display/VirtualDisplayAndroid.java
@@ -10,6 +10,8 @@
  * An instance of DisplayAndroid not associated with any physical display.
  */
 public class VirtualDisplayAndroid extends DisplayAndroid {
+    private float mAndroidUiScalingFactor = 1.0f;
+
     public static VirtualDisplayAndroid createVirtualDisplay() {
         return getManager().addVirtualDisplay();
     }
@@ -25,14 +27,22 @@
         update(new Point(other.getDisplayWidth(), other.getDisplayHeight()), other.getDipScale(),
                 other.getBitsPerPixel(), other.getBitsPerComponent(), other.getRotation(),
                 other.mIsDisplayWideColorGamut, other.mIsDisplayServerWideColorGamut);
+        mAndroidUiScalingFactor = other.getAndroidUIScaling();
+    }
+
+    public void update(Point size, Float dipScale, Float androidUiScalingFactor,
+            Integer bitsPerPixel, Integer bitsPerComponent, Integer rotation,
+            Boolean isDisplayWideColorGamut, Boolean isDisplayServerWideColorGamut) {
+        super.update(size, dipScale, bitsPerPixel, bitsPerComponent, rotation,
+                isDisplayWideColorGamut, isDisplayServerWideColorGamut);
+        if (androidUiScalingFactor != null) {
+            mAndroidUiScalingFactor = androidUiScalingFactor;
+        }
     }
 
     @Override
-    public void update(Point size, Float dipScale, Integer bitsPerPixel, Integer bitsPerComponent,
-            Integer rotation, Boolean isDisplayWideColorGamut,
-            Boolean isDisplayServerWideColorGamut) {
-        super.update(size, dipScale, bitsPerPixel, bitsPerComponent, rotation,
-                isDisplayWideColorGamut, isDisplayServerWideColorGamut);
+    public float getAndroidUIScaling() {
+        return mAndroidUiScalingFactor;
     }
 
     /**
diff --git a/ui/app_list/BUILD.gn b/ui/app_list/BUILD.gn
index 0499533..97811769 100644
--- a/ui/app_list/BUILD.gn
+++ b/ui/app_list/BUILD.gn
@@ -158,6 +158,7 @@
   deps = [
     ":app_list",
     "//base",
+    "//ui/base:base",
     "//ui/events",
     "//ui/gfx",
     "//ui/gfx/geometry",
diff --git a/ui/app_list/app_list_view_delegate.h b/ui/app_list/app_list_view_delegate.h
index 1a90a78..4b03dff2 100644
--- a/ui/app_list/app_list_view_delegate.h
+++ b/ui/app_list/app_list_view_delegate.h
@@ -5,6 +5,7 @@
 #ifndef UI_APP_LIST_APP_LIST_VIEW_DELEGATE_H_
 #define UI_APP_LIST_APP_LIST_VIEW_DELEGATE_H_
 
+#include <string>
 #include <vector>
 
 #include "base/strings/string16.h"
@@ -20,6 +21,10 @@
 class View;
 }
 
+namespace ui {
+class MenuModel;
+}
+
 namespace app_list {
 
 class AppListModel;
@@ -83,6 +88,14 @@
   // Gets the wallpaper prominent colors.
   virtual void GetWallpaperProminentColors(std::vector<SkColor>* colors) = 0;
 
+  // Activates (opens) the item.
+  virtual void ActivateItem(const std::string& id, int event_flags) = 0;
+
+  // Returns the context menu model for this item, or NULL if there is currently
+  // no menu for the item (e.g. during install).
+  // Note the returned menu model is owned by this item.
+  virtual ui::MenuModel* GetContextMenuModel(const std::string& id) = 0;
+
   // Add/remove observer for AppListViewDelegate.
   virtual void AddObserver(AppListViewDelegateObserver* observer) = 0;
   virtual void RemoveObserver(AppListViewDelegateObserver* observer) = 0;
diff --git a/ui/app_list/test/app_list_test_model.cc b/ui/app_list/test/app_list_test_model.cc
index 024f90c..401d43a 100644
--- a/ui/app_list/test/app_list_test_model.cc
+++ b/ui/app_list/test/app_list_test_model.cc
@@ -13,6 +13,7 @@
 #include "base/strings/stringprintf.h"
 #include "third_party/skia/include/core/SkBitmap.h"
 #include "ui/app_list/app_list_constants.h"
+#include "ui/base/models/menu_model.h"
 #include "ui/gfx/image/image_skia.h"
 
 namespace app_list {
@@ -45,6 +46,10 @@
   model_->ItemActivated(this);
 }
 
+ui::MenuModel* AppListTestModel::AppListTestItem::GetContextMenuModel() {
+  return nullptr;
+}
+
 const char* AppListTestModel::AppListTestItem::GetItemType() const {
   return AppListTestModel::kItemType;
 }
diff --git a/ui/app_list/test/app_list_test_model.h b/ui/app_list/test/app_list_test_model.h
index e10b8a4..d809617 100644
--- a/ui/app_list/test/app_list_test_model.h
+++ b/ui/app_list/test/app_list_test_model.h
@@ -12,6 +12,10 @@
 #include "ash/app_list/model/app_list_model.h"
 #include "base/macros.h"
 
+namespace ui {
+class MenuModel;
+}  // namespace ui
+
 namespace app_list {
 
 namespace test {
@@ -23,7 +27,8 @@
    public:
     AppListTestItem(const std::string& id, AppListTestModel* model);
     ~AppListTestItem() override;
-    void Activate(int event_flags) override;
+    void Activate(int event_flags);
+    ui::MenuModel* GetContextMenuModel();
     const char* GetItemType() const override;
 
     void SetPosition(const syncer::StringOrdinal& new_position);
diff --git a/ui/app_list/test/app_list_test_view_delegate.cc b/ui/app_list/test/app_list_test_view_delegate.cc
index 94e46f0..37c723f 100644
--- a/ui/app_list/test/app_list_test_view_delegate.cc
+++ b/ui/app_list/test/app_list_test_view_delegate.cc
@@ -80,5 +80,24 @@
   search_model_->SetSearchEngineIsGoogle(is_google);
 }
 
+void AppListTestViewDelegate::ActivateItem(const std::string& id,
+                                           int event_flags) {
+  app_list::AppListItem* item = model_->FindItem(id);
+  if (!item)
+    return;
+  DCHECK(!item->is_folder());
+  static_cast<AppListTestModel::AppListTestItem*>(item)->Activate(event_flags);
+}
+
+ui::MenuModel* AppListTestViewDelegate::GetContextMenuModel(
+    const std::string& id) {
+  app_list::AppListItem* item = model_->FindItem(id);
+  // TODO(stevenjb/jennyz): Implement this for folder items
+  if (!item || item->is_folder())
+    return nullptr;
+  return static_cast<AppListTestModel::AppListTestItem*>(item)
+      ->GetContextMenuModel();
+}
+
 }  // namespace test
 }  // namespace app_list
diff --git a/ui/app_list/test/app_list_test_view_delegate.h b/ui/app_list/test/app_list_test_view_delegate.h
index 296daaf..89b47b65 100644
--- a/ui/app_list/test/app_list_test_view_delegate.h
+++ b/ui/app_list/test/app_list_test_view_delegate.h
@@ -66,6 +66,8 @@
   views::View* CreateStartPageWebView(const gfx::Size& size) override;
   bool IsSpeechRecognitionEnabled() override;
   void GetWallpaperProminentColors(std::vector<SkColor>* colors) override {}
+  void ActivateItem(const std::string& id, int event_flags) override;
+  ui::MenuModel* GetContextMenuModel(const std::string& id) override;
   void AddObserver(app_list::AppListViewDelegateObserver* observer) override {}
   void RemoveObserver(
       app_list::AppListViewDelegateObserver* observer) override {}
diff --git a/ui/app_list/views/app_list_item_view.cc b/ui/app_list/views/app_list_item_view.cc
index d39aa87a..07bb446 100644
--- a/ui/app_list/views/app_list_item_view.cc
+++ b/ui/app_list/views/app_list_item_view.cc
@@ -13,6 +13,7 @@
 #include "ui/accessibility/ax_node_data.h"
 #include "ui/app_list/app_list_constants.h"
 #include "ui/app_list/app_list_switches.h"
+#include "ui/app_list/app_list_view_delegate.h"
 #include "ui/app_list/views/apps_grid_view.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/resource/resource_bundle.h"
@@ -56,11 +57,13 @@
 const char AppListItemView::kViewClassName[] = "ui/app_list/AppListItemView";
 
 AppListItemView::AppListItemView(AppsGridView* apps_grid_view,
-                                 AppListItem* item)
+                                 AppListItem* item,
+                                 AppListViewDelegate* delegate)
     : Button(apps_grid_view),
       is_folder_(item->GetItemType() == AppListFolderItem::kItemType),
       is_in_folder_(item->IsInFolder()),
       item_weak_(item),
+      delegate_(delegate),
       apps_grid_view_(apps_grid_view),
       icon_(new views::ImageView),
       title_(new views::Label),
@@ -268,8 +271,7 @@
   if (context_menu_runner_ && context_menu_runner_->IsRunning())
     return;
 
-  ui::MenuModel* menu_model =
-      item_weak_ ? item_weak_->GetContextMenuModel() : NULL;
+  ui::MenuModel* menu_model = delegate_->GetContextMenuModel(item_weak_->id());
   if (!menu_model)
     return;
 
diff --git a/ui/app_list/views/app_list_item_view.h b/ui/app_list/views/app_list_item_view.h
index 6f39764..0df667b 100644
--- a/ui/app_list/views/app_list_item_view.h
+++ b/ui/app_list/views/app_list_item_view.h
@@ -28,6 +28,7 @@
 namespace app_list {
 
 class AppListItem;
+class AppListViewDelegate;
 class AppsGridView;
 
 class APP_LIST_EXPORT AppListItemView : public views::Button,
@@ -38,7 +39,9 @@
   // Internal class name.
   static const char kViewClassName[];
 
-  AppListItemView(AppsGridView* apps_grid_view, AppListItem* item);
+  AppListItemView(AppsGridView* apps_grid_view,
+                  AppListItem* item,
+                  AppListViewDelegate* delegate);
   ~AppListItemView() override;
 
   // Set the icon of this image, adding a drop shadow if |has_shadow|.
@@ -158,6 +161,7 @@
 
   AppListItem* item_weak_;  // Owned by AppListModel. Can be NULL.
 
+  AppListViewDelegate* delegate_;     // Unowned.
   AppsGridView* apps_grid_view_;      // Parent view, owns this.
   views::ImageView* icon_;            // Strongly typed child view.
   views::Label* title_;               // Strongly typed child view.
diff --git a/ui/app_list/views/app_list_main_view.cc b/ui/app_list/views/app_list_main_view.cc
index fd86c0d9..26a531b 100644
--- a/ui/app_list/views/app_list_main_view.cc
+++ b/ui/app_list/views/app_list_main_view.cc
@@ -145,7 +145,7 @@
                               kMaxFolderOpened);
   } else {
     base::RecordAction(base::UserMetricsAction("AppList_ClickOnApp"));
-    item->Activate(event_flags);
+    delegate_->ActivateItem(item->id(), event_flags);
     UMA_HISTOGRAM_BOOLEAN(features::IsFullscreenAppListEnabled()
                               ? kAppListAppLaunchedFullscreen
                               : kAppListAppLaunched,
diff --git a/ui/app_list/views/apps_grid_view.cc b/ui/app_list/views/apps_grid_view.cc
index e82ca79f..a573c65 100644
--- a/ui/app_list/views/apps_grid_view.cc
+++ b/ui/app_list/views/apps_grid_view.cc
@@ -785,7 +785,9 @@
 
   // Create a new AppListItemView to duplicate the original_drag_view in the
   // folder's grid view.
-  AppListItemView* view = new AppListItemView(this, original_drag_view->item());
+  AppListItemView* view = new AppListItemView(
+      this, original_drag_view->item(),
+      contents_view_->app_list_main_view()->view_delegate());
   AddChildView(view);
   drag_view_ = view;
   drag_view_->SetPaintToLayer();
@@ -1125,7 +1127,9 @@
   // The drag_view_ might be pending for deletion, therefore view_model_
   // may have one more item than item_list_.
   DCHECK_LE(index, item_list_->item_count());
-  AppListItemView* view = new AppListItemView(this, item_list_->item_at(index));
+  AppListItemView* view = new AppListItemView(
+      this, item_list_->item_at(index),
+      contents_view_->app_list_main_view()->view_delegate());
   view->SetPaintToLayer();
   view->layer()->SetFillsBoundsOpaquely(false);
   return view;
diff --git a/ui/gfx/x/OWNERS b/ui/gfx/x/OWNERS
index fd5ad4bf..1b19a9d3 100644
--- a/ui/gfx/x/OWNERS
+++ b/ui/gfx/x/OWNERS
@@ -1,3 +1,6 @@
 derat@chromium.org
 
+# Adding new atoms is allowed without OWNERS review.
+per-file x11_atom_cache.cc=*
+
 # COMPONENT: UI>GFX
diff --git a/ui/gfx/x/x11_atom_cache.cc b/ui/gfx/x/x11_atom_cache.cc
index 1b1d333..3447421d 100644
--- a/ui/gfx/x/x11_atom_cache.cc
+++ b/ui/gfx/x/x11_atom_cache.cc
@@ -155,6 +155,7 @@
     "_NETSCAPE_URL",
     "_NET_SUPPORTED",
     "_NET_SUPPORTING_WM_CHECK",
+    "_NET_WM_BYPASS_COMPOSITOR",
     "_NET_WM_CM_S0",
     "_NET_WM_DESKTOP",
     "_NET_WM_ICON",
diff --git a/ui/views/controls/tree/tree_view.cc b/ui/views/controls/tree/tree_view.cc
index ed567ca..04fb709 100644
--- a/ui/views/controls/tree/tree_view.cc
+++ b/ui/views/controls/tree/tree_view.cc
@@ -28,6 +28,7 @@
 #include "ui/gfx/skia_util.h"
 #include "ui/native_theme/native_theme.h"
 #include "ui/resources/grit/ui_resources.h"
+#include "ui/views/border.h"
 #include "ui/views/controls/focus_ring.h"
 #include "ui/views/controls/prefix_selector.h"
 #include "ui/views/controls/scroll_view.h"
@@ -51,7 +52,6 @@
 // Padding around the text (on each side).
 static const int kTextVerticalPadding = 3;
 static const int kTextHorizontalPadding = 2;
-static const int kTextHorizontalPaddingWithFocusRing = 4;
 // How much children are indented from their parent.
 static const int kIndent = 20;
 
@@ -104,16 +104,6 @@
   }
   text_offset_ = closed_icon_.width() + kImagePadding + kImagePadding +
       kArrowRegionSize;
-
-  // The horizontal padding will be needed before an editor text field is ever
-  // constructed, otherwise it would be nice to use editor_->uses_focus_ring()
-  // or similar. Since Textfields only use focus rings when
-  // IsSecondaryUiMaterial() and when they have no border, checking that here
-  // is safe.
-  text_horizontal_padding_ =
-      ui::MaterialDesignController::IsSecondaryUiMaterial()
-          ? kTextHorizontalPaddingWithFocusRing
-          : kTextHorizontalPadding;
 }
 
 TreeView::~TreeView() {
@@ -186,6 +176,7 @@
   editing_ = true;
   if (!editor_) {
     editor_ = new Textfield;
+    editor_->SetBorder(views::CreateSolidBorder(1, gfx::kGoogleBlue700));
     // Add the editor immediately as GetPreferredSize returns the wrong thing if
     // not parented.
     AddChildView(editor_);
@@ -724,7 +715,7 @@
 
   preferred_size_.SetSize(
       root_.GetMaxWidth(this, text_offset_, root_shown_ ? 1 : 0) +
-          text_horizontal_padding_ * 2,
+          kTextHorizontalPadding * 2,
       row_height_ * GetRowCount());
 }
 
@@ -739,7 +730,7 @@
       GetMirroredXWithWidthInView(row_bounds.x(), row_bounds.width()));
   row_bounds.set_x(row_bounds.x() + text_offset_);
   row_bounds.set_width(row_bounds.width() - text_offset_);
-  row_bounds.Inset(text_horizontal_padding_, kTextVerticalPadding);
+  row_bounds.Inset(kTextHorizontalPadding, kTextVerticalPadding);
   row_bounds.Inset(-empty_editor_size_.width() / 2,
                    -(empty_editor_size_.height() - font_list_.GetHeight()) / 2);
   // Give a little extra space for editing.
@@ -828,9 +819,9 @@
 
   // Paint the text.
   const gfx::Rect internal_bounds(
-      text_bounds.x() + text_horizontal_padding_,
+      text_bounds.x() + kTextHorizontalPadding,
       text_bounds.y() + kTextVerticalPadding,
-      text_bounds.width() - text_horizontal_padding_ * 2,
+      text_bounds.width() - kTextHorizontalPadding * 2,
       text_bounds.height() - kTextVerticalPadding * 2);
   canvas->DrawStringRect(
       node->model_node()->GetTitle(), font_list_,
@@ -931,15 +922,14 @@
 // leading aligned.
 gfx::Rect TreeView::GetAuxiliaryTextBoundsForNode(InternalNode* node) {
   gfx::Rect text_bounds = GetTextBoundsForNode(node);
-  int width = base::i18n::IsRTL()
-                  ? text_bounds.x() - text_horizontal_padding_ * 2
-                  : bounds().width() - text_bounds.right() -
-                        2 * text_horizontal_padding_;
+  int width = base::i18n::IsRTL() ? text_bounds.x() - kTextHorizontalPadding * 2
+                                  : bounds().width() - text_bounds.right() -
+                                        2 * kTextHorizontalPadding;
   if (width < 0)
     return gfx::Rect();
   int x = base::i18n::IsRTL()
-              ? text_horizontal_padding_
-              : bounds().right() - width - text_horizontal_padding_;
+              ? kTextHorizontalPadding
+              : bounds().right() - width - kTextHorizontalPadding;
   return gfx::Rect(x, text_bounds.y(), width, text_bounds.height());
 }
 
@@ -948,9 +938,8 @@
                                                    int depth) {
   int width =
       drawing_provider()->ShouldDrawIconForNode(this, node->model_node())
-          ? text_offset_ + node->text_width() + text_horizontal_padding_ * 2
-          : kArrowRegionSize + node->text_width() +
-                text_horizontal_padding_ * 2;
+          ? text_offset_ + node->text_width() + kTextHorizontalPadding * 2
+          : kArrowRegionSize + node->text_width() + kTextHorizontalPadding * 2;
 
   gfx::Rect rect(depth * kIndent + kHorizontalInset, row * row_height_, width,
                  row_height_);
diff --git a/ui/views/controls/tree/tree_view.h b/ui/views/controls/tree/tree_view.h
index bc7fde5..2ab62a6b 100644
--- a/ui/views/controls/tree/tree_view.h
+++ b/ui/views/controls/tree/tree_view.h
@@ -429,9 +429,6 @@
   // control, icon and offsets.
   int text_offset_;
 
-  // Horizontal padding around the text on both sides.
-  int text_horizontal_padding_ = 0;
-
   std::unique_ptr<PrefixSelector> selector_;
 
   // The current drawing provider for this TreeView.
diff --git a/ui/views/widget/desktop_aura/desktop_window_tree_host_x11.cc b/ui/views/widget/desktop_aura/desktop_window_tree_host_x11.cc
index 15c966c..7e32aed 100644
--- a/ui/views/widget/desktop_aura/desktop_window_tree_host_x11.cc
+++ b/ui/views/widget/desktop_aura/desktop_window_tree_host_x11.cc
@@ -1518,6 +1518,11 @@
                     kDarkGtkThemeVariant, arraysize(kDarkGtkThemeVariant) - 1);
   }
 
+  // Always composite Chromium windows if a compositing WM is used.  Sometimes,
+  // WMs will not composite fullscreen windows as an optimization, but this can
+  // lead to tearing of fullscreen videos.
+  ui::SetIntProperty(xwindow_, "_NET_WM_BYPASS_COMPOSITOR", "CARDINAL", 2);
+
   // If we have a parent, record the parent/child relationship. We use this
   // data during destruction to make sure that when we try to close a parent
   // window, we also destroy all child windows.