diff --git a/.gitignore b/.gitignore
index 98d23f96..5ba7c07 100644
--- a/.gitignore
+++ b/.gitignore
@@ -188,6 +188,7 @@
 /ios/third_party/material_text_accessibility_ios/src
 /ios/third_party/motion_animator_objc/src
 /ios/third_party/motion_interchange_objc/src
+/ios/third_party/motion_transitioning_objc/src
 /ios/third_party/ochamcrest/src
 /ios_internal
 /libassistant
diff --git a/DEPS b/DEPS
index db3d51a..2148c4d 100644
--- a/DEPS
+++ b/DEPS
@@ -74,19 +74,19 @@
   # 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': 'cad08c855e2373df3f0c53e943bad29dbd371d9c',
+  'skia_revision': '5031e5f8b77f9fedf7f0d662a0228bf423bcef71',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling V8
   # and whatever else without interference from each other.
-  'v8_revision': 'ee13fe4bd16f72be2e81fd11523a238903975e4d',
+  'v8_revision': 'b463eed75e8129843643189c0d08b3f9536faf66',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling swarming_client
   # and whatever else without interference from each other.
-  'swarming_revision': '6fd3c7b6eb7c60f89e83f8ab1f93c133488f984e',
+  'swarming_revision': '4bd9152f8a975d57c972c071dfb4ddf668e02200',
   # 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': '10a4d43462fa72c6b104a23a6958a0b82fd443be',
+  'angle_revision': '030017a4855c7b6e7f2ff8d9566c146f31eb301b',
   # 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.
@@ -98,7 +98,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': '4bd2ad8cf901134cabae0c56524a05a542c118fd',
+  'pdfium_revision': '7b0be4ced5f3687e922fc9ed11a4c49fe9848221',
   # 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.
@@ -130,7 +130,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling catapult
   # and whatever else without interference from each other.
-  'catapult_revision': '307c9f954dc52f4bbce5b8a5e9ce40ff2ac0451d',
+  'catapult_revision': 'db654910e39e4d8866a4eaf93167a24a41ceacdf',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libFuzzer
   # and whatever else without interference from each other.
@@ -232,6 +232,11 @@
       'condition': 'checkout_ios',
   },
 
+  'src/ios/third_party/motion_transitioning_objc/src': {
+      'url': Var('chromium_git') + '/external/github.com/material-motion/motion-transitioning-objc.git' + '@' + '994fd02d1de3d80ed284f0c1a4b5f459b8b051a6',
+      'condition': 'checkout_ios',
+  },
+
   'src/ios/third_party/ochamcrest/src': {
       'url': Var('chromium_git') + '/external/github.com/hamcrest/OCHamcrest.git' + '@' + '92d9c14d13bb864255e65c09383564653896916b',
       'condition': 'checkout_ios',
@@ -308,7 +313,7 @@
 
   # For Linux and Chromium OS.
   'src/third_party/cros_system_api': {
-      'url': Var('chromium_git') + '/chromiumos/platform/system_api.git' + '@' + 'e494ee7de6e2c99ede5683f0f78e07909f1ba2ed',
+      'url': Var('chromium_git') + '/chromiumos/platform/system_api.git' + '@' + '304b21ef6d9182ebb812cde8f04db17b070bd858',
       'condition': 'checkout_linux',
   },
 
@@ -634,7 +639,7 @@
     Var('chromium_git') + '/external/khronosgroup/webgl.git' + '@' + '05591bbeae6592fd924caec8e728a4ea86cbb8c9',
 
   'src/third_party/webrtc':
-    Var('webrtc_git') + '/src.git' + '@' + 'c3da1e61bccf4c6a37e871f5202f937ace78898a', # commit position 20628
+    Var('webrtc_git') + '/src.git' + '@' + '40f0b37d3b9ad17fa19ddb27a7903990e355f0a8', # commit position 20628
 
   'src/third_party/xdg-utils': {
       'url': Var('chromium_git') + '/chromium/deps/xdg-utils.git' + '@' + 'd80274d5869b17b8c9067a1022e4416ee7ed5e0d',
diff --git a/WATCHLISTS b/WATCHLISTS
index fcbd1bc..06f2280 100644
--- a/WATCHLISTS
+++ b/WATCHLISTS
@@ -1609,6 +1609,7 @@
                       'dougt+watch@chromium.org',
                       'dtseng+watch@chromium.org',
                       'je_julie.kim@chromium.org',
+                      'katie+watch@chromium.org',
                       'nektar+watch@chromium.org',
                       'yuzo+watch@chromium.org'],
     'add_to_homescreen': ['dominickn+watch@chromium.org',
@@ -1694,6 +1695,7 @@
                             'dmazzoni@chromium.org',
                             'dougt+watch@chromium.org',
                             'je_julie.kim@chromium.org',
+                            'katie+watch@chromium.org',
                             'nektar@chromium.org'],
     'blink_animation': ['alexis.menard@intel.com',
                         'blink-reviews-animation@chromium.org',
diff --git a/android_webview/BUILD.gn b/android_webview/BUILD.gn
index eb82e9c..7c55671 100644
--- a/android_webview/BUILD.gn
+++ b/android_webview/BUILD.gn
@@ -681,6 +681,7 @@
     "//components/crash/content/app",
     "//components/crash/content/browser",
     "//components/google/core/browser",
+    "//components/keyed_service/content",
     "//components/metrics",
     "//components/metrics:gpu",
     "//components/metrics:net",
@@ -688,7 +689,9 @@
     "//components/navigation_interception",
     "//components/network_session_configurator/common",
     "//components/policy:generated",
+    "//components/policy/content/",
     "//components/policy/core/browser",
+    "//components/policy/core/common",
     "//components/prefs",
     "//components/printing/browser",
     "//components/printing/common",
@@ -944,7 +947,9 @@
 }
 
 android_library("android_webview_commandline_java") {
-  java_files = [ "java/src/org/chromium/android_webview/command_line/CommandLineUtil.java" ]
+  java_files = [
+    "java/src/org/chromium/android_webview/command_line/CommandLineUtil.java",
+  ]
 
   deps = [
     "//base:base_java",
diff --git a/android_webview/browser/DEPS b/android_webview/browser/DEPS
index 96eaa9b5..709f0d8b 100644
--- a/android_webview/browser/DEPS
+++ b/android_webview/browser/DEPS
@@ -18,6 +18,7 @@
   "+components/navigation_interception",
   "+components/policy/core/browser",
   "+components/policy/core/common",
+  "+components/policy/content",
   "+components/pref_registry",
   "+components/printing/browser",
   "+components/printing/common",
diff --git a/android_webview/browser/aw_browser_context.cc b/android_webview/browser/aw_browser_context.cc
index 34a4952..89c9844 100644
--- a/android_webview/browser/aw_browser_context.cc
+++ b/android_webview/browser/aw_browser_context.cc
@@ -86,24 +86,6 @@
   return config_service;
 }
 
-bool OverrideBlacklistForURL(const GURL& url, bool* block, int* reason) {
-  // We don't have URLs that should never be blacklisted here.
-  return false;
-}
-
-policy::URLBlacklistManager* CreateURLBlackListManager(
-    PrefService* pref_service) {
-  scoped_refptr<base::SequencedTaskRunner> background_task_runner =
-      base::CreateSequencedTaskRunnerWithTraits(
-          {base::MayBlock(), base::TaskPriority::BACKGROUND});
-  scoped_refptr<base::SingleThreadTaskRunner> io_task_runner =
-      BrowserThread::GetTaskRunnerForThread(BrowserThread::IO);
-
-  return new policy::URLBlacklistManager(pref_service, background_task_runner,
-                                         io_task_runner,
-                                         base::Bind(OverrideBlacklistForURL));
-}
-
 std::unique_ptr<AwSafeBrowsingWhitelistManager>
 CreateSafeBrowsingWhitelistManager() {
   // Should not be called until the end of PreMainMessageLoopRun,
@@ -174,8 +156,6 @@
 
   EnsureResourceContextInitialized(this);
 
-  blacklist_manager_.reset(CreateURLBlackListManager(user_pref_service_.get()));
-
   AwMetricsServiceClient::GetInstance()->Initialize(
       user_pref_service_.get(),
       content::BrowserContext::GetDefaultStoragePartition(this)
@@ -369,13 +349,6 @@
   return NULL;
 }
 
-policy::URLBlacklistManager* AwBrowserContext::GetURLBlacklistManager() {
-  // Should not be called until the end of PreMainMessageLoopRun, where
-  // blacklist_manager_ is initialized.
-  DCHECK(blacklist_manager_);
-  return blacklist_manager_.get();
-}
-
 web_restrictions::WebRestrictionsClient*
 AwBrowserContext::GetWebRestrictionProvider() {
   DCHECK(web_restriction_provider_);
diff --git a/android_webview/browser/aw_browser_context.h b/android_webview/browser/aw_browser_context.h
index 4e4b424..1b104c4 100644
--- a/android_webview/browser/aw_browser_context.h
+++ b/android_webview/browser/aw_browser_context.h
@@ -33,7 +33,6 @@
 }
 
 namespace policy {
-class URLBlacklistManager;
 class BrowserPolicyConnectorBase;
 }
 
@@ -85,7 +84,6 @@
   AwFormDatabaseService* GetFormDatabaseService();
   AwURLRequestContextGetter* GetAwURLRequestContext();
 
-  policy::URLBlacklistManager* GetURLBlacklistManager();
   web_restrictions::WebRestrictionsClient* GetWebRestrictionProvider();
 
   // content::BrowserContext implementation.
@@ -139,8 +137,6 @@
 
   std::unique_ptr<PrefService> user_pref_service_;
   std::unique_ptr<policy::BrowserPolicyConnectorBase> browser_policy_connector_;
-  std::unique_ptr<policy::URLBlacklistManager> blacklist_manager_;
-
   std::unique_ptr<AwSSLHostStateDelegate> ssl_host_state_delegate_;
   std::unique_ptr<content::PermissionManager> permission_manager_;
   std::unique_ptr<web_restrictions::WebRestrictionsClient>
diff --git a/android_webview/browser/aw_content_browser_client.cc b/android_webview/browser/aw_content_browser_client.cc
index a5a5673..b1f03bc8 100644
--- a/android_webview/browser/aw_content_browser_client.cc
+++ b/android_webview/browser/aw_content_browser_client.cc
@@ -41,6 +41,7 @@
 #include "components/cdm/browser/cdm_message_filter_android.h"
 #include "components/crash/content/browser/crash_dump_observer_android.h"
 #include "components/navigation_interception/intercept_navigation_delegate.h"
+#include "components/policy/content/policy_blacklist_navigation_throttle.h"
 #include "components/safe_browsing/browser/browser_url_loader_throttle.h"
 #include "components/safe_browsing/browser/mojo_safe_browsing_impl.h"
 #include "components/spellcheck/spellcheck_build_features.h"
@@ -517,6 +518,8 @@
     throttles.push_back(
         navigation_interception::InterceptNavigationDelegate::CreateThrottleFor(
             navigation_handle));
+    throttles.push_back(base::MakeUnique<PolicyBlacklistNavigationThrottle>(
+        navigation_handle, browser_context_.get()));
   }
   return throttles;
 }
diff --git a/android_webview/browser/aw_contents.cc b/android_webview/browser/aw_contents.cc
index 15f4d3a..4f65783 100644
--- a/android_webview/browser/aw_contents.cc
+++ b/android_webview/browser/aw_contents.cc
@@ -81,6 +81,7 @@
 #include "jni/AwContents_jni.h"
 #include "net/base/auth.h"
 #include "net/cert/x509_certificate.h"
+#include "net/cert/x509_util.h"
 #include "third_party/skia/include/core/SkPicture.h"
 #include "ui/gfx/android/java_bitmap.h"
 #include "ui/gfx/geometry/rect_f.h"
@@ -841,9 +842,8 @@
     return ScopedJavaLocalRef<jbyteArray>();
 
   // Convert the certificate and return it
-  std::string der_string;
-  net::X509Certificate::GetDEREncoded(
-      entry->GetSSL().certificate->os_cert_handle(), &der_string);
+  base::StringPiece der_string = net::x509_util::CryptoBufferAsStringPiece(
+      entry->GetSSL().certificate->cert_buffer());
   return base::android::ToJavaByteArray(
       env, reinterpret_cast<const uint8_t*>(der_string.data()),
       der_string.length());
diff --git a/android_webview/browser/aw_contents_client_bridge.cc b/android_webview/browser/aw_contents_client_bridge.cc
index 8c9d15f..8abb9c3 100644
--- a/android_webview/browser/aw_contents_client_bridge.cc
+++ b/android_webview/browser/aw_contents_client_bridge.cc
@@ -23,6 +23,7 @@
 #include "content/public/browser/web_contents.h"
 #include "jni/AwContentsClientBridge_jni.h"
 #include "net/cert/x509_certificate.h"
+#include "net/cert/x509_util.h"
 #include "net/http/http_response_headers.h"
 #include "net/ssl/ssl_cert_request_info.h"
 #include "net/ssl/ssl_client_cert_type.h"
@@ -137,8 +138,8 @@
   if (obj.is_null())
     return;
 
-  std::string der_string;
-  net::X509Certificate::GetDEREncoded(cert->os_cert_handle(), &der_string);
+  base::StringPiece der_string =
+      net::x509_util::CryptoBufferAsStringPiece(cert->cert_buffer());
   ScopedJavaLocalRef<jbyteArray> jcert = base::android::ToJavaByteArray(
       env, reinterpret_cast<const uint8_t*>(der_string.data()),
       der_string.length());
diff --git a/android_webview/browser/aw_metrics_service_client.cc b/android_webview/browser/aw_metrics_service_client.cc
index ef48c7c4..3ce165d4 100644
--- a/android_webview/browser/aw_metrics_service_client.cc
+++ b/android_webview/browser/aw_metrics_service_client.cc
@@ -196,12 +196,12 @@
   Java_AwMetricsServiceClient_nativeInitialized(env);
 }
 
-bool AwMetricsServiceClient::IsConsentGiven() {
+bool AwMetricsServiceClient::IsConsentGiven() const {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
   return consent_;
 }
 
-bool AwMetricsServiceClient::IsReportingEnabled() {
+bool AwMetricsServiceClient::IsReportingEnabled() const {
   return consent_ && in_sample_;
 }
 
diff --git a/android_webview/browser/aw_metrics_service_client.h b/android_webview/browser/aw_metrics_service_client.h
index 9dfb212..c2262da 100644
--- a/android_webview/browser/aw_metrics_service_client.h
+++ b/android_webview/browser/aw_metrics_service_client.h
@@ -54,8 +54,8 @@
                   net::URLRequestContextGetter* request_context);
 
   // metrics::EnabledStateProvider implementation
-  bool IsConsentGiven() override;
-  bool IsReportingEnabled() override;
+  bool IsConsentGiven() const override;
+  bool IsReportingEnabled() const override;
 
   // The below functions must not be called until initialization has
   // asynchronously finished.
diff --git a/android_webview/browser/net/aw_network_delegate.cc b/android_webview/browser/net/aw_network_delegate.cc
index 4474ef0..7faf749 100644
--- a/android_webview/browser/net/aw_network_delegate.cc
+++ b/android_webview/browser/net/aw_network_delegate.cc
@@ -10,7 +10,6 @@
 #include "android_webview/browser/aw_cookie_access_policy.h"
 #include "android_webview/browser/net/aw_web_resource_request.h"
 #include "base/android/build_info.h"
-#include "components/policy/core/browser/url_blacklist_manager.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/resource_request_info.h"
 #include "net/base/completion_callback.h"
@@ -42,25 +41,11 @@
 
 }  // namespace
 
-AwNetworkDelegate::AwNetworkDelegate() : url_blacklist_manager_(nullptr) {
-}
+AwNetworkDelegate::AwNetworkDelegate() {}
 
 AwNetworkDelegate::~AwNetworkDelegate() {
 }
 
-int AwNetworkDelegate::OnBeforeURLRequest(
-    net::URLRequest* request,
-    const net::CompletionCallback& callback,
-    GURL* new_url) {
-  if (!url_blacklist_manager_) {
-    url_blacklist_manager_ =
-        AwBrowserContext::GetDefault()->GetURLBlacklistManager();
-  }
-  if (url_blacklist_manager_->IsURLBlocked(request->url()))
-    return net::ERR_BLOCKED_BY_ADMINISTRATOR;
-  return net::OK;
-}
-
 int AwNetworkDelegate::OnBeforeStartTransaction(
     net::URLRequest* request,
     const net::CompletionCallback& callback,
diff --git a/android_webview/browser/net/aw_network_delegate.h b/android_webview/browser/net/aw_network_delegate.h
index a3f0d984..2ee2317 100644
--- a/android_webview/browser/net/aw_network_delegate.h
+++ b/android_webview/browser/net/aw_network_delegate.h
@@ -12,10 +12,6 @@
 class URLRequest;
 }
 
-namespace policy {
-class URLBlacklistManager;
-}
-
 namespace android_webview {
 
 // WebView's implementation of the NetworkDelegate.
@@ -26,9 +22,6 @@
 
  private:
   // NetworkDelegate implementation.
-  int OnBeforeURLRequest(net::URLRequest* request,
-                         const net::CompletionCallback& callback,
-                         GURL* new_url) override;
   int OnBeforeStartTransaction(net::URLRequest* request,
                                const net::CompletionCallback& callback,
                                net::HttpRequestHeaders* headers) override;
@@ -62,9 +55,6 @@
                        const base::FilePath& original_path,
                        const base::FilePath& absolute_path) const override;
 
-  // Used to filter URL requests. Owned by AwBrowserContext.
-  const policy::URLBlacklistManager* url_blacklist_manager_;
-
   DISALLOW_COPY_AND_ASSIGN(AwNetworkDelegate);
 };
 
diff --git a/android_webview/java/src/org/chromium/android_webview/AwAutofillProvider.java b/android_webview/java/src/org/chromium/android_webview/AwAutofillProvider.java
index 8204aca..06bf771 100644
--- a/android_webview/java/src/org/chromium/android_webview/AwAutofillProvider.java
+++ b/android_webview/java/src/org/chromium/android_webview/AwAutofillProvider.java
@@ -352,7 +352,6 @@
     @Override
     protected void setNativeAutofillProvider(long nativeAutofillProvider) {
         if (nativeAutofillProvider == mNativeAutofillProvider) return;
-        mNativeAutofillProvider = nativeAutofillProvider;
         // Setting the mNativeAutofillProvider to 0 may occur as a
         // result of WebView.destroy, or because a WebView has been
         // gc'ed. In the former case we can go ahead and clean up the
@@ -362,10 +361,9 @@
         // possible to know which case we're in, so just catch and
         // ignore the exception.
         try {
-            reset();
-            if (nativeAutofillProvider == 0) {
-                mAutofillManager.destroy();
-            }
+            if (mNativeAutofillProvider != 0) reset();
+            mNativeAutofillProvider = nativeAutofillProvider;
+            if (nativeAutofillProvider == 0) mAutofillManager.destroy();
         } catch (IllegalStateException e) {
         }
     }
@@ -373,8 +371,8 @@
     @Override
     public void setWebContents(WebContents webContents) {
         if (webContents == mWebContents) return;
+        if (mWebContents != null) reset();
         mWebContents = webContents;
-        reset();
     }
 
     @Override
diff --git a/android_webview/java/src/org/chromium/android_webview/AwContents.java b/android_webview/java/src/org/chromium/android_webview/AwContents.java
index d157663..b35fc15 100644
--- a/android_webview/java/src/org/chromium/android_webview/AwContents.java
+++ b/android_webview/java/src/org/chromium/android_webview/AwContents.java
@@ -3463,7 +3463,6 @@
             // update.
             mLayoutSizer.onSizeChanged(w, h, ow, oh);
             nativeOnSizeChanged(mNativeAwContents, w, h, ow, oh);
-            mContentViewCore.onSizeChanged(w, h, ow, oh);
         }
 
         @Override
diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/AwAutofillTest.java b/android_webview/javatests/src/org/chromium/android_webview/test/AwAutofillTest.java
index 05aac35..0c7cf09 100644
--- a/android_webview/javatests/src/org/chromium/android_webview/test/AwAutofillTest.java
+++ b/android_webview/javatests/src/org/chromium/android_webview/test/AwAutofillTest.java
@@ -538,9 +538,6 @@
             int cnt = 0;
             final String url = webServer.setResponse(FILE, data, null);
             loadUrlSync(url);
-            // Note that we cancel autofill in loading as a precautious measure.
-            cnt += waitForCallbackAndVerifyTypes(
-                    cnt, new Integer[] {AUTOFILL_CANCEL, AUTOFILL_CANCEL});
             DOMUtils.waitForNonZeroNodeBounds(mAwContents.getWebContents(), "text1");
             // Note that we currently depend on keyboard app's behavior.
             // TODO(changwan): mock out IME interaction.
@@ -586,9 +583,6 @@
             final String url = webServer.setResponse(FILE, data, null);
             loadUrlSync(url);
             executeJavaScriptAndWaitForResult("document.getElementById('text1').select();");
-            // Note that we cancel autofill in loading as a precautious measure.
-            cnt += waitForCallbackAndVerifyTypes(
-                    cnt, new Integer[] {AUTOFILL_CANCEL, AUTOFILL_CANCEL});
             dispatchDownAndUpKeyEvents(KeyEvent.KEYCODE_A);
             // Note that we currently call ENTER/EXIT one more time.
             cnt += waitForCallbackAndVerifyTypes(cnt,
@@ -703,10 +697,6 @@
             loadUrlSync(url);
             int cnt = 0;
             executeJavaScriptAndWaitForResult("document.getElementById('text1').select();");
-            // Note that we cancel autofill in loading as a precautious measure.
-            cnt += waitForCallbackAndVerifyTypes(
-                    cnt, new Integer[] {AUTOFILL_CANCEL, AUTOFILL_CANCEL});
-
             dispatchDownAndUpKeyEvents(KeyEvent.KEYCODE_A);
 
             // Note that we currently call ENTER/EXIT one more time.
@@ -749,9 +739,6 @@
             loadUrlSync(url);
             int cnt = 0;
             executeJavaScriptAndWaitForResult("document.getElementById('text1').select();");
-            // Note that we cancel autofill in loading as a precautious measure.
-            cnt += waitForCallbackAndVerifyTypes(
-                    cnt, new Integer[] {AUTOFILL_CANCEL, AUTOFILL_CANCEL});
             dispatchDownAndUpKeyEvents(KeyEvent.KEYCODE_A);
             // Note that we currently call ENTER/EXIT one more time.
             cnt += waitForCallbackAndVerifyTypes(cnt,
@@ -762,7 +749,7 @@
             assertEquals(1, values.size());
             assertEquals("a", values.get(0).second.getTextValue());
             executeJavaScriptAndWaitForResult("document.getElementById('text1').value='c';");
-            assertEquals(7, getCallbackCount());
+            assertEquals(5, getCallbackCount());
             dispatchDownAndUpKeyEvents(KeyEvent.KEYCODE_B);
             // Check if NotifyVirtualValueChanged() called one more time and value is 'cb', this
             // means javascript change didn't trigger the NotifyVirtualValueChanged().
@@ -796,9 +783,6 @@
             loadUrlSync(url);
             int cnt = 0;
             executeJavaScriptAndWaitForResult("document.getElementById('text1').select();");
-            // Note that we cancel autofill in loading as a precautious measure.
-            cnt += waitForCallbackAndVerifyTypes(
-                    cnt, new Integer[] {AUTOFILL_CANCEL, AUTOFILL_CANCEL});
             dispatchDownAndUpKeyEvents(KeyEvent.KEYCODE_A);
             // Note that we currently call ENTER/EXIT one more time.
             cnt += waitForCallbackAndVerifyTypes(cnt,
@@ -836,8 +820,6 @@
         int cnt = 0;
         loadUrlSync(FILE_URL);
         executeJavaScriptAndWaitForResult("document.getElementById('text1').select();");
-        // Note that we cancel autofill in loading as a precautious measure.
-        cnt += waitForCallbackAndVerifyTypes(cnt, new Integer[] {AUTOFILL_CANCEL, AUTOFILL_CANCEL});
         dispatchDownAndUpKeyEvents(KeyEvent.KEYCODE_A);
         // Cancel called for the first query.
         // Note that we currently call ENTER/EXIT one more time.
@@ -866,9 +848,6 @@
             final String url = webServer.setResponse(FILE, data, null);
             loadUrlSync(url);
             executeJavaScriptAndWaitForResult("document.getElementById('text1').select();");
-            // Note that we cancel autofill in loading as a precautious measure.
-            cnt += waitForCallbackAndVerifyTypes(
-                    cnt, new Integer[] {AUTOFILL_CANCEL, AUTOFILL_CANCEL});
             dispatchDownAndUpKeyEvents(KeyEvent.KEYCODE_A);
             // Note that we currently call ENTER/EXIT one more time.
             cnt += waitForCallbackAndVerifyTypes(cnt,
diff --git a/ash/BUILD.gn b/ash/BUILD.gn
index 8b9d2bf..5ac54c77 100644
--- a/ash/BUILD.gn
+++ b/ash/BUILD.gn
@@ -245,6 +245,8 @@
     "lock_screen_action/lock_screen_action_background_state.h",
     "lock_screen_action/lock_screen_action_background_view.cc",
     "lock_screen_action/lock_screen_action_background_view.h",
+    "lock_screen_action/lock_screen_note_display_state_handler.cc",
+    "lock_screen_action/lock_screen_note_display_state_handler.h",
     "lock_screen_action/lock_screen_note_launcher.cc",
     "lock_screen_action/lock_screen_note_launcher.h",
     "login/lock_screen_apps_focus_observer.h",
@@ -1367,6 +1369,7 @@
     "laser/laser_pointer_controller_unittest.cc",
     "laser/laser_segment_utils_unittest.cc",
     "lock_screen_action/lock_screen_action_background_controller_impl_unittest.cc",
+    "lock_screen_action/lock_screen_note_display_state_handler_unittest.cc",
     "lock_screen_action/lock_screen_note_launcher_unittest.cc",
     "login/login_screen_controller_unittest.cc",
     "login/mock_login_screen_client.cc",
diff --git a/ash/accessibility/accessibility_focus_ring_controller.cc b/ash/accessibility/accessibility_focus_ring_controller.cc
index b39e876..46b1173 100644
--- a/ash/accessibility/accessibility_focus_ring_controller.cc
+++ b/ash/accessibility/accessibility_focus_ring_controller.cc
@@ -100,11 +100,15 @@
   OnLayerChange(&focus_animation_info_);
   focus_rects_ = rects;
   UpdateFocusRingsFromFocusRects();
+  if (focus_ring_observer_for_testing_)
+    focus_ring_observer_for_testing_.Run();
 }
 
 void AccessibilityFocusRingController::HideFocusRing() {
   focus_rects_.clear();
   UpdateFocusRingsFromFocusRects();
+  if (focus_ring_observer_for_testing_)
+    focus_ring_observer_for_testing_.Run();
 }
 
 void AccessibilityFocusRingController::UpdateFocusRingsFromFocusRects() {
diff --git a/ash/accessibility/accessibility_focus_ring_controller.h b/ash/accessibility/accessibility_focus_ring_controller.h
index 27cd23e..13e5ab9 100644
--- a/ash/accessibility/accessibility_focus_ring_controller.h
+++ b/ash/accessibility/accessibility_focus_ring_controller.h
@@ -12,6 +12,7 @@
 #include "ash/accessibility/accessibility_focus_ring_layer.h"
 #include "ash/accessibility/accessibility_highlight_layer.h"
 #include "ash/ash_export.h"
+#include "base/bind.h"
 #include "base/macros.h"
 #include "base/memory/singleton.h"
 #include "base/optional.h"
@@ -61,12 +62,26 @@
   // Don't fade in / out, for testing.
   void SetNoFadeForTesting();
 
+  // Get accessibility layers, for testing.
   AccessibilityCursorRingLayer* cursor_layer_for_testing() {
     return cursor_layer_.get();
   }
   AccessibilityCursorRingLayer* caret_layer_for_testing() {
     return caret_layer_.get();
   }
+  const std::vector<std::unique_ptr<AccessibilityFocusRingLayer>>&
+  focus_ring_layers_for_testing() {
+    return focus_layers_;
+  }
+  AccessibilityHighlightLayer* highlight_layer_for_testing() {
+    return highlight_layer_.get();
+  }
+
+  // Sets an observer of focus ring layer changes.
+  void set_focus_ring_observer_for_testing(
+      base::RepeatingCallback<void()> observer) {
+    focus_ring_observer_for_testing_ = observer;
+  }
 
  protected:
   AccessibilityFocusRingController();
@@ -145,6 +160,8 @@
 
   friend struct base::DefaultSingletonTraits<AccessibilityFocusRingController>;
 
+  base::RepeatingCallback<void()> focus_ring_observer_for_testing_;
+
   DISALLOW_COPY_AND_ASSIGN(AccessibilityFocusRingController);
 };
 
diff --git a/ash/app_list/model/app_list_model.cc b/ash/app_list/model/app_list_model.cc
index fb535cd..56c57ba 100644
--- a/ash/app_list/model/app_list_model.cc
+++ b/ash/app_list/model/app_list_model.cc
@@ -91,10 +91,6 @@
 
 const std::string AppListModel::MergeItems(const std::string& target_item_id,
                                            const std::string& source_item_id) {
-  if (!folders_enabled()) {
-    LOG(ERROR) << "MergeItems called with folders disabled.";
-    return "";
-  }
   DVLOG(2) << "MergeItems: " << source_item_id << " -> " << target_item_id;
 
   if (target_item_id == source_item_id) {
@@ -280,31 +276,6 @@
   }
 }
 
-void AppListModel::SetFoldersEnabled(bool folders_enabled) {
-  folders_enabled_ = folders_enabled;
-  if (folders_enabled)
-    return;
-  // Remove child items from folders.
-  std::vector<std::string> folder_ids;
-  for (size_t i = 0; i < top_level_item_list_->item_count(); ++i) {
-    AppListItem* item = top_level_item_list_->item_at(i);
-    if (item->GetItemType() != AppListFolderItem::kItemType)
-      continue;
-    AppListFolderItem* folder = static_cast<AppListFolderItem*>(item);
-    if (folder->folder_type() == AppListFolderItem::FOLDER_TYPE_OEM)
-      continue;  // Do not remove OEM folders.
-    while (folder->item_list()->item_count()) {
-      std::unique_ptr<AppListItem> child = folder->item_list()->RemoveItemAt(0);
-      child->set_folder_id("");
-      AddItemToItemListAndNotifyUpdate(std::move(child));
-    }
-    folder_ids.push_back(folder->id());
-  }
-  // Delete folders.
-  for (size_t i = 0; i < folder_ids.size(); ++i)
-    DeleteItem(folder_ids[i]);
-}
-
 void AppListModel::SetCustomLauncherPageEnabled(bool enabled) {
   custom_launcher_page_enabled_ = enabled;
   for (auto& observer : observers_)
@@ -345,11 +316,6 @@
   if (dest_folder)
     return dest_folder;
 
-  if (!folders_enabled()) {
-    LOG(ERROR) << "Attempt to create folder item when disabled: " << folder_id;
-    return NULL;
-  }
-
   DVLOG(2) << "Creating new folder: " << folder_id;
   std::unique_ptr<AppListFolderItem> new_folder(
       new AppListFolderItem(folder_id, AppListFolderItem::FOLDER_TYPE_NORMAL));
diff --git a/ash/app_list/model/app_list_model.h b/ash/app_list/model/app_list_model.h
index bb2c774c..efa3aee 100644
--- a/ash/app_list/model/app_list_model.h
+++ b/ash/app_list/model/app_list_model.h
@@ -131,10 +131,6 @@
   // has a single child left.
   void DeleteUninstalledItem(const std::string& id);
 
-  // Sets whether or not the folder UI should be enabled. If |folders_enabled|
-  // is false, removes any non-OEM folders.
-  void SetFoldersEnabled(bool folders_enabled);
-
   // Sets whether or not the custom launcher page should be enabled.
   void SetCustomLauncherPageEnabled(bool enabled);
   bool custom_launcher_page_enabled() const {
@@ -167,7 +163,6 @@
   AppListItemList* top_level_item_list() { return top_level_item_list_.get(); }
 
   Status status() const { return status_; }
-  bool folders_enabled() const { return folders_enabled_; }
 
  private:
   // AppListItemListObserver
@@ -209,7 +204,6 @@
   // The AppListView state. Controlled by the AppListView.
   AppListViewState state_fullscreen_ = AppListViewState::CLOSED;
   base::ObserverList<AppListModelObserver, true> observers_;
-  bool folders_enabled_ = false;
   bool custom_launcher_page_enabled_ = true;
   std::string custom_launcher_page_name_;
 
diff --git a/ash/frame/custom_frame_view_ash.cc b/ash/frame/custom_frame_view_ash.cc
index c1539cf5..368a1b7 100644
--- a/ash/frame/custom_frame_view_ash.cc
+++ b/ash/frame/custom_frame_view_ash.cc
@@ -506,17 +506,19 @@
 }
 
 void CustomFrameViewAsh::OnOverviewModeStarting() {
+  in_overview_mode_ = true;
   SetShouldPaintHeader(false);
 }
 
 void CustomFrameViewAsh::OnOverviewModeEnded() {
+  in_overview_mode_ = false;
   SetShouldPaintHeader(true);
 }
 
 void CustomFrameViewAsh::OnSplitViewStateChanged(
     SplitViewController::State /* previous_state */,
     SplitViewController::State state) {
-  if (Shell::Get()->window_selector_controller()->IsSelecting())
+  if (in_overview_mode_)
     MaybePaintHeaderForSplitview(state);
 }
 
diff --git a/ash/frame/custom_frame_view_ash.h b/ash/frame/custom_frame_view_ash.h
index 9d74736..5eec4861 100644
--- a/ash/frame/custom_frame_view_ash.h
+++ b/ash/frame/custom_frame_view_ash.h
@@ -155,6 +155,13 @@
 
   static bool use_empty_minimum_size_for_test_;
 
+  // Track whether the device is in overview mode. Set this to true when
+  // overview mode started and false when overview mode finished. Use this to
+  // check whether we should paint when splitview state changes instead of
+  // Shell::Get()->window_selector_controller()->IsSelecting() because the later
+  // actually may be still be false after overview mode has started.
+  bool in_overview_mode_ = false;
+
   DISALLOW_COPY_AND_ASSIGN(CustomFrameViewAsh);
 };
 
diff --git a/ash/frame/custom_frame_view_ash_unittest.cc b/ash/frame/custom_frame_view_ash_unittest.cc
index fc4176c..d3009f3 100644
--- a/ash/frame/custom_frame_view_ash_unittest.cc
+++ b/ash/frame/custom_frame_view_ash_unittest.cc
@@ -374,6 +374,15 @@
   EXPECT_TRUE(delegate1->header_view()->should_paint());
   EXPECT_TRUE(delegate2->header_view()->should_paint());
 
+  // Toggle overview mode so we return back to left snapped mode. Verify that
+  // the header is again drawn for the snapped window, but not for the unsnapped
+  // window.
+  Shell::Get()->window_selector_controller()->ToggleOverview();
+  ASSERT_EQ(SplitViewController::LEFT_SNAPPED,
+            Shell::Get()->split_view_controller()->state());
+  EXPECT_TRUE(delegate1->header_view()->should_paint());
+  EXPECT_FALSE(delegate2->header_view()->should_paint());
+
   Shell::Get()->split_view_controller()->EndSplitView();
 }
 
diff --git a/ash/lock_screen_action/lock_screen_note_display_state_handler.cc b/ash/lock_screen_action/lock_screen_note_display_state_handler.cc
new file mode 100644
index 0000000..e38fb85
--- /dev/null
+++ b/ash/lock_screen_action/lock_screen_note_display_state_handler.cc
@@ -0,0 +1,141 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ash/lock_screen_action/lock_screen_note_display_state_handler.h"
+
+#include <utility>
+
+#include "ash/lock_screen_action/lock_screen_note_launcher.h"
+#include "ash/public/interfaces/tray_action.mojom.h"
+#include "ash/shell.h"
+#include "ash/system/power/scoped_backlights_forced_off.h"
+#include "ash/tray_action/tray_action.h"
+#include "base/bind.h"
+#include "base/location.h"
+#include "base/time/time.h"
+
+namespace ash {
+
+namespace {
+
+// The max amount of time display state change handling can be delayed due to a
+// lock screen note action launch. The time starts running when the app launch
+// is requested.
+constexpr base::TimeDelta kNoteLaunchTimeout =
+    base::TimeDelta::FromMilliseconds(1500);
+
+}  // namespace
+
+LockScreenNoteDisplayStateHandler::LockScreenNoteDisplayStateHandler(
+    BacklightsForcedOffSetter* backlights_forced_off_setter)
+    : backlights_forced_off_setter_(backlights_forced_off_setter),
+      backlights_forced_off_observer_(this),
+      weak_ptr_factory_(this) {
+  backlights_forced_off_observer_.Add(backlights_forced_off_setter_);
+}
+
+LockScreenNoteDisplayStateHandler::~LockScreenNoteDisplayStateHandler() =
+    default;
+
+void LockScreenNoteDisplayStateHandler::OnBacklightsForcedOffChanged(
+    bool backlights_forced_off) {
+  // Close lock screen note when backlights are forced off - unless the
+  // backlights are forced off by this as part of note app launch.
+  if (backlights_forced_off && !backlights_forced_off_) {
+    Shell::Get()->tray_action()->CloseLockScreenNote(
+        mojom::CloseLockScreenNoteReason::kScreenDimmed);
+  }
+}
+
+void LockScreenNoteDisplayStateHandler::OnScreenStateChanged(
+    BacklightsForcedOffSetter::ScreenState screen_state) {
+  if (screen_state != BacklightsForcedOffSetter::ScreenState::ON &&
+      note_launch_delayed_until_screen_off_) {
+    RunLockScreenNoteLauncher();
+  }
+}
+
+void LockScreenNoteDisplayStateHandler::AttemptNoteLaunchForStylusEject() {
+  if (!LockScreenNoteLauncher::CanAttemptLaunch() ||
+      NoteLaunchInProgressOrDelayed()) {
+    return;
+  }
+
+  if (!backlights_forced_off_ && ShouldForceBacklightsOffForNoteLaunch()) {
+    backlights_forced_off_ =
+        backlights_forced_off_setter_->ForceBacklightsOff();
+  }
+
+  DCHECK(!launch_timer_.IsRunning());
+  launch_timer_.Start(
+      FROM_HERE, kNoteLaunchTimeout,
+      base::Bind(&LockScreenNoteDisplayStateHandler::NoteLaunchDone,
+                 weak_ptr_factory_.GetWeakPtr(), false));
+
+  // Delay note launch if backlights are forced off, but the screen hasn't
+  // been turned off yet - the note should be launched when the pending
+  // backlights state is finished (i.e. the screen is turned off).
+  if (backlights_forced_off_setter_->backlights_forced_off() &&
+      backlights_forced_off_setter_->screen_state() ==
+          BacklightsForcedOffSetter::ScreenState::ON) {
+    note_launch_delayed_until_screen_off_ = true;
+    return;
+  }
+
+  RunLockScreenNoteLauncher();
+}
+
+void LockScreenNoteDisplayStateHandler::Reset() {
+  note_launch_delayed_until_screen_off_ = false;
+  backlights_forced_off_.reset();
+  lock_screen_note_launcher_.reset();
+  launch_timer_.Stop();
+}
+
+void LockScreenNoteDisplayStateHandler::RunLockScreenNoteLauncher() {
+  DCHECK(!lock_screen_note_launcher_);
+  if (!LockScreenNoteLauncher::CanAttemptLaunch()) {
+    Reset();
+    return;
+  }
+
+  note_launch_delayed_until_screen_off_ = false;
+
+  lock_screen_note_launcher_ = std::make_unique<LockScreenNoteLauncher>();
+  lock_screen_note_launcher_->Run(
+      mojom::LockScreenNoteOrigin::kStylusEject,
+      base::BindOnce(&LockScreenNoteDisplayStateHandler::NoteLaunchDone,
+                     weak_ptr_factory_.GetWeakPtr()));
+}
+
+bool LockScreenNoteDisplayStateHandler::ShouldForceBacklightsOffForNoteLaunch()
+    const {
+  // Backlights should be kept off during app launch if the display has been
+  // turned off without user interaction (e.g. due to user inactivity), or if
+  // the backlights are currently being forced off - the goal is to avoid flash
+  // of lock screen UI if the display gets turned on before lock screen app
+  // window is shown.
+  // There is no need to force the backlight off if the display has been turned
+  // off due to user action - in this case display brightness will not change
+  // when backlights stop being forced off (due to stylus eject) - the
+  // brightness will remain at user selected level, so the lock screen UI will
+  // not actually become visible.
+  //
+  // Note that backlights_forced_off_setter_ check is required as there is a
+  // delay between request to force backlights off and screen state getting
+  // updated due to that request.
+  return backlights_forced_off_setter_->backlights_forced_off() ||
+         backlights_forced_off_setter_->screen_state() ==
+             BacklightsForcedOffSetter::ScreenState::OFF_AUTO;
+}
+
+bool LockScreenNoteDisplayStateHandler::NoteLaunchInProgressOrDelayed() const {
+  return note_launch_delayed_until_screen_off_ || lock_screen_note_launcher_;
+}
+
+void LockScreenNoteDisplayStateHandler::NoteLaunchDone(bool success) {
+  Reset();
+}
+
+}  // namespace ash
diff --git a/ash/lock_screen_action/lock_screen_note_display_state_handler.h b/ash/lock_screen_action/lock_screen_note_display_state_handler.h
new file mode 100644
index 0000000..7d72733
--- /dev/null
+++ b/ash/lock_screen_action/lock_screen_note_display_state_handler.h
@@ -0,0 +1,95 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef ASH_LOCK_SCREEN_ACTION_LOCK_SCREEN_NOTE_DISPLAY_STATE_HANDLER_H_
+#define ASH_LOCK_SCREEN_ACTION_LOCK_SCREEN_NOTE_DISPLAY_STATE_HANDLER_H_
+
+#include <memory>
+
+#include "ash/system/power/backlights_forced_off_setter.h"
+#include "base/macros.h"
+#include "base/memory/weak_ptr.h"
+#include "base/scoped_observer.h"
+#include "base/timer/timer.h"
+
+namespace ash {
+
+class LockScreenNoteLauncher;
+class ScopedBacklightsForcedOff;
+
+// Handles display state changes related to lock screen note state.
+// For example it will close any active lock screen notes if the display is
+// forced off.
+// This class also handles a lock screen note launch when stylus is ejected.
+// When the note is launched while the screen is off, note launch forces the
+// display off, in order to delay screen being turned on (which happens, among
+// other things, when the stylus gets ejected) until the lock screen note is
+// visible. This is to prevent a flash of the lock screen UI as the lock screen
+// note app window is being shown.
+class LockScreenNoteDisplayStateHandler
+    : public BacklightsForcedOffSetter::Observer {
+ public:
+  explicit LockScreenNoteDisplayStateHandler(
+      BacklightsForcedOffSetter* backlights_forced_off_setter);
+  ~LockScreenNoteDisplayStateHandler() override;
+
+  base::OneShotTimer* launch_timer_for_test() { return &launch_timer_; }
+
+  // BacklightsForcedOffSetter::Observer:
+  void OnBacklightsForcedOffChanged(bool backlights_forced_off) override;
+  void OnScreenStateChanged(
+      BacklightsForcedOffSetter::ScreenState screen_state) override;
+
+  // If lock screen note action is available, it requests a new lock screen note
+  // with launch reason set to stylus eject.
+  void AttemptNoteLaunchForStylusEject();
+
+  // Resets the internal state, cancelling any in progress launch.
+  void Reset();
+
+ private:
+  // Runs lock screen note launcher, which starts lock screen app launch.
+  void RunLockScreenNoteLauncher();
+
+  // Whether the backlights should be forced off during lock screen note
+  // launch.
+  bool ShouldForceBacklightsOffForNoteLaunch() const;
+
+  // Whether a lock screen note is currently being launched by |this|.
+  bool NoteLaunchInProgressOrDelayed() const;
+
+  // Called by |lock_screen_note_launcher_| when lock screen note launch is
+  // done.
+  void NoteLaunchDone(bool success);
+
+  // Object used to force the backlights off.
+  BacklightsForcedOffSetter* const backlights_forced_off_setter_;
+
+  // Whether lock screen note launch is delayed until the screen is reported to
+  // be off - this is used if lock screen note launch is requested when
+  // backlights have been forced off, but the power manager still reports screen
+  // to be on.
+  bool note_launch_delayed_until_screen_off_ = false;
+
+  std::unique_ptr<LockScreenNoteLauncher> lock_screen_note_launcher_;
+
+  // Scoped backlights forced off request - this is returned by
+  // |backlights_forced_off_setter_->ForceBacklightsOff()|, and will keep the
+  // backlights in forced-off state until they are reset.
+  std::unique_ptr<ScopedBacklightsForcedOff> backlights_forced_off_;
+
+  // Timer used to set up timeout for lock screen note launch.
+  base::OneShotTimer launch_timer_;
+
+  ScopedObserver<BacklightsForcedOffSetter, BacklightsForcedOffSetter::Observer>
+      backlights_forced_off_observer_;
+
+  base::WeakPtrFactory<LockScreenNoteDisplayStateHandler> weak_ptr_factory_;
+
+  DISALLOW_COPY_AND_ASSIGN(LockScreenNoteDisplayStateHandler);
+};
+
+}  // namespace ash
+
+#endif  // ASH_LOCK_SCREEN_ACTION_LOCK_SCREEN_NOTE_DISPLAY_STATE_HANDLER_H_
diff --git a/ash/lock_screen_action/lock_screen_note_display_state_handler_unittest.cc b/ash/lock_screen_action/lock_screen_note_display_state_handler_unittest.cc
new file mode 100644
index 0000000..011ce25a
--- /dev/null
+++ b/ash/lock_screen_action/lock_screen_note_display_state_handler_unittest.cc
@@ -0,0 +1,512 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ash/lock_screen_action/lock_screen_note_display_state_handler.h"
+
+#include <memory>
+#include <utility>
+#include <vector>
+
+#include "ash/accessibility/accessibility_controller.h"
+#include "ash/accessibility/test_accessibility_controller_client.h"
+#include "ash/public/cpp/ash_switches.h"
+#include "ash/public/cpp/config.h"
+#include "ash/public/interfaces/tray_action.mojom.h"
+#include "ash/shell.h"
+#include "ash/system/power/power_button_controller.h"
+#include "ash/test/ash_test_base.h"
+#include "ash/tray_action/test_tray_action_client.h"
+#include "ash/tray_action/tray_action.h"
+#include "ash/wm/tablet_mode/tablet_mode_controller.h"
+#include "base/command_line.h"
+#include "base/run_loop.h"
+#include "base/test/simple_test_tick_clock.h"
+#include "chromeos/dbus/dbus_thread_manager.h"
+#include "chromeos/dbus/fake_power_manager_client.h"
+#include "ui/events/devices/stylus_state.h"
+#include "ui/events/test/device_data_manager_test_api.h"
+
+namespace ash {
+
+namespace {
+
+constexpr double kVisibleBrightnessPercent = 10;
+
+class TestPowerManagerObserver : public chromeos::PowerManagerClient::Observer {
+ public:
+  explicit TestPowerManagerObserver(
+      chromeos::FakePowerManagerClient* power_manager)
+      : power_manager_(power_manager), scoped_observer_(this) {
+    scoped_observer_.Add(power_manager_);
+    power_manager_->set_user_activity_callback(base::BindRepeating(
+        &TestPowerManagerObserver::OnUserActivity, base::Unretained(this)));
+  }
+  ~TestPowerManagerObserver() override {
+    power_manager_->set_user_activity_callback(base::RepeatingClosure());
+  }
+
+  const std::vector<int> brightness_changes() const {
+    return brightness_changes_;
+  }
+
+  void ClearBrightnessChanges() { brightness_changes_.clear(); }
+
+  // chromeos::PowerManagerClient::Observer:
+  void BrightnessChanged(int level, bool user_initiated) override {
+    brightness_changes_.push_back(level);
+  }
+
+  void OnUserActivity() {
+    if (!power_manager_->backlights_forced_off() &&
+        power_manager_->screen_brightness_percent() == 0) {
+      brightness_changes_.push_back(kVisibleBrightnessPercent);
+    }
+  }
+
+ private:
+  chromeos::FakePowerManagerClient* power_manager_;
+  std::vector<int> brightness_changes_;
+
+  ScopedObserver<chromeos::PowerManagerClient,
+                 chromeos::PowerManagerClient::Observer>
+      scoped_observer_;
+
+  DISALLOW_COPY_AND_ASSIGN(TestPowerManagerObserver);
+};
+
+}  // namespace
+
+class LockScreenNoteDisplayStateHandlerTest : public AshTestBase {
+ public:
+  LockScreenNoteDisplayStateHandlerTest() = default;
+  ~LockScreenNoteDisplayStateHandlerTest() override = default;
+
+  // AshTestBase:
+  void SetUp() override {
+    base::CommandLine::ForCurrentProcess()->AppendSwitch(
+        switches::kAshEnableTabletMode);
+
+    auto power_manager_client =
+        std::make_unique<chromeos::FakePowerManagerClient>();
+    power_manager_client_ = power_manager_client.get();
+    power_manager_client_->SetScreenBrightnessPercent(kVisibleBrightnessPercent,
+                                                      false /*gradual*/);
+    power_manager_observer_ =
+        std::make_unique<TestPowerManagerObserver>(power_manager_client_);
+    chromeos::DBusThreadManager::GetSetterForTesting()->SetPowerManagerClient(
+        std::move(power_manager_client));
+
+    AshTestBase::SetUp();
+
+    BlockUserSession(BLOCKED_BY_LOCK_SCREEN);
+    InitializeTabletPowerButtonState();
+
+    Shell::Get()->tray_action()->SetClient(
+        tray_action_client_.CreateInterfacePtrAndBind(),
+        mojom::TrayActionState::kAvailable);
+    Shell::Get()->tray_action()->FlushMojoForTesting();
+    // Run the loop so the lock screen note display state handler picks up
+    // initial screen brightness.
+    base::RunLoop().RunUntilIdle();
+    power_manager_observer_->ClearBrightnessChanges();
+
+    // Advance the tick clock so it's not close to the null clock value.
+    tick_clock_.Advance(base::TimeDelta::FromMilliseconds(10000));
+  }
+  void TearDown() override {
+    AshTestBase::TearDown();
+    power_manager_observer_.reset();
+    chromeos::DBusThreadManager::Shutdown();
+  }
+
+  bool LaunchTimeoutRunning() {
+    return Shell::Get()
+        ->tray_action()
+        ->lock_screen_note_display_state_handler_for_test()
+        ->launch_timer_for_test()
+        ->IsRunning();
+  }
+
+  bool TriggerNoteLaunchTimeout() {
+    base::OneShotTimer* timer =
+        Shell::Get()
+            ->tray_action()
+            ->lock_screen_note_display_state_handler_for_test()
+            ->launch_timer_for_test();
+    if (!timer->IsRunning())
+      return false;
+
+    base::Closure task = timer->user_task();
+    timer->Stop();
+    task.Run();
+    return true;
+  }
+
+  void TurnScreenOffForUserInactivity() {
+    power_manager_client_->set_screen_brightness_percent(0);
+    power_manager_client_->SendBrightnessChanged(0, false /*user_initiated*/);
+    power_manager_observer_->ClearBrightnessChanges();
+  }
+
+  void SimulatePowerButtonPress() {
+    power_manager_client_->SendPowerButtonEvent(true, tick_clock_.NowTicks());
+    tick_clock_.Advance(base::TimeDelta::FromMilliseconds(10));
+    power_manager_client_->SendPowerButtonEvent(false, tick_clock_.NowTicks());
+    base::RunLoop().RunUntilIdle();
+  }
+
+  testing::AssertionResult SimulateNoteLaunchStartedIfNoteActionRequested(
+      mojom::LockScreenNoteOrigin expected_note_origin) {
+    Shell::Get()->tray_action()->FlushMojoForTesting();
+
+    if (tray_action_client_.note_origins().size() != 1) {
+      return testing::AssertionFailure()
+             << "Expected a single note action request, found "
+             << tray_action_client_.note_origins().size();
+    }
+
+    if (tray_action_client_.note_origins()[0] != expected_note_origin) {
+      return testing::AssertionFailure()
+             << "Unexpected note request origin: "
+             << tray_action_client_.note_origins()[0]
+             << "; expected: " << expected_note_origin;
+    }
+
+    Shell::Get()->tray_action()->UpdateLockScreenNoteState(
+        mojom::TrayActionState::kLaunching);
+    return testing::AssertionSuccess();
+  }
+
+ protected:
+  chromeos::FakePowerManagerClient* power_manager_client_ = nullptr;
+  std::unique_ptr<TestPowerManagerObserver> power_manager_observer_;
+  TestTrayActionClient tray_action_client_;
+
+ private:
+  void InitializeTabletPowerButtonState() {
+    // Tablet button controller initialization is deferred until the
+    // accelerometer update is received by the power button controller.
+    scoped_refptr<chromeos::AccelerometerUpdate> accelerometer_update(
+        new chromeos::AccelerometerUpdate());
+    Shell::Get()->power_button_controller()->OnAccelerometerUpdated(
+        accelerometer_update);
+  }
+
+  base::SimpleTestTickClock tick_clock_;
+
+  DISALLOW_COPY_AND_ASSIGN(LockScreenNoteDisplayStateHandlerTest);
+};
+
+TEST_F(LockScreenNoteDisplayStateHandlerTest, EjectWhenScreenOn) {
+  // ui::test::DeviceDataManagerTestAPI only works in classic ash.
+  // TODO(tbarzic): Fix this in mus/mash.
+  if (Shell::GetAshConfig() != Config::CLASSIC)
+    return;
+
+  ui::test::DeviceDataManagerTestAPI devices_test_api;
+  devices_test_api.NotifyObserversStylusStateChanged(ui::StylusState::REMOVED);
+  base::RunLoop().RunUntilIdle();
+
+  EXPECT_FALSE(power_manager_client_->backlights_forced_off());
+  EXPECT_TRUE(power_manager_observer_->brightness_changes().empty());
+
+  ASSERT_TRUE(SimulateNoteLaunchStartedIfNoteActionRequested(
+      mojom::LockScreenNoteOrigin::kStylusEject));
+
+  Shell::Get()->tray_action()->UpdateLockScreenNoteState(
+      mojom::TrayActionState::kActive);
+  base::RunLoop().RunUntilIdle();
+
+  EXPECT_FALSE(power_manager_client_->backlights_forced_off());
+  EXPECT_TRUE(power_manager_observer_->brightness_changes().empty());
+
+  ASSERT_FALSE(LaunchTimeoutRunning());
+}
+
+TEST_F(LockScreenNoteDisplayStateHandlerTest, EjectWhenScreenOff) {
+  // ui::test::DeviceDataManagerTestAPI only works in classic ash.
+  // TODO(tbarzic): Fix this in mus/mash.
+  if (Shell::GetAshConfig() != Config::CLASSIC)
+    return;
+
+  TurnScreenOffForUserInactivity();
+
+  ui::test::DeviceDataManagerTestAPI devices_test_api;
+  devices_test_api.NotifyObserversStylusStateChanged(ui::StylusState::REMOVED);
+  base::RunLoop().RunUntilIdle();
+
+  EXPECT_TRUE(power_manager_client_->backlights_forced_off());
+  EXPECT_EQ(std::vector<int>({0}),
+            power_manager_observer_->brightness_changes());
+  power_manager_observer_->ClearBrightnessChanges();
+
+  ASSERT_TRUE(SimulateNoteLaunchStartedIfNoteActionRequested(
+      mojom::LockScreenNoteOrigin::kStylusEject));
+
+  Shell::Get()->tray_action()->UpdateLockScreenNoteState(
+      mojom::TrayActionState::kActive);
+  base::RunLoop().RunUntilIdle();
+
+  EXPECT_FALSE(power_manager_client_->backlights_forced_off());
+  EXPECT_EQ(std::vector<int>({kVisibleBrightnessPercent}),
+            power_manager_observer_->brightness_changes());
+
+  ASSERT_FALSE(LaunchTimeoutRunning());
+}
+
+TEST_F(LockScreenNoteDisplayStateHandlerTest,
+       EjectWhenScreenOffAndNoteNotAvailable) {
+  // ui::test::DeviceDataManagerTestAPI only works in classic ash.
+  // TODO(tbarzic): Fix this in mus/mash.
+  if (Shell::GetAshConfig() != Config::CLASSIC)
+    return;
+
+  TurnScreenOffForUserInactivity();
+
+  Shell::Get()->tray_action()->UpdateLockScreenNoteState(
+      mojom::TrayActionState::kNotAvailable);
+
+  EXPECT_FALSE(power_manager_client_->backlights_forced_off());
+  EXPECT_TRUE(power_manager_observer_->brightness_changes().empty());
+
+  ui::test::DeviceDataManagerTestAPI devices_test_api;
+  devices_test_api.NotifyObserversStylusStateChanged(ui::StylusState::REMOVED);
+  base::RunLoop().RunUntilIdle();
+
+  // Styluls eject is expected to turn the screen on due to user activity.
+  EXPECT_FALSE(power_manager_client_->backlights_forced_off());
+  EXPECT_EQ(std::vector<int>({kVisibleBrightnessPercent}),
+            power_manager_observer_->brightness_changes());
+  power_manager_observer_->ClearBrightnessChanges();
+
+  EXPECT_TRUE(tray_action_client_.note_origins().empty());
+
+  // Verify that later (unrelated) note launch does not affect power manager
+  // state.
+  Shell::Get()->tray_action()->UpdateLockScreenNoteState(
+      mojom::TrayActionState::kLaunching);
+  Shell::Get()->tray_action()->UpdateLockScreenNoteState(
+      mojom::TrayActionState::kActive);
+  base::RunLoop().RunUntilIdle();
+
+  EXPECT_FALSE(power_manager_client_->backlights_forced_off());
+  EXPECT_TRUE(power_manager_observer_->brightness_changes().empty());
+
+  ASSERT_FALSE(LaunchTimeoutRunning());
+}
+
+TEST_F(LockScreenNoteDisplayStateHandlerTest, TurnScreenOnWhenAppLaunchFails) {
+  // ui::test::DeviceDataManagerTestAPI only works in classic ash.
+  // TODO(tbarzic): Fix this in mus/mash.
+  if (Shell::GetAshConfig() != Config::CLASSIC)
+    return;
+
+  TurnScreenOffForUserInactivity();
+
+  ui::test::DeviceDataManagerTestAPI devices_test_api;
+  devices_test_api.NotifyObserversStylusStateChanged(ui::StylusState::REMOVED);
+  base::RunLoop().RunUntilIdle();
+
+  EXPECT_TRUE(power_manager_client_->backlights_forced_off());
+  EXPECT_EQ(std::vector<int>({0}),
+            power_manager_observer_->brightness_changes());
+  power_manager_observer_->ClearBrightnessChanges();
+
+  ASSERT_TRUE(SimulateNoteLaunchStartedIfNoteActionRequested(
+      mojom::LockScreenNoteOrigin::kStylusEject));
+
+  Shell::Get()->tray_action()->UpdateLockScreenNoteState(
+      mojom::TrayActionState::kAvailable);
+  base::RunLoop().RunUntilIdle();
+
+  EXPECT_FALSE(power_manager_client_->backlights_forced_off());
+  EXPECT_EQ(std::vector<int>({kVisibleBrightnessPercent}),
+            power_manager_observer_->brightness_changes());
+
+  ASSERT_FALSE(LaunchTimeoutRunning());
+}
+
+// Tests stylus eject when the backlights was turned off by a power button
+// getting pressed - in particular, it makes sure that power button display
+// controller cancelling backlights forced off on stylus eject does not happen
+// before lock screen note display state handler requests backlights to be
+// forced off (i.e. that backlights are continuosly kept forced off).
+TEST_F(LockScreenNoteDisplayStateHandlerTest, EjectWhileScreenForcedOff) {
+  // ui::test::DeviceDataManagerTestAPI only works in classic ash.
+  // TODO(tbarzic): Fix this in mus/mash.
+  if (Shell::GetAshConfig() != Config::CLASSIC)
+    return;
+
+  SimulatePowerButtonPress();
+
+  ASSERT_TRUE(power_manager_client_->backlights_forced_off());
+  EXPECT_EQ(std::vector<int>({0}),
+            power_manager_observer_->brightness_changes());
+  power_manager_observer_->ClearBrightnessChanges();
+
+  ui::test::DeviceDataManagerTestAPI devices_test_api;
+  devices_test_api.NotifyObserversStylusStateChanged(ui::StylusState::REMOVED);
+  base::RunLoop().RunUntilIdle();
+
+  EXPECT_TRUE(power_manager_client_->backlights_forced_off());
+  EXPECT_TRUE(power_manager_observer_->brightness_changes().empty());
+
+  ASSERT_TRUE(SimulateNoteLaunchStartedIfNoteActionRequested(
+      mojom::LockScreenNoteOrigin::kStylusEject));
+
+  Shell::Get()->tray_action()->UpdateLockScreenNoteState(
+      mojom::TrayActionState::kActive);
+  base::RunLoop().RunUntilIdle();
+
+  EXPECT_FALSE(power_manager_client_->backlights_forced_off());
+  EXPECT_EQ(std::vector<int>({kVisibleBrightnessPercent}),
+            power_manager_observer_->brightness_changes());
+
+  ASSERT_FALSE(LaunchTimeoutRunning());
+}
+
+TEST_F(LockScreenNoteDisplayStateHandlerTest, DisplayNotTurnedOffIndefinitely) {
+  // ui::test::DeviceDataManagerTestAPI only works in classic ash.
+  // TODO(tbarzic): Fix this in mus/mash.
+  if (Shell::GetAshConfig() != Config::CLASSIC)
+    return;
+
+  TurnScreenOffForUserInactivity();
+
+  ui::test::DeviceDataManagerTestAPI devices_test_api;
+  devices_test_api.NotifyObserversStylusStateChanged(ui::StylusState::REMOVED);
+  base::RunLoop().RunUntilIdle();
+
+  ASSERT_TRUE(SimulateNoteLaunchStartedIfNoteActionRequested(
+      mojom::LockScreenNoteOrigin::kStylusEject));
+
+  EXPECT_TRUE(power_manager_client_->backlights_forced_off());
+  EXPECT_EQ(std::vector<int>({0}),
+            power_manager_observer_->brightness_changes());
+  power_manager_observer_->ClearBrightnessChanges();
+
+  ASSERT_TRUE(TriggerNoteLaunchTimeout());
+  base::RunLoop().RunUntilIdle();
+
+  EXPECT_FALSE(power_manager_client_->backlights_forced_off());
+  EXPECT_EQ(std::vector<int>({kVisibleBrightnessPercent}),
+            power_manager_observer_->brightness_changes());
+  power_manager_observer_->ClearBrightnessChanges();
+
+  Shell::Get()->tray_action()->UpdateLockScreenNoteState(
+      mojom::TrayActionState::kActive);
+  base::RunLoop().RunUntilIdle();
+  EXPECT_FALSE(power_manager_client_->backlights_forced_off());
+  EXPECT_TRUE(power_manager_observer_->brightness_changes().empty());
+
+  ASSERT_FALSE(LaunchTimeoutRunning());
+}
+
+// Test that verifies that lock screen note request is delayed until screen is
+// turned off if stylus eject happens soon after power button is pressed, while
+// display configuration to off is still in progress.
+TEST_F(LockScreenNoteDisplayStateHandlerTest,
+       StylusEjectWhileForcingDisplayOff) {
+  // ui::test::DeviceDataManagerTestAPI only works in classic ash.
+  // TODO(tbarzic): Fix this in mus/mash.
+  if (Shell::GetAshConfig() != Config::CLASSIC)
+    return;
+
+  power_manager_client_
+      ->set_enqueue_brightness_changes_on_backlights_forced_off(true);
+
+  SimulatePowerButtonPress();
+  EXPECT_TRUE(power_manager_client_->backlights_forced_off());
+  EXPECT_TRUE(power_manager_observer_->brightness_changes().empty());
+  EXPECT_EQ(1u, power_manager_client_->pending_brightness_changes().size());
+
+  ui::test::DeviceDataManagerTestAPI devices_test_api;
+  devices_test_api.NotifyObserversStylusStateChanged(ui::StylusState::REMOVED);
+  base::RunLoop().RunUntilIdle();
+
+  // Verify that there are no note requests when the screen brightness due to
+  // backlights being forced off is still being updated.
+  Shell::Get()->tray_action()->FlushMojoForTesting();
+  EXPECT_TRUE(tray_action_client_.note_origins().empty());
+
+  // Apply screen brightness set by forcing backlights off,
+  EXPECT_EQ(1u, power_manager_client_->pending_brightness_changes().size());
+  ASSERT_TRUE(power_manager_client_->ApplyPendingBrightnessChange());
+
+  EXPECT_TRUE(power_manager_client_->backlights_forced_off());
+  EXPECT_TRUE(power_manager_client_->pending_brightness_changes().empty());
+  EXPECT_EQ(std::vector<int>({0}),
+            power_manager_observer_->brightness_changes());
+  power_manager_observer_->ClearBrightnessChanges();
+
+  ASSERT_TRUE(SimulateNoteLaunchStartedIfNoteActionRequested(
+      mojom::LockScreenNoteOrigin::kStylusEject));
+
+  Shell::Get()->tray_action()->UpdateLockScreenNoteState(
+      mojom::TrayActionState::kActive);
+  base::RunLoop().RunUntilIdle();
+  EXPECT_FALSE(power_manager_client_->backlights_forced_off());
+  ASSERT_TRUE(power_manager_client_->ApplyPendingBrightnessChange());
+  EXPECT_EQ(std::vector<int>({kVisibleBrightnessPercent}),
+            power_manager_observer_->brightness_changes());
+
+  ASSERT_FALSE(LaunchTimeoutRunning());
+}
+
+TEST_F(LockScreenNoteDisplayStateHandlerTest, ScreenA11yAlerts) {
+  // ui::test::DeviceDataManagerTestAPI only works in classic ash.
+  // TODO(tbarzic): Fix this in mus/mash.
+  if (Shell::GetAshConfig() != Config::CLASSIC)
+    return;
+
+  TestAccessibilityControllerClient a11y_client;
+  AccessibilityController* a11y_controller =
+      Shell::Get()->accessibility_controller();
+  a11y_controller->SetClient(a11y_client.CreateInterfacePtrAndBind());
+
+  SimulatePowerButtonPress();
+  ASSERT_TRUE(power_manager_client_->backlights_forced_off());
+
+  a11y_controller->FlushMojoForTest();
+  EXPECT_EQ(mojom::AccessibilityAlert::SCREEN_OFF,
+            a11y_client.last_a11y_alert());
+
+  ui::test::DeviceDataManagerTestAPI devices_test_api;
+  devices_test_api.NotifyObserversStylusStateChanged(ui::StylusState::REMOVED);
+  base::RunLoop().RunUntilIdle();
+
+  ASSERT_TRUE(SimulateNoteLaunchStartedIfNoteActionRequested(
+      mojom::LockScreenNoteOrigin::kStylusEject));
+  EXPECT_TRUE(power_manager_client_->backlights_forced_off());
+
+  // Screen ON alert is delayed until the screen is turned on after lock screen
+  // note launch.
+  a11y_controller->FlushMojoForTest();
+  EXPECT_EQ(mojom::AccessibilityAlert::SCREEN_OFF,
+            a11y_client.last_a11y_alert());
+
+  Shell::Get()->tray_action()->UpdateLockScreenNoteState(
+      mojom::TrayActionState::kActive);
+  base::RunLoop().RunUntilIdle();
+
+  // Verify that screen on a11y alert has been sent.
+  a11y_controller->FlushMojoForTest();
+  EXPECT_EQ(mojom::AccessibilityAlert::SCREEN_ON,
+            a11y_client.last_a11y_alert());
+}
+
+TEST_F(LockScreenNoteDisplayStateHandlerTest,
+       PowerButtonPressClosesLockScreenNote) {
+  Shell::Get()->tray_action()->UpdateLockScreenNoteState(
+      mojom::TrayActionState::kActive);
+
+  SimulatePowerButtonPress();
+
+  Shell::Get()->tray_action()->FlushMojoForTesting();
+  EXPECT_EQ(std::vector<mojom::CloseLockScreenNoteReason>(
+                {mojom::CloseLockScreenNoteReason::kScreenDimmed}),
+            tray_action_client_.close_note_reasons());
+}
+
+}  // namespace ash
diff --git a/ash/shell.cc b/ash/shell.cc
index 4c96e100b..f50167aa 100644
--- a/ash/shell.cc
+++ b/ash/shell.cc
@@ -599,7 +599,6 @@
       shutdown_controller_(std::make_unique<ShutdownController>()),
       system_tray_controller_(std::make_unique<SystemTrayController>()),
       system_tray_notifier_(std::make_unique<SystemTrayNotifier>()),
-      tray_action_(std::make_unique<TrayAction>()),
       vpn_list_(std::make_unique<VpnList>()),
       window_cycle_controller_(std::make_unique<WindowCycleController>()),
       window_selector_controller_(std::make_unique<WindowSelectorController>()),
@@ -724,6 +723,8 @@
   toplevel_window_event_handler_.reset();
   visibility_controller_.reset();
 
+  tray_action_.reset();
+
   power_button_controller_.reset();
   lock_state_controller_.reset();
   backlights_forced_off_setter_.reset();
@@ -1013,6 +1014,9 @@
 
   backlights_forced_off_setter_ = std::make_unique<BacklightsForcedOffSetter>();
 
+  tray_action_ =
+      std::make_unique<TrayAction>(backlights_forced_off_setter_.get());
+
   lock_state_controller_ =
       std::make_unique<LockStateController>(shutdown_controller_.get());
   power_button_controller_ = std::make_unique<PowerButtonController>(
diff --git a/ash/tray_action/tray_action.cc b/ash/tray_action/tray_action.cc
index 5874a855..f114c1b 100644
--- a/ash/tray_action/tray_action.cc
+++ b/ash/tray_action/tray_action.cc
@@ -6,14 +6,22 @@
 
 #include <utility>
 
+#include "ash/lock_screen_action/lock_screen_note_display_state_handler.h"
 #include "ash/tray_action/tray_action_observer.h"
 #include "base/bind.h"
 #include "base/callback.h"
 #include "base/logging.h"
+#include "ui/events/devices/input_device_manager.h"
+#include "ui/events/devices/stylus_state.h"
 
 namespace ash {
 
-TrayAction::TrayAction() : binding_(this) {}
+TrayAction::TrayAction(BacklightsForcedOffSetter* backlights_forced_off_setter)
+    : backlights_forced_off_setter_(backlights_forced_off_setter),
+      binding_(this),
+      stylus_observer_(this) {
+  stylus_observer_.Add(ui::InputDeviceManager::GetInstance());
+}
 
 TrayAction::~TrayAction() = default;
 
@@ -51,6 +59,12 @@
         base::Bind(&TrayAction::SetClient, base::Unretained(this), nullptr,
                    mojom::TrayActionState::kNotAvailable));
     lock_screen_note_state_ = lock_screen_note_state;
+
+    lock_screen_note_display_state_handler_ =
+        std::make_unique<LockScreenNoteDisplayStateHandler>(
+            backlights_forced_off_setter_);
+  } else {
+    lock_screen_note_display_state_handler_.reset();
   }
 
   // Setting action handler value can change effective state - notify observers
@@ -65,6 +79,9 @@
 
   lock_screen_note_state_ = state;
 
+  if (lock_screen_note_state_ == mojom::TrayActionState::kNotAvailable)
+    lock_screen_note_display_state_handler_->Reset();
+
   // If the client is not set, the effective state has not changed, so no need
   // to notify observers of a state change.
   if (tray_action_client_)
@@ -85,6 +102,11 @@
     tray_action_client_->CloseLockScreenNote(reason);
 }
 
+void TrayAction::OnStylusStateChanged(ui::StylusState state) {
+  if (state == ui::StylusState::REMOVED)
+    lock_screen_note_display_state_handler_->AttemptNoteLaunchForStylusEject();
+}
+
 void TrayAction::FlushMojoForTesting() {
   if (tray_action_client_)
     tray_action_client_.FlushForTesting();
diff --git a/ash/tray_action/tray_action.h b/ash/tray_action/tray_action.h
index 40e2ebb4..41ffccc 100644
--- a/ash/tray_action/tray_action.h
+++ b/ash/tray_action/tray_action.h
@@ -5,14 +5,25 @@
 #ifndef ASH_TRAY_ACTION_TRAY_ACTION_H_
 #define ASH_TRAY_ACTION_TRAY_ACTION_H_
 
+#include <memory>
+
 #include "ash/ash_export.h"
 #include "ash/public/interfaces/tray_action.mojom.h"
 #include "base/macros.h"
 #include "base/observer_list.h"
+#include "base/scoped_observer.h"
 #include "mojo/public/cpp/bindings/binding.h"
+#include "ui/events/devices/input_device_event_observer.h"
+
+namespace ui {
+class InputDeviceManager;
+enum class StylusState;
+}  // namespace ui
 
 namespace ash {
 
+class BacklightsForcedOffSetter;
+class LockScreenNoteDisplayStateHandler;
 class TrayActionObserver;
 
 // Controller that ash can use to request a predefined set of actions to be
@@ -24,11 +35,17 @@
 // Currently, only single action is supported - creating new note on the lock
 // screen - Chrome handles this action by launching an app (if any) that is
 // registered as a lock screen enabled action handler for the new note action.
-class ASH_EXPORT TrayAction : public mojom::TrayAction {
+class ASH_EXPORT TrayAction : public mojom::TrayAction,
+                              public ui::InputDeviceEventObserver {
  public:
-  TrayAction();
+  explicit TrayAction(BacklightsForcedOffSetter* backlights_forced_off_setter);
   ~TrayAction() override;
 
+  LockScreenNoteDisplayStateHandler*
+  lock_screen_note_display_state_handler_for_test() {
+    return lock_screen_note_display_state_handler_.get();
+  }
+
   void AddObserver(TrayActionObserver* observer);
   void RemoveObserver(TrayActionObserver* observer);
 
@@ -54,6 +71,9 @@
                  mojom::TrayActionState lock_screen_note_state) override;
   void UpdateLockScreenNoteState(mojom::TrayActionState state) override;
 
+  // ui::InputDeviceEventObserver:
+  void OnStylusStateChanged(ui::StylusState state) override;
+
   void FlushMojoForTesting();
 
  private:
@@ -61,16 +81,24 @@
   // updated.
   void NotifyLockScreenNoteStateChanged();
 
+  BacklightsForcedOffSetter* const backlights_forced_off_setter_;
+
   // Last known state for lock screen note action.
   mojom::TrayActionState lock_screen_note_state_ =
       mojom::TrayActionState::kNotAvailable;
 
+  std::unique_ptr<LockScreenNoteDisplayStateHandler>
+      lock_screen_note_display_state_handler_;
+
   base::ObserverList<TrayActionObserver> observers_;
 
   mojo::Binding<mojom::TrayAction> binding_;
 
   mojom::TrayActionClientPtr tray_action_client_;
 
+  ScopedObserver<ui::InputDeviceManager, ui::InputDeviceEventObserver>
+      stylus_observer_;
+
   DISALLOW_COPY_AND_ASSIGN(TrayAction);
 };
 
diff --git a/ash/wm/window_positioner.cc b/ash/wm/window_positioner.cc
index 8ceccaa..be12bcd 100644
--- a/ash/wm/window_positioner.cc
+++ b/ash/wm/window_positioner.cc
@@ -21,8 +21,6 @@
 
 namespace ash {
 
-const int WindowPositioner::kMinimumWindowOffset = 32;
-
 // The number of pixels which are kept free top, left and right when a window
 // gets positioned to its default location.
 // static
@@ -280,9 +278,8 @@
       // the top level window and use its restore bounds
       // instead. Offset the bounds to prevent the windows from
       // overlapping exactly when restored.
-      *bounds_in_out =
-          top_window_state->GetRestoreBoundsInScreen() +
-          gfx::Vector2d(kMinimumWindowOffset, kMinimumWindowOffset);
+      *bounds_in_out = top_window_state->GetRestoreBoundsInScreen() +
+                       gfx::Vector2d(kFirstPopupOffset, kFirstPopupOffset);
     }
     if (is_saved_bounds || has_restore_bounds) {
       gfx::Rect work_area = display::Screen::GetScreen()
@@ -394,13 +391,7 @@
     added_window->SetBounds(added_bounds);
 }
 
-WindowPositioner::WindowPositioner()
-    : pop_position_offset_increment_x(0),
-      pop_position_offset_increment_y(0),
-      popup_position_offset_from_screen_corner_x(0),
-      popup_position_offset_from_screen_corner_y(0),
-      last_popup_position_x_(0),
-      last_popup_position_y_(0) {}
+WindowPositioner::WindowPositioner() = default;
 
 WindowPositioner::~WindowPositioner() = default;
 
@@ -423,18 +414,15 @@
                    default_width, default_height);
 }
 
-gfx::Rect WindowPositioner::GetPopupPosition(const gfx::Rect& old_pos) {
-  int grid = kMinimumWindowOffset;
-  popup_position_offset_from_screen_corner_x = grid;
-  popup_position_offset_from_screen_corner_y = grid;
-  if (!pop_position_offset_increment_x) {
-    // When the popup position increment is 0, the last popup position
-    // was not yet initialized.
-    last_popup_position_x_ = popup_position_offset_from_screen_corner_x;
-    last_popup_position_y_ = popup_position_offset_from_screen_corner_y;
+gfx::Rect WindowPositioner::GetPopupPosition(const gfx::Size& popup_size) {
+  if (!has_last_popup_position_) {
+    // Start with the initial offset.
+    // NOTE: This should probably move into NormalPopupPosition() but is here to
+    // match historical behavior.
+    last_popup_position_x_ = kFirstPopupOffset;
+    last_popup_position_y_ = kFirstPopupOffset;
+    has_last_popup_position_ = true;
   }
-  pop_position_offset_increment_x = grid;
-  pop_position_offset_increment_y = grid;
   // We handle the Multi monitor support by retrieving the active window's
   // work area.
   aura::Window* window = wm::GetActiveWindow();
@@ -444,17 +432,16 @@
                 ->GetDisplayNearestWindow(window)
                 .work_area()
           : display::Screen::GetScreen()->GetPrimaryDisplay().work_area();
-  // Only try to reposition the popup when it is not spanning the entire
-  // screen.
-  if ((old_pos.width() + popup_position_offset_from_screen_corner_x >=
-       work_area.width()) ||
-      (old_pos.height() + popup_position_offset_from_screen_corner_y >=
-       work_area.height()))
-    return AlignPopupPosition(old_pos, work_area, grid);
-  const gfx::Rect result = SmartPopupPosition(old_pos, work_area, grid);
+  // If the popup would span the entire display, position it at top-left.
+  if ((popup_size.width() + kFirstPopupOffset >= work_area.width()) ||
+      (popup_size.height() + kFirstPopupOffset >= work_area.height())) {
+    return AlignPopupPosition(gfx::Rect(popup_size), work_area);
+  }
+  const gfx::Rect result = SmartPopupPosition(popup_size, work_area);
   if (!result.IsEmpty())
-    return AlignPopupPosition(result, work_area, grid);
-  return NormalPopupPosition(old_pos, work_area);
+    return AlignPopupPosition(result, work_area);
+
+  return NormalPopupPosition(popup_size, work_area);
 }
 
 // static
@@ -462,10 +449,10 @@
   maximize_first_window = maximize;
 }
 
-gfx::Rect WindowPositioner::NormalPopupPosition(const gfx::Rect& old_pos,
+gfx::Rect WindowPositioner::NormalPopupPosition(const gfx::Size& popup_size,
                                                 const gfx::Rect& work_area) {
-  int w = old_pos.width();
-  int h = old_pos.height();
+  int w = popup_size.width();
+  int h = popup_size.height();
   // Note: The 'last_popup_position' is checked and kept relative to the
   // screen size. The offsetting will be done in the last step when the
   // target rectangle gets returned.
@@ -473,30 +460,29 @@
   if (last_popup_position_y_ + h > work_area.height() ||
       last_popup_position_x_ + w > work_area.width()) {
     // Popup does not fit on screen. Reset to next diagonal row.
-    last_popup_position_x_ -= last_popup_position_y_ -
-                              popup_position_offset_from_screen_corner_x -
-                              pop_position_offset_increment_x;
-    last_popup_position_y_ = popup_position_offset_from_screen_corner_y;
+    last_popup_position_x_ -=
+        last_popup_position_y_ - kFirstPopupOffset - kNextPopupOffset;
+    last_popup_position_y_ = kFirstPopupOffset;
     reset = true;
   }
   if (last_popup_position_x_ + w > work_area.width()) {
     // Start again over.
-    last_popup_position_x_ = popup_position_offset_from_screen_corner_x;
-    last_popup_position_y_ = popup_position_offset_from_screen_corner_y;
+    last_popup_position_x_ = kFirstPopupOffset;
+    last_popup_position_y_ = kFirstPopupOffset;
     reset = true;
   }
   int x = last_popup_position_x_;
   int y = last_popup_position_y_;
   if (!reset) {
-    last_popup_position_x_ += pop_position_offset_increment_x;
-    last_popup_position_y_ += pop_position_offset_increment_y;
+    last_popup_position_x_ += kNextPopupOffset;
+    last_popup_position_y_ += kNextPopupOffset;
   }
   return gfx::Rect(x + work_area.x(), y + work_area.y(), w, h);
 }
 
-gfx::Rect WindowPositioner::SmartPopupPosition(const gfx::Rect& old_pos,
-                                               const gfx::Rect& work_area,
-                                               int grid) {
+// static
+gfx::Rect WindowPositioner::SmartPopupPosition(const gfx::Size& popup_size,
+                                               const gfx::Rect& work_area) {
   const aura::Window::Windows windows =
       Shell::Get()->mru_window_tracker()->BuildWindowListIgnoreModal();
 
@@ -519,8 +505,8 @@
   if (regions.empty())
     return gfx::Rect(0, 0, 0, 0);
 
-  int w = old_pos.width();
-  int h = old_pos.height();
+  int w = popup_size.width();
+  int h = popup_size.height();
   int x_end = work_area.width() / 2;
   int x, x_increment;
   // We parse for a proper location on the screen. We do this in two runs:
@@ -535,10 +521,10 @@
   for (int run = 0; run < 2; run++) {
     if (run == 0) {  // First run: Start left, parse right till mid screen.
       x = 0;
-      x_increment = pop_position_offset_increment_x;
+      x_increment = kNextPopupOffset;
     } else {  // Second run: Start right, parse left till mid screen.
       x = work_area.width() - w;
-      x_increment = -pop_position_offset_increment_x;
+      x_increment = -kNextPopupOffset;
     }
     // Note: The passing (x,y,w,h) window is always relative to the work area's
     // origin.
@@ -561,22 +547,19 @@
   return gfx::Rect(0, 0, 0, 0);
 }
 
+// static
 gfx::Rect WindowPositioner::AlignPopupPosition(const gfx::Rect& pos,
-                                               const gfx::Rect& work_area,
-                                               int grid) {
-  if (grid <= 1)
-    return pos;
-
-  int x = pos.x() - (pos.x() - work_area.x()) % grid;
-  int y = pos.y() - (pos.y() - work_area.y()) % grid;
+                                               const gfx::Rect& work_area) {
+  int x = pos.x() - (pos.x() - work_area.x()) % kPopupGridSize;
+  int y = pos.y() - (pos.y() - work_area.y()) % kPopupGridSize;
   int w = pos.width();
   int h = pos.height();
 
   // If the alignment was pushing the window out of the screen, we ignore the
   // alignment for that call.
-  if (abs(pos.right() - work_area.right()) < grid)
+  if (abs(pos.right() - work_area.right()) < kPopupGridSize)
     x = work_area.right() - w;
-  if (abs(pos.bottom() - work_area.bottom()) < grid)
+  if (abs(pos.bottom() - work_area.bottom()) < kPopupGridSize)
     y = work_area.bottom() - h;
   return gfx::Rect(x, y, w, h);
 }
diff --git a/ash/wm/window_positioner.h b/ash/wm/window_positioner.h
index 10006b3..228b3fd85 100644
--- a/ash/wm/window_positioner.h
+++ b/ash/wm/window_positioner.h
@@ -19,6 +19,7 @@
 
 namespace gfx {
 class Rect;
+class Size;
 }
 
 namespace ash {
@@ -73,12 +74,11 @@
   WindowPositioner();
   ~WindowPositioner();
 
-  // Find a suitable screen position for a popup window and return it. The
-  // passed input position is only used to retrieve the width and height.
+  // Find a suitable screen position for a popup window and return it.
   // The position is determined on the left / right / top / bottom first. If
   // no smart space is found, the position will follow the standard what other
   // operating systems do (default cascading style).
-  gfx::Rect GetPopupPosition(const gfx::Rect& old_pos);
+  gfx::Rect GetPopupPosition(const gfx::Size& popup_size);
 
   // Accessor to set a flag indicating whether the first window in ASH should
   // be maximized.
@@ -89,34 +89,32 @@
 
   // Find a smart way to position the popup window. If there is no space this
   // function will return an empty rectangle.
-  gfx::Rect SmartPopupPosition(const gfx::Rect& old_pos,
-                               const gfx::Rect& work_area,
-                               int grid);
+  static gfx::Rect SmartPopupPosition(const gfx::Size& popup_size,
+                                      const gfx::Rect& work_area);
 
   // Find the next available cascading popup position (on the given screen).
-  gfx::Rect NormalPopupPosition(const gfx::Rect& old_pos,
+  gfx::Rect NormalPopupPosition(const gfx::Size& popup_size,
                                 const gfx::Rect& work_area);
 
   // Align the location to the grid / snap to the right / bottom corner.
-  gfx::Rect AlignPopupPosition(const gfx::Rect& pos,
-                               const gfx::Rect& work_area,
-                               int grid);
+  static gfx::Rect AlignPopupPosition(const gfx::Rect& pos,
+                                      const gfx::Rect& work_area);
 
-  // Constant exposed for unittest.
-  static const int kMinimumWindowOffset;
+  // The grid size in DIPs used to align popup windows.
+  static constexpr int kPopupGridSize = 32;
 
   // The offset in X and Y for the next popup which opens.
-  int pop_position_offset_increment_x;
-  int pop_position_offset_increment_y;
+  static constexpr int kNextPopupOffset = 32;
 
   // The position on the screen for the first popup which gets shown if no
   // empty space can be found.
-  int popup_position_offset_from_screen_corner_x;
-  int popup_position_offset_from_screen_corner_y;
+  static constexpr int kFirstPopupOffset = 32;
 
   // The last used position.
-  int last_popup_position_x_;
-  int last_popup_position_y_;
+  // TODO(jamescook): These seem more like *next* popup position.
+  int last_popup_position_x_ = 0;
+  int last_popup_position_y_ = 0;
+  bool has_last_popup_position_ = false;
 
   DISALLOW_COPY_AND_ASSIGN(WindowPositioner);
 };
diff --git a/base/BUILD.gn b/base/BUILD.gn
index 5aeb3f44..26acacb7 100644
--- a/base/BUILD.gn
+++ b/base/BUILD.gn
@@ -733,6 +733,8 @@
     "strings/pattern.h",
     "strings/safe_sprintf.cc",
     "strings/safe_sprintf.h",
+    "strings/strcat.cc",
+    "strings/strcat.h",
     "strings/string16.cc",
     "strings/string16.h",
     "strings/string_number_conversions.cc",
@@ -2189,6 +2191,7 @@
     "strings/nullable_string16_unittest.cc",
     "strings/pattern_unittest.cc",
     "strings/safe_sprintf_unittest.cc",
+    "strings/strcat_unittest.cc",
     "strings/string16_unittest.cc",
     "strings/string_number_conversions_unittest.cc",
     "strings/string_piece_unittest.cc",
diff --git a/base/android/java/src/org/chromium/base/ApplicationStatus.java b/base/android/java/src/org/chromium/base/ApplicationStatus.java
index 9b3e7b8..fdaf83e 100644
--- a/base/android/java/src/org/chromium/base/ApplicationStatus.java
+++ b/base/android/java/src/org/chromium/base/ApplicationStatus.java
@@ -10,6 +10,7 @@
 import android.app.Application.ActivityLifecycleCallbacks;
 import android.os.Build;
 import android.os.Bundle;
+import android.support.annotation.Nullable;
 import android.view.Window;
 
 import org.chromium.base.annotations.CalledByNative;
@@ -435,8 +436,9 @@
      * @return The state of the specified activity (see {@link ActivityState}).
      */
     @ActivityState
-    public static int getStateForActivity(Activity activity) {
+    public static int getStateForActivity(@Nullable Activity activity) {
         ApplicationStatus.assertInitialized();
+        if (activity == null) return ActivityState.DESTROYED;
         ActivityInfo info = sActivityInfo.get(activity);
         return info != null ? info.getStatus() : ActivityState.DESTROYED;
     }
diff --git a/base/strings/strcat.cc b/base/strings/strcat.cc
new file mode 100644
index 0000000..3d5b2ca
--- /dev/null
+++ b/base/strings/strcat.cc
@@ -0,0 +1,81 @@
+// 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/strings/strcat.h"
+
+namespace base {
+
+namespace {
+
+// Reserves an additional amount of size in the given string, growing by at
+// least 2x. Used by StrAppend().
+//
+// The "at least 2x" growing rule duplicates the exponential growth of
+// std::string. The problem is that most implementations of reserve() will grow
+// exactly to the requested amount instead of exponentially growing like would
+// happen when appending normally. If we didn't do this, an append after the
+// call to StrAppend() would definitely cause a reallocation, and loops with
+// StrAppend() calls would have O(n^2) complexity to execute. Instead, we want
+// StrAppend() to have the same semantics as std::string::append().
+//
+// If the string is empty, we assume that exponential growth is not necessary.
+template <typename String>
+void ReserveAdditional(String* str, typename String::size_type additional) {
+  str->reserve(std::max(str->size() + additional, str->size() * 2));
+}
+
+template <typename DestString, typename InputString>
+void StrAppendT(DestString* dest, span<const InputString> pieces) {
+  size_t additional_size = 0;
+  for (const auto& cur : pieces)
+    additional_size += cur.size();
+  ReserveAdditional(dest, additional_size);
+
+  for (const auto& cur : pieces)
+    dest->append(cur.data(), cur.size());
+}
+
+}  // namespace
+
+std::string StrCat(span<const StringPiece> pieces) {
+  std::string result;
+  StrAppendT(&result, pieces);
+  return result;
+}
+
+string16 StrCat(span<const StringPiece16> pieces) {
+  string16 result;
+  StrAppendT(&result, pieces);
+  return result;
+}
+
+std::string StrCat(span<const std::string> pieces) {
+  std::string result;
+  StrAppendT(&result, pieces);
+  return result;
+}
+
+string16 StrCat(span<const string16> pieces) {
+  string16 result;
+  StrAppendT(&result, pieces);
+  return result;
+}
+
+void StrAppend(std::string* dest, span<const StringPiece> pieces) {
+  StrAppendT(dest, pieces);
+}
+
+void StrAppend(string16* dest, span<const StringPiece16> pieces) {
+  StrAppendT(dest, pieces);
+}
+
+void StrAppend(std::string* dest, span<const std::string> pieces) {
+  StrAppendT(dest, pieces);
+}
+
+void StrAppend(string16* dest, span<const string16> pieces) {
+  StrAppendT(dest, pieces);
+}
+
+}  // namespace base
diff --git a/base/strings/strcat.h b/base/strings/strcat.h
new file mode 100644
index 0000000..b249d49
--- /dev/null
+++ b/base/strings/strcat.h
@@ -0,0 +1,93 @@
+// 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_STRINGS_STRCAT_H_
+#define BASE_STRINGS_STRCAT_H_
+
+#include <initializer_list>
+
+#include "base/base_export.h"
+#include "base/compiler_specific.h"
+#include "base/containers/span.h"
+#include "base/strings/string_piece.h"
+
+namespace base {
+
+// StrCat ----------------------------------------------------------------------
+//
+// StrCat is a function to perform concatenation on a sequence of strings.
+// It is preferrable to a sequence of "a + b + c" because it is both faster and
+// generates less code.
+//
+//   std::string result = base::StrCat({"foo ", result, "\nfoo ", bar});
+//
+// To join an array of strings with a separator, see base::JoinString in
+// base/strings/string_util.h.
+//
+// MORE INFO
+//
+// StrCat can see all arguments at once, so it can allocate one return buffer
+// of exactly the right size and copy once, as opposed to a sequence of
+// operator+ which generates a series of temporary strings, copying as it goes.
+// And by using StringPiece arguments, StrCat can avoid creating temporary
+// string objects for char* constants.
+//
+// ALTERNATIVES
+//
+// Internal Google / Abseil has a similar StrCat function. That version takes
+// an overloaded number of arguments instead of initializer list (overflowing
+// to initializer list for many arguments). We don't have any legacy
+// requirements and using only initializer_list is simpler and generates
+// roughly the same amount of code at the call sites.
+//
+// Abseil's StrCat also allows numbers by using an intermediate class that can
+// be implicitly constructed from either a string or various number types. This
+// class formats the numbers into a static buffer for increased performance,
+// and the call sites look nice.
+//
+// As-written Abseil's helper class for numbers generates slightly more code
+// than the raw StringPiece version. We can de-inline the helper class'
+// constructors which will cause the StringPiece constructors to be de-inlined
+// for this call and generate slightly less code. This is something we can
+// explore more in the future.
+
+BASE_EXPORT std::string StrCat(span<const StringPiece> pieces);
+BASE_EXPORT string16 StrCat(span<const StringPiece16> pieces);
+BASE_EXPORT std::string StrCat(span<const std::string> pieces);
+BASE_EXPORT string16 StrCat(span<const string16> pieces);
+
+// Initializer list forwards to the array version.
+inline std::string StrCat(std::initializer_list<StringPiece> pieces) {
+  return StrCat(make_span(pieces.begin(), pieces.size()));
+}
+inline string16 StrCat(std::initializer_list<StringPiece16> pieces) {
+  return StrCat(make_span(pieces.begin(), pieces.size()));
+}
+
+// StrAppend -------------------------------------------------------------------
+//
+// Appends a sequence of strings to a destination. Prefer:
+//   StrAppend(&foo, ...);
+// over:
+//   foo += StrCat(...);
+// because it avoids a temporary string allocation and copy.
+
+BASE_EXPORT void StrAppend(std::string* dest, span<const StringPiece> pieces);
+BASE_EXPORT void StrAppend(string16* dest, span<const StringPiece16> pieces);
+BASE_EXPORT void StrAppend(std::string* dest, span<const std::string> pieces);
+BASE_EXPORT void StrAppend(string16* dest, span<const string16> pieces);
+
+// Initializer list forwards to the array version.
+inline void StrAppend(std::string* dest,
+                      std::initializer_list<StringPiece> pieces) {
+  return StrAppend(dest, make_span(pieces.begin(), pieces.size()));
+}
+inline void StrAppend(string16* dest,
+                      std::initializer_list<StringPiece16> pieces) {
+  return StrAppend(dest, make_span(pieces.begin(), pieces.size()));
+}
+
+}  // namespace base
+
+#endif  // BASE_STRINGS_STRCAT_H_
diff --git a/base/strings/strcat_unittest.cc b/base/strings/strcat_unittest.cc
new file mode 100644
index 0000000..cf2db518
--- /dev/null
+++ b/base/strings/strcat_unittest.cc
@@ -0,0 +1,67 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/strings/strcat.h"
+#include "base/strings/utf_string_conversions.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+TEST(StrCat, 8Bit) {
+  EXPECT_EQ("", StrCat({""}));
+  EXPECT_EQ("1", StrCat({"1"}));
+  EXPECT_EQ("122", StrCat({"1", "22"}));
+  EXPECT_EQ("122333", StrCat({"1", "22", "333"}));
+  EXPECT_EQ("1223334444", StrCat({"1", "22", "333", "4444"}));
+  EXPECT_EQ("122333444455555", StrCat({"1", "22", "333", "4444", "55555"}));
+}
+
+TEST(StrCat, 16Bit) {
+  string16 arg1 = ASCIIToUTF16("1");
+  string16 arg2 = ASCIIToUTF16("22");
+  string16 arg3 = ASCIIToUTF16("333");
+
+  EXPECT_EQ(ASCIIToUTF16(""), StrCat({string16()}));
+  EXPECT_EQ(ASCIIToUTF16("1"), StrCat({arg1}));
+  EXPECT_EQ(ASCIIToUTF16("122"), StrCat({arg1, arg2}));
+  EXPECT_EQ(ASCIIToUTF16("122333"), StrCat({arg1, arg2, arg3}));
+}
+
+TEST(StrAppend, 8Bit) {
+  std::string result;
+
+  result = "foo";
+  StrAppend(&result, {std::string()});
+  EXPECT_EQ("foo", result);
+
+  result = "foo";
+  StrAppend(&result, {"1"});
+  EXPECT_EQ("foo1", result);
+
+  result = "foo";
+  StrAppend(&result, {"1", "22", "333"});
+  EXPECT_EQ("foo122333", result);
+}
+
+TEST(StrAppend, 16Bit) {
+  string16 arg1 = ASCIIToUTF16("1");
+  string16 arg2 = ASCIIToUTF16("22");
+  string16 arg3 = ASCIIToUTF16("333");
+
+  string16 result;
+
+  result = ASCIIToUTF16("foo");
+  StrAppend(&result, {string16()});
+  EXPECT_EQ(ASCIIToUTF16("foo"), result);
+
+  result = ASCIIToUTF16("foo");
+  StrAppend(&result, {arg1});
+  EXPECT_EQ(ASCIIToUTF16("foo1"), result);
+
+  result = ASCIIToUTF16("foo");
+  StrAppend(&result, {arg1, arg2, arg3});
+  EXPECT_EQ(ASCIIToUTF16("foo122333"), result);
+}
+
+}  // namespace base
diff --git a/base/strings/string_util.h b/base/strings/string_util.h
index 55ceb44..7603eed 100644
--- a/base/strings/string_util.h
+++ b/base/strings/string_util.h
@@ -437,6 +437,8 @@
 // strings. For example, instead of using SplitString, modifying the vector,
 // then using JoinString, use SplitStringPiece followed by JoinString so that no
 // copies of those strings are created until the final join operation.
+//
+// Use StrCat (in base/strings/strcat.h) if you don't need a separator.
 BASE_EXPORT std::string JoinString(const std::vector<std::string>& parts,
                                    StringPiece separator);
 BASE_EXPORT string16 JoinString(const std::vector<string16>& parts,
diff --git a/build/android/BUILD.gn b/build/android/BUILD.gn
index b07bf34..dd501338 100644
--- a/build/android/BUILD.gn
+++ b/build/android/BUILD.gn
@@ -34,7 +34,9 @@
 
   java_prebuilt("sun_tools_java") {
     jar_path = sun_tools_jar_path
-    jar_dep = ":find_sun_tools_jar"
+    deps = [
+      ":find_sun_tools_jar",
+    ]
   }
 
   generate_interface_jar("android_ijar") {
diff --git a/build/android/gyp/create_java_binary_script.py b/build/android/gyp/create_java_binary_script.py
index 3bde1c3..141b175 100755
--- a/build/android/gyp/create_java_binary_script.py
+++ b/build/android/gyp/create_java_binary_script.py
@@ -69,7 +69,6 @@
   parser = optparse.OptionParser()
   build_utils.AddDepfileOption(parser)
   parser.add_option('--output', help='Output path for executable script.')
-  parser.add_option('--jar-path', help='Path to the main jar.')
   parser.add_option('--main-class',
       help='Name of the java class with the "main" entry point.')
   parser.add_option('--classpath', action='append', default=[],
@@ -86,7 +85,7 @@
   else:
     noverify_flag = ''
 
-  classpath = [options.jar_path]
+  classpath = []
   for cp_arg in options.classpath:
     classpath += build_utils.ParseGnList(cp_arg)
 
diff --git a/build/android/gyp/write_build_config.py b/build/android/gyp/write_build_config.py
index 3df54532..2b038236 100755
--- a/build/android/gyp/write_build_config.py
+++ b/build/android/gyp/write_build_config.py
@@ -287,6 +287,8 @@
 
   # java library options
   parser.add_option('--jar-path', help='Path to target\'s jar output.')
+  parser.add_option('--is-prebuilt', action='store_true',
+                    help='Whether the jar was compiled or pre-compiled.')
   parser.add_option('--java-sources-file', help='Path to .sources file')
   parser.add_option('--bundled-srcjars',
       help='GYP-list of .srcjars that have been included in this java_library.')
@@ -352,10 +354,9 @@
     parser.error('\n'.join(build_utils.ParseGnList(options.fail)))
 
   required_options_map = {
-      'java_binary': ['build_config', 'jar_path'],
-      'junit_binary': ['build_config', 'jar_path'],
+      'java_binary': ['build_config'],
+      'junit_binary': ['build_config'],
       'java_library': ['build_config', 'jar_path'],
-      'java_prebuilt': ['build_config', 'jar_path'],
       'android_assets': ['build_config'],
       'android_resources': ['build_config', 'resources_zip'],
       'android_apk': ['build_config', 'jar_path', 'dex_path'],
@@ -370,11 +371,6 @@
 
   build_utils.CheckOptions(options, parser, required_options)
 
-  # Java prebuilts are the same as libraries except for in gradle files.
-  is_java_prebuilt = options.type == 'java_prebuilt'
-  if is_java_prebuilt:
-    options.type = 'java_library'
-
   if options.type == 'java_library':
     if options.supports_android and not options.dex_path:
       raise Exception('java_library that supports Android requires a dex path.')
@@ -424,7 +420,7 @@
 
   # Required for generating gradle files.
   if options.type == 'java_library':
-    deps_info['is_prebuilt'] = is_java_prebuilt
+    deps_info['is_prebuilt'] = bool(options.is_prebuilt)
     deps_info['gradle_treat_as_prebuilt'] = options.gradle_treat_as_prebuilt
 
   if options.android_manifest:
@@ -485,9 +481,10 @@
 
   if options.type in (
       'java_binary', 'junit_binary', 'java_library', 'android_apk'):
-    deps_info['jar_path'] = options.jar_path
-    if options.type == 'android_apk' or options.supports_android:
-      deps_info['dex_path'] = options.dex_path
+    if options.jar_path:
+      deps_info['jar_path'] = options.jar_path
+      if options.type == 'android_apk' or options.supports_android:
+        deps_info['dex_path'] = options.dex_path
     if options.type == 'android_apk':
       deps_info['apk_path'] = options.apk_path
       deps_info['incremental_apk_path'] = options.incremental_apk_path
@@ -496,12 +493,10 @@
       deps_info['non_native_packed_relocations'] = str(
           options.non_native_packed_relocations)
 
-  requires_javac_classpath = options.type in (
+  requires_classpath = options.type in (
       'java_binary', 'junit_binary', 'java_library', 'android_apk', 'dist_jar')
-  requires_full_classpath = (
-      options.type == 'java_prebuilt' or requires_javac_classpath)
 
-  if requires_javac_classpath:
+  if requires_classpath:
     # Classpath values filled in below (after applying tested_apk_config).
     config['javac'] = {}
 
@@ -600,7 +595,7 @@
   if options.type in ['android_apk', 'deps_dex']:
     deps_dex_files = [c['dex_path'] for c in all_library_deps]
 
-  if requires_javac_classpath:
+  if requires_classpath:
     extra_jars = []
     if options.extra_classpath_jars:
       extra_jars += build_utils.ParseGnList(options.extra_classpath_jars)
@@ -612,8 +607,7 @@
           c['jar_path'] for c in classpath_deps.Direct('java_library')]
 
     javac_classpath = [c['jar_path'] for c in direct_library_deps]
-    if requires_full_classpath:
-      java_full_classpath = [c['jar_path'] for c in all_library_deps]
+    java_full_classpath = [c['jar_path'] for c in all_library_deps]
 
     if extra_jars:
       deps_info['extra_classpath_jars'] = extra_jars
@@ -693,15 +687,13 @@
     dex_config = config['final_dex']
     dex_config['dependency_dex_files'] = deps_dex_files
 
-  if requires_javac_classpath:
+  if requires_classpath:
     config['javac']['classpath'] = javac_classpath
     javac_interface_classpath = [
         _AsInterfaceJar(p) for p in javac_classpath
         if p not in deps_info.get('extra_classpath_jars', [])]
     javac_interface_classpath += deps_info.get('extra_classpath_jars', [])
     config['javac']['interface_classpath'] = javac_interface_classpath
-
-  if requires_full_classpath:
     deps_info['java'] = {
       'full_classpath': java_full_classpath,
     }
diff --git a/build/config/android/internal_rules.gni b/build/config/android/internal_rules.gni
index f3ab85cb..f0cd33f7 100644
--- a/build/config/android/internal_rules.gni
+++ b/build/config/android/internal_rules.gni
@@ -53,12 +53,10 @@
 # build/android/gyp/util/build_utils.py:ExpandFileArgs
 template("write_build_config") {
   type = invoker.type
-  _is_prebuilt_binary =
-      defined(invoker.is_prebuilt_binary) && invoker.is_prebuilt_binary
 
   # Don't need to enforce naming scheme for these targets since we never
   # consider them in dependency chains.
-  if (!_is_prebuilt_binary && type != "android_apk" && type != "java_binary" &&
+  if (type != "android_apk" && type != "java_binary" &&
       type != "resource_rewriter" && type != "dist_jar") {
     set_sources_assignment_filter(_java_target_whitelist)
     _parent_invoker = invoker.invoker
@@ -88,7 +86,7 @@
            type == "android_resources" || type == "deps_dex" ||
            type == "dist_jar" || type == "android_assets" ||
            type == "resource_rewriter" || type == "java_binary" ||
-           type == "group" || type == "java_prebuilt" || type == "junit_binary")
+           type == "group" || type == "junit_binary")
 
     forward_variables_from(invoker,
                            [
@@ -192,6 +190,9 @@
     if (requires_android) {
       args += [ "--requires-android" ]
     }
+    if (defined(invoker.is_prebuilt) && invoker.is_prebuilt) {
+      args += [ "--is-prebuilt" ]
+    }
     if (defined(invoker.bypass_platform_checks) &&
         invoker.bypass_platform_checks) {
       args += [ "--bypass-platform-checks" ]
@@ -918,50 +919,54 @@
   #
   # Variables
   #   main_class: The class containing the program entry point.
-  #   jar_path: The path to the jar to run.
+  #   jar_file: Optional first classpath entry.
   #   script_name: Name of the script to generate.
   #   build_config: Path to .build_config for the jar (contains classpath).
   #   wrapper_script_args: List of extra arguments to pass to the executable.
   #
   template("java_binary_script") {
-    set_sources_assignment_filter([])
-    forward_variables_from(invoker, [ "testonly" ])
-
-    _main_class = invoker.main_class
-    _build_config = invoker.build_config
-    _jar_path = invoker.jar_path
-    _script_name = invoker.script_name
-
     action(target_name) {
+      forward_variables_from(invoker,
+                             [
+                               "deps",
+                               "testonly",
+                             ])
+
+      _main_class = invoker.main_class
+      _build_config = invoker.build_config
+      _script_name = invoker.script_name
+
       script = "//build/android/gyp/create_java_binary_script.py"
       depfile = "$target_gen_dir/$_script_name.d"
-      java_script = "$root_build_dir/bin/$_script_name"
+      _java_script = "$root_build_dir/bin/$_script_name"
       inputs = [
         _build_config,
       ]
       outputs = [
-        java_script,
+        _java_script,
       ]
-      forward_variables_from(invoker, [ "deps" ])
       _rebased_build_config = rebase_path(_build_config, root_build_dir)
       args = [
         "--depfile",
         rebase_path(depfile, root_build_dir),
         "--output",
-        rebase_path(java_script, root_build_dir),
-        "--classpath=@FileArg($_rebased_build_config:deps_info:java:full_classpath)",
-        "--jar-path",
-        rebase_path(_jar_path, root_build_dir),
+        rebase_path(_java_script, root_build_dir),
         "--main-class",
         _main_class,
       ]
+      if (defined(invoker.jar_path)) {
+        _jar_path_list = [ rebase_path(invoker.jar_path, root_build_dir) ]
+        args += [ "--classpath=$_jar_path_list" ]
+      }
+      args += [ "--classpath=@FileArg($_rebased_build_config:deps_info:java:full_classpath)" ]
+
       if (emma_coverage) {
         args += [
           "--classpath",
           rebase_path("//third_party/android_tools/sdk/tools/lib/emma.jar",
                       root_build_dir),
+          "--noverify",
         ]
-        args += [ "--noverify" ]
       }
       if (defined(invoker.wrapper_script_args)) {
         args += [ "--" ] + invoker.wrapper_script_args
@@ -1332,6 +1337,7 @@
       forward_variables_from(invoker,
                              [
                                "deps",
+                               "public_deps",
                                "testonly",
                              ])
 
@@ -1383,6 +1389,9 @@
   # Runs process_resources.py
   template("process_resources") {
     _process_resources_target_name = target_name
+    if (defined(invoker.srcjar_path)) {
+      _srcjar_path = invoker.srcjar_path
+    }
     if (defined(invoker.output)) {
       _post_process = defined(invoker.post_process_script)
       _packaged_resources_path = invoker.output
@@ -1392,6 +1401,11 @@
             get_path_info(_packaged_resources_path, "dir") + "/" +
             get_path_info(_packaged_resources_path, "name") +
             ".intermediate.ap_"
+
+        # TODO(estevenson): Remove this check.
+        if (defined(invoker.post_process_args)) {
+          _srcjar_path = "${_srcjar_path}.intermediate.srcjar"
+        }
       }
     }
     action(_process_resources_target_name) {
@@ -1508,11 +1522,11 @@
         ]
       }
 
-      if (defined(invoker.srcjar_path)) {
-        outputs += [ invoker.srcjar_path ]
+      if (defined(_srcjar_path)) {
+        outputs += [ _srcjar_path ]
         args += [
           "--srcjar-out",
-          rebase_path(invoker.srcjar_path, root_build_dir),
+          rebase_path(_srcjar_path, root_build_dir),
         ]
       }
 
@@ -1627,6 +1641,19 @@
         public_deps = [
           ":${_process_resources_target_name}",
         ]
+
+        # TODO(estevenson): Remove this check.
+        if (defined(invoker.post_process_args)) {
+          args += [
+                    "--srcjar-in",
+                    rebase_path(_srcjar_path, root_build_dir),
+                    "--srcjar-out",
+                    rebase_path(invoker.srcjar_path, root_build_dir),
+                  ] + invoker.post_process_args
+          inputs += [ _srcjar_path ]
+          outputs += [ invoker.srcjar_path ]
+          public_deps += invoker.post_process_deps
+        }
       }
     }
   }
@@ -2039,226 +2066,17 @@
     }
   }
 
-  template("java_prebuilt_impl") {
-    set_sources_assignment_filter([])
-    forward_variables_from(invoker, [ "testonly" ])
-    _supports_android =
-        defined(invoker.supports_android) && invoker.supports_android
-    _requires_android =
-        defined(invoker.requires_android) && invoker.requires_android
-
-    assert(defined(invoker.jar_path))
-    if (defined(invoker.output_name)) {
-      _output_name = invoker.output_name
-    } else {
-      _output_name = get_path_info(invoker.jar_path, "name")
-    }
-    _base_path = "${target_gen_dir}/$target_name"
-
-    # Jar files can be needed at runtime (by Robolectric tests or java binaries),
-    # so do not put them under gen/.
-    _target_dir_name = get_label_info(":$target_name", "dir")
-    _jar_path = "$root_out_dir/lib.java$_target_dir_name/$_output_name.jar"
-    _ijar_path =
-        "$root_out_dir/lib.java$_target_dir_name/$_output_name.interface.jar"
-    _build_config = _base_path + ".build_config"
-
-    if (_supports_android) {
-      _dex_path = _base_path + ".dex.jar"
-    }
-    _deps = []
-    if (defined(invoker.deps)) {
-      _deps = invoker.deps
-    }
-    _jar_deps = []
-    if (defined(invoker.jar_dep)) {
-      _jar_deps = [ invoker.jar_dep ]
-    }
-
-    _template_name = target_name
-
-    _build_config_target_name = "${_template_name}__build_config"
-    _process_jar_target_name = "${_template_name}__process_jar"
-    _ijar_target_name = "${_template_name}__ijar"
-    if (_supports_android) {
-      _dex_target_name = "${_template_name}__dex"
-    }
-
-    _enable_build_hooks =
-        _supports_android &&
-        (!defined(invoker.no_build_hooks) || !invoker.no_build_hooks)
-    if (_enable_build_hooks) {
-      _deps += [ "//build/android/buildhooks:build_hooks_java" ]
-    }
-
-    # Some testonly targets use their own resources and the code being
-    # tested will use custom resources so there's no need to enable this
-    # for testonly targets.
-    _enable_build_hooks_android =
-        _enable_build_hooks && _requires_android &&
-        (!defined(invoker.testonly) || !invoker.testonly)
-    if (_enable_build_hooks_android) {
-      _deps += [ "//build/android/buildhooks:build_hooks_android_java" ]
-    }
-
-    write_build_config(_build_config_target_name) {
-      type = "java_prebuilt"
-      is_prebuilt_binary = defined(invoker.main_class)
-      forward_variables_from(invoker,
-                             [
-                               "input_jars_paths",
-                               "proguard_configs",
-                             ])
-      supports_android = _supports_android
-      requires_android = _requires_android
-
-      if (defined(invoker.deps)) {
-        possible_config_deps = _deps
-      }
-      build_config = _build_config
-      jar_path = _jar_path
-      if (_supports_android) {
-        dex_path = _dex_path
-      }
-      if (defined(invoker.include_java_resources) &&
-          invoker.include_java_resources) {
-        # Use original jar_path because _jar_path points to a library without
-        # resources.
-        java_resources_jar = invoker.jar_path
-      }
-    }
-
-    process_java_prebuilt(_process_jar_target_name) {
-      forward_variables_from(invoker,
-                             [
-                               "jar_excluded_patterns",
-                               "strip_resource_classes",
-                             ])
-
-      visibility = [
-        ":$_ijar_target_name",
-        ":$_template_name",
-      ]
-      if (_supports_android) {
-        visibility += [ ":$_dex_target_name" ]
-      }
-
-      supports_android = _supports_android
-      enable_build_hooks = _enable_build_hooks
-      enable_build_hooks_android = _enable_build_hooks_android
-      build_config = _build_config
-      input_jar_path = invoker.jar_path
-      output_jar_path = _jar_path
-
-      deps = [ ":$_build_config_target_name" ] + _deps + _jar_deps
-    }
-
-    generate_interface_jar(_ijar_target_name) {
-      # Always used the unfiltered .jar to create the interface jar so that
-      # other targets will resolve filtered classes when depending on
-      # BuildConfig, NativeLibraries, etc.
-      input_jar = invoker.jar_path
-      deps = _deps + _jar_deps
-      output_jar = _ijar_path
-    }
-
-    if (_supports_android) {
-      dex(_dex_target_name) {
-        sources = [
-          _jar_path,
-        ]
-        output = _dex_path
-        deps = [ ":$_process_jar_target_name" ] + _deps + _jar_deps
-      }
-    }
-
-    if (defined(invoker.main_class)) {
-      _binary_script_target_name = "${_template_name}__java_binary_script"
-      java_binary_script(_binary_script_target_name) {
-        forward_variables_from(invoker,
-                               [
-                                 "bootclasspath",
-                                 "deps",
-                                 "main_class",
-                                 "wrapper_script_args",
-                               ])
-        if (!defined(deps)) {
-          deps = []
-        }
-        build_config = _build_config
-        jar_path = _jar_path
-        script_name = _template_name
-        if (defined(invoker.wrapper_script_name)) {
-          script_name = invoker.wrapper_script_name
-        }
-        deps += [ ":$_build_config_target_name" ]
-      }
-    }
-
-    group(target_name) {
-      forward_variables_from(invoker,
-                             [
-                               "data",
-                               "data_deps",
-                               "visibility",
-                             ])
-      public_deps = [
-        ":$_ijar_target_name",
-        ":$_process_jar_target_name",
-      ]
-      if (_supports_android) {
-        public_deps += [ ":$_dex_target_name" ]
-      }
-      if (defined(invoker.main_class)) {
-        # Some targets use the generated script while building, so make it a dep
-        # rather than a data_dep.
-        public_deps += [ ":$_binary_script_target_name" ]
-      }
-    }
-  }
-
-  # Compiles and jars a set of java files.
-  #
-  # Outputs:
-  #  $jar_path.jar
-  #  $jar_path.interface.jar
-  #
-  # Variables
-  #   java_files: List of .java files to compile (same as exists in java_sources_file)
-  #   java_sources_file: Path to file containing list of files to compile.
-  #   chromium_code: If true, enable extra warnings.
-  #   srcjar_deps: List of srcjar dependencies. The .java files contained in the
-  #     dependencies srcjar outputs will be compiled and added to the output jar.
-  #   jar_path: Use this to explicitly set the output jar path. Defaults to
-  #     "${target_gen_dir}/${target_name}.jar.
-  #   javac_args: Additional arguments to pass to javac.
   template("compile_java") {
-    set_sources_assignment_filter([])
     forward_variables_from(invoker, [ "testonly" ])
 
-    assert(defined(invoker.build_config))
-    assert(defined(invoker.jar_path))
-
     _build_config = invoker.build_config
+    _chromium_code = invoker.chromium_code
+    _requires_android = invoker.requires_android
 
-    _chromium_code = false
-    if (defined(invoker.chromium_code)) {
-      _chromium_code = invoker.chromium_code
-    }
-
-    _supports_android = true
-    if (defined(invoker.supports_android)) {
-      _supports_android = invoker.supports_android
-    }
-
-    _requires_android =
-        defined(invoker.requires_android) && invoker.requires_android
-
-    _enable_errorprone = use_errorprone_java_compiler
-    if (!_chromium_code) {
-      _enable_errorprone = false
-    } else if (defined(invoker.enable_errorprone)) {
+    if (defined(invoker.enable_errorprone)) {
       _enable_errorprone = invoker.enable_errorprone
+    } else {
+      _enable_errorprone = use_errorprone_java_compiler && _chromium_code
     }
 
     _provider_configurations = []
@@ -2302,9 +2120,6 @@
     }
 
     _java_srcjars = []
-    if (defined(invoker.srcjars)) {
-      _java_srcjars = invoker.srcjars
-    }
     foreach(dep, _srcjar_deps) {
       _dep_gen_dir = get_label_info(dep, "target_gen_dir")
       _dep_name = get_label_info(dep, "name")
@@ -2316,31 +2131,11 @@
       _javac_args = invoker.javac_args
     }
 
-    # Mark srcjar_deps as used.
-    assert(_srcjar_deps == [] || true)
-
-    _javac_target_name = "${target_name}__javac"
-    _process_prebuilt_target_name = "${target_name}__process_prebuilt"
-    _ijar_target_name = "${target_name}__ijar"
-    _final_target_name = target_name
-
-    _final_jar_path = invoker.jar_path
-    _javac_jar_path = "$target_gen_dir/$target_name.javac.jar"
-    _process_prebuilt_jar_path = _final_jar_path
-    _final_ijar_path = get_path_info(_final_jar_path, "dir") + "/" +
-                       get_path_info(_final_jar_path, "name") + ".interface.jar"
-
-    _emma_instrument = defined(invoker.emma_instrument) &&
-                       invoker.emma_instrument && invoker.java_files != []
-    if (_emma_instrument) {
-      _emma_instr_target_name = "${target_name}__emma_instr"
-      _process_prebuilt_jar_path =
-          "$target_gen_dir/$target_name.process_prebuilt.jar"
+    _javac_target_name = target_name
+    if (defined(invoker.instrumented_jar_path)) {
+      _javac_target_name = "${target_name}__javac"
     }
 
-    _rebased_build_config = rebase_path(_build_config, root_build_dir)
-    _rebased_jar_path = rebase_path(_javac_jar_path, root_build_dir)
-
     action(_javac_target_name) {
       script = "//build/android/gyp/javac.py"
       depfile = "$target_gen_dir/$target_name.d"
@@ -2350,22 +2145,22 @@
       }
 
       outputs = [
-        _javac_jar_path,
-        _javac_jar_path + ".md5.stamp",
+        invoker.javac_jar_path,
+        invoker.javac_jar_path + ".md5.stamp",
       ]
-      sources = invoker.java_files + _java_srcjars
-      inputs = [
-        _build_config,
-      ]
+      inputs = invoker.java_files + _java_srcjars + [ _build_config ]
       if (invoker.java_files != []) {
         inputs += [ invoker.java_sources_file ]
       }
 
+      _rebased_build_config = rebase_path(_build_config, root_build_dir)
+      _rebased_javac_jar_path =
+          rebase_path(invoker.javac_jar_path, root_build_dir)
       _rebased_java_srcjars = rebase_path(_java_srcjars, root_build_dir)
       _rebased_depfile = rebase_path(depfile, root_build_dir)
       args = [
         "--depfile=$_rebased_depfile",
-        "--jar-path=$_rebased_jar_path",
+        "--jar-path=$_rebased_javac_jar_path",
         "--java-srcjars=$_rebased_java_srcjars",
         "--java-srcjars=@FileArg($_rebased_build_config:javac:srcjars)",
         "--java-version=1.8",
@@ -2380,7 +2175,7 @@
         args += [ "--incremental" ]
         deps += [ "//third_party/jmake($default_toolchain)" ]
         inputs += [ "$root_build_dir/bin/jmake" ]
-        outputs += [ "${_javac_jar_path}.pdb" ]
+        outputs += [ "${invoker.javac_jar_path}.pdb" ]
       }
       if (_requires_android) {
         if (defined(invoker.alternative_android_sdk_ijar)) {
@@ -2402,12 +2197,11 @@
         args += [ "--chromium-code=1" ]
       }
       if (_enable_errorprone) {
-        deps +=
-            [ "//third_party/errorprone:errorprone_java($default_toolchain)" ]
+        deps += [ "//third_party/errorprone:errorprone($default_toolchain)" ]
         deps += [ "//tools/android/errorprone_plugin:errorprone_plugin_java($default_toolchain)" ]
         args += [
           "--use-errorprone-path",
-          "bin/errorprone_java",
+          "bin/errorprone",
           "--processorpath",
           "lib.java/tools/android/errorprone_plugin/errorprone_plugin_java.jar",
         ]
@@ -2436,31 +2230,8 @@
       }
     }
 
-    process_java_prebuilt(_process_prebuilt_target_name) {
-      forward_variables_from(invoker,
-                             [
-                               "alternative_android_sdk_ijar",
-                               "alternative_android_sdk_ijar_dep",
-                               "alternative_android_sdk_jar",
-                               "enable_build_hooks",
-                               "enable_build_hooks_android",
-                               "jar_excluded_patterns",
-                             ])
-      supports_android = _supports_android
-      build_config = _build_config
-      input_jar_path = _javac_jar_path
-      output_jar_path = _process_prebuilt_jar_path
-
-      deps = [
-        ":$_javac_target_name",
-      ]
-      if (defined(invoker.deps)) {
-        deps += invoker.deps
-      }
-    }
-
-    if (_emma_instrument) {
-      emma_instr(_emma_instr_target_name) {
+    if (defined(invoker.instrumented_jar_path)) {
+      emma_instr(target_name) {
         forward_variables_from(invoker,
                                [
                                  "deps",
@@ -2468,37 +2239,11 @@
                                  "java_sources_file",
                                ])
 
-        input_jar_path = _process_prebuilt_jar_path
-        output_jar_path = _final_jar_path
-
-        if (!defined(deps)) {
-          deps = []
-        }
-        deps += [ ":$_process_prebuilt_target_name" ]
-      }
-    }
-
-    generate_interface_jar(_ijar_target_name) {
-      # Always used the unfiltered .jar to create the interface jar so that
-      # other targets will resolve filtered classes when depending on
-      # BuildConfig, NativeLibraries, etc.
-      input_jar = _javac_jar_path
-      deps = [
-        ":$_javac_target_name",
-      ]
-      output_jar = _final_ijar_path
-    }
-
-    group(_final_target_name) {
-      forward_variables_from(invoker, [ "visibility" ])
-      public_deps = [
-        ":$_ijar_target_name",
-        ":$_javac_target_name",
-      ]
-      if (_emma_instrument) {
-        public_deps += [ ":$_emma_instr_target_name" ]
-      } else {
-        public_deps += [ ":$_process_prebuilt_target_name" ]
+        input_jar_path = invoker.javac_jar_path
+        output_jar_path = invoker.instrumented_jar_path
+        public_deps = [
+          ":$_javac_target_name",
+        ]
       }
     }
   }
@@ -2506,49 +2251,76 @@
   template("java_library_impl") {
     set_sources_assignment_filter([])
     forward_variables_from(invoker, [ "testonly" ])
-    _accumulated_deps = []
-    if (defined(invoker.deps)) {
-      _accumulated_deps = invoker.deps
-    }
-
-    # Caller overriding build config must have valid java sources file if it has
-    # java files.
-    assert(!defined(invoker.override_build_config) ||
-           !defined(invoker.java_files) || defined(invoker.java_sources_file))
-
-    assert(defined(invoker.java_files) || defined(invoker.srcjars) ||
-           defined(invoker.srcjar_deps))
-    _base_path = "$target_gen_dir/$target_name"
-    assert(_base_path != "")  # Mark as used
-
-    if (defined(invoker.output_name)) {
-      _output_name = invoker.output_name
-    } else {
-      _output_name = target_name
-    }
-
-    # Jar files can be needed at runtime (by Robolectric tests or java binaries),
-    # so do not put them under gen/.
-    target_dir_name = get_label_info(":$target_name", "dir")
-    _jar_path = "$root_out_dir/lib.java$target_dir_name/$_output_name.jar"
-    if (defined(invoker.jar_path)) {
-      _jar_path = invoker.jar_path
-    }
     _template_name = target_name
+    _is_prebuilt = defined(invoker.jar_path)
+    _is_java_binary = defined(invoker.is_java_binary) && invoker.is_java_binary
 
-    _final_deps = []
+    _java_files = []
+    if (defined(invoker.java_files)) {
+      _java_files = invoker.java_files
+    }
+    _srcjar_deps = []
+    if (defined(invoker.srcjar_deps)) {
+      _srcjar_deps = invoker.srcjar_deps
+    }
+    _has_sources = _java_files != [] || _srcjar_deps != []
+
+    if (_is_prebuilt) {
+      assert(!_has_sources)
+    } else {
+      # Caller overriding build config must have valid java sources file if it has
+      # java files.
+      assert(!defined(invoker.override_build_config) || _java_files == [] ||
+             defined(invoker.java_sources_file))
+
+      # Allow java_binary to not specify any sources. This is needed when a prebuilt
+      # is needed as a library as well as a binary.
+      assert(_is_java_binary || _has_sources)
+    }
+
+    if (_is_java_binary) {
+      assert(defined(invoker.main_class), "java_binary() must set main_class")
+    } else {
+      assert(!defined(invoker.main_class),
+             "Use java_binary() to set main_class")
+    }
+
+    if (_is_prebuilt || _has_sources) {
+      if (defined(invoker.output_name)) {
+        _output_name = invoker.output_name
+      } else if (_is_prebuilt) {
+        _output_name = get_path_info(invoker.jar_path, "name")
+      } else {
+        _output_name = target_name
+      }
+
+      # Jar files can be needed at runtime (by Robolectric tests or java binaries),
+      # so do not put them under gen/.
+      _target_dir_name = get_label_info(":$target_name", "dir")
+      _final_jar_path =
+          "$root_out_dir/lib.java$_target_dir_name/$_output_name.jar"
+      if (defined(invoker.final_jar_path)) {
+        _final_jar_path = invoker.final_jar_path
+      }
+    }
 
     _supports_android =
         defined(invoker.supports_android) && invoker.supports_android
     _requires_android =
         defined(invoker.requires_android) && invoker.requires_android
     assert(_requires_android || true)  # Mark as used.
+
     _android_manifest = "//build/android/AndroidManifest.xml"
     if (defined(invoker.android_manifest)) {
       _android_manifest = invoker.android_manifest
     }
     assert(_android_manifest != "")  # Mark as used.
 
+    _accumulated_deps = []
+    if (defined(invoker.deps)) {
+      _accumulated_deps = invoker.deps
+    }
+
     _enable_build_hooks =
         _supports_android &&
         (!defined(invoker.no_build_hooks) || !invoker.no_build_hooks)
@@ -2572,57 +2344,52 @@
     if (defined(invoker.chromium_code)) {
       _chromium_code = invoker.chromium_code
     } else {
-      _chromium_code = defined(invoker.java_files) && invoker.java_files != []
-      if (_chromium_code) {
-        # Make chromium_code = false be the default for targets within
-        # third_party which contain no chromium-namespaced java files.
-        set_sources_assignment_filter([ "*\bthird_party\b*" ])
-        sources = [
-          get_label_info(":$target_name", "dir"),
-        ]
-        if (sources == []) {
-          set_sources_assignment_filter([ "*\bchromium\b*" ])
-          sources = invoker.java_files
-          _chromium_code = invoker.java_files != sources
-        }
-        set_sources_assignment_filter([])
-        sources = []
+      # Default based on whether target is in third_party.
+      set_sources_assignment_filter([ "*\bthird_party\b*" ])
+      sources = [
+        get_label_info(":$target_name", "dir"),
+      ]
+      _chromium_code = sources != []
+      if (!_chromium_code && !_is_prebuilt && _java_files != []) {
+        # Unless third_party code has an org.chromium file in it.
+        set_sources_assignment_filter([ "*\bchromium\b*" ])
+        sources = _java_files
+        _chromium_code = _java_files != sources
       }
+      set_sources_assignment_filter([])
+      sources = []
     }
 
-    _emma_never_instrument = !_chromium_code
-    if (defined(invoker.emma_never_instrument)) {
-      _emma_never_instrument = invoker.emma_never_instrument
-    }
-    assert(_emma_never_instrument || true)  # Mark as used
-    _emma_instrument = emma_coverage && !_emma_never_instrument
-
-    if (_supports_android) {
-      _dex_path = _base_path + ".dex.jar"
+    if (_supports_android && defined(_final_jar_path)) {
+      _dex_path = "$target_gen_dir/$target_name.dex.jar"
       if (defined(invoker.dex_path)) {
         _dex_path = invoker.dex_path
       }
     }
 
-    _java_files = []
-    if (defined(invoker.java_files)) {
-      _java_files += invoker.java_files
-    }
     if (_java_files != []) {
+      _java_sources_file = "$target_gen_dir/$target_name.sources"
       if (defined(invoker.java_sources_file)) {
         _java_sources_file = invoker.java_sources_file
-      } else {
-        _java_sources_file = "$_base_path.sources"
       }
       write_file(_java_sources_file, rebase_path(_java_files, root_build_dir))
     }
 
+    _emma_instrument = emma_coverage && !_chromium_code && _has_sources
+    if (defined(invoker.emma_never_instrument)) {
+      _emma_instrument = !invoker.emma_never_instrument && _emma_instrument
+    }
+
+    if (_emma_instrument) {
+      _instrumented_jar_path = "$target_gen_dir/$target_name.instrumented.jar"
+    }
+
     # Define build_config_deps which will be a list of targets required to
     # build the _build_config.
     if (defined(invoker.override_build_config)) {
       _build_config = invoker.override_build_config
     } else {
-      _build_config = _base_path + ".build_config"
+      _build_config = "$target_gen_dir/$target_name.build_config"
       build_config_target_name = "${_template_name}__build_config"
 
       write_build_config(build_config_target_name) {
@@ -2635,11 +2402,12 @@
                                  "main_class",
                                  "proguard_configs",
                                ])
-        if (defined(invoker.is_java_binary) && invoker.is_java_binary) {
+        if (_is_java_binary) {
           type = "java_binary"
         } else {
           type = "java_library"
         }
+        is_prebuilt = _is_prebuilt
         possible_config_deps = _accumulated_deps
         supports_android = _supports_android
         requires_android = _requires_android
@@ -2647,21 +2415,27 @@
                                  invoker.bypass_platform_checks
 
         build_config = _build_config
-        jar_path = _jar_path
-        if (_supports_android) {
+        if (!_is_java_binary && defined(_final_jar_path)) {
+          jar_path = _final_jar_path
+        }
+        if (defined(_dex_path)) {
           dex_path = _dex_path
         }
         if (_java_files != []) {
           java_sources_file = _java_sources_file
         }
 
-        if (defined(invoker.srcjar_deps)) {
-          bundled_srcjars = []
-          foreach(d, invoker.srcjar_deps) {
-            _dep_gen_dir = get_label_info(d, "target_gen_dir")
-            _dep_name = get_label_info(d, "name")
-            bundled_srcjars += [ "$_dep_gen_dir/$_dep_name.srcjar" ]
-          }
+        bundled_srcjars = []
+        foreach(d, _srcjar_deps) {
+          _dep_gen_dir = get_label_info(d, "target_gen_dir")
+          _dep_name = get_label_info(d, "name")
+          bundled_srcjars += [ "$_dep_gen_dir/$_dep_name.srcjar" ]
+        }
+        if (defined(invoker.include_java_resources) &&
+            invoker.include_java_resources) {
+          # Use original jar_path because _jar_path points to a library without
+          # resources.
+          java_resources_jar = invoker.jar_path
         }
       }
       _accumulated_deps += [ ":$build_config_target_name" ]
@@ -2670,97 +2444,54 @@
       _accumulated_deps += invoker.classpath_deps
     }
 
-    _srcjar_deps = []
-    if (defined(invoker.srcjar_deps)) {
-      _srcjar_deps = invoker.srcjar_deps
-    }
-
-    _srcjars = []
-    if (defined(invoker.srcjars)) {
-      _srcjars = invoker.srcjars
-    }
-
-    assert(_java_files != [] || _srcjar_deps != [] || _srcjars != [])
-
-    _compile_java_target = "${_template_name}__compile_java"
-    _final_deps += [ ":$_compile_java_target" ]
-    compile_java(_compile_java_target) {
-      forward_variables_from(invoker,
-                             [
-                               "additional_jar_files",
-                               "alternative_android_sdk_ijar",
-                               "alternative_android_sdk_ijar_dep",
-                               "alternative_android_sdk_jar",
-                               "dist_jar_path",
-                               "enable_errorprone",
-                               "enable_incremental_javac_override",
-                               "jar_excluded_patterns",
-                               "manifest_entries",
-                               "processors_javac",
-                               "processor_args_javac",
-                               "provider_configurations",
-                               "javac_args",
-                             ])
-      jar_path = _jar_path
-      build_config = _build_config
-      java_files = _java_files
-      if (_java_files != []) {
-        java_sources_file = _java_sources_file
-      }
-      srcjar_deps = _srcjar_deps
-      srcjars = _srcjars
-      chromium_code = _chromium_code
-      supports_android = _supports_android
-      requires_android = _requires_android
-      emma_instrument = _emma_instrument
-      enable_build_hooks = _enable_build_hooks
-      enable_build_hooks_android = _enable_build_hooks_android
-      deps = _accumulated_deps
-    }
-    _accumulated_deps += [ ":$_compile_java_target" ]
-    assert(_accumulated_deps != [])  # Mark used.
-
-    if (defined(invoker.main_class)) {
-      # Targets might use the generated script while building, so make it a dep
-      # rather than a data_dep.
-      _final_deps += [ ":${_template_name}__java_binary_script" ]
-      java_binary_script("${_template_name}__java_binary_script") {
+    # TODO(agrieve): Enable lint for _has_sources rather than just _java_files.
+    _has_lint_target = _java_files != [] && _supports_android && _chromium_code
+    if (_has_sources) {
+      _javac_jar_path = "$target_gen_dir/$target_name.javac.jar"
+      _compile_java_target = "${_template_name}__compile_java"
+      compile_java(_compile_java_target) {
         forward_variables_from(invoker,
                                [
-                                 "bootclasspath",
-                                 "main_class",
-                                 "wrapper_script_args",
+                                 "additional_jar_files",
+                                 "alternative_android_sdk_ijar",
+                                 "alternative_android_sdk_ijar_dep",
+                                 "enable_errorprone",
+                                 "enable_incremental_javac_override",
+                                 "manifest_entries",
+                                 "processors_javac",
+                                 "processor_args_javac",
+                                 "provider_configurations",
+                                 "javac_args",
                                ])
         build_config = _build_config
-        jar_path = _jar_path
-        script_name = _template_name
-        if (defined(invoker.wrapper_script_name)) {
-          script_name = invoker.wrapper_script_name
+        java_files = _java_files
+        if (_java_files != []) {
+          java_sources_file = _java_sources_file
         }
+        srcjar_deps = _srcjar_deps
+        chromium_code = _chromium_code
+        requires_android = _requires_android
         deps = _accumulated_deps
+        javac_jar_path = _javac_jar_path
+        if (_emma_instrument) {
+          instrumented_jar_path = _instrumented_jar_path
+        }
       }
-    }
+      _accumulated_deps += [ ":$_compile_java_target" ]
 
-    _has_lint_target = false
-    if (_supports_android) {
-      if (_chromium_code) {
-        _has_lint_target = true
+      if (_has_lint_target) {
         android_lint("${_template_name}__lint") {
-          if (defined(invoker.lint_suppressions_file)) {
-            lint_suppressions_file = invoker.lint_suppressions_file
-          }
-
-          android_manifest = _android_manifest
           build_config = _build_config
-
-          # Run lint on javac output.
-          jar_path = "$target_gen_dir/$_compile_java_target.javac.jar"
-
+          android_manifest = _android_manifest
+          jar_path = _javac_jar_path
+          deps = _accumulated_deps
           java_files = _java_files
           if (_java_files != []) {
             java_sources_file = _java_sources_file
           }
-          deps = _accumulated_deps
+          if (defined(invoker.lint_suppressions_file)) {
+            lint_suppressions_file = invoker.lint_suppressions_file
+          }
           if (_emma_instrument) {
             # Disable the NewApi lint warning when building with coverage
             # enabled. Coverage seems to mess with how the linter detects
@@ -2779,17 +2510,90 @@
           ]
         }
       }
+    }  # _has_sources
 
-      _final_deps += [ ":${_template_name}__dex" ]
-      dex("${_template_name}__dex") {
-        sources = [
-          _jar_path,
-        ]
-        output = _dex_path
-        deps = [
-          ":$_compile_java_target",
-        ]
+    if (defined(_final_jar_path)) {
+      _process_prebuilt_target_name = "${target_name}__process_prebuilt"
+      process_java_prebuilt(_process_prebuilt_target_name) {
+        forward_variables_from(invoker,
+                               [
+                                 "alternative_android_sdk_ijar",
+                                 "alternative_android_sdk_ijar_dep",
+                                 "alternative_android_sdk_jar",
+                                 "jar_excluded_patterns",
+                               ])
+        supports_android = _supports_android
+        enable_build_hooks = _enable_build_hooks
+        enable_build_hooks_android = _enable_build_hooks_android
+        build_config = _build_config
+        if (_is_prebuilt) {
+          input_jar_path = invoker.jar_path
+        } else if (_emma_instrument) {
+          input_jar_path = _instrumented_jar_path
+        } else {
+          input_jar_path = _javac_jar_path
+        }
+        output_jar_path = _final_jar_path
+        deps = _accumulated_deps
       }
+      _accumulated_deps += [ ":$_process_prebuilt_target_name" ]
+
+      if (defined(_dex_path)) {
+        dex("${target_name}__dex") {
+          sources = [
+            _final_jar_path,
+          ]
+          output = _dex_path
+          deps = [
+            ":$_process_prebuilt_target_name",
+          ]
+        }
+        _accumulated_deps += [ ":${target_name}__dex" ]
+      }
+
+      _final_ijar_path =
+          get_path_info(_final_jar_path, "dir") + "/" +
+          get_path_info(_final_jar_path, "name") + ".interface.jar"
+      _ijar_target_name = "${target_name}__ijar"
+      generate_interface_jar(_ijar_target_name) {
+        # Always used the unfiltered .jar to create the interface jar so that
+        # other targets will resolve filtered classes when depending on
+        # BuildConfig, NativeLibraries, etc.
+        if (_is_prebuilt) {
+          input_jar = invoker.jar_path
+          forward_variables_from(invoker, [ "deps" ])
+        } else {
+          input_jar = _javac_jar_path
+          deps = [
+            ":$_compile_java_target",
+          ]
+        }
+        output_jar = _final_ijar_path
+      }
+      _accumulated_deps += [ ":$_ijar_target_name" ]
+    }
+
+    if (_is_java_binary) {
+      # Targets might use the generated script while building, so make it a dep
+      # rather than a data_dep.
+      java_binary_script("${target_name}__java_binary_script") {
+        forward_variables_from(invoker,
+                               [
+                                 "bootclasspath",
+                                 "main_class",
+                                 "wrapper_script_args",
+                               ])
+        build_config = _build_config
+        if (defined(_final_jar_path)) {
+          jar_path = _final_jar_path
+        }
+        script_name = _template_name
+        if (defined(invoker.wrapper_script_name)) {
+          script_name = invoker.wrapper_script_name
+        }
+        deps = _accumulated_deps
+      }
+      _accumulated_deps += [ ":${target_name}__java_binary_script" ]
     }
 
     group(target_name) {
@@ -2799,11 +2603,11 @@
                                "data_deps",
                                "visibility",
                              ])
-      if (!defined(data_deps)) {
-        data_deps = []
-      }
-      public_deps = _final_deps
+      public_deps = _accumulated_deps
       if (_has_lint_target) {
+        if (!defined(data_deps)) {
+          data_deps = []
+        }
         data_deps += [ ":${_template_name}__analysis" ]
       }
     }
diff --git a/build/config/android/rules.gni b/build/config/android/rules.gni
index b9cec7f..9a3f384 100644
--- a/build/config/android/rules.gni
+++ b/build/config/android/rules.gni
@@ -1052,11 +1052,11 @@
   #     will be included in the executable (and the javac classpath).
   #   classpath_deps: Deps that should added to the classpath for this target,
   #     but not linked into the apk (use this for annotation processors).
+  #   jar_path: Path to a prebuilt jar. Mutually exclusive with java_files &
+  #     srcjar_deps.
   #   java_files: List of .java files included in this library.
   #   srcjar_deps: List of srcjar dependencies. The .java files in the srcjars
   #     will be added to java_files and be included in this library.
-  #   srcjars: List of srcjars to be included in this library, together with the
-  #     ones obtained from srcjar_deps.
   #   bypass_platform_checks: Disables checks about cross-platform (Java/Android)
   #     dependencies for this target. This will allow depending on an
   #     android_library target, for example.
@@ -1077,13 +1077,16 @@
   #     deps = [ ":bar_java" ]
   #     main_class = "org.chromium.foo.FooMain"
   #   }
+  #
+  #   java_binary("foo") {
+  #     jar_path = "lib/prebuilt.jar"
+  #     deps = [ ":bar_java" ]
+  #     main_class = "org.chromium.foo.FooMain"
+  #   }
   template("java_binary") {
     java_library_impl(target_name) {
       forward_variables_from(invoker, "*")
-      supports_android = false
-      main_class = invoker.main_class
       is_java_binary = true
-      assert(is_java_binary)  # Mark as used.
     }
   }
 
@@ -1099,8 +1102,6 @@
   #   java_files: List of .java files included in this library.
   #   srcjar_deps: List of srcjar dependencies. The .java files in the srcjars
   #     will be added to java_files and be included in this library.
-  #   srcjars: List of srcjars to be included in this library, together with the
-  #     ones obtained from srcjar_deps.
   #
   #   chromium_code: If true, extra analysis warning/errors will be enabled.
   #
@@ -1147,8 +1148,6 @@
       if (defined(_java_sources_file)) {
         java_sources_file = _java_sources_file
       }
-      _target_dir_name = get_label_info(":$target_name", "dir")
-      jar_path = "$root_out_dir/lib.java$_target_dir_name/$target_name.jar"
     }
 
     if (defined(invoker.classpath_deps)) {
@@ -1218,8 +1217,6 @@
   #   java_files: List of .java files included in this library.
   #   srcjar_deps: List of srcjar dependencies. The .java files in the srcjars
   #     will be added to java_files and be included in this library.
-  #   srcjars: List of srcjars to be included in this library, together with the
-  #     ones obtained from srcjar_deps.
   #
   #   input_jars_paths: A list of paths to the jars that should be included
   #     in the classpath. These are in addition to library .jars that
@@ -1284,7 +1281,6 @@
   #   deps: Specifies the dependencies of this target. Java targets in this list
   #     will be added to the javac classpath.
   #   jar_path: Path to the prebuilt jar.
-  #   jar_dep: Target that builds jar_path (optional).
   #   main_class: When specified, a wrapper script is created within
   #     $root_build_dir/bin to launch the binary with the given class as the
   #     entrypoint.
@@ -1305,7 +1301,7 @@
   #     ]
   #   }
   template("java_prebuilt") {
-    java_prebuilt_impl(target_name) {
+    java_library_impl(target_name) {
       forward_variables_from(invoker, "*")
     }
   }
@@ -1496,8 +1492,6 @@
   #   java_files: List of .java files included in this library.
   #   srcjar_deps: List of srcjar dependencies. The .java files in the srcjars
   #     will be added to java_files and be included in this library.
-  #   srcjars: List of srcjars to be included in this library, together with the
-  #     ones obtained from srcjar_deps.
   #
   #   input_jars_paths: A list of paths to the jars that should be included
   #     in the classpath. These are in addition to library .jars that
@@ -1550,17 +1544,14 @@
   #     ]
   #   }
   template("android_library") {
-    assert(!defined(invoker.jar_path),
-           "android_library does not support a custom jar path")
-
-    if (defined(invoker.alternative_android_sdk_ijar)) {
-      assert(defined(invoker.alternative_android_sdk_ijar_dep))
-      assert(defined(invoker.alternative_android_sdk_jar))
-    }
-
     java_library_impl(target_name) {
       forward_variables_from(invoker, "*")
 
+      if (defined(alternative_android_sdk_ijar)) {
+        assert(defined(alternative_android_sdk_ijar_dep))
+        assert(defined(alternative_android_sdk_jar))
+      }
+
       supports_android = true
       requires_android = true
 
@@ -1618,11 +1609,8 @@
   #     ]
   #   }
   template("android_java_prebuilt") {
-    java_prebuilt_impl(target_name) {
+    android_library(target_name) {
       forward_variables_from(invoker, "*")
-      supports_android = true
-      requires_android = true
-      strip_resource_classes = true
     }
   }
 
@@ -1732,6 +1720,7 @@
     _lib_dex_path = "$_base_path.dex.jar"
     _rebased_lib_dex_path = rebase_path(_lib_dex_path, root_build_dir)
     _template_name = target_name
+    _emma_never_instrument = defined(invoker.testonly) && invoker.testonly
     if (defined(invoker.java_files)) {
       _java_sources_file = "$_base_path.sources"
     }
@@ -1953,7 +1942,6 @@
       _proguard_output_jar_path = "$_base_path.proguard.jar"
     }
 
-    _emma_never_instrument = defined(invoker.testonly) && invoker.testonly
     _incremental_allowed =
         !(defined(invoker.never_incremental) && invoker.never_incremental)
 
@@ -2060,6 +2048,12 @@
       version_name = _version_name
       if (defined(invoker.post_process_package_resources_script)) {
         post_process_script = invoker.post_process_package_resources_script
+
+        # TODO(estevenson): Remove this check.
+        if (defined(invoker.post_process_package_resources_deps)) {
+          post_process_deps = invoker.post_process_package_resources_deps
+          post_process_args = invoker.post_process_package_resources_args
+        }
       }
       srcjar_path = "${target_gen_dir}/${target_name}.srcjar"
       r_text_out_path = "${target_gen_dir}/${target_name}_R.txt"
@@ -2187,7 +2181,7 @@
 
       android_manifest = _android_manifest
       srcjar_deps = _srcjar_deps
-      jar_path = _jar_path
+      final_jar_path = _jar_path
       dex_path = _lib_dex_path
       emma_never_instrument = _emma_never_instrument
       if (defined(_java_sources_file)) {
diff --git a/build/config/compiler/BUILD.gn b/build/config/compiler/BUILD.gn
index fff84887..95128a1 100644
--- a/build/config/compiler/BUILD.gn
+++ b/build/config/compiler/BUILD.gn
@@ -1189,7 +1189,7 @@
       ]
     }
   } else {
-    if (is_mac && !is_nacl) {
+    if ((is_mac || is_ios) && !is_nacl) {
       # When compiling Objective-C, warns if a method is used whose
       # availability is newer than the deployment target.
       cflags += [ "-Wunguarded-availability" ]
@@ -1364,13 +1364,6 @@
       cflags_objc = [ "-Wobjc-missing-property-synthesis" ]
       cflags_objcc = [ "-Wobjc-missing-property-synthesis" ]
     }
-
-    # TODO(crbug.com/761419): Add to default_warnings instead of to
-    # chromium_code once fixed in third_party.
-    if (is_ios) {
-      cflags_objc += [ "-Wunguarded-availability" ]
-      cflags_objcc += [ "-Wunguarded-availability" ]
-    }
   }
 
   configs = [ ":default_warnings" ]
diff --git a/build/fuchsia/runner_common.py b/build/fuchsia/runner_common.py
index 81ab47b3..c001172 100755
--- a/build/fuchsia/runner_common.py
+++ b/build/fuchsia/runner_common.py
@@ -156,7 +156,8 @@
     if os.path.exists(exe_unstripped_path):
       symbols_mapping[target] = exe_unstripped_path
     elif os.path.exists(lib_unstripped_path):
-      symbols_mapping[target] = lib_unstripped_path
+      # TODO(wez): libraries are named by basename in stacks, not by path.
+      symbols_mapping[binary_name] = lib_unstripped_path
     else:
       symbols_mapping[target] = source
 
@@ -532,6 +533,7 @@
   # Group |backtrace| entries according to the associated binary, and locate
   # the path to the debug symbols for that binary, if any.
   batches = {}
+
   for entry in backtrace:
     debug_binary = _LookupDebugBinary(entry, file_mapping)
     if debug_binary:
diff --git a/build/sanitizers/lsan_suppressions.cc b/build/sanitizers/lsan_suppressions.cc
index fc99126..d2464717 100644
--- a/build/sanitizers/lsan_suppressions.cc
+++ b/build/sanitizers/lsan_suppressions.cc
@@ -87,9 +87,6 @@
     // http://crbug.com/356306
     "leak:service_manager::SetProcessTitleFromCommandLine\n"
 
-    // http://crbug.com/601435
-    "leak:mojo/edk/js/handle.h\n"
-
     // https://crbug.com/755670
     "leak:third_party/yasm/\n"
 
diff --git a/cc/base/region.cc b/cc/base/region.cc
index 08e4051..5653634 100644
--- a/cc/base/region.cc
+++ b/cc/base/region.cc
@@ -120,18 +120,17 @@
     return gfx::Rect().ToString();
 
   std::string result;
-  for (Iterator it(*this); it.has_rect(); it.next()) {
+  for (gfx::Rect rect : *this) {
     if (!result.empty())
       result += " | ";
-    result += it.rect().ToString();
+    result += rect.ToString();
   }
   return result;
 }
 
 std::unique_ptr<base::Value> Region::AsValue() const {
   std::unique_ptr<base::ListValue> result(new base::ListValue());
-  for (Iterator it(*this); it.has_rect(); it.next()) {
-    gfx::Rect rect(it.rect());
+  for (gfx::Rect rect : *this) {
     result->AppendInteger(rect.x());
     result->AppendInteger(rect.y());
     result->AppendInteger(rect.width());
@@ -141,8 +140,7 @@
 }
 
 void Region::AsValueInto(base::trace_event::TracedValue* result) const {
-  for (Iterator it(*this); it.has_rect(); it.next()) {
-    gfx::Rect rect(it.rect());
+  for (gfx::Rect rect : *this) {
     result->AppendInteger(rect.x());
     result->AppendInteger(rect.y());
     result->AppendInteger(rect.width());
@@ -150,12 +148,12 @@
   }
 }
 
-Region::Iterator::Iterator() = default;
+Region::Iterator Region::begin() const {
+  return Region::Iterator(*this);
+}
 
 Region::Iterator::Iterator(const Region& region)
     : it_(region.skregion_) {
 }
 
-Region::Iterator::~Iterator() = default;
-
 }  // namespace cc
diff --git a/cc/base/region.h b/cc/base/region.h
index 4ce78ed..29e102b 100644
--- a/cc/base/region.h
+++ b/cc/base/region.h
@@ -74,28 +74,39 @@
   std::unique_ptr<base::Value> AsValue() const;
   void AsValueInto(base::trace_event::TracedValue* array) const;
 
+  // Iterator for iterating through the gfx::Rects contained in this Region.
+  // We only support forward iteration as the underlying SkRegion::Iterator
+  // only supports forward iteration.
   class CC_BASE_EXPORT Iterator {
    public:
-    Iterator();
-    explicit Iterator(const Region& region);
-    ~Iterator();
+    Iterator() = default;
+    ~Iterator() = default;
 
-    gfx::Rect rect() const {
-      return gfx::SkIRectToRect(it_.rect());
-    }
+    gfx::Rect operator*() const { return gfx::SkIRectToRect(it_.rect()); }
 
-    void next() {
+    Iterator& operator++() {
       it_.next();
+      return *this;
     }
 
-    bool has_rect() const {
-      return !it_.done();
+    bool operator==(const Iterator& b) const {
+      // This should only be used to compare to end().
+      DCHECK(b.it_.done());
+      return it_.done();
     }
 
+    bool operator!=(const Iterator& b) const { return !(*this == b); }
+
    private:
+    explicit Iterator(const Region& region);
+    friend class Region;
+
     SkRegion::Iterator it_;
   };
 
+  Iterator begin() const;
+  Iterator end() const { return Iterator(); }
+
  private:
   SkRegion skregion_;
 };
diff --git a/cc/base/region_unittest.cc b/cc/base/region_unittest.cc
index c9a218d6..8b434a1b 100644
--- a/cc/base/region_unittest.cc
+++ b/cc/base/region_unittest.cc
@@ -94,8 +94,8 @@
   r.Union(gfx::Rect(0, 5, 10, 10));
   r.Subtract(gfx::Rect(7, 7, 10, 0));
 
-  for (Region::Iterator it(r); it.has_rect(); it.next())
-    EXPECT_FALSE(it.rect().IsEmpty());
+  for (gfx::Rect rect : r)
+    EXPECT_FALSE(rect.IsEmpty());
 }
 
 #define TEST_NO_INTERSECT(a, b) {  \
diff --git a/cc/base/simple_enclosed_region.cc b/cc/base/simple_enclosed_region.cc
index 76230874..00c58aba 100644
--- a/cc/base/simple_enclosed_region.cc
+++ b/cc/base/simple_enclosed_region.cc
@@ -20,8 +20,8 @@
 }
 
 SimpleEnclosedRegion::SimpleEnclosedRegion(const Region& region) {
-  for (Region::Iterator it(region); it.has_rect(); it.next())
-    Union(it.rect());
+  for (gfx::Rect rect : region)
+    Union(rect);
 }
 
 SimpleEnclosedRegion::~SimpleEnclosedRegion() = default;
diff --git a/cc/blink/web_layer_impl.cc b/cc/blink/web_layer_impl.cc
index 94bee9a..7dc9dd7a 100644
--- a/cc/blink/web_layer_impl.cc
+++ b/cc/blink/web_layer_impl.cc
@@ -11,6 +11,7 @@
 #include <vector>
 
 #include "base/bind.h"
+#include "base/compiler_specific.h"
 #include "base/containers/flat_map.h"
 #include "base/strings/string_util.h"
 #include "base/threading/thread_checker.h"
@@ -290,17 +291,15 @@
 
 WebVector<WebRect> WebLayerImpl::NonFastScrollableRegion() const {
   size_t num_rects = 0;
-  for (cc::Region::Iterator region_rects(layer_->non_fast_scrollable_region());
-       region_rects.has_rect();
-       region_rects.next())
+  for (gfx::Rect rect : layer_->non_fast_scrollable_region()) {
+    ALLOW_UNUSED_LOCAL(rect);
     ++num_rects;
+  }
 
   WebVector<WebRect> result(num_rects);
   size_t i = 0;
-  for (cc::Region::Iterator region_rects(layer_->non_fast_scrollable_region());
-       region_rects.has_rect();
-       region_rects.next()) {
-    result[i] = region_rects.rect();
+  for (gfx::Rect rect : layer_->non_fast_scrollable_region()) {
+    result[i] = rect;
     ++i;
   }
   return result;
@@ -316,17 +315,15 @@
 
 WebVector<WebRect> WebLayerImpl::TouchEventHandlerRegion() const {
   size_t num_rects = 0;
-  for (cc::Region::Iterator region_rects(
-           layer_->touch_action_region().region());
-       region_rects.has_rect(); region_rects.next())
+  for (gfx::Rect rect : layer_->touch_action_region().region()) {
+    ALLOW_UNUSED_LOCAL(rect);
     ++num_rects;
+  }
 
   WebVector<WebRect> result(num_rects);
   size_t i = 0;
-  for (cc::Region::Iterator region_rects(
-           layer_->touch_action_region().region());
-       region_rects.has_rect(); region_rects.next()) {
-    result[i] = region_rects.rect();
+  for (gfx::Rect rect : layer_->touch_action_region().region()) {
+    result[i] = rect;
     ++i;
   }
   return result;
@@ -336,17 +333,17 @@
 WebLayerImpl::TouchEventHandlerRegionForTouchActionForTesting(
     cc::TouchAction touch_action) const {
   size_t num_rects = 0;
-  for (cc::Region::Iterator region_rects(
-           layer_->touch_action_region().GetRegionForTouchAction(touch_action));
-       region_rects.has_rect(); region_rects.next())
+  for (gfx::Rect rect :
+       layer_->touch_action_region().GetRegionForTouchAction(touch_action)) {
+    ALLOW_UNUSED_LOCAL(rect);
     ++num_rects;
+  }
 
   WebVector<WebRect> result(num_rects);
   size_t i = 0;
-  for (cc::Region::Iterator region_rects(
-           layer_->touch_action_region().GetRegionForTouchAction(touch_action));
-       region_rects.has_rect(); region_rects.next()) {
-    result[i] = region_rects.rect();
+  for (gfx::Rect rect :
+       layer_->touch_action_region().GetRegionForTouchAction(touch_action)) {
+    result[i] = rect;
     ++i;
   }
   return result;
diff --git a/cc/output/overlay_candidate.cc b/cc/output/overlay_candidate.cc
index af2aa05..829cacd 100644
--- a/cc/output/overlay_candidate.cc
+++ b/cc/output/overlay_candidate.cc
@@ -194,8 +194,15 @@
 
 // static
 bool OverlayCandidate::FromDrawQuad(DisplayResourceProvider* resource_provider,
+                                    const SkMatrix44& output_color_matrix,
                                     const viz::DrawQuad* quad,
                                     OverlayCandidate* candidate) {
+  // It is currently not possible to set a color conversion matrix on an HW
+  // overlay plane.
+  // TODO(dcastagna): Remove this check once crbug.com/792757 is resolved.
+  if (!output_color_matrix.isIdentity())
+    return false;
+
   // We don't support an opacity value different than one for an overlay plane.
   if (quad->shared_quad_state->opacity != 1.f)
     return false;
diff --git a/cc/output/overlay_candidate.h b/cc/output/overlay_candidate.h
index 91b720a..f304951 100644
--- a/cc/output/overlay_candidate.h
+++ b/cc/output/overlay_candidate.h
@@ -36,6 +36,7 @@
   // Returns true and fills in |candidate| if |draw_quad| is of a known quad
   // type and contains an overlayable resource.
   static bool FromDrawQuad(DisplayResourceProvider* resource_provider,
+                           const SkMatrix44& output_color_matrix,
                            const viz::DrawQuad* quad,
                            OverlayCandidate* candidate);
   // Returns true if |quad| will not block quads underneath from becoming
diff --git a/cc/tiles/picture_layer_tiling.cc b/cc/tiles/picture_layer_tiling.cc
index 1a5df00b..8b9698d3 100644
--- a/cc/tiles/picture_layer_tiling.cc
+++ b/cc/tiles/picture_layer_tiling.cc
@@ -111,10 +111,9 @@
                 active_twin->TileAt(key.index_x, key.index_y)) {
           gfx::Rect tile_rect = tile->content_rect();
           gfx::Rect invalidated;
-          for (Region::Iterator iter(*invalidation); iter.has_rect();
-               iter.next()) {
+          for (gfx::Rect rect : *invalidation) {
             gfx::Rect invalid_content_rect =
-                EnclosingContentsRectFromLayerRect(iter.rect());
+                EnclosingContentsRectFromLayerRect(rect);
             invalid_content_rect.Intersect(tile_rect);
             invalidated.Union(invalid_content_rect);
           }
@@ -263,9 +262,7 @@
   base::flat_map<TileMapKey, gfx::Rect> remove_tiles;
   gfx::Rect expanded_live_tiles_rect =
       tiling_data_.ExpandRectToTileBounds(live_tiles_rect_);
-  for (Region::Iterator iter(layer_invalidation); iter.has_rect();
-       iter.next()) {
-    gfx::Rect layer_rect = iter.rect();
+  for (gfx::Rect layer_rect : layer_invalidation) {
     // The pixels which are invalid in content space.
     gfx::Rect invalid_content_rect =
         EnclosingContentsRectFromLayerRect(layer_rect);
@@ -344,10 +341,9 @@
   // If this tile is invalidated, then the pending tree should create one.
   // Do the intersection test in content space to match the corresponding check
   // on the active tree and avoid floating point inconsistencies.
-  for (Region::Iterator iter(*layer_invalidation); iter.has_rect();
-       iter.next()) {
+  for (gfx::Rect layer_rect : *layer_invalidation) {
     gfx::Rect invalid_content_rect =
-        EnclosingContentsRectFromLayerRect(iter.rect());
+        EnclosingContentsRectFromLayerRect(layer_rect);
     if (invalid_content_rect.Intersects(info.content_rect))
       return true;
   }
diff --git a/cc/tiles/picture_layer_tiling_set.cc b/cc/tiles/picture_layer_tiling_set.cc
index 2d4b29e..d6baa4cc 100644
--- a/cc/tiles/picture_layer_tiling_set.cc
+++ b/cc/tiles/picture_layer_tiling_set.cc
@@ -586,9 +586,9 @@
   // If we don't have any more tilings to process, then return the region
   // iterator rect that we need to fill, so that the caller can checkerboard it.
   if (!tiling_iter_) {
-    if (!region_iter_.has_rect())
+    if (region_iter_ == current_region_.end())
       return gfx::Rect();
-    return region_iter_.rect();
+    return *region_iter_;
   }
   return tiling_iter_.geometry_rect();
 }
@@ -670,14 +670,14 @@
     // If the set of current rects for this tiling is done, go to the next
     // tiling and set up to iterate through all of the remaining holes.
     // This will also happen the first time through the loop.
-    if (!region_iter_.has_rect()) {
+    if (region_iter_ == current_region_.end()) {
       current_tiling_ = NextTiling();
       current_region_.Swap(&missing_region_);
       missing_region_.Clear();
-      region_iter_ = Region::Iterator(current_region_);
+      region_iter_ = current_region_.begin();
 
       // All done and all filled.
-      if (!region_iter_.has_rect()) {
+      if (region_iter_ == current_region_.end()) {
         current_tiling_ = set_->tilings_.size();
         return *this;
       }
@@ -689,8 +689,8 @@
 
     // Pop a rect off.  If there are no more tilings, then these will be
     // treated as geometry with null tiles that the caller can checkerboard.
-    gfx::Rect last_rect = region_iter_.rect();
-    region_iter_.next();
+    gfx::Rect last_rect = *region_iter_;
+    ++region_iter_;
 
     // Done, found next checkerboard rect to return.
     if (current_tiling_ >= set_->tilings_.size())
@@ -706,7 +706,8 @@
 }
 
 PictureLayerTilingSet::CoverageIterator::operator bool() const {
-  return current_tiling_ < set_->tilings_.size() || region_iter_.has_rect();
+  return current_tiling_ < set_->tilings_.size() ||
+         region_iter_ != current_region_.end();
 }
 
 void PictureLayerTilingSet::AsValueInto(
diff --git a/cc/trees/debug_rect_history.cc b/cc/trees/debug_rect_history.cc
index 953d1e3b..1fb0255 100644
--- a/cc/trees/debug_rect_history.cc
+++ b/cc/trees/debug_rect_history.cc
@@ -72,10 +72,10 @@
     if (invalidation_region.IsEmpty() || !layer->DrawsContent())
       continue;
 
-    for (Region::Iterator it(invalidation_region); it.has_rect(); it.next()) {
-      debug_rects_.push_back(DebugRect(
-          PAINT_RECT_TYPE, MathUtil::MapEnclosingClippedRect(
-                               layer->ScreenSpaceTransform(), it.rect())));
+    for (gfx::Rect rect : invalidation_region) {
+      debug_rects_.push_back(
+          DebugRect(PAINT_RECT_TYPE, MathUtil::MapEnclosingClippedRect(
+                                         layer->ScreenSpaceTransform(), rect)));
     }
   }
 }
@@ -136,10 +136,10 @@
        touch_action_index != kTouchActionMax; ++touch_action_index) {
     auto touch_action = static_cast<TouchAction>(touch_action_index);
     Region region = touch_action_region.GetRegionForTouchAction(touch_action);
-    for (Region::Iterator iter(region); iter.has_rect(); iter.next()) {
+    for (gfx::Rect rect : region) {
       debug_rects_.emplace_back(TOUCH_EVENT_HANDLER_RECT_TYPE,
                                 MathUtil::MapEnclosingClippedRect(
-                                    layer->ScreenSpaceTransform(), iter.rect()),
+                                    layer->ScreenSpaceTransform(), rect),
                                 touch_action);
     }
   }
@@ -187,12 +187,10 @@
 }
 
 void DebugRectHistory::SaveNonFastScrollableRectsCallback(LayerImpl* layer) {
-  for (Region::Iterator iter(layer->non_fast_scrollable_region());
-       iter.has_rect(); iter.next()) {
-    debug_rects_.push_back(
-        DebugRect(NON_FAST_SCROLLABLE_RECT_TYPE,
-                  MathUtil::MapEnclosingClippedRect(
-                      layer->ScreenSpaceTransform(), iter.rect())));
+  for (gfx::Rect rect : layer->non_fast_scrollable_region()) {
+    debug_rects_.push_back(DebugRect(NON_FAST_SCROLLABLE_RECT_TYPE,
+                                     MathUtil::MapEnclosingClippedRect(
+                                         layer->ScreenSpaceTransform(), rect)));
   }
 }
 
diff --git a/cc/trees/layer_tree_host_impl.cc b/cc/trees/layer_tree_host_impl.cc
index fcf74cc..d978be7 100644
--- a/cc/trees/layer_tree_host_impl.cc
+++ b/cc/trees/layer_tree_host_impl.cc
@@ -817,9 +817,7 @@
                             are_contents_opaque, opacity, SkBlendMode::kSrcOver,
                             sorting_context_id);
 
-  for (Region::Iterator fill_rects(fill_region); fill_rects.has_rect();
-       fill_rects.next()) {
-    gfx::Rect screen_space_rect = fill_rects.rect();
+  for (gfx::Rect screen_space_rect : fill_region) {
     gfx::Rect visible_screen_space_rect = screen_space_rect;
     // Skip the quad culler and just append the quads directly to avoid
     // occlusion checks.
@@ -1788,7 +1786,8 @@
     return false;
   }
 
-  fps_counter_->SaveTimeStamp(CurrentBeginFrameArgs().frame_time,
+  base::TimeTicks frame_time = CurrentBeginFrameArgs().frame_time;
+  fps_counter_->SaveTimeStamp(frame_time,
                               !layer_tree_frame_sink_->context_provider());
   rendering_stats_instrumentation_->IncrementFrameCount(1);
 
@@ -1835,20 +1834,27 @@
   viz::CompositorFrameMetadata metadata = MakeCompositorFrameMetadata();
   metadata.may_contain_video = frame->may_contain_video;
   metadata.activation_dependencies = std::move(frame->activation_dependencies);
+
   active_tree()->FinishSwapPromises(&metadata);
-  for (auto& latency : metadata.latency_info) {
-    TRACE_EVENT_WITH_FLOW1("input,benchmark", "LatencyInfo.Flow",
-                           TRACE_ID_DONT_MANGLE(latency.trace_id()),
-                           TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT,
-                           "step", "SwapBuffers");
-    // Only add the latency component once for renderer swap, not the browser
-    // swap.
-    if (!latency.FindLatency(ui::INPUT_EVENT_LATENCY_RENDERER_SWAP_COMPONENT, 0,
-                             nullptr)) {
-      latency.AddLatencyNumber(ui::INPUT_EVENT_LATENCY_RENDERER_SWAP_COMPONENT,
-                               0, 0);
+
+  metadata.latency_info.emplace_back(ui::SourceEventType::FRAME);
+  ui::LatencyInfo& new_latency_info = metadata.latency_info.back();
+  if (CommitToActiveTree()) {
+    new_latency_info.AddLatencyNumberWithTimestamp(
+        ui::LATENCY_BEGIN_FRAME_UI_COMPOSITOR_COMPONENT, 0, 0, frame_time, 1);
+  } else {
+    new_latency_info.AddLatencyNumberWithTimestamp(
+        ui::LATENCY_BEGIN_FRAME_RENDERER_COMPOSITOR_COMPONENT, 0, 0, frame_time,
+        1);
+
+    base::TimeTicks draw_time = base::TimeTicks::Now();
+    for (auto& latency : metadata.latency_info) {
+      latency.AddLatencyNumberWithTimestamp(
+          ui::INPUT_EVENT_LATENCY_RENDERER_SWAP_COMPONENT, 0, 0, draw_time, 1);
     }
   }
+  ui::LatencyInfo::TraceIntermediateFlowEvents(metadata.latency_info,
+                                               "SwapBuffers");
 
   // Collect all resource ids in the render passes into a single array.
   ResourceProvider::ResourceIdArray resources;
diff --git a/cc/trees/layer_tree_host_impl_unittest.cc b/cc/trees/layer_tree_host_impl_unittest.cc
index 6f5dfd9..c0b5394 100644
--- a/cc/trees/layer_tree_host_impl_unittest.cc
+++ b/cc/trees/layer_tree_host_impl_unittest.cc
@@ -9784,22 +9784,52 @@
             host_impl_->CurrentlyScrollingNode()->id);
 }
 
-// Make sure LatencyInfo carried by LatencyInfoSwapPromise are passed
-// in viz::CompositorFrameMetadata.
-TEST_F(LayerTreeHostImplTest, LatencyInfoPassedToCompositorFrameMetadata) {
-  std::unique_ptr<SolidColorLayerImpl> root =
-      SolidColorLayerImpl::Create(host_impl_->active_tree(), 1);
-  root->SetPosition(gfx::PointF());
-  root->SetBounds(gfx::Size(10, 10));
-  root->SetDrawsContent(true);
-  root->test_properties()->force_render_surface = true;
+template <bool commit_to_active_tree>
+class LayerTreeHostImplLatencyInfoTest : public LayerTreeHostImplTest {
+ public:
+  void SetUp() override {
+    LayerTreeSettings settings = DefaultSettings();
+    settings.commit_to_active_tree = commit_to_active_tree;
+    CreateHostImpl(settings, CreateLayerTreeFrameSink());
 
-  host_impl_->active_tree()->SetRootLayerForTesting(std::move(root));
-  host_impl_->active_tree()->BuildPropertyTreesForTesting();
+    std::unique_ptr<SolidColorLayerImpl> root =
+        SolidColorLayerImpl::Create(host_impl_->active_tree(), 1);
+    root->SetPosition(gfx::PointF());
+    root->SetBounds(gfx::Size(10, 10));
+    root->SetDrawsContent(true);
+    root->test_properties()->force_render_surface = true;
 
+    host_impl_->active_tree()->SetRootLayerForTesting(std::move(root));
+    host_impl_->active_tree()->BuildPropertyTreesForTesting();
+  }
+};
+
+// Make sure LatencyInfo are passed in viz::CompositorFrameMetadata properly in
+// the Renderer. This includes components added by LatencyInfoSwapPromise and
+// the default LATENCY_BEGIN_FRAME_RENDERER_COMPOSITOR_COMPONENT.
+using LayerTreeHostImplLatencyInfoRendererTest =
+    LayerTreeHostImplLatencyInfoTest<false>;
+TEST_F(LayerTreeHostImplLatencyInfoRendererTest,
+       LatencyInfoPassedToCompositorFrameMetadataRenderer) {
   auto* fake_layer_tree_frame_sink =
       static_cast<FakeLayerTreeFrameSink*>(host_impl_->layer_tree_frame_sink());
 
+  // The first frame should only have the default BeginFrame component.
+  TestFrameData frame1;
+  EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame1));
+  EXPECT_TRUE(host_impl_->DrawLayers(&frame1));
+  host_impl_->DidDrawAllLayers(frame1);
+
+  const std::vector<ui::LatencyInfo>& metadata_latency_after1 =
+      fake_layer_tree_frame_sink->last_sent_frame()->metadata.latency_info;
+  EXPECT_EQ(1u, metadata_latency_after1.size());
+  EXPECT_TRUE(metadata_latency_after1[0].FindLatency(
+      ui::LATENCY_BEGIN_FRAME_RENDERER_COMPOSITOR_COMPONENT, 0, nullptr));
+  EXPECT_TRUE(metadata_latency_after1[0].FindLatency(
+      ui::INPUT_EVENT_LATENCY_RENDERER_SWAP_COMPONENT, 0, nullptr));
+
+  // The second frame should have the default BeginFrame component and the
+  // component attached via LatencyInfoSwapPromise.
   ui::LatencyInfo latency_info;
   latency_info.set_trace_id(5);
   latency_info.AddLatencyNumber(ui::INPUT_EVENT_LATENCY_BEGIN_RWH_COMPONENT, 0,
@@ -9808,17 +9838,82 @@
       new LatencyInfoSwapPromise(latency_info));
   host_impl_->active_tree()->QueuePinnedSwapPromise(std::move(swap_promise));
 
-  gfx::Rect full_frame_damage(host_impl_->DeviceViewport().size());
-  TestFrameData frame;
-  EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
-  EXPECT_TRUE(host_impl_->DrawLayers(&frame));
-  host_impl_->DidDrawAllLayers(frame);
+  TestFrameData frame2;
+  host_impl_->SetFullViewportDamage();
+  host_impl_->SetNeedsRedraw();
+  EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame2));
+  EXPECT_TRUE(host_impl_->DrawLayers(&frame2));
+  host_impl_->DidDrawAllLayers(frame2);
 
-  const std::vector<ui::LatencyInfo>& metadata_latency_after =
+  const std::vector<ui::LatencyInfo>& metadata_latency_after2 =
       fake_layer_tree_frame_sink->last_sent_frame()->metadata.latency_info;
-  EXPECT_EQ(1u, metadata_latency_after.size());
-  EXPECT_TRUE(metadata_latency_after[0].FindLatency(
+  EXPECT_EQ(2u, metadata_latency_after2.size());
+  EXPECT_TRUE(metadata_latency_after2[0].FindLatency(
       ui::INPUT_EVENT_LATENCY_BEGIN_RWH_COMPONENT, 0, nullptr));
+  EXPECT_TRUE(metadata_latency_after2[1].FindLatency(
+      ui::LATENCY_BEGIN_FRAME_RENDERER_COMPOSITOR_COMPONENT, 0, nullptr));
+
+  // Renderer should also record INPUT_EVENT_LATENCY_RENDERER_SWAP_COMPONENT.
+  EXPECT_TRUE(metadata_latency_after2[0].FindLatency(
+      ui::INPUT_EVENT_LATENCY_RENDERER_SWAP_COMPONENT, 0, nullptr));
+  EXPECT_TRUE(metadata_latency_after2[1].FindLatency(
+      ui::INPUT_EVENT_LATENCY_RENDERER_SWAP_COMPONENT, 0, nullptr));
+}
+
+// Make sure LatencyInfo are passed in viz::CompositorFrameMetadata properly in
+// the UI. This includes components added by LatencyInfoSwapPromise and
+// the default LATENCY_BEGIN_FRAME_UI_COMPOSITOR_COMPONENT.
+using LayerTreeHostImplLatencyInfoUITest =
+    LayerTreeHostImplLatencyInfoTest<true>;
+TEST_F(LayerTreeHostImplLatencyInfoUITest,
+       LatencyInfoPassedToCompositorFrameMetadataUI) {
+  auto* fake_layer_tree_frame_sink =
+      static_cast<FakeLayerTreeFrameSink*>(host_impl_->layer_tree_frame_sink());
+
+  // The first frame should only have the default BeginFrame component.
+  TestFrameData frame1;
+  EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame1));
+  EXPECT_TRUE(host_impl_->DrawLayers(&frame1));
+  host_impl_->DidDrawAllLayers(frame1);
+
+  const std::vector<ui::LatencyInfo>& metadata_latency_after1 =
+      fake_layer_tree_frame_sink->last_sent_frame()->metadata.latency_info;
+  EXPECT_EQ(1u, metadata_latency_after1.size());
+  EXPECT_TRUE(metadata_latency_after1[0].FindLatency(
+      ui::LATENCY_BEGIN_FRAME_UI_COMPOSITOR_COMPONENT, 0, nullptr));
+  EXPECT_FALSE(metadata_latency_after1[0].FindLatency(
+      ui::INPUT_EVENT_LATENCY_RENDERER_SWAP_COMPONENT, 0, nullptr));
+
+  // The second frame should have the default BeginFrame component and the
+  // component attached via LatencyInfoSwapPromise.
+  ui::LatencyInfo latency_info;
+  latency_info.set_trace_id(5);
+  latency_info.AddLatencyNumber(ui::INPUT_EVENT_LATENCY_BEGIN_RWH_COMPONENT, 0,
+                                0);
+  std::unique_ptr<SwapPromise> swap_promise(
+      new LatencyInfoSwapPromise(latency_info));
+  host_impl_->active_tree()->QueuePinnedSwapPromise(std::move(swap_promise));
+
+  TestFrameData frame2;
+  host_impl_->SetFullViewportDamage();
+  host_impl_->SetNeedsRedraw();
+  EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame2));
+  EXPECT_TRUE(host_impl_->DrawLayers(&frame2));
+  host_impl_->DidDrawAllLayers(frame2);
+
+  const std::vector<ui::LatencyInfo>& metadata_latency_after2 =
+      fake_layer_tree_frame_sink->last_sent_frame()->metadata.latency_info;
+  EXPECT_EQ(2u, metadata_latency_after2.size());
+  EXPECT_TRUE(metadata_latency_after2[0].FindLatency(
+      ui::INPUT_EVENT_LATENCY_BEGIN_RWH_COMPONENT, 0, nullptr));
+  EXPECT_TRUE(metadata_latency_after2[1].FindLatency(
+      ui::LATENCY_BEGIN_FRAME_UI_COMPOSITOR_COMPONENT, 0, nullptr));
+
+  // UI should not record INPUT_EVENT_LATENCY_RENDERER_SWAP_COMPONENT.
+  EXPECT_FALSE(metadata_latency_after2[0].FindLatency(
+      ui::INPUT_EVENT_LATENCY_RENDERER_SWAP_COMPONENT, 0, nullptr));
+  EXPECT_FALSE(metadata_latency_after2[1].FindLatency(
+      ui::INPUT_EVENT_LATENCY_RENDERER_SWAP_COMPONENT, 0, nullptr));
 }
 
 TEST_F(LayerTreeHostImplTest, SelectionBoundsPassedToCompositorFrameMetadata) {
diff --git a/cc/trees/proxy_main.cc b/cc/trees/proxy_main.cc
index 8248d1f..8b6a764 100644
--- a/cc/trees/proxy_main.cc
+++ b/cc/trees/proxy_main.cc
@@ -14,6 +14,7 @@
 #include "cc/base/devtools_instrumentation.h"
 #include "cc/benchmarks/benchmark_instrumentation.h"
 #include "cc/resources/ui_resource_manager.h"
+#include "cc/trees/latency_info_swap_promise.h"
 #include "cc/trees/layer_tree_frame_sink.h"
 #include "cc/trees/layer_tree_host.h"
 #include "cc/trees/mutator_host.h"
@@ -120,14 +121,20 @@
 
 void ProxyMain::BeginMainFrame(
     std::unique_ptr<BeginMainFrameAndCommitState> begin_main_frame_state) {
+  DCHECK(IsMainThread());
+  DCHECK_EQ(NO_PIPELINE_STAGE, current_pipeline_stage_);
+
+  base::TimeTicks begin_main_frame_start_time = base::TimeTicks::Now();
+
   benchmark_instrumentation::ScopedBeginFrameTask begin_frame_task(
       benchmark_instrumentation::kDoBeginFrame,
       begin_main_frame_state->begin_frame_id);
 
-  base::TimeTicks begin_main_frame_start_time = base::TimeTicks::Now();
-
-  DCHECK(IsMainThread());
-  DCHECK_EQ(NO_PIPELINE_STAGE, current_pipeline_stage_);
+  // If the commit finishes, LayerTreeHost will transfer its swap promises to
+  // LayerTreeImpl. The destructor of ScopedSwapPromiseChecker aborts the
+  // remaining swap promises.
+  ScopedAbortRemainingSwapPromises swap_promise_checker(
+      layer_tree_host_->GetSwapPromiseManager());
 
   // We need to issue image decode callbacks whether or not we will abort this
   // commit, since the request ids are only stored in |begin_main_frame_state|.
@@ -147,12 +154,6 @@
     return;
   }
 
-  // If the commit finishes, LayerTreeHost will transfer its swap promises to
-  // LayerTreeImpl. The destructor of ScopedSwapPromiseChecker aborts the
-  // remaining swap promises.
-  ScopedAbortRemainingSwapPromises swap_promise_checker(
-      layer_tree_host_->GetSwapPromiseManager());
-
   final_pipeline_stage_ = max_requested_pipeline_stage_;
   max_requested_pipeline_stage_ = NO_PIPELINE_STAGE;
 
@@ -266,6 +267,16 @@
     return;
   }
 
+  // Queue the LATENCY_BEGIN_FRAME_RENDERER_MAIN_COMPONENT swap promise only
+  // once we know we will commit since QueueSwapPromise itself requests a
+  // commit.
+  ui::LatencyInfo new_latency_info(ui::SourceEventType::FRAME);
+  new_latency_info.AddLatencyNumberWithTimestamp(
+      ui::LATENCY_BEGIN_FRAME_RENDERER_MAIN_COMPONENT, 0, 0,
+      begin_main_frame_state->begin_frame_args.frame_time, 1);
+  layer_tree_host_->QueueSwapPromise(
+      std::make_unique<LatencyInfoSwapPromise>(new_latency_info));
+
   // Notify the impl thread that the main thread is ready to commit. This will
   // begin the commit process, which is blocking from the main thread's
   // point of view, but asynchronously performed on the impl thread,
diff --git a/cc/trees/single_thread_proxy.cc b/cc/trees/single_thread_proxy.cc
index 4b06003..f86d1e1 100644
--- a/cc/trees/single_thread_proxy.cc
+++ b/cc/trees/single_thread_proxy.cc
@@ -13,6 +13,7 @@
 #include "cc/scheduler/commit_earlyout_reason.h"
 #include "cc/scheduler/compositor_timing_history.h"
 #include "cc/scheduler/scheduler.h"
+#include "cc/trees/latency_info_swap_promise.h"
 #include "cc/trees/layer_tree_frame_sink.h"
 #include "cc/trees/layer_tree_host.h"
 #include "cc/trees/layer_tree_host_common.h"
@@ -657,6 +658,11 @@
 
 void SingleThreadProxy::BeginMainFrame(
     const viz::BeginFrameArgs& begin_frame_args) {
+  // This checker assumes NotifyReadyToCommit in this stack causes a synchronous
+  // commit.
+  ScopedAbortRemainingSwapPromises swap_promise_checker(
+      layer_tree_host_->GetSwapPromiseManager());
+
   if (scheduler_on_impl_thread_) {
     scheduler_on_impl_thread_->NotifyBeginMainFrameStarted(
         base::TimeTicks::Now());
@@ -673,11 +679,6 @@
     return;
   }
 
-  // This checker assumes NotifyReadyToCommit in this stack causes a synchronous
-  // commit.
-  ScopedAbortRemainingSwapPromises swap_promise_checker(
-      layer_tree_host_->GetSwapPromiseManager());
-
   if (!layer_tree_host_->IsVisible()) {
     TRACE_EVENT_INSTANT0("cc", "EarlyOut_NotVisible", TRACE_EVENT_SCOPE_THREAD);
     BeginMainFrameAbortedOnImplThread(
@@ -706,6 +707,15 @@
     return;
   }
 
+  // Queue the LATENCY_BEGIN_FRAME_UI_MAIN_COMPONENT swap promise only once we
+  // know we will commit since QueueSwapPromise itself requests a commit.
+  ui::LatencyInfo new_latency_info(ui::SourceEventType::FRAME);
+  new_latency_info.AddLatencyNumberWithTimestamp(
+      ui::LATENCY_BEGIN_FRAME_UI_MAIN_COMPONENT, 0, 0,
+      begin_frame_args.frame_time, 1);
+  layer_tree_host_->QueueSwapPromise(
+      std::make_unique<LatencyInfoSwapPromise>(new_latency_info));
+
   DoPainting();
 }
 
diff --git a/chrome/VERSION b/chrome/VERSION
index 341c616..ed4d6a9 100644
--- a/chrome/VERSION
+++ b/chrome/VERSION
@@ -1,4 +1,4 @@
 MAJOR=65
 MINOR=0
-BUILD=3287
+BUILD=3288
 PATCH=0
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/OverlayPanelContent.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/OverlayPanelContent.java
index 4c8d118e..ce7a2192 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/OverlayPanelContent.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/OverlayPanelContent.java
@@ -512,8 +512,6 @@
     void onSizeChanged(int width, int height) {
         if (mContentViewCore == null || getWebContents() == null) return;
         getWebContents().setSize(width, height);
-        mContentViewCore.onSizeChanged(width, height, mContentViewCore.getViewportWidthPix(),
-                mContentViewCore.getViewportHeightPix());
     }
 
     void onPhysicalBackingSizeChanged(int width, int height) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/media/router/BaseMediaRouteProvider.java b/chrome/android/java/src/org/chromium/chrome/browser/media/router/BaseMediaRouteProvider.java
new file mode 100644
index 0000000..6141c71
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/media/router/BaseMediaRouteProvider.java
@@ -0,0 +1,160 @@
+// 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.media.router;
+
+import android.os.Handler;
+import android.support.v7.media.MediaRouteSelector;
+import android.support.v7.media.MediaRouter;
+import android.support.v7.media.MediaRouter.RouteInfo;
+
+import org.chromium.base.Log;
+import org.chromium.chrome.browser.media.router.cast.DiscoveryCallback;
+import org.chromium.chrome.browser.media.router.cast.MediaSink;
+import org.chromium.chrome.browser.media.router.cast.MediaSource;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+/**
+ * A {@link BaseMediaRouteProvider} common implementation for MediaRouteProviders.
+ */
+public abstract class BaseMediaRouteProvider implements MediaRouteProvider, DiscoveryDelegate {
+    private static final String TAG = "MediaRouter";
+
+    protected static final List<MediaSink> NO_SINKS = Collections.emptyList();
+
+    protected final MediaRouter mAndroidMediaRouter;
+    protected final MediaRouteManager mManager;
+    protected final Map<String, DiscoveryCallback> mDiscoveryCallbacks =
+            new HashMap<String, DiscoveryCallback>();
+    protected final Map<String, MediaRoute> mRoutes = new HashMap<String, MediaRoute>();
+    protected Handler mHandler = new Handler();
+
+    protected BaseMediaRouteProvider(MediaRouter androidMediaRouter, MediaRouteManager manager) {
+        mAndroidMediaRouter = androidMediaRouter;
+        mManager = manager;
+    }
+
+    /**
+     * @return A MediaSource object constructed from |sourceId|, or null if the derived class does
+     * not support the source.
+     */
+    @Nullable
+    protected abstract MediaSource getSourceFromId(@Nonnull String sourceId);
+
+    /**
+     * Forward the sinks back to the native counterpart.
+     */
+    protected void onSinksReceivedInternal(String sourceId, @Nonnull List<MediaSink> sinks) {
+        Log.d(TAG, "Reporting %d sinks for source: %s", sinks.size(), sourceId);
+        mManager.onSinksReceived(sourceId, this, sinks);
+    }
+
+    /**
+     * {@link DiscoveryDelegate} implementation.
+     */
+    @Override
+    public void onSinksReceived(String sourceId, @Nonnull List<MediaSink> sinks) {
+        Log.d(TAG, "Received %d sinks for sourceId: %s", sinks.size(), sourceId);
+        mHandler.post(() -> { onSinksReceivedInternal(sourceId, sinks); });
+    }
+
+    /**
+     * {@link MediaRouteProvider} implementation.
+     */
+    @Override
+    public boolean supportsSource(@Nonnull String sourceId) {
+        return getSourceFromId(sourceId) != null;
+    }
+
+    @Override
+    public void startObservingMediaSinks(@Nonnull String sourceId) {
+        Log.d(TAG, "startObservingMediaSinks: " + sourceId);
+
+        if (mAndroidMediaRouter == null) {
+            // If the MediaRouter API is not available, report no devices so the page doesn't even
+            // try to cast.
+            onSinksReceived(sourceId, NO_SINKS);
+            return;
+        }
+
+        MediaSource source = getSourceFromId(sourceId);
+        if (source == null) {
+            // If the source is invalid or not supported by this provider, report no devices
+            // available.
+            onSinksReceived(sourceId, NO_SINKS);
+            return;
+        }
+
+        MediaRouteSelector routeSelector = source.buildRouteSelector();
+        if (routeSelector == null) {
+            // If the application invalid, report no devices available.
+            onSinksReceived(sourceId, NO_SINKS);
+            return;
+        }
+
+        // No-op, if already monitoring the application for this source.
+        String applicationId = source.getApplicationId();
+        DiscoveryCallback callback = mDiscoveryCallbacks.get(applicationId);
+        if (callback != null) {
+            callback.addSourceUrn(sourceId);
+            return;
+        }
+
+        List<MediaSink> knownSinks = new ArrayList<MediaSink>();
+        for (RouteInfo route : mAndroidMediaRouter.getRoutes()) {
+            if (route.matchesSelector(routeSelector)) {
+                knownSinks.add(MediaSink.fromRoute(route));
+            }
+        }
+
+        callback = new DiscoveryCallback(sourceId, knownSinks, this, routeSelector);
+        mAndroidMediaRouter.addCallback(
+                routeSelector, callback, MediaRouter.CALLBACK_FLAG_REQUEST_DISCOVERY);
+        mDiscoveryCallbacks.put(applicationId, callback);
+    }
+
+    @Override
+    public void stopObservingMediaSinks(@Nonnull String sourceId) {
+        Log.d(TAG, "stopObservingMediaSinks: " + sourceId);
+        if (mAndroidMediaRouter == null) return;
+
+        MediaSource source = getSourceFromId(sourceId);
+        if (source == null) return;
+
+        String applicationId = source.getApplicationId();
+        DiscoveryCallback callback = mDiscoveryCallbacks.get(applicationId);
+        if (callback == null) return;
+
+        callback.removeSourceUrn(sourceId);
+
+        if (callback.isEmpty()) {
+            mAndroidMediaRouter.removeCallback(callback);
+            mDiscoveryCallbacks.remove(applicationId);
+        }
+    }
+
+    @Override
+    public abstract void createRoute(String sourceId, String sinkId, String presentationId,
+            String origin, int tabId, boolean isIncognito, int nativeRequestId);
+
+    @Override
+    public abstract void joinRoute(
+            String sourceId, String presentationId, String origin, int tabId, int nativeRequestId);
+
+    @Override
+    public abstract void closeRoute(String routeId);
+
+    @Override
+    public abstract void detachRoute(String routeId);
+
+    @Override
+    public abstract void sendStringMessage(String routeId, String message, int nativeCallbackId);
+}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/media/router/ChromeMediaRouter.java b/chrome/android/java/src/org/chromium/chrome/browser/media/router/ChromeMediaRouter.java
index b9df3623..bedf326 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/media/router/ChromeMediaRouter.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/media/router/ChromeMediaRouter.java
@@ -46,8 +46,9 @@
                 }
             };
 
-    // The pointer to the native object. Can be null only during tests.
-    private final long mNativeMediaRouterAndroidBridge;
+    // The pointer to the native object. Can be null during tests, or when the
+    // native object has been destroyed.
+    private long mNativeMediaRouterAndroidBridge;
     private final List<MediaRouteProvider> mRouteProviders = new ArrayList<MediaRouteProvider>();
     private final Map<String, MediaRouteProvider> mRouteIdsToProviders =
             new HashMap<String, MediaRouteProvider>();
@@ -173,12 +174,16 @@
 
     @Override
     public void onMessageSentResult(boolean success, int callbackId) {
-        nativeOnMessageSentResult(mNativeMediaRouterAndroidBridge, success, callbackId);
+        if (mNativeMediaRouterAndroidBridge != 0) {
+            nativeOnMessageSentResult(mNativeMediaRouterAndroidBridge, success, callbackId);
+        }
     }
 
     @Override
     public void onMessage(String mediaRouteId, String message) {
-        nativeOnMessage(mNativeMediaRouterAndroidBridge, mediaRouteId, message);
+        if (mNativeMediaRouterAndroidBridge != 0) {
+            nativeOnMessage(mNativeMediaRouterAndroidBridge, mediaRouteId, message);
+        }
     }
 
     /**
@@ -356,6 +361,15 @@
         mNativeMediaRouterAndroidBridge = nativeMediaRouterAndroidBridge;
     }
 
+    /**
+     * Called when the native object is being destroyed.
+     */
+    @CalledByNative
+    public void teardown() {
+        // The native object has been destroyed.
+        mNativeMediaRouterAndroidBridge = 0;
+    }
+
     private MediaSink getSink(String sourceId, int index) {
         assert mSinksPerSource.containsKey(sourceId);
         return mSinksPerSource.get(sourceId).get(index);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/media/router/cast/CastMediaRouteProvider.java b/chrome/android/java/src/org/chromium/chrome/browser/media/router/cast/CastMediaRouteProvider.java
index f4c3bcdf..44541197 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/media/router/cast/CastMediaRouteProvider.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/media/router/cast/CastMediaRouteProvider.java
@@ -4,26 +4,20 @@
 
 package org.chromium.chrome.browser.media.router.cast;
 
-import android.os.Handler;
-import android.support.v7.media.MediaRouteSelector;
 import android.support.v7.media.MediaRouter;
-import android.support.v7.media.MediaRouter.RouteInfo;
 
 import org.json.JSONException;
 import org.json.JSONObject;
 
 import org.chromium.base.Log;
 import org.chromium.base.VisibleForTesting;
+import org.chromium.chrome.browser.media.router.BaseMediaRouteProvider;
 import org.chromium.chrome.browser.media.router.ChromeMediaRouter;
-import org.chromium.chrome.browser.media.router.DiscoveryDelegate;
 import org.chromium.chrome.browser.media.router.MediaRoute;
 import org.chromium.chrome.browser.media.router.MediaRouteManager;
 import org.chromium.chrome.browser.media.router.MediaRouteProvider;
 
-import java.lang.ref.WeakReference;
-import java.util.ArrayList;
 import java.util.HashMap;
-import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
@@ -32,56 +26,25 @@
 /**
  * A {@link MediaRouteProvider} implementation for Cast devices and applications.
  */
-public class CastMediaRouteProvider implements MediaRouteProvider, DiscoveryDelegate {
-
+public class CastMediaRouteProvider extends BaseMediaRouteProvider {
     private static final String TAG = "MediaRouter";
 
     private static final String AUTO_JOIN_PRESENTATION_ID = "auto-join";
     private static final String PRESENTATION_ID_SESSION_ID_PREFIX = "cast-session_";
 
-    private final MediaRouter mAndroidMediaRouter;
-    private final MediaRouteManager mManager;
     private final CastMessageHandler mMessageHandler;
-    private final Map<String, DiscoveryCallback> mDiscoveryCallbacks =
-            new HashMap<String, DiscoveryCallback>();
-    private final Map<String, MediaRoute> mRoutes = new HashMap<String, MediaRoute>();
     private ClientRecord mLastRemovedRouteRecord;
     private final Map<String, ClientRecord> mClientRecords = new HashMap<String, ClientRecord>();
 
     // There can be only one Cast session at the same time on Android.
     private CastSession mSession;
     private CreateRouteRequest mPendingCreateRouteRequest;
-    private Handler mHandler = new Handler();
-
-    private static class OnSinksReceivedRunnable implements Runnable {
-
-        private final WeakReference<MediaRouteManager> mRouteManager;
-        private final MediaRouteProvider mRouteProvider;
-        private final String mSourceId;
-        private final List<MediaSink> mSinks;
-
-        OnSinksReceivedRunnable(MediaRouteManager manager, MediaRouteProvider routeProvider,
-                String sourceId, List<MediaSink> sinks) {
-            mRouteManager = new WeakReference<MediaRouteManager>(manager);
-            mRouteProvider = routeProvider;
-            mSourceId = sourceId;
-            mSinks = sinks;
-        }
-
-        @Override
-        public void run() {
-            MediaRouteManager manager = mRouteManager.get();
-            if (manager != null) manager.onSinksReceived(mSourceId, mRouteProvider, mSinks);
-        }
-    }
 
     /**
      * @return Initialized {@link CastMediaRouteProvider} object.
      */
     public static CastMediaRouteProvider create(MediaRouteManager manager) {
-        MediaRouter androidMediaRouter = ChromeMediaRouter.getAndroidMediaRouter();
-
-        return new CastMediaRouteProvider(androidMediaRouter, manager);
+        return new CastMediaRouteProvider(ChromeMediaRouter.getAndroidMediaRouter(), manager);
     }
 
     public void onLaunchError() {
@@ -160,77 +123,8 @@
     }
 
     @Override
-    public void onSinksReceived(String sourceId, List<MediaSink> sinks) {
-        mHandler.post(new OnSinksReceivedRunnable(mManager, this, sourceId, sinks));
-    }
-
-    @Override
-    public boolean supportsSource(String sourceId) {
-        return CastMediaSource.from(sourceId) != null;
-    }
-
-    @Override
-    public void startObservingMediaSinks(String sourceId) {
-        if (mAndroidMediaRouter == null) {
-            // If the MediaRouter API is not available, report no devices so the page doesn't even
-            // try to cast.
-            onSinksReceived(sourceId, new ArrayList<MediaSink>());
-            return;
-        }
-
-        MediaSource source = CastMediaSource.from(sourceId);
-        if (source == null) {
-            // If the source is invalid, report no devices available.
-            onSinksReceived(sourceId, new ArrayList<MediaSink>());
-            return;
-        }
-
-        MediaRouteSelector routeSelector = source.buildRouteSelector();
-        if (routeSelector == null) {
-            // If the application invalid, report no devices available.
-            onSinksReceived(sourceId, new ArrayList<MediaSink>());
-            return;
-        }
-
-        String applicationId = source.getApplicationId();
-        DiscoveryCallback callback = mDiscoveryCallbacks.get(applicationId);
-        if (callback != null) {
-            callback.addSourceUrn(sourceId);
-            return;
-        }
-
-        List<MediaSink> knownSinks = new ArrayList<MediaSink>();
-        for (RouteInfo route : mAndroidMediaRouter.getRoutes()) {
-            if (route.matchesSelector(routeSelector)) {
-                knownSinks.add(MediaSink.fromRoute(route));
-            }
-        }
-
-        callback = new DiscoveryCallback(sourceId, knownSinks, this, routeSelector);
-        mAndroidMediaRouter.addCallback(
-                routeSelector,
-                callback,
-                MediaRouter.CALLBACK_FLAG_REQUEST_DISCOVERY);
-        mDiscoveryCallbacks.put(applicationId, callback);
-    }
-
-    @Override
-    public void stopObservingMediaSinks(String sourceId) {
-        if (mAndroidMediaRouter == null) return;
-
-        MediaSource source = CastMediaSource.from(sourceId);
-        if (source == null) return;
-
-        String applicationId = source.getApplicationId();
-        DiscoveryCallback callback = mDiscoveryCallbacks.get(applicationId);
-        if (callback == null) return;
-
-        callback.removeSourceUrn(sourceId);
-
-        if (callback.isEmpty()) {
-            mAndroidMediaRouter.removeCallback(callback);
-            mDiscoveryCallbacks.remove(applicationId);
-        }
+    protected MediaSource getSourceFromId(String sourceId) {
+        return CastMediaSource.from(sourceId);
     }
 
     @Override
@@ -448,8 +342,7 @@
 
     @VisibleForTesting
     CastMediaRouteProvider(MediaRouter androidMediaRouter, MediaRouteManager manager) {
-        mAndroidMediaRouter = androidMediaRouter;
-        mManager = manager;
+        super(androidMediaRouter, manager);
         mMessageHandler = new CastMessageHandler(this);
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/media/router/cast/remoting/RemotingMediaRouteProvider.java b/chrome/android/java/src/org/chromium/chrome/browser/media/router/cast/remoting/RemotingMediaRouteProvider.java
index 36027f4..614ce53 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/media/router/cast/remoting/RemotingMediaRouteProvider.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/media/router/cast/remoting/RemotingMediaRouteProvider.java
@@ -3,144 +3,31 @@
 // found in the LICENSE file.
 package org.chromium.chrome.browser.media.router.cast.remoting;
 
-import android.os.Handler;
-import android.support.v7.media.MediaRouteSelector;
 import android.support.v7.media.MediaRouter;
-import android.support.v7.media.MediaRouter.RouteInfo;
 
-import org.chromium.base.Log;
 import org.chromium.base.VisibleForTesting;
+import org.chromium.chrome.browser.media.router.BaseMediaRouteProvider;
 import org.chromium.chrome.browser.media.router.ChromeMediaRouter;
-import org.chromium.chrome.browser.media.router.DiscoveryDelegate;
 import org.chromium.chrome.browser.media.router.MediaRouteManager;
 import org.chromium.chrome.browser.media.router.MediaRouteProvider;
-import org.chromium.chrome.browser.media.router.cast.DiscoveryCallback;
-import org.chromium.chrome.browser.media.router.cast.MediaSink;
-
-import java.lang.ref.WeakReference;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
+import org.chromium.chrome.browser.media.router.cast.MediaSource;
 
 /**
  * A {@link MediaRouteProvider} implementation for media remote playback.
  */
-public class RemotingMediaRouteProvider implements MediaRouteProvider, DiscoveryDelegate {
+public class RemotingMediaRouteProvider extends BaseMediaRouteProvider {
     private static final String TAG = "MediaRemoting";
 
-    private static final List<MediaSink> NO_SINKS = Collections.emptyList();
-
-    private final MediaRouter mAndroidMediaRouter;
-    private final MediaRouteManager mManager;
-    private final Map<String, DiscoveryCallback> mDiscoveryCallbacks =
-            new HashMap<String, DiscoveryCallback>();
-    private Handler mHandler = new Handler();
-
-    private static class OnSinksReceivedRunnable implements Runnable {
-        private final WeakReference<MediaRouteManager> mRouteManager;
-        private final MediaRouteProvider mRouteProvider;
-        private final String mSourceId;
-        private final List<MediaSink> mSinks;
-
-        OnSinksReceivedRunnable(MediaRouteManager manager, MediaRouteProvider routeProvider,
-                String sourceId, List<MediaSink> sinks) {
-            mRouteManager = new WeakReference<MediaRouteManager>(manager);
-            mRouteProvider = routeProvider;
-            mSourceId = sourceId;
-            mSinks = sinks;
-        }
-
-        @Override
-        public void run() {
-            MediaRouteManager manager = mRouteManager.get();
-            if (manager != null) {
-                Log.d(TAG, "Reporting %d sinks for source: %s", mSinks.size(), mSourceId);
-                manager.onSinksReceived(mSourceId, mRouteProvider, mSinks);
-            }
-        }
-    }
-
     /**
      * @return Initialized {@link RemotingMediaRouteProvider} object.
      */
     public static RemotingMediaRouteProvider create(MediaRouteManager manager) {
-        MediaRouter androidMediaRouter = ChromeMediaRouter.getAndroidMediaRouter();
-        return new RemotingMediaRouteProvider(androidMediaRouter, manager);
-    }
-    /**
-     * {@link DiscoveryDelegate} implementation.
-     */
-    @Override
-    public void onSinksReceived(String sourceId, List<MediaSink> sinks) {
-        Log.d(TAG, "Received %d sinks for sourceId: %s", sinks.size(), sourceId);
-        mHandler.post(new OnSinksReceivedRunnable(mManager, this, sourceId, sinks));
+        return new RemotingMediaRouteProvider(ChromeMediaRouter.getAndroidMediaRouter(), manager);
     }
 
     @Override
-    public boolean supportsSource(String sourceId) {
-        return RemotingMediaSource.from(sourceId) != null;
-    }
-
-    @Override
-    public void startObservingMediaSinks(String sourceId) {
-        Log.d(TAG, "startObservingMediaSinks: " + sourceId);
-
-        if (mAndroidMediaRouter == null) {
-            // If the MediaRouter API is not available, report no devices so the page doesn't even
-            // try to cast.
-            onSinksReceived(sourceId, NO_SINKS);
-            return;
-        }
-
-        RemotingMediaSource source = RemotingMediaSource.from(sourceId);
-        if (source == null) {
-            // If the source is invalid or not supported by this provider, report no devices
-            // available.
-            onSinksReceived(sourceId, NO_SINKS);
-            return;
-        }
-
-        // No-op, if already monitoring the application for this source.
-        String applicationId = source.getApplicationId();
-        DiscoveryCallback callback = mDiscoveryCallbacks.get(applicationId);
-        if (callback != null) {
-            callback.addSourceUrn(sourceId);
-            return;
-        }
-
-        MediaRouteSelector routeSelector = source.buildRouteSelector();
-        List<MediaSink> knownSinks = new ArrayList<MediaSink>();
-        for (RouteInfo route : mAndroidMediaRouter.getRoutes()) {
-            if (route.matchesSelector(routeSelector)) {
-                knownSinks.add(MediaSink.fromRoute(route));
-            }
-        }
-
-        callback = new DiscoveryCallback(sourceId, knownSinks, this, routeSelector);
-        mAndroidMediaRouter.addCallback(
-                routeSelector, callback, MediaRouter.CALLBACK_FLAG_REQUEST_DISCOVERY);
-        mDiscoveryCallbacks.put(applicationId, callback);
-    }
-
-    @Override
-    public void stopObservingMediaSinks(String sourceId) {
-        Log.d(TAG, "stopObservingMediaSinks: " + sourceId);
-        if (mAndroidMediaRouter == null) return;
-
-        RemotingMediaSource source = RemotingMediaSource.from(sourceId);
-        if (source == null) return;
-
-        String applicationId = source.getApplicationId();
-        DiscoveryCallback callback = mDiscoveryCallbacks.get(applicationId);
-        if (callback == null) return;
-
-        callback.removeSourceUrn(sourceId);
-        if (callback.isEmpty()) {
-            mAndroidMediaRouter.removeCallback(callback);
-            mDiscoveryCallbacks.remove(applicationId);
-        }
+    protected MediaSource getSourceFromId(String sourceId) {
+        return RemotingMediaSource.from(sourceId);
     }
 
     // TODO(avayvod): implement the methods below. See https://crbug.com/517102.
@@ -163,7 +50,6 @@
 
     @VisibleForTesting
     RemotingMediaRouteProvider(MediaRouter androidMediaRouter, MediaRouteManager manager) {
-        mAndroidMediaRouter = androidMediaRouter;
-        mManager = manager;
+        super(androidMediaRouter, manager);
     }
-}
\ No newline at end of file
+}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarLayout.java b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarLayout.java
index 70216777..78d3111 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarLayout.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarLayout.java
@@ -1295,12 +1295,11 @@
     /**
      * @param provider The {@link ToolbarDataProvider}.
      * @param resources The Resources for the Context.
-     * @param isOmniboxOpaque Whether the omnibox is an opaque color.
      * @param isChromeHomeEnabled Whether Chrome Home is enabled.
      * @return The {@link ColorStateList} to use to tint the security state icon.
      */
-    public static ColorStateList getColorStateList(ToolbarDataProvider provider,
-            Resources resources, boolean isOmniboxOpaque, boolean isChromeHomeEnabled) {
+    public static ColorStateList getColorStateList(
+            ToolbarDataProvider provider, Resources resources, boolean isChromeHomeEnabled) {
         int securityLevel = provider.getSecurityLevel();
 
         ColorStateList list = null;
@@ -1309,9 +1308,7 @@
         if (provider.isIncognito() || needLightIcon) {
             // For a dark theme color, use light icons.
             list = ApiCompatibilityUtils.getColorStateList(resources, R.color.light_mode_tint);
-        } else if (!ColorUtils.isUsingDefaultToolbarColor(resources,
-                           isChromeHomeEnabled, provider.isIncognito(), color)
-                && !isOmniboxOpaque) {
+        } else if (provider.isUsingBrandColor()) {
             // For theme colors which are not dark and are also not
             // light enough to warrant an opaque URL bar, use dark
             // icons.
@@ -1346,8 +1343,6 @@
             // ImageView#setImageResource is no-op if given resource is the current one.
             mSecurityButton.setImageResource(id);
             mSecurityButton.setTint(getColorStateList(mToolbarDataProvider, getResources(),
-                    ColorUtils.shouldUseOpaqueTextboxBackground(
-                            mToolbarDataProvider.getPrimaryColor()),
                     mBottomSheet != null));
         }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/permissions/PermissionDialogController.java b/chrome/android/java/src/org/chromium/chrome/browser/permissions/PermissionDialogController.java
index dedd8d5..88fb37ee 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/permissions/PermissionDialogController.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/permissions/PermissionDialogController.java
@@ -241,6 +241,13 @@
             @Override
             public void onDismiss(DialogInterface dialog) {
                 mDialog = null;
+
+                if (mDialogDelegate == null) {
+                    // We get into here if a tab navigates or is closed underneath the prompt.
+                    mState = NOT_SHOWING;
+                    return;
+                }
+
                 if (mState == PROMPT_ACCEPTED) {
                     // Request Android permissions if necessary. This will call back into either
                     // onAndroidPermissionAccepted or onAndroidPermissionCanceled, which will
@@ -287,15 +294,16 @@
 
     public void dismissFromNative(PermissionDialogDelegate delegate) {
         if (mDialogDelegate == delegate) {
-            if (mState == PROMPT_OPEN) {
-                mDialog.setOnDismissListener(null);
-                mDialog.dismiss();
-                mDialog = null;
-                mState = NOT_SHOWING;
-            } else {
-                assert mState == PROMPT_PENDING || mState == REQUEST_ANDROID_PERMISSIONS;
-            }
+            // Some caution is required here to handle cases where the user actions or dismisses
+            // the prompt at roughly the same time as native. Due to asynchronicity, this function
+            // may be called after onClick and before onDismiss, or before both of those listeners.
             mDialogDelegate = null;
+            if (mState == PROMPT_OPEN) {
+                mDialog.dismiss();
+            } else {
+                assert mState == PROMPT_PENDING || mState == REQUEST_ANDROID_PERMISSIONS
+                        || mState == PROMPT_DENIED || mState == PROMPT_ACCEPTED;
+            }
         } else {
             assert mRequestQueue.contains(delegate);
             mRequestQueue.remove(delegate);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/website/ContentSetting.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/website/ContentSetting.java
index 2c24c029..d6b63d9 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/website/ContentSetting.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/website/ContentSetting.java
@@ -17,7 +17,7 @@
     SESSION_ONLY(ContentSettingValues.SESSION_ONLY),
     DETECT_IMPORTANT_CONTENT(ContentSettingValues.DETECT_IMPORTANT_CONTENT);
 
-    private int mValue;
+    private final int mValue;
 
     /**
      * Converts the enum value to int. The integer value should be used when dealing with native
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/website/SingleWebsitePreferences.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/website/SingleWebsitePreferences.java
index f1009a4..276a717 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/website/SingleWebsitePreferences.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/website/SingleWebsitePreferences.java
@@ -255,13 +255,14 @@
                         && other.getBackgroundSyncException() != null) {
                     merged.setBackgroundSyncException(other.getBackgroundSyncException());
                 }
+                if (merged.getPopupException() == null && other.getPopupException() != null) {
+                    merged.setPopupException(other.getPopupException());
+                }
             }
 
             // TODO(crbug.com/763982): Deal with this TODO colony.
             // TODO(mvanouwerkerk): Make the various info types share a common interface that
             // supports reading the origin or host.
-            // TODO(mvanouwerkerk): Merge in PopupExceptionInfo? It uses a pattern, and is never
-            // set on Android.
             // TODO(lshang): Merge in CookieException? It will use patterns.
         }
         return merged;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tab/Tab.java b/chrome/android/java/src/org/chromium/chrome/browser/tab/Tab.java
index 4726f29..3f5f1eb 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tab/Tab.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tab/Tab.java
@@ -2550,12 +2550,10 @@
         destroyContentViewCore(deleteOldNativeWebContents);
         NativePage previousNativePage = mNativePage;
         mNativePage = null;
-        // Size of the new ContentViewCore is zero at this point. If we don't call onSizeChanged(),
-        // next onShow() call would send a resize message with the current ContentViewCore size
-        // (zero) to the renderer process, although the new size will be set soon.
-        // However, this size fluttering may confuse Blink and rendered result can be broken
-        // (see http://crbug.com/340987).
-        newContentViewCore.onSizeChanged(originalWidth, originalHeight, 0, 0);
+        // Size of the new content is zero at this point. Set the view size in advance
+        // so that next onShow() call won't send a resize message with zero size
+        // to the renderer process. This prevents the size fluttering that may confuse
+        // Blink and break rendered result (see http://crbug.com/340987).
         newContentViewCore.getWebContents().setSize(originalWidth, originalHeight);
 
         if (!bounds.isEmpty()) {
@@ -3186,7 +3184,6 @@
         Rect bounds = getEstimatedContentSize(context);
         int width = bounds.right - bounds.left;
         int height = bounds.bottom - bounds.top;
-        tab.getContentViewCore().onSizeChanged(width, height, 0, 0);
         tab.getWebContents().setSize(width, height);
 
         tab.detach();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/CustomTabToolbar.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/CustomTabToolbar.java
index 725e974f..882359a 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/CustomTabToolbar.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/CustomTabToolbar.java
@@ -477,8 +477,8 @@
         } else {
             // ImageView#setImageResource is no-op if given resource is the current one.
             mSecurityButton.setImageResource(getToolbarDataProvider().getSecurityIconResource());
-            mSecurityButton.setTint(LocationBarLayout.getColorStateList(getToolbarDataProvider(),
-                    getResources(), false /* omnibox is not opaque */, false));
+            mSecurityButton.setTint(LocationBarLayout.getColorStateList(
+                    getToolbarDataProvider(), getResources(), false));
         }
 
         if (showSecurityButton) {
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 1f31a04..5814cc3 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
@@ -510,7 +510,6 @@
         mContentVirtualDisplay.update(size, dpr, null, null, null, null, null);
         assert mTab != null;
         if (mTab.getContentViewCore() != null) {
-            mTab.getContentViewCore().onSizeChanged(surfaceWidth, surfaceHeight, 0, 0);
             nativeOnPhysicalBackingSizeChanged(
                     mNativeVrShell, mTab.getWebContents(), surfaceWidth, surfaceHeight);
         }
@@ -605,7 +604,6 @@
         if (mTab.getContentViewCore() != null) {
             View parent = mTab.getContentViewCore().getContainerView();
             mTab.getWebContents().setSize(parent.getWidth(), parent.getHeight());
-            mTab.getContentViewCore().onSizeChanged(parent.getWidth(), parent.getHeight(), 0, 0);
         }
         mTab.updateBrowserControlsState(BrowserControlsState.SHOWN, true);
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheet.java b/chrome/android/java/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheet.java
index 08172ae..92b33af 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheet.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheet.java
@@ -974,7 +974,7 @@
 
     @Override
     public boolean isContentScrolledToTop() {
-        return mSheetContent == null || mSheetContent.getVerticalScrollOffset() > 0;
+        return mSheetContent == null || mSheetContent.getVerticalScrollOffset() <= 0;
     }
 
     @Override
diff --git a/chrome/android/java_sources.gni b/chrome/android/java_sources.gni
index f27267f..cfa65afd 100644
--- a/chrome/android/java_sources.gni
+++ b/chrome/android/java_sources.gni
@@ -585,6 +585,7 @@
   "java/src/org/chromium/chrome/browser/media/remote/RemoteVideoInfo.java",
   "java/src/org/chromium/chrome/browser/media/remote/PositionExtrapolator.java",
   "java/src/org/chromium/chrome/browser/media/router/BaseMediaRouteDialogManager.java",
+  "java/src/org/chromium/chrome/browser/media/router/BaseMediaRouteProvider.java",
   "java/src/org/chromium/chrome/browser/media/router/ChromeMediaRouter.java",
   "java/src/org/chromium/chrome/browser/media/router/ChromeMediaRouterDialogController.java",
   "java/src/org/chromium/chrome/browser/media/router/DiscoveryDelegate.java",
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/download/DownloadManagerServiceTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/download/DownloadManagerServiceTest.java
index 73b6dca..e3bed5f 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/download/DownloadManagerServiceTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/download/DownloadManagerServiceTest.java
@@ -24,6 +24,7 @@
 import org.chromium.base.metrics.RecordHistogram;
 import org.chromium.base.test.BaseJUnit4ClassRunner;
 import org.chromium.base.test.util.AdvancedMockContext;
+import org.chromium.base.test.util.DisabledTest;
 import org.chromium.base.test.util.Feature;
 import org.chromium.base.test.util.RetryOnFailure;
 import org.chromium.chrome.browser.download.DownloadInfo.Builder;
@@ -498,8 +499,9 @@
     }
 
     @Test
-    @MediumTest
-    @Feature({"Download"})
+    //@MediumTest
+    //@Feature({"Download"})
+    @DisabledTest // crbug.com/789931
     public void testInterruptedUnmeteredDownloadCannotAutoResumeOnMeteredNetwork()
             throws InterruptedException {
         MockDownloadNotifier notifier = new MockDownloadNotifier(getTestContext());
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestServiceWorkerPaymentAppTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestServiceWorkerPaymentAppTest.java
index 2f51dfa2..cca27472 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestServiceWorkerPaymentAppTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestServiceWorkerPaymentAppTest.java
@@ -13,7 +13,6 @@
 import org.junit.runner.RunWith;
 
 import org.chromium.base.test.util.CommandLineFlags;
-import org.chromium.base.test.util.DisabledTest;
 import org.chromium.base.test.util.Feature;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.ChromeFeatureList;
@@ -310,7 +309,6 @@
 
     @Test
     @MediumTest
-    @DisabledTest(message = "crbug.com/787837")
     @Feature({"Payments"})
     public void testDoNotCallCanMakePayment()
             throws InterruptedException, ExecutionException, TimeoutException {
diff --git a/chrome/android/sync_shell/javatests/src/org/chromium/chrome/browser/sync/GmsCoreSyncListenerTest.java b/chrome/android/sync_shell/javatests/src/org/chromium/chrome/browser/sync/GmsCoreSyncListenerTest.java
index 8a8792fa..81c4e81 100644
--- a/chrome/android/sync_shell/javatests/src/org/chromium/chrome/browser/sync/GmsCoreSyncListenerTest.java
+++ b/chrome/android/sync_shell/javatests/src/org/chromium/chrome/browser/sync/GmsCoreSyncListenerTest.java
@@ -16,8 +16,8 @@
 
 import org.chromium.base.ThreadUtils;
 import org.chromium.base.test.util.CommandLineFlags;
+import org.chromium.base.test.util.DisabledTest;
 import org.chromium.base.test.util.Feature;
-import org.chromium.base.test.util.RetryOnFailure;
 import org.chromium.chrome.browser.ChromeSwitches;
 import org.chromium.chrome.test.ChromeActivityTestRule;
 import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
@@ -35,7 +35,7 @@
         ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE,
         ChromeActivityTestRule.DISABLE_NETWORK_PREDICTION_FLAG,
 })
-@RetryOnFailure // crbug.com/637448
+@DisabledTest // crbug.com/789947
 public class GmsCoreSyncListenerTest {
     @Rule
     public SyncTestRule mSyncTestRule = new SyncTestRule();
diff --git a/chrome/android/webapk/shell_apk/shell_apk_version.gni b/chrome/android/webapk/shell_apk/shell_apk_version.gni
index d39ef26..8203d56 100644
--- a/chrome/android/webapk/shell_apk/shell_apk_version.gni
+++ b/chrome/android/webapk/shell_apk/shell_apk_version.gni
@@ -6,7 +6,7 @@
 # (including AndroidManifest.xml) is updated. This version should be incremented
 # prior to uploading a new ShellAPK to the WebAPK Minting Server.
 # Does not affect Chrome.apk
-template_shell_apk_version = 36
+template_shell_apk_version = 37
 
 # The ShellAPK version expected by Chrome. Chrome will try to update the WebAPK
 # if the WebAPK's ShellAPK version is less than |expected_shell_apk_version|.
diff --git a/chrome/android/webapk/shell_apk/src/org/chromium/webapk/shell_apk/WebApkServiceImplWrapper.java b/chrome/android/webapk/shell_apk/src/org/chromium/webapk/shell_apk/WebApkServiceImplWrapper.java
index a813299..301faec 100644
--- a/chrome/android/webapk/shell_apk/src/org/chromium/webapk/shell_apk/WebApkServiceImplWrapper.java
+++ b/chrome/android/webapk/shell_apk/src/org/chromium/webapk/shell_apk/WebApkServiceImplWrapper.java
@@ -4,11 +4,13 @@
 
 package org.chromium.webapk.shell_apk;
 
+import android.annotation.TargetApi;
 import android.app.Notification;
 import android.app.NotificationChannel;
 import android.app.NotificationManager;
 import android.content.Context;
 import android.os.Binder;
+import android.os.Build;
 import android.os.IBinder;
 import android.os.Parcel;
 import android.os.RemoteException;
@@ -80,10 +82,12 @@
     @Override
     @SuppressWarnings("NewApi")
     public void notifyNotification(String platformTag, int platformID, Notification notification) {
-        // We always rewrite the notification channel id to the WebAPK's default channel id on O+.
+        // The WebApkServiceImplWrapper was introduced at the same time when WebAPKs target SDK 26.
+        // That means, we don't need to check whether the target SDK is less than 26 in a WebAPK
+        // that has a WebApkServiceImplWrapper class.
         if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
             ensureNotificationChannelExists();
-            if (!setNotificationChannelId(notification)) return;
+            notification = rebuildNotificationWithChannelId(mContext, notification);
         }
         delegateNotifyNotification(platformTag, platformID, notification);
     }
@@ -144,22 +148,13 @@
         return false;
     }
 
-    /** Sets the notification channel of the given notification object via reflection. */
-    private boolean setNotificationChannelId(Notification notification) {
-        try {
-            // Now that WebAPKs target SDK 26, we need to set a channel id to display the
-            // notification properly on O+. We set the channel id via reflection because the
-            // notification is already built (and therefore supposedly immutable) when received from
-            // Chrome. This is unavoidable because Notification.Builder is not parcelable.
-            Field channelId = notification.getClass().getDeclaredField("mChannelId");
-            channelId.setAccessible(true);
-            channelId.set(notification, DEFAULT_NOTIFICATION_CHANNEL_ID);
-            return true;
-        } catch (Exception e) {
-            e.printStackTrace();
-        }
-
-        return false;
+    /** Rebuilds a notification with channel ID from the given notification object. */
+    @TargetApi(Build.VERSION_CODES.O)
+    private static Notification rebuildNotificationWithChannelId(
+            Context context, Notification notification) {
+        Notification.Builder builder = Notification.Builder.recoverBuilder(context, notification);
+        builder.setChannelId(DEFAULT_NOTIFICATION_CHANNEL_ID);
+        return builder.build();
     }
 
     /** Calls the delegate's {@link notifyNotification} method via reflection. */
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd
index e877737..b4952242 100644
--- a/chrome/app/generated_resources.grd
+++ b/chrome/app/generated_resources.grd
@@ -5178,7 +5178,7 @@
       <message name="IDS_OMNIBOX_CLEAR_ALL" desc="Accessibility text for the button that deletes all text input from the omnibox on touch devices.">
         Clear input
       </message>
-      <if expr="is_android">
+      <if expr="is_android or enable_vr">
         <message name="IDS_SEARCH_OR_TYPE_URL" desc="Prompt to enter text into the text field that will either perform web searches or navigate to a URL. [CHAR-LIMIT=38]" formatter_data="android_java">
           Search or type URL
         </message>
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index cc6b73db..7a8e27e 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -621,8 +621,6 @@
     "media/media_device_id_salt.h",
     "media/media_engagement_contents_observer.cc",
     "media/media_engagement_contents_observer.h",
-    "media/media_engagement_preloaded_list.cc",
-    "media/media_engagement_preloaded_list.h",
     "media/media_engagement_score.cc",
     "media/media_engagement_score.h",
     "media/media_engagement_service.cc",
@@ -1563,7 +1561,6 @@
     "//chrome/app/theme:theme_resources",
     "//chrome/browser/budget_service:budget_proto",
     "//chrome/browser/devtools",
-    "//chrome/browser/media:media_engagement_preload_proto",
     "//chrome/browser/media:mojo_bindings",
     "//chrome/browser/media/router",
     "//chrome/browser/metrics:expired_histograms_array",
@@ -1653,6 +1650,7 @@
     "//components/payments/core",
     "//components/physical_web/eddystone",
     "//components/policy:generated",
+    "//components/policy/content/",
     "//components/policy/core/browser",
     "//components/policy/proto",
     "//components/prefs:prefs",
@@ -1742,7 +1740,6 @@
     "//mojo/common",
     "//mojo/edk/system",
     "//mojo/public/cpp/bindings",
-    "//mojo/public/js",
     "//net:extras",
     "//net:net_browser_services",
     "//ppapi/features",
diff --git a/chrome/browser/DEPS b/chrome/browser/DEPS
index fb133651..a36a42cc 100644
--- a/chrome/browser/DEPS
+++ b/chrome/browser/DEPS
@@ -16,6 +16,7 @@
   "+chrome_elf/dll_hash",
   "+chromeos",
   "+components",
+  "+components/policy/throttle/",
   "+content/public/browser",
   "+courgette",
   "+device/base",
diff --git a/chrome/browser/android/search_permissions/search_permissions_service.cc b/chrome/browser/android/search_permissions/search_permissions_service.cc
index ddf59d5..d56bfb20 100644
--- a/chrome/browser/android/search_permissions/search_permissions_service.cc
+++ b/chrome/browser/android/search_permissions/search_permissions_service.cc
@@ -192,7 +192,8 @@
 
 void SearchPermissionsService::ResetDSEPermissions() {
   ResetDSEPermission(CONTENT_SETTINGS_TYPE_GEOLOCATION);
-  ResetDSEPermission(CONTENT_SETTINGS_TYPE_NOTIFICATIONS);
+  if (base::FeatureList::IsEnabled(features::kGrantNotificationsToDSE))
+    ResetDSEPermission(CONTENT_SETTINGS_TYPE_NOTIFICATIONS);
 }
 
 void SearchPermissionsService::Shutdown() {
diff --git a/chrome/browser/android/search_permissions/search_permissions_service_unittest.cc b/chrome/browser/android/search_permissions/search_permissions_service_unittest.cc
index 95fd8b4..115786d 100644
--- a/chrome/browser/android/search_permissions/search_permissions_service_unittest.cc
+++ b/chrome/browser/android/search_permissions/search_permissions_service_unittest.cc
@@ -613,3 +613,100 @@
   EXPECT_EQ(CONTENT_SETTING_BLOCK,
             GetContentSetting(kGoogleURL, CONTENT_SETTINGS_TYPE_GEOLOCATION));
 }
+
+TEST_F(SearchPermissionsServiceTest, GrantNotificationsToDSEFeatureDisabled) {
+  base::test::ScopedFeatureList scoped_feature_list;
+  scoped_feature_list.InitAndDisableFeature(features::kGrantNotificationsToDSE);
+
+  SetContentSetting(kGoogleURL, CONTENT_SETTINGS_TYPE_NOTIFICATIONS,
+                    CONTENT_SETTING_DEFAULT);
+  SetContentSetting(kGoogleURL, CONTENT_SETTINGS_TYPE_GEOLOCATION,
+                    CONTENT_SETTING_DEFAULT);
+  ReinitializeService(true /* clear_pref */);
+  test_delegate()->ChangeDSEOrigin(kGoogleURL);
+
+  // Only geolocation should be granted to the DSE.
+  EXPECT_EQ(CONTENT_SETTING_ALLOW,
+            GetContentSetting(kGoogleURL, CONTENT_SETTINGS_TYPE_GEOLOCATION));
+  EXPECT_EQ(CONTENT_SETTING_ASK,
+            GetContentSetting(kGoogleURL, CONTENT_SETTINGS_TYPE_NOTIFICATIONS));
+
+  // Only geolocation should be granted when changing DSEs.
+  test_delegate()->ChangeDSEOrigin(kGoogleAusURL);
+
+  EXPECT_EQ(CONTENT_SETTING_ASK,
+            GetContentSetting(kGoogleURL, CONTENT_SETTINGS_TYPE_GEOLOCATION));
+  EXPECT_EQ(CONTENT_SETTING_ASK,
+            GetContentSetting(kGoogleURL, CONTENT_SETTINGS_TYPE_NOTIFICATIONS));
+
+  EXPECT_EQ(
+      CONTENT_SETTING_ALLOW,
+      GetContentSetting(kGoogleAusURL, CONTENT_SETTINGS_TYPE_GEOLOCATION));
+  EXPECT_EQ(
+      CONTENT_SETTING_ASK,
+      GetContentSetting(kGoogleAusURL, CONTENT_SETTINGS_TYPE_NOTIFICATIONS));
+
+  EXPECT_TRUE(GetService()->IsPermissionControlledByDSE(
+      CONTENT_SETTINGS_TYPE_GEOLOCATION, ToOrigin(kGoogleAusURL)));
+  EXPECT_FALSE(GetService()->IsPermissionControlledByDSE(
+      CONTENT_SETTINGS_TYPE_NOTIFICATIONS, ToOrigin(kGoogleAusURL)));
+
+  // Resetting the DSE setting should only impact geolocation.
+  SetContentSetting(kGoogleAusURL, CONTENT_SETTINGS_TYPE_GEOLOCATION,
+                    CONTENT_SETTING_BLOCK);
+  SetContentSetting(kGoogleAusURL, CONTENT_SETTINGS_TYPE_NOTIFICATIONS,
+                    CONTENT_SETTING_BLOCK);
+  GetService()->ResetDSEPermissions();
+  EXPECT_EQ(
+      CONTENT_SETTING_ALLOW,
+      GetContentSetting(kGoogleAusURL, CONTENT_SETTINGS_TYPE_GEOLOCATION));
+  EXPECT_EQ(
+      CONTENT_SETTING_BLOCK,
+      GetContentSetting(kGoogleAusURL, CONTENT_SETTINGS_TYPE_NOTIFICATIONS));
+}
+
+TEST_F(SearchPermissionsServiceTest,
+       GrantNotificationsToDSEFeatureEnabledThenDisabled) {
+  EXPECT_EQ(CONTENT_SETTING_ALLOW,
+            GetContentSetting(kGoogleURL, CONTENT_SETTINGS_TYPE_GEOLOCATION));
+  EXPECT_EQ(CONTENT_SETTING_ALLOW,
+            GetContentSetting(kGoogleURL, CONTENT_SETTINGS_TYPE_NOTIFICATIONS));
+
+  // When the feature flag was enabled previously and is then disabled, the
+  // notifications permission should be restored to its previous value.
+  {
+    base::test::ScopedFeatureList scoped_feature_list;
+    scoped_feature_list.InitAndDisableFeature(
+        features::kGrantNotificationsToDSE);
+
+    ReinitializeService(false /* clear_pref */);
+
+    EXPECT_EQ(CONTENT_SETTING_ALLOW,
+              GetContentSetting(kGoogleURL, CONTENT_SETTINGS_TYPE_GEOLOCATION));
+    EXPECT_EQ(
+        CONTENT_SETTING_ASK,
+        GetContentSetting(kGoogleURL, CONTENT_SETTINGS_TYPE_NOTIFICATIONS));
+  }
+
+  // The setting should be restored correctly even if it was non-ask.
+  SetContentSetting(kGoogleURL, CONTENT_SETTINGS_TYPE_NOTIFICATIONS,
+                    CONTENT_SETTING_BLOCK);
+  ReinitializeService(true /* clear_pref */);
+
+  EXPECT_EQ(CONTENT_SETTING_BLOCK,
+            GetContentSetting(kGoogleURL, CONTENT_SETTINGS_TYPE_NOTIFICATIONS));
+
+  {
+    base::test::ScopedFeatureList scoped_feature_list;
+    scoped_feature_list.InitAndDisableFeature(
+        features::kGrantNotificationsToDSE);
+
+    ReinitializeService(false /* clear_pref */);
+
+    EXPECT_EQ(CONTENT_SETTING_ALLOW,
+              GetContentSetting(kGoogleURL, CONTENT_SETTINGS_TYPE_GEOLOCATION));
+    EXPECT_EQ(
+        CONTENT_SETTING_BLOCK,
+        GetContentSetting(kGoogleURL, CONTENT_SETTINGS_TYPE_NOTIFICATIONS));
+  }
+}
diff --git a/chrome/browser/android/vr_shell/vr_shell_gl.cc b/chrome/browser/android/vr_shell/vr_shell_gl.cc
index 5d33ad1b..435c217 100644
--- a/chrome/browser/android/vr_shell/vr_shell_gl.cc
+++ b/chrome/browser/android/vr_shell/vr_shell_gl.cc
@@ -1297,6 +1297,11 @@
 void VrShellGl::OnAssetsLoaded(bool success,
                                std::string environment,
                                const base::Version& component_version) {
+  if (success && environment == "zq7sax8chrtjchxysh7b\n") {
+    VLOG(1) << "Successfully loaded VR assets component";
+  } else {
+    VLOG(1) << "Failed to load VR assets component";
+  }
   if (!success) {
     browser_->OnAssetsLoaded(vr::AssetsLoadStatus::kParseFailure,
                              component_version);
@@ -1308,11 +1313,6 @@
     return;
   }
   browser_->OnAssetsLoaded(vr::AssetsLoadStatus::kSuccess, component_version);
-  if (success && environment == "zq7sax8chrtjchxysh7b\n") {
-    VLOG(1) << "Successfully loaded VR assets component";
-  } else {
-    VLOG(1) << "Failed to load VR assets component";
-  }
 }
 
 }  // namespace vr_shell
diff --git a/chrome/browser/android/webapps/DEPS b/chrome/browser/android/webapps/DEPS
deleted file mode 100644
index e604f09..0000000
--- a/chrome/browser/android/webapps/DEPS
+++ /dev/null
@@ -1,9 +0,0 @@
-specific_include_rules = {
-  "add_to_homescreen_data_fetcher_unittest\.cc": [
-    "+content/browser/service_worker/embedded_worker_test_helper.h",
-    "+content/browser/service_worker/service_worker_context_core.h",
-    "+content/common/service_worker/service_worker_status_code.h",
-    "+content/test",
-  ],
-}
-
diff --git a/chrome/browser/banners/app_banner_manager.cc b/chrome/browser/banners/app_banner_manager.cc
index bd1c3cdf..22b96ba 100644
--- a/chrome/browser/banners/app_banner_manager.cc
+++ b/chrome/browser/banners/app_banner_manager.cc
@@ -12,6 +12,8 @@
 #include "base/feature_list.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/time/time.h"
+#include "build/build_config.h"
+#include "chrome/browser/banners/app_banner_manager_desktop.h"
 #include "chrome/browser/banners/app_banner_metrics.h"
 #include "chrome/browser/banners/app_banner_settings_helper.h"
 #include "chrome/browser/browser_process.h"
@@ -29,6 +31,12 @@
 #include "third_party/WebKit/public/platform/modules/installation/installation.mojom.h"
 #include "third_party/skia/include/core/SkBitmap.h"
 
+#if defined(OS_ANDROID)
+#include "chrome/browser/banners/app_banner_manager_android.h"
+#else
+#include "chrome/browser/banners/app_banner_manager_desktop.h"
+#endif
+
 namespace {
 
 int gTimeDeltaInDaysForTesting = 0;
@@ -192,6 +200,7 @@
       load_finished_(false),
       triggered_by_devtools_(false),
       status_reporter_(std::make_unique<NullStatusReporter>()),
+      installable_(Installable::UNKNOWN),
       weak_factory_(this) {
   DCHECK(manager_);
 
@@ -266,12 +275,33 @@
                                GetWeakPtr()));
 }
 
+// static
+AppBannerManager::Installable AppBannerManager::GetInstallable(
+    content::WebContents* web_contents) {
+  AppBannerManager* manager = nullptr;
+#if defined(OS_ANDROID)
+  manager = AppBannerManagerAndroid::FromWebContents(web_contents);
+#else
+  manager = AppBannerManagerDesktop::FromWebContents(web_contents);
+#endif
+
+  return manager ? manager->installable() : Installable::UNKNOWN;
+}
+
+AppBannerManager::Installable AppBannerManager::installable() const {
+  return installable_;
+}
+
 void AppBannerManager::OnDidPerformInstallableCheck(
     const InstallableData& data) {
   UpdateState(State::ACTIVE);
   if (data.has_worker && data.valid_manifest)
     TrackDisplayEvent(DISPLAY_EVENT_WEB_APP_BANNER_REQUESTED);
 
+  installable_ = data.error_code == NO_ERROR_DETECTED
+                     ? Installable::INSTALLABLE_YES
+                     : Installable::INSTALLABLE_NO;
+
   if (data.error_code != NO_ERROR_DETECTED) {
     if (data.error_code == NO_MATCHING_SERVICE_WORKER)
       TrackDisplayEvent(DISPLAY_EVENT_LACKS_SERVICE_WORKER);
@@ -323,6 +353,7 @@
   manifest_url_ = GURL();
   validated_url_ = GURL();
   referrer_.erase();
+  installable_ = Installable::UNKNOWN;
 }
 
 void AppBannerManager::Terminate() {
diff --git a/chrome/browser/banners/app_banner_manager.h b/chrome/browser/banners/app_banner_manager.h
index 9c56925..c2470b7 100644
--- a/chrome/browser/banners/app_banner_manager.h
+++ b/chrome/browser/banners/app_banner_manager.h
@@ -97,6 +97,10 @@
     COMPLETE,
   };
 
+  // Installable describes whether a site satisifes the installablity
+  // requirements.
+  enum class Installable { INSTALLABLE_YES, INSTALLABLE_NO, UNKNOWN };
+
   // Returns the current time.
   static base::Time GetCurrentTime();
 
@@ -142,6 +146,9 @@
   // desktop platforms.
   virtual void OnAppIconFetched(const SkBitmap& bitmap) {}
 
+  // Returns the installability status of a site.
+  static Installable GetInstallable(content::WebContents* web_contents);
+
  protected:
   explicit AppBannerManager(content::WebContents* web_contents);
   ~AppBannerManager() override;
@@ -301,6 +308,10 @@
   // Returns a status code based on the current state, to log when terminating.
   InstallableStatusCode TerminationCode() const;
 
+  // Returns the installability status of the site pertaining to the
+  // AppBannerManager.
+  Installable installable() const;
+
   // Fetches the data required to display a banner for the current page.
   InstallableManager* manager_;
 
@@ -322,8 +333,8 @@
   // Whether the current flow was begun via devtools.
   bool triggered_by_devtools_;
 
- private:
   std::unique_ptr<StatusReporter> status_reporter_;
+  Installable installable_;
 
   // The concrete subclasses of this class are expected to have their lifetimes
   // scoped to the WebContents which they are observing. This allows us to use
diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc
index 4ae3b24..188e23a 100644
--- a/chrome/browser/chrome_content_browser_client.cc
+++ b/chrome/browser/chrome_content_browser_client.cc
@@ -157,6 +157,7 @@
 #include "components/net_log/chrome_net_log.h"
 #include "components/password_manager/content/browser/content_password_manager_driver_factory.h"
 #include "components/patch_service/public/interfaces/constants.mojom.h"
+#include "components/policy/content/policy_blacklist_navigation_throttle.h"
 #include "components/pref_registry/pref_registry_syncable.h"
 #include "components/prefs/pref_registry_simple.h"
 #include "components/prefs/pref_service.h"
@@ -3548,6 +3549,9 @@
   if (tab_under_throttle)
     throttles.push_back(std::move(tab_under_throttle));
 
+  throttles.push_back(base::MakeUnique<PolicyBlacklistNavigationThrottle>(
+      handle, handle->GetWebContents()->GetBrowserContext()));
+
   if (base::CommandLine::ForCurrentProcess()->HasSwitch(
           switches::kCommittedInterstitials)) {
     throttles.push_back(std::make_unique<SSLErrorNavigationThrottle>(
diff --git a/chrome/browser/chromeos/accessibility/select_to_speak_browsertest.cc b/chrome/browser/chromeos/accessibility/select_to_speak_browsertest.cc
index ea5cf7b8..bfe5032 100644
--- a/chrome/browser/chromeos/accessibility/select_to_speak_browsertest.cc
+++ b/chrome/browser/chromeos/accessibility/select_to_speak_browsertest.cc
@@ -2,8 +2,15 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include <memory>
+#include <vector>
+
+#include "ash/accessibility/accessibility_focus_ring_controller.h"
+#include "ash/accessibility/accessibility_focus_ring_layer.h"
 #include "ash/shell.h"
 #include "ash/system/tray/system_tray.h"
+#include "base/bind.h"
+#include "base/memory/weak_ptr.h"
 #include "base/strings/pattern.h"
 #include "chrome/browser/chromeos/accessibility/accessibility_manager.h"
 #include "chrome/browser/chromeos/accessibility/speech_monitor.h"
@@ -20,8 +27,15 @@
 namespace chromeos {
 
 class SelectToSpeakTest : public InProcessBrowserTest {
+ public:
+  void OnFocusRingChanged() {
+    if (loop_runner_) {
+      loop_runner_->Quit();
+    }
+  }
+
  protected:
-  SelectToSpeakTest() {}
+  SelectToSpeakTest() : weak_ptr_factory_(this) {}
   ~SelectToSpeakTest() override {}
 
   void SetUpOnMainThread() override {
@@ -56,7 +70,23 @@
     generator_->ReleaseKey(ui::VKEY_LWIN, 0 /* flags */);
   }
 
+  void PrepareToWaitForFocusRingChanged() {
+    loop_runner_ = new content::MessageLoopRunner();
+  }
+
+  // Blocks until the focus ring is changed.
+  void WaitForFocusRingChanged() {
+    loop_runner_->Run();
+    loop_runner_ = nullptr;
+  }
+
+  base::WeakPtr<SelectToSpeakTest> GetWeakPtr() {
+    return weak_ptr_factory_.GetWeakPtr();
+  }
+
  private:
+  scoped_refptr<content::MessageLoopRunner> loop_runner_;
+  base::WeakPtrFactory<SelectToSpeakTest> weak_ptr_factory_;
   DISALLOW_COPY_AND_ASSIGN(SelectToSpeakTest);
 };
 
@@ -75,28 +105,6 @@
       base::MatchPattern(speech_monitor_.GetNextUtterance(), "Status tray*"));
 }
 
-IN_PROC_BROWSER_TEST_F(SelectToSpeakTest, SearchLocksToSelectToSpeakMode) {
-  ui_test_utils::NavigateToURL(browser(), GURL("data:text/html;charset=utf-8,"
-                                               "<p>This is some text</p>"));
-  gfx::Rect bounds = browser()->window()->GetBounds();
-
-  // Hold click Search, then and click a few pixels into the window bounds.
-  generator_->PressKey(ui::VKEY_LWIN, 0 /* flags */);
-  generator_->ReleaseKey(ui::VKEY_LWIN, 0 /* flags */);
-
-  for (int i = 0; i < 2; ++i) {
-    // With the mouse only, have it speak a few times.
-    generator_->MoveMouseTo(bounds.x() + 8, bounds.y() + 50);
-    generator_->PressLeftButton();
-    generator_->MoveMouseTo(bounds.x() + bounds.width() - 8,
-                            bounds.y() + bounds.height() - 8);
-    generator_->ReleaseLeftButton();
-
-    EXPECT_TRUE(base::MatchPattern(speech_monitor_.GetNextUtterance(),
-                                   "This is some text*"));
-  }
-}
-
 IN_PROC_BROWSER_TEST_F(SelectToSpeakTest, SmoothlyReadsAcrossInlineUrl) {
   // Make sure an inline URL is read smoothly.
   ActivateSelectToSpeakInWindowBounds(
@@ -151,4 +159,71 @@
                                  "Second paragraph*"));
 }
 
+IN_PROC_BROWSER_TEST_F(SelectToSpeakTest, FocusRingMovesWithMouse) {
+  ash::AccessibilityFocusRingController* controller =
+      ash::AccessibilityFocusRingController::GetInstance();
+  // Create a callback for the focus ring observer.
+  base::RepeatingCallback<void()> callback =
+      base::BindRepeating(&SelectToSpeakTest::OnFocusRingChanged, GetWeakPtr());
+  controller->set_focus_ring_observer_for_testing(callback);
+
+  std::vector<std::unique_ptr<ash::AccessibilityFocusRingLayer>> const&
+      focus_rings = controller->focus_ring_layers_for_testing();
+
+  // No focus rings to start.
+  EXPECT_EQ(focus_rings.size(), 0u);
+
+  ui_test_utils::NavigateToURL(browser(), GURL("data:text/html;charset=utf-8,"
+                                               "<p>This is some text</p>"));
+  gfx::Rect bounds = browser()->window()->GetBounds();
+  PrepareToWaitForFocusRingChanged();
+  generator_->PressKey(ui::VKEY_LWIN, 0 /* flags */);
+  generator_->MoveMouseTo(bounds.x() + 8, bounds.y() + 50);
+  generator_->PressLeftButton();
+
+  // Expect a focus ring to have been drawn.
+  WaitForFocusRingChanged();
+  EXPECT_EQ(focus_rings.size(), 1u);
+
+  gfx::Rect target_bounds = focus_rings.at(0)->layer()->GetTargetBounds();
+
+  // Make sure it's in a reasonable position.
+  EXPECT_LT(abs(target_bounds.x() - (bounds.x() + 8)), 50);
+  EXPECT_LT(abs(target_bounds.y() - (bounds.y() + 50)), 50);
+  EXPECT_LT(target_bounds.width(), 50);
+  EXPECT_LT(target_bounds.height(), 50);
+
+  // Move the mouse.
+  PrepareToWaitForFocusRingChanged();
+  generator_->MoveMouseTo(bounds.x() + 108, bounds.y() + 158);
+
+  // Expect focus ring to have moved with the mouse.
+  // The size should have grown to be over 100 (the rect is now size 100,
+  // and the focus ring has some buffer). Position should be unchanged.
+  WaitForFocusRingChanged();
+  target_bounds = focus_rings.at(0)->layer()->GetTargetBounds();
+  EXPECT_LT(abs(target_bounds.x() - (bounds.x() + 8)), 50);
+  EXPECT_LT(abs(target_bounds.y() - (bounds.y() + 50)), 50);
+  EXPECT_GT(target_bounds.width(), 100);
+  EXPECT_GT(target_bounds.height(), 100);
+
+  // Move the mouse smaller again, it should shrink.
+  PrepareToWaitForFocusRingChanged();
+  generator_->MoveMouseTo(bounds.x() + 18, bounds.y() + 68);
+  WaitForFocusRingChanged();
+  target_bounds = focus_rings.at(0)->layer()->GetTargetBounds();
+  EXPECT_LT(target_bounds.width(), 50);
+  EXPECT_LT(target_bounds.height(), 50);
+
+  // Cancel this by releasing the key before the mouse.
+  PrepareToWaitForFocusRingChanged();
+  generator_->ReleaseKey(ui::VKEY_LWIN, 0 /* flags */);
+  generator_->ReleaseLeftButton();
+
+  // Expect focus ring to have been cleared, this was canceled in STS
+  // by releasing the key before the button.
+  WaitForFocusRingChanged();
+  EXPECT_EQ(focus_rings.size(), 0u);
+}
+
 }  // namespace chromeos
diff --git a/chrome/browser/chromeos/arc/enterprise/arc_cert_store_bridge.cc b/chrome/browser/chromeos/arc/enterprise/arc_cert_store_bridge.cc
index 4c65a00..33e3181 100644
--- a/chrome/browser/chromeos/arc/enterprise/arc_cert_store_bridge.cc
+++ b/chrome/browser/chromeos/arc/enterprise/arc_cert_store_bridge.cc
@@ -293,7 +293,7 @@
             x509_cert, Profile::FromBrowserContext(context_)->GetPrefs())) {
       mojom::CertificatePtr certificate = mojom::Certificate::New();
       certificate->alias = cert->nickname;
-      net::X509Certificate::GetPEMEncoded(x509_cert->os_cert_handle(),
+      net::X509Certificate::GetPEMEncoded(x509_cert->cert_buffer(),
                                           &certificate->cert);
       permitted_certs.emplace_back(std::move(certificate));
     }
diff --git a/chrome/browser/chromeos/arc/enterprise/arc_cert_store_bridge_browsertest.cc b/chrome/browser/chromeos/arc/enterprise/arc_cert_store_bridge_browsertest.cc
index 7c0f966e..b6561d3 100644
--- a/chrome/browser/chromeos/arc/enterprise/arc_cert_store_bridge_browsertest.cc
+++ b/chrome/browser/chromeos/arc/enterprise/arc_cert_store_bridge_browsertest.cc
@@ -347,7 +347,7 @@
   mojom_cert1->alias = client_cert1_->nickname;
   auto x509_cert = net::x509_util::CreateX509CertificateFromCERTCertificate(
       client_cert1_.get());
-  net::X509Certificate::GetPEMEncoded(x509_cert->os_cert_handle(),
+  net::X509Certificate::GetPEMEncoded(x509_cert->cert_buffer(),
                                       &mojom_cert1->cert);
 
   std::vector<mojom::CertificatePtr> expected_certs;
diff --git a/chrome/browser/chromeos/arc/intent_helper/arc_settings_service.cc b/chrome/browser/chromeos/arc/intent_helper/arc_settings_service.cc
index 8d47ef1..2442ba4 100644
--- a/chrome/browser/chromeos/arc/intent_helper/arc_settings_service.cc
+++ b/chrome/browser/chromeos/arc/intent_helper/arc_settings_service.cc
@@ -431,14 +431,6 @@
     DCHECK(value->is_bool());
     backup_settings->SetBackupEnabled(value->GetBool(),
                                       !pref->IsUserModifiable());
-  } else {
-    // TODO(crbug.com/783567): Remove this code path after we made sure we
-    // rolled the ARC image that implements backup_settings.
-    //
-    // Fallback to use intent broadcast, if the new method is not available.
-    SendBoolPrefSettingsBroadcast(
-        prefs::kArcBackupRestoreEnabled,
-        "org.chromium.arc.intent_helper.SET_BACKUP_ENABLED");
   }
 
   if (GetPrefs()->IsManagedPreference(prefs::kArcBackupRestoreEnabled)) {
diff --git a/chrome/browser/chromeos/arc/intent_helper/arc_settings_service_browsertest.cc b/chrome/browser/chromeos/arc/intent_helper/arc_settings_service_browsertest.cc
index 7e3d875..a8c73639 100644
--- a/chrome/browser/chromeos/arc/intent_helper/arc_settings_service_browsertest.cc
+++ b/chrome/browser/chromeos/arc/intent_helper/arc_settings_service_browsertest.cc
@@ -29,6 +29,7 @@
 #include "components/arc/arc_service_manager.h"
 #include "components/arc/arc_util.h"
 #include "components/arc/test/connection_holder_util.h"
+#include "components/arc/test/fake_backup_settings_instance.h"
 #include "components/arc/test/fake_intent_helper_instance.h"
 #include "components/policy/core/browser/browser_policy_connector.h"
 #include "components/policy/core/common/mock_configuration_policy_provider.h"
@@ -178,8 +179,6 @@
 
 constexpr char kONCPacUrl[] = "http://domain.com/x";
 
-constexpr char kBackupBroadcastAction[] =
-    "org.chromium.arc.intent_helper.SET_BACKUP_ENABLED";
 constexpr char kLocationServiceBroadcastAction[] =
     "org.chromium.arc.intent_helper.SET_LOCATION_SERVICE_ENABLED";
 constexpr char kSetProxyBroadcastAction[] =
@@ -245,11 +244,26 @@
         ->SetInstance(fake_intent_helper_instance_.get());
     WaitForInstanceReady(
         ArcServiceManager::Get()->arc_bridge_service()->intent_helper());
+
+    fake_backup_settings_instance_ =
+        std::make_unique<FakeBackupSettingsInstance>();
+    ArcServiceManager::Get()
+        ->arc_bridge_service()
+        ->backup_settings()
+        ->SetInstance(fake_backup_settings_instance_.get());
+    WaitForInstanceReady(
+        ArcServiceManager::Get()->arc_bridge_service()->backup_settings());
   }
 
   void TearDownOnMainThread() override {
     ArcServiceManager::Get()
         ->arc_bridge_service()
+        ->backup_settings()
+        ->SetInstance(nullptr);
+    fake_backup_settings_instance_.reset();
+
+    ArcServiceManager::Get()
+        ->arc_bridge_service()
         ->intent_helper()
         ->SetInstance(nullptr);
     fake_intent_helper_instance_.reset();
@@ -301,6 +315,7 @@
   }
 
   std::unique_ptr<FakeIntentHelperInstance> fake_intent_helper_instance_;
+  std::unique_ptr<FakeBackupSettingsInstance> fake_backup_settings_instance_;
 
  private:
   void SetupNetworkEnvironment() {
@@ -337,7 +352,7 @@
   prefs->SetBoolean(prefs::kArcBackupRestoreEnabled, true);
   EXPECT_TRUE(prefs->GetBoolean(prefs::kArcBackupRestoreEnabled));
 
-  fake_intent_helper_instance_->clear_broadcasts();
+  fake_backup_settings_instance_->ClearCallHistory();
 
   // The policy is set to false.
   policy::PolicyMap policy;
@@ -347,18 +362,15 @@
              nullptr);
   UpdatePolicy(policy);
 
-  // The pref is disabled and managed, and the corresponding broadcast is sent
-  // at least once.
+  // The pref is disabled and managed, and the corresponding sync method
+  // reflects the pref.
   EXPECT_FALSE(prefs->GetBoolean(prefs::kArcBackupRestoreEnabled));
   EXPECT_TRUE(prefs->IsManagedPreference(prefs::kArcBackupRestoreEnabled));
-  base::DictionaryValue expected_broadcast_extras;
-  expected_broadcast_extras.SetBoolean("enabled", false);
-  expected_broadcast_extras.SetBoolean("managed", true);
-  EXPECT_GE(CountBroadcasts(fake_intent_helper_instance_->broadcasts(),
-                            kBackupBroadcastAction, &expected_broadcast_extras),
-            1);
+  EXPECT_TRUE(fake_backup_settings_instance_->set_backup_enabled_called());
+  EXPECT_FALSE(fake_backup_settings_instance_->enabled());
+  EXPECT_TRUE(fake_backup_settings_instance_->managed());
 
-  fake_intent_helper_instance_->clear_broadcasts();
+  fake_backup_settings_instance_->ClearCallHistory();
 
   // The policy is set to true.
   policy.Set(policy::key::kArcBackupRestoreEnabled,
@@ -367,30 +379,27 @@
              nullptr);
   UpdatePolicy(policy);
 
-  // The pref is enabled and managed, and the corresponding broadcast is sent at
-  // least once.
+  // The pref is enabled and managed, and the corresponding sync method
+  // reflects the pref.
   EXPECT_TRUE(prefs->GetBoolean(prefs::kArcBackupRestoreEnabled));
   EXPECT_TRUE(prefs->IsManagedPreference(prefs::kArcBackupRestoreEnabled));
-  expected_broadcast_extras.SetBoolean("enabled", true);
-  EXPECT_GE(CountBroadcasts(fake_intent_helper_instance_->broadcasts(),
-                            kBackupBroadcastAction, &expected_broadcast_extras),
-            1);
+  EXPECT_TRUE(fake_backup_settings_instance_->set_backup_enabled_called());
+  EXPECT_TRUE(fake_backup_settings_instance_->enabled());
+  EXPECT_TRUE(fake_backup_settings_instance_->managed());
 
-  fake_intent_helper_instance_->clear_broadcasts();
+  fake_backup_settings_instance_->ClearCallHistory();
 
   // The policy is unset.
   policy.Erase(policy::key::kArcBackupRestoreEnabled);
   UpdatePolicy(policy);
 
-  // The pref is disabled and unmanaged, and the corresponding broadcast is
-  // sent.
+  // The pref is disabled and unmanaged, and the corresponding sync method
+  // reflects the pref.
   EXPECT_FALSE(prefs->GetBoolean(prefs::kArcBackupRestoreEnabled));
   EXPECT_FALSE(prefs->IsManagedPreference(prefs::kArcBackupRestoreEnabled));
-  expected_broadcast_extras.SetBoolean("enabled", false);
-  expected_broadcast_extras.SetBoolean("managed", false);
-  EXPECT_EQ(CountBroadcasts(fake_intent_helper_instance_->broadcasts(),
-                            kBackupBroadcastAction, &expected_broadcast_extras),
-            1);
+  EXPECT_TRUE(fake_backup_settings_instance_->set_backup_enabled_called());
+  EXPECT_FALSE(fake_backup_settings_instance_->enabled());
+  EXPECT_FALSE(fake_backup_settings_instance_->managed());
 }
 
 IN_PROC_BROWSER_TEST_F(ArcSettingsServiceTest, LocationServicePolicyTest) {
diff --git a/chrome/browser/chromeos/certificate_provider/certificate_provider_service_factory.cc b/chrome/browser/chromeos/certificate_provider/certificate_provider_service_factory.cc
index 943690e..a689cdf6 100644
--- a/chrome/browser/chromeos/certificate_provider/certificate_provider_service_factory.cc
+++ b/chrome/browser/chromeos/certificate_provider/certificate_provider_service_factory.cc
@@ -28,6 +28,7 @@
 #include "extensions/browser/extension_registry_observer.h"
 #include "extensions/common/extension.h"
 #include "net/cert/x509_certificate.h"
+#include "net/cert/x509_util.h"
 #include "net/ssl/ssl_private_key.h"
 #include "third_party/boringssl/src/include/openssl/ssl.h"
 
@@ -135,12 +136,8 @@
       return false;
   }
   request.digest.assign(digest.begin(), digest.end());
-  std::string cert_der;
-  if (!net::X509Certificate::GetDEREncoded(certificate->os_cert_handle(),
-                                           &cert_der)) {
-    LOG(ERROR) << "Could not DER encode the certificate.";
-    return false;  // Behave as if the extension wasn't registered anymore.
-  }
+  base::StringPiece cert_der =
+      net::x509_util::CryptoBufferAsStringPiece(certificate->cert_buffer());
   request.certificate.assign(cert_der.begin(), cert_der.end());
 
   std::unique_ptr<base::ListValue> internal_args(new base::ListValue);
diff --git a/chrome/browser/chromeos/certificate_provider/thread_safe_certificate_map.cc b/chrome/browser/chromeos/certificate_provider/thread_safe_certificate_map.cc
index 72327e0..8eea02d 100644
--- a/chrome/browser/chromeos/certificate_provider/thread_safe_certificate_map.cc
+++ b/chrome/browser/chromeos/certificate_provider/thread_safe_certificate_map.cc
@@ -22,7 +22,7 @@
     for (const CertificateInfo& cert_info : entry.second) {
       const net::SHA256HashValue fingerprint =
           net::X509Certificate::CalculateFingerprint256(
-              cert_info.certificate->os_cert_handle());
+              cert_info.certificate->cert_buffer());
       fingerprint_to_cert->insert(std::make_pair(
           fingerprint, base::MakeUnique<ThreadSafeCertificateMap::MapValue>(
                            cert_info, extension_id)));
@@ -66,7 +66,7 @@
     std::string* extension_id) {
   *is_currently_provided = false;
   const net::SHA256HashValue fingerprint =
-      net::X509Certificate::CalculateFingerprint256(cert.os_cert_handle());
+      net::X509Certificate::CalculateFingerprint256(cert.cert_buffer());
 
   base::AutoLock auto_lock(lock_);
   const auto it = fingerprint_to_cert_and_extension_.find(fingerprint);
diff --git a/chrome/browser/chromeos/extensions/file_manager/private_api_misc.cc b/chrome/browser/chromeos/extensions/file_manager/private_api_misc.cc
index 3cf7a30a..6f86ce96 100644
--- a/chrome/browser/chromeos/extensions/file_manager/private_api_misc.cc
+++ b/chrome/browser/chromeos/extensions/file_manager/private_api_misc.cc
@@ -511,22 +511,31 @@
 
 ExtensionFunction::ResponseAction
 FileManagerPrivateGetProvidingExtensionsFunction::Run() {
+  using chromeos::file_system_provider::Capabilities;
+  using chromeos::file_system_provider::ProviderId;
+  using chromeos::file_system_provider::ProviderInterface;
   using chromeos::file_system_provider::Service;
-  using chromeos::file_system_provider::ProvidingExtensionInfo;
   const Service* const service = Service::Get(chrome_details_.GetProfile());
-  const std::vector<ProvidingExtensionInfo> info_list =
-      service->GetProvidingExtensionInfoList();
 
   using api::file_manager_private::ProvidingExtension;
   std::vector<ProvidingExtension> providing_extensions;
-  for (const auto& info : info_list) {
+  for (const auto& pair : service->GetProviders()) {
+    const ProviderInterface* const provider = pair.second.get();
+    const ProviderId provider_id = provider->GetId();
+
+    // TODO(baileyberro, mtomasz): Add support for NATIVE too.
+    if (provider_id.GetType() != ProviderId::EXTENSION) {
+      continue;
+    }
+
     ProvidingExtension providing_extension;
-    providing_extension.extension_id = info.extension_id;
-    providing_extension.name = info.name;
-    providing_extension.configurable = info.capabilities.configurable();
-    providing_extension.watchable = info.capabilities.watchable();
-    providing_extension.multiple_mounts = info.capabilities.multiple_mounts();
-    switch (info.capabilities.source()) {
+    providing_extension.extension_id = provider_id.GetExtensionId();
+    providing_extension.name = provider->GetName();
+    Capabilities capabilities = provider->GetCapabilities();
+    providing_extension.configurable = capabilities.configurable;
+    providing_extension.watchable = capabilities.watchable;
+    providing_extension.multiple_mounts = capabilities.multiple_mounts;
+    switch (capabilities.source) {
       case SOURCE_FILE:
         providing_extension.source =
             api::manifest_types::FILE_SYSTEM_PROVIDER_SOURCE_FILE;
diff --git a/chrome/browser/chromeos/file_system_provider/extension_provider.cc b/chrome/browser/chromeos/file_system_provider/extension_provider.cc
index 971a9ea..c6cc183e 100644
--- a/chrome/browser/chromeos/file_system_provider/extension_provider.cc
+++ b/chrome/browser/chromeos/file_system_provider/extension_provider.cc
@@ -80,6 +80,10 @@
   return provider_id_;
 }
 
+const std::string& ExtensionProvider::GetName() const {
+  return name_;
+}
+
 ExtensionProvider::ExtensionProvider(
     const extensions::ExtensionId& extension_id,
     const ProvidingExtensionInfo& info)
@@ -88,6 +92,7 @@
   capabilities_.watchable = info.capabilities.watchable();
   capabilities_.multiple_mounts = info.capabilities.multiple_mounts();
   capabilities_.source = info.capabilities.source();
+  name_ = info.name;
 }
 
 }  // namespace file_system_provider
diff --git a/chrome/browser/chromeos/file_system_provider/extension_provider.h b/chrome/browser/chromeos/file_system_provider/extension_provider.h
index c84594820..0d1d9fc 100644
--- a/chrome/browser/chromeos/file_system_provider/extension_provider.h
+++ b/chrome/browser/chromeos/file_system_provider/extension_provider.h
@@ -48,6 +48,7 @@
       const ProvidedFileSystemInfo& file_system_info) override;
   const Capabilities& GetCapabilities() const override;
   const ProviderId& GetId() const override;
+  const std::string& GetName() const override;
 
  private:
   ExtensionProvider(const extensions::ExtensionId& extension_id,
@@ -55,6 +56,7 @@
 
   ProviderId provider_id_;
   Capabilities capabilities_;
+  std::string name_;
 };
 
 }  // namespace file_system_provider
diff --git a/chrome/browser/chromeos/file_system_provider/fake_extension_provider.cc b/chrome/browser/chromeos/file_system_provider/fake_extension_provider.cc
index c7bcc9df..28e24f5 100644
--- a/chrome/browser/chromeos/file_system_provider/fake_extension_provider.cc
+++ b/chrome/browser/chromeos/file_system_provider/fake_extension_provider.cc
@@ -45,11 +45,16 @@
   return provider_id_;
 }
 
+const std::string& FakeExtensionProvider::GetName() const {
+  return name_;
+}
+
 FakeExtensionProvider::FakeExtensionProvider(
     const extensions::ExtensionId& extension_id,
     const Capabilities& capabilities)
     : provider_id_(ProviderId::CreateFromExtensionId(extension_id)),
-      capabilities_(capabilities) {}
+      capabilities_(capabilities),
+      name_("Fake Extension Provider") {}
 
 }  // namespace file_system_provider
 }  // namespace chromeos
diff --git a/chrome/browser/chromeos/file_system_provider/fake_extension_provider.h b/chrome/browser/chromeos/file_system_provider/fake_extension_provider.h
index 71c91f5..05b5fd44 100644
--- a/chrome/browser/chromeos/file_system_provider/fake_extension_provider.h
+++ b/chrome/browser/chromeos/file_system_provider/fake_extension_provider.h
@@ -6,6 +6,7 @@
 #define CHROME_BROWSER_CHROMEOS_FILE_SYSTEM_PROVIDER_FAKE_EXTENSION_PROVIDER_H_
 
 #include <memory>
+#include <string>
 
 #include "chrome/browser/chromeos/file_system_provider/extension_provider.h"
 #include "chrome/browser/chromeos/file_system_provider/provided_file_system_interface.h"
@@ -32,6 +33,7 @@
       const ProvidedFileSystemInfo& file_system_info) override;
   const Capabilities& GetCapabilities() const override;
   const ProviderId& GetId() const override;
+  const std::string& GetName() const override;
 
  protected:
   FakeExtensionProvider(const extensions::ExtensionId& extension_id,
@@ -39,6 +41,7 @@
 
   ProviderId provider_id_;
   Capabilities capabilities_;
+  std::string name_;
 };
 
 }  // namespace file_system_provider
diff --git a/chrome/browser/chromeos/file_system_provider/provider_interface.h b/chrome/browser/chromeos/file_system_provider/provider_interface.h
index 1070f30d..cc49ae5 100644
--- a/chrome/browser/chromeos/file_system_provider/provider_interface.h
+++ b/chrome/browser/chromeos/file_system_provider/provider_interface.h
@@ -54,6 +54,9 @@
 
   // Returns id of this provider.
   virtual const ProviderId& GetId() const = 0;
+
+  // Returns a user friendly name of this provider.
+  virtual const std::string& GetName() const = 0;
 };
 
 }  // namespace file_system_provider
diff --git a/chrome/browser/chromeos/file_system_provider/service.cc b/chrome/browser/chromeos/file_system_provider/service.cc
index 6265c544..4e73930 100644
--- a/chrome/browser/chromeos/file_system_provider/service.cc
+++ b/chrome/browser/chromeos/file_system_provider/service.cc
@@ -304,48 +304,8 @@
   return file_system_it->second.get();
 }
 
-std::vector<ProvidingExtensionInfo> Service::GetProvidingExtensionInfoList()
-    const {
-  extensions::ExtensionRegistry* const registry =
-      extensions::ExtensionRegistry::Get(profile_);
-  DCHECK(registry);
-
-  std::vector<ProvidingExtensionInfo> result;
-  for (const auto& extension : registry->enabled_extensions()) {
-    ProvidingExtensionInfo info;
-    if (GetProvidingExtensionInfo(extension->id(), &info))
-      result.push_back(info);
-  }
-
-  return result;
-}
-
-// TODO(mtomasz): Refactor providers into per-filesystem, enabling this code
-// duplication to be removed.
-bool Service::GetProvidingExtensionInfo(
-    const extensions::ExtensionId& extension_id,
-    ProvidingExtensionInfo* result) const {
-  DCHECK(result);
-  extensions::ExtensionRegistry* const registry =
-      extensions::ExtensionRegistry::Get(profile_);
-  DCHECK(registry);
-
-  const extensions::Extension* const extension = registry->GetExtensionById(
-      extension_id, extensions::ExtensionRegistry::ENABLED);
-  if (!extension ||
-      !extension->permissions_data()->HasAPIPermission(
-          extensions::APIPermission::kFileSystemProvider)) {
-    return false;
-  }
-
-  result->extension_id = extension->id();
-  result->name = extension->name();
-  const extensions::FileSystemProviderCapabilities* const capabilities =
-      extensions::FileSystemProviderCapabilities::Get(extension);
-  DCHECK(capabilities);
-  result->capabilities = *capabilities;
-
-  return true;
+const Service::ProviderMap& Service::GetProviders() const {
+  return provider_map_;
 }
 
 void Service::OnExtensionUnloaded(content::BrowserContext* browser_context,
diff --git a/chrome/browser/chromeos/file_system_provider/service.h b/chrome/browser/chromeos/file_system_provider/service.h
index 3614a359..f899d61 100644
--- a/chrome/browser/chromeos/file_system_provider/service.h
+++ b/chrome/browser/chromeos/file_system_provider/service.h
@@ -62,6 +62,8 @@
                 public extensions::ExtensionRegistryObserver,
                 public ProvidedFileSystemObserver {
  public:
+  typedef std::map<ProviderId, std::unique_ptr<ProviderInterface>> ProviderMap;
+
   // Reason for unmounting. In case of UNMOUNT_REASON_SHUTDOWN, the file system
   // will be remounted automatically after a reboot. In case of
   // UNMOUNT_REASON_USER it will be permanently unmounted.
@@ -109,6 +111,9 @@
   // items are copied.
   std::vector<ProvidedFileSystemInfo> GetProvidedFileSystemInfoList();
 
+  // Returns an immutable map of all registered providers.
+  const ProviderMap& GetProviders() const;
+
   // Returns a provided file system with |file_system_id|, handled by
   // the extension with |provider_id|. If not found, then returns NULL.
   ProvidedFileSystemInterface* GetProvidedFileSystem(
@@ -120,16 +125,6 @@
   ProvidedFileSystemInterface* GetProvidedFileSystem(
       const std::string& mount_point_name);
 
-  // Returns a list of information of all currently installed providing
-  // extensions.
-  std::vector<ProvidingExtensionInfo> GetProvidingExtensionInfoList() const;
-
-  // Fills information of the specified providing extension and returns true.
-  // If the extension is not a provider, or it doesn't exist, then false is
-  // returned.
-  bool GetProvidingExtensionInfo(const extensions::ExtensionId& extension_id,
-                                 ProvidingExtensionInfo* result) const;
-
   // Adds and removes observers.
   void AddObserver(Observer* observer);
   void RemoveObserver(Observer* observer);
@@ -209,7 +204,7 @@
   std::map<std::string, FileSystemKey> mount_point_name_to_key_map_;
   std::unique_ptr<RegistryInterface> registry_;
   base::ThreadChecker thread_checker_;
-  std::map<ProviderId, std::unique_ptr<ProviderInterface>> provider_map_;
+  ProviderMap provider_map_;
 
   base::WeakPtrFactory<Service> weak_ptr_factory_;
   DISALLOW_COPY_AND_ASSIGN(Service);
diff --git a/chrome/browser/chromeos/lock_screen_apps/state_controller.cc b/chrome/browser/chromeos/lock_screen_apps/state_controller.cc
index c092933..1d5e41c 100644
--- a/chrome/browser/chromeos/lock_screen_apps/state_controller.cc
+++ b/chrome/browser/chromeos/lock_screen_apps/state_controller.cc
@@ -43,7 +43,6 @@
 #include "extensions/common/extension.h"
 #include "services/service_manager/public/cpp/connector.h"
 #include "ui/events/devices/input_device_manager.h"
-#include "ui/events/devices/stylus_state.h"
 
 using ash::mojom::CloseLockScreenNoteReason;
 using ash::mojom::LockScreenNoteOrigin;
@@ -53,10 +52,6 @@
 
 namespace {
 
-// The time span a stylus eject is considered valid - i.e. the time period
-// within a stylus eject event can cause a lock screen note launch.
-constexpr int kStylusEjectValidityMs = 1000;
-
 // Key for user pref that contains the 256 bit AES key that should be used to
 // encrypt persisted user data created on the lock screen.
 constexpr char kDataCryptoKeyPref[] = "lockScreenAppDataCryptoKey";
@@ -267,11 +262,6 @@
 void StateController::InitializeWithStylusInputPresent() {
   stylus_input_missing_ = false;
 
-  chromeos::DBusThreadManager::Get()
-      ->GetPowerManagerClient()
-      ->GetScreenBrightnessPercent(
-          base::Bind(&StateController::SetInitialScreenState,
-                     weak_ptr_factory_.GetWeakPtr()));
   power_manager_client_observer_.Add(
       chromeos::DBusThreadManager::Get()->GetPowerManagerClient());
   session_observer_.Add(session_manager::SessionManager::Get());
@@ -406,36 +396,11 @@
       false /*close_window*/, CloseLockScreenNoteReason::kAppWindowClosed);
 }
 
-void StateController::OnStylusStateChanged(ui::StylusState state) {
-  if (lock_screen_note_state_ != TrayActionState::kAvailable)
-    return;
-
-  if (state != ui::StylusState::REMOVED) {
-    stylus_eject_timestamp_ = base::TimeTicks();
-    return;
-  }
-
-  if (screen_state_ == ScreenState::kOn) {
-    RequestNewLockScreenNote(LockScreenNoteOrigin::kStylusEject);
-  } else {
-    stylus_eject_timestamp_ = tick_clock_->NowTicks();
-  }
-}
-
 void StateController::OnTouchscreenDeviceConfigurationChanged() {
   if (stylus_input_missing_ && ash::stylus_utils::HasStylusInput())
     InitializeWithStylusInputPresent();
 }
 
-void StateController::BrightnessChanged(int level, bool user_initiated) {
-  if (level == 0 && !user_initiated) {
-    ResetNoteTakingWindowAndMoveToNextState(
-        true /*close_window*/, CloseLockScreenNoteReason::kScreenDimmed);
-  }
-
-  SetScreenState(level == 0 ? ScreenState::kOff : ScreenState::kOn);
-}
-
 void StateController::SuspendImminent(
     power_manager::SuspendImminent::Reason reason) {
   ResetNoteTakingWindowAndMoveToNextState(true /*close_window*/,
@@ -527,35 +492,11 @@
   note_app_window_->web_contents()->Focus();
 }
 
-void StateController::SetInitialScreenState(
-    base::Optional<double> screen_brightness) {
-  if (screen_state_ != ScreenState::kUnknown || !screen_brightness.has_value())
-    return;
-
-  SetScreenState(screen_brightness.value() == 0 ? ScreenState::kOff
-                                                : ScreenState::kOn);
-}
-
-void StateController::SetScreenState(ScreenState screen_state) {
-  if (screen_state_ == screen_state)
-    return;
-
-  screen_state_ = screen_state;
-
-  if (screen_state_ == ScreenState::kOn && !stylus_eject_timestamp_.is_null() &&
-      tick_clock_->NowTicks() - stylus_eject_timestamp_ <
-          base::TimeDelta::FromMilliseconds(kStylusEjectValidityMs)) {
-    stylus_eject_timestamp_ = base::TimeTicks();
-    RequestNewLockScreenNote(LockScreenNoteOrigin::kStylusEject);
-  }
-}
-
 void StateController::ResetNoteTakingWindowAndMoveToNextState(
     bool close_window,
     CloseLockScreenNoteReason reason) {
   note_window_observer_.RemoveAll();
   app_window_observer_.RemoveAll();
-  stylus_eject_timestamp_ = base::TimeTicks();
   app_launch_delayed_for_animation_ = false;
   if (first_app_run_toast_manager_)
     first_app_run_toast_manager_->Reset();
@@ -587,7 +528,8 @@
     note_app_window_ = nullptr;
   }
 
-  UpdateLockScreenNoteState(app_manager_->IsNoteTakingAppAvailable()
+  UpdateLockScreenNoteState(app_manager_ &&
+                                    app_manager_->IsNoteTakingAppAvailable()
                                 ? TrayActionState::kAvailable
                                 : TrayActionState::kNotAvailable);
 }
diff --git a/chrome/browser/chromeos/lock_screen_apps/state_controller.h b/chrome/browser/chromeos/lock_screen_apps/state_controller.h
index 4ad8c141..e210eea 100644
--- a/chrome/browser/chromeos/lock_screen_apps/state_controller.h
+++ b/chrome/browser/chromeos/lock_screen_apps/state_controller.h
@@ -14,7 +14,6 @@
 #include "base/observer_list.h"
 #include "base/optional.h"
 #include "base/scoped_observer.h"
-#include "base/time/time.h"
 #include "chrome/browser/chromeos/lock_screen_apps/app_manager.h"
 #include "chrome/browser/chromeos/lock_screen_apps/state_observer.h"
 #include "chromeos/dbus/power_manager_client.h"
@@ -153,11 +152,9 @@
   void OnAppWindowRemoved(extensions::AppWindow* app_window) override;
 
   // ui::InputDeviceEventObserver:
-  void OnStylusStateChanged(ui::StylusState state) override;
   void OnTouchscreenDeviceConfigurationChanged() override;
 
   // chromeos::PowerManagerClient::Observer
-  void BrightnessChanged(int level, bool user_initiated) override;
   void SuspendImminent(power_manager::SuspendImminent::Reason reason) override;
 
   // Creates and registers an app window as action handler for the action on
@@ -188,17 +185,6 @@
   }
 
  private:
-  // The screen state determined by observing brightness changes from power
-  // manager client.
-  enum class ScreenState {
-    // The screen state has not yet been initialized.
-    kUnknown,
-    // The screen is on - i.e. not completely dimmed.
-    kOn,
-    // The screen is off - it's brightness level is 0.
-    kOff
-  };
-
   // Gets the encryption key that should be used to encrypt user data created on
   // the lock screen. If a key hadn't previously been created and saved to
   // user prefs, a new key is created and saved.
@@ -243,16 +229,6 @@
   // It focuses the app window.
   void FocusAppWindow(bool reverse);
 
-  // Updates the screen state to match the current screen brightness - no-op
-  // unless the current screen state is unknown.
-  void SetInitialScreenState(base::Optional<double> screen_brightness);
-
-  // Updates ths screen state - if the stylus was recently removed and screen
-  // has turned on, this will launch a new note action (stylus being removed
-  // should launch the note action, but this is deferred if the screen is off
-  // when the removal event occurs).
-  void SetScreenState(ScreenState screen_state);
-
   // Lock screen note action state.
   ash::mojom::TrayActionState lock_screen_note_state_ =
       ash::mojom::TrayActionState::kNotAvailable;
@@ -264,15 +240,6 @@
 
   std::unique_ptr<LockScreenProfileCreator> lock_screen_profile_creator_;
 
-  // The current screen state.
-  ScreenState screen_state_ = ScreenState::kUnknown;
-
-  // The time-stamp of the last observed stylus eject event. This will get set
-  // if stylus was ejected while the screen was off, and the note action launch
-  // was thus deferred. If the screen is turned on soon after the stylus is
-  // ejected, lock screen note action will be launched.
-  base::TimeTicks stylus_eject_timestamp_;
-
   // Whether sending app launch request to the note taking app (using
   // |app_manager_|) was delayed until the note action launch animation is
   // completed by lock screen UI - this is only used with Web UI lock
diff --git a/chrome/browser/chromeos/lock_screen_apps/state_controller_unittest.cc b/chrome/browser/chromeos/lock_screen_apps/state_controller_unittest.cc
index 8414334a..1ce73acd 100644
--- a/chrome/browser/chromeos/lock_screen_apps/state_controller_unittest.cc
+++ b/chrome/browser/chromeos/lock_screen_apps/state_controller_unittest.cc
@@ -58,7 +58,6 @@
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/aura/window.h"
 #include "ui/events/devices/input_device_manager.h"
-#include "ui/events/devices/stylus_state.h"
 #include "ui/events/test/device_data_manager_test_api.h"
 
 using ash::mojom::CloseLockScreenNoteReason;
@@ -408,7 +407,6 @@
         chromeos::DBusThreadManager::GetSetterForTesting();
     dbus_setter->SetPowerManagerClient(
         std::make_unique<chromeos::FakePowerManagerClient>());
-    GetPowerManagerClient()->set_screen_brightness_percent(80);
 
     BrowserWithTestWindowTest::SetUp();
 
@@ -803,12 +801,6 @@
   EXPECT_EQ(TrayActionState::kAvailable,
             state_controller()->GetLockScreenNoteState());
   ExpectObservedStatesMatch({TrayActionState::kAvailable}, "Stylus enabled");
-  ClearObservedStates();
-
-  // Ejecting the stylus should trigger lock screen app launch.
-  devices_test_api.NotifyObserversStylusStateChanged(ui::StylusState::REMOVED);
-  ExpectObservedStatesMatch({TrayActionState::kLaunching},
-                            "Launch on stylus ejected");
 }
 
 TEST_F(LockScreenAppStateNoStylusInputTest, StylusDetectedAfterInitialization) {
@@ -1209,60 +1201,12 @@
   EXPECT_EQ(2, app_manager()->launch_count());
 }
 
-TEST_F(LockScreenAppStateWebUiLockTest, LaunchActionWhenStylusGetsRemoved) {
-  ui::test::DeviceDataManagerTestAPI devices_test_api;
-  ASSERT_TRUE(InitializeNoteTakingApp(TrayActionState::kAvailable,
-                                      true /* enable_app_launch */));
-  devices_test_api.NotifyObserversStylusStateChanged(ui::StylusState::REMOVED);
-
-  ExpectObservedStatesMatch({TrayActionState::kLaunching},
-                            "Launch on new note request");
-  ClearObservedStates();
-  // The app should not be launched until the lock UI reports the animation as
-  // complete.
-  EXPECT_EQ(0, app_manager()->launch_count());
-  state_controller()->NewNoteLaunchAnimationDone();
-  EXPECT_EQ(1, app_manager()->launch_count());
-
-  // If the stylus is inserted and removed while launching the app, there should
-  // be no new launch event.
-  devices_test_api.NotifyObserversStylusStateChanged(ui::StylusState::INSERTED);
-  devices_test_api.NotifyObserversStylusStateChanged(ui::StylusState::REMOVED);
-  EXPECT_EQ(0u, observer()->observed_states().size());
-  EXPECT_EQ(0u, tray_action()->observed_states().size());
-  state_controller()->NewNoteLaunchAnimationDone();
-  EXPECT_EQ(1, app_manager()->launch_count());
-}
-
-TEST_F(LockScreenAppStateTest, LaunchActionWhenStylusGetsRemoved) {
-  ui::test::DeviceDataManagerTestAPI devices_test_api;
-  ASSERT_TRUE(InitializeNoteTakingApp(TrayActionState::kAvailable,
-                                      true /* enable_app_launch */));
-  devices_test_api.NotifyObserversStylusStateChanged(ui::StylusState::REMOVED);
-
-  ExpectObservedStatesMatch({TrayActionState::kLaunching},
-                            "Launch on new note request");
-  ClearObservedStates();
-  // When show-md-login flag is present, the action launch process should not
-  // wait for launch animation in lock UI to finish (as is the case with Web UI
-  // base lock).
-  EXPECT_EQ(1, app_manager()->launch_count());
-
-  // If the stylus is inserted and removed while launching the app, there should
-  // be no new launch event.
-  devices_test_api.NotifyObserversStylusStateChanged(ui::StylusState::INSERTED);
-  devices_test_api.NotifyObserversStylusStateChanged(ui::StylusState::REMOVED);
-  EXPECT_EQ(0u, observer()->observed_states().size());
-  EXPECT_EQ(0u, tray_action()->observed_states().size());
-  EXPECT_EQ(1, app_manager()->launch_count());
-}
-
 TEST_F(LockScreenAppStateWebUiLockTest,
        LaunchActionWhenStylusRemoved_ActionClosedBeforeAnimationDone) {
   ui::test::DeviceDataManagerTestAPI devices_test_api;
   ASSERT_TRUE(InitializeNoteTakingApp(TrayActionState::kAvailable,
                                       true /* enable_app_launch */));
-  devices_test_api.NotifyObserversStylusStateChanged(ui::StylusState::REMOVED);
+  tray_action()->SendNewNoteRequest(LockScreenNoteOrigin::kStylusEject);
 
   ExpectObservedStatesMatch({TrayActionState::kLaunching},
                             "Launch on new note request");
@@ -1286,124 +1230,6 @@
   EXPECT_TRUE(tray_action()->observed_states().empty());
 }
 
-TEST_F(LockScreenAppStateTest, StylusRemovedBeforeScreenLock) {
-  ui::test::DeviceDataManagerTestAPI devices_test_api;
-  ASSERT_TRUE(InitializeNoteTakingApp(TrayActionState::kNotAvailable,
-                                      true /* enable_app_launch */));
-
-  devices_test_api.NotifyObserversStylusStateChanged(ui::StylusState::REMOVED);
-  session_manager()->SetSessionState(session_manager::SessionState::LOCKED);
-
-  // Stylus removed event should be ignored if it came before note taking on
-  // lock screen was available (in this case due to session being active).
-  // Screen unlock should still make lock screen note taking available.
-  ExpectObservedStatesMatch({TrayActionState::kAvailable},
-                            "Remove stylus, then unlock.");
-
-  ClearObservedStates();
-  EXPECT_EQ(0, app_manager()->launch_count());
-}
-
-TEST_F(LockScreenAppStateTest, StylusRemovedWhileScreenOff) {
-  ui::test::DeviceDataManagerTestAPI devices_test_api;
-  ASSERT_TRUE(InitializeNoteTakingApp(TrayActionState::kAvailable,
-                                      true /* enable_app_launch */));
-
-  GetPowerManagerClient()->SendBrightnessChanged(0 /* level */,
-                                                 true /* user_initiated */);
-
-  devices_test_api.NotifyObserversStylusStateChanged(ui::StylusState::REMOVED);
-
-  // State should not change if the stylus is removed while the screen is off.
-  EXPECT_EQ(TrayActionState::kAvailable,
-            state_controller()->GetLockScreenNoteState());
-  EXPECT_TRUE(observer()->observed_states().empty());
-  EXPECT_TRUE(tray_action()->observed_states().empty());
-
-  // The note action should be launched if the screen brightness is turned back
-  // up soon after stylus eject.
-  GetPowerManagerClient()->SendBrightnessChanged(70 /* level */,
-                                                 true /* user_initiated */);
-  EXPECT_EQ(TrayActionState::kLaunching,
-            state_controller()->GetLockScreenNoteState());
-  ExpectObservedStatesMatch({TrayActionState::kLaunching},
-                            "Launch on new note request");
-  ClearObservedStates();
-
-  state_controller()->NewNoteLaunchAnimationDone();
-  EXPECT_EQ(1, app_manager()->launch_count());
-}
-
-TEST_F(LockScreenAppStateTest,
-       StylusRemovedWhileScreenOff_LongDelayBeforeScreenOn) {
-  ui::test::DeviceDataManagerTestAPI devices_test_api;
-  ASSERT_TRUE(InitializeNoteTakingApp(TrayActionState::kAvailable,
-                                      true /* enable_app_launch */));
-
-  GetPowerManagerClient()->SendBrightnessChanged(0 /* level */,
-                                                 true /* user_initiated */);
-
-  devices_test_api.NotifyObserversStylusStateChanged(ui::StylusState::REMOVED);
-
-  // State should not change if the stylus is removed while the screen is off.
-  EXPECT_EQ(TrayActionState::kAvailable,
-            state_controller()->GetLockScreenNoteState());
-  EXPECT_TRUE(observer()->observed_states().empty());
-  EXPECT_TRUE(tray_action()->observed_states().empty());
-
-  // If sufficient time has passed, turning screen brightness up should not
-  // launch a lock screen note.
-  tick_clock()->Advance(base::TimeDelta::FromSeconds(10));
-  GetPowerManagerClient()->SendBrightnessChanged(70 /* level */,
-                                                 true /* user_initiated */);
-
-  EXPECT_EQ(TrayActionState::kAvailable,
-            state_controller()->GetLockScreenNoteState());
-  EXPECT_TRUE(observer()->observed_states().empty());
-  EXPECT_TRUE(tray_action()->observed_states().empty());
-}
-
-TEST_F(LockScreenAppStateTest, StylusRemovedAndInsertedWhileScreenOff) {
-  ui::test::DeviceDataManagerTestAPI devices_test_api;
-  ASSERT_TRUE(InitializeNoteTakingApp(TrayActionState::kAvailable,
-                                      true /* enable_app_launch */));
-
-  GetPowerManagerClient()->SendBrightnessChanged(0 /* level */,
-                                                 true /* user_initiated */);
-
-  devices_test_api.NotifyObserversStylusStateChanged(ui::StylusState::REMOVED);
-
-  // State should not change if the stylus is removed while the screen is off.
-  EXPECT_EQ(TrayActionState::kAvailable,
-            state_controller()->GetLockScreenNoteState());
-  EXPECT_TRUE(observer()->observed_states().empty());
-  EXPECT_TRUE(tray_action()->observed_states().empty());
-
-  // Turning the screen brightness up soon after stylus eject should not launch
-  // note taking app if the stylus has been inserted back.
-  devices_test_api.NotifyObserversStylusStateChanged(ui::StylusState::INSERTED);
-  GetPowerManagerClient()->SendBrightnessChanged(70 /* level */,
-                                                 true /* user_initiated */);
-  EXPECT_EQ(TrayActionState::kAvailable,
-            state_controller()->GetLockScreenNoteState());
-  EXPECT_TRUE(observer()->observed_states().empty());
-  EXPECT_TRUE(tray_action()->observed_states().empty());
-}
-
-TEST_F(LockScreenAppStateTest, StylusRemovedWhileActive) {
-  ui::test::DeviceDataManagerTestAPI devices_test_api;
-  ASSERT_TRUE(InitializeNoteTakingApp(TrayActionState::kActive,
-                                      true /* enable_app_launch */));
-
-  devices_test_api.NotifyObserversStylusStateChanged(ui::StylusState::REMOVED);
-
-  EXPECT_EQ(0u, observer()->observed_states().size());
-  EXPECT_EQ(0u, tray_action()->observed_states().size());
-
-  ClearObservedStates();
-  EXPECT_EQ(0, app_manager()->launch_count());
-}
-
 TEST_F(LockScreenAppStateTest, AppWindowRegistration) {
   ASSERT_TRUE(InitializeNoteTakingApp(TrayActionState::kAvailable,
                                       true /* enable_app_launch */));
@@ -1498,39 +1324,6 @@
   EXPECT_TRUE(app_window()->closed());
 }
 
-TEST_F(LockScreenAppStateTest, CloseAppWindowOnScreenOff) {
-  ASSERT_TRUE(InitializeNoteTakingApp(TrayActionState::kActive,
-                                      true /* enable_app_launch */));
-
-  GetPowerManagerClient()->SendBrightnessChanged(10 /* level */,
-                                                 true /* user_initiated */);
-  base::RunLoop().RunUntilIdle();
-  EXPECT_FALSE(app_window()->closed());
-  EXPECT_EQ(TrayActionState::kActive,
-            state_controller()->GetLockScreenNoteState());
-
-  GetPowerManagerClient()->SendBrightnessChanged(0 /* level */,
-                                                 true /* user_initiated */);
-  base::RunLoop().RunUntilIdle();
-  EXPECT_FALSE(app_window()->closed());
-  EXPECT_EQ(TrayActionState::kActive,
-            state_controller()->GetLockScreenNoteState());
-
-  GetPowerManagerClient()->SendBrightnessChanged(10 /* level */,
-                                                 false /* user_initiated */);
-  base::RunLoop().RunUntilIdle();
-  EXPECT_FALSE(app_window()->closed());
-  EXPECT_EQ(TrayActionState::kActive,
-            state_controller()->GetLockScreenNoteState());
-
-  GetPowerManagerClient()->SendBrightnessChanged(0 /* level */,
-                                                 false /* user_initiated */);
-  base::RunLoop().RunUntilIdle();
-  EXPECT_TRUE(app_window()->closed());
-  EXPECT_EQ(TrayActionState::kAvailable,
-            state_controller()->GetLockScreenNoteState());
-}
-
 TEST_F(LockScreenAppStateTest, AppWindowClosedOnAppUnload) {
   ASSERT_TRUE(InitializeNoteTakingApp(TrayActionState::kActive,
                                       true /* enable_app_launch */));
diff --git a/chrome/browser/chromeos/login/lock/screen_locker.h b/chrome/browser/chromeos/login/lock/screen_locker.h
index 791d3b6..8755614 100644
--- a/chrome/browser/chromeos/login/lock/screen_locker.h
+++ b/chrome/browser/chromeos/login/lock/screen_locker.h
@@ -109,7 +109,6 @@
   // Returns the default instance if it has been created.
   static ScreenLocker* default_screen_locker() { return screen_locker_; }
 
-  // Returns true if the lock UI has been confirmed as displayed.
   bool locked() const { return locked_; }
 
   // Initialize and show the screen locker.
diff --git a/chrome/browser/chromeos/net/cert_verify_proc_chromeos_unittest.cc b/chrome/browser/chromeos/net/cert_verify_proc_chromeos_unittest.cc
index e2e46326..fabd1c9 100644
--- a/chrome/browser/chromeos/net/cert_verify_proc_chromeos_unittest.cc
+++ b/chrome/browser/chromeos/net/cert_verify_proc_chromeos_unittest.cc
@@ -12,6 +12,7 @@
 #include "net/cert/cert_verify_proc.h"
 #include "net/cert/cert_verify_result.h"
 #include "net/cert/nss_cert_database_chromeos.h"
+#include "net/cert/x509_util.h"
 #include "net/cert/x509_util_nss.h"
 #include "net/test/cert_test_util.h"
 #include "net/test/test_data_directory.h"
@@ -21,10 +22,10 @@
 
 namespace {
 
-std::string GetSubjectCN(net::X509Certificate::OSCertHandle cert_handle) {
+std::string GetSubjectCN(CRYPTO_BUFFER* cert_handle) {
   scoped_refptr<net::X509Certificate> cert =
-      net::X509Certificate::CreateFromHandle(
-          cert_handle, net::X509Certificate::OSCertHandles());
+      net::X509Certificate::CreateFromBuffer(
+          net::x509_util::DupCryptoBuffer(cert_handle), {});
   if (!cert)
     return std::string();
   return "CN=" + cert->subject().common_name;
@@ -109,10 +110,9 @@
     int error =
         verify_proc->Verify(cert, "127.0.0.1", std::string(), flags, NULL,
                             additional_trust_anchors, &verify_result);
-    if (!verify_result.verified_cert->GetIntermediateCertificates().empty()) {
-      net::X509Certificate::OSCertHandle root =
-          verify_result.verified_cert->GetIntermediateCertificates().back();
-      root_subject_name->assign(GetSubjectCN(root));
+    if (!verify_result.verified_cert->intermediate_buffers().empty()) {
+      root_subject_name->assign(GetSubjectCN(
+          verify_result.verified_cert->intermediate_buffers().back().get()));
     } else {
       root_subject_name->clear();
     }
diff --git a/chrome/browser/chromeos/platform_keys/platform_keys.cc b/chrome/browser/chromeos/platform_keys/platform_keys.cc
index 0b2f0a6..48243d5 100644
--- a/chrome/browser/chromeos/platform_keys/platform_keys.cc
+++ b/chrome/browser/chromeos/platform_keys/platform_keys.cc
@@ -29,13 +29,13 @@
   // Fill the map with fingerprints of certs from |certs2|.
   for (const auto& cert2 : certs2) {
     fingerprints2[net::X509Certificate::CalculateFingerprint256(
-        cert2->os_cert_handle())] = cert2;
+        cert2->cert_buffer())] = cert2;
   }
 
   // Compare each cert from |certs1| with the entries of the map.
   for (const auto& cert1 : certs1) {
     const net::SHA256HashValue fingerprint1 =
-        net::X509Certificate::CalculateFingerprint256(cert1->os_cert_handle());
+        net::X509Certificate::CalculateFingerprint256(cert1->cert_buffer());
     const auto it = fingerprints2.find(fingerprint1);
     if (it == fingerprints2.end())
       continue;
diff --git a/chrome/browser/chromeos/platform_keys/platform_keys_nss.cc b/chrome/browser/chromeos/platform_keys/platform_keys_nss.cc
index c8bf905..d18c43de 100644
--- a/chrome/browser/chromeos/platform_keys/platform_keys_nss.cc
+++ b/chrome/browser/chromeos/platform_keys/platform_keys_nss.cc
@@ -42,6 +42,7 @@
 #include "net/cert/asn1_util.h"
 #include "net/cert/cert_database.h"
 #include "net/cert/nss_cert_database.h"
+#include "net/cert/x509_util.h"
 #include "net/cert/x509_util_nss.h"
 #include "net/ssl/ssl_cert_request_info.h"
 #include "net/third_party/mozilla_security_manager/nsNSSCertificateDB.h"
@@ -830,13 +831,10 @@
 
 std::string GetSubjectPublicKeyInfo(
     const scoped_refptr<net::X509Certificate>& certificate) {
-  std::string der_bytes;
-  if (!net::X509Certificate::GetDEREncoded(certificate->os_cert_handle(),
-                                           &der_bytes))
-    return {};
-
   base::StringPiece spki_bytes;
-  if (!net::asn1::ExtractSPKIFromDERCert(der_bytes, &spki_bytes))
+  if (!net::asn1::ExtractSPKIFromDERCert(
+          net::x509_util::CryptoBufferAsStringPiece(certificate->cert_buffer()),
+          &spki_bytes))
     return {};
   return spki_bytes.as_string();
 }
@@ -847,7 +845,7 @@
   net::X509Certificate::PublicKeyType key_type_tmp =
       net::X509Certificate::kPublicKeyTypeUnknown;
   size_t key_size_bits_tmp = 0;
-  net::X509Certificate::GetPublicKeyInfo(certificate->os_cert_handle(),
+  net::X509Certificate::GetPublicKeyInfo(certificate->cert_buffer(),
                                          &key_size_bits_tmp, &key_type_tmp);
 
   if (key_type_tmp == net::X509Certificate::kPublicKeyTypeUnknown) {
diff --git a/chrome/browser/chromeos/platform_keys/platform_keys_service.cc b/chrome/browser/chromeos/platform_keys/platform_keys_service.cc
index 75c7ea1..4bc40414 100644
--- a/chrome/browser/chromeos/platform_keys/platform_keys_service.cc
+++ b/chrome/browser/chromeos/platform_keys/platform_keys_service.cc
@@ -424,7 +424,7 @@
             net::X509Certificate::kPublicKeyTypeUnknown;
         size_t unused_key_size = 0;
         net::X509Certificate::GetPublicKeyInfo(
-            certificate->os_cert_handle(), &unused_key_size, &actual_key_type);
+            certificate->cert_buffer(), &unused_key_size, &actual_key_type);
         const std::vector<net::X509Certificate::PublicKeyType>& accepted_types =
             request_.certificate_key_types;
         if (!base::ContainsValue(accepted_types, actual_key_type))
diff --git a/chrome/browser/chromeos/smb_client/smb_service.cc b/chrome/browser/chromeos/smb_client/smb_service.cc
index 79c00b6..96d4ca0 100644
--- a/chrome/browser/chromeos/smb_client/smb_service.cc
+++ b/chrome/browser/chromeos/smb_client/smb_service.cc
@@ -15,7 +15,10 @@
 SmbService::SmbService(Profile* profile)
     : profile_(profile),
       provider_id_(ProviderId::CreateFromNativeId("smb")),
-      capabilities_(false, false, false, extensions::SOURCE_NETWORK) {
+      capabilities_(false, false, false, extensions::SOURCE_NETWORK),
+      // TODO(baileyberro): Localize this string, so it shows correctly in all
+      // languages. See l10n_util::GetStringUTF8.
+      name_("SMB Shares") {
   GetProviderService()->RegisterProvider(std::make_unique<SmbService>(profile));
 }
 
@@ -46,5 +49,9 @@
   return provider_id_;
 }
 
+const std::string& SmbService::GetName() const {
+  return name_;
+}
+
 }  // namespace smb_client
 }  // namespace chromeos
diff --git a/chrome/browser/chromeos/smb_client/smb_service.h b/chrome/browser/chromeos/smb_client/smb_service.h
index ad8afba9..c73142b3d 100644
--- a/chrome/browser/chromeos/smb_client/smb_service.h
+++ b/chrome/browser/chromeos/smb_client/smb_service.h
@@ -6,6 +6,7 @@
 #define CHROME_BROWSER_CHROMEOS_SMB_CLIENT_SMB_SERVICE_H_
 
 #include <memory>
+#include <string>
 
 #include "base/files/file.h"
 #include "base/macros.h"
@@ -41,6 +42,7 @@
       const ProvidedFileSystemInfo& file_system_info) override;
   const Capabilities& GetCapabilities() const override;
   const ProviderId& GetId() const override;
+  const std::string& GetName() const override;
 
  private:
   Service* GetProviderService() const;
@@ -48,6 +50,7 @@
   Profile* profile_;
   ProviderId provider_id_;
   Capabilities capabilities_;
+  std::string name_;
 
   DISALLOW_COPY_AND_ASSIGN(SmbService);
 };
diff --git a/chrome/browser/custom_handlers/protocol_handler_registry_unittest.cc b/chrome/browser/custom_handlers/protocol_handler_registry_unittest.cc
index f2b4891..5b47bd09 100644
--- a/chrome/browser/custom_handlers/protocol_handler_registry_unittest.cc
+++ b/chrome/browser/custom_handlers/protocol_handler_registry_unittest.cc
@@ -991,3 +991,16 @@
   ASSERT_EQ(InPrefIgnoredHandlerCount(), 1);
   ASSERT_EQ(InMemoryIgnoredHandlerCount(), 4);
 }
+
+TEST_F(ProtocolHandlerRegistryTest, TestMultiplePlaceholders) {
+  ProtocolHandler ph =
+      CreateProtocolHandler("test", GURL("http://example.com/%s/url=%s"));
+  registry()->OnAcceptRegisterProtocolHandler(ph);
+
+  GURL translated_url = ph.TranslateUrl(GURL("test:duplicated_placeholders"));
+
+  // When URL contains multiple placeholders, only the first placeholder should
+  // be changed to the given URL.
+  ASSERT_EQ(translated_url,
+            GURL("http://example.com/test%3Aduplicated_placeholders/url=%s"));
+}
diff --git a/chrome/browser/devtools/device/android_device_manager.cc b/chrome/browser/devtools/device/android_device_manager.cc
index 1bd8dcf..7fa8c23 100644
--- a/chrome/browser/devtools/device/android_device_manager.cc
+++ b/chrome/browser/devtools/device/android_device_manager.cc
@@ -12,6 +12,7 @@
 #include "base/location.h"
 #include "base/memory/ptr_util.h"
 #include "base/message_loop/message_loop.h"
+#include "base/strings/strcat.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
@@ -163,7 +164,7 @@
     }
     pieces.insert(pieces.end(), {crlf});
 
-    std::string request = base::JoinString(pieces, "");
+    std::string request = base::StrCat(pieces);
     scoped_refptr<net::IOBuffer> base_buffer =
         new net::IOBuffer(request.size());
     memcpy(base_buffer->data(), request.data(), request.size());
diff --git a/chrome/browser/experiments/memory_ablation_experiment.cc b/chrome/browser/experiments/memory_ablation_experiment.cc
index ef98d0ba..4603a4b 100644
--- a/chrome/browser/experiments/memory_ablation_experiment.cc
+++ b/chrome/browser/experiments/memory_ablation_experiment.cc
@@ -12,6 +12,7 @@
 #include "base/debug/alias.h"
 #include "base/metrics/field_trial_params.h"
 #include "base/process/process_metrics.h"
+#include "base/rand_util.h"
 #include "base/sequenced_task_runner.h"
 #include "base/sys_info.h"
 
@@ -86,13 +87,26 @@
 void MemoryAblationExperiment::TouchMemory(size_t offset) {
   if (memory_) {
     size_t page_size = base::GetPageSize();
-    auto* memory = static_cast<volatile uint8_t*>(memory_.get());
+    uint8_t* memory = memory_.get();
     size_t max_offset = std::min(offset + kTouchChunkSize, memory_size_);
+    if (offset == 0) {
+      // Fill the first page with random bytes. We'll use this page as
+      // a template for all other pages.
+      size_t rand_size = std::min(page_size, memory_size_);
+      base::RandBytes(memory, rand_size);
+      offset += rand_size;
+    }
     for (; offset < max_offset; offset += page_size) {
-      memory[offset] = static_cast<uint8_t>(offset);
+      // Copy from the first page.
+      size_t copy_size = std::min(page_size, max_offset - offset);
+      memcpy(memory + offset, memory, copy_size);
+      // Make this page different by stamping it with the offset.
+      if (copy_size >= sizeof(size_t)) {
+        *reinterpret_cast<size_t*>(memory + offset) = offset;
+      }
     }
     // Make sure compiler doesn't optimize away the writes.
-    base::debug::Alias(memory_.get());
+    base::debug::Alias(memory);
     if (offset < memory_size_) {
       ScheduleTouchMemory(offset);
     }
diff --git a/chrome/browser/extensions/api/autotest_private/autotest_private_api.cc b/chrome/browser/extensions/api/autotest_private/autotest_private_api.cc
index 8432002..b01bc99 100644
--- a/chrome/browser/extensions/api/autotest_private/autotest_private_api.cc
+++ b/chrome/browser/extensions/api/autotest_private/autotest_private_api.cc
@@ -109,12 +109,8 @@
 #if defined(OS_CHROMEOS)
   const user_manager::UserManager* user_manager =
       user_manager::UserManager::Get();
-
-  // default_screen_locker()->locked() is set when the UI is ready, so this
-  // tells us both views based lockscreen UI and screenlocker are ready.
   const bool is_screen_locked =
-      !!chromeos::ScreenLocker::default_screen_locker() &&
-      chromeos::ScreenLocker::default_screen_locker()->locked();
+      !!chromeos::ScreenLocker::default_screen_locker();
 
   if (user_manager) {
     result->SetBoolean("isLoggedIn", user_manager->IsUserLoggedIn());
diff --git a/chrome/browser/extensions/api/cast_streaming/performance_test.cc b/chrome/browser/extensions/api/cast_streaming/performance_test.cc
index d505f8b..8a53d8a 100644
--- a/chrome/browser/extensions/api/cast_streaming/performance_test.cc
+++ b/chrome/browser/extensions/api/cast_streaming/performance_test.cc
@@ -104,26 +104,25 @@
 
 class SkewedCastEnvironment : public media::cast::StandaloneCastEnvironment {
  public:
-  explicit SkewedCastEnvironment(const base::TimeDelta& delta) :
-      StandaloneCastEnvironment() {
-    auto skewed_clock =
-        base::MakeUnique<media::cast::test::SkewedTickClock>(&default_clock_);
+  explicit SkewedCastEnvironment(const base::TimeDelta& delta)
+      : StandaloneCastEnvironment(),
+        skewed_clock_(base::DefaultTickClock::GetInstance()) {
     // If testing with a receiver clock that is ahead or behind the sender
     // clock, fake a clock that is offset and also ticks at a rate of 50 parts
     // per million faster or slower than the local sender's clock. This is the
     // worst-case scenario for skew in-the-wild.
     if (!delta.is_zero()) {
       const double skew = delta < base::TimeDelta() ? 0.999950 : 1.000050;
-      skewed_clock->SetSkew(skew, delta);
+      skewed_clock_.SetSkew(skew, delta);
     }
-    clock_ = std::move(skewed_clock);
+    clock_ = &skewed_clock_;
   }
 
  protected:
   ~SkewedCastEnvironment() override {}
 
  private:
-  base::DefaultTickClock default_clock_;
+  media::cast::test::SkewedTickClock skewed_clock_;
 };
 
 // We log one of these for each call to OnAudioFrame/OnVideoFrame.
diff --git a/chrome/browser/extensions/api/certificate_provider/certificate_provider_api.cc b/chrome/browser/extensions/api/certificate_provider/certificate_provider_api.cc
index 4b792356..83528fa0 100644
--- a/chrome/browser/extensions/api/certificate_provider/certificate_provider_api.cc
+++ b/chrome/browser/extensions/api/certificate_provider/certificate_provider_api.cc
@@ -139,9 +139,8 @@
   size_t public_key_length_in_bits = 0;
   net::X509Certificate::PublicKeyType type =
       net::X509Certificate::kPublicKeyTypeUnknown;
-  net::X509Certificate::GetPublicKeyInfo(
-      out_info->certificate->os_cert_handle(), &public_key_length_in_bits,
-      &type);
+  net::X509Certificate::GetPublicKeyInfo(out_info->certificate->cert_buffer(),
+                                         &public_key_length_in_bits, &type);
 
   switch (type) {
     case net::X509Certificate::kPublicKeyTypeRSA:
diff --git a/chrome/browser/extensions/api/developer_private/developer_private_api.cc b/chrome/browser/extensions/api/developer_private/developer_private_api.cc
index 45cf2051..d261f135 100644
--- a/chrome/browser/extensions/api/developer_private/developer_private_api.cc
+++ b/chrome/browser/extensions/api/developer_private/developer_private_api.cc
@@ -189,6 +189,29 @@
   return info;
 }
 
+// Creates a developer::LoadError from the provided data.
+developer::LoadError CreateLoadError(
+    const base::FilePath& file_path,
+    const std::string& error,
+    size_t line_number,
+    const std::string& manifest,
+    const DeveloperPrivateAPI::UnpackedRetryId& retry_guid) {
+  base::FilePath prettified_path = path_util::PrettifyPath(file_path);
+
+  SourceHighlighter highlighter(manifest, line_number);
+  developer::LoadError response;
+  response.error = error;
+  response.path = base::UTF16ToUTF8(prettified_path.LossyDisplayName());
+  response.retry_guid = retry_guid;
+
+  response.source = std::make_unique<developer::ErrorFileSource>();
+  response.source->before_highlight = highlighter.GetBeforeFeature();
+  response.source->highlight = highlighter.GetFeature();
+  response.source->after_highlight = highlighter.GetAfterFeature();
+
+  return response;
+}
+
 }  // namespace
 
 namespace ChoosePath = api::developer_private::ChoosePath;
@@ -724,6 +747,8 @@
   return RespondNow(NoArguments());
 }
 
+DeveloperPrivateReloadFunction::DeveloperPrivateReloadFunction()
+    : registry_observer_(this), error_reporter_observer_(this) {}
 DeveloperPrivateReloadFunction::~DeveloperPrivateReloadFunction() {}
 
 ExtensionFunction::ResponseAction DeveloperPrivateReloadFunction::Run() {
@@ -734,9 +759,19 @@
   if (!extension)
     return RespondNow(Error(kNoSuchExtensionError));
 
-  bool fail_quietly = params->options &&
-                      params->options->fail_quietly &&
-                      *params->options->fail_quietly;
+  reloading_extension_path_ = extension->path();
+
+  bool fail_quietly = false;
+  bool wait_for_completion = false;
+  if (params->options) {
+    fail_quietly =
+        params->options->fail_quietly && *params->options->fail_quietly;
+    // We only wait for completion for unpacked extensions, since they are the
+    // only extensions for which we can show actionable feedback to the user.
+    wait_for_completion = params->options->populate_error_for_unpacked &&
+                          *params->options->populate_error_for_unpacked &&
+                          Manifest::IsUnpackedLocation(extension->location());
+  }
 
   ExtensionService* service = GetExtensionService(browser_context());
   if (fail_quietly)
@@ -744,9 +779,73 @@
   else
     service->ReloadExtension(params->extension_id);
 
-  // TODO(devlin): We shouldn't return until the extension has finished trying
-  // to reload (and then we could also return the error).
-  return RespondNow(NoArguments());
+  if (!wait_for_completion)
+    return RespondNow(NoArguments());
+
+  // Balanced in ClearObservers(), which is called from the first observer
+  // method to be called with the appropriate extension (or shutdown).
+  AddRef();
+  error_reporter_observer_.Add(ExtensionErrorReporter::GetInstance());
+  registry_observer_.Add(ExtensionRegistry::Get(browser_context()));
+
+  return RespondLater();
+}
+
+void DeveloperPrivateReloadFunction::OnExtensionLoaded(
+    content::BrowserContext* browser_context,
+    const Extension* extension) {
+  if (extension->path() == reloading_extension_path_) {
+    // Reload succeeded!
+    Respond(NoArguments());
+    ClearObservers();
+  }
+}
+
+void DeveloperPrivateReloadFunction::OnShutdown(ExtensionRegistry* registry) {
+  Respond(Error("Shutting down."));
+  ClearObservers();
+}
+
+void DeveloperPrivateReloadFunction::OnLoadFailure(
+    content::BrowserContext* browser_context,
+    const base::FilePath& file_path,
+    const std::string& error) {
+  if (file_path == reloading_extension_path_) {
+    // Reload failed - create an error to pass back to the extension.
+    ExtensionLoaderHandler::GetManifestError(
+        error, file_path,
+        // TODO(devlin): Update GetManifestError to take a OnceCallback.
+        base::BindRepeating(&DeveloperPrivateReloadFunction::OnGotManifestError,
+                            this));  // Creates a reference.
+    ClearObservers();
+  }
+}
+
+void DeveloperPrivateReloadFunction::OnGotManifestError(
+    const base::FilePath& file_path,
+    const std::string& error,
+    size_t line_number,
+    const std::string& manifest) {
+  DeveloperPrivateAPI::UnpackedRetryId retry_guid =
+      DeveloperPrivateAPI::Get(browser_context())
+          ->AddUnpackedPath(GetSenderWebContents(), reloading_extension_path_);
+  // Respond to the caller with the load error, which allows the caller to retry
+  // reloading through developerPrivate.loadUnpacked().
+  // TODO(devlin): This is weird. Really, we should allow retrying through this
+  // function instead of through loadUnpacked(), but
+  // ExtensionService::ReloadExtension doesn't behave well with an extension
+  // that failed to reload, and untangling that mess is quite significant.
+  // See https://crbug.com/792277.
+  Respond(OneArgument(
+      CreateLoadError(file_path, error, line_number, manifest, retry_guid)
+          .ToValue()));
+}
+
+void DeveloperPrivateReloadFunction::ClearObservers() {
+  registry_observer_.RemoveAll();
+  error_reporter_observer_.RemoveAll();
+
+  Release();  // Balanced in Run().
 }
 
 DeveloperPrivateShowPermissionsDialogFunction::
@@ -865,20 +964,9 @@
     size_t line_number,
     const std::string& manifest) {
   DCHECK(!retry_guid_.empty());
-  base::FilePath prettified_path = path_util::PrettifyPath(file_path);
-
-  SourceHighlighter highlighter(manifest, line_number);
-  developer::LoadError response;
-  response.error = error;
-  response.path = base::UTF16ToUTF8(prettified_path.LossyDisplayName());
-  response.retry_guid = retry_guid_;
-
-  response.source = base::MakeUnique<developer::ErrorFileSource>();
-  response.source->before_highlight = highlighter.GetBeforeFeature();
-  response.source->highlight = highlighter.GetFeature();
-  response.source->after_highlight = highlighter.GetAfterFeature();
-
-  Respond(OneArgument(response.ToValue()));
+  Respond(OneArgument(
+      CreateLoadError(file_path, error, line_number, manifest, retry_guid_)
+          .ToValue()));
 }
 
 bool DeveloperPrivateChooseEntryFunction::ShowPicker(
diff --git a/chrome/browser/extensions/api/developer_private/developer_private_api.h b/chrome/browser/extensions/api/developer_private/developer_private_api.h
index ac72496..ed423b1d 100644
--- a/chrome/browser/extensions/api/developer_private/developer_private_api.h
+++ b/chrome/browser/extensions/api/developer_private/developer_private_api.h
@@ -15,6 +15,7 @@
 #include "chrome/browser/extensions/api/developer_private/entry_picker.h"
 #include "chrome/browser/extensions/chrome_extension_function.h"
 #include "chrome/browser/extensions/error_console/error_console.h"
+#include "chrome/browser/extensions/extension_error_reporter.h"
 #include "chrome/browser/extensions/extension_management.h"
 #include "chrome/browser/extensions/extension_uninstall_dialog.h"
 #include "chrome/browser/extensions/pack_extension_job.h"
@@ -353,16 +354,50 @@
   ResponseAction Run() override;
 };
 
-class DeveloperPrivateReloadFunction : public DeveloperPrivateAPIFunction {
+class DeveloperPrivateReloadFunction : public DeveloperPrivateAPIFunction,
+                                       public ExtensionRegistryObserver,
+                                       public ExtensionErrorReporter::Observer {
  public:
   DECLARE_EXTENSION_FUNCTION("developerPrivate.reload",
                              DEVELOPERPRIVATE_RELOAD);
 
+  DeveloperPrivateReloadFunction();
+
+  // ExtensionRegistryObserver:
+  void OnExtensionLoaded(content::BrowserContext* browser_context,
+                         const Extension* extension) override;
+  void OnShutdown(ExtensionRegistry* registry) override;
+
+  // ExtensionErrorReporter::Observer:
+  void OnLoadFailure(content::BrowserContext* browser_context,
+                     const base::FilePath& file_path,
+                     const std::string& error) override;
+
  protected:
   ~DeveloperPrivateReloadFunction() override;
 
   // ExtensionFunction:
   ResponseAction Run() override;
+
+ private:
+  // Callback once we parse a manifest error from a failed reload.
+  void OnGotManifestError(const base::FilePath& file_path,
+                          const std::string& error,
+                          size_t line_number,
+                          const std::string& manifest);
+
+  // Clears the scoped observers.
+  void ClearObservers();
+
+  // The file path of the extension that's reloading.
+  base::FilePath reloading_extension_path_;
+
+  ScopedObserver<ExtensionRegistry, ExtensionRegistryObserver>
+      registry_observer_;
+  ScopedObserver<ExtensionErrorReporter, ExtensionErrorReporter::Observer>
+      error_reporter_observer_;
+
+  DISALLOW_COPY_AND_ASSIGN(DeveloperPrivateReloadFunction);
 };
 
 class DeveloperPrivateShowPermissionsDialogFunction
diff --git a/chrome/browser/extensions/api/developer_private/developer_private_api_unittest.cc b/chrome/browser/extensions/api/developer_private/developer_private_api_unittest.cc
index a4a281a..2b7ccc2 100644
--- a/chrome/browser/extensions/api/developer_private/developer_private_api_unittest.cc
+++ b/chrome/browser/extensions/api/developer_private/developer_private_api_unittest.cc
@@ -10,8 +10,10 @@
 #include "base/files/file_util.h"
 #include "base/macros.h"
 #include "base/memory/ptr_util.h"
+#include "base/scoped_observer.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/chrome_notification_types.h"
+#include "chrome/browser/extensions/chrome_test_extension_loader.h"
 #include "chrome/browser/extensions/error_console/error_console.h"
 #include "chrome/browser/extensions/extension_function_test_utils.h"
 #include "chrome/browser/extensions/extension_service.h"
@@ -40,6 +42,7 @@
 #include "extensions/browser/extension_error_test_util.h"
 #include "extensions/browser/extension_prefs.h"
 #include "extensions/browser/extension_registry.h"
+#include "extensions/browser/extension_registry_observer.h"
 #include "extensions/browser/extension_system.h"
 #include "extensions/browser/extension_util.h"
 #include "extensions/browser/mock_external_provider.h"
@@ -736,6 +739,128 @@
   }
 }
 
+// Tests calling "reload" on an unpacked extension with a manifest error,
+// resulting in the reload failing. The reload call should then respond with
+// the load error, which includes a retry GUID to be passed to loadUnpacked().
+TEST_F(DeveloperPrivateApiUnitTest, ReloadBadExtensionToLoadUnpackedRetry) {
+  std::unique_ptr<content::WebContents> web_contents(
+      content::WebContentsTester::CreateTestWebContents(profile(), nullptr));
+
+  // A broken manifest (version's value should be a string).
+  constexpr const char kBadManifest[] =
+      R"({
+           "name": "foo",
+           "description": "bar",
+           "version": 1,
+           "manifest_version": 2
+         })";
+  constexpr const char kGoodManifest[] =
+      R"({
+           "name": "foo",
+           "description": "bar",
+           "version": "1",
+           "manifest_version": 2
+         })";
+
+  // Create a good unpacked extension.
+  TestExtensionDir dir;
+  dir.WriteManifest(kGoodManifest);
+  base::FilePath path = dir.UnpackedPath();
+  api::EntryPicker::SkipPickerAndAlwaysSelectPathForTest(&path);
+
+  scoped_refptr<const Extension> extension;
+  {
+    ChromeTestExtensionLoader loader(profile());
+    loader.set_pack_extension(false);
+    extension = loader.LoadExtension(path);
+  }
+  ASSERT_TRUE(extension);
+  const ExtensionId id = extension->id();
+
+  std::string reload_args = base::StringPrintf(
+      R"(["%s", {"failQuietly": true, "populateErrorForUnpacked":true}])",
+      id.c_str());
+
+  {
+    // Try reloading while the manifest is still good. This should succeed, and
+    // the extension should still be enabled. Additionally, the function should
+    // wait for the reload to complete, so we should see an unload and reload.
+    class UnloadedRegistryObserver : public ExtensionRegistryObserver {
+     public:
+      UnloadedRegistryObserver(const base::FilePath& expected_path,
+                               ExtensionRegistry* registry)
+          : expected_path_(expected_path), observer_(this) {
+        observer_.Add(registry);
+      }
+
+      void OnExtensionUnloaded(content::BrowserContext* browser_context,
+                               const Extension* extension,
+                               UnloadedExtensionReason reason) override {
+        ASSERT_FALSE(saw_unload_);
+        saw_unload_ = extension->path() == expected_path_;
+      }
+
+      bool saw_unload() const { return saw_unload_; }
+
+     private:
+      bool saw_unload_ = false;
+      base::FilePath expected_path_;
+      ScopedObserver<ExtensionRegistry, ExtensionRegistryObserver> observer_;
+
+      DISALLOW_COPY_AND_ASSIGN(UnloadedRegistryObserver);
+    };
+
+    UnloadedRegistryObserver unload_observer(path, registry());
+    auto function =
+        base::MakeRefCounted<api::DeveloperPrivateReloadFunction>();
+    function->SetRenderFrameHost(web_contents->GetMainFrame());
+    api_test_utils::RunFunction(function.get(), reload_args, profile());
+    // Note: no need to validate a saw_load()-type method because the presence
+    // in enabled_extensions() indicates the extension was loaded.
+    EXPECT_TRUE(unload_observer.saw_unload());
+    EXPECT_TRUE(registry()->enabled_extensions().Contains(id));
+  }
+
+  dir.WriteManifest(kBadManifest);
+
+  DeveloperPrivateAPI::UnpackedRetryId retry_guid;
+  {
+    // Trying to load the extension should result in a load error with the
+    // retry GUID populated.
+    auto function = base::MakeRefCounted<api::DeveloperPrivateReloadFunction>();
+    function->SetRenderFrameHost(web_contents->GetMainFrame());
+    std::unique_ptr<base::Value> result =
+        api_test_utils::RunFunctionAndReturnSingleResult(
+            function.get(), reload_args, profile());
+    ASSERT_TRUE(result);
+    std::unique_ptr<api::developer_private::LoadError> error =
+        api::developer_private::LoadError::FromValue(*result);
+    ASSERT_TRUE(error);
+    EXPECT_FALSE(error->retry_guid.empty());
+    retry_guid = error->retry_guid;
+    EXPECT_TRUE(registry()->disabled_extensions().Contains(id));
+  }
+
+  dir.WriteManifest(kGoodManifest);
+  {
+    // Try reloading the extension by supplying the retry id. It should succeed,
+    // and the extension should be enabled again.
+    auto function =
+        base::MakeRefCounted<api::DeveloperPrivateLoadUnpackedFunction>();
+    function->SetRenderFrameHost(web_contents->GetMainFrame());
+    TestExtensionRegistryObserver observer(registry());
+    std::string args =
+        base::StringPrintf(R"([{"failQuietly": true, "populateError": true,
+                                "retryGuid": "%s"}])",
+                           retry_guid.c_str());
+    api_test_utils::RunFunction(function.get(), args, profile());
+    const Extension* extension = observer.WaitForExtensionLoaded();
+    ASSERT_TRUE(extension);
+    EXPECT_EQ(extension->path(), path);
+    EXPECT_TRUE(registry()->enabled_extensions().Contains(id));
+  }
+}
+
 // Test developerPrivate.requestFileSource.
 TEST_F(DeveloperPrivateApiUnitTest, DeveloperPrivateRequestFileSource) {
   // Testing of this function seems light, but that's because it basically just
diff --git a/chrome/browser/extensions/api/enterprise_platform_keys/enterprise_platform_keys_api.cc b/chrome/browser/extensions/api/enterprise_platform_keys/enterprise_platform_keys_api.cc
index d20974aad..38502bd 100644
--- a/chrome/browser/extensions/api/enterprise_platform_keys/enterprise_platform_keys_api.cc
+++ b/chrome/browser/extensions/api/enterprise_platform_keys/enterprise_platform_keys_api.cc
@@ -16,6 +16,7 @@
 #include "chrome/common/extensions/api/enterprise_platform_keys_internal.h"
 #include "content/public/browser/browser_thread.h"
 #include "net/cert/x509_certificate.h"
+#include "net/cert/x509_util.h"
 
 namespace extensions {
 
@@ -117,10 +118,10 @@
   for (net::CertificateList::const_iterator it = certs->begin();
        it != certs->end();
        ++it) {
-    std::string der_encoding;
-    net::X509Certificate::GetDEREncoded((*it)->os_cert_handle(), &der_encoding);
-    client_certs->Append(base::Value::CreateWithCopiedBuffer(
-        der_encoding.data(), der_encoding.size()));
+    base::StringPiece cert_der =
+        net::x509_util::CryptoBufferAsStringPiece((*it)->cert_buffer());
+    client_certs->Append(std::make_unique<base::Value>(
+        base::Value::BlobStorage(cert_der.begin(), cert_der.end())));
   }
 
   std::unique_ptr<base::ListValue> results(new base::ListValue());
diff --git a/chrome/browser/extensions/api/platform_keys/platform_keys_api.cc b/chrome/browser/extensions/api/platform_keys/platform_keys_api.cc
index 7fd7ef4d..3cfa9e9 100644
--- a/chrome/browser/extensions/api/platform_keys/platform_keys_api.cc
+++ b/chrome/browser/extensions/api/platform_keys/platform_keys_api.cc
@@ -21,6 +21,7 @@
 #include "content/public/browser/browser_thread.h"
 #include "net/base/net_errors.h"
 #include "net/cert/x509_certificate.h"
+#include "net/cert/x509_util.h"
 
 namespace extensions {
 
@@ -273,9 +274,8 @@
     }
 
     api_pk::Match result_match;
-    std::string der_encoded_cert;
-    net::X509Certificate::GetDEREncoded(match->os_cert_handle(),
-                                        &der_encoded_cert);
+    base::StringPiece der_encoded_cert =
+        net::x509_util::CryptoBufferAsStringPiece(match->cert_buffer());
     result_match.certificate.assign(der_encoded_cert.begin(),
                                     der_encoded_cert.end());
 
diff --git a/chrome/browser/extensions/bookmark_app_navigation_throttle.cc b/chrome/browser/extensions/bookmark_app_navigation_throttle.cc
index fc6d2eb..7e1a97c 100644
--- a/chrome/browser/extensions/bookmark_app_navigation_throttle.cc
+++ b/chrome/browser/extensions/bookmark_app_navigation_throttle.cc
@@ -23,6 +23,7 @@
 #include "chrome/common/extensions/api/url_handlers/url_handlers_parser.h"
 #include "content/public/browser/browser_context.h"
 #include "content/public/browser/browser_thread.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"
@@ -349,6 +350,19 @@
       return content::NavigationThrottle::CANCEL_AND_IGNORE;
     }
 
+    content::NavigationEntry* last_entry = navigation_handle()
+                                               ->GetWebContents()
+                                               ->GetController()
+                                               .GetLastCommittedEntry();
+    // We are about to open a new app window context. Record the time since the
+    // last navigation in this context. (If it is very small, this context
+    // probably redirected immediately, which is a bad user experience.)
+    if (last_entry && !last_entry->GetTimestamp().is_null()) {
+      UMA_HISTOGRAM_MEDIUM_TIMES(
+          "Extensions.BookmarkApp.OpenAppDeltaSinceLastNavigation",
+          base::Time::Now() - last_entry->GetTimestamp());
+    }
+
     content::NavigationThrottle::ThrottleCheckResult result =
         OpenInAppWindowAndCloseTabIfNecessary(target_app);
 
@@ -464,6 +478,7 @@
 
 scoped_refptr<const Extension>
 BookmarkAppNavigationThrottle::GetAppForWindow() {
+  SCOPED_UMA_HISTOGRAM_TIMER("Extensions.BookmarkApp.GetAppForWindowDuration");
   content::WebContents* source = navigation_handle()->GetWebContents();
   content::BrowserContext* context = source->GetBrowserContext();
   Browser* browser = chrome::FindBrowserWithWebContents(source);
@@ -487,12 +502,15 @@
 }
 
 scoped_refptr<const Extension> BookmarkAppNavigationThrottle::GetTargetApp() {
+  SCOPED_UMA_HISTOGRAM_TIMER("Extensions.BookmarkApp.GetTargetAppDuration");
   return GetAppForURL(navigation_handle()->GetURL(),
                       navigation_handle()->GetWebContents());
 }
 
 scoped_refptr<const Extension>
 BookmarkAppNavigationThrottle::GetAppForCurrentURL() {
+  SCOPED_UMA_HISTOGRAM_TIMER(
+      "Extensions.BookmarkApp.GetAppForCurrentURLDuration");
   return GetAppForURL(navigation_handle()
                           ->GetWebContents()
                           ->GetMainFrame()
diff --git a/chrome/browser/loader/chrome_resource_dispatcher_host_delegate.cc b/chrome/browser/loader/chrome_resource_dispatcher_host_delegate.cc
index 783505f..82f7dbd2 100644
--- a/chrome/browser/loader/chrome_resource_dispatcher_host_delegate.cc
+++ b/chrome/browser/loader/chrome_resource_dispatcher_host_delegate.cc
@@ -55,6 +55,7 @@
 #include "components/nacl/common/features.h"
 #include "components/offline_pages/core/request_header/offline_page_navigation_ui_data.h"
 #include "components/offline_pages/features/features.h"
+#include "components/policy/content/policy_blacklist_navigation_throttle.h"
 #include "components/policy/core/common/cloud/policy_header_io_helper.h"
 #include "components/previews/content/previews_content_util.h"
 #include "components/previews/content/previews_io_data.h"
@@ -232,8 +233,7 @@
     const GURL& url,
     const content::ResourceRequestInfo::WebContentsGetter& web_contents_getter,
     ui::PageTransition page_transition,
-    bool has_user_gesture,
-    bool is_whitelisted) {
+    bool has_user_gesture) {
   // If there is no longer a WebContents, the request may have raced with tab
   // closing. Don't fire the external request. (It may have been a prerender.)
   content::WebContents* web_contents = web_contents_getter.Run();
@@ -249,6 +249,18 @@
     return;
   }
 
+  bool is_whitelisted = false;
+  Profile* profile =
+      Profile::FromBrowserContext(web_contents->GetBrowserContext());
+  PolicyBlacklistService* service =
+      PolicyBlacklistFactory::GetForProfile(profile);
+  if (service) {
+    const policy::URLBlacklist::URLBlacklistState url_state =
+        service->GetURLBlacklistState(url);
+    is_whitelisted =
+        url_state == policy::URLBlacklist::URLBlacklistState::URL_IN_WHITELIST;
+  }
+
   // If the URL is in whitelist, we launch it without asking the user and
   // without any additional security checks. Since the URL is whitelisted,
   // we assume it can be executed.
@@ -587,18 +599,6 @@
 bool ChromeResourceDispatcherHostDelegate::HandleExternalProtocol(
     const GURL& url,
     content::ResourceRequestInfo* info) {
-  // Get the state, if |url| is in blacklist, whitelist or in none of those.
-  ProfileIOData* io_data =
-      ProfileIOData::FromResourceContext(info->GetContext());
-  const policy::URLBlacklist::URLBlacklistState url_state =
-      io_data->GetURLBlacklistState(url);
-  if (url_state == policy::URLBlacklist::URLBlacklistState::URL_IN_BLACKLIST) {
-    // It's a link with custom scheme and it's blacklisted. We return false here
-    // and let it process as a normal URL. Eventually chrome_network_delegate
-    // will see it's in the blacklist and the user will be shown the blocked
-    // content page.
-    return false;
-  }
 
 #if BUILDFLAG(ENABLE_EXTENSIONS)
   // External protocols are disabled for guests. An exception is made for the
@@ -622,13 +622,10 @@
     return false;
 #endif  // defined(ANDROID)
 
-  const bool is_whitelisted =
-      url_state == policy::URLBlacklist::URLBlacklistState::URL_IN_WHITELIST;
   BrowserThread::PostTask(
       BrowserThread::UI, FROM_HERE,
       base::BindOnce(&LaunchURL, url, info->GetWebContentsGetterForRequest(),
-                     info->GetPageTransition(), info->HasUserGesture(),
-                     is_whitelisted));
+                     info->GetPageTransition(), info->HasUserGesture()));
   return true;
 }
 
diff --git a/chrome/browser/media/BUILD.gn b/chrome/browser/media/BUILD.gn
index 434a262..7cdced2 100644
--- a/chrome/browser/media/BUILD.gn
+++ b/chrome/browser/media/BUILD.gn
@@ -3,7 +3,6 @@
 # found in the LICENSE file.
 
 import("//mojo/public/tools/bindings/mojom.gni")
-import("//third_party/protobuf/proto_library.gni")
 
 mojom("mojo_bindings") {
   sources = [
@@ -15,9 +14,3 @@
     "//url/mojo:url_mojom_gurl",
   ]
 }
-
-proto_library("media_engagement_preload_proto") {
-  sources = [
-    "media_engagement_preload.proto",
-  ]
-}
diff --git a/chrome/browser/media/android/router/media_router_android_bridge.cc b/chrome/browser/media/android/router/media_router_android_bridge.cc
index 5138f28..4e86648 100644
--- a/chrome/browser/media/android/router/media_router_android_bridge.cc
+++ b/chrome/browser/media/android/router/media_router_android_bridge.cc
@@ -24,7 +24,14 @@
       Java_ChromeMediaRouter_create(env, reinterpret_cast<jlong>(this)));
 }
 
-MediaRouterAndroidBridge::~MediaRouterAndroidBridge() = default;
+MediaRouterAndroidBridge::~MediaRouterAndroidBridge() {
+  JNIEnv* env = base::android::AttachCurrentThread();
+  // When |this| is destroyed, there might still pending runnables on the Java
+  // side, that are keeping the Java object alive. These runnables might try to
+  // call back to the native side when executed. We need to signal to the Java
+  // counterpart that it can't call back into native anymore.
+  Java_ChromeMediaRouter_teardown(env, java_media_router_);
+}
 
 void MediaRouterAndroidBridge::CreateRoute(const MediaSource::Id& source_id,
                                            const MediaSink::Id& sink_id,
diff --git a/chrome/browser/media/cast_remoting_sender.cc b/chrome/browser/media/cast_remoting_sender.cc
index 04a43da..170a097 100644
--- a/chrome/browser/media/cast_remoting_sender.cc
+++ b/chrome/browser/media/cast_remoting_sender.cc
@@ -85,7 +85,7 @@
                 media::cast::RtpPayloadType::REMOTE_AUDIO),
       logging_flush_interval_(logging_flush_interval),
       frame_event_cb_(cb),
-      clock_(new base::DefaultTickClock()),
+      clock_(base::DefaultTickClock::GetInstance()),
       binding_(this),
       max_ack_delay_(kMaxAckDelay),
       last_sent_frame_id_(media::cast::FrameId::first() - 1),
diff --git a/chrome/browser/media/cast_remoting_sender.h b/chrome/browser/media/cast_remoting_sender.h
index adf642a..c6f49dd 100644
--- a/chrome/browser/media/cast_remoting_sender.h
+++ b/chrome/browser/media/cast_remoting_sender.h
@@ -145,7 +145,7 @@
   // The callback to send frame events to renderer process for logging.
   const FrameEventCallback frame_event_cb_;
 
-  std::unique_ptr<base::TickClock> clock_;
+  base::TickClock* clock_;
 
   // Callback that is run to notify when a fatal error occurs.
   base::Closure error_callback_;
diff --git a/chrome/browser/media/cast_transport_host_filter.cc b/chrome/browser/media/cast_transport_host_filter.cc
index 7a2d20de..f7a36b8 100644
--- a/chrome/browser/media/cast_transport_host_filter.cc
+++ b/chrome/browser/media/cast_transport_host_filter.cc
@@ -184,7 +184,7 @@
   udp_transport->SetUdpOptions(options);
   std::unique_ptr<media::cast::CastTransport> transport =
       media::cast::CastTransport::Create(
-          &clock_, kSendEventsInterval,
+          base::DefaultTickClock::GetInstance(), kSendEventsInterval,
           base::MakeUnique<TransportClient>(channel_id, this),
           std::move(udp_transport), base::ThreadTaskRunnerHandle::Get());
   transport->SetOptions(options);
diff --git a/chrome/browser/media/cast_transport_host_filter.h b/chrome/browser/media/cast_transport_host_filter.h
index 7dc5bc46c..e6681eb 100644
--- a/chrome/browser/media/cast_transport_host_filter.h
+++ b/chrome/browser/media/cast_transport_host_filter.h
@@ -101,9 +101,6 @@
 
   base::IDMap<std::unique_ptr<media::cast::CastTransport>> id_map_;
 
-  // Clock used by Cast transport.
-  base::DefaultTickClock clock_;
-
   // While |id_map_| is non-empty, we use |wake_lock_| to request and
   // hold a wake lock. This prevents Chrome from being suspended while remoting
   // content. If any wake lock is held upon destruction, it's implicitly
diff --git a/chrome/browser/media/media_engagement_browsertest.cc b/chrome/browser/media/media_engagement_browsertest.cc
index 1947372..6f7db07 100644
--- a/chrome/browser/media/media_engagement_browsertest.cc
+++ b/chrome/browser/media/media_engagement_browsertest.cc
@@ -71,8 +71,7 @@
 class MediaEngagementBrowserTest : public InProcessBrowserTest {
  public:
   MediaEngagementBrowserTest()
-      : test_clock_(new base::SimpleTestClock()),
-        task_runner_(new base::TestMockTimeTaskRunner()) {
+      : task_runner_(new base::TestMockTimeTaskRunner()) {
     http_server_.ServeFilesFromSourceDirectory(kMediaEngagementTestDataPath);
     http_server_origin2_.ServeFilesFromSourceDirectory(
         kMediaEngagementTestDataPath);
@@ -141,8 +140,7 @@
   void Advance(base::TimeDelta time) {
     DCHECK(injected_clock_);
     task_runner_->FastForwardBy(time);
-    static_cast<base::SimpleTestClock*>(GetService()->clock_.get())
-        ->Advance(time);
+    test_clock_.Advance(time);
     base::RunLoop().RunUntilIdle();
   }
 
@@ -236,7 +234,7 @@
  private:
   void InjectTimerTaskRunner() {
     if (!injected_clock_) {
-      GetService()->clock_ = std::move(test_clock_);
+      GetService()->clock_ = &test_clock_;
       injected_clock_ = true;
     }
 
@@ -250,7 +248,7 @@
 
   bool injected_clock_ = false;
 
-  std::unique_ptr<base::SimpleTestClock> test_clock_;
+  base::SimpleTestClock test_clock_;
 
   net::EmbeddedTestServer http_server_;
   net::EmbeddedTestServer http_server_origin2_;
diff --git a/chrome/browser/media/media_engagement_contents_observer.cc b/chrome/browser/media/media_engagement_contents_observer.cc
index 0f974b4..c9acba8d 100644
--- a/chrome/browser/media/media_engagement_contents_observer.cc
+++ b/chrome/browser/media/media_engagement_contents_observer.cc
@@ -175,8 +175,8 @@
   if (state != player_states_.end())
     return state->second;
 
-  auto iter = player_states_.insert(
-      std::make_pair(id, PlayerState(service_->clock_.get())));
+  auto iter =
+      player_states_.insert(std::make_pair(id, PlayerState(service_->clock_)));
   return iter.first->second;
 }
 
diff --git a/chrome/browser/media/media_engagement_contents_observer_unittest.cc b/chrome/browser/media/media_engagement_contents_observer_unittest.cc
index 86876b7e..6cb16b1 100644
--- a/chrome/browser/media/media_engagement_contents_observer_unittest.cc
+++ b/chrome/browser/media/media_engagement_contents_observer_unittest.cc
@@ -29,8 +29,7 @@
     : public ChromeRenderViewHostTestHarness {
  public:
   MediaEngagementContentsObserverTest()
-      : task_runner_(new base::TestMockTimeTaskRunner()),
-        test_clock_(new base::SimpleTestClock()) {}
+      : task_runner_(new base::TestMockTimeTaskRunner()) {}
 
   void SetUp() override {
     scoped_feature_list_.InitFromCommandLine("RecordMediaEngagementScores",
@@ -41,8 +40,8 @@
     SetContents(content::WebContentsTester::CreateTestWebContents(
         browser_context(), nullptr));
 
-    service_ = base::WrapUnique(
-        new MediaEngagementService(profile(), base::WrapUnique(test_clock_)));
+    service_ =
+        base::WrapUnique(new MediaEngagementService(profile(), &test_clock_));
     contents_observer_ = CreateContentsObserverFor(web_contents());
 
     // Navigate to an initial URL to setup the |session|.
@@ -120,7 +119,7 @@
   void SimulatePlaybackStoppedWithTime(int id,
                                        bool finished,
                                        base::TimeDelta elapsed) {
-    test_clock_->Advance(elapsed);
+    test_clock_.Advance(elapsed);
 
     content::WebContentsObserver::MediaPlayerInfo player_info(true, true);
     content::WebContentsObserver::MediaPlayerId player_id =
@@ -367,10 +366,10 @@
     EXPECT_EQ(expected_time, score.last_media_playback_time());
   }
 
-  base::Time Now() const { return test_clock_->Now(); }
+  base::Time Now() { return test_clock_.Now(); }
 
   void Advance15Minutes() {
-    test_clock_->Advance(base::TimeDelta::FromMinutes(15));
+    test_clock_.Advance(base::TimeDelta::FromMinutes(15));
   }
 
   ukm::TestAutoSetUkmRecorder& test_ukm_recorder() {
@@ -391,7 +390,7 @@
 
   scoped_refptr<base::TestMockTimeTaskRunner> task_runner_;
 
-  base::SimpleTestClock* test_clock_;
+  base::SimpleTestClock test_clock_;
 
   const base::TimeDelta kMaxWaitingTime =
       MediaEngagementContentsObserver::kSignificantMediaPlaybackTime +
diff --git a/chrome/browser/media/media_engagement_preload.proto b/chrome/browser/media/media_engagement_preload.proto
deleted file mode 100644
index 924ee63..0000000
--- a/chrome/browser/media/media_engagement_preload.proto
+++ /dev/null
@@ -1,12 +0,0 @@
-syntax = "proto2";
-
-package chrome_browser_media;
-
-// Chrome requires this.
-option optimize_for = LITE_RUNTIME;
-
-// Next available id: 2
-message PreloadedData {
-  // The data in DAFSA format.
-  optional bytes dafsa = 1;
-}
diff --git a/chrome/browser/media/media_engagement_preloaded_list.cc b/chrome/browser/media/media_engagement_preloaded_list.cc
deleted file mode 100644
index 05a62d8..0000000
--- a/chrome/browser/media/media_engagement_preloaded_list.cc
+++ /dev/null
@@ -1,51 +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 "chrome/browser/media/media_engagement_preloaded_list.h"
-
-#include "base/files/file_util.h"
-#include "base/path_service.h"
-#include "chrome/browser/media/media_engagement_preload.pb.h"
-#include "net/base/lookup_string_in_fixed_set.h"
-#include "url/origin.h"
-
-MediaEngagementPreloadedList::MediaEngagementPreloadedList() = default;
-
-MediaEngagementPreloadedList::~MediaEngagementPreloadedList() = default;
-
-bool MediaEngagementPreloadedList::LoadFromFile(const base::FilePath& path) {
-  // Check the file exists.
-  if (!base::PathExists(path))
-    return false;
-
-  // Read the file to a string.
-  std::string file_data;
-  if (!base::ReadFileToString(path, &file_data))
-    return false;
-
-  // Load the preloaded list into a proto message.
-  chrome_browser_media::PreloadedData message;
-  if (!message.ParseFromString(file_data))
-    return false;
-
-  // Copy data from the protobuf message.
-  dafsa_ = std::vector<unsigned char>(
-      message.dafsa().c_str(),
-      message.dafsa().c_str() + message.dafsa().length());
-
-  is_loaded_ = true;
-  return true;
-}
-
-bool MediaEngagementPreloadedList::CheckOriginIsPresent(
-    const url::Origin& origin) const {
-  return CheckStringIsPresent(origin.Serialize());
-}
-
-bool MediaEngagementPreloadedList::CheckStringIsPresent(
-    const std::string& input) const {
-  return net::LookupStringInFixedSet(dafsa_.data(), dafsa_.size(),
-                                     input.c_str(),
-                                     input.size()) == net::kDafsaFound;
-}
diff --git a/chrome/browser/media/media_engagement_preloaded_list.h b/chrome/browser/media/media_engagement_preloaded_list.h
deleted file mode 100644
index 939253e2..0000000
--- a/chrome/browser/media/media_engagement_preloaded_list.h
+++ /dev/null
@@ -1,55 +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 CHROME_BROWSER_MEDIA_MEDIA_ENGAGEMENT_PRELOADED_LIST_H_
-#define CHROME_BROWSER_MEDIA_MEDIA_ENGAGEMENT_PRELOADED_LIST_H_
-
-#include <string>
-#include <vector>
-
-#include "base/macros.h"
-
-namespace base {
-class FilePath;
-}  // namespace base
-
-namespace url {
-class Origin;
-}  // namespace url
-
-class MediaEngagementPreloadedList {
- public:
-  MediaEngagementPreloadedList();
-  ~MediaEngagementPreloadedList();
-
-  // Load the contents from |path|.
-  bool LoadFromFile(const base::FilePath& path);
-
-  // Checks whether |origin| has a high global engagement and is present in the
-  // preloaded list.
-  bool CheckOriginIsPresent(const url::Origin& origin) const;
-
-  // Check whether we have loaded a list.
-  bool loaded() const { return is_loaded_; }
-
-  // Check whether the list we have loaded is empty.
-  bool empty() const { return dafsa_.empty(); }
-
- protected:
-  friend class MediaEngagementPreloadedListTest;
-
-  // Checks if |input| is present in the preloaded data.
-  bool CheckStringIsPresent(const std::string& input) const;
-
- private:
-  // The preloaded data in dafsa format.
-  std::vector<unsigned char> dafsa_;
-
-  // If a list has been successfully loaded.
-  bool is_loaded_ = false;
-
-  DISALLOW_COPY_AND_ASSIGN(MediaEngagementPreloadedList);
-};
-
-#endif  // CHROME_BROWSER_MEDIA_MEDIA_ENGAGEMENT_PRELOADED_LIST_H_
diff --git a/chrome/browser/media/media_engagement_preloaded_list_unittest.cc b/chrome/browser/media/media_engagement_preloaded_list_unittest.cc
deleted file mode 100644
index 1a6d78285b..0000000
--- a/chrome/browser/media/media_engagement_preloaded_list_unittest.cc
+++ /dev/null
@@ -1,117 +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 "chrome/browser/media/media_engagement_preloaded_list.h"
-
-#include <utility>
-
-#include "base/files/file_path.h"
-#include "base/macros.h"
-#include "base/path_service.h"
-#include "build/build_config.h"
-#include "chrome/browser/profiles/profile.h"
-#include "chrome/test/base/testing_profile.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "url/gurl.h"
-#include "url/origin.h"
-
-namespace {
-
-const base::FilePath kTestDataPath = base::FilePath(
-    FILE_PATH_LITERAL("gen/chrome/test/data/media/engagement/preload"));
-
-// This sample data is auto generated at build time.
-const base::FilePath kSampleDataPath = kTestDataPath.AppendASCII("test.pb");
-
-const base::FilePath kMissingFilePath = kTestDataPath.AppendASCII("missing.pb");
-
-const base::FilePath kBadFormatFilePath =
-    kTestDataPath.AppendASCII("bad_format.pb");
-
-const base::FilePath kEmptyFilePath = kTestDataPath.AppendASCII("empty.pb");
-
-base::FilePath GetModulePath() {
-  base::FilePath module_dir;
-#if defined(OS_ANDROID)
-  EXPECT_TRUE(PathService::Get(base::DIR_SOURCE_ROOT, &module_dir));
-#else
-  EXPECT_TRUE(PathService::Get(base::DIR_MODULE, &module_dir));
-#endif
-  return module_dir;
-}
-
-}  // namespace
-
-class MediaEngagementPreloadedListTest : public ::testing::Test {
- public:
-  void SetUp() override {
-    preloaded_list_ = std::make_unique<MediaEngagementPreloadedList>();
-    ASSERT_FALSE(IsLoaded());
-    ASSERT_TRUE(IsEmpty());
-  }
-
-  bool LoadFromFile(base::FilePath path) {
-    return preloaded_list_->LoadFromFile(path);
-  }
-
-  bool CheckOriginIsPresent(GURL url) {
-    return preloaded_list_->CheckOriginIsPresent(url::Origin::Create(url));
-  }
-
-  bool CheckStringIsPresent(const std::string& input) {
-    return preloaded_list_->CheckStringIsPresent(input);
-  }
-
-  base::FilePath GetFilePathRelativeToModule(base::FilePath path) {
-    return GetModulePath().Append(path);
-  }
-
-  bool IsLoaded() { return preloaded_list_->loaded(); }
-
-  bool IsEmpty() { return preloaded_list_->empty(); }
-
- protected:
-  std::unique_ptr<MediaEngagementPreloadedList> preloaded_list_;
-};
-
-TEST_F(MediaEngagementPreloadedListTest, CheckOriginIsPresent) {
-  ASSERT_TRUE(LoadFromFile(GetFilePathRelativeToModule(kSampleDataPath)));
-  EXPECT_TRUE(IsLoaded());
-  EXPECT_FALSE(IsEmpty());
-
-  EXPECT_TRUE(CheckOriginIsPresent(GURL("https://example.com")));
-  EXPECT_TRUE(CheckOriginIsPresent(GURL("https://example.org:1234")));
-  EXPECT_TRUE(CheckOriginIsPresent(GURL("https://test--3ya.com")));
-  EXPECT_TRUE(CheckOriginIsPresent(GURL("http://123.123.123.123")));
-
-  EXPECT_FALSE(CheckOriginIsPresent(GURL("https://example.org")));
-  EXPECT_FALSE(CheckOriginIsPresent(GURL("http://example.com")));
-  EXPECT_FALSE(CheckOriginIsPresent(GURL("http://123.123.123.124")));
-
-  // Make sure only the full origin matches.
-  EXPECT_FALSE(CheckStringIsPresent("123"));
-  EXPECT_FALSE(CheckStringIsPresent("http"));
-  EXPECT_FALSE(CheckStringIsPresent("example.com"));
-}
-
-TEST_F(MediaEngagementPreloadedListTest, LoadMissingFile) {
-  ASSERT_FALSE(LoadFromFile(GetFilePathRelativeToModule(kMissingFilePath)));
-  EXPECT_FALSE(IsLoaded());
-  EXPECT_TRUE(IsEmpty());
-  EXPECT_FALSE(CheckOriginIsPresent(GURL("https://example.com")));
-}
-
-TEST_F(MediaEngagementPreloadedListTest, LoadBadFormatFile) {
-  ASSERT_FALSE(LoadFromFile(GetFilePathRelativeToModule(kBadFormatFilePath)));
-  EXPECT_FALSE(IsLoaded());
-  EXPECT_TRUE(IsEmpty());
-  EXPECT_FALSE(CheckOriginIsPresent(GURL("https://example.com")));
-}
-
-TEST_F(MediaEngagementPreloadedListTest, LoadEmptyFile) {
-  ASSERT_TRUE(LoadFromFile(GetFilePathRelativeToModule(kEmptyFilePath)));
-  EXPECT_TRUE(IsLoaded());
-  EXPECT_TRUE(IsEmpty());
-  EXPECT_FALSE(CheckOriginIsPresent(GURL("https://example.com")));
-}
diff --git a/chrome/browser/media/media_engagement_service.cc b/chrome/browser/media/media_engagement_service.cc
index cee4af53..03ac529 100644
--- a/chrome/browser/media/media_engagement_service.cc
+++ b/chrome/browser/media/media_engagement_service.cc
@@ -113,12 +113,11 @@
 }
 
 MediaEngagementService::MediaEngagementService(Profile* profile)
-    : MediaEngagementService(profile, base::MakeUnique<base::DefaultClock>()) {}
+    : MediaEngagementService(profile, base::DefaultClock::GetInstance()) {}
 
-MediaEngagementService::MediaEngagementService(
-    Profile* profile,
-    std::unique_ptr<base::Clock> clock)
-    : profile_(profile), clock_(std::move(clock)) {
+MediaEngagementService::MediaEngagementService(Profile* profile,
+                                               base::Clock* clock)
+    : profile_(profile), clock_(clock) {
   DCHECK(IsEnabled());
 
   // May be null in tests.
@@ -283,8 +282,7 @@
   // the original profile migrated in, so all engagement scores in incognito
   // will be initialised to the values from the original profile.
   return MediaEngagementScore(
-      clock_.get(), url,
-      HostContentSettingsMapFactory::GetForProfile(profile_));
+      clock_, url, HostContentSettingsMapFactory::GetForProfile(profile_));
 }
 
 MediaEngagementContentsObserver* MediaEngagementService::GetContentsObserverFor(
diff --git a/chrome/browser/media/media_engagement_service.h b/chrome/browser/media/media_engagement_service.h
index 33d01ec..152c41b 100644
--- a/chrome/browser/media/media_engagement_service.h
+++ b/chrome/browser/media/media_engagement_service.h
@@ -108,7 +108,7 @@
   friend class MediaEngagementSessionTest;
   friend class MediaEngagementContentsObserver;
 
-  MediaEngagementService(Profile* profile, std::unique_ptr<base::Clock> clock);
+  MediaEngagementService(Profile* profile, base::Clock* clock);
 
   // Returns true if we should record engagement for this url. Currently,
   // engagement is only earned for HTTP and HTTPS.
@@ -123,7 +123,7 @@
   void Clear(const GURL& url);
 
   // An internal clock for testing.
-  std::unique_ptr<base::Clock> clock_;
+  base::Clock* clock_;
 
   // Records all the stored scores to a histogram.
   void RecordStoredScoresToHistogram();
diff --git a/chrome/browser/media/media_engagement_service_unittest.cc b/chrome/browser/media/media_engagement_service_unittest.cc
index e5e4782..eba30cb 100644
--- a/chrome/browser/media/media_engagement_service_unittest.cc
+++ b/chrome/browser/media/media_engagement_service_unittest.cc
@@ -110,10 +110,9 @@
     HistoryServiceFactory::GetInstance()->SetTestingFactory(
         profile(), &BuildTestHistoryService);
 
-    test_clock_ = new base::SimpleTestClock();
-    test_clock_->SetNow(GetReferenceTime());
-    service_ = base::WrapUnique(
-        new MediaEngagementService(profile(), base::WrapUnique(test_clock_)));
+    test_clock_.SetNow(GetReferenceTime());
+    service_ =
+        base::WrapUnique(new MediaEngagementService(profile(), &test_clock_));
   }
 
   MediaEngagementService* StartNewMediaEngagementService() {
@@ -133,7 +132,7 @@
   }
 
   void AdvanceClock() {
-    test_clock_->SetNow(Now() + base::TimeDelta::FromHours(1));
+    test_clock_.SetNow(Now() + base::TimeDelta::FromHours(1));
   }
 
   void RecordVisit(GURL url) { service_->RecordVisit(url); }
@@ -191,11 +190,11 @@
     service_->ClearDataBetweenTime(begin, end);
   }
 
-  base::Time Now() const { return test_clock_->Now(); }
+  base::Time Now() { return test_clock_.Now(); }
 
   base::Time TimeNotSet() const { return base::Time(); }
 
-  void SetNow(base::Time now) { test_clock_->SetNow(now); }
+  void SetNow(base::Time now) { test_clock_.SetNow(now); }
 
   std::vector<media::mojom::MediaEngagementScoreDetailsPtr> GetAllScoreDetails()
       const {
@@ -209,7 +208,7 @@
   void SetSchemaVersion(int version) { service_->SetSchemaVersion(version); }
 
  private:
-  base::SimpleTestClock* test_clock_ = nullptr;
+  base::SimpleTestClock test_clock_;
 
   std::unique_ptr<MediaEngagementService> service_;
 
diff --git a/chrome/browser/media/media_engagement_session_unittest.cc b/chrome/browser/media/media_engagement_session_unittest.cc
index 0dda1b0..253456aa 100644
--- a/chrome/browser/media/media_engagement_session_unittest.cc
+++ b/chrome/browser/media/media_engagement_session_unittest.cc
@@ -94,14 +94,13 @@
   }
 
   MediaEngagementSessionTest()
-      : origin_(url::Origin::Create(GURL("https://example.com"))),
-        test_clock_(new base::SimpleTestClock()) {}
+      : origin_(url::Origin::Create(GURL("https://example.com"))) {}
 
   ~MediaEngagementSessionTest() override = default;
 
   void SetUp() override {
-    service_ = base::WrapUnique(
-        new MediaEngagementService(&profile_, base::WrapUnique(test_clock_)));
+    service_ =
+        base::WrapUnique(new MediaEngagementService(&profile_, &test_clock_));
   }
 
   MediaEngagementService* service() const { return service_.get(); }
@@ -112,12 +111,11 @@
     return test_ukm_recorder_;
   }
 
-  base::SimpleTestClock* test_clock() { return test_clock_; }
+  base::SimpleTestClock* test_clock() { return &test_clock_; }
 
  private:
   const url::Origin origin_;
-  // Owned by |service_| but keeping a reference to it to manipulate.
-  base::SimpleTestClock* test_clock_;
+  base::SimpleTestClock test_clock_;
 
   content::TestBrowserThreadBundle thread_bundle_;
   TestingProfile profile_;
diff --git a/chrome/browser/media/router/discovery/dial/dial_media_sink_service_impl.cc b/chrome/browser/media/router/discovery/dial/dial_media_sink_service_impl.cc
index 508645a..a2883146 100644
--- a/chrome/browser/media/router/discovery/dial/dial_media_sink_service_impl.cc
+++ b/chrome/browser/media/router/discovery/dial/dial_media_sink_service_impl.cc
@@ -115,7 +115,7 @@
   // ID when it is sent to the extension, because it derives a different sink ID
   // using the given sink ID.
   MediaSink sink(description_data.unique_id, description_data.friendly_name,
-                 SinkIconType::GENERIC);
+                 SinkIconType::GENERIC, MediaRouteProviderId::EXTENSION);
   DialSinkExtraData extra_data;
   extra_data.app_url = description_data.app_url;
   extra_data.model_name = description_data.model_name;
diff --git a/chrome/browser/media/router/discovery/dial/dial_registry.cc b/chrome/browser/media/router/discovery/dial/dial_registry.cc
index 3c980b7..87d0650 100644
--- a/chrome/browser/media/router/discovery/dial/dial_registry.cc
+++ b/chrome/browser/media/router/discovery/dial/dial_registry.cc
@@ -46,7 +46,7 @@
       refresh_interval_delta_(TimeDelta::FromSeconds(kDialRefreshIntervalSecs)),
       expiration_delta_(TimeDelta::FromSeconds(kDialExpirationSecs)),
       max_devices_(kDialMaxDevices),
-      clock_(new base::DefaultClock()) {
+      clock_(base::DefaultClock::GetInstance()) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
   DCHECK_GT(max_devices_, 0U);
   // This is a leaky singleton, so there's no code to remove |this| as an
@@ -126,8 +126,8 @@
       std::make_pair(device_data.device_id(), std::move(test_data)));
 }
 
-void DialRegistry::SetClockForTest(std::unique_ptr<base::Clock> clock) {
-  clock_ = std::move(clock);
+void DialRegistry::SetClockForTest(base::Clock* clock) {
+  clock_ = clock;
 }
 
 bool DialRegistry::ReadyToDiscover() {
diff --git a/chrome/browser/media/router/discovery/dial/dial_registry.h b/chrome/browser/media/router/discovery/dial/dial_registry.h
index f033959..d061d1b 100644
--- a/chrome/browser/media/router/discovery/dial/dial_registry.h
+++ b/chrome/browser/media/router/discovery/dial/dial_registry.h
@@ -97,7 +97,7 @@
   void AddDeviceForTest(const DialDeviceData& device_data);
 
   // Allows tests to swap in a fake clock.
-  void SetClockForTest(std::unique_ptr<base::Clock> clock);
+  void SetClockForTest(base::Clock* clock);
 
  protected:
   // Returns a new instance of the DIAL service.  Overridden by tests.
@@ -203,7 +203,7 @@
   // Set just after construction, only used on the IO thread.
   net::NetLog* net_log_ = nullptr;
 
-  std::unique_ptr<base::Clock> clock_;
+  base::Clock* clock_;
 
   FRIEND_TEST_ALL_PREFIXES(DialRegistryTest, TestAddRemoveListeners);
   FRIEND_TEST_ALL_PREFIXES(DialRegistryTest, TestNoDevicesDiscovered);
diff --git a/chrome/browser/media/router/discovery/dial/dial_registry_unittest.cc b/chrome/browser/media/router/discovery/dial/dial_registry_unittest.cc
index 63c9102..f60d441f 100644
--- a/chrome/browser/media/router/discovery/dial/dial_registry_unittest.cc
+++ b/chrome/browser/media/router/discovery/dial/dial_registry_unittest.cc
@@ -45,10 +45,7 @@
 
 class MockDialRegistry : public DialRegistry {
  public:
-  MockDialRegistry() : DialRegistry(), clock_(new base::SimpleTestClock()) {
-    // Takes ownership of |clock|.
-    SetClockForTest(base::WrapUnique(clock_));
-  }
+  MockDialRegistry() : DialRegistry() { SetClockForTest(&clock_); }
 
   ~MockDialRegistry() override {
     // Don't let the DialRegistry delete this.
@@ -59,7 +56,7 @@
 
   // Returns the mock Dial service.
   MockDialService& mock_service() { return mock_service_; }
-  base::SimpleTestClock* clock() const { return clock_; }
+  base::SimpleTestClock* clock() { return &clock_; }
 
  protected:
   std::unique_ptr<DialService> CreateDialService() override {
@@ -74,8 +71,7 @@
  private:
   MockDialService mock_service_;
 
-  // Owned by DialRegistry.
-  base::SimpleTestClock* const clock_;
+  base::SimpleTestClock clock_;
 };
 
 class DialRegistryTest : public testing::Test {
diff --git a/chrome/browser/media/router/discovery/discovery_network_monitor.cc b/chrome/browser/media/router/discovery/discovery_network_monitor.cc
index 4e99854..4f1a69a 100644
--- a/chrome/browser/media/router/discovery/discovery_network_monitor.cc
+++ b/chrome/browser/media/router/discovery/discovery_network_monitor.cc
@@ -96,7 +96,7 @@
       task_runner_(base::CreateSequencedTaskRunnerWithTraits(base::MayBlock())),
       network_info_function_(strategy),
       metric_observer_(base::MakeUnique<DiscoveryNetworkMonitorMetricObserver>(
-          base::MakeUnique<base::DefaultTickClock>(),
+          base::DefaultTickClock::GetInstance(),
           base::MakeUnique<DiscoveryNetworkMonitorMetrics>())) {
   DETACH_FROM_SEQUENCE(sequence_checker_);
   AddObserver(metric_observer_.get());
diff --git a/chrome/browser/media/router/discovery/discovery_network_monitor_metric_observer.cc b/chrome/browser/media/router/discovery/discovery_network_monitor_metric_observer.cc
index 96ae2af..033a243 100644
--- a/chrome/browser/media/router/discovery/discovery_network_monitor_metric_observer.cc
+++ b/chrome/browser/media/router/discovery/discovery_network_monitor_metric_observer.cc
@@ -52,11 +52,11 @@
 }  // namespace
 
 DiscoveryNetworkMonitorMetricObserver::DiscoveryNetworkMonitorMetricObserver(
-    std::unique_ptr<base::TickClock> tick_clock,
+    base::TickClock* tick_clock,
     std::unique_ptr<DiscoveryNetworkMonitorMetrics> metrics)
-    : tick_clock_(std::move(tick_clock)),
+    : tick_clock_(tick_clock),
       metrics_(std::move(metrics)),
-      disconnect_timer_(tick_clock_.get()) {
+      disconnect_timer_(tick_clock_) {
   DCHECK(tick_clock_);
   DCHECK(metrics_);
 }
diff --git a/chrome/browser/media/router/discovery/discovery_network_monitor_metric_observer.h b/chrome/browser/media/router/discovery/discovery_network_monitor_metric_observer.h
index 351def2..0263b98 100644
--- a/chrome/browser/media/router/discovery/discovery_network_monitor_metric_observer.h
+++ b/chrome/browser/media/router/discovery/discovery_network_monitor_metric_observer.h
@@ -19,7 +19,7 @@
     : public DiscoveryNetworkMonitor::Observer {
  public:
   DiscoveryNetworkMonitorMetricObserver(
-      std::unique_ptr<base::TickClock> tick_clock,
+      base::TickClock* tick_clock,
       std::unique_ptr<DiscoveryNetworkMonitorMetrics> metrics);
   ~DiscoveryNetworkMonitorMetricObserver();
 
@@ -36,7 +36,7 @@
   // value instead of the time that this later check runs.
   void ConfirmDisconnectedToReportMetrics(base::TimeTicks disconnect_time);
 
-  std::unique_ptr<base::TickClock> tick_clock_;
+  base::TickClock* tick_clock_;
   std::unique_ptr<DiscoveryNetworkMonitorMetrics> metrics_;
   base::Optional<base::TimeTicks> last_event_time_;
   base::OneShotTimer disconnect_timer_;
diff --git a/chrome/browser/media/router/discovery/discovery_network_monitor_metric_observer_unittest.cc b/chrome/browser/media/router/discovery/discovery_network_monitor_metric_observer_unittest.cc
index 4801177..e6f133f0 100644
--- a/chrome/browser/media/router/discovery/discovery_network_monitor_metric_observer_unittest.cc
+++ b/chrome/browser/media/router/discovery/discovery_network_monitor_metric_observer_unittest.cc
@@ -82,8 +82,8 @@
         start_ticks_(mock_clock_->NowTicks()),
         metrics_(base::MakeUnique<MockMetrics>()),
         mock_metrics_(metrics_.get()),
-        metric_observer_(task_runner_->GetMockTickClock(),
-                         std::move(metrics_)) {}
+        clock_(task_runner_->GetMockTickClock()),
+        metric_observer_(clock_.get(), std::move(metrics_)) {}
 
  protected:
   base::TimeDelta time_advance_ = base::TimeDelta::FromMilliseconds(10);
@@ -94,6 +94,11 @@
   const base::TimeTicks start_ticks_;
   std::unique_ptr<MockMetrics> metrics_;
   MockMetrics* mock_metrics_;
+
+  // TODO(tzik): Remove |clock_| after updating GetMockTickClock to own the
+  // instance.
+  std::unique_ptr<base::TickClock> clock_;
+
   DiscoveryNetworkMonitorMetricObserver metric_observer_;
 };
 
diff --git a/chrome/browser/media/router/discovery/mdns/cast_media_sink_service.cc b/chrome/browser/media/router/discovery/mdns/cast_media_sink_service.cc
index cf4d624..46ef622 100644
--- a/chrome/browser/media/router/discovery/mdns/cast_media_sink_service.cc
+++ b/chrome/browser/media/router/discovery/mdns/cast_media_sink_service.cc
@@ -64,7 +64,8 @@
   std::string friendly_name = service_data["fn"];
   if (friendly_name.empty())
     return ErrorType::MISSING_FRIENDLY_NAME;
-  MediaSink sink(unique_id, friendly_name, SinkIconType::CAST);
+  MediaSink sink(unique_id, friendly_name, SinkIconType::CAST,
+                 MediaRouteProviderId::EXTENSION);
 
   CastSinkExtraData extra_data;
   extra_data.ip_endpoint =
diff --git a/chrome/browser/media/router/discovery/mdns/cast_media_sink_service_impl.cc b/chrome/browser/media/router/discovery/mdns/cast_media_sink_service_impl.cc
index b2deb6a..3f69a5cb 100644
--- a/chrome/browser/media/router/discovery/mdns/cast_media_sink_service_impl.cc
+++ b/chrome/browser/media/router/discovery/mdns/cast_media_sink_service_impl.cc
@@ -30,7 +30,8 @@
   const std::string& unique_id = dial_sink.sink().id();
   const std::string& friendly_name = dial_sink.sink().name();
   media_router::MediaSink sink(unique_id, friendly_name,
-                               media_router::SinkIconType::CAST);
+                               media_router::SinkIconType::CAST,
+                               media_router::MediaRouteProviderId::EXTENSION);
 
   media_router::CastSinkExtraData extra_data;
   extra_data.ip_endpoint =
@@ -177,7 +178,7 @@
       network_monitor_(network_monitor),
       task_runner_(cast_socket_service_->task_runner()),
       url_request_context_getter_(url_request_context_getter),
-      clock_(new base::DefaultClock()),
+      clock_(base::DefaultClock::GetInstance()),
       weak_ptr_factory_(this) {
   DETACH_FROM_SEQUENCE(sequence_checker_);
   DCHECK(cast_socket_service_);
@@ -226,9 +227,8 @@
   cast_socket_service_->RemoveObserver(this);
 }
 
-void CastMediaSinkServiceImpl::SetClockForTest(
-    std::unique_ptr<base::Clock> clock) {
-  clock_ = std::move(clock);
+void CastMediaSinkServiceImpl::SetClockForTest(base::Clock* clock) {
+  clock_ = clock;
 }
 
 void CastMediaSinkServiceImpl::Start() {
diff --git a/chrome/browser/media/router/discovery/mdns/cast_media_sink_service_impl.h b/chrome/browser/media/router/discovery/mdns/cast_media_sink_service_impl.h
index bece811..ef4bd73 100644
--- a/chrome/browser/media/router/discovery/mdns/cast_media_sink_service_impl.h
+++ b/chrome/browser/media/router/discovery/mdns/cast_media_sink_service_impl.h
@@ -65,7 +65,7 @@
     return task_runner_;
   }
 
-  void SetClockForTest(std::unique_ptr<base::Clock> clock);
+  void SetClockForTest(base::Clock* clock);
 
   // Marked virtual for tests.
   virtual void Start();
@@ -333,7 +333,7 @@
   // NetworkService.
   scoped_refptr<net::URLRequestContextGetter> url_request_context_getter_;
 
-  std::unique_ptr<base::Clock> clock_;
+  base::Clock* clock_;
 
   SEQUENCE_CHECKER(sequence_checker_);
   base::WeakPtrFactory<CastMediaSinkServiceImpl> weak_ptr_factory_;
diff --git a/chrome/browser/media/router/discovery/mdns/cast_media_sink_service_impl_unittest.cc b/chrome/browser/media/router/discovery/mdns/cast_media_sink_service_impl_unittest.cc
index 3cedfc18a..4913406d 100644
--- a/chrome/browser/media/router/discovery/mdns/cast_media_sink_service_impl_unittest.cc
+++ b/chrome/browser/media/router/discovery/mdns/cast_media_sink_service_impl_unittest.cc
@@ -358,10 +358,10 @@
   net::IPEndPoint ip_endpoint2 = CreateIPEndPoint(2);
   net::IPEndPoint ip_endpoint3 = CreateIPEndPoint(3);
 
-  base::SimpleTestClock* clock = new base::SimpleTestClock();
+  base::SimpleTestClock clock;
   base::Time start_time = base::Time::Now();
-  clock->SetNow(start_time);
-  media_sink_service_impl_.SetClockForTest(base::WrapUnique(clock));
+  clock.SetNow(start_time);
+  media_sink_service_impl_.SetClockForTest(&clock);
 
   EXPECT_CALL(*mock_cast_socket_service_,
               OpenSocketInternal(ip_endpoint1, _, _));
@@ -379,7 +379,7 @@
   socket2.SetErrorState(cast_channel::ChannelError::NONE);
 
   base::TimeDelta delta = base::TimeDelta::FromSeconds(2);
-  clock->Advance(delta);
+  clock.Advance(delta);
   base::HistogramTester tester;
 
   media_sink_service_impl_.OnChannelOpened(
diff --git a/chrome/browser/media/router/discovery/media_sink_discovery_metrics.cc b/chrome/browser/media/router/discovery/media_sink_discovery_metrics.cc
index fdf8e36..6818a91 100644
--- a/chrome/browser/media/router/discovery/media_sink_discovery_metrics.cc
+++ b/chrome/browser/media/router/discovery/media_sink_discovery_metrics.cc
@@ -15,7 +15,8 @@
 
 namespace media_router {
 
-DeviceCountMetrics::DeviceCountMetrics() : clock_(new base::DefaultClock()) {}
+DeviceCountMetrics::DeviceCountMetrics()
+    : clock_(base::DefaultClock::GetInstance()) {}
 DeviceCountMetrics::~DeviceCountMetrics() = default;
 
 void DeviceCountMetrics::RecordDeviceCountsIfNeeded(
@@ -30,7 +31,7 @@
   device_count_metrics_record_time_ = now;
 }
 
-void DeviceCountMetrics::SetClockForTest(std::unique_ptr<base::Clock> clock) {
+void DeviceCountMetrics::SetClockForTest(base::Clock* clock) {
   clock_ = std::move(clock);
 }
 
diff --git a/chrome/browser/media/router/discovery/media_sink_discovery_metrics.h b/chrome/browser/media/router/discovery/media_sink_discovery_metrics.h
index 05ed917..c22d252 100644
--- a/chrome/browser/media/router/discovery/media_sink_discovery_metrics.h
+++ b/chrome/browser/media/router/discovery/media_sink_discovery_metrics.h
@@ -47,7 +47,7 @@
                                   size_t known_device_count);
 
   // Allows tests to swap in a fake clock.
-  void SetClockForTest(std::unique_ptr<base::Clock> clock);
+  void SetClockForTest(base::Clock* clock);
 
  protected:
   // Record device counts.
@@ -57,7 +57,7 @@
  private:
   base::Time device_count_metrics_record_time_;
 
-  std::unique_ptr<base::Clock> clock_;
+  base::Clock* clock_;
 };
 
 // Metrics for DIAL device counts.
diff --git a/chrome/browser/media/router/discovery/media_sink_discovery_metrics_unittest.cc b/chrome/browser/media/router/discovery/media_sink_discovery_metrics_unittest.cc
index 83b4d34..d4c7e7ed 100644
--- a/chrome/browser/media/router/discovery/media_sink_discovery_metrics_unittest.cc
+++ b/chrome/browser/media/router/discovery/media_sink_discovery_metrics_unittest.cc
@@ -19,8 +19,8 @@
 
 TEST(DialDeviceCountMetricsTest, RecordDeviceCountsIfNeeded) {
   DialDeviceCountMetrics metrics;
-  base::SimpleTestClock* clock = new base::SimpleTestClock();
-  metrics.SetClockForTest(base::WrapUnique(clock));
+  base::SimpleTestClock clock;
+  metrics.SetClockForTest(&clock);
   base::HistogramTester tester;
   tester.ExpectTotalCount(
       DialDeviceCountMetrics::kHistogramDialAvailableDeviceCount, 0);
@@ -28,7 +28,7 @@
       DialDeviceCountMetrics::kHistogramDialKnownDeviceCount, 0);
 
   // Only record one count within one hour.
-  clock->SetNow(base::Time::Now());
+  clock.SetNow(base::Time::Now());
   metrics.RecordDeviceCountsIfNeeded(6, 10);
   metrics.RecordDeviceCountsIfNeeded(7, 10);
   tester.ExpectTotalCount(
@@ -41,7 +41,7 @@
       DialDeviceCountMetrics::kHistogramDialKnownDeviceCount, 10, 1);
 
   // Record another count.
-  clock->Advance(base::TimeDelta::FromHours(2));
+  clock.Advance(base::TimeDelta::FromHours(2));
   metrics.RecordDeviceCountsIfNeeded(7, 10);
   tester.ExpectTotalCount(
       DialDeviceCountMetrics::kHistogramDialAvailableDeviceCount, 2);
@@ -57,8 +57,8 @@
 
 TEST(CastDeviceCountMetricsTest, RecordDeviceCountsIfNeeded) {
   CastDeviceCountMetrics metrics;
-  base::SimpleTestClock* clock = new base::SimpleTestClock();
-  metrics.SetClockForTest(base::WrapUnique(clock));
+  base::SimpleTestClock clock;
+  metrics.SetClockForTest(&clock);
   base::HistogramTester tester;
   tester.ExpectTotalCount(
       CastDeviceCountMetrics::kHistogramCastConnectedDeviceCount, 0);
@@ -66,7 +66,7 @@
       CastDeviceCountMetrics::kHistogramCastKnownDeviceCount, 0);
 
   // Only record one count within one hour.
-  clock->SetNow(base::Time::Now());
+  clock.SetNow(base::Time::Now());
   metrics.RecordDeviceCountsIfNeeded(6, 10);
   metrics.RecordDeviceCountsIfNeeded(7, 10);
   tester.ExpectTotalCount(
@@ -79,7 +79,7 @@
       CastDeviceCountMetrics::kHistogramCastKnownDeviceCount, 10, 1);
 
   // Record another count.
-  clock->Advance(base::TimeDelta::FromHours(2));
+  clock.Advance(base::TimeDelta::FromHours(2));
   metrics.RecordDeviceCountsIfNeeded(7, 10);
   tester.ExpectTotalCount(
       CastDeviceCountMetrics::kHistogramCastConnectedDeviceCount, 2);
diff --git a/chrome/browser/metrics/chrome_metrics_services_manager_client.cc b/chrome/browser/metrics/chrome_metrics_services_manager_client.cc
index 9b01aaa3..fdf915f 100644
--- a/chrome/browser/metrics/chrome_metrics_services_manager_client.cc
+++ b/chrome/browser/metrics/chrome_metrics_services_manager_client.cc
@@ -121,11 +121,11 @@
   ChromeEnabledStateProvider() {}
   ~ChromeEnabledStateProvider() override {}
 
-  bool IsConsentGiven() override {
+  bool IsConsentGiven() const override {
     return ChromeMetricsServiceAccessor::IsMetricsAndCrashReportingEnabled();
   }
 
-  bool IsReportingEnabled() override {
+  bool IsReportingEnabled() const override {
     return IsConsentGiven() &&
            ChromeMetricsServicesManagerClient::IsClientInSample();
   }
diff --git a/chrome/browser/metrics/process_memory_metrics_emitter.cc b/chrome/browser/metrics/process_memory_metrics_emitter.cc
index eca9db90..4b40ea3 100644
--- a/chrome/browser/metrics/process_memory_metrics_emitter.cc
+++ b/chrome/browser/metrics/process_memory_metrics_emitter.cc
@@ -66,6 +66,13 @@
                                 pmd->os_dump->private_footprint_kb / 1024);
   UMA_HISTOGRAM_MEMORY_LARGE_MB("Memory.Browser.SharedMemoryFootprint",
                                 pmd->os_dump->shared_footprint_kb / 1024);
+#if defined(OS_LINUX) || defined(OS_ANDROID)
+  UMA_HISTOGRAM_MEMORY_LARGE_MB("Memory.Browser.PrivateSwapFootprint",
+                                pmd->os_dump->private_footprint_swap_kb / 1024);
+  builder.SetPrivateSwapFootprint(pmd->os_dump->private_footprint_swap_kb /
+                                  1024);
+#endif
+
   builder.SetPrivateMemoryFootprint(pmd->os_dump->private_footprint_kb / 1024);
   builder.SetSharedMemoryFootprint(pmd->os_dump->shared_footprint_kb / 1024);
 
@@ -114,12 +121,22 @@
     UMA_HISTOGRAM_MEMORY_LARGE_MB("Memory.Experimental.Renderer2.Malloc",
                                   pmd->chrome_dump->malloc_total_kb / 1024);
 #endif
+#if defined(OS_LINUX) || defined(OS_ANDROID)
+    UMA_HISTOGRAM_MEMORY_LARGE_MB(
+        "Memory.Experimental.Renderer2.PrivateSwapFootprint",
+        pmd->os_dump->private_footprint_swap_kb / 1024);
+#endif
   } else {
     RENDERER_MEMORY_UMA_HISTOGRAMS("Extension");
 #if !defined(OS_WIN)
     UMA_HISTOGRAM_MEMORY_LARGE_MB("Memory.Experimental.Extension2.Malloc",
                                   pmd->chrome_dump->malloc_total_kb / 1024);
 #endif
+#if defined(OS_LINUX) || defined(OS_ANDROID)
+    UMA_HISTOGRAM_MEMORY_LARGE_MB(
+        "Memory.Experimental.Extension2.PrivateSwapFootprint",
+        pmd->os_dump->private_footprint_swap_kb / 1024);
+#endif
   }
   // UKM
   ukm::SourceId ukm_source_id = page_info.is_null()
@@ -138,6 +155,10 @@
   builder.SetBlinkGC(pmd->chrome_dump->blink_gc_total_kb / 1024);
   builder.SetV8(pmd->chrome_dump->v8_total_kb / 1024);
   builder.SetNumberOfExtensions(number_of_extensions);
+#if defined(OS_LINUX) || defined(OS_ANDROID)
+  builder.SetPrivateSwapFootprint(pmd->os_dump->private_footprint_swap_kb /
+                                  1024);
+#endif
 
   if (!page_info.is_null()) {
     builder.SetIsVisible(page_info->is_visible);
@@ -180,6 +201,12 @@
                                 pmd->os_dump->private_footprint_kb / 1024);
   UMA_HISTOGRAM_MEMORY_LARGE_MB("Memory.Gpu.SharedMemoryFootprint",
                                 pmd->os_dump->shared_footprint_kb / 1024);
+#if defined(OS_LINUX) || defined(OS_ANDROID)
+  UMA_HISTOGRAM_MEMORY_LARGE_MB("Memory.Gpu.PrivateSwapFootprint",
+                                pmd->os_dump->private_footprint_swap_kb / 1024);
+  builder.SetPrivateSwapFootprint(pmd->os_dump->private_footprint_swap_kb /
+                                  1024);
+#endif
   builder.SetPrivateMemoryFootprint(pmd->os_dump->private_footprint_kb / 1024);
   builder.SetSharedMemoryFootprint(pmd->os_dump->shared_footprint_kb / 1024);
   if (uptime)
diff --git a/chrome/browser/metrics/process_memory_metrics_emitter_unittest.cc b/chrome/browser/metrics/process_memory_metrics_emitter_unittest.cc
index 06d925c7..e0889e9 100644
--- a/chrome/browser/metrics/process_memory_metrics_emitter_unittest.cc
+++ b/chrome/browser/metrics/process_memory_metrics_emitter_unittest.cc
@@ -81,7 +81,8 @@
 
 OSMemDumpPtr GetFakeOSMemDump(uint32_t resident_set_kb,
                               uint32_t private_footprint_kb,
-                              uint32_t shared_footprint_kb) {
+                              uint32_t shared_footprint_kb,
+                              uint32_t private_swap_footprint_kb) {
   using memory_instrumentation::mojom::VmRegion;
 
   std::vector<memory_instrumentation::mojom::VmRegionPtr> vm_regions;
@@ -99,7 +100,7 @@
                     200));  // byte_stats_proportional_resident
   return memory_instrumentation::mojom::OSMemDump::New(
       resident_set_kb, private_footprint_kb, shared_footprint_kb,
-      std::move(vm_regions));
+      std::move(vm_regions), private_swap_footprint_kb);
 }
 
 void PopulateBrowserMetrics(GlobalMemoryDumpPtr& global_dump,
@@ -114,7 +115,16 @@
   OSMemDumpPtr os_dump =
       GetFakeOSMemDump(metrics_mb["Resident"] * 1024,
                        metrics_mb["PrivateMemoryFootprint"] * 1024,
-                       metrics_mb["SharedMemoryFootprint"] * 1024);
+                       metrics_mb["SharedMemoryFootprint"] * 1024,
+#if defined(OS_LINUX) || defined(OS_ANDROID)
+                       // accessing PrivateSwapFootprint on other OSes will
+                       // modify metrics_mb to create the value, which leads to
+                       // expectation failures.
+                       metrics_mb["PrivateSwapFootprint"] * 1024
+#else
+                       0
+#endif
+                       );
   pmd->os_dump = std::move(os_dump);
   global_dump->process_dumps.push_back(std::move(pmd));
 }
@@ -129,6 +139,9 @@
 #endif
             {"PrivateMemoryFootprint", 30}, {"SharedMemoryFootprint", 35},
             {"Uptime", 42},
+#if defined(OS_LINUX) || defined(OS_ANDROID)
+            {"PrivateSwapFootprint", 50},
+#endif
       },
       base::KEEP_FIRST_OF_DUPES);
 }
@@ -150,7 +163,16 @@
   OSMemDumpPtr os_dump =
       GetFakeOSMemDump(metrics_mb["Resident"] * 1024,
                        metrics_mb["PrivateMemoryFootprint"] * 1024,
-                       metrics_mb["SharedMemoryFootprint"] * 1024);
+                       metrics_mb["SharedMemoryFootprint"] * 1024,
+#if defined(OS_LINUX) || defined(OS_ANDROID)
+                       // accessing PrivateSwapFootprint on other OSes will
+                       // modify metrics_mb to create the value, which leads to
+                       // expectation failures.
+                       metrics_mb["PrivateSwapFootprint"] * 1024
+#else
+                       0
+#endif
+                       );
   pmd->os_dump = std::move(os_dump);
   pmd->pid = pid;
   global_dump->process_dumps.push_back(std::move(pmd));
@@ -166,9 +188,10 @@
 #endif
             {"PrivateMemoryFootprint", 130}, {"SharedMemoryFootprint", 135},
             {"PartitionAlloc", 140}, {"BlinkGC", 150}, {"V8", 160},
-            {"NumberOfExtensions", 0}, {
-          "Uptime", 42
-        }
+            {"NumberOfExtensions", 0}, {"Uptime", 42},
+#if defined(OS_LINUX) || defined(OS_ANDROID)
+            {"PrivateSwapFootprint", 50},
+#endif
       },
       base::KEEP_FIRST_OF_DUPES);
 }
@@ -193,7 +216,16 @@
   OSMemDumpPtr os_dump =
       GetFakeOSMemDump(metrics_mb["Resident"] * 1024,
                        metrics_mb["PrivateMemoryFootprint"] * 1024,
-                       metrics_mb["SharedMemoryFootprint"] * 1024);
+                       metrics_mb["SharedMemoryFootprint"] * 1024,
+#if defined(OS_LINUX) || defined(OS_ANDROID)
+                       // accessing PrivateSwapFootprint on other OSes will
+                       // modify metrics_mb to create the value, which leads to
+                       // expectation failures.
+                       metrics_mb["PrivateSwapFootprint"] * 1024
+#else
+                       0
+#endif
+                       );
   pmd->os_dump = std::move(os_dump);
   global_dump->process_dumps.push_back(std::move(pmd));
 }
@@ -208,6 +240,9 @@
 #endif
             {"PrivateMemoryFootprint", 230}, {"SharedMemoryFootprint", 235},
             {"CommandBuffer", 240}, {"Uptime", 42},
+#if defined(OS_LINUX) || defined(OS_ANDROID)
+            {"PrivateSwapFootprint", 50},
+#endif
       },
       base::KEEP_FIRST_OF_DUPES);
 }
diff --git a/chrome/browser/net/chrome_network_delegate.cc b/chrome/browser/net/chrome_network_delegate.cc
index b806d9dd..44e551b 100644
--- a/chrome/browser/net/chrome_network_delegate.cc
+++ b/chrome/browser/net/chrome_network_delegate.cc
@@ -36,7 +36,6 @@
 #include "components/content_settings/core/browser/cookie_settings.h"
 #include "components/data_usage/core/data_use_aggregator.h"
 #include "components/domain_reliability/monitor.h"
-#include "components/policy/core/browser/url_blacklist_manager.h"
 #include "components/prefs/pref_member.h"
 #include "components/prefs/pref_service.h"
 #include "content/public/browser/browser_thread.h"
@@ -205,7 +204,6 @@
       force_google_safe_search_(nullptr),
       force_youtube_restrict_(nullptr),
       allowed_domains_for_apps_(nullptr),
-      url_blacklist_manager_(NULL),
       experimental_web_platform_features_enabled_(
           base::CommandLine::ForCurrentProcess()->HasSwitch(
               switches::kEnableExperimentalWebPlatformFeatures)),
@@ -278,23 +276,6 @@
     net::URLRequest* request,
     const net::CompletionCallback& callback,
     GURL* new_url) {
-  // TODO(joaodasilva): This prevents extensions from seeing URLs that are
-  // blocked. However, an extension might redirect the request to another URL,
-  // which is not blocked.
-
-  const ResourceRequestInfo* info = ResourceRequestInfo::ForRequest(request);
-  int error = net::ERR_BLOCKED_BY_ADMINISTRATOR;
-  if (info && content::IsResourceTypeFrame(info->GetResourceType()) &&
-      url_blacklist_manager_ &&
-      url_blacklist_manager_->ShouldBlockRequestForFrame(
-          request->url(), &error)) {
-    // URL access blocked by policy.
-    request->net_log().AddEvent(
-        net::NetLogEventType::CHROME_POLICY_ABORTED_REQUEST,
-        net::NetLog::StringCallback("url",
-                                    &request->url().possibly_invalid_spec()));
-    return error;
-  }
 
   extensions_delegate_->ForwardStartRequestStatus(request);
 
diff --git a/chrome/browser/net/chrome_network_delegate.h b/chrome/browser/net/chrome_network_delegate.h
index ae49e8a..964b589 100644
--- a/chrome/browser/net/chrome_network_delegate.h
+++ b/chrome/browser/net/chrome_network_delegate.h
@@ -49,10 +49,6 @@
 class URLRequest;
 }
 
-namespace policy {
-class URLBlacklistManager;
-}
-
 // ChromeNetworkDelegate is the central point from within the chrome code to
 // add hooks into the network stack.
 class ChromeNetworkDelegate : public net::NetworkDelegateImpl {
@@ -67,11 +63,6 @@
   // Pass through to ChromeExtensionsNetworkDelegate::set_extension_info_map().
   void set_extension_info_map(extensions::InfoMap* extension_info_map);
 
-  void set_url_blacklist_manager(
-      const policy::URLBlacklistManager* url_blacklist_manager) {
-    url_blacklist_manager_ = url_blacklist_manager;
-  }
-
   // If |profile| is nullptr or not set, events will be broadcast to all
   // profiles, otherwise they will only be sent to the specified profile.
   // Also pass through to ChromeExtensionsNetworkDelegate::set_profile().
@@ -224,7 +215,6 @@
   StringPrefMember* allowed_domains_for_apps_;
 
   // Weak, owned by our owner.
-  const policy::URLBlacklistManager* url_blacklist_manager_;
   std::unique_ptr<domain_reliability::DomainReliabilityMonitor>
       domain_reliability_monitor_;
 
diff --git a/chrome/browser/net/spdyproxy/data_reduction_proxy_chrome_io_data.cc b/chrome/browser/net/spdyproxy/data_reduction_proxy_chrome_io_data.cc
index bdd1ff749..3ae4a96b 100644
--- a/chrome/browser/net/spdyproxy/data_reduction_proxy_chrome_io_data.cc
+++ b/chrome/browser/net/spdyproxy/data_reduction_proxy_chrome_io_data.cc
@@ -11,6 +11,7 @@
 #include "build/build_config.h"
 #include "chrome/browser/net/spdyproxy/data_reduction_proxy_chrome_settings.h"
 #include "chrome/browser/previews/previews_infobar_delegate.h"
+#include "chrome/browser/previews/previews_infobar_tab_helper.h"
 #include "chrome/browser/previews/previews_service.h"
 #include "chrome/browser/previews/previews_service_factory.h"
 #include "chrome/browser/profiles/profile.h"
@@ -46,12 +47,13 @@
     content::BrowserContext* browser_context,
     const GURL& url,
     previews::PreviewsType type,
+    uint64_t page_id,
     bool opt_out) {
   PreviewsService* previews_service = PreviewsServiceFactory::GetForProfile(
       Profile::FromBrowserContext(browser_context));
   if (previews_service && previews_service->previews_ui_service()) {
-    previews_service->previews_ui_service()->AddPreviewNavigation(url, type,
-                                                                  opt_out);
+    previews_service->previews_ui_service()->AddPreviewNavigation(
+        url, type, opt_out, page_id);
   }
 }
 
@@ -66,6 +68,14 @@
   previews::PreviewsUIService* previews_ui_service =
       previews_service ? previews_service->previews_ui_service() : nullptr;
 
+  PreviewsInfoBarTabHelper* infobar_tab_helper =
+      PreviewsInfoBarTabHelper::FromWebContents(web_contents);
+
+  uint64_t page_id = 0;
+  if (infobar_tab_helper && infobar_tab_helper->previews_user_data()) {
+    page_id = infobar_tab_helper->previews_user_data()->page_id();
+  }
+
   PreviewsInfoBarDelegate::Create(
       web_contents, previews::PreviewsType::LOFI,
       base::Time() /* previews_freshness */, true /* is_data_saver_user */,
@@ -75,11 +85,11 @@
                  web_contents->GetController()
                      .GetLastCommittedEntry()
                      ->GetRedirectChain()[0],
-                 previews::PreviewsType::LOFI),
+                 previews::PreviewsType::LOFI, page_id),
       previews_ui_service);
 }
 
-} // namespace
+}  // namespace
 
 std::unique_ptr<data_reduction_proxy::DataReductionProxyIOData>
 CreateDataReductionProxyChromeIOData(
diff --git a/chrome/browser/offline_pages/background_loader_offliner_unittest.cc b/chrome/browser/offline_pages/background_loader_offliner_unittest.cc
index a55946f..7a30320b 100644
--- a/chrome/browser/offline_pages/background_loader_offliner_unittest.cc
+++ b/chrome/browser/offline_pages/background_loader_offliner_unittest.cc
@@ -28,6 +28,7 @@
 #include "content/public/browser/navigation_handle.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/test/test_browser_thread_bundle.h"
+#include "content/public/test/test_renderer_host.h"
 #include "content/public/test/web_contents_tester.h"
 #include "net/base/net_errors.h"
 #include "net/http/http_response_headers.h"
@@ -223,6 +224,7 @@
   void OnProgress(const SavePageRequest& request, int64_t bytes);
   void OnCancel(const SavePageRequest& request);
   content::TestBrowserThreadBundle thread_bundle_;
+  content::RenderViewHostTestEnabler rvhte_;
   TestingProfile profile_;
   std::unique_ptr<OfflinerPolicy> policy_;
   TestLoadTerminationListener* load_termination_listener_;
diff --git a/chrome/browser/page_load_metrics/observers/multi_tab_loading_page_load_metrics_observer.cc b/chrome/browser/page_load_metrics/observers/multi_tab_loading_page_load_metrics_observer.cc
index 767ce004..f221916 100644
--- a/chrome/browser/page_load_metrics/observers/multi_tab_loading_page_load_metrics_observer.cc
+++ b/chrome/browser/page_load_metrics/observers/multi_tab_loading_page_load_metrics_observer.cc
@@ -19,6 +19,8 @@
 
 namespace internal {
 
+const char kHistogramMultiTabLoadingNumTabsWithInflightLoad[] =
+    "PageLoad.Clients.MultiTabLoading.NumTabsWithInflightLoad";
 const char kHistogramMultiTabLoadingFirstContentfulPaint[] =
     "PageLoad.Clients.MultiTabLoading.PaintTiming."
     "NavigationToFirstContentfulPaint";
@@ -57,7 +59,20 @@
     content::NavigationHandle* navigation_handle,
     const GURL& currently_committed_url,
     bool started_in_foreground) {
-  return IsAnyTabLoading(navigation_handle) ? CONTINUE_OBSERVING
+  num_loading_tabs_when_started_ =
+      NumberOfTabsWithInflightLoad(navigation_handle);
+  return CONTINUE_OBSERVING;
+}
+
+page_load_metrics::PageLoadMetricsObserver::ObservePolicy
+MultiTabLoadingPageLoadMetricsObserver::OnCommit(
+    content::NavigationHandle* navigation_handle,
+    ukm::SourceId source_id) {
+  // Report here so that this is logged only for normal page loads.
+  UMA_HISTOGRAM_COUNTS_100(
+      internal::kHistogramMultiTabLoadingNumTabsWithInflightLoad,
+      num_loading_tabs_when_started_);
+  return num_loading_tabs_when_started_ > 0 ? CONTINUE_OBSERVING
                                             : STOP_OBSERVING;
 }
 
@@ -127,38 +142,43 @@
 
 #if defined(OS_ANDROID)
 
-bool MultiTabLoadingPageLoadMetricsObserver::IsAnyTabLoading(
+int MultiTabLoadingPageLoadMetricsObserver::NumberOfTabsWithInflightLoad(
     content::NavigationHandle* navigation_handle) {
   content::WebContents* this_contents = navigation_handle->GetWebContents();
+  int num_loading = 0;
   for (TabModelList::const_iterator it = TabModelList::begin();
        it != TabModelList::end(); ++it) {
     TabModel* model = *it;
+    // Note: |this_contents| may not appear in |model|.
     for (int i = 0; i < model->GetTabCount(); ++i) {
       content::WebContents* other_contents = model->GetWebContentsAt(i);
       if (other_contents && other_contents != this_contents &&
           other_contents->IsLoading()) {
-        return true;
+        num_loading++;
       }
     }
   }
-  return false;
+  return num_loading;
 }
 
 #else  // defined(OS_ANDROID)
 
-bool MultiTabLoadingPageLoadMetricsObserver::IsAnyTabLoading(
+int MultiTabLoadingPageLoadMetricsObserver::NumberOfTabsWithInflightLoad(
     content::NavigationHandle* navigation_handle) {
   content::WebContents* this_contents = navigation_handle->GetWebContents();
+  int num_loading = 0;
   for (auto* browser : *BrowserList::GetInstance()) {
     TabStripModel* model = browser->tab_strip_model();
+    // Note: |this_contents| may not appear in |model|, e.g. for a new
+    // background tab navigation.
     for (int i = 0; i < model->count(); ++i) {
       content::WebContents* other_contents = model->GetWebContentsAt(i);
       if (other_contents != this_contents && other_contents->IsLoading()) {
-        return true;
+        num_loading++;
       }
     }
   }
-  return false;
+  return num_loading;
 }
 
 #endif  // defined(OS_ANDROID)
diff --git a/chrome/browser/page_load_metrics/observers/multi_tab_loading_page_load_metrics_observer.h b/chrome/browser/page_load_metrics/observers/multi_tab_loading_page_load_metrics_observer.h
index 5753f20..63058ed 100644
--- a/chrome/browser/page_load_metrics/observers/multi_tab_loading_page_load_metrics_observer.h
+++ b/chrome/browser/page_load_metrics/observers/multi_tab_loading_page_load_metrics_observer.h
@@ -15,6 +15,7 @@
 namespace internal {
 
 // Exposed for tests.
+extern const char kHistogramMultiTabLoadingNumTabsWithInflightLoad[];
 extern const char kHistogramMultiTabLoadingFirstContentfulPaint[];
 extern const char kHistogramMultiTabLoadingForegroundToFirstContentfulPaint[];
 extern const char kHistogramMultiTabLoadingFirstMeaningfulPaint[];
@@ -39,6 +40,9 @@
       content::NavigationHandle* navigation_handle,
       const GURL& currently_committed_url,
       bool started_in_foreground) override;
+  page_load_metrics::PageLoadMetricsObserver::ObservePolicy OnCommit(
+      content::NavigationHandle* navigation_handle,
+      ukm::SourceId source_id) override;
   void OnFirstContentfulPaintInPage(
       const page_load_metrics::mojom::PageLoadTiming& timing,
       const page_load_metrics::PageLoadExtraInfo& extra_info) override;
@@ -53,10 +57,14 @@
       const page_load_metrics::PageLoadExtraInfo& info) override;
 
  protected:
-  // Overridden in testing.
-  virtual bool IsAnyTabLoading(content::NavigationHandle* navigation_handle);
+  // Overridden in testing. Returns the number of loading tabs, excluding
+  // current tab.
+  virtual int NumberOfTabsWithInflightLoad(
+      content::NavigationHandle* navigation_handle);
 
  private:
+  int num_loading_tabs_when_started_;
+
   DISALLOW_COPY_AND_ASSIGN(MultiTabLoadingPageLoadMetricsObserver);
 };
 
diff --git a/chrome/browser/page_load_metrics/observers/multi_tab_loading_page_load_metrics_observer_unittest.cc b/chrome/browser/page_load_metrics/observers/multi_tab_loading_page_load_metrics_observer_unittest.cc
index e3eafff..0687bd5 100644
--- a/chrome/browser/page_load_metrics/observers/multi_tab_loading_page_load_metrics_observer_unittest.cc
+++ b/chrome/browser/page_load_metrics/observers/multi_tab_loading_page_load_metrics_observer_unittest.cc
@@ -23,8 +23,9 @@
   ~TestMultiTabLoadingPageLoadMetricsObserver() override {}
 
  private:
-  bool IsAnyTabLoading(content::NavigationHandle* navigation_handle) override {
-    return multi_tab_loading_;
+  int NumberOfTabsWithInflightLoad(
+      content::NavigationHandle* navigation_handle) override {
+    return multi_tab_loading_ ? 1 : 0;
   }
 
   const bool multi_tab_loading_;
@@ -82,6 +83,8 @@
 
 TEST_F(MultiTabLoadingPageLoadMetricsObserverTest, SingleTabLoading) {
   SimulatePageLoad(SingleTabLoading, Foreground);
+  histogram_tester().ExpectUniqueSample(
+      internal::kHistogramMultiTabLoadingNumTabsWithInflightLoad, 0, 1);
   histogram_tester().ExpectTotalCount(
       internal::kHistogramMultiTabLoadingFirstContentfulPaint, 0);
   histogram_tester().ExpectTotalCount(
@@ -102,6 +105,8 @@
 
 TEST_F(MultiTabLoadingPageLoadMetricsObserverTest, MultiTabLoading) {
   SimulatePageLoad(MultiTabLoading, Foreground);
+  histogram_tester().ExpectUniqueSample(
+      internal::kHistogramMultiTabLoadingNumTabsWithInflightLoad, 1, 1);
   histogram_tester().ExpectTotalCount(
       internal::kHistogramMultiTabLoadingFirstContentfulPaint, 1);
   histogram_tester().ExpectTotalCount(
@@ -122,6 +127,8 @@
 
 TEST_F(MultiTabLoadingPageLoadMetricsObserverTest, MultiTabBackground) {
   SimulatePageLoad(MultiTabLoading, Background);
+  histogram_tester().ExpectUniqueSample(
+      internal::kHistogramMultiTabLoadingNumTabsWithInflightLoad, 1, 1);
   histogram_tester().ExpectTotalCount(
       internal::kHistogramMultiTabLoadingFirstContentfulPaint, 0);
   histogram_tester().ExpectTotalCount(
diff --git a/chrome/browser/page_load_metrics/page_load_tracker.cc b/chrome/browser/page_load_metrics/page_load_tracker.cc
index be7a5ec8..b64d0cf 100644
--- a/chrome/browser/page_load_metrics/page_load_tracker.cc
+++ b/chrome/browser/page_load_metrics/page_load_tracker.cc
@@ -12,6 +12,7 @@
 #include "base/logging.h"
 #include "base/memory/ptr_util.h"
 #include "base/metrics/histogram_macros.h"
+#include "base/trace_event/trace_event.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/page_load_metrics/page_load_metrics_embedder_interface.h"
 #include "chrome/browser/page_load_metrics/page_load_metrics_util.h"
@@ -28,14 +29,18 @@
 // This macro invokes the specified method on each observer, passing the
 // variable length arguments as the method's arguments, and removes the observer
 // from the list of observers if the given method returns STOP_OBSERVING.
-#define INVOKE_AND_PRUNE_OBSERVERS(observers, Method, ...)    \
-  for (auto it = observers.begin(); it != observers.end();) { \
-    if ((*it)->Method(__VA_ARGS__) ==                         \
-        PageLoadMetricsObserver::STOP_OBSERVING) {            \
-      it = observers.erase(it);                               \
-    } else {                                                  \
-      ++it;                                                   \
-    }                                                         \
+#define INVOKE_AND_PRUNE_OBSERVERS(observers, Method, ...)      \
+  {                                                             \
+    TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("loading"),          \
+                 "PageLoadMetricsObserver::" #Method);          \
+    for (auto it = observers.begin(); it != observers.end();) { \
+      if ((*it)->Method(__VA_ARGS__) ==                         \
+          PageLoadMetricsObserver::STOP_OBSERVING) {            \
+        it = observers.erase(it);                               \
+      } else {                                                  \
+        ++it;                                                   \
+      }                                                         \
+    }                                                           \
   }
 
 namespace page_load_metrics {
diff --git a/chrome/browser/previews/previews_infobar_delegate.cc b/chrome/browser/previews/previews_infobar_delegate.cc
index 7d5464cc..a552a85 100644
--- a/chrome/browser/previews/previews_infobar_delegate.cc
+++ b/chrome/browser/previews/previews_infobar_delegate.cc
@@ -137,6 +137,9 @@
 #endif
 
   infobar_service->AddInfoBar(std::move(infobar_ptr));
+  uint64_t page_id = (infobar_tab_helper->previews_user_data())
+                         ? infobar_tab_helper->previews_user_data()->page_id()
+                         : 0;
 
   if (previews_ui_service) {
     // Not in incognito mode or guest mode.
@@ -146,7 +149,7 @@
         web_contents->GetController()
             .GetLastCommittedEntry()
             ->GetRedirectChain()[0] /* GURL */,
-        base::Time::Now());
+        base::Time::Now(), page_id);
   }
 
   RecordPreviewsInfoBarAction(previews_type, INFOBAR_SHOWN);
diff --git a/chrome/browser/previews/previews_infobar_delegate_unittest.cc b/chrome/browser/previews/previews_infobar_delegate_unittest.cc
index e5d27e9..8e356d3 100644
--- a/chrome/browser/previews/previews_infobar_delegate_unittest.cc
+++ b/chrome/browser/previews/previews_infobar_delegate_unittest.cc
@@ -130,7 +130,8 @@
   void LogMessage(const std::string& event_type,
                   const std::string& event_description,
                   const GURL& url,
-                  base::Time time) override {
+                  base::Time time,
+                  uint64_t page_id) override {
     event_type_ = event_type;
     event_description_ = event_description;
   }
diff --git a/chrome/browser/previews/previews_infobar_tab_helper.cc b/chrome/browser/previews/previews_infobar_tab_helper.cc
index 8d5f75de..db56af13 100644
--- a/chrome/browser/previews/previews_infobar_tab_helper.cc
+++ b/chrome/browser/previews/previews_infobar_tab_helper.cc
@@ -37,12 +37,13 @@
 void AddPreviewNavigationCallback(content::BrowserContext* browser_context,
                                   const GURL& url,
                                   previews::PreviewsType type,
+                                  uint64_t page_id,
                                   bool opt_out) {
   PreviewsService* previews_service = PreviewsServiceFactory::GetForProfile(
       Profile::FromBrowserContext(browser_context));
   if (previews_service && previews_service->previews_ui_service()) {
-    previews_service->previews_ui_service()->AddPreviewNavigation(url, type,
-                                                                  opt_out);
+    previews_service->previews_ui_service()->AddPreviewNavigation(
+        url, type, opt_out, page_id);
   }
 }
 
@@ -75,6 +76,8 @@
     previews_user_data_ = nav_data->previews_user_data()->DeepCopy();
   }
 
+  uint64_t page_id = (previews_user_data_) ? previews_user_data_->page_id() : 0;
+
   // The infobar should only be told if the page was a reload if the previous
   // page displayed a timestamp.
   bool is_reload =
@@ -111,7 +114,7 @@
         base::Bind(&AddPreviewNavigationCallback,
                    web_contents()->GetBrowserContext(),
                    navigation_handle->GetRedirectChain()[0],
-                   previews::PreviewsType::OFFLINE),
+                   previews::PreviewsType::OFFLINE, page_id),
         previews_ui_service);
     // Don't try to show other infobars if this is an offline preview.
     return;
@@ -133,7 +136,7 @@
         base::Bind(&AddPreviewNavigationCallback,
                    web_contents()->GetBrowserContext(),
                    navigation_handle->GetRedirectChain()[0],
-                   previews::PreviewsType::LITE_PAGE),
+                   previews::PreviewsType::LITE_PAGE, page_id),
         previews_ui_service);
     return;
   }
@@ -148,7 +151,7 @@
           base::Bind(&AddPreviewNavigationCallback,
                      web_contents()->GetBrowserContext(),
                      navigation_handle->GetRedirectChain()[0],
-                     previews::PreviewsType::NOSCRIPT),
+                     previews::PreviewsType::NOSCRIPT, page_id),
           previews_ui_service);
     }
   }
diff --git a/chrome/browser/printing/cloud_print/privet_http_unittest.cc b/chrome/browser/printing/cloud_print/privet_http_unittest.cc
index 2ee1a40c..39812a8 100644
--- a/chrome/browser/printing/cloud_print/privet_http_unittest.cc
+++ b/chrome/browser/printing/cloud_print/privet_http_unittest.cc
@@ -43,192 +43,197 @@
 using content::BrowserThread;
 using net::EmbeddedTestServer;
 
-const char kSampleInfoResponse[] = "{"
-    "       \"version\": \"1.0\","
-    "       \"name\": \"Common printer\","
-    "       \"description\": \"Printer connected through Chrome connector\","
-    "       \"url\": \"https://www.google.com/cloudprint\","
-    "       \"type\": ["
-    "               \"printer\""
-    "       ],"
-    "       \"id\": \"\","
-    "       \"device_state\": \"idle\","
-    "       \"connection_state\": \"online\","
-    "       \"manufacturer\": \"Google\","
-    "       \"model\": \"Google Chrome\","
-    "       \"serial_number\": \"1111-22222-33333-4444\","
-    "       \"firmware\": \"24.0.1312.52\","
-    "       \"uptime\": 600,"
-    "       \"setup_url\": \"http://support.google.com/\","
-    "       \"support_url\": \"http://support.google.com/cloudprint/?hl=en\","
-    "       \"update_url\": \"http://support.google.com/cloudprint/?hl=en\","
-    "       \"x-privet-token\": \"SampleTokenForTesting\","
-    "       \"api\": ["
-    "               \"/privet/accesstoken\","
-    "               \"/privet/capabilities\","
-    "               \"/privet/printer/submitdoc\","
-    "       ]"
-    "}";
+const char kSampleInfoResponse[] =
+    R"({
+         "version": "1.0",
+         "name": "Common printer",
+         "description": "Printer connected through Chrome connector",
+         "url": "https://www.google.com/cloudprint",
+         "type": [ "printer" ],
+         "id": "",
+         "device_state": "idle",
+         "connection_state": "online",
+         "manufacturer": "Google",
+         "model": "Google Chrome",
+         "serial_number": "1111-22222-33333-4444",
+         "firmware": "24.0.1312.52",
+         "uptime": 600,
+         "setup_url": "http://support.google.com/",
+         "support_url": "http://support.google.com/cloudprint/?hl=en",
+         "update_url": "http://support.google.com/cloudprint/?hl=en",
+         "x-privet-token": "SampleTokenForTesting",
+         "api": [
+           "/privet/accesstoken",
+           "/privet/capabilities",
+           "/privet/printer/submitdoc",
+         ]
+       })";
 
-const char kSampleInfoResponseRegistered[] = "{"
-    "       \"version\": \"1.0\","
-    "       \"name\": \"Common printer\","
-    "       \"description\": \"Printer connected through Chrome connector\","
-    "       \"url\": \"https://www.google.com/cloudprint\","
-    "       \"type\": ["
-    "               \"printer\""
-    "       ],"
-    "       \"id\": \"MyDeviceID\","
-    "       \"device_state\": \"idle\","
-    "       \"connection_state\": \"online\","
-    "       \"manufacturer\": \"Google\","
-    "       \"model\": \"Google Chrome\","
-    "       \"serial_number\": \"1111-22222-33333-4444\","
-    "       \"firmware\": \"24.0.1312.52\","
-    "       \"uptime\": 600,"
-    "       \"setup_url\": \"http://support.google.com/\","
-    "       \"support_url\": \"http://support.google.com/cloudprint/?hl=en\","
-    "       \"update_url\": \"http://support.google.com/cloudprint/?hl=en\","
-    "       \"x-privet-token\": \"SampleTokenForTesting\","
-    "       \"api\": ["
-    "               \"/privet/accesstoken\","
-    "               \"/privet/capabilities\","
-    "               \"/privet/printer/submitdoc\","
-    "       ]"
-    "}";
+const char kSampleInfoResponseRegistered[] =
+    R"({
+         "version": "1.0",
+         "name": "Common printer",
+         "description": "Printer connected through Chrome connector",
+         "url": "https://www.google.com/cloudprint",
+         "type": [ "printer" ],
+         "id": "MyDeviceID",
+         "device_state": "idle",
+         "connection_state": "online",
+         "manufacturer": "Google",
+         "model": "Google Chrome",
+         "serial_number": "1111-22222-33333-4444",
+         "firmware": "24.0.1312.52",
+         "uptime": 600,
+         "setup_url": "http://support.google.com/",
+         "support_url": "http://support.google.com/cloudprint/?hl=en",
+         "update_url": "http://support.google.com/cloudprint/?hl=en",
+         "x-privet-token": "SampleTokenForTesting",
+         "api": [
+           "/privet/accesstoken",
+           "/privet/capabilities",
+           "/privet/printer/submitdoc",
+         ]
+       })";
 
-const char kSampleRegisterStartResponse[] = "{"
-    "\"user\": \"example@google.com\","
-    "\"action\": \"start\""
-    "}";
+const char kSampleRegisterStartResponse[] =
+    R"({
+         "user": "example@google.com",
+         "action": "start"
+       })";
 
-const char kSampleRegisterGetClaimTokenResponse[] = "{"
-    "       \"action\": \"getClaimToken\","
-    "       \"user\": \"example@google.com\","
-    "       \"token\": \"MySampleToken\","
-    "       \"claim_url\": \"https://domain.com/SoMeUrL\""
-    "}";
+const char kSampleRegisterGetClaimTokenResponse[] =
+    R"({
+         "action": "getClaimToken",
+         "user": "example@google.com",
+         "token": "MySampleToken",
+         "claim_url": "https://domain.com/SoMeUrL"
+       })";
 
-const char kSampleRegisterCompleteResponse[] = "{"
-    "\"user\": \"example@google.com\","
-    "\"action\": \"complete\","
-    "\"device_id\": \"MyDeviceID\""
-    "}";
+const char kSampleRegisterCompleteResponse[] =
+    R"({
+         "user": "example@google.com",
+         "action": "complete",
+         "device_id": "MyDeviceID"
+       })";
 
 const char kSampleXPrivetErrorResponse[] =
-    "{ \"error\": \"invalid_x_privet_token\" }";
+    R"({ "error": "invalid_x_privet_token" })";
 
 const char kSampleRegisterErrorTransient[] =
-    "{ \"error\": \"device_busy\", \"timeout\": 1}";
+    R"({ "error": "device_busy", "timeout": 1})";
 
 const char kSampleRegisterErrorPermanent[] =
-    "{ \"error\": \"user_cancel\" }";
+    R"({ "error": "user_cancel" })";
 
 const char kSampleInfoResponseBadJson[] = "{";
 
-const char kSampleRegisterCancelResponse[] = "{"
-    "\"user\": \"example@google.com\","
-    "\"action\": \"cancel\""
-    "}";
+const char kSampleRegisterCancelResponse[] =
+    R"({
+         "user": "example@google.com",
+         "action": "cancel"
+       })";
 
-const char kSampleCapabilitiesResponse[] = "{"
-    "\"version\" : \"1.0\","
-    "\"printer\" : {"
-    "  \"supported_content_type\" : ["
-    "   { \"content_type\" : \"application/pdf\" },"
-    "   { \"content_type\" : \"image/pwg-raster\" }"
-    "  ]"
-    "}"
-    "}";
+const char kSampleCapabilitiesResponse[] =
+    R"({
+         "version" : "1.0",
+         "printer" : {
+           "supported_content_type" : [
+             { "content_type" : "application/pdf" },
+             { "content_type" : "image/pwg-raster" }
+           ]
+         }
+       })";
 
 #if BUILDFLAG(ENABLE_PRINT_PREVIEW)
-const char kSampleInfoResponseWithCreatejob[] = "{"
-    "       \"version\": \"1.0\","
-    "       \"name\": \"Common printer\","
-    "       \"description\": \"Printer connected through Chrome connector\","
-    "       \"url\": \"https://www.google.com/cloudprint\","
-    "       \"type\": ["
-    "               \"printer\""
-    "       ],"
-    "       \"id\": \"\","
-    "       \"device_state\": \"idle\","
-    "       \"connection_state\": \"online\","
-    "       \"manufacturer\": \"Google\","
-    "       \"model\": \"Google Chrome\","
-    "       \"serial_number\": \"1111-22222-33333-4444\","
-    "       \"firmware\": \"24.0.1312.52\","
-    "       \"uptime\": 600,"
-    "       \"setup_url\": \"http://support.google.com/\","
-    "       \"support_url\": \"http://support.google.com/cloudprint/?hl=en\","
-    "       \"update_url\": \"http://support.google.com/cloudprint/?hl=en\","
-    "       \"x-privet-token\": \"SampleTokenForTesting\","
-    "       \"api\": ["
-    "               \"/privet/accesstoken\","
-    "               \"/privet/capabilities\","
-    "               \"/privet/printer/createjob\","
-    "               \"/privet/printer/submitdoc\","
-    "       ]"
-    "}";
+const char kSampleInfoResponseWithCreatejob[] =
+    R"({
+         "version": "1.0",
+         "name": "Common printer",
+         "description": "Printer connected through Chrome connector",
+         "url": "https://www.google.com/cloudprint",
+         "type": [ "printer" ],
+         "id": "",
+         "device_state": "idle",
+         "connection_state": "online",
+         "manufacturer": "Google",
+         "model": "Google Chrome",
+         "serial_number": "1111-22222-33333-4444",
+         "firmware": "24.0.1312.52",
+         "uptime": 600,
+         "setup_url": "http://support.google.com/",
+         "support_url": "http://support.google.com/cloudprint/?hl=en",
+         "update_url": "http://support.google.com/cloudprint/?hl=en",
+         "x-privet-token": "SampleTokenForTesting",
+         "api": [
+           "/privet/accesstoken",
+           "/privet/capabilities",
+           "/privet/printer/createjob",
+           "/privet/printer/submitdoc",
+         ]
+       })";
 
-const char kSampleLocalPrintResponse[] = "{"
-    "\"job_id\": \"123\","
-    "\"expires_in\": 500,"
-    "\"job_type\": \"application/pdf\","
-    "\"job_size\": 16,"
-    "\"job_name\": \"Sample job name\","
-    "}";
+const char kSampleLocalPrintResponse[] =
+    R"({
+         "job_id": "123",
+         "expires_in": 500,
+         "job_type": "application/pdf",
+         "job_size": 16,
+         "job_name": "Sample job name",
+       })";
 
-const char kSampleCapabilitiesResponsePWGOnly[] = "{"
-    "\"version\" : \"1.0\","
-    "\"printer\" : {"
-    "  \"supported_content_type\" : ["
-    "   { \"content_type\" : \"image/pwg-raster\" }"
-    "  ]"
-    "}"
-    "}";
+const char kSampleCapabilitiesResponsePWGOnly[] =
+    R"({
+         "version" : "1.0",
+         "printer" : {
+           "supported_content_type" : [
+              { "content_type" : "image/pwg-raster" }
+           ]
+         }
+       })";
 
-const char kSampleErrorResponsePrinterBusy[] = "{"
-    "\"error\": \"invalid_print_job\","
-    "\"timeout\": 1 "
-    "}";
+const char kSampleErrorResponsePrinterBusy[] =
+    R"({
+         "error": "invalid_print_job",
+         "timeout": 1
+       })";
 
-const char kSampleInvalidDocumentTypeResponse[] = "{"
-    "\"error\" : \"invalid_document_type\""
-    "}";
+const char kSampleInvalidDocumentTypeResponse[] =
+    R"({ "error" : "invalid_document_type" })";
 
-const char kSampleCreatejobResponse[] = "{ \"job_id\": \"1234\" }";
+const char kSampleCreatejobResponse[] = R"({ "job_id": "1234" })";
 
-const char kSampleCapabilitiesResponseWithAnyMimetype[] = "{"
-    "\"version\" : \"1.0\","
-    "\"printer\" : {"
-    "  \"supported_content_type\" : ["
-    "   { \"content_type\" : \"*/*\" },"
-    "   { \"content_type\" : \"image/pwg-raster\" }"
-    "  ]"
-    "}"
-    "}";
+const char kSampleCapabilitiesResponseWithAnyMimetype[] =
+    R"({
+         "version" : "1.0",
+         "printer" : {
+           "supported_content_type" : [
+             { "content_type" : "*/*" },
+             { "content_type" : "image/pwg-raster" }
+           ]
+         }
+       })";
 
-const char kSampleCJT[] = "{ \"version\" : \"1.0\" }";
+const char kSampleCJT[] = R"({ "version" : "1.0" })";
 
 const char kSampleCapabilitiesResponsePWGSettings[] =
-    "{"
-    "\"version\" : \"1.0\","
-    "\"printer\" : {"
-    " \"pwg_raster_config\" : {"
-    "   \"document_sheet_back\" : \"MANUAL_TUMBLE\","
-    "   \"reverse_order_streaming\": true"
-    "  },"
-    "  \"supported_content_type\" : ["
-    "   { \"content_type\" : \"image/pwg-raster\" }"
-    "  ]"
-    "}"
-    "}";
+    R"({
+         "version" : "1.0",
+         "printer" : {
+           "pwg_raster_config" : {
+             "document_sheet_back" : "MANUAL_TUMBLE",
+             "reverse_order_streaming": true
+           },
+           "supported_content_type" : [
+             { "content_type" : "image/pwg-raster" }
+           ]
+         }
+       })";
 
 const char kSampleCJTDuplex[] =
-    "{"
-    "\"version\" : \"1.0\","
-    "\"print\": { \"duplex\": {\"type\": \"SHORT_EDGE\"} }"
-    "}";
+    R"({
+         "version" : "1.0",
+         "print": { "duplex": {"type": "SHORT_EDGE"} }
+       })";
 #endif  // BUILDFLAG(ENABLE_PRINT_PREVIEW)
 
 const char* const kTestParams[] = {"8.8.4.4", "2001:4860:4860::8888"};
@@ -282,10 +287,13 @@
   bool SuccessfulResponseToURL(const GURL& url,
                                const std::string& response) {
     net::TestURLFetcher* fetcher = fetcher_factory_.GetFetcherByID(0);
-    EXPECT_TRUE(fetcher);
-    EXPECT_EQ(url, fetcher->GetOriginalURL());
+    if (!fetcher) {
+      ADD_FAILURE();
+      return false;
+    }
 
-    if (!fetcher || url != fetcher->GetOriginalURL())
+    EXPECT_EQ(url, fetcher->GetOriginalURL());
+    if (url != fetcher->GetOriginalURL())
       return false;
 
     fetcher->SetResponseString(response);
@@ -300,11 +308,12 @@
                                       const std::string& data,
                                       const std::string& response) {
     net::TestURLFetcher* fetcher = fetcher_factory_.GetFetcherByID(0);
-    EXPECT_TRUE(fetcher);
-    EXPECT_EQ(url, fetcher->GetOriginalURL());
-
-    if (!fetcher)
+    if (!fetcher) {
+      ADD_FAILURE();
       return false;
+    }
+
+    EXPECT_EQ(url, fetcher->GetOriginalURL());
 
     EXPECT_EQ(data, fetcher->upload_data());
     if (data != fetcher->upload_data())
@@ -317,11 +326,12 @@
                                           const std::string& data,
                                           const std::string& response) {
     net::TestURLFetcher* fetcher = fetcher_factory_.GetFetcherByID(0);
-    EXPECT_TRUE(fetcher);
-    EXPECT_EQ(url, fetcher->GetOriginalURL());
-
-    if (!fetcher)
+    if (!fetcher) {
+      ADD_FAILURE();
       return false;
+    }
+
+    EXPECT_EQ(url, fetcher->GetOriginalURL());
 
     std::string normalized_data = NormalizeJson(data);
     std::string normalized_upload_data = NormalizeJson(fetcher->upload_data());
@@ -336,11 +346,12 @@
                                           const base::FilePath& file_path,
                                           const std::string& response) {
     net::TestURLFetcher* fetcher = fetcher_factory_.GetFetcherByID(0);
-    EXPECT_TRUE(fetcher);
-    EXPECT_EQ(url, fetcher->GetOriginalURL());
-
-    if (!fetcher)
+    if (!fetcher) {
+      ADD_FAILURE();
       return false;
+    }
+
+    EXPECT_EQ(url, fetcher->GetOriginalURL());
 
     EXPECT_EQ(file_path, fetcher->upload_file_path());
     if (file_path != fetcher->upload_file_path())
@@ -500,9 +511,13 @@
   bool SuccessfulResponseToURL(const GURL& url,
                                const std::string& response) {
     net::TestURLFetcher* fetcher = fetcher_factory_.GetFetcherByID(0);
-    EXPECT_TRUE(fetcher);
+    if (!fetcher) {
+      ADD_FAILURE();
+      return false;
+    }
+
     EXPECT_EQ(url, fetcher->GetOriginalURL());
-    if (!fetcher || url != fetcher->GetOriginalURL())
+    if (url != fetcher->GetOriginalURL())
       return false;
 
     fetcher->SetResponseString(response);
@@ -807,7 +822,6 @@
 
   EXPECT_CALL(local_print_delegate_, OnPrivetPrintingDoneInternal());
 
-  // TODO(noamsml): Is encoding spaces as pluses standard?
   EXPECT_TRUE(SuccessfulResponseToURLAndData(
       GetUrl("/privet/printer/submitdoc?"
              "client_name=Chrome&user_name=sample%40gmail.com&"
@@ -832,7 +846,6 @@
 
   EXPECT_CALL(local_print_delegate_, OnPrivetPrintingDoneInternal());
 
-  // TODO(noamsml): Is encoding spaces as pluses standard?
   EXPECT_TRUE(SuccessfulResponseToURLAndData(
       GetUrl("/privet/printer/submitdoc?"
              "client_name=Chrome&user_name=sample%40gmail.com&"
@@ -856,7 +869,6 @@
 
   EXPECT_CALL(local_print_delegate_, OnPrivetPrintingDoneInternal());
 
-  // TODO(noamsml): Is encoding spaces as pluses standard?
   EXPECT_TRUE(SuccessfulResponseToURLAndFilePath(
       GetUrl("/privet/printer/submitdoc?"
              "client_name=Chrome&user_name=sample%40gmail.com"
@@ -891,7 +903,6 @@
 
   EXPECT_CALL(local_print_delegate_, OnPrivetPrintingDoneInternal());
 
-  // TODO(noamsml): Is encoding spaces as pluses standard?
   EXPECT_TRUE(SuccessfulResponseToURLAndFilePath(
       GetUrl("/privet/printer/submitdoc?"
              "client_name=Chrome&user_name=sample%40gmail.com"
@@ -926,7 +937,6 @@
 
   EXPECT_CALL(local_print_delegate_, OnPrivetPrintingDoneInternal());
 
-  // TODO(noamsml): Is encoding spaces as pluses standard?
   EXPECT_TRUE(SuccessfulResponseToURLAndData(
       GetUrl("/privet/printer/submitdoc?"
              "client_name=Chrome&user_name=sample%40gmail.com&"
@@ -956,7 +966,6 @@
 
   EXPECT_CALL(local_print_delegate_, OnPrivetPrintingDoneInternal());
 
-  // TODO(noamsml): Is encoding spaces as pluses standard?
   EXPECT_TRUE(SuccessfulResponseToURLAndData(
       GetUrl("/privet/printer/submitdoc?"
              "client_name=Chrome&user_name=sample%40gmail.com&"
@@ -984,7 +993,6 @@
       SuccessfulResponseToURLAndJSONData(GetUrl("/privet/printer/createjob"),
                                          kSampleCJT, kSampleCreatejobResponse));
 
-  // TODO(noamsml): Is encoding spaces as pluses standard?
   EXPECT_TRUE(SuccessfulResponseToURLAndData(
       GetUrl("/privet/printer/submitdoc?"
              "client_name=Chrome&user_name=sample%40gmail.com&"
diff --git a/chrome/browser/printing/pwg_raster_converter.cc b/chrome/browser/printing/pwg_raster_converter.cc
index 0ab1c92..01ae255 100644
--- a/chrome/browser/printing/pwg_raster_converter.cc
+++ b/chrome/browser/printing/pwg_raster_converter.cc
@@ -131,7 +131,7 @@
 
   PdfRenderSettings settings_;
   PwgRasterSettings bitmap_settings_;
-  mojo::InterfacePtr<printing::mojom::PDFToPWGRasterConverter>
+  mojo::InterfacePtr<printing::mojom::PdfToPwgRasterConverter>
       pdf_to_pwg_raster_converter_ptr_;
   PWGRasterConverter::ResultCallback callback_;
   const scoped_refptr<base::SequencedTaskRunner> blocking_task_runner_;
diff --git a/chrome/browser/printing/pwg_raster_converter_browsertest.cc b/chrome/browser/printing/pwg_raster_converter_browsertest.cc
index fcc9c5eb..978d4ba5 100644
--- a/chrome/browser/printing/pwg_raster_converter_browsertest.cc
+++ b/chrome/browser/printing/pwg_raster_converter_browsertest.cc
@@ -33,11 +33,11 @@
   quit_closure.Run();
 }
 
-class PDFToPWGRasterBrowserTest : public InProcessBrowserTest {
+class PdfToPwgRasterBrowserTest : public InProcessBrowserTest {
  public:
-  PDFToPWGRasterBrowserTest()
+  PdfToPwgRasterBrowserTest()
       : converter_(PWGRasterConverter::CreateDefault()) {}
-  ~PDFToPWGRasterBrowserTest() override {}
+  ~PdfToPwgRasterBrowserTest() override {}
 
   void Convert(base::RefCountedMemory* pdf_data,
                const PdfRenderSettings& conversion_settings,
@@ -66,7 +66,7 @@
 
 }  // namespace
 
-IN_PROC_BROWSER_TEST_F(PDFToPWGRasterBrowserTest, TestFailure) {
+IN_PROC_BROWSER_TEST_F(PdfToPwgRasterBrowserTest, TestFailure) {
   scoped_refptr<base::RefCountedStaticMemory> bad_pdf_data =
       base::MakeRefCounted<base::RefCountedStaticMemory>("0123456789", 10);
   base::FilePath temp_file;
@@ -74,7 +74,7 @@
           /*expect_success=*/false, &temp_file);
 }
 
-IN_PROC_BROWSER_TEST_F(PDFToPWGRasterBrowserTest, TestSuccess) {
+IN_PROC_BROWSER_TEST_F(PdfToPwgRasterBrowserTest, TestSuccess) {
   base::ScopedAllowBlockingForTesting allow_blocking;
 
   base::FilePath test_data_dir;
diff --git a/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc b/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc
index 7ebfcede..fec54fa5 100644
--- a/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc
+++ b/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc
@@ -44,6 +44,7 @@
 #include "chrome/browser/plugins/plugin_prefs_factory.h"
 #include "chrome/browser/policy/cloud/policy_header_service_factory.h"
 #include "chrome/browser/policy/cloud/user_cloud_policy_invalidator_factory.h"
+#include "chrome/browser/policy/policy_helpers.h"
 #include "chrome/browser/policy/profile_policy_connector_factory.h"
 #include "chrome/browser/policy/schema_registry_service_factory.h"
 #include "chrome/browser/predictors/autocomplete_action_predictor_factory.h"
@@ -80,6 +81,7 @@
 #include "chrome/browser/web_data_service_factory.h"
 #include "chrome/common/features.h"
 #include "components/feature_engagement/features.h"
+#include "components/policy/content/policy_blacklist_navigation_throttle.h"
 #include "components/spellcheck/spellcheck_build_features.h"
 #include "extensions/features/features.h"
 #include "ppapi/features/features.h"
@@ -333,6 +335,8 @@
   prerender::PrerenderMessageFilter::EnsureShutdownNotifierFactoryBuilt();
   ProfileSyncServiceFactory::GetInstance();
   ProtocolHandlerRegistryFactory::GetInstance();
+  PolicyBlacklistFactory::GetInstance()->SetBlacklistOverride(
+      base::BindRepeating(policy::OverrideBlacklistForURL));
 #if defined(OS_ANDROID)
   SearchPermissionsService::Factory::GetInstance();
 #endif
diff --git a/chrome/browser/profiles/profile_io_data.cc b/chrome/browser/profiles/profile_io_data.cc
index d7ccd7a5c..49f919a9 100644
--- a/chrome/browser/profiles/profile_io_data.cc
+++ b/chrome/browser/profiles/profile_io_data.cc
@@ -64,7 +64,6 @@
 #include "components/metrics/metrics_pref_names.h"
 #include "components/metrics/metrics_service.h"
 #include "components/net_log/chrome_net_log.h"
-#include "components/policy/core/browser/url_blacklist_manager.h"
 #include "components/policy/core/common/cloud/policy_header_io_helper.h"
 #include "components/policy/core/common/cloud/policy_header_service.h"
 #include "components/policy/core/common/cloud/user_cloud_policy_manager.h"
@@ -556,17 +555,6 @@
         policy::PolicyCertServiceFactory::CreateForProfile(profile);
   }
 #endif
-  // The URLBlacklistManager has to be created on the UI thread to register
-  // observers of |pref_service|, and it also has to clean up on
-  // ShutdownOnUIThread to release these observers on the right thread.
-  // Don't pass it in |profile_params_| to make sure it is correctly cleaned up,
-  // in particular when this ProfileIOData isn't |initialized_| during deletion.
-  scoped_refptr<base::SequencedTaskRunner> background_task_runner =
-      base::CreateSequencedTaskRunnerWithTraits(
-          {base::MayBlock(), base::TaskPriority::BACKGROUND});
-  url_blacklist_manager_.reset(new policy::URLBlacklistManager(
-      pref_service, background_task_runner, io_task_runner,
-      base::Bind(policy::OverrideBlacklistForURL)));
 
   // The CTPolicyManager shares the same constraints of needing to be cleaned
   // up on the UI thread.
@@ -1094,8 +1082,6 @@
   }
 #endif
 
-  chrome_network_delegate->set_url_blacklist_manager(
-      url_blacklist_manager_.get());
   chrome_network_delegate->set_profile(profile_params_->profile);
   chrome_network_delegate->set_profile_path(profile_params_->path);
   chrome_network_delegate->set_cookie_settings(
@@ -1446,8 +1432,6 @@
   enable_metrics_.Destroy();
   safe_browsing_enabled_.Destroy();
   network_prediction_options_.Destroy();
-  if (url_blacklist_manager_)
-    url_blacklist_manager_->ShutdownOnUIThread();
   if (ct_policy_manager_)
     ct_policy_manager_->Shutdown();
   if (chrome_http_user_agent_settings_)
@@ -1505,8 +1489,3 @@
   DCHECK(!cookie_settings_.get());
   cookie_settings_ = cookie_settings;
 }
-
-policy::URLBlacklist::URLBlacklistState ProfileIOData::GetURLBlacklistState(
-    const GURL& url) const {
-  return url_blacklist_manager_->GetURLBlacklistState(url);
-}
diff --git a/chrome/browser/profiles/profile_io_data.h b/chrome/browser/profiles/profile_io_data.h
index 6fc8cd3..a8d52e05 100644
--- a/chrome/browser/profiles/profile_io_data.h
+++ b/chrome/browser/profiles/profile_io_data.h
@@ -25,7 +25,6 @@
 #include "chrome/browser/profiles/storage_partition_descriptor.h"
 #include "chrome/common/features.h"
 #include "components/content_settings/core/common/content_settings_types.h"
-#include "components/policy/core/browser/url_blacklist_manager.h"
 #include "components/prefs/pref_member.h"
 #include "content/public/browser/content_browser_client.h"
 #include "content/public/browser/resource_context.h"
@@ -92,7 +91,6 @@
 namespace policy {
 class PolicyCertVerifier;
 class PolicyHeaderIOHelper;
-class URLBlacklistManager;
 }  // namespace policy
 
 namespace previews {
@@ -246,11 +244,6 @@
     return previews_io_data_.get();
   }
 
-  // This function is to be used to check if the |url| is defined in
-  // blacklist or whitelist policy.
-  virtual policy::URLBlacklist::URLBlacklistState GetURLBlacklistState(
-      const GURL& url) const;
-
   // Returns the predictor service for this Profile. Returns nullptr if there is
   // no Predictor, as is the case with OffTheRecord profiles.
   virtual chrome_browser_net::Predictor* GetPredictor();
@@ -581,7 +574,6 @@
   BooleanPrefMember enable_metrics_;
 
   // Pointed to by NetworkDelegate.
-  mutable std::unique_ptr<policy::URLBlacklistManager> url_blacklist_manager_;
   mutable std::unique_ptr<policy::PolicyHeaderIOHelper> policy_header_helper_;
 
   // Pointed to by URLRequestContext.
diff --git a/chrome/browser/profiling_host/background_profiling_triggers_unittest.cc b/chrome/browser/profiling_host/background_profiling_triggers_unittest.cc
index 1fcece9f..128a3561 100644
--- a/chrome/browser/profiling_host/background_profiling_triggers_unittest.cc
+++ b/chrome/browser/profiling_host/background_profiling_triggers_unittest.cc
@@ -39,7 +39,7 @@
   std::vector<memory_instrumentation::mojom::VmRegionPtr> vm_regions;
   return memory_instrumentation::mojom::OSMemDump::New(
       resident_set_kb, private_footprint_kb, shared_footprint_kb,
-      std::move(vm_regions));
+      std::move(vm_regions), 0);
 }
 
 void PopulateMetrics(GlobalMemoryDumpPtr* global_dump,
diff --git a/chrome/browser/profiling_host/profiling_process_host.cc b/chrome/browser/profiling_host/profiling_process_host.cc
index cad494a7..50980bd2 100644
--- a/chrome/browser/profiling_host/profiling_process_host.cc
+++ b/chrome/browser/profiling_host/profiling_process_host.cc
@@ -322,10 +322,17 @@
 }
 
 void ProfilingProcessHost::DumpProcessFinishedUIThread() {
-  if (dump_process_for_tracing_callback_) {
-    std::move(dump_process_for_tracing_callback_).Run();
-    dump_process_for_tracing_callback_.Reset();
-  }
+  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
+  heap_dump_has_been_added_ = true;
+  if (minimum_time_has_elapsed_ && !finish_tracing_callback_.is_null())
+    std::move(finish_tracing_callback_).Run();
+}
+
+void ProfilingProcessHost::OnMinimumTimeHasElapsed() {
+  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
+  minimum_time_has_elapsed_ = true;
+  if (heap_dump_has_been_added_ && !finish_tracing_callback_.is_null())
+    std::move(finish_tracing_callback_).Run();
 }
 
 void ProfilingProcessHost::AddClientToProfilingService(
@@ -545,19 +552,24 @@
           &content::TracingController::StopTracing),
       base::Unretained(content::TracingController::GetInstance()), sink);
 
+  // There is no race condition between setting
+  // |finish_tracing_callback_| and starting tracing, since
+  // the callback is only ever accessed on the UI thread.
+  DCHECK(!finish_tracing_callback_);
+  finish_tracing_callback_ = std::move(stop_tracing_closure);
+
+  heap_dump_has_been_added_ = false;
   if (stop_immediately_after_heap_dump_for_tests) {
-    // There is no race condition between setting
-    // |dump_process_for_tracing_callback_| and starting tracing, since running
-    // the callback is an asynchronous task executed on the UI thread.
-    DCHECK(!dump_process_for_tracing_callback_);
-    dump_process_for_tracing_callback_ = std::move(stop_tracing_closure);
+    minimum_time_has_elapsed_ = true;
   } else {
-    // Wait 30 seconds, then end the trace. 10 seconds has been observed to not
-    // be sufficient time for the profiling service to dump its data to the
-    // trace.
+    minimum_time_has_elapsed_ = false;
+
+    // Give the MDPs 10 seconds to emit their memory dumps to the trace.
     base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
-        FROM_HERE, std::move(stop_tracing_closure),
-        base::TimeDelta::FromSeconds(30));
+        FROM_HERE,
+        base::BindOnce(&ProfilingProcessHost::OnMinimumTimeHasElapsed,
+                       base::Unretained(this)),
+        base::TimeDelta::FromSeconds(10));
   }
 }
 
diff --git a/chrome/browser/profiling_host/profiling_process_host.h b/chrome/browser/profiling_host/profiling_process_host.h
index ba62f12..4f902833 100644
--- a/chrome/browser/profiling_host/profiling_process_host.h
+++ b/chrome/browser/profiling_host/profiling_process_host.h
@@ -191,6 +191,10 @@
   // Called on the UI thread after the heap dump has been added to the trace.
   void DumpProcessFinishedUIThread();
 
+  // Must be called on the UI thread.
+  // Called after the MDPs have been given time to emit memory dumps.
+  void OnMinimumTimeHasElapsed();
+
   // Sends the end of the data pipe to the profiling service.
   void AddClientToProfilingService(profiling::mojom::ProfilingClientPtr client,
                                    base::ProcessId pid,
@@ -264,9 +268,10 @@
   // a renderer process if one is already not going.
   bool always_sample_for_tests_;
 
-  // Only used for testing. Must only ever be used from the UI thread. Will be
-  // called after the profiling process dumps heaps into the trace log.
-  base::OnceClosure dump_process_for_tracing_callback_;
+  // Must only ever be used from the UI thread. Will be called after the
+  // profiling process dumps heaps into the trace log and MDPs have been given
+  // time to do the same.
+  base::OnceClosure finish_tracing_callback_;
 
   // True if the instance is attempting to take a trace to upload to the crash
   // servers. Pruning of small allocations is always enabled for these traces.
@@ -275,6 +280,11 @@
   // Guards |taking_trace_for_upload_|.
   base::Lock taking_trace_for_upload_lock_;
 
+  // If the instance has started a trace, the trace should be stopped when both
+  // members become true. Both members must only be accessed on the UI thread.
+  bool minimum_time_has_elapsed_ = false;
+  bool heap_dump_has_been_added_ = false;
+
   DISALLOW_COPY_AND_ASSIGN(ProfilingProcessHost);
 };
 
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 6cb4944..a0bad97 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
@@ -392,6 +392,8 @@
    * @return {boolean} True if the default action should be performed.
    */
   onMouseUp_: function(evt) {
+    if (!this.trackingMouse_)
+      return false;
     this.onMouseMove_(evt);
     this.trackingMouse_ = false;
 
diff --git a/chrome/browser/resources/interventions_internals/index.css b/chrome/browser/resources/interventions_internals/index.css
index bb04a5b0..b06a5b42 100644
--- a/chrome/browser/resources/interventions_internals/index.css
+++ b/chrome/browser/resources/interventions_internals/index.css
@@ -116,9 +116,8 @@
 }
 
 table {
-  border-collapse: separate;
+  border: 0;
   font-size: 90%;
-  margin-top: 10px;
   max-height: 100px;
   table-layout: fixed;
   width: 100%;
@@ -129,9 +128,10 @@
 }
 
 td {
-  border: 1px solid white;
+  border: 0;
   padding: 10px;
   text-align: left;
+  vertical-align: middle;
 }
 
 tr:nth-child(odd) td {
@@ -153,6 +153,7 @@
 
 td.log-description {
   font-size: 80%;
+  vertical-align: center;
 }
 
 td.log-url {
@@ -200,6 +201,56 @@
   position: absolute;
 }
 
+.expansion-row {
+  background: transparent;
+  border: 0;
+  margin-left: 20px;
+  padding: 0 0 0 15px;
+  width: 80%;
+}
+
+tr.expansion-row td {
+  background-color: silver;
+  border: 0;
+}
+
+tr.expansion-row td:nth-child(odd) {
+  background-color: silver;
+  border: 0;
+  padding: 0;
+}
+
+.hide {
+  display: none;
+}
+
+.expansion-logs-table {
+  border: 0;
+  border-spacing: 0;
+  color: black;
+}
+
+.expansion-logs-table tr {
+  color: black;
+}
+
+.expansion-logs-table tr:nth-child(odd) td {
+  background: rgb(240,248,255);
+  color: black;
+  padding: 10px;
+}
+
+.expansion-logs-table tr:nth-child(even) td {
+  background: rgb(220, 228, 235);
+  color: black;
+  padding: 10px;
+}
+
+.expansion-logs-table td {
+  background: silver;
+  color: black;
+}
+
 @media(min-device-width: 600px) {
   body {
     font-size: 85%;
@@ -261,6 +312,31 @@
   }
 }
 
+.more-details-button {
+  background: transparent;
+  border: 0;
+  float: right;
+  vertical-align: center;
+}
+
+i {
+  border: solid black;
+  border-width: 0 3px 3px 0;
+  display: inline-block;
+  padding: 3px;
+  vertical-align: center;
+}
+
+.down {
+  -webkit-transform: rotate(45deg);
+  transform: rotate(45deg);
+}
+
+.up {
+  -webkit-transform: rotate(-135deg);
+  transform: rotate(-135deg);
+}
+
 .error-header {
   font-size: 150%;
   font-weight: bold;
diff --git a/chrome/browser/resources/interventions_internals/index.js b/chrome/browser/resources/interventions_internals/index.js
index 39304a9..40a4b9b6a 100644
--- a/chrome/browser/resources/interventions_internals/index.js
+++ b/chrome/browser/resources/interventions_internals/index.js
@@ -9,6 +9,8 @@
 const IGNORE_BLACKLIST_MESSAGE = 'Blacklist decisions are ignored.';
 const URL_THRESHOLD = 40;  // Maximum URL length
 
+window.logTableMap = {};
+
 /**
  * Convert milliseconds to human readable date/time format.
  * The return format will be "MM/dd/YYYY hh:mm:ss.sss"
@@ -29,6 +31,145 @@
 }
 
 /**
+ * Append a button to |element|, so that when the button is clicked, the
+ * detailed logs table associated with |pageId| will be shown/hidden.
+ * @param {!HTMLElement} element The element that the button will be added to.
+ * @param {number} pageId Used to locate the ID of the logs table row.
+ */
+function addMoreDetailsButton(element, pageId) {
+  let moreDetailsButton = document.createElement('button');
+  moreDetailsButton.setAttribute('class', 'more-details-button');
+  element.appendChild(moreDetailsButton);
+
+  let icon = document.createElement('i');
+  icon.setAttribute('class', 'arrow down');
+  moreDetailsButton.appendChild(icon);
+
+  moreDetailsButton.addEventListener('click', () => {
+    let expansionRow = $('expansion-row-' + pageId);
+    expansionRow.className = (expansionRow.className.includes('hide')) ?
+        expansionRow.className.replace('hide', 'show') :
+        expansionRow.className.replace('show', 'hide');
+
+    icon.className = (icon.className.includes('down')) ?
+        icon.className.replace('down', 'up') :
+        icon.className.replace('up', 'down');
+  });
+}
+
+/**
+ * Helper method to move a row to the top of a html table, below the header
+ * row.
+ * @param {!HTMLElement} row The row to move.
+ * @param {!HTMLElement} table The table to move.
+ */
+function pushRowToTopOfLogsTable(row, table) {
+  let newRow = table.insertRow(1);
+  newRow.className = row.className;
+  newRow.id = row.id;
+  newRow.innerHTML = row.innerHTML;
+  row.remove();
+}
+
+/**
+ * Helper method to move a group of messages to the top of the Logs Table,
+ * including the expansion row corresponding to the |pageId|.
+ *
+ * @param {number} pageId The key of |logTableMap| of the moving row.
+ */
+function pushMessagesToTopOfLogsTable(pageId) {
+  let logsTable = $('message-logs-table');
+  let currentMessageRow = window.logTableMap[pageId];
+
+  // Moving empty row.
+  let emptyRow = logsTable.rows[currentMessageRow.rowIndex + 2];
+  pushRowToTopOfLogsTable(emptyRow, logsTable);
+
+  // Moving expansion row.
+  let expansionRow = logsTable.rows[currentMessageRow.rowIndex + 1];
+  pushRowToTopOfLogsTable(expansionRow, logsTable);
+
+  // Moving the original row.
+  pushRowToTopOfLogsTable(currentMessageRow, logsTable);
+  window.logTableMap[pageId] = logsTable.rows[1];
+}
+
+/**
+ * Update the |pageId| log message group. Copy the main row that contains the
+ * most updated log message of the group to the expansion row, and update the
+ * current main row with new info.
+ *
+ * @param {number!} time Millisecond since Unix Epoch representation of time.
+ * @param {string!} type The message event type.
+ * @param {string!} description The event message description.
+ * @param {string} url The URL associated with the event.
+ */
+function updateTableRowByPageId(time, type, description, url, pageId) {
+  assert(pageId > 0);
+  assert(window.logTableMap[pageId]);
+  pushMessagesToTopOfLogsTable(pageId);
+
+  let currentRow = window.logTableMap[pageId];
+  let expansionRow = $('expansion-row-' + pageId);
+  let newRow = expansionRow.querySelector('.expansion-logs-table').insertRow(0);
+  newRow.setAttribute('class', 'expand-log-message');
+
+  // Copying data from previous row, to the first row of the expansion table.
+  currentRow.querySelectorAll('td').forEach((column) => {
+    let cell = column.cloneNode(true);
+    let expandButton = cell.querySelector('.more-details-button');
+    if (expandButton) {
+      expandButton.remove();
+    }
+    newRow.appendChild(cell);
+  });
+
+  // Update current row with new data.
+  currentRow.querySelector('.log-time').textContent = getTimeFormat(time);
+  currentRow.querySelector('.log-type').textContent = type;
+  let descriptionTd = currentRow.querySelector('.log-description');
+  descriptionTd.textContent = description;
+  addMoreDetailsButton(descriptionTd, pageId);
+
+  let urlTd = currentRow.querySelector('.log-url');
+  if (urlTd) {
+    urlTd.remove();
+    if (url.length > 0) {
+      urlTd = createUrlElement(url);
+      urlTd.setAttribute('class', 'log-url');
+      currentRow.appendChild(urlTd);
+    }
+  }
+}
+
+/**
+ * Create an new row for expansion table below the |mainRow|.
+ *
+ * @param {!HTMLElement} mainRow The row with the most updated log event of the
+ * group.
+ * @param {number} pageId The ID associated with the group event.
+ */
+function createExpansionRow(mainRow, pageId) {
+  let logsTable = $('message-logs-table');
+  let expansionRow = logsTable.insertRow(mainRow.rowIndex + 1);
+  expansionRow.setAttribute('class', 'expansion-row hide');
+  expansionRow.setAttribute('id', 'expansion-row-' + pageId);
+  window.logTableMap[pageId] = mainRow;
+
+  let tdNode = document.createElement('td');
+  tdNode.setAttribute('colspan', '4');
+  expansionRow.appendChild(tdNode);
+
+  let expansionTable = document.createElement('table');
+  expansionTable.setAttribute('class', 'expansion-logs-table');
+  tdNode.appendChild(expansionTable);
+
+  // Insert row so that the table even/odd coloring remains the same.
+  let hiddenRow = logsTable.insertRow(expansionRow.rowIndex + 1);
+  hiddenRow.setAttribute('class', 'hide');
+}
+
+/**
  * Insert a log message row to the top of the log message table.
  *
  * @param {number!} time Millisecond since Unix Epoch representation of time.
@@ -36,11 +177,22 @@
  * @param {string!} description The event message description.
  * @param {string} url The URL associated with the event.
  */
-function insertMessageRowToMessageLogTable(time, type, description, url) {
+function insertMessageRowToMessageLogTable(
+    time, type, description, url, pageId) {
+  assert(pageId >= 0);
+  if (pageId > 0 && window.logTableMap[pageId]) {
+    updateTableRowByPageId(time, type, description, url, pageId);
+    return;
+  }
+
   let tableRow =
       $('message-logs-table').insertRow(1);  // Index 0 belongs to header row.
   tableRow.setAttribute('class', 'log-message');
 
+  if (pageId > 0) {  // If the new message will be grouped.
+    createExpansionRow(tableRow, pageId);
+  }
+
   let timeTd = document.createElement('td');
   timeTd.textContent = getTimeFormat(time);
   timeTd.setAttribute('class', 'log-time');
@@ -117,16 +269,19 @@
 function setupLogSearch() {
   $('log-search-bar').addEventListener('keyup', () => {
     let keyword = $('log-search-bar').value.toUpperCase();
-    let rows = document.querySelectorAll('.log-message');
+    let rows = $('message-logs-table').rows;
 
-    rows.forEach((row) => {
+    for (let i = 1; i < rows.length; i++) {
+      let row = rows[i];
       let found = KEY_COLUMNS.some((column) => {
-        return (row.querySelector('.' + column)
-                    .textContent.toUpperCase()
-                    .includes(keyword));
+        let cell = row.querySelector('.' + column);
+        if (!cell) {
+          return keyword == '';
+        }
+        return cell.textContent.toUpperCase().includes(keyword);
       });
       row.style.display = found ? '' : 'none';
-    });
+    }
   });
 }
 
@@ -229,7 +384,7 @@
    */
   logNewMessage: function(log) {
     insertMessageRowToMessageLogTable(
-        log.time, log.type, log.description, log.url.url);
+        log.time, log.type, log.description, log.url.url, log.pageId);
   },
 
   /**
@@ -290,6 +445,10 @@
 
     // Remove log message from logs table.
     removeAllLogMessagesRows();
+
+    // Log event message.
+    insertMessageRowToMessageLogTable(
+        time, 'Blacklist', 'Blacklist Cleared', '' /* URL */, 0 /* pageId */);
   },
 
   /**
@@ -339,7 +498,8 @@
 
     // Insert ECT changed message to message-logs-table.
     insertMessageRowToMessageLogTable(
-        now, 'ECT Changed', 'Effective Connection Type changed to ' + type, '');
+        now, 'ECT Changed', 'Effective Connection Type changed to ' + type,
+        '' /* URL */, 0 /* pageId */);
   },
 };
 
diff --git a/chrome/browser/resources/md_extensions/item.js b/chrome/browser/resources/md_extensions/item.js
index 37a95fc..7b76628 100644
--- a/chrome/browser/resources/md_extensions/item.js
+++ b/chrome/browser/resources/md_extensions/item.js
@@ -44,7 +44,10 @@
      */
     inspectItemView(id, view) {}
 
-    /** @param {string} id */
+    /**
+     * @param {string} id
+     * @return {!Promise}
+     */
     reloadItem(id) {}
 
     /** @param {string} id */
@@ -164,7 +167,9 @@
 
     /** @private */
     onReloadTap_: function() {
-      this.delegate.reloadItem(this.data.id);
+      this.delegate.reloadItem(this.data.id).catch(loadError => {
+        this.fire('load-error', loadError);
+      });
     },
 
     /** @private */
diff --git a/chrome/browser/resources/md_extensions/manager.html b/chrome/browser/resources/md_extensions/manager.html
index 17ef796..35ef151 100644
--- a/chrome/browser/resources/md_extensions/manager.html
+++ b/chrome/browser/resources/md_extensions/manager.html
@@ -79,7 +79,8 @@
           delegate="[[delegate]]" in-dev-mode="[[inDevMode]]"
           filter="[[filter]]" hidden$="[[!didInitPage_]]" slot="view"
           apps="[[apps_]]" extensions="[[extensions_]]"
-          on-show-install-warnings="onShowInstallWarnings_">
+          on-show-install-warnings="onShowInstallWarnings_"
+          on-load-error="onLoadError_">
       </extensions-item-list>
       <template id="details-view" is="cr-lazy-render">
         <extensions-detail-view delegate="[[delegate]]" slot="view"
diff --git a/chrome/browser/resources/md_extensions/service.js b/chrome/browser/resources/md_extensions/service.js
index f265b6c..2ad14ee 100644
--- a/chrome/browser/resources/md_extensions/service.js
+++ b/chrome/browser/resources/md_extensions/service.js
@@ -176,7 +176,18 @@
 
     /** @override */
     reloadItem(id) {
-      chrome.developerPrivate.reload(id, {failQuietly: false});
+      return new Promise(function(resolve, reject) {
+        chrome.developerPrivate.reload(
+            id, {failQuietly: true, populateErrorForUnpacked: true},
+            (loadError) => {
+              if (loadError) {
+                reject(loadError);
+                return;
+              }
+
+              resolve();
+            });
+      });
     }
 
     /** @override */
diff --git a/chrome/browser/resources/settings/device_page/night_light_slider.html b/chrome/browser/resources/settings/device_page/night_light_slider.html
index 84bd90b..641129f 100644
--- a/chrome/browser/resources/settings/device_page/night_light_slider.html
+++ b/chrome/browser/resources/settings/device_page/night_light_slider.html
@@ -9,6 +9,7 @@
     <style>
       :host {
         cursor: default;
+        font-weight: 500;
         text-align: center;
         user-select: none;
       }
diff --git a/chrome/browser/safe_browsing/download_protection/download_protection_service.cc b/chrome/browser/safe_browsing/download_protection/download_protection_service.cc
index 3c11fb6..eaa2557 100644
--- a/chrome/browser/safe_browsing/download_protection/download_protection_service.cc
+++ b/chrome/browser/safe_browsing/download_protection/download_protection_service.cc
@@ -23,6 +23,7 @@
 #include "content/public/browser/browser_context.h"
 #include "content/public/browser/web_contents.h"
 #include "net/base/url_util.h"
+#include "net/cert/x509_util.h"
 
 using content::BrowserThread;
 namespace safe_browsing {
@@ -345,9 +346,8 @@
     paths_to_check.insert(ou_tokens[i]);
   }
 
-  std::string issuer_der;
-  net::X509Certificate::GetDEREncoded(issuer.os_cert_handle(), &issuer_der);
-  std::string hashed = base::SHA1HashString(issuer_der);
+  std::string hashed = base::SHA1HashString(std::string(
+      net::x509_util::CryptoBufferAsStringPiece(issuer.cert_buffer())));
   std::string issuer_fp = base::HexEncode(hashed.data(), hashed.size());
   for (std::set<std::string>::iterator it = paths_to_check.begin();
        it != paths_to_check.end(); ++it) {
diff --git a/chrome/browser/safe_browsing/download_protection/download_protection_service_unittest.cc b/chrome/browser/safe_browsing/download_protection/download_protection_service_unittest.cc
index 3761732..7ee00ae 100644
--- a/chrome/browser/safe_browsing/download_protection/download_protection_service_unittest.cc
+++ b/chrome/browser/safe_browsing/download_protection/download_protection_service_unittest.cc
@@ -56,6 +56,7 @@
 #include "content/public/test/web_contents_tester.h"
 #include "net/base/url_util.h"
 #include "net/cert/x509_certificate.h"
+#include "net/cert/x509_util.h"
 #include "net/http/http_status_code.h"
 #include "net/url_request/test_url_fetcher_factory.h"
 #include "net/url_request/url_fetcher_delegate.h"
@@ -849,9 +850,8 @@
   scoped_refptr<net::X509Certificate> test_cert(
       ReadTestCertificate("test_cn.pem"));
   ASSERT_TRUE(test_cert.get());
-  std::string test_cert_der;
-  net::X509Certificate::GetDEREncoded(test_cert->os_cert_handle(),
-                                      &test_cert_der);
+  std::string test_cert_der(
+      net::x509_util::CryptoBufferAsStringPiece(test_cert->cert_buffer()));
   EXPECT_CALL(*binary_feature_extractor_.get(), CheckSignature(tmp_path_, _))
       .WillRepeatedly(TrustSignature(test_cert_der));
   EXPECT_CALL(*sb_service_->mock_database_manager(),
@@ -2089,10 +2089,8 @@
   scoped_refptr<net::X509Certificate> issuer_cert(
       ReadTestCertificate("issuer.pem"));
   ASSERT_TRUE(issuer_cert.get());
-  std::string issuer_der;
-  net::X509Certificate::GetDEREncoded(issuer_cert->os_cert_handle(),
-                                      &issuer_der);
-  std::string hashed = base::SHA1HashString(issuer_der);
+  std::string hashed = base::SHA1HashString(std::string(
+      net::x509_util::CryptoBufferAsStringPiece(issuer_cert->cert_buffer())));
   std::string cert_base =
       "cert/" + base::HexEncode(hashed.data(), hashed.size());
 
diff --git a/chrome/browser/ssl/ssl_browsertest.cc b/chrome/browser/ssl/ssl_browsertest.cc
index efe89b7a..f63326a 100644
--- a/chrome/browser/ssl/ssl_browsertest.cc
+++ b/chrome/browser/ssl/ssl_browsertest.cc
@@ -126,6 +126,7 @@
 #include "net/cert/cert_status_flags.h"
 #include "net/cert/mock_cert_verifier.h"
 #include "net/cert/x509_certificate.h"
+#include "net/cert/x509_util.h"
 #include "net/dns/mock_host_resolver.h"
 #include "net/http/http_response_headers.h"
 #include "net/ssl/ssl_info.h"
@@ -374,13 +375,10 @@
 }
 
 // Returns the Sha256 hash of the SPKI of |cert|.
-net::HashValue GetSPKIHash(net::X509Certificate* cert) {
-  std::string der_data;
-  EXPECT_TRUE(
-      net::X509Certificate::GetDEREncoded(cert->os_cert_handle(), &der_data));
-  base::StringPiece der_bytes(der_data);
+net::HashValue GetSPKIHash(const CRYPTO_BUFFER* cert) {
   base::StringPiece spki_bytes;
-  EXPECT_TRUE(net::asn1::ExtractSPKIFromDERCert(der_bytes, &spki_bytes));
+  EXPECT_TRUE(net::asn1::ExtractSPKIFromDERCert(
+      net::x509_util::CryptoBufferAsStringPiece(cert), &spki_bytes));
   net::HashValue sha256(net::HASH_VALUE_SHA256);
   crypto::SHA256HashString(spki_bytes, sha256.data(), crypto::kSHA256Length);
   return sha256;
@@ -904,7 +902,7 @@
 };
 
 static std::string MakeCertSPKIFingerprint(net::X509Certificate* cert) {
-  net::HashValue hash = GetSPKIHash(cert);
+  net::HashValue hash = GetSPKIHash(cert->cert_buffer());
   std::string hash_base64;
   base::Base64Encode(
       base::StringPiece(reinterpret_cast<const char*>(hash.data()),
@@ -5303,7 +5301,7 @@
 
   // Mark the server's cert as a captive portal cert.
   const net::HashValue server_spki_hash =
-      GetSPKIHash(https_server_mismatched_.GetCertificate().get());
+      GetSPKIHash(https_server_mismatched_.GetCertificate()->cert_buffer());
   SSLErrorHandler::SetErrorAssistantProto(MakeCaptivePortalConfig(
       kLargeVersionId, std::set<std::string>{server_spki_hash.ToString()}));
   ASSERT_TRUE(SSLErrorHandler::GetErrorAssistantProtoVersionIdForTesting() > 0);
@@ -5344,7 +5342,7 @@
 
   // Mark the server's cert as a captive portal cert.
   const net::HashValue server_spki_hash =
-      GetSPKIHash(https_server_mismatched_.GetCertificate().get());
+      GetSPKIHash(https_server_mismatched_.GetCertificate()->cert_buffer());
   SSLErrorHandler::SetErrorAssistantProto(MakeCaptivePortalConfig(
       kLargeVersionId, std::set<std::string>{server_spki_hash.ToString()}));
   ASSERT_TRUE(SSLErrorHandler::GetErrorAssistantProtoVersionIdForTesting() > 0);
@@ -6230,14 +6228,11 @@
 
     // Collect the hashes of the leaf and intermediates.
     verify_result.public_key_hashes.push_back(
-        GetSPKIHash(verify_result.verified_cert.get()));
-    for (const net::X509Certificate::OSCertHandle& intermediate :
-         verify_result.verified_cert->GetIntermediateCertificates()) {
-      scoped_refptr<net::X509Certificate> intermediate_x509 =
-          net::X509Certificate::CreateFromHandle(
-              intermediate, net::X509Certificate::OSCertHandles());
+        GetSPKIHash(verify_result.verified_cert->cert_buffer()));
+    for (const auto& intermediate :
+         verify_result.verified_cert->intermediate_buffers()) {
       verify_result.public_key_hashes.push_back(
-          GetSPKIHash(intermediate_x509.get()));
+          GetSPKIHash(intermediate.get()));
     }
 
     mock_cert_verifier()->AddResultForCert(https_server_.GetCertificate().get(),
@@ -6452,15 +6447,11 @@
 
     // Collect the hashes of the leaf and intermediates.
     verify_result.public_key_hashes.push_back(
-        GetSPKIHash(verify_result.verified_cert.get()));
-    for (const net::X509Certificate::OSCertHandle& intermediate :
-         verify_result.verified_cert->GetIntermediateCertificates()) {
-      scoped_refptr<net::X509Certificate> intermediate_x509 =
-          net::X509Certificate::CreateFromHandle(
-              intermediate, net::X509Certificate::OSCertHandles());
-      ASSERT_TRUE(intermediate_x509);
+        GetSPKIHash(verify_result.verified_cert->cert_buffer()));
+    for (const auto& intermediate :
+         verify_result.verified_cert->intermediate_buffers()) {
       verify_result.public_key_hashes.push_back(
-          GetSPKIHash(intermediate_x509.get()));
+          GetSPKIHash(intermediate.get()));
     }
 
     mock_cert_verifier()->AddResultForCert(https_server_.GetCertificate().get(),
diff --git a/chrome/browser/ssl/ssl_error_handler.cc b/chrome/browser/ssl/ssl_error_handler.cc
index 99139ef..11f6b158 100644
--- a/chrome/browser/ssl/ssl_error_handler.cc
+++ b/chrome/browser/ssl/ssl_error_handler.cc
@@ -101,10 +101,9 @@
       {0xB6, 0xFE, 0x91, 0x51, 0x40, 0x2B, 0xAD, 0x1C, 0x06, 0xD7, 0xE6,
        0x6D, 0xB6, 0x7A, 0x26, 0xAA, 0x73, 0x56, 0xF2, 0xE6, 0xC6, 0x44,
        0xDB, 0xCF, 0x9F, 0x98, 0x96, 0x8F, 0xF6, 0x32, 0xE1, 0xB7}};
-  for (const net::X509Certificate::OSCertHandle& intermediate :
-       cert->GetIntermediateCertificates()) {
+  for (const auto& intermediate : cert->intermediate_buffers()) {
     net::SHA256HashValue hash =
-        net::X509Certificate::CalculateFingerprint256(intermediate);
+        net::X509Certificate::CalculateFingerprint256(intermediate.get());
     if (hash == kSuperfishFingerprint) {
       return true;
     }
diff --git a/chrome/browser/thumbnails/thumbnail_list_source.cc b/chrome/browser/thumbnails/thumbnail_list_source.cc
index 67357f1..3c3431cc 100644
--- a/chrome/browser/thumbnails/thumbnail_list_source.cc
+++ b/chrome/browser/thumbnails/thumbnail_list_source.cc
@@ -12,7 +12,7 @@
 #include "base/bind.h"
 #include "base/logging.h"
 #include "base/memory/ref_counted_memory.h"
-#include "base/strings/string_util.h"
+#include "base/strings/strcat.h"
 #include "chrome/browser/history/top_sites_factory.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/search/instant_io_context.h"
@@ -172,6 +172,6 @@
   }
   out.push_back(kHtmlFooter);
 
-  std::string out_html = base::JoinString(out, base::StringPiece());
+  std::string out_html = base::StrCat(out);
   callback.Run(base::RefCountedString::TakeString(&out_html));
 }
diff --git a/chrome/browser/ui/android/page_info/certificate_chain_helper.cc b/chrome/browser/ui/android/page_info/certificate_chain_helper.cc
index eccc1372..a7dfa26 100644
--- a/chrome/browser/ui/android/page_info/certificate_chain_helper.cc
+++ b/chrome/browser/ui/android/page_info/certificate_chain_helper.cc
@@ -33,11 +33,13 @@
     return ScopedJavaLocalRef<jobjectArray>();
 
   std::vector<std::string> cert_chain;
-  cert_chain.reserve(1 + cert->GetIntermediateCertificates().size());
+  cert_chain.reserve(1 + cert->intermediate_buffers().size());
   cert_chain.emplace_back(
-      net::x509_util::CryptoBufferAsStringPiece(cert->os_cert_handle()));
-  for (auto* handle : cert->GetIntermediateCertificates())
-    cert_chain.emplace_back(net::x509_util::CryptoBufferAsStringPiece(handle));
+      net::x509_util::CryptoBufferAsStringPiece(cert->cert_buffer()));
+  for (const auto& handle : cert->intermediate_buffers()) {
+    cert_chain.emplace_back(
+        net::x509_util::CryptoBufferAsStringPiece(handle.get()));
+  }
 
   return base::android::ToJavaArrayOfByteArray(env, cert_chain);
 }
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 44745589..6dfb547 100644
--- a/chrome/browser/ui/app_list/app_list_syncable_service.cc
+++ b/chrome/browser/ui/app_list/app_list_syncable_service.cc
@@ -349,8 +349,6 @@
   oem_folder_name_ =
       l10n_util::GetStringUTF8(IDS_APP_LIST_OEM_DEFAULT_FOLDER_NAME);
 
-  model_->SetFoldersEnabled(true);
-
   if (IsExtensionServiceReady()) {
     BuildModel();
   } else {
diff --git a/chrome/browser/ui/ash/window_positioner_unittest.cc b/chrome/browser/ui/ash/window_positioner_unittest.cc
index 59287a18..9e40384a 100644
--- a/chrome/browser/ui/ash/window_positioner_unittest.cc
+++ b/chrome/browser/ui/ash/window_positioner_unittest.cc
@@ -53,7 +53,7 @@
 };
 
 WindowPositionerTest::WindowPositionerTest()
-    : grid_size_(WindowPositioner::kMinimumWindowOffset) {}
+    : grid_size_(WindowPositioner::kPopupGridSize) {}
 
 void WindowPositionerTest::SetUp() {
   AshTestBase::SetUp();
@@ -103,75 +103,75 @@
   window()->SetBounds(work_area);
   window()->Show();
 
-  gfx::Rect popup_position(0, 0, 200, 200);
+  gfx::Size popup_size(200, 200);
   // Check that it gets cascaded.
-  gfx::Rect cascade_1 = window_positioner()->GetPopupPosition(popup_position);
+  gfx::Rect cascade_1 = window_positioner()->GetPopupPosition(popup_size);
   EXPECT_EQ(gfx::Rect(work_area.x() + grid_size_, work_area.y() + grid_size_,
-                      popup_position.width(), popup_position.height()),
+                      popup_size.width(), popup_size.height()),
             cascade_1);
 
-  gfx::Rect cascade_2 = window_positioner()->GetPopupPosition(popup_position);
+  gfx::Rect cascade_2 = window_positioner()->GetPopupPosition(popup_size);
   EXPECT_EQ(
       gfx::Rect(work_area.x() + 2 * grid_size_, work_area.y() + 2 * grid_size_,
-                popup_position.width(), popup_position.height()),
+                popup_size.width(), popup_size.height()),
       cascade_2);
 
   // Check that if there is even only a pixel missing it will cascade.
   window()->SetBounds(
-      gfx::Rect(work_area.x() + popup_position.width() - 1,
-                work_area.y() + popup_position.height() - 1,
-                work_area.width() - 2 * (popup_position.width() - 1),
-                work_area.height() - 2 * (popup_position.height() - 1)));
+      gfx::Rect(work_area.x() + popup_size.width() - 1,
+                work_area.y() + popup_size.height() - 1,
+                work_area.width() - 2 * (popup_size.width() - 1),
+                work_area.height() - 2 * (popup_size.height() - 1)));
 
-  gfx::Rect cascade_3 = window_positioner()->GetPopupPosition(popup_position);
+  gfx::Rect cascade_3 = window_positioner()->GetPopupPosition(popup_size);
   EXPECT_EQ(
       gfx::Rect(work_area.x() + 3 * grid_size_, work_area.y() + 3 * grid_size_,
-                popup_position.width(), popup_position.height()),
+                popup_size.width(), popup_size.height()),
       cascade_3);
 
   // Check that we overflow into the next line when we do not fit anymore in Y.
-  gfx::Rect popup_position_4(
-      0, 0, 200, work_area.height() - (cascade_3.y() - work_area.y()));
-  gfx::Rect cascade_4 = window_positioner()->GetPopupPosition(popup_position_4);
+  gfx::Size popup_size_4(200,
+                         work_area.height() - (cascade_3.y() - work_area.y()));
+  gfx::Rect cascade_4 = window_positioner()->GetPopupPosition(popup_size_4);
   EXPECT_EQ(
       gfx::Rect(work_area.x() + 2 * grid_size_, work_area.y() + grid_size_,
-                popup_position_4.width(), popup_position_4.height()),
+                popup_size_4.width(), popup_size_4.height()),
       cascade_4);
 
   // Check that we overflow back to the first possible location if we overflow
   // to the end.
-  gfx::Rect popup_position_5(
-      0, 0, work_area.width() + 1 - (cascade_4.x() - work_area.x()),
+  gfx::Size popup_size_5(
+      work_area.width() + 1 - (cascade_4.x() - work_area.x()),
       work_area.height() - (2 * grid_size_ - work_area.y()));
-  gfx::Rect cascade_5 = window_positioner()->GetPopupPosition(popup_position_5);
+  gfx::Rect cascade_5 = window_positioner()->GetPopupPosition(popup_size_5);
   EXPECT_EQ(gfx::Rect(work_area.x() + grid_size_, work_area.y() + grid_size_,
-                      popup_position_5.width(), popup_position_5.height()),
+                      popup_size_5.width(), popup_size_5.height()),
             cascade_5);
 }
 
 TEST_F(WindowPositionerTest, filling) {
   const gfx::Rect work_area =
       display::Screen::GetScreen()->GetPrimaryDisplay().work_area();
-  gfx::Rect popup_position(0, 0, 256, 128);
+  gfx::Size popup_size(256, 128);
   // Leave space on the left and the right and see if we fill top to bottom.
   window()->SetBounds(gfx::Rect(
-      work_area.x() + popup_position.width(), work_area.y(),
-      work_area.width() - 2 * popup_position.width(), work_area.height()));
+      work_area.x() + popup_size.width(), work_area.y(),
+      work_area.width() - 2 * popup_size.width(), work_area.height()));
   window()->Show();
   // Check that we are positioned in the top left corner.
-  gfx::Rect top_left = window_positioner()->GetPopupPosition(popup_position);
-  EXPECT_EQ(gfx::Rect(work_area.x(), work_area.y(), popup_position.width(),
-                      popup_position.height()),
+  gfx::Rect top_left = window_positioner()->GetPopupPosition(popup_size);
+  EXPECT_EQ(gfx::Rect(work_area.x(), work_area.y(), popup_size.width(),
+                      popup_size.height()),
             top_left);
 
   // Now block the found location.
   popup()->SetBounds(top_left);
   popup()->Show();
-  gfx::Rect mid_left = window_positioner()->GetPopupPosition(popup_position);
+  gfx::Rect mid_left = window_positioner()->GetPopupPosition(popup_size);
   EXPECT_EQ(gfx::Rect(work_area.x(),
                       AlignToGridRoundDown(work_area.y() + top_left.height(),
                                            grid_size_),
-                      popup_position.width(), popup_position.height()),
+                      popup_size.width(), popup_size.height()),
             mid_left);
 
   // Block now everything so that we can only put the popup on the bottom
@@ -179,36 +179,33 @@
   // Note: We need to keep one "grid spacing free" if the window does not
   // fit into the grid (which is true for 200 height).`
   popup()->SetBounds(
-      gfx::Rect(work_area.x(), work_area.y(), popup_position.width(),
-                work_area.height() - popup_position.height() - grid_size_ + 1));
-  gfx::Rect bottom_left = window_positioner()->GetPopupPosition(popup_position);
-  EXPECT_EQ(
-      gfx::Rect(work_area.x(), work_area.bottom() - popup_position.height(),
-                popup_position.width(), popup_position.height()),
-      bottom_left);
+      gfx::Rect(work_area.x(), work_area.y(), popup_size.width(),
+                work_area.height() - popup_size.height() - grid_size_ + 1));
+  gfx::Rect bottom_left = window_positioner()->GetPopupPosition(popup_size);
+  EXPECT_EQ(gfx::Rect(work_area.x(), work_area.bottom() - popup_size.height(),
+                      popup_size.width(), popup_size.height()),
+            bottom_left);
 
   // Block now enough to force the right side.
-  popup()->SetBounds(
-      gfx::Rect(work_area.x(), work_area.y(), popup_position.width(),
-                work_area.height() - popup_position.height() + 1));
-  gfx::Rect top_right = window_positioner()->GetPopupPosition(popup_position);
-  EXPECT_EQ(
-      gfx::Rect(AlignToGridRoundDown(work_area.right() - popup_position.width(),
-                                     grid_size_),
-                work_area.y(), popup_position.width(), popup_position.height()),
-      top_right);
+  popup()->SetBounds(gfx::Rect(work_area.x(), work_area.y(), popup_size.width(),
+                               work_area.height() - popup_size.height() + 1));
+  gfx::Rect top_right = window_positioner()->GetPopupPosition(popup_size);
+  EXPECT_EQ(gfx::Rect(AlignToGridRoundDown(
+                          work_area.right() - popup_size.width(), grid_size_),
+                      work_area.y(), popup_size.width(), popup_size.height()),
+            top_right);
 }
 
 TEST_F(WindowPositionerTest, biggerThenBorder) {
   const gfx::Rect work_area =
       display::Screen::GetScreen()->GetPrimaryDisplay().work_area();
 
-  gfx::Rect pop_position(0, 0, work_area.width(), work_area.height());
+  gfx::Size popup_size(work_area.width(), work_area.height());
 
   // Check that the popup is placed full screen.
-  gfx::Rect full = window_positioner()->GetPopupPosition(pop_position);
-  EXPECT_EQ(gfx::Rect(work_area.x(), work_area.y(), pop_position.width(),
-                      pop_position.height()),
+  gfx::Rect full = window_positioner()->GetPopupPosition(popup_size);
+  EXPECT_EQ(gfx::Rect(work_area.x(), work_area.y(), popup_size.width(),
+                      popup_size.height()),
             full);
 }
 
diff --git a/chrome/browser/ui/browser_focus_uitest.cc b/chrome/browser/ui/browser_focus_uitest.cc
index 8178c11..8cac17b 100644
--- a/chrome/browser/ui/browser_focus_uitest.cc
+++ b/chrome/browser/ui/browser_focus_uitest.cc
@@ -673,8 +673,8 @@
   EXPECT_FALSE(IsViewFocused(VIEW_ID_OMNIBOX));
 }
 
-// Flaky on Mac (http://crbug.com/665296).
-#if defined(OS_MACOSX)
+// Flaky on Mac and ChromeOS (http://crbug.com/665296).
+#if defined(OS_MACOSX) || defined(OS_CHROMEOS)
 #define MAYBE_FocusOnNavigate DISABLED_FocusOnNavigate
 #else
 #define MAYBE_FocusOnNavigate FocusOnNavigate
diff --git a/chrome/browser/ui/libgtkui/BUILD.gn b/chrome/browser/ui/libgtkui/BUILD.gn
index de81b27e..3f93720 100644
--- a/chrome/browser/ui/libgtkui/BUILD.gn
+++ b/chrome/browser/ui/libgtkui/BUILD.gn
@@ -78,6 +78,14 @@
       configs += [ "//build/config/linux/gconf" ]
     }
 
+    if (use_gio) {
+      sources += [
+        "nav_button_layout_manager_gsettings.cc",
+        "nav_button_layout_manager_gsettings.h",
+      ]
+      configs += [ "//build/linux:gio_config" ]
+    }
+
     if (use_cups) {
       configs += [ "//printing:cups" ]
     }
diff --git a/chrome/browser/ui/libgtkui/gtk_ui.cc b/chrome/browser/ui/libgtkui/gtk_ui.cc
index bf37dd5c..27ad5a28 100644
--- a/chrome/browser/ui/libgtkui/gtk_ui.cc
+++ b/chrome/browser/ui/libgtkui/gtk_ui.cc
@@ -73,6 +73,10 @@
 #include "chrome/browser/ui/libgtkui/nav_button_provider_gtk3.h"  // nogncheck
 #endif
 
+#if defined(USE_GIO)
+#include "chrome/browser/ui/libgtkui/nav_button_layout_manager_gsettings.h"
+#endif
+
 #if BUILDFLAG(ENABLE_BASIC_PRINTING)
 #include "printing/printing_context_linux.h"
 #endif
@@ -281,10 +285,13 @@
   if (GtkVersionCheck(3, 14))
     return std::make_unique<NavButtonLayoutManagerGtk3>(gtk_ui);
 #endif
-#if defined(USE_GCONF)
+#if defined(USE_GIO)
+  return std::make_unique<NavButtonLayoutManagerGSettings>(gtk_ui);
+#elif defined(USE_GCONF)
   return std::make_unique<NavButtonLayoutManagerGconf>(gtk_ui);
-#endif
+#else
   return nullptr;
+#endif
 }
 
 // Returns a gfx::FontRenderParams corresponding to GTK's configuration.
diff --git a/chrome/browser/ui/libgtkui/nav_button_layout_manager_gsettings.cc b/chrome/browser/ui/libgtkui/nav_button_layout_manager_gsettings.cc
new file mode 100644
index 0000000..89914932
--- /dev/null
+++ b/chrome/browser/ui/libgtkui/nav_button_layout_manager_gsettings.cc
@@ -0,0 +1,119 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/ui/libgtkui/nav_button_layout_manager_gsettings.h"
+
+#include <gio/gio.h>
+
+#include "chrome/browser/ui/libgtkui/gtk_ui.h"
+#include "chrome/browser/ui/libgtkui/gtk_util.h"
+
+namespace {
+
+const char kGeneralPreferencesSchema[] = "org.gnome.desktop.wm.preferences";
+
+const char kButtonLayoutKey[] = "button-layout";
+const char kButtonLayoutChangedSignal[] = "changed::button-layout";
+
+const char kMiddleClickActionKey[] = "action-middle-click-titlebar";
+const char kMiddleClickActionChangedSignal[] =
+    "changed::action-middle-click-titlebar";
+
+const char kDefaultButtonString[] = ":minimize,maximize,close";
+
+}  // namespace
+
+namespace libgtkui {
+
+// Public interface:
+
+NavButtonLayoutManagerGSettings::NavButtonLayoutManagerGSettings(
+    GtkUi* delegate)
+    : delegate_(delegate), settings_(nullptr) {
+  DCHECK(delegate_);
+
+  if (!g_settings_schema_source_lookup(g_settings_schema_source_get_default(),
+                                       kGeneralPreferencesSchema, FALSE) ||
+      !(settings_ = g_settings_new(kGeneralPreferencesSchema))) {
+    LOG(ERROR) << "Unable to create a gsettings client - setting button layout "
+                  "to default";
+    ParseAndStoreButtonValue(kDefaultButtonString);
+    return;
+  }
+
+  // Get the inital value of the keys we're interested in.
+  OnDecorationButtonLayoutChanged(settings_, kButtonLayoutKey);
+  signal_button_id_ =
+      g_signal_connect(settings_, kButtonLayoutChangedSignal,
+                       G_CALLBACK(OnDecorationButtonLayoutChangedThunk), this);
+
+  OnMiddleClickActionChanged(settings_, kMiddleClickActionKey);
+  signal_middle_click_id_ =
+      g_signal_connect(settings_, kMiddleClickActionChangedSignal,
+                       G_CALLBACK(OnMiddleClickActionChangedThunk), this);
+}
+
+NavButtonLayoutManagerGSettings::~NavButtonLayoutManagerGSettings() {
+  if (settings_) {
+    if (signal_button_id_)
+      g_signal_handler_disconnect(settings_, signal_button_id_);
+    if (signal_middle_click_id_)
+      g_signal_handler_disconnect(settings_, signal_middle_click_id_);
+  }
+  g_free(settings_);
+}
+
+// Private:
+
+void NavButtonLayoutManagerGSettings::OnDecorationButtonLayoutChanged(
+    GSettings* settings,
+    const gchar* key) {
+  gchar* button_layout = g_settings_get_string(settings, kButtonLayoutKey);
+  if (!button_layout)
+    return;
+  ParseAndStoreButtonValue(button_layout);
+  g_free(button_layout);
+}
+
+void NavButtonLayoutManagerGSettings::ParseAndStoreButtonValue(
+    const std::string& button_string) {
+  std::vector<views::FrameButton> leading_buttons;
+  std::vector<views::FrameButton> trailing_buttons;
+  ParseButtonLayout(button_string, &leading_buttons, &trailing_buttons);
+  delegate_->SetWindowButtonOrdering(leading_buttons, trailing_buttons);
+}
+
+void NavButtonLayoutManagerGSettings::OnMiddleClickActionChanged(
+    GSettings* settings,
+    const gchar* key) {
+  gchar* click_action = g_settings_get_string(settings, kMiddleClickActionKey);
+  if (!click_action)
+    return;
+  ParseAndStoreMiddleClickValue(click_action);
+  g_free(click_action);
+}
+
+void NavButtonLayoutManagerGSettings::ParseAndStoreMiddleClickValue(
+    const std::string& click_action) {
+  GtkUi::NonClientMiddleClickAction action;
+
+  if (click_action == "none") {
+    action = views::LinuxUI::MIDDLE_CLICK_ACTION_NONE;
+  } else if (click_action == "lower") {
+    action = views::LinuxUI::MIDDLE_CLICK_ACTION_LOWER;
+  } else if (click_action == "minimize") {
+    action = views::LinuxUI::MIDDLE_CLICK_ACTION_MINIMIZE;
+  } else if (click_action == "toggle-maximize") {
+    action = views::LinuxUI::MIDDLE_CLICK_ACTION_TOGGLE_MAXIMIZE;
+  } else {
+    // While we want to have the default state be lower if there isn't a
+    // value, we want to default to no action if the user has explicitly
+    // chose an action that we don't implement.
+    action = views::LinuxUI::MIDDLE_CLICK_ACTION_NONE;
+  }
+
+  delegate_->SetNonClientMiddleClickAction(action);
+}
+
+}  // namespace libgtkui
diff --git a/chrome/browser/ui/libgtkui/nav_button_layout_manager_gsettings.h b/chrome/browser/ui/libgtkui/nav_button_layout_manager_gsettings.h
new file mode 100644
index 0000000..320f738
--- /dev/null
+++ b/chrome/browser/ui/libgtkui/nav_button_layout_manager_gsettings.h
@@ -0,0 +1,54 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_UI_LIBGTKUI_NAV_BUTTON_LAYOUT_MANAGER_GSETTINGS_H_
+#define CHROME_BROWSER_UI_LIBGTKUI_NAV_BUTTON_LAYOUT_MANAGER_GSETTINGS_H_
+
+#include <gio/gio.h>
+
+#include "base/macros.h"
+#include "chrome/browser/ui/libgtkui/nav_button_layout_manager.h"
+#include "ui/base/glib/glib_signal.h"
+
+namespace libgtkui {
+class GtkUi;
+
+// On GNOME desktops, subscribes to the gsettings key which controlls button
+// order and the middle click action. Everywhere else, SetTiltebarButtons()
+// just calls back into BrowserTitlebar with the default ordering.
+class NavButtonLayoutManagerGSettings : public NavButtonLayoutManager {
+ public:
+  // Sends data to the GtkUi when available.
+  explicit NavButtonLayoutManagerGSettings(GtkUi* delegate);
+  ~NavButtonLayoutManagerGSettings() override;
+
+ private:
+  CHROMEG_CALLBACK_1(NavButtonLayoutManagerGSettings,
+                     void,
+                     OnDecorationButtonLayoutChanged,
+                     GSettings*,
+                     const gchar*);
+
+  CHROMEG_CALLBACK_1(NavButtonLayoutManagerGSettings,
+                     void,
+                     OnMiddleClickActionChanged,
+                     GSettings*,
+                     const gchar*);
+
+  void ParseAndStoreButtonValue(const std::string&);
+
+  void ParseAndStoreMiddleClickValue(const std::string&);
+
+  GtkUi* delegate_;
+
+  GSettings* settings_;
+  gulong signal_button_id_;
+  gulong signal_middle_click_id_;
+
+  DISALLOW_COPY_AND_ASSIGN(NavButtonLayoutManagerGSettings);
+};
+
+}  // namespace libgtkui
+
+#endif  // CHROME_BROWSER_UI_LIBGTKUI_NAV_BUTTON_LAYOUT_MANAGER_GSETTINGS_H_
diff --git a/chrome/browser/ui/page_info/page_info.cc b/chrome/browser/ui/page_info/page_info.cc
index 216301a..36818182 100644
--- a/chrome/browser/ui/page_info/page_info.cc
+++ b/chrome/browser/ui/page_info/page_info.cc
@@ -181,6 +181,10 @@
   // gets checked there regardless of default setting on Desktop.
   if (info.type == CONTENT_SETTINGS_TYPE_GEOLOCATION)
     return true;
+#else
+  // Flash will always be shown. See https://crbug.com/791142.
+  if (info.type == CONTENT_SETTINGS_TYPE_PLUGINS)
+    return true;
 #endif
 
 #if !defined(OS_ANDROID)
diff --git a/chrome/browser/ui/page_info/page_info_unittest.cc b/chrome/browser/ui/page_info/page_info_unittest.cc
index 40b39a0..f393964a 100644
--- a/chrome/browser/ui/page_info/page_info_unittest.cc
+++ b/chrome/browser/ui/page_info/page_info_unittest.cc
@@ -213,25 +213,34 @@
 
 TEST_F(PageInfoTest, NonFactoryDefaultAndRecentlyChangedPermissionsShown) {
   page_info()->PresentSitePermissions();
-// By default, the number of permissions shown should be 0, except on Android,
-// where Geolocation needs to be checked for DSE settings.
+  std::vector<ContentSettingsType> expected_visible_permissions;
+
 #if defined(OS_ANDROID)
+  // Geolocation is always allowed to pass through to Android-specific logic to
+  // check for DSE settings (so expect 1 item), but isn't actually shown later
+  // on because this test isn't testing with a default search engine origin.
   EXPECT_EQ(1uL, last_permission_info_list().size());
+  EXPECT_EQ(CONTENT_SETTINGS_TYPE_GEOLOCATION,
+            last_permission_info_list().back().type);
 #else
-  EXPECT_EQ(0uL, last_permission_info_list().size());
+  expected_visible_permissions.push_back(CONTENT_SETTINGS_TYPE_PLUGINS);
+  // Flash is always visible on desktop - see https://crbug.com/791142.
+  EXPECT_EQ(expected_visible_permissions.size(),
+            last_permission_info_list().size());
+  EXPECT_EQ(CONTENT_SETTINGS_TYPE_PLUGINS,
+            last_permission_info_list().back().type);
 #endif
 
-  std::vector<ContentSettingsType> expected_visible_permissions = {
-      CONTENT_SETTINGS_TYPE_GEOLOCATION, CONTENT_SETTINGS_TYPE_NOTIFICATIONS,
-      CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC,
-  };
   // Change some default-ask settings away from the default.
   page_info()->OnSitePermissionChanged(CONTENT_SETTINGS_TYPE_GEOLOCATION,
                                        CONTENT_SETTING_ALLOW);
+  expected_visible_permissions.push_back(CONTENT_SETTINGS_TYPE_GEOLOCATION);
   page_info()->OnSitePermissionChanged(CONTENT_SETTINGS_TYPE_NOTIFICATIONS,
                                        CONTENT_SETTING_ALLOW);
+  expected_visible_permissions.push_back(CONTENT_SETTINGS_TYPE_NOTIFICATIONS);
   page_info()->OnSitePermissionChanged(CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC,
                                        CONTENT_SETTING_ALLOW);
+  expected_visible_permissions.push_back(CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC);
   EXPECT_EQ(expected_visible_permissions.size(),
             last_permission_info_list().size());
 
diff --git a/chrome/browser/ui/toolbar/app_menu_model.cc b/chrome/browser/ui/toolbar/app_menu_model.cc
index 450ab114..218e6ed 100644
--- a/chrome/browser/ui/toolbar/app_menu_model.cc
+++ b/chrome/browser/ui/toolbar/app_menu_model.cc
@@ -108,6 +108,26 @@
   }
 }
 
+// Returns the appropriate menu label for the IDC_CREATE_HOSTED_APP command.
+base::string16 GetCreateHostedAppMenuItemName(Browser* browser) {
+  bool installable_app = false;
+
+  if (browser->tab_strip_model() &&
+      browser->tab_strip_model()->GetActiveWebContents()) {
+    const banners::AppBannerManager::Installable installable =
+        banners::AppBannerManager::GetInstallable(
+            browser->tab_strip_model()->GetActiveWebContents());
+    if (installable ==
+        banners::AppBannerManager::Installable::INSTALLABLE_YES) {
+      installable_app = true;
+    }
+  }
+
+  return l10n_util::GetStringUTF16(installable_app
+                                       ? IDS_INSTALL_TO_OS_LAUNCH_SURFACE
+                                       : IDS_ADD_TO_OS_LAUNCH_SURFACE);
+}
+
 }  // namespace
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -250,6 +270,7 @@
 #elif defined(OS_WIN)
          command_id == IDC_PIN_TO_START_SCREEN ||
 #endif
+         command_id == IDC_CREATE_HOSTED_APP ||
          command_id == IDC_UPGRADE_DIALOG;
 }
 
@@ -272,6 +293,8 @@
       return l10n_util::GetStringUTF16(string_id);
     }
 #endif
+    case IDC_CREATE_HOSTED_APP:
+      return GetCreateHostedAppMenuItemName(browser_);
     case IDC_UPGRADE_DIALOG:
       return GetUpgradeDialogMenuItemName();
     default:
@@ -742,7 +765,7 @@
   AddItemWithStringId(IDC_FIND, IDS_FIND);
   if (extensions::util::IsNewBookmarkAppsEnabled() &&
       banners::AppBannerManager::IsExperimentalAppBannersEnabled()) {
-    AddItemWithStringId(IDC_CREATE_HOSTED_APP, IDS_ADD_TO_OS_LAUNCH_SURFACE);
+    AddItem(IDC_CREATE_HOSTED_APP, GetCreateHostedAppMenuItemName(browser_));
   }
 
   if (base::CommandLine::ForCurrentProcess()->HasSwitch(
diff --git a/chrome/browser/ui/views/extensions/pwa_confirmation_view.cc b/chrome/browser/ui/views/extensions/pwa_confirmation_view.cc
index b2559c5..adb42ef2 100644
--- a/chrome/browser/ui/views/extensions/pwa_confirmation_view.cc
+++ b/chrome/browser/ui/views/extensions/pwa_confirmation_view.cc
@@ -62,7 +62,8 @@
 }
 
 base::string16 PWAConfirmationView::GetWindowTitle() const {
-  return l10n_util::GetStringUTF16(IDS_ADD_TO_OS_LAUNCH_SURFACE_BUBBLE_TITLE);
+  return l10n_util::GetStringUTF16(
+      IDS_INSTALL_TO_OS_LAUNCH_SURFACE_BUBBLE_TITLE);
 }
 
 bool PWAConfirmationView::ShouldShowCloseButton() const {
diff --git a/chrome/browser/ui/views/page_info/page_info_bubble_view_unittest.cc b/chrome/browser/ui/views/page_info/page_info_bubble_view_unittest.cc
index 0ad3a32..2f4b9c2 100644
--- a/chrome/browser/ui/views/page_info/page_info_bubble_view_unittest.cc
+++ b/chrome/browser/ui/views/page_info/page_info_bubble_view_unittest.cc
@@ -221,11 +221,12 @@
   list.back().is_incognito = false;
   list.back().setting = CONTENT_SETTING_BLOCK;
 
-  // Initially, no permissions are shown because they are all set to default.
-  int num_expected_children = 0;
+  // Initially, no permissions are shown because they are all set to default,
+  // except for Flash.
+  int num_expected_children = 3;
   EXPECT_EQ(num_expected_children, api_->permissions_view()->child_count());
 
-  num_expected_children = kViewsPerPermissionRow * list.size();
+  num_expected_children += kViewsPerPermissionRow * list.size();
   list.back().setting = CONTENT_SETTING_ALLOW;
   api_->SetPermissionInfo(list);
   EXPECT_EQ(num_expected_children, api_->permissions_view()->child_count());
@@ -279,7 +280,8 @@
 
 // Test UI construction and reconstruction with USB devices.
 TEST_F(PageInfoBubbleViewTest, SetPermissionInfoWithUsbDevice) {
-  const int kExpectedChildren = 0;
+  // One permission row is always shown here (Flash). https://crbug.com/791142
+  const int kExpectedChildren = kViewsPerPermissionRow;
   EXPECT_EQ(kExpectedChildren, api_->permissions_view()->child_count());
 
   const GURL origin = GURL(kUrl).GetOrigin();
diff --git a/chrome/browser/ui/webui/interventions_internals/interventions_internals.mojom b/chrome/browser/ui/webui/interventions_internals/interventions_internals.mojom
index d66b796..8c86cd0 100644
--- a/chrome/browser/ui/webui/interventions_internals/interventions_internals.mojom
+++ b/chrome/browser/ui/webui/interventions_internals/interventions_internals.mojom
@@ -37,6 +37,10 @@
 
   // The time when the event happened in millisecond since Unix epoch.
   int64 time;
+
+  // The ID associated with the request, for grouping log messages in the UI. If
+  // |id| is 0, then they will not be grouped, since pageId values start at 1.
+  uint64 page_id;
 };
 
 
diff --git a/chrome/browser/ui/webui/interventions_internals/interventions_internals_page_handler.cc b/chrome/browser/ui/webui/interventions_internals/interventions_internals_page_handler.cc
index 518ec96..796d4d9 100644
--- a/chrome/browser/ui/webui/interventions_internals/interventions_internals_page_handler.cc
+++ b/chrome/browser/ui/webui/interventions_internals/interventions_internals_page_handler.cc
@@ -114,6 +114,7 @@
   mojo_message_ptr->description = message.event_description;
   mojo_message_ptr->url = message.url;
   mojo_message_ptr->time = message.time.ToJavaTime();
+  mojo_message_ptr->page_id = message.page_id;
 
   page_->LogNewMessage(std::move(mojo_message_ptr));
 }
diff --git a/chrome/browser/ui/webui/interventions_internals/interventions_internals_page_handler_unittest.cc b/chrome/browser/ui/webui/interventions_internals/interventions_internals_page_handler_unittest.cc
index 96eaa1e9..c56005d9 100644
--- a/chrome/browser/ui/webui/interventions_internals/interventions_internals_page_handler_unittest.cc
+++ b/chrome/browser/ui/webui/interventions_internals/interventions_internals_page_handler_unittest.cc
@@ -560,15 +560,15 @@
 
 TEST_F(InterventionsInternalsPageHandlerTest, OnNewMessageLogAddedPostToPage) {
   const previews::PreviewsLogger::MessageLog expected_messages[] = {
-      previews::PreviewsLogger::MessageLog("Event_a", "Some description a",
-                                           GURL("http://www.url_a.com/url_a"),
-                                           base::Time::Now()),
-      previews::PreviewsLogger::MessageLog("Event_b", "Some description b",
-                                           GURL("http://www.url_b.com/url_b"),
-                                           base::Time::Now()),
-      previews::PreviewsLogger::MessageLog("Event_c", "Some description c",
-                                           GURL("http://www.url_c.com/url_c"),
-                                           base::Time::Now()),
+      previews::PreviewsLogger::MessageLog(
+          "Event_a", "Some description a", GURL("http://www.url_a.com/url_a"),
+          base::Time::Now(), 1234UL /* page_id */),
+      previews::PreviewsLogger::MessageLog(
+          "Event_b", "Some description b", GURL("http://www.url_b.com/url_b"),
+          base::Time::Now(), 4321UL /* page_id */),
+      previews::PreviewsLogger::MessageLog(
+          "Event_c", "Some description c", GURL("http://www.url_c.com/url_c"),
+          base::Time::Now(), 6789UL /* page_id */),
   };
 
   for (auto message : expected_messages) {
@@ -581,6 +581,7 @@
     EXPECT_EQ(message.url, (*actual)->url);
     int64_t expected_time = message.time.ToJavaTime();
     EXPECT_EQ(expected_time, (*actual)->time);
+    EXPECT_EQ(message.page_id, (*actual)->page_id);
   }
 }
 
diff --git a/chrome/browser/ui/webui/md_downloads/md_downloads_dom_handler.cc b/chrome/browser/ui/webui/md_downloads/md_downloads_dom_handler.cc
index fdc3fbe2..7cb3c72 100644
--- a/chrome/browser/ui/webui/md_downloads/md_downloads_dom_handler.cc
+++ b/chrome/browser/ui/webui/md_downloads/md_downloads_dom_handler.cc
@@ -75,8 +75,7 @@
 
 MdDownloadsDOMHandler::MdDownloadsDOMHandler(
     content::DownloadManager* download_manager, content::WebUI* web_ui)
-    : list_tracker_(download_manager, web_ui),
-      weak_ptr_factory_(this) {
+    : list_tracker_(download_manager, web_ui) {
   // Create our fileicon data source.
   profile_ = Profile::FromBrowserContext(download_manager->GetBrowserContext());
   content::URLDataSource::Add(profile_, new FileIconSource());
@@ -139,12 +138,14 @@
 void MdDownloadsDOMHandler::OnJavascriptDisallowed() {
   list_tracker_.Stop();
   list_tracker_.Reset();
-  CheckForRemovedFiles();
+  if (!render_process_gone_)
+    CheckForRemovedFiles();
 }
 
 void MdDownloadsDOMHandler::RenderProcessGone(base::TerminationStatus status) {
   // TODO(dbeam): WebUI + WebUIMessageHandler should do this automatically.
   // http://crbug.com/610450
+  render_process_gone_ = true;
   DisallowJavascript();
 }
 
diff --git a/chrome/browser/ui/webui/md_downloads/md_downloads_dom_handler.h b/chrome/browser/ui/webui/md_downloads/md_downloads_dom_handler.h
index 71cc3b4..162aced 100644
--- a/chrome/browser/ui/webui/md_downloads/md_downloads_dom_handler.h
+++ b/chrome/browser/ui/webui/md_downloads/md_downloads_dom_handler.h
@@ -153,9 +153,12 @@
   std::vector<IdSet> removals_;
 
   // User profile that corresponds to this handler.
-  Profile* profile_;
+  Profile* profile_ = nullptr;
 
-  base::WeakPtrFactory<MdDownloadsDOMHandler> weak_ptr_factory_;
+  // Whether the render process has gone.
+  bool render_process_gone_ = false;
+
+  base::WeakPtrFactory<MdDownloadsDOMHandler> weak_ptr_factory_{this};
 
   DISALLOW_COPY_AND_ASSIGN(MdDownloadsDOMHandler);
 };
diff --git a/chrome/browser/ui/webui/sync_internals_message_handler.cc b/chrome/browser/ui/webui/sync_internals_message_handler.cc
index d02db0a..32bd8bba 100644
--- a/chrome/browser/ui/webui/sync_internals_message_handler.cc
+++ b/chrome/browser/ui/webui/sync_internals_message_handler.cc
@@ -54,6 +54,15 @@
   return 0;
 }
 
+// Returns whether the there is any value at the given |index|.
+bool HasSomethingAtIndex(const base::ListValue* list, int index) {
+  std::string str;
+  if (list->GetString(index, &str)) {
+    return !str.empty();
+  }
+  return false;
+}
+
 }  //  namespace
 
 SyncInternalsMessageHandler::SyncInternalsMessageHandler()
@@ -229,8 +238,18 @@
       browser_sync::UserEventServiceFactory::GetForProfile(profile);
 
   sync_pb::UserEventSpecifics event_specifics;
+  // Even though there's nothing to set inside the test event object, it needs
+  // to be created so that later logic can discern our event type.
+  event_specifics.mutable_test_event();
+
+  // |event_time_usec| is required.
   event_specifics.set_event_time_usec(StringAtIndexToInt64(args, 0));
-  event_specifics.set_navigation_id(StringAtIndexToInt64(args, 1));
+
+  // |navigation_id| is optional, treat empty string and 0 differently.
+  if (HasSomethingAtIndex(args, 1)) {
+    event_specifics.set_navigation_id(StringAtIndexToInt64(args, 1));
+  }
+
   user_event_service->RecordUserEvent(event_specifics);
 }
 
diff --git a/chrome/browser/ui/webui/sync_internals_message_handler_unittest.cc b/chrome/browser/ui/webui/sync_internals_message_handler_unittest.cc
index c026478..1842fbe9 100644
--- a/chrome/browser/ui/webui/sync_internals_message_handler_unittest.cc
+++ b/chrome/browser/ui/webui/sync_internals_message_handler_unittest.cc
@@ -27,6 +27,7 @@
 using base::DictionaryValue;
 using base::ListValue;
 using base::Value;
+using sync_pb::UserEventSpecifics;
 using syncer::FakeUserEventService;
 using syncer::SyncService;
 using syncer::SyncServiceObserver;
@@ -337,8 +338,9 @@
   handler()->HandleWriteUserEvent(&args);
 
   ASSERT_EQ(1u, fake_user_event_service()->GetRecordedUserEvents().size());
-  const sync_pb::UserEventSpecifics& event =
+  const UserEventSpecifics& event =
       *fake_user_event_service()->GetRecordedUserEvents().begin();
+  EXPECT_EQ(UserEventSpecifics::kTestEvent, event.event_case());
   EXPECT_EQ(1000000000000000000, event.event_time_usec());
   EXPECT_EQ(-1, event.navigation_id());
 }
@@ -346,13 +348,48 @@
 TEST_F(SyncInternalsMessageHandlerTest, WriteUserEventBadParse) {
   ListValue args;
   args.AppendString("123abc");
+  args.AppendString("abcdefghijklmnopqrstuvwxyz");
+  handler()->HandleWriteUserEvent(&args);
+
+  ASSERT_EQ(1u, fake_user_event_service()->GetRecordedUserEvents().size());
+  const UserEventSpecifics& event =
+      *fake_user_event_service()->GetRecordedUserEvents().begin();
+  EXPECT_EQ(UserEventSpecifics::kTestEvent, event.event_case());
+  EXPECT_EQ(0, event.event_time_usec());
+  EXPECT_EQ(0, event.navigation_id());
+}
+
+TEST_F(SyncInternalsMessageHandlerTest, WriteUserEventBlank) {
+  ListValue args;
+  args.AppendString("");
   args.AppendString("");
   handler()->HandleWriteUserEvent(&args);
 
   ASSERT_EQ(1u, fake_user_event_service()->GetRecordedUserEvents().size());
-  const sync_pb::UserEventSpecifics& event =
+  const UserEventSpecifics& event =
       *fake_user_event_service()->GetRecordedUserEvents().begin();
+  EXPECT_EQ(UserEventSpecifics::kTestEvent, event.event_case());
+  EXPECT_TRUE(event.has_event_time_usec());
   EXPECT_EQ(0, event.event_time_usec());
+  // Should not have a navigation_id because that means something different to
+  // the UserEvents logic.
+  EXPECT_FALSE(event.has_navigation_id());
+}
+
+TEST_F(SyncInternalsMessageHandlerTest, WriteUserEventZero) {
+  ListValue args;
+  args.AppendString("0");
+  args.AppendString("0");
+  handler()->HandleWriteUserEvent(&args);
+
+  ASSERT_EQ(1u, fake_user_event_service()->GetRecordedUserEvents().size());
+  const UserEventSpecifics& event =
+      *fake_user_event_service()->GetRecordedUserEvents().begin();
+  EXPECT_EQ(UserEventSpecifics::kTestEvent, event.event_case());
+  EXPECT_TRUE(event.has_event_time_usec());
+  EXPECT_EQ(0, event.event_time_usec());
+  // Should have a navigation_id, even though the value is 0.
+  EXPECT_TRUE(event.has_navigation_id());
   EXPECT_EQ(0, event.navigation_id());
 }
 
diff --git a/chrome/browser/ui/window_sizer/window_sizer_ash.cc b/chrome/browser/ui/window_sizer/window_sizer_ash.cc
index 0df8ef79..4b27cdb 100644
--- a/chrome/browser/ui/window_sizer/window_sizer_ash.cc
+++ b/chrome/browser/ui/window_sizer/window_sizer_ash.cc
@@ -46,7 +46,8 @@
     // In case of a popup with an 'unspecified' location in ash, we are
     // looking for a good screen location. We are interpreting (0,0) as an
     // unspecified location.
-    *bounds = ash::Shell::Get()->window_positioner()->GetPopupPosition(*bounds);
+    *bounds = ash::Shell::Get()->window_positioner()->GetPopupPosition(
+        bounds->size());
     determined = true;
   }
 
diff --git a/chrome/browser/vr/elements/text.cc b/chrome/browser/vr/elements/text.cc
index b5a610b..c10f408 100644
--- a/chrome/browser/vr/elements/text.cc
+++ b/chrome/browser/vr/elements/text.cc
@@ -105,7 +105,11 @@
   texture_->SetCursorPosition(position);
 }
 
-gfx::RectF Text::GetCursorBounds() {
+gfx::Rect Text::GetRawCursorBounds() const {
+  return texture_->get_cursor_bounds();
+}
+
+gfx::RectF Text::GetCursorBounds() const {
   // Note that gfx:: cursor bounds always indicate a one-pixel width, so we
   // override the width here to be a percentage of height for the sake of
   // arbitrary texture sizes.
diff --git a/chrome/browser/vr/elements/text.h b/chrome/browser/vr/elements/text.h
index 43a9641..bf5ae6e 100644
--- a/chrome/browser/vr/elements/text.h
+++ b/chrome/browser/vr/elements/text.h
@@ -37,9 +37,13 @@
   void SetCursorEnabled(bool enabled);
   void SetCursorPosition(int position);
 
-  // Returns the most recently computed cursor position, in DMM, relative to the
-  // corner of the element.
-  gfx::RectF GetCursorBounds();
+  // Returns the most recently computed cursor position, in pixels.  This is
+  // used for scene dirtiness and testing.
+  gfx::Rect GetRawCursorBounds() const;
+
+  // Returns the most recently computed cursor position, in fractions of the
+  // texture size, relative to the upper-left corner of the element.
+  gfx::RectF GetCursorBounds() const;
 
   void OnSetSize(gfx::SizeF size) override;
 
diff --git a/chrome/browser/vr/elements/text_input.cc b/chrome/browser/vr/elements/text_input.cc
index b110e7a..ff1b685 100644
--- a/chrome/browser/vr/elements/text_input.cc
+++ b/chrome/browser/vr/elements/text_input.cc
@@ -37,9 +37,10 @@
   text = base::MakeUnique<Text>(maximum_width_pixels, font_height_meters);
   text->set_type(kTypeTextInputText);
   text->set_draw_phase(kPhaseForeground);
-  text->set_hit_testable(false);
+  text->set_hit_testable(true);
   text->set_x_anchoring(LEFT);
   text->set_x_centering(LEFT);
+  text->set_bubble_events(true);
   text->SetSize(1, 1);
   text->SetMultiLine(false);
   text->SetTextAlignment(UiTexture::kTextAlignmentLeft);
@@ -48,6 +49,7 @@
   this->AddChild(std::move(text));
 
   auto cursor = base::MakeUnique<Rect>();
+  cursor->SetVisible(false);
   cursor->set_type(kTypeTextInputCursor);
   cursor->set_draw_phase(kPhaseForeground);
   cursor->set_hit_testable(false);
@@ -81,7 +83,8 @@
   if (delegate_ && focused)
     delegate_->UpdateInput(text_info_);
 
-  focus_changed_callback_.Run(focused);
+  if (focus_changed_callback_)
+    focus_changed_callback_.Run(focused);
 }
 
 void TextInput::RequestFocus() {
@@ -109,6 +112,10 @@
   cursor_element_->SetColor(color);
 }
 
+void TextInput::SetHintColor(SkColor color) {
+  hint_element_->SetColor(color);
+}
+
 void TextInput::UpdateInput(const TextInputInfo& info) {
   if (text_info_ == info)
     return;
diff --git a/chrome/browser/vr/elements/text_input.h b/chrome/browser/vr/elements/text_input.h
index 67d0bc6..68d0208 100644
--- a/chrome/browser/vr/elements/text_input.h
+++ b/chrome/browser/vr/elements/text_input.h
@@ -43,6 +43,7 @@
   void SetHintText(const base::string16& text);
   void SetTextColor(SkColor color);
   void SetCursorColor(SkColor color);
+  void SetHintColor(SkColor color);
   void SetTextInputDelegate(TextInputDelegate* text_input_delegate);
 
   bool OnBeginFrame(const base::TimeTicks& time,
@@ -50,6 +51,10 @@
   void OnSetSize(gfx::SizeF size) final;
   void OnSetName() final;
 
+  Text* get_hint_element() { return hint_element_; }
+  Text* get_text_element() { return text_element_; }
+  Rect* get_cursor_element() { return cursor_element_; }
+
  private:
   void LayOutChildren() final;
   bool SetCursorBlinkState(const base::TimeTicks& time);
diff --git a/chrome/browser/vr/elements/url_bar.cc b/chrome/browser/vr/elements/url_bar.cc
index 6bb55858..e001c73d 100644
--- a/chrome/browser/vr/elements/url_bar.cc
+++ b/chrome/browser/vr/elements/url_bar.cc
@@ -9,12 +9,15 @@
 
 namespace vr {
 
-UrlBar::UrlBar(int preferred_width,
-               const base::Callback<void()>& back_button_callback,
-               const base::Callback<void(UiUnsupportedMode)>& failure_callback)
+UrlBar::UrlBar(
+    int preferred_width,
+    const base::RepeatingCallback<void()>& back_button_callback,
+    const base::RepeatingCallback<void()>& url_click_callback,
+    const base::RepeatingCallback<void(UiUnsupportedMode)>& failure_callback)
     : TexturedElement(preferred_width),
       texture_(base::MakeUnique<UrlBarTexture>(failure_callback)),
       back_button_callback_(back_button_callback),
+      url_click_callback_(url_click_callback),
       failure_callback_(failure_callback) {}
 
 UrlBar::~UrlBar() = default;
@@ -38,20 +41,25 @@
 
 void UrlBar::OnButtonDown(const gfx::PointF& position) {
   if (texture_->HitsBackButton(position))
-    down_ = true;
+    back_button_down_ = true;
   else if (texture_->HitsSecurityRegion(position))
     security_region_down_ = true;
+  else if (texture_->HitsUrlBar(position))
+    url_down_ = true;
   OnStateUpdated(position);
 }
 
 void UrlBar::OnButtonUp(const gfx::PointF& position) {
-  down_ = false;
   OnStateUpdated(position);
   if (can_go_back_ && texture_->HitsBackButton(position))
     back_button_callback_.Run();
   else if (security_region_down_ && texture_->HitsSecurityRegion(position))
     failure_callback_.Run(UiUnsupportedMode::kUnhandledPageInfo);
+  else if (url_down_ && texture_->HitsUrlBar(position))
+    url_click_callback_.Run();
+  back_button_down_ = false;
   security_region_down_ = false;
+  url_down_ = false;
 }
 
 bool UrlBar::LocalHitTest(const gfx::PointF& position) const {
@@ -73,7 +81,7 @@
 
 void UrlBar::OnStateUpdated(const gfx::PointF& position) {
   const bool hovered = texture_->HitsBackButton(position);
-  const bool pressed = hovered ? down_ : false;
+  const bool pressed = hovered ? back_button_down_ : false;
 
   texture_->SetBackButtonHovered(hovered);
   texture_->SetBackButtonPressed(pressed);
diff --git a/chrome/browser/vr/elements/url_bar.h b/chrome/browser/vr/elements/url_bar.h
index 090f634..20ef0655 100644
--- a/chrome/browser/vr/elements/url_bar.h
+++ b/chrome/browser/vr/elements/url_bar.h
@@ -23,9 +23,11 @@
 
 class UrlBar : public TexturedElement {
  public:
-  UrlBar(int preferred_width,
-         const base::Callback<void()>& back_button_callback,
-         const base::Callback<void(UiUnsupportedMode)>& failure_callback);
+  UrlBar(
+      int preferred_width,
+      const base::RepeatingCallback<void()>& back_button_callback,
+      const base::RepeatingCallback<void()>& url_click_callback,
+      const base::RepeatingCallback<void(UiUnsupportedMode)>& failure_callback);
   ~UrlBar() override;
 
   void OnHoverEnter(const gfx::PointF& position) override;
@@ -45,11 +47,14 @@
   void OnStateUpdated(const gfx::PointF& position);
 
   std::unique_ptr<UrlBarTexture> texture_;
-  base::Callback<void()> back_button_callback_;
-  base::Callback<void(UiUnsupportedMode)> failure_callback_;
+  base::RepeatingCallback<void()> back_button_callback_;
+  base::RepeatingCallback<void()> url_click_callback_;
+  base::RepeatingCallback<void(UiUnsupportedMode)> failure_callback_;
+
   bool can_go_back_ = false;
-  bool down_ = false;
+  bool back_button_down_ = false;
   bool security_region_down_ = false;
+  bool url_down_ = false;
 
   DISALLOW_COPY_AND_ASSIGN(UrlBar);
 };
diff --git a/chrome/browser/vr/model/color_scheme.cc b/chrome/browser/vr/model/color_scheme.cc
index c399653..756b5eb6 100644
--- a/chrome/browser/vr/model/color_scheme.cc
+++ b/chrome/browser/vr/model/color_scheme.cc
@@ -114,6 +114,7 @@
   normal_scheme.omnibox_background = 0xFFEEEEEE;
   normal_scheme.omnibox_icon = 0xA6000000;
   normal_scheme.omnibox_text = 0xFF595959;
+  normal_scheme.omnibox_hint = 0xFF999999;
   normal_scheme.omnibox_suggestion_content = 0xFF595959;
   normal_scheme.omnibox_suggestion_description = 0xFF5595FE;
   normal_scheme.cursor = 0xFF5595FE;
diff --git a/chrome/browser/vr/model/color_scheme.h b/chrome/browser/vr/model/color_scheme.h
index bda98a5..4ff5cb9 100644
--- a/chrome/browser/vr/model/color_scheme.h
+++ b/chrome/browser/vr/model/color_scheme.h
@@ -106,6 +106,7 @@
   SkColor omnibox_background;
   SkColor omnibox_icon;
   SkColor omnibox_text;
+  SkColor omnibox_hint;
   SkColor omnibox_suggestion_content;
   SkColor omnibox_suggestion_description;
 
diff --git a/chrome/browser/vr/model/text_input_info.cc b/chrome/browser/vr/model/text_input_info.cc
index 263721d..b56ff455 100644
--- a/chrome/browser/vr/model/text_input_info.cc
+++ b/chrome/browser/vr/model/text_input_info.cc
@@ -19,4 +19,8 @@
   return !(*this == other);
 }
 
+static_assert(sizeof(base::string16) + 8 == sizeof(TextInputInfo),
+              "If new fields are added to TextInputInfo, we must explicitly "
+              "bump this size and update operator==");
+
 }  // namespace vr
diff --git a/chrome/browser/vr/testapp/vr_test_context.cc b/chrome/browser/vr/testapp/vr_test_context.cc
index e0a0fa8..8f1b939 100644
--- a/chrome/browser/vr/testapp/vr_test_context.cc
+++ b/chrome/browser/vr/testapp/vr_test_context.cc
@@ -91,6 +91,9 @@
 
   base::i18n::InitializeICU();
 
+  // TODO(cjgrant): Remove this when the keyboard is enabled by default.
+  base::FeatureList::InitializeInstance("VrBrowserKeyboard", "");
+
   text_input_delegate_ = base::MakeUnique<vr::TextInputDelegate>();
   keyboard_delegate_ = base::MakeUnique<vr::TestKeyboardDelegate>();
 
@@ -376,7 +379,6 @@
             "if not truncated through some other means."),
         AutocompleteMatch::Type::VOICE_SUGGEST, GURL("http://www.test.com/")));
   }
-  model_->omnibox_input_active = true;
   ui_->SetOmniboxSuggestions(std::move(result));
 
   num_suggestions++;
diff --git a/chrome/browser/vr/text_input_unittest.cc b/chrome/browser/vr/text_input_unittest.cc
index 07db52c7..4ace6ef9 100644
--- a/chrome/browser/vr/text_input_unittest.cc
+++ b/chrome/browser/vr/text_input_unittest.cc
@@ -11,10 +11,12 @@
 #include "build/build_config.h"
 #include "chrome/browser/vr/databinding/binding.h"
 #include "chrome/browser/vr/elements/keyboard.h"
+#include "chrome/browser/vr/elements/text.h"
 #include "chrome/browser/vr/elements/ui_element.h"
 #include "chrome/browser/vr/keyboard_delegate.h"
 #include "chrome/browser/vr/model/camera_model.h"
 #include "chrome/browser/vr/model/model.h"
+#include "chrome/browser/vr/test/animation_utils.h"
 #include "chrome/browser/vr/test/constants.h"
 #include "chrome/browser/vr/test/ui_test.h"
 #include "chrome/browser/vr/text_input_delegate.h"
@@ -23,6 +25,7 @@
 #include "chrome/browser/vr/ui_scene_creator.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "third_party/WebKit/public/platform/WebGestureEvent.h"
+#include "ui/gfx/render_text.h"
 
 using ::testing::_;
 using ::testing::InSequence;
@@ -30,21 +33,6 @@
 
 namespace vr {
 
-namespace {
-
-#if defined(OS_LINUX)
-// The purpose here is to catch forgetting to update operator==. Ideally this
-// should go in TextInputInfo, but the size of base::string16 varies accross
-// platforms (i.e 24 bytes on linux and 20 bytes on android), so we can't add it
-// there in a generic way.
-static constexpr size_t kTextInputInfoSize = 32;
-static_assert(kTextInputInfoSize == sizeof(TextInputInfo),
-              "If new fields are added to TextInputInfo, we must explicitly "
-              "bump this size and update operator== below");
-#endif
-
-}  // namespace
-
 class MockTextInputDelegate : public TextInputDelegate {
  public:
   MockTextInputDelegate() = default;
@@ -74,7 +62,7 @@
   DISALLOW_COPY_AND_ASSIGN(MockKeyboardDelegate);
 };
 
-class TextInputTest : public UiTest {
+class TextInputSceneTest : public UiTest {
  public:
   void SetUp() override {
     UiTest::SetUp();
@@ -98,7 +86,7 @@
   testing::Sequence in_sequence_;
 };
 
-TEST_F(TextInputTest, InputFieldFocus) {
+TEST_F(TextInputSceneTest, InputFieldFocus) {
   // Set mock delegates.
   auto* kb = static_cast<Keyboard*>(scene_->GetUiElementByName(kKeyboard));
   auto kb_delegate = base::MakeUnique<StrictMock<MockKeyboardDelegate>>();
@@ -126,7 +114,7 @@
   EXPECT_TRUE(OnBeginFrame());
 }
 
-TEST_F(TextInputTest, InputFieldEdit) {
+TEST_F(TextInputSceneTest, InputFieldEdit) {
   // UpdateInput should not be called if the text input doesn't have focus.
   EXPECT_CALL(*text_input_delegate_, UpdateInput(_))
       .Times(0)
@@ -145,4 +133,79 @@
   EXPECT_EQ(info, *text_input_info_);
 }
 
+TEST_F(TextInputSceneTest, ClickOnTextGrabsFocus) {
+  EXPECT_CALL(*text_input_delegate_, RequestFocus(_));
+  text_input_->get_text_element()->OnButtonUp({0, 0});
+}
+
+TEST(TextInputTest, HintText) {
+  UiScene scene;
+
+  auto instance =
+      base::MakeUnique<TextInput>(512, 10, TextInput::OnFocusChangedCallback(),
+                                  TextInput::OnInputEditedCallback());
+  instance->set_name(kOmniboxTextField);
+  instance->SetSize(1, 0);
+  TextInput* element = instance.get();
+  scene.root_element().AddChild(std::move(instance));
+
+  // Text field is empty, so we should be showing hint text.
+  scene.OnBeginFrame(base::TimeTicks(), kForwardVector);
+  EXPECT_GT(element->get_hint_element()->GetTargetOpacity(), 0);
+
+  // When text enters the field, the hint should disappear.
+  TextInputInfo info;
+  info.text = base::UTF8ToUTF16("text");
+  element->UpdateInput(info);
+  scene.OnBeginFrame(base::TimeTicks(), kForwardVector);
+  EXPECT_EQ(element->get_hint_element()->GetTargetOpacity(), 0);
+}
+
+TEST(TextInputTest, Cursor) {
+  UiScene scene;
+
+  auto instance =
+      base::MakeUnique<TextInput>(512, 10, TextInput::OnFocusChangedCallback(),
+                                  TextInput::OnInputEditedCallback());
+  instance->set_name(kOmniboxTextField);
+  instance->SetSize(1, 0);
+  TextInput* element = instance.get();
+  scene.root_element().AddChild(std::move(instance));
+
+  // The cursor should not be blinking or visible.
+  float initial = element->get_cursor_element()->GetTargetOpacity();
+  EXPECT_EQ(initial, 0.f);
+  for (int ms = 0; ms <= 2000; ms += 100) {
+    scene.OnBeginFrame(MsToTicks(ms), kForwardVector);
+    EXPECT_EQ(initial, element->get_cursor_element()->GetTargetOpacity());
+  }
+
+  // When focused, the cursor should start blinking.
+  element->OnFocusChanged(true);
+  initial = element->get_cursor_element()->GetTargetOpacity();
+  bool toggled = false;
+  for (int ms = 0; ms <= 2000; ms += 100) {
+    scene.OnBeginFrame(MsToTicks(ms), kForwardVector);
+    if (initial != element->get_cursor_element()->GetTargetOpacity())
+      toggled = true;
+  }
+  EXPECT_TRUE(toggled);
+
+// TODO(cjgrant): Continue with the test cases below, when they're debugged.
+#if 0
+  TextInputInfo info;
+  info.text = base::UTF8ToUTF16("text");
+
+  // When the cursor position moves, the cursor element should move.
+  element->UpdateInput(info);
+  auto result = element->get_text_element()->LayOutTextForTest({512, 512});
+  auto position1 = element->get_text_element()->GetRawCursorBounds();
+  info.selection_end = 1;
+  element->UpdateInput(info);
+  element->get_text_element()->LayOutTextForTest({512, 512});
+  auto position2 = element->get_text_element()->GetRawCursorBounds();
+  EXPECT_NE(position1, position2);
+#endif
+}
+
 }  // namespace vr
diff --git a/chrome/browser/vr/ui_scene.cc b/chrome/browser/vr/ui_scene.cc
index 378464e..aea044a 100644
--- a/chrome/browser/vr/ui_scene.cc
+++ b/chrome/browser/vr/ui_scene.cc
@@ -98,7 +98,6 @@
 bool UiScene::OnBeginFrame(const base::TimeTicks& current_time,
                            const gfx::Vector3dF& look_at) {
   bool scene_dirty = !initialized_scene_ || is_dirty_;
-  bool needs_redraw = false;
   initialized_scene_ = true;
   is_dirty_ = false;
 
@@ -140,7 +139,7 @@
     // synchronously in response to input should be prohibited.
     for (auto& element : *root_element_) {
       if (element.PrepareToDraw())
-        needs_redraw = true;
+        scene_dirty = true;
       element.set_update_phase(UiElement::kUpdatedTexturesAndSizes);
     }
   }
@@ -151,7 +150,7 @@
     for (auto& element : *root_element_) {
       element.set_update_phase(UiElement::kUpdatedWorldSpaceTransform);
     }
-    return needs_redraw;
+    return false;
   }
 
   {
@@ -175,7 +174,7 @@
     root_element_->UpdateWorldSpaceTransformRecursive();
   }
 
-  return scene_dirty || needs_redraw;
+  return scene_dirty;
 }
 
 bool UiScene::UpdateTextures() {
diff --git a/chrome/browser/vr/ui_scene_creator.cc b/chrome/browser/vr/ui_scene_creator.cc
index 518ca00..831bdedb 100644
--- a/chrome/browser/vr/ui_scene_creator.cc
+++ b/chrome/browser/vr/ui_scene_creator.cc
@@ -48,6 +48,7 @@
 #include "chrome/browser/vr/ui_scene.h"
 #include "chrome/browser/vr/ui_scene_constants.h"
 #include "chrome/browser/vr/vector_icons/vector_icons.h"
+#include "chrome/common/chrome_features.h"
 #include "chrome/grit/generated_resources.h"
 #include "components/vector_icons/vector_icons.h"
 #include "ui/base/l10n/l10n_util.h"
@@ -996,6 +997,7 @@
           },
           base::Unretained(text_input_model)));
   text_input->set_draw_phase(kPhaseNone);
+  text_input->set_hit_testable(false);
   text_input->SetTextInputDelegate(text_input_delegate);
   text_input->AddBinding(base::MakeUnique<Binding<TextInputInfo>>(
       base::BindRepeating([](TextInputInfo* info) { return *info; },
@@ -1023,11 +1025,24 @@
   scaler->set_name(kUrlBarDmmRoot);
   scene_->AddUiElement(k2dBrowsingForeground, std::move(scaler));
 
+  base::RepeatingCallback<void()> url_click_callback;
+  if (base::FeatureList::IsEnabled(features::kVrBrowserKeyboard)) {
+    url_click_callback = base::BindRepeating(
+        [](Model* m, UiBrowserInterface* browser) {
+          m->omnibox_input_active = true;
+        },
+        base::Unretained(model_), base::Unretained(browser_));
+  } else {
+    url_click_callback = base::BindRepeating([] {});
+  }
+
   auto url_bar = base::MakeUnique<UrlBar>(
       512,
-      base::Bind(&UiBrowserInterface::NavigateBack, base::Unretained(browser_)),
-      base::Bind(&UiBrowserInterface::OnUnsupportedMode,
-                 base::Unretained(browser_)));
+      base::BindRepeating(&UiBrowserInterface::NavigateBack,
+                          base::Unretained(browser_)),
+      url_click_callback,
+      base::BindRepeating(&UiBrowserInterface::OnUnsupportedMode,
+                          base::Unretained(browser_)));
   url_bar->set_name(kUrlBar);
   url_bar->set_draw_phase(kPhaseForeground);
   url_bar->SetTranslate(0, kUrlBarVerticalOffsetDMM, 0);
@@ -1125,6 +1140,8 @@
       VR_BIND(TextInputInfo, Model, model_, omnibox_text_field_info,
               UiBrowserInterface, browser_, StartAutocomplete(value.text)));
   omnibox_text_field->SetSize(width, 0);
+  omnibox_text_field->SetHintText(
+      l10n_util::GetStringUTF16(IDS_SEARCH_OR_TYPE_URL));
   omnibox_text_field->set_name(kOmniboxTextField);
   omnibox_text_field->set_x_anchoring(LEFT);
   omnibox_text_field->set_x_centering(LEFT);
@@ -1143,6 +1160,8 @@
             &TextInput::SetTextColor);
   BindColor(model_, omnibox_text_field.get(), &ColorScheme::cursor,
             &TextInput::SetCursorColor);
+  BindColor(model_, omnibox_text_field.get(), &ColorScheme::omnibox_hint,
+            &TextInput::SetHintColor);
 
   scene_->AddUiElement(kOmniboxContainer, std::move(omnibox_text_field));
 
diff --git a/chrome/browser/vr/ui_unittest.cc b/chrome/browser/vr/ui_unittest.cc
index 7fd84f9..9aeb940 100644
--- a/chrome/browser/vr/ui_unittest.cc
+++ b/chrome/browser/vr/ui_unittest.cc
@@ -67,7 +67,6 @@
     kAudioPermissionPromptBackplane,
     kUrlBar,
     kOmniboxContainer,
-    kOmniboxTextField,
     kLoadingIndicator,
     kWebVrTimeoutSpinner,
     kWebVrTimeoutMessage,
@@ -76,10 +75,8 @@
     kWebVrTimeoutMessageButtonText,
     kSpeechRecognitionResultBackplane,
 };
-const std::set<UiElementName> kSpecialHitTestableElements = {
-    kCloseButton,        kWebVrTimeoutMessageButton,
-    kVoiceSearchButton,  kSpeechRecognitionListeningCloseButton,
-    kOmniboxCloseButton,
+const std::set<UiElementType> kHitTestableElementTypes = {
+    kTypeButtonHitTarget, kTypeTextInputText,
 };
 const std::set<UiElementName> kElementsVisibleWithExitWarning = {
     kScreenDimmer, kExitWarning,
@@ -167,30 +164,6 @@
          base::IsApproximatelyEqual(arg.height(), other.height(), tolerance);
 }
 
-void CheckHitTestableRecursive(UiElement* element) {
-  // This shouldn't be necessary in the future once crbug.com/782395 is fixed.
-  // we can use class name to identify a child element in a composited element
-  // such as Button.
-  if (kSpecialHitTestableElements.find(element->name()) !=
-      kSpecialHitTestableElements.end()) {
-    bool has_hittestable_child = false;
-    for (auto& child : *element) {
-      if (child.hit_testable())
-        has_hittestable_child = true;
-    }
-    EXPECT_TRUE(has_hittestable_child)
-        << "element name: " << UiElementNameToString(element->name());
-    return;
-  }
-  const bool should_be_hit_testable =
-      kHitTestableElements.find(element->name()) != kHitTestableElements.end();
-  EXPECT_EQ(should_be_hit_testable, element->hit_testable())
-      << "element name: " << UiElementNameToString(element->name());
-  for (const auto& child : element->children()) {
-    CheckHitTestableRecursive(child.get());
-  }
-}
-
 void VerifyButtonColor(Button* button,
                        SkColor foreground_color,
                        SkColor background_color,
@@ -679,8 +652,21 @@
 
 TEST_F(UiTest, HitTestableElements) {
   CreateScene(kNotInCct, kNotInWebVr);
-  EXPECT_TRUE(RunFor(MsToDelta(0)));
-  CheckHitTestableRecursive(&scene_->root_element());
+  for (const auto& element : scene_->root_element()) {
+    if (element.type() != kTypeNone) {
+      const bool should_be_hit_testable =
+          kHitTestableElementTypes.find(element.type()) !=
+          kHitTestableElementTypes.end();
+      EXPECT_EQ(should_be_hit_testable, element.hit_testable())
+          << "element type: " << UiElementTypeToString(element.type());
+    } else {
+      const bool should_be_hit_testable =
+          kHitTestableElements.find(element.name()) !=
+          kHitTestableElements.end();
+      EXPECT_EQ(should_be_hit_testable, element.hit_testable())
+          << "element name: " << UiElementNameToString(element.name());
+    }
+  }
 }
 
 TEST_F(UiTest, DontPropagateContentBoundsOnNegligibleChange) {
diff --git a/chrome/browser/webshare/share_service_impl.cc b/chrome/browser/webshare/share_service_impl.cc
index b77ead9..df456cae 100644
--- a/chrome/browser/webshare/share_service_impl.cc
+++ b/chrome/browser/webshare/share_service_impl.cc
@@ -9,6 +9,7 @@
 #include <map>
 #include <utility>
 
+#include "base/strings/strcat.h"
 #include "base/strings/string_util.h"
 #include "chrome/browser/engagement/site_engagement_service.h"
 #include "chrome/browser/profiles/profile.h"
@@ -100,7 +101,7 @@
   split_template.push_back(url_template.substr(
       start_index_to_copy, url_template.size() - start_index_to_copy));
 
-  *url_template_filled = base::JoinString(split_template, base::StringPiece());
+  *url_template_filled = base::StrCat(split_template);
   return true;
 }
 
diff --git a/chrome/common/custom_handlers/protocol_handler.cc b/chrome/common/custom_handlers/protocol_handler.cc
index 85749b3f..32aa1998 100644
--- a/chrome/common/custom_handlers/protocol_handler.cc
+++ b/chrome/common/custom_handlers/protocol_handler.cc
@@ -54,7 +54,8 @@
 
 GURL ProtocolHandler::TranslateUrl(const GURL& url) const {
   std::string translatedUrlSpec(url_.spec());
-  base::ReplaceSubstringsAfterOffset(&translatedUrlSpec, 0, "%s",
+  base::ReplaceFirstSubstringAfterOffset(
+      &translatedUrlSpec, 0, "%s",
       net::EscapeQueryParamValue(url.spec(), true));
   return GURL(translatedUrlSpec);
 }
diff --git a/chrome/common/extensions/api/developer_private.idl b/chrome/common/extensions/api/developer_private.idl
index 8f5b54d..88d2439 100644
--- a/chrome/common/extensions/api/developer_private.idl
+++ b/chrome/common/extensions/api/developer_private.idl
@@ -300,6 +300,11 @@
     // If false, an alert dialog will show in the event of a reload error.
     // Defaults to false.
     boolean? failQuietly;
+
+    // If true, populates a LoadError for the response rather than setting
+    // lastError. Only relevant for unpacked extensions; it will be ignored for
+    // any other extension.
+    boolean? populateErrorForUnpacked;
   };
 
   dictionary LoadUnpackedOptions {
@@ -533,7 +538,7 @@
     // |options| : Additional configuration parameters.
     static void reload(DOMString extensionId,
                        optional ReloadOptions options,
-                       optional VoidCallback callback);
+                       optional LoadErrorCallback callback);
 
     // Modifies an extension's current configuration.
     // |update| : The parameters for updating the extension's configuration.
diff --git a/chrome/common/extensions/feature_switch_unittest.cc b/chrome/common/extensions/feature_switch_unittest.cc
index 1125efcd..98fc911d 100644
--- a/chrome/common/extensions/feature_switch_unittest.cc
+++ b/chrome/common/extensions/feature_switch_unittest.cc
@@ -5,7 +5,6 @@
 #include "extensions/common/feature_switch.h"
 
 #include "base/command_line.h"
-#include "base/metrics/field_trial.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 using extensions::FeatureSwitch;
@@ -13,30 +12,6 @@
 namespace {
 
 const char kSwitchName[] = "test-switch";
-const char kFieldTrialName[] = "field-trial";
-
-// Create and register a field trial that will always return the given
-// |group_name|.
-scoped_refptr<base::FieldTrial> CreateFieldTrial(
-    const std::string& group_name) {
-  const int kTotalProbability = 10;
-  // Note: This code will probably fail in the year 5000. But all the cycles we
-  // save in the next 3000 years by not determining the current year will be
-  // worth it.
-  scoped_refptr<base::FieldTrial> trial =
-      base::FieldTrialList::FactoryGetFieldTrial(
-          kFieldTrialName, kTotalProbability, "default",
-// TODO(maksims): remove architecture check
-// in the future. https://crbug.com/619828
-#if defined(OS_LINUX) && defined(ARCH_CPU_64_BITS)
-          5000,
-#else
-          2038,
-#endif
-          1, 1, base::FieldTrial::SESSION_RANDOMIZED, nullptr);
-  trial->AppendGroup(group_name, kTotalProbability);
-  return trial;
-}
 
 template<FeatureSwitch::DefaultValue T>
 class FeatureSwitchTest : public testing::Test {
@@ -155,135 +130,3 @@
   command_line_.AppendSwitchASCII(kSwitchName, "\t\t 0 \n");
   EXPECT_FALSE(feature_.IsEnabled());
 }
-
-TEST_F(FeatureSwitchEnabledTest, TrueFieldTrialValue) {
-  // Construct a fake field trial that defaults to the group "Enabled".
-  base::FieldTrialList field_trials(nullptr);
-  scoped_refptr<base::FieldTrial> enabled_trial = CreateFieldTrial("Enabled");
-  {
-    // A default-enabled switch should be enabled (naturally).
-    FeatureSwitch default_enabled_switch(&command_line_, kSwitchName,
-                                         kFieldTrialName,
-                                         FeatureSwitch::DEFAULT_ENABLED);
-    EXPECT_TRUE(default_enabled_switch.IsEnabled());
-    // Scoped overrides override everything.
-    FeatureSwitch::ScopedOverride scoped_override(&default_enabled_switch,
-                                                  false);
-    EXPECT_FALSE(default_enabled_switch.IsEnabled());
-  }
-
-  {
-    // A default-disabled switch should be enabled because of the field trial.
-    FeatureSwitch default_disabled_switch(&command_line_, kSwitchName,
-                                          kFieldTrialName,
-                                          FeatureSwitch::DEFAULT_DISABLED);
-    EXPECT_TRUE(default_disabled_switch.IsEnabled());
-    // Scoped overrides override everything.
-    FeatureSwitch::ScopedOverride scoped_override(&default_disabled_switch,
-                                                  false);
-    EXPECT_FALSE(default_disabled_switch.IsEnabled());
-  }
-}
-
-TEST_F(FeatureSwitchEnabledTest, TrueFieldTrialDogfoodValue) {
-  // Construct a fake field trial that defaults to the group "Enabled_Dogfood".
-  base::FieldTrialList field_trials(nullptr);
-  scoped_refptr<base::FieldTrial> enabled_trial =
-      CreateFieldTrial("Enabled_Dogfood");
-  {
-    // A default-enabled switch should be enabled (naturally).
-    FeatureSwitch default_enabled_switch(&command_line_, kSwitchName,
-                                         kFieldTrialName,
-                                         FeatureSwitch::DEFAULT_ENABLED);
-    EXPECT_TRUE(default_enabled_switch.IsEnabled());
-    // Scoped overrides override everything.
-    FeatureSwitch::ScopedOverride scoped_override(&default_enabled_switch,
-                                                  false);
-    EXPECT_FALSE(default_enabled_switch.IsEnabled());
-  }
-
-  {
-    // A default-disabled switch should be enabled because of the field trial.
-    FeatureSwitch default_disabled_switch(&command_line_, kSwitchName,
-                                          kFieldTrialName,
-                                          FeatureSwitch::DEFAULT_DISABLED);
-    EXPECT_TRUE(default_disabled_switch.IsEnabled());
-    // Scoped overrides override everything.
-    FeatureSwitch::ScopedOverride scoped_override(&default_disabled_switch,
-                                                  false);
-    EXPECT_FALSE(default_disabled_switch.IsEnabled());
-  }
-}
-
-TEST_F(FeatureSwitchEnabledTest, FalseFieldTrialValue) {
-  // Construct a fake field trial that defaults to the group "Disabled".
-  base::FieldTrialList field_trials(nullptr);
-  scoped_refptr<base::FieldTrial> disabled_trial = CreateFieldTrial("Disabled");
-  {
-    // A default-enabled switch should be disabled because of the field trial.
-    FeatureSwitch default_enabled_switch(&command_line_, kSwitchName,
-                                         kFieldTrialName,
-                                         FeatureSwitch::DEFAULT_ENABLED);
-    EXPECT_FALSE(default_enabled_switch.IsEnabled());
-    // Scoped overrides override everything.
-    FeatureSwitch::ScopedOverride scoped_override(&default_enabled_switch,
-                                                  true);
-    EXPECT_TRUE(default_enabled_switch.IsEnabled());
-  }
-
-  {
-    // A default-disabled switch should remain disabled.
-    FeatureSwitch default_disabled_switch(&command_line_, kSwitchName,
-                                          kFieldTrialName,
-                                          FeatureSwitch::DEFAULT_DISABLED);
-    EXPECT_FALSE(default_disabled_switch.IsEnabled());
-    // Scoped overrides override everything.
-    FeatureSwitch::ScopedOverride scoped_override(&default_disabled_switch,
-                                                  true);
-    EXPECT_TRUE(default_disabled_switch.IsEnabled());
-  }
-}
-
-TEST_F(FeatureSwitchEnabledTest, FalseFieldTrialDogfoodValue) {
-  // Construct a fake field trial that defaults to the group "Disabled_Dogfood".
-  base::FieldTrialList field_trials(nullptr);
-  scoped_refptr<base::FieldTrial> disabled_trial =
-      CreateFieldTrial("Disabled_Dogfood");
-  {
-    // A default-enabled switch should be disabled because of the field trial.
-    FeatureSwitch default_enabled_switch(&command_line_, kSwitchName,
-                                         kFieldTrialName,
-                                         FeatureSwitch::DEFAULT_ENABLED);
-    EXPECT_FALSE(default_enabled_switch.IsEnabled());
-  }
-
-  {
-    // A default-disabled switch should remain disabled.
-    FeatureSwitch default_disabled_switch(&command_line_, kSwitchName,
-                                          kFieldTrialName,
-                                          FeatureSwitch::DEFAULT_DISABLED);
-    EXPECT_FALSE(default_disabled_switch.IsEnabled());
-  }
-}
-
-TEST_F(FeatureSwitchEnabledTest, InvalidGroupFieldTrial) {
-  // Construct a fake field trial that defaults to the group "InvalidGroup".
-  base::FieldTrialList field_trials(nullptr);
-  scoped_refptr<base::FieldTrial> disabled_trial =
-      CreateFieldTrial("InvalidGroup");
-  {
-    // A default-enabled switch should be enabled (the group has no effect).
-    FeatureSwitch default_enabled_switch(&command_line_, kSwitchName,
-                                         kFieldTrialName,
-                                         FeatureSwitch::DEFAULT_ENABLED);
-    EXPECT_TRUE(default_enabled_switch.IsEnabled());
-  }
-
-  {
-    // A default-disabled switch should remain disabled.
-    FeatureSwitch default_disabled_switch(&command_line_, kSwitchName,
-                                          kFieldTrialName,
-                                          FeatureSwitch::DEFAULT_DISABLED);
-    EXPECT_FALSE(default_disabled_switch.IsEnabled());
-  }
-}
diff --git a/chrome/common/printing/pdf_render_settings.mojom b/chrome/common/printing/pdf_render_settings.mojom
index 1a81b8b8..d25c3a7 100644
--- a/chrome/common/printing/pdf_render_settings.mojom
+++ b/chrome/common/printing/pdf_render_settings.mojom
@@ -6,7 +6,7 @@
 

 import "ui/gfx/geometry/mojo/geometry.mojom";

 

-struct PDFRenderSettings {

+struct PdfRenderSettings {

   enum Mode {

     NORMAL = 0,

     // Modes below are Windows only.

diff --git a/chrome/common/printing/pdf_render_settings.typemap b/chrome/common/printing/pdf_render_settings.typemap
index 0aa0330..34898fb0 100644
--- a/chrome/common/printing/pdf_render_settings.typemap
+++ b/chrome/common/printing/pdf_render_settings.typemap
@@ -17,6 +17,6 @@
 ]
 
 type_mappings = [
-  "printing.mojom.PDFRenderSettings=printing::PdfRenderSettings",
-  "printing.mojom.PDFRenderSettings::Mode=printing::PdfRenderSettings::Mode",
+  "printing.mojom.PdfRenderSettings=printing::PdfRenderSettings",
+  "printing.mojom.PdfRenderSettings::Mode=printing::PdfRenderSettings::Mode",
 ]
diff --git a/chrome/common/printing/pdf_render_settings_struct_traits.cc b/chrome/common/printing/pdf_render_settings_struct_traits.cc
index ca0a1479..37c5346 100644
--- a/chrome/common/printing/pdf_render_settings_struct_traits.cc
+++ b/chrome/common/printing/pdf_render_settings_struct_traits.cc
@@ -9,9 +9,9 @@
 namespace mojo {
 
 // static
-bool StructTraits<printing::mojom::PDFRenderSettingsDataView,
+bool StructTraits<printing::mojom::PdfRenderSettingsDataView,
                   printing::PdfRenderSettings>::
-    Read(printing::mojom::PDFRenderSettingsDataView data,
+    Read(printing::mojom::PdfRenderSettingsDataView data,
          printing::PdfRenderSettings* out) {
   out->dpi = data.dpi();
   out->autorotate = data.autorotate();
diff --git a/chrome/common/printing/pdf_render_settings_struct_traits.h b/chrome/common/printing/pdf_render_settings_struct_traits.h
index 6b3a50e..994d597 100644
--- a/chrome/common/printing/pdf_render_settings_struct_traits.h
+++ b/chrome/common/printing/pdf_render_settings_struct_traits.h
@@ -12,52 +12,52 @@
 namespace mojo {
 
 template <>
-struct EnumTraits<printing::mojom::PDFRenderSettings::Mode,
+struct EnumTraits<printing::mojom::PdfRenderSettings::Mode,
                   printing::PdfRenderSettings::Mode> {
-  static printing::mojom::PDFRenderSettings::Mode ToMojom(
+  static printing::mojom::PdfRenderSettings::Mode ToMojom(
       printing::PdfRenderSettings::Mode mode) {
     switch (mode) {
       case printing::PdfRenderSettings::Mode::NORMAL:
-        return printing::mojom::PDFRenderSettings::Mode::NORMAL;
+        return printing::mojom::PdfRenderSettings::Mode::NORMAL;
 #if defined(OS_WIN)
       case printing::PdfRenderSettings::Mode::TEXTONLY:
-        return printing::mojom::PDFRenderSettings::Mode::TEXTONLY;
+        return printing::mojom::PdfRenderSettings::Mode::TEXTONLY;
       case printing::PdfRenderSettings::Mode::GDI_TEXT:
-        return printing::mojom::PDFRenderSettings::Mode::GDI_TEXT;
+        return printing::mojom::PdfRenderSettings::Mode::GDI_TEXT;
       case printing::PdfRenderSettings::Mode::POSTSCRIPT_LEVEL2:
-        return printing::mojom::PDFRenderSettings::Mode::POSTSCRIPT_LEVEL2;
+        return printing::mojom::PdfRenderSettings::Mode::POSTSCRIPT_LEVEL2;
       case printing::PdfRenderSettings::Mode::POSTSCRIPT_LEVEL3:
-        return printing::mojom::PDFRenderSettings::Mode::POSTSCRIPT_LEVEL3;
+        return printing::mojom::PdfRenderSettings::Mode::POSTSCRIPT_LEVEL3;
 #endif
     }
     NOTREACHED() << "Unknown mode " << static_cast<int>(mode);
-    return printing::mojom::PDFRenderSettings::Mode::NORMAL;
+    return printing::mojom::PdfRenderSettings::Mode::NORMAL;
   }
 
-  static bool FromMojom(printing::mojom::PDFRenderSettings::Mode input,
+  static bool FromMojom(printing::mojom::PdfRenderSettings::Mode input,
                         printing::PdfRenderSettings::Mode* output) {
     switch (input) {
-      case printing::mojom::PDFRenderSettings::Mode::NORMAL:
+      case printing::mojom::PdfRenderSettings::Mode::NORMAL:
         *output = printing::PdfRenderSettings::Mode::NORMAL;
         return true;
 #if defined(OS_WIN)
-      case printing::mojom::PDFRenderSettings::Mode::TEXTONLY:
+      case printing::mojom::PdfRenderSettings::Mode::TEXTONLY:
         *output = printing::PdfRenderSettings::Mode::TEXTONLY;
         return true;
-      case printing::mojom::PDFRenderSettings::Mode::GDI_TEXT:
+      case printing::mojom::PdfRenderSettings::Mode::GDI_TEXT:
         *output = printing::PdfRenderSettings::Mode::GDI_TEXT;
         return true;
-      case printing::mojom::PDFRenderSettings::Mode::POSTSCRIPT_LEVEL2:
+      case printing::mojom::PdfRenderSettings::Mode::POSTSCRIPT_LEVEL2:
         *output = printing::PdfRenderSettings::Mode::POSTSCRIPT_LEVEL2;
         return true;
-      case printing::mojom::PDFRenderSettings::Mode::POSTSCRIPT_LEVEL3:
+      case printing::mojom::PdfRenderSettings::Mode::POSTSCRIPT_LEVEL3:
         *output = printing::PdfRenderSettings::Mode::POSTSCRIPT_LEVEL3;
         return true;
 #else
-      case printing::mojom::PDFRenderSettings::Mode::TEXTONLY:
-      case printing::mojom::PDFRenderSettings::Mode::GDI_TEXT:
-      case printing::mojom::PDFRenderSettings::Mode::POSTSCRIPT_LEVEL2:
-      case printing::mojom::PDFRenderSettings::Mode::POSTSCRIPT_LEVEL3:
+      case printing::mojom::PdfRenderSettings::Mode::TEXTONLY:
+      case printing::mojom::PdfRenderSettings::Mode::GDI_TEXT:
+      case printing::mojom::PdfRenderSettings::Mode::POSTSCRIPT_LEVEL2:
+      case printing::mojom::PdfRenderSettings::Mode::POSTSCRIPT_LEVEL3:
         NOTREACHED() << "Unsupported mode " << static_cast<int>(input)
                      << " on non Windows platform ";
         return false;
@@ -69,7 +69,7 @@
 };
 
 template <>
-class StructTraits<printing::mojom::PDFRenderSettingsDataView,
+class StructTraits<printing::mojom::PdfRenderSettingsDataView,
                    printing::PdfRenderSettings> {
  public:
   static gfx::Rect area(const printing::PdfRenderSettings& settings) {
@@ -89,7 +89,7 @@
     return settings.mode;
   }
 
-  static bool Read(printing::mojom::PDFRenderSettingsDataView data,
+  static bool Read(printing::mojom::PdfRenderSettingsDataView data,
                    printing::PdfRenderSettings* out_settings);
 };
 
diff --git a/chrome/common/printing/pdf_to_pwg_raster_converter.mojom b/chrome/common/printing/pdf_to_pwg_raster_converter.mojom
index 6d926cb..1860a95 100644
--- a/chrome/common/printing/pdf_to_pwg_raster_converter.mojom
+++ b/chrome/common/printing/pdf_to_pwg_raster_converter.mojom
@@ -9,7 +9,7 @@
 const string kPdfToPwgRasterConverterServiceName =
     "pdf_to_pwg_raster_converter";
 
-struct PWGRasterSettings {
+struct PwgRasterSettings {
   enum TransformType {
     TRANSFORM_NORMAL,
     TRANSFORM_ROTATE_180,
@@ -27,9 +27,9 @@
   bool reverse_page_order;
 };
 
-interface PDFToPWGRasterConverter {
+interface PdfToPwgRasterConverter {
   Convert(handle pdf_file_in,
-          PDFRenderSettings pdf_settings,
-          PWGRasterSettings pwg_raster_settings,
+          PdfRenderSettings pdf_settings,
+          PwgRasterSettings pwg_raster_settings,
           handle pwg_raster_file_out) => (bool success);
 };
diff --git a/chrome/common/printing/pdf_to_pwg_raster_converter.typemap b/chrome/common/printing/pdf_to_pwg_raster_converter.typemap
index b451070..12631386 100644
--- a/chrome/common/printing/pdf_to_pwg_raster_converter.typemap
+++ b/chrome/common/printing/pdf_to_pwg_raster_converter.typemap
@@ -7,6 +7,6 @@
 ]
 public_deps = []
 type_mappings = [
-  "printing.mojom.PWGRasterTransformType=printing::PwgRasterTransformType",
-  "printing.mojom.PWGRasterSettings=printing::PwgRasterSettings",
+  "printing.mojom.PwgRasterTransformType=printing::PwgRasterTransformType",
+  "printing.mojom.PwgRasterSettings=printing::PwgRasterSettings",
 ]
diff --git a/chrome/common/printing/pdf_to_pwg_raster_converter_struct_traits.cc b/chrome/common/printing/pdf_to_pwg_raster_converter_struct_traits.cc
index 430a327..1383f77 100644
--- a/chrome/common/printing/pdf_to_pwg_raster_converter_struct_traits.cc
+++ b/chrome/common/printing/pdf_to_pwg_raster_converter_struct_traits.cc
@@ -7,9 +7,9 @@
 namespace mojo {
 
 // static
-bool StructTraits<printing::mojom::PWGRasterSettingsDataView,
+bool StructTraits<printing::mojom::PwgRasterSettingsDataView,
                   printing::PwgRasterSettings>::
-    Read(printing::mojom::PWGRasterSettingsDataView data,
+    Read(printing::mojom::PwgRasterSettingsDataView data,
          printing::PwgRasterSettings* out) {
   out->rotate_all_pages = data.rotate_all_pages();
   out->reverse_page_order = data.reverse_page_order();
diff --git a/chrome/common/printing/pdf_to_pwg_raster_converter_struct_traits.h b/chrome/common/printing/pdf_to_pwg_raster_converter_struct_traits.h
index a5796e6..2fcfca4 100644
--- a/chrome/common/printing/pdf_to_pwg_raster_converter_struct_traits.h
+++ b/chrome/common/printing/pdf_to_pwg_raster_converter_struct_traits.h
@@ -12,44 +12,44 @@
 namespace mojo {
 
 template <>
-struct EnumTraits<printing::mojom::PWGRasterSettings::TransformType,
+struct EnumTraits<printing::mojom::PwgRasterSettings::TransformType,
                   printing::PwgRasterTransformType> {
-  static printing::mojom::PWGRasterSettings::TransformType ToMojom(
+  static printing::mojom::PwgRasterSettings::TransformType ToMojom(
       printing::PwgRasterTransformType transform_type) {
     switch (transform_type) {
       case printing::PwgRasterTransformType::TRANSFORM_NORMAL:
-        return printing::mojom::PWGRasterSettings::TransformType::
+        return printing::mojom::PwgRasterSettings::TransformType::
             TRANSFORM_NORMAL;
       case printing::PwgRasterTransformType::TRANSFORM_ROTATE_180:
-        return printing::mojom::PWGRasterSettings::TransformType::
+        return printing::mojom::PwgRasterSettings::TransformType::
             TRANSFORM_ROTATE_180;
       case printing::PwgRasterTransformType::TRANSFORM_FLIP_HORIZONTAL:
-        return printing::mojom::PWGRasterSettings::TransformType::
+        return printing::mojom::PwgRasterSettings::TransformType::
             TRANSFORM_FLIP_HORIZONTAL;
       case printing::PwgRasterTransformType::TRANSFORM_FLIP_VERTICAL:
-        return printing::mojom::PWGRasterSettings::TransformType::
+        return printing::mojom::PwgRasterSettings::TransformType::
             TRANSFORM_FLIP_VERTICAL;
     }
     NOTREACHED() << "Unknown transform type "
                  << static_cast<int>(transform_type);
-    return printing::mojom::PWGRasterSettings::TransformType::TRANSFORM_NORMAL;
+    return printing::mojom::PwgRasterSettings::TransformType::TRANSFORM_NORMAL;
   }
 
-  static bool FromMojom(printing::mojom::PWGRasterSettings::TransformType input,
+  static bool FromMojom(printing::mojom::PwgRasterSettings::TransformType input,
                         printing::PwgRasterTransformType* output) {
     switch (input) {
-      case printing::mojom::PWGRasterSettings::TransformType::TRANSFORM_NORMAL:
+      case printing::mojom::PwgRasterSettings::TransformType::TRANSFORM_NORMAL:
         *output = printing::PwgRasterTransformType::TRANSFORM_NORMAL;
         return true;
-      case printing::mojom::PWGRasterSettings::TransformType::
+      case printing::mojom::PwgRasterSettings::TransformType::
           TRANSFORM_ROTATE_180:
         *output = printing::PwgRasterTransformType::TRANSFORM_ROTATE_180;
         return true;
-      case printing::mojom::PWGRasterSettings::TransformType::
+      case printing::mojom::PwgRasterSettings::TransformType::
           TRANSFORM_FLIP_HORIZONTAL:
         *output = printing::PwgRasterTransformType::TRANSFORM_FLIP_HORIZONTAL;
         return true;
-      case printing::mojom::PWGRasterSettings::TransformType::
+      case printing::mojom::PwgRasterSettings::TransformType::
           TRANSFORM_FLIP_VERTICAL:
         *output = printing::PwgRasterTransformType::TRANSFORM_FLIP_VERTICAL;
         return true;
@@ -60,7 +60,7 @@
 };
 
 template <>
-class StructTraits<printing::mojom::PWGRasterSettingsDataView,
+class StructTraits<printing::mojom::PwgRasterSettingsDataView,
                    printing::PwgRasterSettings> {
  public:
   static bool rotate_all_pages(const printing::PwgRasterSettings& settings) {
@@ -74,7 +74,7 @@
     return settings.odd_page_transform;
   }
 
-  static bool Read(printing::mojom::PWGRasterSettingsDataView data,
+  static bool Read(printing::mojom::PwgRasterSettingsDataView data,
                    printing::PwgRasterSettings* out_settings);
 };
 
diff --git a/chrome/installer/linux/BUILD.gn b/chrome/installer/linux/BUILD.gn
index 225c6fd..5f4cd50e 100644
--- a/chrome/installer/linux/BUILD.gn
+++ b/chrome/installer/linux/BUILD.gn
@@ -431,6 +431,8 @@
       rebase_path(root_out_dir, root_build_dir),
       "-s",
       rebase_path(sysroot, root_build_dir),
+      "-t",
+      target_os,
     ]
     if (is_official_build) {
       args += [ "-f" ]
@@ -481,6 +483,8 @@
         branding_path_component,
         "-o",
         rebase_path(root_out_dir, root_build_dir),
+        "-t",
+        target_os,
       ]
       if (is_official_build) {
         args += [ "-f" ]
diff --git a/chrome/installer/linux/common/installer.include b/chrome/installer/linux/common/installer.include
index 4c460fc..71e8c3f7 100644
--- a/chrome/installer/linux/common/installer.include
+++ b/chrome/installer/linux/common/installer.include
@@ -329,10 +329,25 @@
     exit 1
   fi
 
+  # Check to make sure no ELF binaries set RPATH.
+  if [ "${TARGET_OS}" != "chromeos" ]; then
+    RPATH_BINS=
+    for elf in $(find "${STAGEDIR}/${INSTALLDIR}/" -type f | xargs file |
+                   grep ELF | awk '{print $1;}' | sed 's/:$//'); do
+      if readelf -d ${elf} | grep "(RPATH)" >/dev/null; then
+        RPATH_BINS="${RPATH_BINS} $(basename ${elf})"
+      fi
+    done
+    if [ -n "${RPATH_BINS}" ]; then
+      echo "ERROR: Found binaries with RPATH set:${RPATH_BINS}" 1>&2
+      exit 1
+    fi
+  fi
+
   # Make sure ELF binaries live in INSTALLDIR exclusively.
   ELF_OUTSIDE_INSTALLDIR=$(find "${STAGEDIR}/" -not -path \
     "${STAGEDIR}${INSTALLDIR}/*" -type f | xargs file -b |
-    grep -ce "^ELF" || true)
+                             grep -ce "^ELF" || true)
   if [ "${ELF_OUTSIDE_INSTALLDIR}" -ne 0 ]; then
     echo "ERROR: Found ${ELF_OUTSIDE_INSTALLDIR} ELF binaries" \
       "outside of ${INSTALLDIR}" 1>&2
diff --git a/chrome/installer/linux/debian/build.sh b/chrome/installer/linux/debian/build.sh
index a91c416c..7911a62 100755
--- a/chrome/installer/linux/debian/build.sh
+++ b/chrome/installer/linux/debian/build.sh
@@ -135,15 +135,16 @@
 
 usage() {
   echo "usage: $(basename $0) [-a target_arch] [-b 'dir'] -c channel"
-  echo "                      -d branding [-f] [-o 'dir'] -s 'dir'"
-  echo "-a arch     package architecture (ia32 or x64)"
-  echo "-b dir      build input directory    [${BUILDDIR}]"
-  echo "-c channel  the package channel (unstable, beta, stable)"
-  echo "-d brand    either chromium or google_chrome"
-  echo "-f          indicates that this is an official build"
-  echo "-h          this help message"
-  echo "-o dir      package output directory [${OUTPUTDIR}]"
-  echo "-s dir      /path/to/sysroot"
+  echo "                      -d branding [-f] [-o 'dir'] -s 'dir' -t target_os"
+  echo "-a arch      package architecture (ia32 or x64)"
+  echo "-b dir       build input directory    [${BUILDDIR}]"
+  echo "-c channel   the package channel (unstable, beta, stable)"
+  echo "-d brand     either chromium or google_chrome"
+  echo "-f           indicates that this is an official build"
+  echo "-h           this help message"
+  echo "-o dir       package output directory [${OUTPUTDIR}]"
+  echo "-s dir       /path/to/sysroot"
+  echo "-t platform  target platform"
 }
 
 # Check that the channel name is one of the allowable ones.
@@ -171,7 +172,7 @@
 }
 
 process_opts() {
-  while getopts ":a:b:c:d:fho:s:" OPTNAME
+  while getopts ":a:b:c:d:fho:s:t:" OPTNAME
   do
     case $OPTNAME in
       a )
@@ -200,6 +201,9 @@
       s )
         SYSROOT="$OPTARG"
         ;;
+      t )
+        TARGET_OS="$OPTARG"
+        ;;
      \: )
         echo "'-$OPTARG' needs an argument."
         usage
diff --git a/chrome/installer/linux/rpm/build.sh b/chrome/installer/linux/rpm/build.sh
index d1397286..0bb07c6 100755
--- a/chrome/installer/linux/rpm/build.sh
+++ b/chrome/installer/linux/rpm/build.sh
@@ -126,7 +126,7 @@
 
 usage() {
   echo "usage: $(basename $0) [-a target_arch] [-b 'dir'] -c channel"
-  echo "                      -d branding [-f] [-o 'dir']"
+  echo "                      -d branding [-f] [-o 'dir'] -t target_os"
   echo "-a arch     package architecture (ia32 or x64)"
   echo "-b dir      build input directory    [${BUILDDIR}]"
   echo "-c channel  the package channel (unstable, beta, stable)"
@@ -134,6 +134,7 @@
   echo "-f          indicates that this is an official build"
   echo "-h          this help message"
   echo "-o dir      package output directory [${OUTPUTDIR}]"
+  echo "-t platform target platform"
 }
 
 # Check that the channel name is one of the allowable ones.
@@ -158,7 +159,7 @@
 }
 
 process_opts() {
-  while getopts ":a:b:c:d:fho:" OPTNAME
+  while getopts ":a:b:c:d:fho:t:" OPTNAME
   do
     case $OPTNAME in
       a )
@@ -185,7 +186,10 @@
         OUTPUTDIR=$(readlink -f "${OPTARG}")
         mkdir -p "${OUTPUTDIR}"
         ;;
-      \: )
+      t )
+        TARGET_OS="$OPTARG"
+        ;;
+     \: )
         echo "'-$OPTARG' needs an argument."
         usage
         exit 1
diff --git a/chrome/renderer/extensions/extension_hooks_delegate.cc b/chrome/renderer/extensions/extension_hooks_delegate.cc
index 4e4577ea..a820d7c 100644
--- a/chrome/renderer/extensions/extension_hooks_delegate.cc
+++ b/chrome/renderer/extensions/extension_hooks_delegate.cc
@@ -10,11 +10,11 @@
 #include "extensions/common/extension.h"
 #include "extensions/common/manifest.h"
 #include "extensions/renderer/bindings/api_signature.h"
+#include "extensions/renderer/get_script_context.h"
 #include "extensions/renderer/message_target.h"
 #include "extensions/renderer/messaging_util.h"
 #include "extensions/renderer/native_renderer_messaging_service.h"
 #include "extensions/renderer/script_context.h"
-#include "extensions/renderer/script_context_set.h"
 #include "gin/converter.h"
 
 namespace extensions {
@@ -112,9 +112,7 @@
       // TODO(devlin): Add getBackgroundPage, getExtensionTabs, getViews.
   };
 
-  ScriptContext* script_context =
-      ScriptContextSet::GetContextByV8Context(context);
-  DCHECK(script_context);
+  ScriptContext* script_context = GetScriptContextFromV8ContextChecked(context);
 
   Handler handler = nullptr;
   for (const auto& handler_entry : kHandlers) {
@@ -166,7 +164,7 @@
   // isn't terribly efficient, but is only done for certain unpacked extensions
   // and only if they access the chrome.extension module.
   if (messaging_util::IsSendRequestDisabled(
-          ScriptContextSet::GetContextByV8Context(context))) {
+          GetScriptContextFromV8ContextChecked(context))) {
     static constexpr const char* kDeprecatedSendRequestProperties[] = {
         "sendRequest", "onRequest", "onRequestExternal"};
     for (const char* property : kDeprecatedSendRequestProperties) {
diff --git a/chrome/renderer/extensions/tabs_hooks_delegate.cc b/chrome/renderer/extensions/tabs_hooks_delegate.cc
index 81739d2..1dc3c47 100644
--- a/chrome/renderer/extensions/tabs_hooks_delegate.cc
+++ b/chrome/renderer/extensions/tabs_hooks_delegate.cc
@@ -10,11 +10,11 @@
 #include "extensions/common/extension.h"
 #include "extensions/common/manifest.h"
 #include "extensions/renderer/bindings/api_signature.h"
+#include "extensions/renderer/get_script_context.h"
 #include "extensions/renderer/message_target.h"
 #include "extensions/renderer/messaging_util.h"
 #include "extensions/renderer/native_renderer_messaging_service.h"
 #include "extensions/renderer/script_context.h"
-#include "extensions/renderer/script_context_set.h"
 #include "gin/converter.h"
 
 namespace extensions {
@@ -53,9 +53,7 @@
       {&TabsHooksDelegate::HandleConnect, kConnect},
   };
 
-  ScriptContext* script_context =
-      ScriptContextSet::GetContextByV8Context(context);
-  DCHECK(script_context);
+  ScriptContext* script_context = GetScriptContextFromV8ContextChecked(context);
 
   Handler handler = nullptr;
   for (const auto& handler_entry : kHandlers) {
diff --git a/chrome/renderer/media/cast_session_delegate.cc b/chrome/renderer/media/cast_session_delegate.cc
index 8e57843..881023e 100644
--- a/chrome/renderer/media/cast_session_delegate.cc
+++ b/chrome/renderer/media/cast_session_delegate.cc
@@ -68,11 +68,11 @@
   // CastSender uses the renderer's IO thread as the main thread. This reduces
   // thread hopping for incoming video frames and outgoing network packets.
   // TODO(hubbe): Create cast environment in ctor instead.
-  cast_environment_ = new CastEnvironment(
-      std::unique_ptr<base::TickClock>(new base::DefaultTickClock()),
-      base::ThreadTaskRunnerHandle::Get(),
-      g_cast_threads.Get().GetAudioEncodeTaskRunner(),
-      g_cast_threads.Get().GetVideoEncodeTaskRunner());
+  cast_environment_ =
+      new CastEnvironment(base::DefaultTickClock::GetInstance(),
+                          base::ThreadTaskRunnerHandle::Get(),
+                          g_cast_threads.Get().GetAudioEncodeTaskRunner(),
+                          g_cast_threads.Get().GetVideoEncodeTaskRunner());
 
   // Rationale for using unretained: The callback cannot be called after the
   // destruction of CastTransportIPC, and they both share the same thread.
diff --git a/chrome/renderer/media/chrome_key_systems_provider.cc b/chrome/renderer/media/chrome_key_systems_provider.cc
index bc3b8a6a..e2a90b7 100644
--- a/chrome/renderer/media/chrome_key_systems_provider.cc
+++ b/chrome/renderer/media/chrome_key_systems_provider.cc
@@ -12,7 +12,7 @@
 ChromeKeySystemsProvider::ChromeKeySystemsProvider()
     : has_updated_(false),
       is_update_needed_(true),
-      tick_clock_(new base::DefaultTickClock()) {}
+      tick_clock_(base::DefaultTickClock::GetInstance()) {}
 
 ChromeKeySystemsProvider::~ChromeKeySystemsProvider() {}
 
@@ -69,8 +69,8 @@
 }
 
 void ChromeKeySystemsProvider::SetTickClockForTesting(
-    std::unique_ptr<base::TickClock> tick_clock) {
-  tick_clock_.swap(tick_clock);
+    base::TickClock* tick_clock) {
+  tick_clock_ = tick_clock;
 }
 
 void ChromeKeySystemsProvider::SetProviderDelegateForTesting(
diff --git a/chrome/renderer/media/chrome_key_systems_provider.h b/chrome/renderer/media/chrome_key_systems_provider.h
index 7650fd0..5e3eb05 100644
--- a/chrome/renderer/media/chrome_key_systems_provider.h
+++ b/chrome/renderer/media/chrome_key_systems_provider.h
@@ -32,7 +32,7 @@
   // less fragile (don't assume AddSupportedKeySystems has just one caller).
   bool IsKeySystemsUpdateNeeded();
 
-  void SetTickClockForTesting(std::unique_ptr<base::TickClock> tick_clock);
+  void SetTickClockForTesting(base::TickClock* tick_clock);
 
   void SetProviderDelegateForTesting(
       const KeySystemsProviderDelegate& test_provider);
@@ -49,7 +49,7 @@
   // Throttle how often we signal an update is needed to avoid unnecessary high
   // frequency of expensive IPC calls.
   base::TimeTicks last_update_time_ticks_;
-  std::unique_ptr<base::TickClock> tick_clock_;
+  base::TickClock* tick_clock_;
 
   // Ensure all methods are called from the same (Main) thread.
   base::ThreadChecker thread_checker_;
diff --git a/chrome/renderer/media/chrome_key_systems_provider_unittest.cc b/chrome/renderer/media/chrome_key_systems_provider_unittest.cc
index 65c02a8..eac8034 100644
--- a/chrome/renderer/media/chrome_key_systems_provider_unittest.cc
+++ b/chrome/renderer/media/chrome_key_systems_provider_unittest.cc
@@ -88,9 +88,8 @@
 TEST(ChromeKeySystemsProviderTest, IsKeySystemsUpdateNeeded) {
   ChromeKeySystemsProvider key_systems_provider;
 
-  base::SimpleTestTickClock* tick_clock = new base::SimpleTestTickClock();
-  key_systems_provider.SetTickClockForTesting(
-      std::unique_ptr<base::TickClock>(tick_clock));
+  base::SimpleTestTickClock tick_clock;
+  key_systems_provider.SetTickClockForTesting(&tick_clock);
 
   std::unique_ptr<TestKeySystemsProviderDelegate> provider_delegate(
       new TestKeySystemsProviderDelegate());
@@ -113,9 +112,9 @@
 
   // This is timing related. The update interval for Widevine is 1000 ms.
   EXPECT_FALSE(key_systems_provider.IsKeySystemsUpdateNeeded());
-  tick_clock->Advance(base::TimeDelta::FromMilliseconds(990));
+  tick_clock.Advance(base::TimeDelta::FromMilliseconds(990));
   EXPECT_FALSE(key_systems_provider.IsKeySystemsUpdateNeeded());
-  tick_clock->Advance(base::TimeDelta::FromMilliseconds(10));
+  tick_clock.Advance(base::TimeDelta::FromMilliseconds(10));
 
 #if defined(WIDEVINE_CDM_AVAILABLE) && defined(WIDEVINE_CDM_IS_COMPONENT)
   // Require update once enough time has passed for builds that install Widevine
@@ -139,9 +138,9 @@
 
   // Update not needed now, nor later because Widevine has been described.
   EXPECT_FALSE(key_systems_provider.IsKeySystemsUpdateNeeded());
-  tick_clock->Advance(base::TimeDelta::FromMilliseconds(1000));
+  tick_clock.Advance(base::TimeDelta::FromMilliseconds(1000));
   EXPECT_FALSE(key_systems_provider.IsKeySystemsUpdateNeeded());
-  tick_clock->Advance(base::TimeDelta::FromMilliseconds(1000));
+  tick_clock.Advance(base::TimeDelta::FromMilliseconds(1000));
   EXPECT_FALSE(key_systems_provider.IsKeySystemsUpdateNeeded());
 #else
   // No update needed for builds that either don't offer Widevine or do so
diff --git a/chrome/renderer/resources/extensions/media_router_bindings.js b/chrome/renderer/resources/extensions/media_router_bindings.js
index 72b6202d..d2b8580 100644
--- a/chrome/renderer/resources/extensions/media_router_bindings.js
+++ b/chrome/renderer/resources/extensions/media_router_bindings.js
@@ -703,7 +703,7 @@
  * TODO(imcheng): We should stop exporting mojo bindings classes that the
  * Media Router extension doesn't directly use, such as
  * mojo.AssociatedInterfacePtrInfo, mojo.InterfacePtrController and
- * mojo.interfaceControl2.
+ * mojo.interfaceControl.
  */
 MediaRouter.prototype.getMojoExports = function() {
   return {
@@ -739,7 +739,7 @@
     SinkExtraData: MediaSinkExtraDataAdapter,
     TimeDelta: mojo.common.mojom.TimeDelta,
     Url: url.mojom.Url,
-    interfaceControl2: mojo.interfaceControl2,
+    interfaceControl: mojo.interfaceControl,
     makeRequest: mojo.makeRequest,
   };
 };
diff --git a/chrome/service/service_process.cc b/chrome/service/service_process.cc
index 727b0f3..be7886b 100644
--- a/chrome/service/service_process.cc
+++ b/chrome/service/service_process.cc
@@ -154,7 +154,6 @@
 #endif  // defined(OS_LINUX) || defined(OS_OPENBSD)
   main_message_loop_ = message_loop;
   service_process_state_.reset(state);
-  network_change_notifier_.reset(net::NetworkChangeNotifier::Create());
 
   // Initialize TaskScheduler and redirect SequencedWorkerPool tasks to it.
   constexpr int kMaxBackgroundThreads = 1;
@@ -174,6 +173,10 @@
 
   base::SequencedWorkerPool::EnableWithRedirectionToTaskSchedulerForProcess();
 
+  // The NetworkChangeNotifier must be created after TaskScheduler because it
+  // posts tasks to it.
+  network_change_notifier_.reset(net::NetworkChangeNotifier::Create());
+
   // Initialize the IO and FILE threads.
   base::Thread::Options options;
   options.message_loop_type = base::MessageLoop::TYPE_IO;
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index fc51a1a..1d38906 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -2246,7 +2246,6 @@
     "../browser/media/android/router/media_router_android_unittest.cc",
     "../browser/media/cast_remoting_connector_unittest.cc",
     "../browser/media/media_engagement_contents_observer_unittest.cc",
-    "../browser/media/media_engagement_preloaded_list_unittest.cc",
     "../browser/media/media_engagement_score_unittest.cc",
     "../browser/media/media_engagement_service_unittest.cc",
     "../browser/media/media_engagement_session_unittest.cc",
@@ -2548,8 +2547,6 @@
 
   data_deps = [
     "//testing/buildbot/filters:unit_tests_filters",
-    "//chrome/test/data/media/engagement/preload:generate_preload_list",
-    "//chrome/test/data/media/engagement/preload:test_data",
   ]
 
   data = [
@@ -2562,7 +2559,6 @@
     "//net/tools/testserver/",
     "//third_party/accessibility-audit/axs_testing.js",
     "//third_party/chaijs/chai.js",
-    "//third_party/hunspell_dictionaries/",
     "//third_party/pyftpdlib/",
     "//third_party/pywebsocket/",
     "//third_party/tlslite/",
diff --git a/chrome/test/base/mash_browser_tests_main.cc b/chrome/test/base/mash_browser_tests_main.cc
index 9f24c6b..e134b74 100644
--- a/chrome/test/base/mash_browser_tests_main.cc
+++ b/chrome/test/base/mash_browser_tests_main.cc
@@ -42,8 +42,10 @@
     content::GetContentMainParams()->env_mode = aura::Env::Mode::MUS;
     content::GetContentMainParams()->create_discardable_memory =
         (config_ == AshConfig::MUS);
-    base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
-        switches::kMus, switches::kMusHostVizValue);
+    if (config_ == AshConfig::MASH) {
+      base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
+          switches::kMus, switches::kMusHostVizValue);
+    }
     return ChromeTestLauncherDelegate::RunTestSuite(argc, argv);
   }
 
diff --git a/chrome/test/chromedriver/test/run_py_tests.py b/chrome/test/chromedriver/test/run_py_tests.py
index ae9be97..59ab731a 100755
--- a/chrome/test/chromedriver/test/run_py_tests.py
+++ b/chrome/test/chromedriver/test/run_py_tests.py
@@ -79,8 +79,6 @@
     'MobileEmulationCapabilityTest.testClickElement',
     'MobileEmulationCapabilityTest.testNetworkConnectionTypeIsAppliedToAllTabs',
     'MobileEmulationCapabilityTest.testNetworkConnectionTypeIsAppliedToAllTabsImmediately',
-    # https://bugs.chromium.org/p/chromedriver/issues/detail?id=2025
-    'ChromeDriverTest.testDoesntHangOnFragmentNavigation',
 ]
 
 _VERSION_SPECIFIC_FILTER = {}
@@ -91,6 +89,16 @@
     'MobileEmulationCapabilityTest.testNetworkConnectionTypeIsAppliedToAllTabsImmediately',
 ]
 
+_VERSION_SPECIFIC_FILTER['64'] = [
+    # https://bugs.chromium.org/p/chromedriver/issues/detail?id=2025
+    'ChromeDriverTest.testDoesntHangOnFragmentNavigation',
+]
+
+_VERSION_SPECIFIC_FILTER['63'] = [
+    # https://bugs.chromium.org/p/chromedriver/issues/detail?id=2025
+    'ChromeDriverTest.testDoesntHangOnFragmentNavigation',
+]
+
 _OS_SPECIFIC_FILTER = {}
 _OS_SPECIFIC_FILTER['win'] = [
     # https://bugs.chromium.org/p/chromedriver/issues/detail?id=299
@@ -111,9 +119,6 @@
     'MobileEmulationCapabilityTest.testTapElement',
     # https://bugs.chromium.org/p/chromedriver/issues/detail?id=1945
     'ChromeDriverTest.testWindowFullScreen',
-    # https://bugs.chromium.org/p/chromedriver/issues/detail?id=2025
-    'ChromeDriverPageLoadTimeoutTest.testHistoryNavigationWithPageLoadTimeout',
-    'ChromeDriverPageLoadTimeoutTest.testRefreshWithPageLoadTimeout',
 ]
 
 _DESKTOP_NEGATIVE_FILTER = [
diff --git a/chrome/test/chromedriver/test/test_expectations b/chrome/test/chromedriver/test/test_expectations
index 020549a..04ab70f6 100644
--- a/chrome/test/chromedriver/test/test_expectations
+++ b/chrome/test/chromedriver/test/test_expectations
@@ -109,15 +109,22 @@
     'UnexpectedAlertBehaviorTest.canSpecifyUnhandledAlertBehaviourUsingCapabilities',
     # https://bugs.chromium.org/p/chromium/issues/detail?id=764519
     'FrameSwitchingTest.testShouldBeAbleToClickInAFrameThatRewritesTopWindowLocation',
+]
+
+_REVISION_NEGATIVE_FILTER['64'] = (
+    _REVISION_NEGATIVE_FILTER['HEAD'] + [
     # https://bugs.chromium.org/p/chromedriver/issues/detail?id=2025
     'PageLoadingTest.testShouldBeAbleToGetAFragmentOnTheCurrentPage',
-]
+    ]
+)
 
 _REVISION_NEGATIVE_FILTER['63'] = (
     _REVISION_NEGATIVE_FILTER['HEAD'] + [
         # https://bugs.chromium.org/p/chromedriver/issues/detail?id=2025
         'MiscTest.testStimulatesStrangeOnloadInteractionInFirefox',
-	'PageLoadingTest.testShouldNotHangIfDocumentOpenCallIsNeverFollowedByDocumentCloseCall',
+        'PageLoadingTest.testShouldNotHangIfDocumentOpenCallIsNeverFollowedByDocumentCloseCall',
+        # https://bugs.chromium.org/p/chromedriver/issues/detail?id=2025
+        'PageLoadingTest.testShouldBeAbleToGetAFragmentOnTheCurrentPage',
     ]
 )
 
diff --git a/chrome/test/data/media/engagement/preload/BUILD.gn b/chrome/test/data/media/engagement/preload/BUILD.gn
deleted file mode 100644
index cb7bb11..0000000
--- a/chrome/test/data/media/engagement/preload/BUILD.gn
+++ /dev/null
@@ -1,33 +0,0 @@
-# Copyright 2017 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-import("//build/compiled_action.gni")
-
-# Generates a proto file based on the real list.
-action_foreach("generate_preload_list") {
-  script = "//tools/media_engagement_preload/make_dafsa.py"
-
-  sources = [
-    "test.json",
-  ]
-  outputs = [
-    "$target_gen_dir/{{source_name_part}}.pb",
-  ]
-  args = [
-    "{{source}}",
-    rebase_path("${target_gen_dir}/{{source_name_part}}.pb", root_build_dir),
-  ]
-}
-
-# Copy over protobuf files to output directory.
-copy("test_data") {
-  sources = [
-    "bad_format.pb",
-    "empty.pb",
-  ]
-
-  outputs = [
-    "$target_gen_dir/{{source_file_part}}",
-  ]
-}
diff --git a/chrome/test/data/media/engagement/preload/bad_format.pb b/chrome/test/data/media/engagement/preload/bad_format.pb
deleted file mode 100644
index 9daeafb9..0000000
--- a/chrome/test/data/media/engagement/preload/bad_format.pb
+++ /dev/null
@@ -1 +0,0 @@
-test
diff --git a/chrome/test/data/media/engagement/preload/empty.pb b/chrome/test/data/media/engagement/preload/empty.pb
deleted file mode 100644
index 1302db90..0000000
--- a/chrome/test/data/media/engagement/preload/empty.pb
+++ /dev/null
Binary files differ
diff --git a/chrome/test/data/media/engagement/preload/test.json b/chrome/test/data/media/engagement/preload/test.json
deleted file mode 100644
index 57780e3..0000000
--- a/chrome/test/data/media/engagement/preload/test.json
+++ /dev/null
@@ -1,6 +0,0 @@
-[
-  "https://example.com",
-  "https://example.org:1234",
-  "https://test--3ya.com",
-  "http://123.123.123.123"
-]
diff --git a/chrome/test/data/webui/cr_elements/.eslintrc.js b/chrome/test/data/webui/cr_elements/.eslintrc.js
new file mode 100644
index 0000000..994fc37
--- /dev/null
+++ b/chrome/test/data/webui/cr_elements/.eslintrc.js
@@ -0,0 +1,9 @@
+// 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.exports = {
+  'rules': {
+    'no-var': 'error',
+  },
+};
diff --git a/chrome/test/data/webui/cr_elements/cr_action_menu_test.js b/chrome/test/data/webui/cr_elements/cr_action_menu_test.js
index 08ca209f..1354b59ea 100644
--- a/chrome/test/data/webui/cr_elements/cr_action_menu_test.js
+++ b/chrome/test/data/webui/cr_elements/cr_action_menu_test.js
@@ -8,13 +8,13 @@
  */
 suite('CrActionMenu', function() {
   /** @type {?CrActionMenuElement} */
-  var menu = null;
+  let menu = null;
 
   /** @type {?NodeList<HTMLElement>} */
-  var items = null;
+  let items = null;
 
   /** @type {HTMLElement} */
-  var dots = null;
+  let dots = null;
 
   setup(function() {
     PolymerTest.clearBody();
@@ -109,7 +109,7 @@
 
   test('can navigate to dynamically added items', function() {
     // Can modify children after attached() and before showAt().
-    var item = document.createElement('button');
+    const item = document.createElement('button');
     item.classList.add('dropdown-item');
     menu.insertBefore(item, items[0]);
     menu.showAt(dots);
@@ -165,7 +165,7 @@
 
   test('mouse movement focus options', function() {
     function makeMouseoverEvent(node) {
-      var e = new MouseEvent('mouseover', {bubbles: true});
+      const e = new MouseEvent('mouseover', {bubbles: true});
       node.dispatchEvent(e);
     }
 
@@ -196,7 +196,7 @@
   });
 
   test('items automatically given accessibility role', function() {
-    var newItem = document.createElement('button');
+    const newItem = document.createElement('button');
     newItem.classList.add('dropdown-item');
 
     items[1].setAttribute('role', 'checkbox');
@@ -215,7 +215,7 @@
 
   test('positioning', function() {
     // A 40x10 box at (100, 250).
-    var config = {
+    const config = {
       left: 100,
       top: 250,
       width: 40,
@@ -235,8 +235,8 @@
     menu.showAtPosition(Object.assign({}, config, {
       anchorAlignmentX: AnchorAlignment.CENTER,
     }));
-    var menuWidth = menu.offsetWidth;
-    var menuHeight = menu.offsetHeight;
+    const menuWidth = menu.offsetWidth;
+    const menuHeight = menu.offsetHeight;
     assertEquals(`${120 - menuWidth / 2}px`, menu.style.left);
     assertEquals('250px', menu.style.top);
     menu.close();
@@ -304,14 +304,14 @@
   });
 
   suite('offscreen scroll positioning', function() {
-    var bodyHeight = 10000;
-    var bodyWidth = 20000;
-    var containerLeft = 5000;
-    var containerTop = 10000;
-    var containerWidth = 500;
-    var containerHeight = 500;
-    var menuWidth = 100;
-    var menuHeight = 200;
+    const bodyHeight = 10000;
+    const bodyWidth = 20000;
+    const containerLeft = 5000;
+    const containerTop = 10000;
+    const containerWidth = 500;
+    const containerHeight = 500;
+    const menuWidth = 100;
+    const menuHeight = 200;
 
     setup(function() {
       document.body.scrollTop = 0;
@@ -373,7 +373,7 @@
     test('offscreen and out of scroll container viewport', function() {
       document.body.scrollLeft = bodyWidth;
       document.body.scrollTop = bodyHeight;
-      var container = document.querySelector('#container');
+      const container = document.querySelector('#container');
 
       container.scrollLeft = containerLeft;
       container.scrollTop = containerTop;
@@ -387,13 +387,13 @@
     // Show the menu for an already onscreen button. The anchor should be
     // overridden so that no scrolling happens.
     test('onscreen forces anchor change', function() {
-      var rect = dots.getBoundingClientRect();
+      const rect = dots.getBoundingClientRect();
       document.body.scrollLeft = rect.right - document.body.clientWidth + 10;
       document.body.scrollTop = rect.bottom - document.body.clientHeight + 10;
 
       menu.showAt(dots, {anchorAlignmentX: AnchorAlignment.AFTER_START});
-      var buttonWidth = dots.offsetWidth;
-      var buttonHeight = dots.offsetHeight;
+      const buttonWidth = dots.offsetWidth;
+      const buttonHeight = dots.offsetHeight;
       assertEquals(containerLeft - menuWidth + buttonWidth, menu.offsetLeft);
       assertEquals(containerTop - menuHeight + buttonHeight, menu.offsetTop);
       menu.close();
diff --git a/chrome/test/data/webui/cr_elements/cr_dialog_test.js b/chrome/test/data/webui/cr_elements/cr_dialog_test.js
index 912140c0..600f44b 100644
--- a/chrome/test/data/webui/cr_elements/cr_dialog_test.js
+++ b/chrome/test/data/webui/cr_elements/cr_dialog_test.js
@@ -18,8 +18,8 @@
         <div slot="body"><button>button</button></div>
       </dialog>`;
 
-    var dialog = document.body.querySelector('dialog');
-    var button = document.body.querySelector('button');
+    const dialog = document.body.querySelector('dialog');
+    const button = document.body.querySelector('button');
 
     assertNotEquals(dialog, document.activeElement);
     assertNotEquals(button, document.activeElement);
@@ -40,13 +40,13 @@
         </div>
       </dialog>`;
 
-    var dialog = document.body.querySelector('dialog');
-    var actionButton = document.body.querySelector('.action-button');
+    const dialog = document.body.querySelector('dialog');
+    const actionButton = document.body.querySelector('.action-button');
 
     dialog.showModal();
 
     // MockInteractions triggers event listeners synchronously.
-    var clickedCounter = 0;
+    let clickedCounter = 0;
     actionButton.addEventListener('click', function() {
       clickedCounter++;
     });
@@ -57,7 +57,7 @@
 
     // Enter keys on other buttons should be ignored.
     clickedCounter = 0;
-    var otherButton = document.body.querySelector('#other-button');
+    const otherButton = document.body.querySelector('#other-button');
     assertTrue(!!otherButton);
     pressEnter(otherButton);
     assertEquals(0, clickedCounter);
@@ -79,16 +79,16 @@
         </div>
       </dialog>`;
 
-    var dialog = document.body.querySelector('dialog');
-    var hiddenButton = document.body.querySelector('#hidden');
-    var actionButton = document.body.querySelector('#active');
+    const dialog = document.body.querySelector('dialog');
+    const hiddenButton = document.body.querySelector('#hidden');
+    const actionButton = document.body.querySelector('#active');
     dialog.showModal();
 
     // MockInteractions triggers event listeners synchronously.
     hiddenButton.addEventListener('click', function() {
       assertNotReached('Hidden button received a click.');
     });
-    var clicked = false;
+    let clicked = false;
     actionButton.addEventListener('click', function() {
       clicked = true;
     });
@@ -108,17 +108,17 @@
         </div>
       </dialog>`;
 
-    var dialog = document.body.querySelector('dialog');
+    const dialog = document.body.querySelector('dialog');
 
-    var inputElement = document.body.querySelector('paper-input');
-    var otherElement = document.body.querySelector('foobar');
-    var actionButton = document.body.querySelector('.action-button');
+    const inputElement = document.body.querySelector('paper-input');
+    const otherElement = document.body.querySelector('foobar');
+    const actionButton = document.body.querySelector('.action-button');
     assertTrue(!!inputElement);
     assertTrue(!!otherElement);
     assertTrue(!!actionButton);
 
     // MockInteractions triggers event listeners synchronously.
-    var clickedCounter = 0;
+    let clickedCounter = 0;
     actionButton.addEventListener('click', function() {
       clickedCounter++;
     });
@@ -137,8 +137,8 @@
         <div slot="body"><button autofocus>button</button></div>
       </dialog>`;
 
-    var dialog = document.body.querySelector('dialog');
-    var button = document.body.querySelector('button');
+    const dialog = document.body.querySelector('dialog');
+    const button = document.body.querySelector('button');
 
     assertNotEquals(dialog, document.activeElement);
     assertNotEquals(button, document.activeElement);
@@ -158,9 +158,9 @@
         <div slot="body">body</div>
       </dialog>`;
 
-    var dialog = document.body.querySelector('dialog');
+    const dialog = document.body.querySelector('dialog');
     assertFalse(dialog.open);
-    var bodyContainer = dialog.$$('.body-container');
+    const bodyContainer = dialog.$$('.body-container');
     assertTrue(!!bodyContainer);
 
     // Waiting for 1ms because IntersectionObserver fires one message loop after
@@ -181,17 +181,17 @@
         </div>
       </dialog>`;
 
-    var dialog = document.body.querySelector('dialog');
-    var bodyContainer = dialog.$$('.body-container');
+    const dialog = document.body.querySelector('dialog');
+    const bodyContainer = dialog.$$('.body-container');
     assertTrue(!!bodyContainer);
 
     dialog.showModal();  // Attach the dialog for the first time here.
 
-    var observerCount = 0;
+    let observerCount = 0;
 
     // Needs to setup the observer before attaching, since InteractionObserver
     // calls callback before MutationObserver does.
-    var observer = new MutationObserver(function(changes) {
+    const observer = new MutationObserver(function(changes) {
       // Only care about class mutations.
       if (changes[0].attributeName != 'class')
         return;
@@ -229,20 +229,20 @@
         <div slot="title">title</div>
       </dialog>`;
 
-    var dialog = document.body.querySelector('dialog');
+    const dialog = document.body.querySelector('dialog');
     dialog.showModal();
 
     assertTrue(dialog.getCloseButton().hidden);
 
     // Hitting escape fires a 'cancel' event. Cancelling that event prevents the
     // dialog from closing.
-    var e = new Event('cancel', {cancelable: true});
+    let e = new Event('cancel', {cancelable: true});
     dialog.dispatchEvent(e);
     assertTrue(e.defaultPrevented);
 
     dialog.noCancel = false;
 
-    var e = new Event('cancel', {cancelable: true});
+    e = new Event('cancel', {cancelable: true});
     dialog.dispatchEvent(e);
     assertFalse(e.defaultPrevented);
   });
diff --git a/chrome/test/data/webui/cr_elements/cr_elements_browsertest.js b/chrome/test/data/webui/cr_elements/cr_elements_browsertest.js
index cceeefa..28f1ed2 100644
--- a/chrome/test/data/webui/cr_elements/cr_elements_browsertest.js
+++ b/chrome/test/data/webui/cr_elements/cr_elements_browsertest.js
@@ -5,7 +5,7 @@
 /** @fileoverview Tests for shared Polymer elements. */
 
 /** @const {string} Path to source root. */
-var ROOT_PATH = '../../../../../';
+const ROOT_PATH = '../../../../../';
 
 // Polymer BrowserTest fixture.
 GEN_INCLUDE(
diff --git a/chrome/test/data/webui/cr_elements/cr_elements_focus_test.js b/chrome/test/data/webui/cr_elements/cr_elements_focus_test.js
index 1a3469c..907f754 100644
--- a/chrome/test/data/webui/cr_elements/cr_elements_focus_test.js
+++ b/chrome/test/data/webui/cr_elements/cr_elements_focus_test.js
@@ -5,7 +5,7 @@
 /** @fileoverview Tests for shared Polymer elements which rely on focus. */
 
 /** @const {string} Path to source root. */
-var ROOT_PATH = '../../../../../';
+const ROOT_PATH = '../../../../../';
 
 // Polymer BrowserTest fixture.
 GEN_INCLUDE(
diff --git a/chrome/test/data/webui/cr_elements/cr_lazy_render_tests.js b/chrome/test/data/webui/cr_elements/cr_lazy_render_tests.js
index a98ae28..08895cb 100644
--- a/chrome/test/data/webui/cr_elements/cr_lazy_render_tests.js
+++ b/chrome/test/data/webui/cr_elements/cr_lazy_render_tests.js
@@ -3,8 +3,8 @@
 // found in the LICENSE file.
 
 suite('cr-lazy-render', function() {
-  var lazy;
-  var bind;
+  let lazy;
+  let bind;
 
   suiteSetup(function() {
     return PolymerTest.importHtml(
@@ -13,7 +13,7 @@
 
   setup(function() {
     PolymerTest.clearBody();
-    var template =
+    const template =
         '<template is="dom-bind" id="bind">' +
         '  <template is="cr-lazy-render" id="lazy">' +
         '    <h1>' +
@@ -31,7 +31,7 @@
     assertFalse(!!document.body.querySelector('h1'));
     assertFalse(!!lazy.getIfExists());
 
-    var inner = lazy.get();
+    const inner = lazy.get();
     assertEquals('H1', inner.nodeName);
     assertEquals(inner, document.body.querySelector('h1'));
   });
@@ -39,7 +39,7 @@
   test('one-way binding works', function() {
     bind.name = 'Wings';
 
-    var inner = lazy.get();
+    const inner = lazy.get();
     assertNotEquals(-1, inner.textContent.indexOf('Wings'));
     bind.name = 'DC';
     assertNotEquals(-1, inner.textContent.indexOf('DC'));
@@ -48,8 +48,8 @@
   test('two-way binding works', function() {
     bind.checked = true;
 
-    var inner = lazy.get();
-    var checkbox = document.querySelector('paper-checkbox');
+    const inner = lazy.get();
+    const checkbox = document.querySelector('paper-checkbox');
     assertTrue(checkbox.checked);
     MockInteractions.tap(checkbox);
     assertFalse(checkbox.checked);
diff --git a/chrome/test/data/webui/cr_elements/cr_policy_indicator_behavior_tests.js b/chrome/test/data/webui/cr_elements/cr_policy_indicator_behavior_tests.js
index 8f13188..ad3c43d 100644
--- a/chrome/test/data/webui/cr_elements/cr_policy_indicator_behavior_tests.js
+++ b/chrome/test/data/webui/cr_elements/cr_policy_indicator_behavior_tests.js
@@ -4,7 +4,7 @@
 
 /** @fileoverview Suite of tests for CrPolicyIndicatorBehavior. */
 suite('CrPolicyIndicatorBehavior', function() {
-  var TestIndicator;
+  let TestIndicator;
   suiteSetup(function() {
     TestIndicator = Polymer({
       is: 'test-indicator',
@@ -13,7 +13,7 @@
     });
   });
 
-  var indicator;
+  let indicator;
   setup(function() {
     indicator = new TestIndicator;
   });
diff --git a/chrome/test/data/webui/cr_elements/cr_policy_indicator_tests.js b/chrome/test/data/webui/cr_elements/cr_policy_indicator_tests.js
index bbdac7a..5f1b092 100644
--- a/chrome/test/data/webui/cr_elements/cr_policy_indicator_tests.js
+++ b/chrome/test/data/webui/cr_elements/cr_policy_indicator_tests.js
@@ -5,10 +5,10 @@
 /** @fileoverview Suite of tests for cr-policy-indicator. */
 suite('CrPolicyIndicator', function() {
   /** @type {!CrPolicyIndicatorElement|undefined} */
-  var indicator;
+  let indicator;
 
   /** @type {!CrTooltipIconElement|undefined} */
-  var icon;
+  let icon;
 
   setup(function() {
     PolymerTest.clearBody();
diff --git a/chrome/test/data/webui/cr_elements/cr_policy_network_indicator_tests.js b/chrome/test/data/webui/cr_elements/cr_policy_network_indicator_tests.js
index 70a8b0e..f35eea38 100644
--- a/chrome/test/data/webui/cr_elements/cr_policy_network_indicator_tests.js
+++ b/chrome/test/data/webui/cr_elements/cr_policy_network_indicator_tests.js
@@ -5,10 +5,10 @@
 /** @fileoverview Suite of tests for cr_policy-network-indicator. */
 suite('cr-policy-network-indicator', function() {
   /** @type {!CrPolicyNetworkIndicatorElement|undefined} */
-  var indicator;
+  let indicator;
 
   /** @type {!CrTooltipIconElement|undefined} */
-  var icon;
+  let icon;
 
   // Prevent 'Cannot read property of undefined' errors in cr_onc_types.js.
   chrome.networkingPrivate = {};
diff --git a/chrome/test/data/webui/cr_elements/cr_policy_pref_indicator_tests.js b/chrome/test/data/webui/cr_elements/cr_policy_pref_indicator_tests.js
index 07fe7b9..7bbdc96 100644
--- a/chrome/test/data/webui/cr_elements/cr_policy_pref_indicator_tests.js
+++ b/chrome/test/data/webui/cr_elements/cr_policy_pref_indicator_tests.js
@@ -5,10 +5,10 @@
 /** @fileoverview Suite of tests for cr_policy-pref-indicator. */
 suite('CrPolicyPrefIndicator', function() {
   /** @type {!CrPolicyPrefIndicatorElement|undefined} */
-  var indicator;
+  let indicator;
 
   /** @type {!CrTooltipIconElement|undefined} */
-  var icon;
+  let icon;
 
   setup(function() {
     PolymerTest.clearBody();
diff --git a/chrome/test/data/webui/cr_elements/cr_policy_strings.js b/chrome/test/data/webui/cr_elements/cr_policy_strings.js
index c9cd1eb..5349aba 100644
--- a/chrome/test/data/webui/cr_elements/cr_policy_strings.js
+++ b/chrome/test/data/webui/cr_elements/cr_policy_strings.js
@@ -3,6 +3,7 @@
 // found in the LICENSE file.
 
 /** @fileoverview Sets up strings used by policy indicator elements. */
+// eslint-disable-next-line no-var
 var CrPolicyStrings = CrPolicyStrings || {
   controlledSettingPolicy: 'policy',
   controlledSettingRecommendedMatches: 'matches',
diff --git a/chrome/test/data/webui/cr_elements/cr_profile_avatar_selector_tests.js b/chrome/test/data/webui/cr_elements/cr_profile_avatar_selector_tests.js
index d678863..c6d7031 100644
--- a/chrome/test/data/webui/cr_elements/cr_profile_avatar_selector_tests.js
+++ b/chrome/test/data/webui/cr_elements/cr_profile_avatar_selector_tests.js
@@ -4,7 +4,7 @@
 
 /** @fileoverview Suite of tests for cr-profile-avatar-selector. */
 cr.define('cr_profile_avatar_selector', function() {
-  var TestNames = {
+  const TestNames = {
     Basic: 'basic',
     Focus: 'Ignores modified key events',
   };
@@ -12,11 +12,11 @@
   function registerTests() {
     suite('cr-profile-avatar-selector', function() {
       /** @type {CrProfileAvatarSelectorElement} */
-      var avatarSelector = null;
+      let avatarSelector = null;
 
       /** @return {CrProfileAvatarSelectorElement} */
       function createElement() {
-        var avatarSelector =
+        const avatarSelector =
             document.createElement('cr-profile-avatar-selector');
         avatarSelector.avatars =
             [{url: 'chrome://avatar1.png', label: 'avatar1'},
@@ -59,7 +59,7 @@
         });
 
         test('Can select avatar', function() {
-          var items = getGridItems();
+          const items = getGridItems();
 
           // Simulate tapping the third avatar.
           MockInteractions.tap(items[2]);
@@ -74,8 +74,8 @@
       // Run in CrElementsProfileAvatarSelectorFocusTest.All as an
       // interactive_ui_test.
       test(TestNames.Focus, function() {
-        var selector = avatarSelector.$['avatar-grid'];
-        var items = getGridItems();
+        const selector = avatarSelector.$['avatar-grid'];
+        const items = getGridItems();
 
         items[0].focus();
         assertTrue(items[0].focused);
diff --git a/chrome/test/data/webui/cr_elements/cr_scrollable_behavior_tests.js b/chrome/test/data/webui/cr_elements/cr_scrollable_behavior_tests.js
index e422baf..278e998 100644
--- a/chrome/test/data/webui/cr_elements/cr_scrollable_behavior_tests.js
+++ b/chrome/test/data/webui/cr_elements/cr_scrollable_behavior_tests.js
@@ -3,9 +3,9 @@
 // found in the LICENSE file.
 
 suite('cr-scrollable-behavior', function() {
-  /** @type {CrScrollableListElement} */ var testElement;
-  /** @type {HTMLDivElement} */ var container;
-  /** @type {IronListElement} */ var ironList;
+  /** @type {CrScrollableListElement} */ let testElement;
+  /** @type {HTMLDivElement} */ let container;
+  /** @type {IronListElement} */ let ironList;
 
   suiteSetup(function() {
     document.body.innerHTML = `
@@ -82,7 +82,7 @@
     scrollToIndex(2);
     assertTrue(container.classList.contains('can-scroll'));
     assertTrue(container.classList.contains('is-scrolled'));
-    var scrollTop = container.scrollTop;
+    const scrollTop = container.scrollTop;
     testElement.saveScroll(ironList);
     testElement.items = ['apple', 'bannana', 'cactus', 'cucumber', 'doughnut'];
     testElement.restoreScroll(ironList);
diff --git a/chrome/test/data/webui/cr_elements/cr_toast_test.js b/chrome/test/data/webui/cr_elements/cr_toast_test.js
index e12bf26..5031b90 100644
--- a/chrome/test/data/webui/cr_elements/cr_toast_test.js
+++ b/chrome/test/data/webui/cr_elements/cr_toast_test.js
@@ -3,7 +3,7 @@
 // found in the LICENSE file.
 
 suite('cr-toast', function() {
-  var toast;
+  let toast;
 
   setup(function() {
     PolymerTest.clearBody();
diff --git a/chrome/test/data/webui/cr_elements/cr_toggle_test.js b/chrome/test/data/webui/cr_elements/cr_toggle_test.js
index b2d0202..202c01a 100644
--- a/chrome/test/data/webui/cr_elements/cr_toggle_test.js
+++ b/chrome/test/data/webui/cr_elements/cr_toggle_test.js
@@ -3,7 +3,7 @@
 // found in the LICENSE file.
 
 suite('cr-toggle', function() {
-  var toggle;
+  let toggle;
 
   setup(function() {
     PolymerTest.clearBody();
@@ -68,10 +68,10 @@
     // Simulate events in the same order they are fired by the browser.
     // Need to provide a valid |pointerId| for setPointerCapture() to not throw
     // an error.
-    var xStart = 100;
+    const xStart = 100;
     toggle.dispatchEvent(new PointerEvent(
         'pointerdown', {pointerId: 1, clientX: xStart}));
-    var xEnd = xStart;
+    let xEnd = xStart;
     if (moveDirection) {
       xEnd = moveDirection > 0 ? xStart + diff : xStart - diff;
       toggle.dispatchEvent(new PointerEvent(
@@ -101,7 +101,7 @@
   // Test that the control is toggled when the user taps on it (no movement
   // between pointerdown and pointerup).
   test('ToggleByPointerTap', function() {
-    var whenChanged = test_util.eventToPromise('change', toggle);
+    let whenChanged = test_util.eventToPromise('change', toggle);
     triggerPointerDownMoveUpTapSequence(0 /* no pointermove */);
     return whenChanged.then(function() {
       assertChecked();
@@ -116,7 +116,7 @@
   // Test that the control is toggled if the user moves the pointer by a
   // MOVE_THRESHOLD_PX pixels accidentally (shaky hands) in any direction.
   test('ToggleByShakyPointerTap', function() {
-    var whenChanged = test_util.eventToPromise('change', toggle);
+    let whenChanged = test_util.eventToPromise('change', toggle);
     triggerPointerDownMoveUpTapSequence(
         1 /* right */, toggle.MOVE_THRESHOLD_PX - 1);
     return whenChanged.then(function() {
@@ -133,7 +133,7 @@
   // Test that the control is toggled when the user moves the pointer while
   // holding down.
   test('ToggleByPointerMove', function() {
-    var whenChanged = test_util.eventToPromise('change', toggle);
+    let whenChanged = test_util.eventToPromise('change', toggle);
     triggerPointerDownMoveUpTapSequence(
         1 /* right */, toggle.MOVE_THRESHOLD_PX);
     return whenChanged.then(function() {
@@ -157,7 +157,7 @@
   // Test that the control is toggled when the user presses the 'Enter' or
   // 'Space' key.
   test('ToggleByKey', function() {
-    var whenChanged = test_util.eventToPromise('change', toggle);
+    let whenChanged = test_util.eventToPromise('change', toggle);
     triggerKeyPressEvent('Enter');
     return whenChanged.then(function() {
       assertChecked();
diff --git a/chrome/test/data/webui/cr_elements/cr_toolbar_search_field_tests.js b/chrome/test/data/webui/cr_elements/cr_toolbar_search_field_tests.js
index 5dd5e121..dd68801 100644
--- a/chrome/test/data/webui/cr_elements/cr_toolbar_search_field_tests.js
+++ b/chrome/test/data/webui/cr_elements/cr_toolbar_search_field_tests.js
@@ -7,10 +7,10 @@
   function registerTests() {
     suite('cr-toolbar-search-field', function() {
       /** @type {?CrToolbarSearchFieldElement} */
-      var field = null;
+      let field = null;
 
       /** @type {?Array<string>} */
-      var searches = null;
+      let searches = null;
 
       /** @param {string} term */
       function simulateSearch(term) {
@@ -38,8 +38,8 @@
       // Test that no initial 'search-changed' event is fired during
       // construction and initialization of the cr-toolbar-search-field element.
       test('no initial search-changed event', function() {
-        var didFire = false;
-        var onSearchChanged = function () { didFire = true; };
+        let didFire = false;
+        const onSearchChanged = function () { didFire = true; };
 
         // Need to attach listener event before the element is created, to catch
         // the unnecessary initial event.
@@ -76,7 +76,7 @@
         Polymer.dom.flush();
         assertTrue(field.hasSearchText);
 
-        var clearSearch = field.$$('#clearSearch');
+        const clearSearch = field.$$('#clearSearch');
         clearSearch.focus();
         MockInteractions.tap(clearSearch);
         assertTrue(field.showingSearch);
@@ -124,7 +124,7 @@
       // Tests that calling setValue() from within a 'search-changed' callback
       // does not result in an infinite loop.
       test('no infinite loop', function() {
-        var counter = 0;
+        let counter = 0;
         field.addEventListener('search-changed', function(event) {
           counter++;
           // Calling setValue() with the already existing value should not
@@ -155,7 +155,7 @@
         assertTrue(field.hasSearchText);
         Polymer.dom.flush();
 
-        var clearSearch = field.$$('#clearSearch');
+        const clearSearch = field.$$('#clearSearch');
         assertFalse(clearSearch.hidden);
         assertTrue(field.showingSearch);
       });
diff --git a/chrome/test/data/webui/extensions/cr_extensions_browsertest.js b/chrome/test/data/webui/extensions/cr_extensions_browsertest.js
index 1deda31..a30664a4 100644
--- a/chrome/test/data/webui/extensions/cr_extensions_browsertest.js
+++ b/chrome/test/data/webui/extensions/cr_extensions_browsertest.js
@@ -161,6 +161,10 @@
   this.runMochaTest(extension_item_tests.TestNames.ClickableItems);
 });
 
+TEST_F('CrExtensionsItemsTest', 'FailedReloadFiresLoadError', function() {
+  this.runMochaTest(extension_item_tests.TestNames.FailedReloadFiresLoadError);
+});
+
 TEST_F('CrExtensionsItemsTest', 'Warnings', function() {
   this.runMochaTest(extension_item_tests.TestNames.Warnings);
 });
diff --git a/chrome/test/data/webui/extensions/extension_item_test.js b/chrome/test/data/webui/extensions/extension_item_test.js
index e6edce6..2ce32dcc 100644
--- a/chrome/test/data/webui/extensions/extension_item_test.js
+++ b/chrome/test/data/webui/extensions/extension_item_test.js
@@ -69,6 +69,7 @@
     ElementVisibilityDeveloperState:
         'element visibility: after enabling developer mode',
     ClickableItems: 'clickable items',
+    FailedReloadFiresLoadError: 'failed reload fires load error',
     Warnings: 'warnings',
     SourceIndicator: 'source indicator',
     EnableToggle: 'toggle is disabled when necessary',
@@ -167,13 +168,55 @@
       item.set('data.state', chrome.developerPrivate.ExtensionState.TERMINATED);
       Polymer.dom.flush();
       mockDelegate.testClickingCalls(
-          item.$$('#terminated-reload-button'), 'reloadItem', [item.data.id]);
+          item.$$('#terminated-reload-button'), 'reloadItem', [item.data.id],
+          Promise.resolve());
 
       item.set('data.location', chrome.developerPrivate.Location.UNPACKED);
       item.set('data.state', chrome.developerPrivate.ExtensionState.ENABLED);
       Polymer.dom.flush();
-      mockDelegate.testClickingCalls(
-          item.$$('#dev-reload-button'), 'reloadItem', [item.data.id]);
+    });
+
+    /** Tests that the reload button properly fires the load-error event. */
+    test(assert(TestNames.FailedReloadFiresLoadError), function() {
+      item.set('inDevMode', true);
+      item.set('data.location', chrome.developerPrivate.Location.UNPACKED);
+      Polymer.dom.flush();
+      extension_test_util.testVisible(item, '#dev-reload-button', true);
+
+      // Check clicking the reload button. The reload button should fire a
+      // load-error event if and only if the reload fails (indicated by a
+      // rejected promise).
+      // This is a bit of a pain to verify because the promises finish
+      // asynchronously, so we have to use setTimeout()s.
+      var firedLoadError = false;
+      item.addEventListener('load-error', () => { firedLoadError = true; });
+
+      // This is easier to test with a TestBrowserProxy-style delegate.
+      var proxyDelegate = new extensions.TestService();
+      item.delegate = proxyDelegate;
+
+      var verifyEventPromise = function(expectCalled) {
+        return new Promise((resolve, reject) => {
+          setTimeout(() => {
+            expectEquals(expectCalled, firedLoadError);
+            resolve();
+          });
+        });
+      };
+
+      MockInteractions.tap(item.$$('#dev-reload-button'));
+      return proxyDelegate.whenCalled('reloadItem').then(function(id) {
+        expectEquals(item.data.id, id);
+        return verifyEventPromise(false);
+      }).then(function() {
+        proxyDelegate.resetResolver('reloadItem');
+        proxyDelegate.setForceReloadItemError(true);
+        MockInteractions.tap(item.$$('#dev-reload-button'));
+        return proxyDelegate.whenCalled('reloadItem');
+      }).then(function(id) {
+        expectEquals(item.data.id, id);
+        return verifyEventPromise(true);
+      });
     });
 
     test(assert(TestNames.Warnings), function() {
diff --git a/chrome/test/data/webui/extensions/extension_test_util.js b/chrome/test/data/webui/extensions/extension_test_util.js
index 9c52273..4d6235651e 100644
--- a/chrome/test/data/webui/extensions/extension_test_util.js
+++ b/chrome/test/data/webui/extensions/extension_test_util.js
@@ -17,10 +17,13 @@
      * @param {string} callName The function expected to be called.
      * @param {Array<*>=} opt_expectedArgs The arguments the function is
      *     expected to be called with.
+     * @param {*=} opt_returnValue The value to return from the function call.
      */
-    testClickingCalls: function(element, callName, opt_expectedArgs) {
+    testClickingCalls: function(element, callName, opt_expectedArgs,
+                                opt_returnValue) {
       var mock = new MockController();
       var mockMethod = mock.createFunctionMock(this, callName);
+      mockMethod.returnValue = opt_returnValue;
       MockMethod.prototype.addExpectation.apply(
           mockMethod, opt_expectedArgs);
       MockInteractions.tap(element);
@@ -118,6 +121,9 @@
     inspectItemView: function(id, view) {},
 
     /** @override */
+    reloadItem: function(id) {},
+
+    /** @override */
     repairItem: function(id) {},
 
     /** @override */
diff --git a/chrome/test/data/webui/extensions/test_service.js b/chrome/test/data/webui/extensions/test_service.js
index 557ae5bb..621d9dd 100644
--- a/chrome/test/data/webui/extensions/test_service.js
+++ b/chrome/test/data/webui/extensions/test_service.js
@@ -11,6 +11,7 @@
         'getProfileConfiguration',
         'loadUnpacked',
         'retryLoadUnpacked',
+        'reloadItem',
         'setProfileInDevMode',
         'setShortcutHandlingSuspended',
         'updateAllExtensions',
@@ -22,6 +23,9 @@
 
       /** @private {!chrome.developerPrivate.LoadError} */
       this.retryLoadUnpackedError_;
+
+      /** @type {boolean} */
+      this.forceReloadItemError_ = false;
     }
 
     /**
@@ -31,6 +35,13 @@
       this.retryLoadUnpackedError_ = error;
     }
 
+    /**
+     * @param {boolean} force
+     */
+    setForceReloadItemError(force) {
+      this.forceReloadItemError_ = force;
+    }
+
     /** @override */
     getProfileConfiguration() {
       this.methodCalled('getProfileConfiguration');
@@ -71,6 +82,12 @@
     }
 
     /** @override */
+    reloadItem(id) {
+      this.methodCalled('reloadItem', id);
+      return this.forceReloadItemError_ ? Promise.reject() : Promise.resolve();
+    }
+
+    /** @override */
     retryLoadUnpacked(guid) {
       this.methodCalled('retryLoadUnpacked', guid);
       return (this.retryLoadUnpackedError_ !== undefined) ?
diff --git a/chrome/test/data/webui/interventions_internals_browsertest.js b/chrome/test/data/webui/interventions_internals_browsertest.js
index 95d1a75..ee59dc9a 100644
--- a/chrome/test/data/webui/interventions_internals_browsertest.js
+++ b/chrome/test/data/webui/interventions_internals_browsertest.js
@@ -215,18 +215,21 @@
         description: 'Some description_a',
         url: {url: 'Some gurl.spec()_a'},
         time: 1507221689240,  // Oct 05 2017 16:41:29 UTC
+        pageId: 0,
       },
       {
         type: 'Type_b',
         description: 'Some description_b',
         url: {url: 'Some gurl.spec()_b'},
         time: 758675653000,  // Jan 15 1994 23:14:13 UTC
+        pageId: 0,
       },
       {
         type: 'Type_c',
         description: 'Some description_c',
         url: {url: 'Some gurl.spec()_c'},
         time: -314307870000,  // Jan 16 1960 04:15:30 UTC
+        pageId: 0,
       },
     ];
 
@@ -234,8 +237,7 @@
       pageImpl.logNewMessage(log);
     });
 
-    let logTable = $('message-logs-table');
-    let rows = logTable.querySelectorAll('.log-message');
+    let rows = $('message-logs-table').querySelectorAll('.log-message');
     expectEquals(logs.length, rows.length);
 
     logs.forEach((log, index) => {
@@ -265,6 +267,7 @@
       url: {url: ''},
       description: 'Some description',
       time: 758675653000,  // Jan 15 1994 23:14:13 UTC
+      pageId: 0,
     };
     // Creating long url.
     for (let i = 0; i <= 2 * URL_THRESHOLD; i++) {
@@ -288,6 +291,7 @@
       url: {url: ''},
       description: 'Some description',
       time: 758675653000,  // Jan 15 1994 23:14:13 UTC
+      pageId: 0,
     };
     pageImpl.logNewMessage(log);
     let actual = $('message-logs-table').rows[1];
@@ -301,6 +305,207 @@
   mocha.run();
 });
 
+TEST_F('InterventionsInternalsUITest', 'LogNewMessagePageIdZero', function() {
+  test('LogMessageWithPageIdZero', () => {
+    let pageImpl = new InterventionsInternalPageImpl(null);
+    let logs = [
+      {
+        type: 'Type_a',
+        description: 'Some description_a',
+        url: {url: 'Some gurl.spec()_a'},
+        time: 1507221689240,  // Oct 05 2017 16:41:29 UTC
+        pageId: 0,
+      },
+      {
+        type: 'Type_b',
+        description: 'Some description_b',
+        url: {url: 'Some gurl.spec()_b'},
+        time: 758675653000,  // Jan 15 1994 23:14:13 UTC
+        pageId: 0,
+      },
+    ];
+
+    logs.forEach((log) => {
+      pageImpl.logNewMessage(log);
+    });
+
+    // Expect 2 different rows in logs table.
+    let rows = $('message-logs-table').querySelectorAll('.log-message');
+    let expectedNumberOfRows = 2;
+    expectEquals(expectedNumberOfRows, rows.length);
+
+    logs.forEach((log, index) => {
+      let expectedTime = getTimeFormat(log.time);
+      let row = rows[logs.length - index - 1];
+
+      expectEquals(expectedTime, row.querySelector('.log-time').textContent);
+      expectEquals(log.type, row.querySelector('.log-type').textContent);
+      expectEquals(
+          log.description, row.querySelector('.log-description').textContent);
+      expectEquals(
+          log.url.url, row.querySelector('.log-url-value').textContent);
+    });
+  });
+
+  mocha.run();
+});
+
+TEST_F('InterventionsInternalsUITest', 'LogNewMessageNewPageId', function() {
+  test('LogMessageWithNewPageId', () => {
+    let pageImpl = new InterventionsInternalPageImpl(null);
+    let logs = [
+      {
+        type: 'Type_a',
+        description: 'Some description_a',
+        url: {url: 'Some gurl.spec()_a'},
+        time: 1507221689240,  // Oct 05 2017 16:41:29 UTC
+        pageId: 123,
+      },
+      {
+        type: 'Type_b',
+        description: 'Some description_b',
+        url: {url: 'Some gurl.spec()_b'},
+        time: 758675653000,  // Jan 15 1994 23:14:13 UTC
+        pageId: 321,
+      },
+    ];
+
+    logs.forEach((log) => {
+      pageImpl.logNewMessage(log);
+    });
+
+    // Expect 2 different rows in logs table.
+    let rows = $('message-logs-table').querySelectorAll('.log-message');
+    expectEquals(2, rows.length);
+
+    logs.forEach((log, index) => {
+      let expectedTime = getTimeFormat(log.time);
+      let row = rows[logs.length - index - 1];
+
+      expectEquals(expectedTime, row.querySelector('.log-time').textContent);
+      expectEquals(log.type, row.querySelector('.log-type').textContent);
+      expectEquals(
+          log.description, row.querySelector('.log-description').textContent);
+      expectEquals(
+          log.url.url, row.querySelector('.log-url-value').textContent);
+    });
+  });
+
+  mocha.run();
+});
+
+TEST_F(
+    'InterventionsInternalsUITest', 'LogNewMessageExistedPageId', function() {
+      test('LogMessageWithExistedPageId', () => {
+        let pageImpl = new InterventionsInternalPageImpl(null);
+        let logs = [
+          {
+            type: 'Type_a',
+            description: 'Some description_a',
+            url: {url: 'Some gurl.spec()_a'},
+            time: 1507221689240,  // Oct 05 2017 16:41:29 UTC
+            pageId: 3,
+          },
+          {
+            type: 'Type_b',
+            description: 'Some description_b',
+            url: {url: 'Some gurl.spec()_b'},
+            time: 758675653000,  // Jan 15 1994 23:14:13 UTC
+            pageId: 3,
+          },
+        ];
+
+        logs.forEach((log) => {
+          pageImpl.logNewMessage(log);
+        });
+
+        let logTableRows =
+            $('message-logs-table').querySelectorAll('.log-message');
+        expectEquals(1, logTableRows.length);
+        expectEquals(
+            1, document.querySelector('.expansion-logs-table').rows.length);
+
+        // Log table row.
+        let row = $('message-logs-table').querySelector('.log-message');
+        let expectedRowTime = getTimeFormat(logs[1].time);
+        expectEquals(
+            expectedRowTime, row.querySelector('.log-time').textContent);
+        expectEquals(logs[1].type, row.querySelector('.log-type').textContent);
+        expectEquals(
+            logs[1].description,
+            row.querySelector('.log-description').textContent);
+        expectEquals(
+            logs[1].url.url, row.querySelector('.log-url-value').textContent);
+
+        // Sub log table row.
+        let subRow = document.querySelector('.expansion-logs-table').rows[0];
+        let expectedSubTime = getTimeFormat(logs[0].time);
+        expectEquals(
+            expectedSubTime, subRow.querySelector('.log-time').textContent);
+        expectEquals(
+            logs[0].type, subRow.querySelector('.log-type').textContent);
+        expectEquals(
+            logs[0].description,
+            subRow.querySelector('.log-description').textContent);
+        expectEquals(
+            logs[0].url.url,
+            subRow.querySelector('.log-url-value').textContent);
+      });
+
+      mocha.run();
+    });
+
+TEST_F(
+    'InterventionsInternalsUITest',
+    'LogNewMessageExistedPageIdGroupToTopOfTable', function() {
+      test('NewMessagePushedToTopOfTable', () => {
+        let pageImpl = new InterventionsInternalPageImpl(null);
+        let logs = [
+          {
+            type: 'Type_a',
+            description: 'Some description_a',
+            url: {url: 'Some gurl.spec()_a'},
+            time: 0,
+            pageId: 3,
+          },
+          {
+            type: 'Type_b',
+            description: 'Some description_b',
+            url: {url: 'Some gurl.spec()_b'},
+            time: 1,
+            pageId: 123,
+          },
+          {
+            type: 'Type_c',
+            description: 'Some description_c',
+            url: {url: 'Some gurl.spec()_c'},
+            time: 2,
+            pageId: 3,
+          },
+        ];
+
+        pageImpl.logNewMessage(logs[0]);
+        pageImpl.logNewMessage(logs[1]);
+        let rows = $('message-logs-table').querySelectorAll('.log-message');
+        expectEquals(2, rows.length);
+        expectEquals(
+            logs[1].type, rows[0].querySelector('.log-type').textContent);
+        expectEquals(
+            logs[0].type, rows[1].querySelector('.log-type').textContent);
+
+        // Existing group pushed to the top of the log table.
+        pageImpl.logNewMessage(logs[2]);
+        rows = $('message-logs-table').querySelectorAll('.log-message');
+        expectEquals(2, rows.length);
+        expectEquals(
+            logs[2].type, rows[0].querySelector('.log-type').textContent);
+        expectEquals(
+            logs[1].type, rows[1].querySelector('.log-type').textContent);
+      });
+
+      mocha.run();
+    });
+
 TEST_F('InterventionsInternalsUITest', 'AddNewBlacklistedHost', function() {
   test('AddNewBlacklistedHost', () => {
     let pageImpl = new InterventionsInternalPageImpl(null);
@@ -402,7 +607,12 @@
         pageImpl.logNewMessage(log);
         expectGT($('message-logs-table').rows.length, 1 /* header row */);
         pageImpl.onBlacklistCleared(time);
-        expectEquals(1 /* header row */, $('message-logs-table').rows.length);
+        let expectedNumberOfRows = 2;  // header row and clear blacklist log.
+        let rows = $('message-logs-table').rows;
+        expectEquals(expectedNumberOfRows, rows.length);
+        expectEquals(
+            'Blacklist Cleared',
+            rows[1].querySelector('.log-description').textContent);
       });
 
       mocha.run();
diff --git a/chrome/utility/chrome_content_utility_client.cc b/chrome/utility/chrome_content_utility_client.cc
index f257d161..3b3e0ba3 100644
--- a/chrome/utility/chrome_content_utility_client.cc
+++ b/chrome/utility/chrome_content_utility_client.cc
@@ -222,7 +222,7 @@
 #if BUILDFLAG(ENABLE_PRINT_PREVIEW)
   service_manager::EmbeddedServiceInfo pdf_to_pwg_converter_info;
   pdf_to_pwg_converter_info.factory =
-      base::Bind(&printing::PDFToPWGRasterConverterService::CreateService);
+      base::Bind(&printing::PdfToPwgRasterConverterService::CreateService);
   services->emplace(printing::mojom::kPdfToPwgRasterConverterServiceName,
                     pdf_to_pwg_converter_info);
 #endif
diff --git a/chrome/utility/printing/pdf_to_pwg_raster_converter_impl.cc b/chrome/utility/printing/pdf_to_pwg_raster_converter_impl.cc
index c2bcf2d..3cd6056e 100644
--- a/chrome/utility/printing/pdf_to_pwg_raster_converter_impl.cc
+++ b/chrome/utility/printing/pdf_to_pwg_raster_converter_impl.cc
@@ -14,7 +14,7 @@
 
 namespace {
 
-bool RenderPDFPagesToPWGRaster(base::File pdf_file,
+bool RenderPdfPagesToPwgRaster(base::File pdf_file,
                                const PdfRenderSettings& settings,
                                const PwgRasterSettings& bitmap_settings,
                                base::File bitmap_file) {
@@ -96,13 +96,13 @@
 
 }  // namespace
 
-PDFToPWGRasterConverterImpl::PDFToPWGRasterConverterImpl(
+PdfToPwgRasterConverterImpl::PdfToPwgRasterConverterImpl(
     std::unique_ptr<service_manager::ServiceContextRef> service_ref)
     : service_ref_(std::move(service_ref)) {}
 
-PDFToPWGRasterConverterImpl::~PDFToPWGRasterConverterImpl() {}
+PdfToPwgRasterConverterImpl::~PdfToPwgRasterConverterImpl() {}
 
-void PDFToPWGRasterConverterImpl::Convert(
+void PdfToPwgRasterConverterImpl::Convert(
     mojo::ScopedHandle pdf_file_in,
     const PdfRenderSettings& pdf_settings,
     const PwgRasterSettings& pwg_raster_settings,
@@ -111,7 +111,7 @@
   base::PlatformFile pdf_file;
   if (mojo::UnwrapPlatformFile(std::move(pdf_file_in), &pdf_file) !=
       MOJO_RESULT_OK) {
-    LOG(ERROR) << "Invalid PDF file passed to PDFToPWGRasterConverterImpl";
+    LOG(ERROR) << "Invalid PDF file passed to PdfToPwgRasterConverterImpl";
     std::move(callback).Run(false);
     return;
   }
@@ -120,12 +120,12 @@
   if (mojo::UnwrapPlatformFile(std::move(pwg_raster_file_out),
                                &pwg_raster_file) != MOJO_RESULT_OK) {
     LOG(ERROR)
-        << "Invalid PWGRaster file passed to PDFToPWGRasterConverterImpl";
+        << "Invalid PWGRaster file passed to PdfToPwgRasterConverterImpl";
     std::move(callback).Run(false);
     return;
   }
 
-  bool result = RenderPDFPagesToPWGRaster(base::File(pdf_file), pdf_settings,
+  bool result = RenderPdfPagesToPwgRaster(base::File(pdf_file), pdf_settings,
                                           pwg_raster_settings,
                                           base::File(pwg_raster_file));
   std::move(callback).Run(result);
diff --git a/chrome/utility/printing/pdf_to_pwg_raster_converter_impl.h b/chrome/utility/printing/pdf_to_pwg_raster_converter_impl.h
index aad4fb6..2a88df8 100644
--- a/chrome/utility/printing/pdf_to_pwg_raster_converter_impl.h
+++ b/chrome/utility/printing/pdf_to_pwg_raster_converter_impl.h
@@ -14,15 +14,15 @@
 
 namespace printing {
 
-class PDFToPWGRasterConverterImpl
-    : public printing::mojom::PDFToPWGRasterConverter {
+class PdfToPwgRasterConverterImpl
+    : public printing::mojom::PdfToPwgRasterConverter {
  public:
-  explicit PDFToPWGRasterConverterImpl(
+  explicit PdfToPwgRasterConverterImpl(
       std::unique_ptr<service_manager::ServiceContextRef> service_ref);
-  ~PDFToPWGRasterConverterImpl() override;
+  ~PdfToPwgRasterConverterImpl() override;
 
  private:
-  // printing::mojom::PDFToPWGRasterConverter
+  // printing::mojom::PdfToPwgRasterConverter
   void Convert(mojo::ScopedHandle pdf_file_in,
                const PdfRenderSettings& pdf_settings,
                const PwgRasterSettings& pwg_raster_settings,
@@ -31,7 +31,7 @@
 
   const std::unique_ptr<service_manager::ServiceContextRef> service_ref_;
 
-  DISALLOW_COPY_AND_ASSIGN(PDFToPWGRasterConverterImpl);
+  DISALLOW_COPY_AND_ASSIGN(PdfToPwgRasterConverterImpl);
 };
 
 }  // namespace printing
diff --git a/chrome/utility/printing/pdf_to_pwg_raster_converter_manifest.json b/chrome/utility/printing/pdf_to_pwg_raster_converter_manifest.json
index d49419ba..cb6b923 100644
--- a/chrome/utility/printing/pdf_to_pwg_raster_converter_manifest.json
+++ b/chrome/utility/printing/pdf_to_pwg_raster_converter_manifest.json
@@ -4,7 +4,7 @@
   "interface_provider_specs": {
     "service_manager:connector": {
       "provides": {
-        "converter": [ "printing::mojom::PDFToPWGRasterConverter" ]
+        "converter": [ "printing::mojom::PdfToPwgRasterConverter" ]
        },
        "requires": {
          "service_manager": [ "service_manager:all_users" ]
diff --git a/chrome/utility/printing/pdf_to_pwg_raster_converter_service.cc b/chrome/utility/printing/pdf_to_pwg_raster_converter_service.cc
index 7a1bab7..db875a14 100644
--- a/chrome/utility/printing/pdf_to_pwg_raster_converter_service.cc
+++ b/chrome/utility/printing/pdf_to_pwg_raster_converter_service.cc
@@ -12,35 +12,35 @@
 
 namespace {
 
-void OnPDFToPWGRasterConverterRequest(
+void OnPdfToPwgRasterConverterRequest(
     service_manager::ServiceContextRefFactory* ref_factory,
-    printing::mojom::PDFToPWGRasterConverterRequest request) {
+    printing::mojom::PdfToPwgRasterConverterRequest request) {
   mojo::MakeStrongBinding(
-      std::make_unique<printing::PDFToPWGRasterConverterImpl>(
+      std::make_unique<printing::PdfToPwgRasterConverterImpl>(
           ref_factory->CreateRef()),
       std::move(request));
 }
 
 }  // namespace
 
-PDFToPWGRasterConverterService::PDFToPWGRasterConverterService() {}
+PdfToPwgRasterConverterService::PdfToPwgRasterConverterService() {}
 
-PDFToPWGRasterConverterService::~PDFToPWGRasterConverterService() {}
+PdfToPwgRasterConverterService::~PdfToPwgRasterConverterService() {}
 
 std::unique_ptr<service_manager::Service>
-PDFToPWGRasterConverterService::CreateService() {
-  return base::MakeUnique<PDFToPWGRasterConverterService>();
+PdfToPwgRasterConverterService::CreateService() {
+  return std::make_unique<PdfToPwgRasterConverterService>();
 }
 
-void PDFToPWGRasterConverterService::OnStart() {
+void PdfToPwgRasterConverterService::OnStart() {
   ref_factory_ = std::make_unique<service_manager::ServiceContextRefFactory>(
       base::Bind(&service_manager::ServiceContext::RequestQuit,
                  base::Unretained(context())));
   registry_.AddInterface(
-      base::Bind(&OnPDFToPWGRasterConverterRequest, ref_factory_.get()));
+      base::Bind(&OnPdfToPwgRasterConverterRequest, ref_factory_.get()));
 }
 
-void PDFToPWGRasterConverterService::OnBindInterface(
+void PdfToPwgRasterConverterService::OnBindInterface(
     const service_manager::BindSourceInfo& source_info,
     const std::string& interface_name,
     mojo::ScopedMessagePipeHandle interface_pipe) {
diff --git a/chrome/utility/printing/pdf_to_pwg_raster_converter_service.h b/chrome/utility/printing/pdf_to_pwg_raster_converter_service.h
index 9232722..5f66341 100644
--- a/chrome/utility/printing/pdf_to_pwg_raster_converter_service.h
+++ b/chrome/utility/printing/pdf_to_pwg_raster_converter_service.h
@@ -11,10 +11,10 @@
 
 namespace printing {
 
-class PDFToPWGRasterConverterService : public service_manager::Service {
+class PdfToPwgRasterConverterService : public service_manager::Service {
  public:
-  PDFToPWGRasterConverterService();
-  ~PDFToPWGRasterConverterService() override;
+  PdfToPwgRasterConverterService();
+  ~PdfToPwgRasterConverterService() override;
 
   // Factory method for creating the service.
   static std::unique_ptr<service_manager::Service> CreateService();
@@ -30,7 +30,7 @@
   std::unique_ptr<service_manager::ServiceContextRefFactory> ref_factory_;
   service_manager::BinderRegistry registry_;
 
-  DISALLOW_COPY_AND_ASSIGN(PDFToPWGRasterConverterService);
+  DISALLOW_COPY_AND_ASSIGN(PdfToPwgRasterConverterService);
 };
 
 }  // namespace printing
diff --git a/chromecast/browser/BUILD.gn b/chromecast/browser/BUILD.gn
index 117f420..1d87afc4 100644
--- a/chromecast/browser/BUILD.gn
+++ b/chromecast/browser/BUILD.gn
@@ -70,6 +70,7 @@
 
   if (chromecast_branding == "public") {
     sources += [
+      "cast_browser_main_parts_simple.cc",
       "cast_content_browser_client_simple.cc",
       "cast_network_delegate_simple.cc",
       "pref_service_helper_simple.cc",
diff --git a/chromecast/browser/cast_browser_main_parts.cc b/chromecast/browser/cast_browser_main_parts.cc
index 2334f02..52daf29 100644
--- a/chromecast/browser/cast_browser_main_parts.cc
+++ b/chromecast/browser/cast_browser_main_parts.cc
@@ -442,9 +442,6 @@
       command_line->GetSwitchValueASCII(switches::kEnableFeatures),
       command_line->GetSwitchValueASCII(switches::kDisableFeatures));
 
-  // Hook for internal code
-  cast_browser_process_->browser_client()->PreCreateThreads();
-
 #if defined(USE_AURA)
   cast_browser_process_->SetCastScreen(base::WrapUnique(new CastScreen()));
   DCHECK(!display::Screen::GetScreen());
diff --git a/chromecast/browser/cast_browser_main_parts.h b/chromecast/browser/cast_browser_main_parts.h
index df504306..69e150a1 100644
--- a/chromecast/browser/cast_browser_main_parts.h
+++ b/chromecast/browser/cast_browser_main_parts.h
@@ -42,6 +42,12 @@
 
 class CastBrowserMainParts : public content::BrowserMainParts {
  public:
+  // Creates an implementation of CastBrowserMainParts. Platform should
+  // link in an implementation as needed.
+  static std::unique_ptr<CastBrowserMainParts> Create(
+      const content::MainFunctionParams& parameters,
+      URLRequestContextFactory* url_request_context_factory);
+
   // This class does not take ownership of |url_request_content_factory|.
   CastBrowserMainParts(const content::MainFunctionParams& parameters,
                        URLRequestContextFactory* url_request_context_factory);
diff --git a/chromecast/browser/cast_browser_main_parts_simple.cc b/chromecast/browser/cast_browser_main_parts_simple.cc
new file mode 100644
index 0000000..c442288
--- /dev/null
+++ b/chromecast/browser/cast_browser_main_parts_simple.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 "chromecast/browser/cast_browser_main_parts.h"
+
+namespace chromecast {
+namespace shell {
+
+// static
+std::unique_ptr<CastBrowserMainParts> CastBrowserMainParts::Create(
+    const content::MainFunctionParams& parameters,
+    URLRequestContextFactory* url_request_context_factory) {
+  return std::make_unique<CastBrowserMainParts>(parameters,
+                                                url_request_context_factory);
+}
+
+}  // namespace shell
+}  // namespace chromecast
diff --git a/chromecast/browser/cast_content_browser_client.cc b/chromecast/browser/cast_content_browser_client.cc
index 9d6623f..40f0748 100644
--- a/chromecast/browser/cast_content_browser_client.cc
+++ b/chromecast/browser/cast_content_browser_client.cc
@@ -182,8 +182,6 @@
 #endif  // defined(USE_AURA)
 }
 
-void CastContentBrowserClient::PreCreateThreads() {}
-
 std::unique_ptr<CastService> CastContentBrowserClient::CreateCastService(
     content::BrowserContext* browser_context,
     PrefService* pref_service,
@@ -282,10 +280,14 @@
 content::BrowserMainParts* CastContentBrowserClient::CreateBrowserMainParts(
     const content::MainFunctionParams& parameters) {
   DCHECK(!cast_browser_main_parts_);
-  cast_browser_main_parts_ =
-      new CastBrowserMainParts(parameters, url_request_context_factory_.get());
+  auto main_parts = CastBrowserMainParts::Create(
+      parameters, url_request_context_factory_.get());
+  cast_browser_main_parts_ = main_parts.get();
   CastBrowserProcess::GetInstance()->SetCastContentBrowserClient(this);
-  return cast_browser_main_parts_;
+
+  // TODO(halliwell): would like to change CreateBrowserMainParts to return
+  // unique_ptr, then we don't have to release.
+  return main_parts.release();
 }
 
 void CastContentBrowserClient::RenderProcessWillLaunch(
diff --git a/chromecast/browser/cast_content_browser_client.h b/chromecast/browser/cast_content_browser_client.h
index f276b6d..c6aa7b1 100644
--- a/chromecast/browser/cast_content_browser_client.h
+++ b/chromecast/browser/cast_content_browser_client.h
@@ -67,9 +67,6 @@
   // Appends extra command line arguments before launching a new process.
   virtual void AppendExtraCommandLineSwitches(base::CommandLine* command_line);
 
-  // Hook for code to run before browser threads created.
-  virtual void PreCreateThreads();
-
   // Creates and returns the CastService instance for the current process.
   // Note: |request_context_getter| might be different than the main request
   // getter accessible via CastBrowserProcess.
diff --git a/chromecast/browser/metrics/cast_metrics_service_client.cc b/chromecast/browser/metrics/cast_metrics_service_client.cc
index cf8085af..ae199fd 100644
--- a/chromecast/browser/metrics/cast_metrics_service_client.cc
+++ b/chromecast/browser/metrics/cast_metrics_service_client.cc
@@ -253,7 +253,7 @@
   return base::TimeDelta::FromMinutes(kStandardUploadIntervalMinutes);
 }
 
-bool CastMetricsServiceClient::IsConsentGiven() {
+bool CastMetricsServiceClient::IsConsentGiven() const {
   return pref_service_->GetBoolean(prefs::kOptInStats);
 }
 
diff --git a/chromecast/browser/metrics/cast_metrics_service_client.h b/chromecast/browser/metrics/cast_metrics_service_client.h
index 1080b61..cf00abc 100644
--- a/chromecast/browser/metrics/cast_metrics_service_client.h
+++ b/chromecast/browser/metrics/cast_metrics_service_client.h
@@ -84,7 +84,7 @@
   base::TimeDelta GetStandardUploadInterval() override;
 
   // ::metrics::EnabledStateProvider:
-  bool IsConsentGiven() override;
+  bool IsConsentGiven() const override;
 
   // Starts/stops the metrics service.
   void EnableMetricsService(bool enabled);
diff --git a/chromecast/tools/trace.py b/chromecast/tools/trace.py
index 0e4383b0..9342e600 100755
--- a/chromecast/tools/trace.py
+++ b/chromecast/tools/trace.py
@@ -100,11 +100,11 @@
     tracing_backend.StartTracing(options.category_filter,
                                  options.record_continuously, options.systrace)
     raw_input('Capturing trace. Press Enter to stop...')
-    filepath = GetOutputFilePath(options)
-    tracing_backend.StopTracing(filepath)
+    output_path_base = GetOutputFilePath(options)
+    output_path = tracing_backend.StopTracing(output_path_base)
 
   print('Done')
-  print('Trace written to file://%s' % filepath)
+  print('Trace written to file://%s' % output_path)
 
 
 if __name__ == '__main__':
diff --git a/chromecast/tools/tracinglib.py b/chromecast/tools/tracinglib.py
index af8097f4..243adc25 100644
--- a/chromecast/tools/tracinglib.py
+++ b/chromecast/tools/tracinglib.py
@@ -5,6 +5,7 @@
 
 """Utilities for capturing traces for chromecast devices."""
 
+import base64
 import json
 import logging
 import math
@@ -45,6 +46,7 @@
     self._excluded_categories = []
     self._pending_read_ids = []
     self._stream_handle = None
+    self._output_file = None
 
   def Connect(self):
     """Connect to cast_shell."""
@@ -82,6 +84,8 @@
         'params': {
             'transferMode':
                 'ReturnAsStream' if systrace else 'ReportEvents',
+            'streamCompression':
+                'gzip' if systrace else 'none',
             'traceConfig': {
                 'enableSystrace':
                     systrace,
@@ -99,28 +103,39 @@
     }
     self._SendRequest(req)
 
-  def StopTracing(self, output_file):
+  def StopTracing(self, output_path_base):
     """End a tracing session on device.
 
     Args:
-      output_file: Path to the file to store the trace.
+      output_path_base: Path to the file to store the trace. A .gz extension
+        will be appended to this path if the trace is compressed.
+
+    Returns:
+      Final output filename.
     """
     self._socket.settimeout(self._timeout)
     req = {'method': 'Tracing.end'}
     self._SendRequest(req)
+    self._output_path_base = output_path_base
 
-    with open(output_file, 'w') as f:
+    try:
       while self._socket:
         res = self._ReceiveResponse()
         has_error = 'error' in res
         if has_error:
           logging.error('Tracing error: ' + str(res.get('error')))
-        if has_error or self._HandleResponse(res, f):
+        if has_error or self._HandleResponse(res):
           self._tracing_client = None
           if not self._stream_handle:
-            json.dump(self._tracing_data, f)
+            # Compression not supported for ReportEvents transport.
+            self._output_path = self._output_path_base
+            with open(self._output_path, 'w') as output_file:
+              json.dump(self._tracing_data, output_file)
           self._tracing_data = []
-          return
+          return self._output_path
+    finally:
+      if self._output_file:
+        self._output_file.close()
 
   def _SendRequest(self, req):
     """Sends request to remote devtools.
@@ -159,7 +174,7 @@
     while len(self._pending_read_ids) < 2:
       self._pending_read_ids.append(self._SendRequest(req))
 
-  def _HandleResponse(self, res, output_file):
+  def _HandleResponse(self, res):
     """Handle response from remote devtools.
 
     Args:
@@ -179,7 +194,13 @@
       self._tracing_client.BufferUsage(value)
     elif 'Tracing.tracingComplete' == method:
       self._stream_handle = res.get('params', {}).get('stream')
+      compression = res.get('params', {}).get('streamCompression')
       if self._stream_handle:
+        compression_suffix = '.gz' if compression == 'gzip' else ''
+        self._output_path = self._output_path_base
+        if not self._output_path.endswith(compression_suffix):
+          self._output_path += compression_suffix
+        self._output_file = open(self._output_path, 'w')
         self._SendReadRequest()
       else:
         return True
@@ -187,7 +208,12 @@
       self._pending_read_ids.remove(response_id)
       data = res.get('result', {}).get('data')
       eof = res.get('result', {}).get('eof')
-      output_file.write(data.encode('utf-8'))
+      base64_encoded = res.get('result', {}).get('base64Encoded')
+      if base64_encoded:
+        data = base64.b64decode(data)
+      else:
+        data = data.encode('utf-8')
+      self._output_file.write(data)
       if eof:
         return True
       else:
@@ -262,6 +288,7 @@
         break
 
     self._AdbCommand(['pull', self._file, output_file])
+    return output_file
 
   def _AdbCommand(self, command):
     args = ['adb', '-s', self.device]
diff --git a/chromeos/dbus/fake_power_manager_client.cc b/chromeos/dbus/fake_power_manager_client.cc
index 12b245a..acd9780 100644
--- a/chromeos/dbus/fake_power_manager_client.cc
+++ b/chromeos/dbus/fake_power_manager_client.cc
@@ -59,6 +59,11 @@
 void FakePowerManagerClient::SetScreenBrightnessPercent(double percent,
                                                         bool gradual) {
   screen_brightness_percent_ = percent;
+  requested_screen_brightness_percent_ = percent;
+
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE, base::BindOnce(&FakePowerManagerClient::SendBrightnessChanged,
+                                weak_ptr_factory_.GetWeakPtr(), percent, true));
 }
 
 void FakePowerManagerClient::GetScreenBrightnessPercent(
@@ -96,7 +101,10 @@
 }
 
 void FakePowerManagerClient::NotifyUserActivity(
-    power_manager::UserActivityType type) {}
+    power_manager::UserActivityType type) {
+  if (user_activity_callback_)
+    user_activity_callback_.Run();
+}
 
 void FakePowerManagerClient::NotifyVideoActivity(bool is_fullscreen) {
   video_activity_reports_.push_back(is_fullscreen);
@@ -136,6 +144,19 @@
 void FakePowerManagerClient::SetBacklightsForcedOff(bool forced_off) {
   backlights_forced_off_ = forced_off;
   ++num_set_backlights_forced_off_calls_;
+
+  double target_brightness =
+      forced_off ? 0 : requested_screen_brightness_percent_;
+  if (enqueue_brightness_changes_on_backlights_forced_off_) {
+    pending_brightness_changes_.push(target_brightness);
+  } else {
+    screen_brightness_percent_ = target_brightness;
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
+        FROM_HERE,
+        base::BindOnce(&FakePowerManagerClient::SendBrightnessChanged,
+                       weak_ptr_factory_.GetWeakPtr(), target_brightness,
+                       false));
+  }
 }
 
 void FakePowerManagerClient::GetBacklightsForcedOff(
@@ -252,4 +273,17 @@
   power_policy_quit_closure_ = std::move(quit_closure);
 }
 
+bool FakePowerManagerClient::ApplyPendingBrightnessChange() {
+  if (pending_brightness_changes_.empty())
+    return false;
+  double brightness = pending_brightness_changes_.front();
+  pending_brightness_changes_.pop();
+
+  DCHECK(brightness == 0 || brightness == requested_screen_brightness_percent_);
+
+  screen_brightness_percent_ = brightness;
+  SendBrightnessChanged(brightness, false);
+  return true;
+}
+
 }  // namespace chromeos
diff --git a/chromeos/dbus/fake_power_manager_client.h b/chromeos/dbus/fake_power_manager_client.h
index e845917..09d0901c 100644
--- a/chromeos/dbus/fake_power_manager_client.h
+++ b/chromeos/dbus/fake_power_manager_client.h
@@ -5,7 +5,9 @@
 #ifndef CHROMEOS_DBUS_FAKE_POWER_MANAGER_CLIENT_H_
 #define CHROMEOS_DBUS_FAKE_POWER_MANAGER_CLIENT_H_
 
+#include <queue>
 #include <string>
+#include <utility>
 
 #include "base/callback_forward.h"
 #include "base/containers/circular_deque.h"
@@ -48,6 +50,15 @@
   int num_set_backlights_forced_off_calls() const {
     return num_set_backlights_forced_off_calls_;
   }
+  void set_enqueue_brightness_changes_on_backlights_forced_off(bool enqueue) {
+    enqueue_brightness_changes_on_backlights_forced_off_ = enqueue;
+  }
+  const std::queue<double>& pending_brightness_changes() const {
+    return pending_brightness_changes_;
+  }
+  void set_user_activity_callback(base::RepeatingClosure callback) {
+    user_activity_callback_ = std::move(callback);
+  }
 
   // PowerManagerClient overrides:
   void Init(dbus::Bus* bus) override;
@@ -117,6 +128,12 @@
   // lock has been created.
   void SetPowerPolicyQuitClosure(base::OnceClosure quit_closure);
 
+  // Updates screen brightness to the first pending value in
+  // |pending_brightness_changes_|.
+  // Returns whether the screen brightness change was applied - this will
+  // return false if there are no pending brightness changes.
+  bool ApplyPendingBrightnessChange();
+
   // Sets the screen brightness percent to be returned.
   // The nullopt |percent| means an error. In case of success,
   // |percent| must be in the range of [0, 100].
@@ -150,9 +167,16 @@
   // Number of pending suspend readiness callbacks.
   int num_pending_suspend_readiness_callbacks_ = 0;
 
-  // The ratio of the screen brightness.
+  // Current screen brightness in the range [0.0, 100.0].
   base::Optional<double> screen_brightness_percent_;
 
+  // Last screen brightness requested via SetScreenBrightnessPercent().
+  // Unlike |screen_brightness_percent_|, this value will not be changed by
+  // SetBacklightsForcedOff() method - a method that implicitly changes screen
+  // brightness.
+  // Initially set to an arbitrary non-null value.
+  double requested_screen_brightness_percent_ = 80;
+
   // Last projecting state set in SetIsProjecting().
   bool is_projecting_ = false;
 
@@ -160,6 +184,20 @@
   // SetBacklightsForcedOff().
   bool backlights_forced_off_ = false;
 
+  // Whether screen brightness changes in SetBacklightsForcedOff() should be
+  // enqueued.
+  // If not set, SetBacklightsForcedOff() will update current screen
+  // brightness and send a brightness change event (provided undimmed
+  // brightness percent is set).
+  // If set, brightness changes will be enqueued to
+  // pending_brightness_changes_, and will have to be applied explicitly by
+  // calling ApplyPendingBrightnessChange().
+  bool enqueue_brightness_changes_on_backlights_forced_off_ = false;
+
+  // Pending brightness changes caused by SetBacklightsForcedOff().
+  // ApplyPendingBrightnessChange() applies the first pending change.
+  std::queue<double> pending_brightness_changes_;
+
   // States returned by GetSwitchStates().
   LidState lid_state_ = LidState::OPEN;
   TabletMode tablet_mode_ = TabletMode::UNSUPPORTED;
@@ -174,6 +212,9 @@
   // If non-empty, called by SetPowerPolicy().
   base::OnceClosure power_policy_quit_closure_;
 
+  // If non-empty, called by NotifyUserActivity().
+  base::RepeatingClosure user_activity_callback_;
+
   // Note: This should remain the last member so it'll be destroyed and
   // invalidate its weak pointers before any other members are destroyed.
   base::WeakPtrFactory<FakePowerManagerClient> weak_ptr_factory_;
diff --git a/chromeos/network/client_cert_resolver.cc b/chromeos/network/client_cert_resolver.cc
index 34f1547..a358ad69 100644
--- a/chromeos/network/client_cert_resolver.cc
+++ b/chromeos/network/client_cert_resolver.cc
@@ -169,7 +169,7 @@
     return std::string();
   }
   std::string pem_encoded_issuer;
-  if (!net::X509Certificate::GetPEMEncoded(issuer->os_cert_handle(),
+  if (!net::X509Certificate::GetPEMEncoded(issuer->cert_buffer(),
                                            &pem_encoded_issuer)) {
     LOG(ERROR) << "Couldn't PEM-encode certificate.";
     return std::string();
diff --git a/chromeos/network/network_state_handler.cc b/chromeos/network/network_state_handler.cc
index 9ab391da..924d930 100644
--- a/chromeos/network/network_state_handler.cc
+++ b/chromeos/network/network_state_handler.cc
@@ -1410,8 +1410,8 @@
       // If the new default network from Shill's point of view is a Wi-Fi
       // network which corresponds to a hotspot for a Tether network, set the
       // default network to be the associated Tether network instead.
-      default_network_path_ = network->tether_guid();
-      return;
+      network = GetNetworkStateFromGuid(network->tether_guid());
+      default_network_path_ = network->path();
     }
   }
   if (network && !network->IsConnectedState()) {
diff --git a/chromeos/network/network_state_handler_unittest.cc b/chromeos/network/network_state_handler_unittest.cc
index 5f37a63a1..1ec49d5 100644
--- a/chromeos/network/network_state_handler_unittest.cc
+++ b/chromeos/network/network_state_handler_unittest.cc
@@ -1333,6 +1333,82 @@
 }
 
 TEST_F(NetworkStateHandlerTest,
+       EthernetIsDefaultNetwork_ThenTetherConnects_ThenEthernetDisconnects) {
+  network_state_handler_->SetTetherTechnologyState(
+      NetworkStateHandler::TECHNOLOGY_ENABLED);
+
+  // The ethernet corresponding to |eth1| starts out connected, then ends up
+  // becoming disconnected.
+  const std::string eth1 = kShillManagerClientStubDefaultService;
+
+  // Disconnect the Wi-Fi network, which will serve as the underlying connection
+  // for the Tether network under test.
+  const std::string wifi1 = kShillManagerClientStubDefaultWifi;
+  service_test_->SetServiceProperty(wifi1, shill::kStateProperty,
+                                    base::Value(shill::kStateIdle));
+  base::RunLoop().RunUntilIdle();
+  EXPECT_EQ(eth1, test_observer_->default_network());
+
+  // Simulate a host scan, and reset the change counts for the connection flow.
+  network_state_handler_->AddTetherNetworkState(
+      kTetherGuid1, kTetherName1, kTetherCarrier1, kTetherBatteryPercentage1,
+      kTetherSignalStrength1, kTetherHasConnectedToHost1);
+  test_observer_->reset_change_counts();
+  test_observer_->reset_updates();
+
+  // Preconditions.
+  EXPECT_EQ(0, test_observer_->ConnectionStateChangesForService(kTetherGuid1));
+  EXPECT_EQ(0, test_observer_->PropertyUpdatesForService(kTetherGuid1));
+  EXPECT_EQ(0u, test_observer_->default_network_change_count());
+  EXPECT_EQ(eth1, test_observer_->default_network());
+  EXPECT_EQ(shill::kStateOnline,
+            test_observer_->default_network_connection_state());
+
+  // Set the Tether network state to "connecting." This is expected to be called
+  // before the connection to the underlying hotspot Wi-Fi network begins.
+  const NetworkState* tether_network =
+      network_state_handler_->GetNetworkStateFromGuid(kTetherGuid1);
+  network_state_handler_->SetTetherNetworkStateConnecting(kTetherGuid1);
+  EXPECT_TRUE(tether_network->IsConnectingState());
+  EXPECT_EQ(1, test_observer_->ConnectionStateChangesForService(kTetherGuid1));
+  EXPECT_EQ(1, test_observer_->PropertyUpdatesForService(kTetherGuid1));
+
+  // Associate Tether and Wi-Fi networks.
+  network_state_handler_->AssociateTetherNetworkStateWithWifiNetwork(
+      kTetherGuid1, "wifi1_guid");
+  EXPECT_EQ(1, test_observer_->ConnectionStateChangesForService(kTetherGuid1));
+  EXPECT_EQ(2, test_observer_->PropertyUpdatesForService(kTetherGuid1));
+
+  // Connect to the underlying Wi-Fi network.
+  service_test_->SetServiceProperty(wifi1, shill::kStateProperty,
+                                    base::Value(shill::kStateOnline));
+  base::RunLoop().RunUntilIdle();
+
+  // Now, set the Tether network state to "connected."
+  network_state_handler_->SetTetherNetworkStateConnected(kTetherGuid1);
+  EXPECT_TRUE(tether_network->IsConnectedState());
+  EXPECT_EQ(2, test_observer_->ConnectionStateChangesForService(kTetherGuid1));
+  EXPECT_EQ(3, test_observer_->PropertyUpdatesForService(kTetherGuid1));
+
+  // No default network changes should have occurred, since the Ethernet
+  // network should still be considered the default network.
+  EXPECT_EQ(0u, test_observer_->default_network_change_count());
+
+  // Disconnect from the Ethernet network.
+  service_test_->SetServiceProperty(eth1, shill::kStateProperty,
+                                    base::Value(shill::kStateIdle));
+  base::RunLoop().RunUntilIdle();
+
+  // The Tether network should now be the default network. However, there should
+  // have been two updates to the default network: one which changed it from
+  // |eth1| to null, then one from null to |kTetherGuid1"|.
+  EXPECT_EQ(2u, test_observer_->default_network_change_count());
+  EXPECT_EQ(kTetherGuid1, test_observer_->default_network());
+  EXPECT_EQ(shill::kStateOnline,
+            test_observer_->default_network_connection_state());
+}
+
+TEST_F(NetworkStateHandlerTest,
        SetTetherNetworkStateConnectionState_NoDefaultThenTetherThenEthernet) {
   network_state_handler_->SetTetherTechnologyState(
       NetworkStateHandler::TECHNOLOGY_ENABLED);
diff --git a/components/arc/BUILD.gn b/components/arc/BUILD.gn
index 9d5d168..941cf63 100644
--- a/components/arc/BUILD.gn
+++ b/components/arc/BUILD.gn
@@ -167,6 +167,8 @@
     "test/fake_arc_bridge_host.h",
     "test/fake_arc_session.cc",
     "test/fake_arc_session.h",
+    "test/fake_backup_settings_instance.cc",
+    "test/fake_backup_settings_instance.h",
     "test/fake_bluetooth_instance.cc",
     "test/fake_bluetooth_instance.h",
     "test/fake_file_system_instance.cc",
diff --git a/components/arc/test/fake_backup_settings_instance.cc b/components/arc/test/fake_backup_settings_instance.cc
new file mode 100644
index 0000000..8465281
--- /dev/null
+++ b/components/arc/test/fake_backup_settings_instance.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 "components/arc/test/fake_backup_settings_instance.h"
+
+namespace arc {
+
+FakeBackupSettingsInstance::FakeBackupSettingsInstance() = default;
+
+FakeBackupSettingsInstance::~FakeBackupSettingsInstance() = default;
+
+void FakeBackupSettingsInstance::ClearCallHistory() {
+  set_backup_enabled_called_ = false;
+}
+
+void FakeBackupSettingsInstance::SetBackupEnabled(bool enabled, bool managed) {
+  set_backup_enabled_called_ = true;
+  enabled_ = enabled;
+  managed_ = managed;
+}
+
+}  // namespace arc
diff --git a/components/arc/test/fake_backup_settings_instance.h b/components/arc/test/fake_backup_settings_instance.h
new file mode 100644
index 0000000..7f4212dc
--- /dev/null
+++ b/components/arc/test/fake_backup_settings_instance.h
@@ -0,0 +1,37 @@
+// 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_ARC_TEST_FAKE_BACKUP_SETTINGS_INSTANCE_H_
+#define COMPONENTS_ARC_TEST_FAKE_BACKUP_SETTINGS_INSTANCE_H_
+
+#include "base/macros.h"
+#include "components/arc/common/backup_settings.mojom.h"
+
+namespace arc {
+
+class FakeBackupSettingsInstance : public mojom::BackupSettingsInstance {
+ public:
+  FakeBackupSettingsInstance();
+  ~FakeBackupSettingsInstance() override;
+
+  // mojom::BackupSettingsInstance overrides:
+  void SetBackupEnabled(bool enabled, bool managed) override;
+
+  void ClearCallHistory();
+
+  bool set_backup_enabled_called() const { return set_backup_enabled_called_; }
+  bool enabled() const { return enabled_; }
+  bool managed() const { return managed_; }
+
+ private:
+  bool set_backup_enabled_called_ = false;
+  bool enabled_ = false;
+  bool managed_ = false;
+
+  DISALLOW_COPY_AND_ASSIGN(FakeBackupSettingsInstance);
+};
+
+}  // namespace arc
+
+#endif  // COMPONENTS_ARC_TEST_FAKE_BACKUP_SETTINGS_INSTANCE_H_
diff --git a/components/autofill/content/browser/risk/fingerprint.cc b/components/autofill/content/browser/risk/fingerprint.cc
index 3a97366f..37ddaf7 100644
--- a/components/autofill/content/browser/risk/fingerprint.cc
+++ b/components/autofill/content/browser/risk/fingerprint.cc
@@ -205,10 +205,7 @@
   // Callbacks for asynchronously loaded data.
   void OnGotFonts(std::unique_ptr<base::ListValue> fonts);
   void OnGotPlugins(const std::vector<content::WebPluginInfo>& plugins);
-  void OnGotGeoposition(
-      device::mojom::GeolocationContextPtr geolocation_context,
-      device::mojom::GeolocationPtr geolocation,
-      device::mojom::GeopositionPtr geoposition);
+  void OnGotGeoposition(device::mojom::GeopositionPtr geoposition);
 
   // If all of the asynchronous data has been loaded, calls |callback_| with
   // the fingerprint data.
@@ -243,6 +240,8 @@
   std::vector<content::WebPluginInfo> plugins_;
   bool waiting_on_plugins_;
   device::mojom::Geoposition geoposition_;
+  device::mojom::GeolocationPtr geolocation_;
+  device::mojom::GeolocationContextPtr geolocation_context_;
 
   // Timer to enforce a maximum timeout before the |callback_| is called, even
   // if not all asynchronous data has been loaded.
@@ -316,18 +315,13 @@
 
   // Load geolocation data.
   DCHECK(connector);
-  device::mojom::GeolocationContextPtr geolocation_context;
-  device::mojom::GeolocationPtr geolocation;
   connector->BindInterface(device::mojom::kServiceName,
-                           mojo::MakeRequest(&geolocation_context));
-  geolocation_context->BindGeolocation(mojo::MakeRequest(&geolocation));
-  geolocation->SetHighAccuracy(false);
-  geolocation->QueryNextPosition(
-      // Pass the ownership of |geolocation_context| and |geolocation| to ensure
-      // the connections are kept alive until the callback is received.
+                           mojo::MakeRequest(&geolocation_context_));
+  geolocation_context_->BindGeolocation(mojo::MakeRequest(&geolocation_));
+  geolocation_->SetHighAccuracy(false);
+  geolocation_->QueryNextPosition(
       base::BindOnce(&FingerprintDataLoader::OnGotGeoposition,
-                     weak_ptr_factory_.GetWeakPtr(),
-                     std::move(geolocation_context), std::move(geolocation)));
+                     weak_ptr_factory_.GetWeakPtr()));
 }
 
 void FingerprintDataLoader::OnGpuInfoUpdate() {
@@ -353,8 +347,6 @@
 }
 
 void FingerprintDataLoader::OnGotGeoposition(
-    device::mojom::GeolocationContextPtr geolocation_context,
-    device::mojom::GeolocationPtr geolocation,
     device::mojom::GeopositionPtr geoposition) {
   DCHECK(!device::ValidateGeoposition(geoposition_));
 
@@ -363,6 +355,9 @@
          geoposition_.error_code !=
              device::mojom::Geoposition::ErrorCode::NONE);
 
+  geolocation_.reset();
+  geolocation_context_.reset();
+
   MaybeFillFingerprint();
 }
 
diff --git a/components/autofill/core/browser/address_combobox_model_unittest.cc b/components/autofill/core/browser/address_combobox_model_unittest.cc
index d05efb0..487e735 100644
--- a/components/autofill/core/browser/address_combobox_model_unittest.cc
+++ b/components/autofill/core/browser/address_combobox_model_unittest.cc
@@ -28,7 +28,7 @@
 TEST(AddressComboboxModelTest, OneAddress) {
   TestPersonalDataManager test_personal_data_manager;
   AutofillProfile profile1(test::GetFullProfile());
-  test_personal_data_manager.AddTestingProfile(&profile1);
+  test_personal_data_manager.AddProfile(profile1);
 
   AddressComboboxModel model(test_personal_data_manager, kAppLocale,
                              profile1.guid());
@@ -50,8 +50,8 @@
 
   // Force |profile1| to be shown first in the combobox.
   profile1.set_use_count(100);
-  test_personal_data_manager.AddTestingProfile(&profile1);
-  test_personal_data_manager.AddTestingProfile(&profile2);
+  test_personal_data_manager.AddProfile(profile1);
+  test_personal_data_manager.AddProfile(profile2);
 
   AddressComboboxModel model(test_personal_data_manager, kAppLocale,
                              profile2.guid());
@@ -71,7 +71,7 @@
 TEST(AddressComboboxModelTest, AddAnAddress) {
   TestPersonalDataManager test_personal_data_manager;
   AutofillProfile profile1(test::GetFullProfile());
-  test_personal_data_manager.AddTestingProfile(&profile1);
+  test_personal_data_manager.AddProfile(profile1);
 
   AddressComboboxModel model(test_personal_data_manager, kAppLocale, "");
   EXPECT_EQ(3, model.GetItemCount());
diff --git a/components/autofill/core/browser/autofill_manager_unittest.cc b/components/autofill/core/browser/autofill_manager_unittest.cc
index 068102c..0f4b2a0 100644
--- a/components/autofill/core/browser/autofill_manager_unittest.cc
+++ b/components/autofill/core/browser/autofill_manager_unittest.cc
@@ -42,6 +42,7 @@
 #include "components/autofill/core/browser/test_autofill_clock.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_personal_data_manager.h"
 #include "components/autofill/core/browser/validation.h"
 #include "components/autofill/core/browser/webdata/autofill_webdata_service.h"
 #include "components/autofill/core/common/autofill_clock.h"
@@ -101,205 +102,6 @@
   DISALLOW_COPY_AND_ASSIGN(MockAutofillClient);
 };
 
-class TestPersonalDataManager : public PersonalDataManager {
- public:
-  TestPersonalDataManager()
-      : PersonalDataManager("en-US"),
-        num_times_save_imported_profile_called_(0) {
-    CreateTestAutofillProfiles(&web_profiles_);
-    CreateTestCreditCards(&local_credit_cards_);
-  }
-
-  using PersonalDataManager::set_database;
-  using PersonalDataManager::SetPrefService;
-
-  int num_times_save_imported_profile_called() {
-    return num_times_save_imported_profile_called_;
-  }
-
-  std::string SaveImportedProfile(const AutofillProfile& profile) override {
-    num_times_save_imported_profile_called_++;
-    AddProfile(profile);
-    return profile.guid();
-  }
-
-  AutofillProfile* GetProfileWithGUID(const char* guid) {
-    for (AutofillProfile* profile : GetProfiles()) {
-      if (!profile->guid().compare(guid))
-        return profile;
-    }
-    return nullptr;
-  }
-
-  CreditCard* GetCreditCardWithGUID(const char* guid) {
-    for (CreditCard* card : GetCreditCards()) {
-      if (!card->guid().compare(guid))
-        return card;
-    }
-    return nullptr;
-  }
-
-  void AddProfile(const AutofillProfile& profile) override {
-    std::unique_ptr<AutofillProfile> profile_ptr =
-        std::make_unique<AutofillProfile>(profile);
-    profile_ptr->set_modification_date(AutofillClock::Now());
-    web_profiles_.push_back(std::move(profile_ptr));
-  }
-
-  void AddCreditCard(const CreditCard& credit_card) override {
-    std::unique_ptr<CreditCard> local_credit_card =
-        std::make_unique<CreditCard>(credit_card);
-    local_credit_card->set_modification_date(AutofillClock::Now());
-    local_credit_cards_.push_back(std::move(local_credit_card));
-  }
-
-  void AddFullServerCreditCard(const CreditCard& credit_card) override {
-    AddServerCreditCard(credit_card);
-  }
-
-  void RecordUseOf(const AutofillDataModel& data_model) override {
-    CreditCard* credit_card = GetCreditCardWithGUID(data_model.guid().c_str());
-    if (credit_card)
-      credit_card->RecordAndLogUse();
-
-    AutofillProfile* profile = GetProfileWithGUID(data_model.guid().c_str());
-    if (profile)
-      profile->RecordAndLogUse();
-  }
-
-  void RemoveByGUID(const std::string& guid) override {
-    CreditCard* credit_card = GetCreditCardWithGUID(guid.c_str());
-    if (credit_card) {
-      local_credit_cards_.erase(
-          std::find_if(local_credit_cards_.begin(), local_credit_cards_.end(),
-                       [credit_card](const std::unique_ptr<CreditCard>& ptr) {
-                         return ptr.get() == credit_card;
-                       }));
-    }
-
-    AutofillProfile* profile = GetProfileWithGUID(guid.c_str());
-    if (profile) {
-      web_profiles_.erase(
-          std::find_if(web_profiles_.begin(), web_profiles_.end(),
-                       [profile](const std::unique_ptr<AutofillProfile>& ptr) {
-                         return ptr.get() == profile;
-                       }));
-    }
-  }
-
-  void ClearAutofillProfiles() { web_profiles_.clear(); }
-
-  void ClearCreditCards() {
-    local_credit_cards_.clear();
-    server_credit_cards_.clear();
-  }
-
-  void AddServerCreditCard(const CreditCard& credit_card) {
-    std::unique_ptr<CreditCard> server_credit_card =
-        std::make_unique<CreditCard>(credit_card);
-    server_credit_card->set_modification_date(AutofillClock::Now());
-    server_credit_cards_.push_back(std::move(server_credit_card));
-  }
-
-  // Create Elvis card with whitespace in the credit card number.
-  void CreateTestCreditCardWithWhitespace() {
-    ClearCreditCards();
-    std::unique_ptr<CreditCard> credit_card = std::make_unique<CreditCard>();
-    test::SetCreditCardInfo(credit_card.get(), "Elvis Presley",
-                            "4234 5678 9012 3456",  // Visa
-                            "04", "2999", "1");
-    credit_card->set_guid("00000000-0000-0000-0000-000000000008");
-    local_credit_cards_.push_back(std::move(credit_card));
-  }
-
-  // Create Elvis card with separator characters in the credit card number.
-  void CreateTestCreditCardWithSeparators() {
-    ClearCreditCards();
-    std::unique_ptr<CreditCard> credit_card = std::make_unique<CreditCard>();
-    test::SetCreditCardInfo(credit_card.get(), "Elvis Presley",
-                            "4234-5678-9012-3456",  // Visa
-                            "04", "2999", "1");
-    credit_card->set_guid("00000000-0000-0000-0000-000000000009");
-    local_credit_cards_.push_back(std::move(credit_card));
-  }
-
-  void CreateTestCreditCardsYearAndMonth(const char* year, const char* month) {
-    ClearCreditCards();
-    std::unique_ptr<CreditCard> credit_card = std::make_unique<CreditCard>();
-    test::SetCreditCardInfo(credit_card.get(), "Miku Hatsune",
-                            "4234567890654321",  // Visa
-                            month, year, "1");
-    credit_card->set_guid("00000000-0000-0000-0000-000000000007");
-    local_credit_cards_.push_back(std::move(credit_card));
-  }
-
-  void CreateTestExpiredCreditCard() {
-    ClearCreditCards();
-    std::unique_ptr<CreditCard> credit_card = std::make_unique<CreditCard>();
-    test::SetCreditCardInfo(credit_card.get(), "Homer Simpson",
-                            "4234567890654321",  // Visa
-                            "05", "2000", "1");
-    credit_card->set_guid("00000000-0000-0000-0000-000000000009");
-    local_credit_cards_.push_back(std::move(credit_card));
-  }
-
- private:
-  void CreateTestAutofillProfiles(
-      std::vector<std::unique_ptr<AutofillProfile>>* profiles) {
-    std::unique_ptr<AutofillProfile> profile =
-        std::make_unique<AutofillProfile>();
-    test::SetProfileInfo(profile.get(), "Elvis", "Aaron", "Presley",
-                         "theking@gmail.com", "RCA", "3734 Elvis Presley Blvd.",
-                         "Apt. 10", "Memphis", "Tennessee", "38116", "US",
-                         "12345678901");
-    profile->set_guid("00000000-0000-0000-0000-000000000001");
-    profiles->push_back(std::move(profile));
-    profile = std::make_unique<AutofillProfile>();
-    test::SetProfileInfo(profile.get(), "Charles", "Hardin", "Holley",
-                         "buddy@gmail.com", "Decca", "123 Apple St.", "unit 6",
-                         "Lubbock", "Texas", "79401", "US", "23456789012");
-    profile->set_guid("00000000-0000-0000-0000-000000000002");
-    profiles->push_back(std::move(profile));
-    profile = std::make_unique<AutofillProfile>();
-    test::SetProfileInfo(profile.get(), "", "", "", "", "", "", "", "", "", "",
-                         "", "");
-    profile->set_guid("00000000-0000-0000-0000-000000000003");
-    profiles->push_back(std::move(profile));
-  }
-
-  void CreateTestCreditCards(
-      std::vector<std::unique_ptr<CreditCard>>* credit_cards) {
-    std::unique_ptr<CreditCard> credit_card = std::make_unique<CreditCard>();
-    test::SetCreditCardInfo(credit_card.get(), "Elvis Presley",
-                            "4234567890123456",  // Visa
-                            "04", "2999", "1");
-    credit_card->set_guid("00000000-0000-0000-0000-000000000004");
-    credit_card->set_use_count(10);
-    credit_card->set_use_date(AutofillClock::Now() -
-                              base::TimeDelta::FromDays(5));
-    credit_cards->push_back(std::move(credit_card));
-
-    credit_card = std::make_unique<CreditCard>();
-    test::SetCreditCardInfo(credit_card.get(), "Buddy Holly",
-                            "5187654321098765",  // Mastercard
-                            "10", "2998", "1");
-    credit_card->set_guid("00000000-0000-0000-0000-000000000005");
-    credit_card->set_use_count(5);
-    credit_card->set_use_date(AutofillClock::Now() -
-                              base::TimeDelta::FromDays(4));
-    credit_cards->push_back(std::move(credit_card));
-
-    credit_card = std::make_unique<CreditCard>();
-    test::SetCreditCardInfo(credit_card.get(), "", "", "", "", "");
-    credit_card->set_guid("00000000-0000-0000-0000-000000000006");
-    credit_cards->push_back(std::move(credit_card));
-  }
-
-  size_t num_times_save_imported_profile_called_;
-
-  DISALLOW_COPY_AND_ASSIGN(TestPersonalDataManager);
-};
-
 class TestAutofillDownloadManager : public AutofillDownloadManager {
  public:
   TestAutofillDownloadManager(AutofillDriver* driver,
@@ -620,30 +422,6 @@
     return submitted_form_signature_;
   }
 
-  AutofillProfile* GetProfileWithGUID(const char* guid) {
-    return personal_data_->GetProfileWithGUID(guid);
-  }
-
-  CreditCard* GetCreditCardWithGUID(const char* guid) {
-    return personal_data_->GetCreditCardWithGUID(guid);
-  }
-
-  std::vector<CreditCard*> GetLocalCreditCards() const {
-    return personal_data_->GetLocalCreditCards();
-  }
-
-  std::vector<CreditCard*> GetCreditCards() const {
-    return personal_data_->GetCreditCards();
-  }
-
-  void AddProfile(std::unique_ptr<AutofillProfile> profile) {
-    personal_data_->AddProfile(*profile);
-  }
-
-  void AddCreditCard(const CreditCard& credit_card) {
-    personal_data_->AddCreditCard(credit_card);
-  }
-
   int GetPackedCreditCardID(int credit_card_id) {
     std::string credit_card_guid =
         base::StringPrintf("00000000-0000-0000-0000-%012d", credit_card_id);
@@ -807,6 +585,10 @@
     autofill_manager_->SetExternalDelegate(external_delegate_.get());
 
     variation_params_.ClearAllVariationParams();
+
+    // Initialize the TestPersonalDataManager with some default data.
+    CreateTestAutofillProfiles();
+    CreateTestCreditCards();
   }
 
   void TearDown() override {
@@ -993,6 +775,56 @@
     NOTREACHED();
     return 0;
   }
+
+  void CreateTestAutofillProfiles() {
+    AutofillProfile profile1;
+    test::SetProfileInfo(&profile1, "Elvis", "Aaron", "Presley",
+                         "theking@gmail.com", "RCA", "3734 Elvis Presley Blvd.",
+                         "Apt. 10", "Memphis", "Tennessee", "38116", "US",
+                         "12345678901");
+    profile1.set_guid("00000000-0000-0000-0000-000000000001");
+    personal_data_.AddProfile(profile1);
+
+    AutofillProfile profile2;
+    test::SetProfileInfo(&profile2, "Charles", "Hardin", "Holley",
+                         "buddy@gmail.com", "Decca", "123 Apple St.", "unit 6",
+                         "Lubbock", "Texas", "79401", "US", "23456789012");
+    profile2.set_guid("00000000-0000-0000-0000-000000000002");
+    personal_data_.AddProfile(profile2);
+
+    AutofillProfile profile3;
+    test::SetProfileInfo(&profile3, "", "", "", "", "", "", "", "", "", "", "",
+                         "");
+    profile3.set_guid("00000000-0000-0000-0000-000000000003");
+    personal_data_.AddProfile(profile3);
+  }
+
+  void CreateTestCreditCards() {
+    CreditCard credit_card1;
+    test::SetCreditCardInfo(&credit_card1, "Elvis Presley",
+                            "4234567890123456",  // Visa
+                            "04", "2999", "1");
+    credit_card1.set_guid("00000000-0000-0000-0000-000000000004");
+    credit_card1.set_use_count(10);
+    credit_card1.set_use_date(AutofillClock::Now() -
+                              base::TimeDelta::FromDays(5));
+    personal_data_.AddCreditCard(credit_card1);
+
+    CreditCard credit_card2;
+    test::SetCreditCardInfo(&credit_card2, "Buddy Holly",
+                            "5187654321098765",  // Mastercard
+                            "10", "2998", "1");
+    credit_card2.set_guid("00000000-0000-0000-0000-000000000005");
+    credit_card2.set_use_count(5);
+    credit_card2.set_use_date(AutofillClock::Now() -
+                              base::TimeDelta::FromDays(4));
+    personal_data_.AddCreditCard(credit_card2);
+
+    CreditCard credit_card3;
+    test::SetCreditCardInfo(&credit_card3, "", "", "", "", "");
+    credit_card3.set_guid("00000000-0000-0000-0000-000000000006");
+    personal_data_.AddCreditCard(credit_card3);
+  }
 };
 
 class TestFormStructure : public FormStructure {
@@ -1385,32 +1217,29 @@
 
   // Two profiles have the same last name, and the third shares the same first
   // letter for last name.
-  std::unique_ptr<AutofillProfile> profile1 =
-      std::make_unique<AutofillProfile>();
-  profile1->set_guid("00000000-0000-0000-0000-000000000103");
-  profile1->SetInfo(NAME_FIRST, ASCIIToUTF16("Robin"), "en-US");
-  profile1->SetInfo(NAME_LAST, ASCIIToUTF16("Grimes"), "en-US");
-  profile1->SetInfo(ADDRESS_HOME_LINE1, ASCIIToUTF16("1234 Smith Blvd."),
-                    "en-US");
-  autofill_manager_->AddProfile(std::move(profile1));
+  AutofillProfile profile1;
+  profile1.set_guid("00000000-0000-0000-0000-000000000103");
+  profile1.SetInfo(NAME_FIRST, ASCIIToUTF16("Robin"), "en-US");
+  profile1.SetInfo(NAME_LAST, ASCIIToUTF16("Grimes"), "en-US");
+  profile1.SetInfo(ADDRESS_HOME_LINE1, ASCIIToUTF16("1234 Smith Blvd."),
+                   "en-US");
+  personal_data_.AddProfile(profile1);
 
-  std::unique_ptr<AutofillProfile> profile2 =
-      std::make_unique<AutofillProfile>();
-  profile2->set_guid("00000000-0000-0000-0000-000000000124");
-  profile2->SetInfo(NAME_FIRST, ASCIIToUTF16("Carl"), "en-US");
-  profile2->SetInfo(NAME_LAST, ASCIIToUTF16("Grimes"), "en-US");
-  profile2->SetInfo(ADDRESS_HOME_LINE1, ASCIIToUTF16("1234 Smith Blvd."),
-                    "en-US");
-  autofill_manager_->AddProfile(std::move(profile2));
+  AutofillProfile profile2;
+  profile2.set_guid("00000000-0000-0000-0000-000000000124");
+  profile2.SetInfo(NAME_FIRST, ASCIIToUTF16("Carl"), "en-US");
+  profile2.SetInfo(NAME_LAST, ASCIIToUTF16("Grimes"), "en-US");
+  profile2.SetInfo(ADDRESS_HOME_LINE1, ASCIIToUTF16("1234 Smith Blvd."),
+                   "en-US");
+  personal_data_.AddProfile(profile2);
 
-  std::unique_ptr<AutofillProfile> profile3 =
-      std::make_unique<AutofillProfile>();
-  profile3->set_guid("00000000-0000-0000-0000-000000000126");
-  profile3->SetInfo(NAME_FIRST, ASCIIToUTF16("Aaron"), "en-US");
-  profile3->SetInfo(NAME_LAST, ASCIIToUTF16("Googler"), "en-US");
-  profile3->SetInfo(ADDRESS_HOME_LINE1, ASCIIToUTF16("1600 Amphitheater pkwy"),
-                    "en-US");
-  autofill_manager_->AddProfile(std::move(profile3));
+  AutofillProfile profile3;
+  profile3.set_guid("00000000-0000-0000-0000-000000000126");
+  profile3.SetInfo(NAME_FIRST, ASCIIToUTF16("Aaron"), "en-US");
+  profile3.SetInfo(NAME_LAST, ASCIIToUTF16("Googler"), "en-US");
+  profile3.SetInfo(ADDRESS_HOME_LINE1, ASCIIToUTF16("1600 Amphitheater pkwy"),
+                   "en-US");
+  personal_data_.AddProfile(profile3);
 
   FormFieldData field;
   test::CreateTestFormField("Last Name", "lastname", "G", "text", &field);
@@ -1479,10 +1308,9 @@
   FormsSeen(forms);
 
   // Add a duplicate profile.
-  std::unique_ptr<AutofillProfile> duplicate_profile =
-      std::make_unique<AutofillProfile>(*(autofill_manager_->GetProfileWithGUID(
-          "00000000-0000-0000-0000-000000000001")));
-  autofill_manager_->AddProfile(std::move(duplicate_profile));
+  AutofillProfile duplicate_profile = *(personal_data_.GetProfileWithGUID(
+      "00000000-0000-0000-0000-000000000001"));
+  personal_data_.AddProfile(duplicate_profile);
 
   const FormFieldData& field = form.fields[0];
   GetAutofillSuggestions(form, field);
@@ -1609,7 +1437,7 @@
                           "5255667890123123",  // Mastercard
                           "08", "2017", "1");
   credit_card.set_guid("00000000-0000-0000-0000-000000000007");
-  autofill_manager_->AddCreditCard(credit_card);
+  personal_data_.AddCreditCard(credit_card);
 
   // Set up our form data.
   FormData form;
@@ -1895,7 +1723,7 @@
   credit_card.set_guid("00000000-0000-0000-0000-000000000007");
   credit_card.set_use_date(AutofillClock::Now() -
                            base::TimeDelta::FromDays(15));
-  autofill_manager_->AddCreditCard(credit_card);
+  personal_data_.AddCreditCard(credit_card);
 
   // Set up our form data.
   FormData form;
@@ -2099,12 +1927,11 @@
   FormsSeen(forms);
 
   // |profile| will be owned by the mock PersonalDataManager.
-  std::unique_ptr<AutofillProfile> profile =
-      std::make_unique<AutofillProfile>();
-  test::SetProfileInfo(profile.get(), "Elvis", "", "", "", "", "", "", "", "",
-                       "", "", "");
-  profile->set_guid("00000000-0000-0000-0000-000000000101");
-  autofill_manager_->AddProfile(std::move(profile));
+  AutofillProfile profile;
+  test::SetProfileInfo(&profile, "Elvis", "", "", "", "", "", "", "", "", "",
+                       "", "");
+  profile.set_guid("00000000-0000-0000-0000-000000000101");
+  personal_data_.AddProfile(profile);
 
   FormFieldData& field = form.fields[0];
   field.is_autofilled = true;
@@ -2123,12 +1950,11 @@
   std::vector<FormData> forms(1, form);
   FormsSeen(forms);
 
-  std::unique_ptr<AutofillProfile> profile =
-      std::make_unique<AutofillProfile>();
-  profile->set_guid("00000000-0000-0000-0000-000000000103");
-  profile->SetInfo(NAME_FULL, ASCIIToUTF16("Natty Bumppo"), "en-US");
-  profile->SetRawInfo(PHONE_HOME_WHOLE_NUMBER, ASCIIToUTF16("1800PRAIRIE"));
-  autofill_manager_->AddProfile(std::move(profile));
+  AutofillProfile profile;
+  profile.set_guid("00000000-0000-0000-0000-000000000103");
+  profile.SetInfo(NAME_FULL, ASCIIToUTF16("Natty Bumppo"), "en-US");
+  profile.SetRawInfo(PHONE_HOME_WHOLE_NUMBER, ASCIIToUTF16("1800PRAIRIE"));
+  personal_data_.AddProfile(profile);
 
   const FormFieldData& field = form.fields[9];
   GetAutofillSuggestions(form, field);
@@ -2172,12 +1998,11 @@
   std::vector<FormData> forms(1, form);
   FormsSeen(forms);
 
-  std::unique_ptr<AutofillProfile> profile =
-      std::make_unique<AutofillProfile>();
-  profile->set_guid("00000000-0000-0000-0000-000000000104");
-  profile->SetRawInfo(PHONE_HOME_WHOLE_NUMBER, ASCIIToUTF16("1800FLOWERS"));
-  personal_data_.ClearAutofillProfiles();
-  autofill_manager_->AddProfile(std::move(profile));
+  personal_data_.ClearProfiles();
+  AutofillProfile profile;
+  profile.set_guid("00000000-0000-0000-0000-000000000104");
+  profile.SetRawInfo(PHONE_HOME_WHOLE_NUMBER, ASCIIToUTF16("1800FLOWERS"));
+  personal_data_.AddProfile(profile);
 
   const FormFieldData& phone_prefix = form.fields[2];
   GetAutofillSuggestions(form, phone_prefix);
@@ -2203,7 +2028,7 @@
   FormsSeen(forms);
 
   const char guid[] = "00000000-0000-0000-0000-000000000001";
-  AutofillProfile* profile = autofill_manager_->GetProfileWithGUID(guid);
+  AutofillProfile* profile = personal_data_.GetProfileWithGUID(guid);
   ASSERT_TRUE(profile);
   EXPECT_EQ(1U, profile->use_count());
   EXPECT_NE(base::Time(), profile->use_date());
@@ -2302,8 +2127,14 @@
 // Test that whitespace is stripped from the credit card number.
 TEST_F(AutofillManagerTest, FillCreditCardForm_StripCardNumberWhitespace) {
   // Same as the SetUp(), but generate Elvis card with whitespace in credit
-  // card number.
-  personal_data_.CreateTestCreditCardWithWhitespace();
+  // card number.  |credit_card| will be owned by the TestPersonalDataManager.
+  personal_data_.ClearCreditCards();
+  CreditCard credit_card;
+  test::SetCreditCardInfo(&credit_card, "Elvis Presley",
+                          "4234 5678 9012 3456",  // Visa
+                          "04", "2999", "1");
+  credit_card.set_guid("00000000-0000-0000-0000-000000000008");
+  personal_data_.AddCreditCard(credit_card);
   // Set up our form data.
   FormData form;
   CreateTestCreditCardFormData(&form, true, false);
@@ -2323,8 +2154,15 @@
 // Test that separator characters are stripped from the credit card number.
 TEST_F(AutofillManagerTest, FillCreditCardForm_StripCardNumberSeparators) {
   // Same as the SetUp(), but generate Elvis card with separator characters in
-  // credit card number.
-  personal_data_.CreateTestCreditCardWithSeparators();
+  // credit card number.  |credit_card| will be owned by the
+  // TestPersonalDataManager.
+  personal_data_.ClearCreditCards();
+  CreditCard credit_card;
+  test::SetCreditCardInfo(&credit_card, "Elvis Presley",
+                          "4234-5678-9012-3456",  // Visa
+                          "04", "2999", "1");
+  credit_card.set_guid("00000000-0000-0000-0000-000000000009");
+  personal_data_.AddCreditCard(credit_card);
   // Set up our form data.
   FormData form;
   CreateTestCreditCardFormData(&form, true, false);
@@ -2342,11 +2180,15 @@
 }
 
 // Test that we correctly fill a credit card form with month input type.
-// 1. year empty, month empty
+// Test 1 of 4: Empty month, empty year
 TEST_F(AutofillManagerTest, FillCreditCardForm_NoYearNoMonth) {
-  // Same as the SetUp(), but generate 4 credit cards with year month
-  // combination.
-  personal_data_.CreateTestCreditCardsYearAndMonth("", "");
+  personal_data_.ClearCreditCards();
+  CreditCard credit_card;
+  test::SetCreditCardInfo(&credit_card, "Miku Hatsune",
+                          "4234567890654321",  // Visa
+                          "", "", "1");
+  credit_card.set_guid("00000000-0000-0000-0000-000000000007");
+  personal_data_.AddCreditCard(credit_card);
   // Set up our form data.
   FormData form;
   CreateTestCreditCardFormData(&form, true, true);
@@ -2364,11 +2206,15 @@
 }
 
 // Test that we correctly fill a credit card form with month input type.
-// 2. year empty, month non-empty
+// Test 2 of 4: Non-empty month, empty year
 TEST_F(AutofillManagerTest, FillCreditCardForm_NoYearMonth) {
-  // Same as the SetUp(), but generate 4 credit cards with year month
-  // combination.
-  personal_data_.CreateTestCreditCardsYearAndMonth("", "04");
+  personal_data_.ClearCreditCards();
+  CreditCard credit_card;
+  test::SetCreditCardInfo(&credit_card, "Miku Hatsune",
+                          "4234567890654321",  // Visa
+                          "04", "", "1");
+  credit_card.set_guid("00000000-0000-0000-0000-000000000007");
+  personal_data_.AddCreditCard(credit_card);
   // Set up our form data.
   FormData form;
   CreateTestCreditCardFormData(&form, true, true);
@@ -2386,11 +2232,17 @@
 }
 
 // Test that we correctly fill a credit card form with month input type.
-// 3. year non-empty, month empty
+// Test 3 of 4: Empty month, non-empty year
 TEST_F(AutofillManagerTest, FillCreditCardForm_YearNoMonth) {
   // Same as the SetUp(), but generate 4 credit cards with year month
   // combination.
-  personal_data_.CreateTestCreditCardsYearAndMonth("2999", "");
+  personal_data_.ClearCreditCards();
+  CreditCard credit_card;
+  test::SetCreditCardInfo(&credit_card, "Miku Hatsune",
+                          "4234567890654321",  // Visa
+                          "", "2999", "1");
+  credit_card.set_guid("00000000-0000-0000-0000-000000000007");
+  personal_data_.AddCreditCard(credit_card);
   // Set up our form data.
   FormData form;
   CreateTestCreditCardFormData(&form, true, true);
@@ -2408,11 +2260,15 @@
 }
 
 // Test that we correctly fill a credit card form with month input type.
-// 4. year non-empty, month empty
+// Test 4 of 4: Non-empty month, non-empty year
 TEST_F(AutofillManagerTest, FillCreditCardForm_YearMonth) {
-  // Same as the SetUp(), but generate 4 credit cards with year month
-  // combination.
-  personal_data_.CreateTestCreditCardsYearAndMonth("2999", "04");
+  personal_data_.ClearCreditCards();
+  CreditCard credit_card;
+  test::SetCreditCardInfo(&credit_card, "Miku Hatsune",
+                          "4234567890654321",  // Visa
+                          "04", "2999", "1");
+  credit_card.set_guid("00000000-0000-0000-0000-000000000007");
+  personal_data_.AddCreditCard(credit_card);
   // Set up our form data.
   FormData form;
   CreateTestCreditCardFormData(&form, true, true);
@@ -2757,7 +2613,13 @@
 // Test that selecting an expired credit card fills everything except the
 // expiration date.
 TEST_F(AutofillManagerTest, FillCreditCardForm_ExpiredCard) {
-  personal_data_.CreateTestExpiredCreditCard();
+  personal_data_.ClearCreditCards();
+  CreditCard expired_card;
+  test::SetCreditCardInfo(&expired_card, "Homer Simpson",
+                          "4234567890654321",  // Visa
+                          "05", "2000", "1");
+  expired_card.set_guid("00000000-0000-0000-0000-000000000009");
+  personal_data_.AddCreditCard(expired_card);
 
   // Set up the form data.
   FormData form;
@@ -3221,8 +3083,8 @@
   FormsSeen(forms);
 
   // We should be able to fill prefix and suffix fields for US numbers.
-  AutofillProfile* work_profile = autofill_manager_->GetProfileWithGUID(
-      "00000000-0000-0000-0000-000000000002");
+  AutofillProfile* work_profile =
+      personal_data_.GetProfileWithGUID("00000000-0000-0000-0000-000000000002");
   ASSERT_TRUE(work_profile != nullptr);
   work_profile->SetRawInfo(PHONE_HOME_WHOLE_NUMBER,
                            ASCIIToUTF16("16505554567"));
@@ -3301,8 +3163,8 @@
 }
 
 TEST_F(AutofillManagerTest, FillFirstPhoneNumber_ComponentizedNumbers) {
-  AutofillProfile* work_profile = autofill_manager_->GetProfileWithGUID(
-      "00000000-0000-0000-0000-000000000002");
+  AutofillProfile* work_profile =
+      personal_data_.GetProfileWithGUID("00000000-0000-0000-0000-000000000002");
   ASSERT_TRUE(work_profile != nullptr);
   work_profile->SetRawInfo(PHONE_HOME_WHOLE_NUMBER,
                            ASCIIToUTF16("16505554567"));
@@ -3400,8 +3262,8 @@
 }
 
 TEST_F(AutofillManagerTest, FillFirstPhoneNumber_WholeNumbers) {
-  AutofillProfile* work_profile = autofill_manager_->GetProfileWithGUID(
-      "00000000-0000-0000-0000-000000000002");
+  AutofillProfile* work_profile =
+      personal_data_.GetProfileWithGUID("00000000-0000-0000-0000-000000000002");
   ASSERT_TRUE(work_profile != nullptr);
   work_profile->SetRawInfo(PHONE_HOME_WHOLE_NUMBER,
                            ASCIIToUTF16("16505554567"));
@@ -3479,8 +3341,8 @@
 }
 
 TEST_F(AutofillManagerTest, FillFirstPhoneNumber_FillPartsOnceOnly) {
-  AutofillProfile* work_profile = autofill_manager_->GetProfileWithGUID(
-      "00000000-0000-0000-0000-000000000002");
+  AutofillProfile* work_profile =
+      personal_data_.GetProfileWithGUID("00000000-0000-0000-0000-000000000002");
   ASSERT_TRUE(work_profile != nullptr);
   work_profile->SetRawInfo(PHONE_HOME_WHOLE_NUMBER,
                            ASCIIToUTF16("16505554567"));
@@ -3584,8 +3446,8 @@
 // phone field, we do not fill anything to extension field.
 TEST_F(AutofillManagerTest,
        FillFirstPhoneNumber_NotFillMisclassifiedExtention) {
-  AutofillProfile* work_profile = autofill_manager_->GetProfileWithGUID(
-      "00000000-0000-0000-0000-000000000002");
+  AutofillProfile* work_profile =
+      personal_data_.GetProfileWithGUID("00000000-0000-0000-0000-000000000002");
   ASSERT_TRUE(work_profile != nullptr);
   work_profile->SetRawInfo(PHONE_HOME_WHOLE_NUMBER,
                            ASCIIToUTF16("16505554567"));
@@ -3674,8 +3536,8 @@
 
 // Verify when no complete number can be found, we do best-effort filling.
 TEST_F(AutofillManagerTest, FillFirstPhoneNumber_BestEfforFilling) {
-  AutofillProfile* work_profile = autofill_manager_->GetProfileWithGUID(
-      "00000000-0000-0000-0000-000000000002");
+  AutofillProfile* work_profile =
+      personal_data_.GetProfileWithGUID("00000000-0000-0000-0000-000000000002");
   ASSERT_TRUE(work_profile != nullptr);
   work_profile->SetRawInfo(PHONE_HOME_WHOLE_NUMBER,
                            ASCIIToUTF16("16505554567"));
@@ -3759,8 +3621,8 @@
 // When the focus is on second phone field explicitly, we will fill the
 // entire form, both first phone field and second phone field included.
 TEST_F(AutofillManagerTest, FillFirstPhoneNumber_FocusOnSecondPhoneNumber) {
-  AutofillProfile* work_profile = autofill_manager_->GetProfileWithGUID(
-      "00000000-0000-0000-0000-000000000002");
+  AutofillProfile* work_profile =
+      personal_data_.GetProfileWithGUID("00000000-0000-0000-0000-000000000002");
   ASSERT_TRUE(work_profile != nullptr);
   work_profile->SetRawInfo(PHONE_HOME_WHOLE_NUMBER,
                            ASCIIToUTF16("16505554567"));
@@ -3844,8 +3706,8 @@
 }
 
 TEST_F(AutofillManagerTest, FillFirstPhoneNumber_HiddenFieldShouldNotCount) {
-  AutofillProfile* work_profile = autofill_manager_->GetProfileWithGUID(
-      "00000000-0000-0000-0000-000000000002");
+  AutofillProfile* work_profile =
+      personal_data_.GetProfileWithGUID("00000000-0000-0000-0000-000000000002");
   ASSERT_TRUE(work_profile != nullptr);
   work_profile->SetRawInfo(PHONE_HOME_WHOLE_NUMBER,
                            ASCIIToUTF16("16505554567"));
@@ -3926,8 +3788,8 @@
 
 TEST_F(AutofillManagerTest,
        FillFirstPhoneNumber_MultipleSectionFilledCorrectly) {
-  AutofillProfile* work_profile = autofill_manager_->GetProfileWithGUID(
-      "00000000-0000-0000-0000-000000000002");
+  AutofillProfile* work_profile =
+      personal_data_.GetProfileWithGUID("00000000-0000-0000-0000-000000000002");
   ASSERT_TRUE(work_profile != nullptr);
   work_profile->SetRawInfo(PHONE_HOME_WHOLE_NUMBER,
                            ASCIIToUTF16("16505554567"));
@@ -4557,12 +4419,17 @@
   ExpectFilledAddressFormElvis(response_page_id, response_data, kDefaultPageID,
                                false);
 
-  personal_data_.ClearAutofillProfiles();
+  personal_data_.ClearProfiles();
   // The default credit card is a Elvis card. It must be removed because name
   // fields would be detected. However at least one profile or card is needed to
   // start the upload process, which is why this other card is created.
   personal_data_.ClearCreditCards();
-  personal_data_.CreateTestCreditCardsYearAndMonth("2999", "04");
+  CreditCard credit_card;
+  test::SetCreditCardInfo(&credit_card, "Miku Hatsune",
+                          "4234567890654321",  // Visa
+                          "04", "2999", "1");
+  credit_card.set_guid("00000000-0000-0000-0000-000000000007");
+  personal_data_.AddCreditCard(credit_card);
   ASSERT_EQ(0u, personal_data_.GetProfiles().size());
 
   // Simulate form submission. The first submission should not count the data
@@ -5022,17 +4889,16 @@
 
 TEST_F(AutofillManagerTest, RemoveProfile) {
   // Add and remove an Autofill profile.
-  std::unique_ptr<AutofillProfile> profile =
-      std::make_unique<AutofillProfile>();
+  AutofillProfile profile;
   const char guid[] = "00000000-0000-0000-0000-000000000102";
-  profile->set_guid(guid);
-  autofill_manager_->AddProfile(std::move(profile));
+  profile.set_guid(guid);
+  personal_data_.AddProfile(profile);
 
   int id = MakeFrontendID(std::string(), guid);
 
   autofill_manager_->RemoveAutofillProfileOrCreditCard(id);
 
-  EXPECT_FALSE(autofill_manager_->GetProfileWithGUID(guid));
+  EXPECT_FALSE(personal_data_.GetProfileWithGUID(guid));
 }
 
 TEST_F(AutofillManagerTest, RemoveCreditCard) {
@@ -5040,13 +4906,13 @@
   CreditCard credit_card;
   const char guid[] = "00000000-0000-0000-0000-000000100007";
   credit_card.set_guid(guid);
-  autofill_manager_->AddCreditCard(credit_card);
+  personal_data_.AddCreditCard(credit_card);
 
   int id = MakeFrontendID(guid, std::string());
 
   autofill_manager_->RemoveAutofillProfileOrCreditCard(id);
 
-  EXPECT_FALSE(autofill_manager_->GetCreditCardWithGUID(guid));
+  EXPECT_FALSE(personal_data_.GetCreditCardWithGUID(guid));
 }
 
 // Test our external delegate is called at the right time.
@@ -5710,25 +5576,23 @@
   std::vector<FormData> forms(1, form);
   FormsSeen(forms);
 
-  std::unique_ptr<AutofillProfile> profile1 =
-      std::make_unique<AutofillProfile>();
-  profile1->set_guid("00000000-0000-0000-0000-000000000103");
-  profile1->SetInfo(NAME_FIRST, ASCIIToUTF16("Robin"), "en-US");
-  profile1->SetInfo(NAME_MIDDLE, ASCIIToUTF16("Adam Smith"), "en-US");
-  profile1->SetInfo(NAME_LAST, ASCIIToUTF16("Grimes"), "en-US");
-  profile1->SetInfo(ADDRESS_HOME_LINE1, ASCIIToUTF16("1234 Smith Blvd."),
-                    "en-US");
-  autofill_manager_->AddProfile(std::move(profile1));
+  AutofillProfile profile1;
+  profile1.set_guid("00000000-0000-0000-0000-000000000103");
+  profile1.SetInfo(NAME_FIRST, ASCIIToUTF16("Robin"), "en-US");
+  profile1.SetInfo(NAME_MIDDLE, ASCIIToUTF16("Adam Smith"), "en-US");
+  profile1.SetInfo(NAME_LAST, ASCIIToUTF16("Grimes"), "en-US");
+  profile1.SetInfo(ADDRESS_HOME_LINE1, ASCIIToUTF16("1234 Smith Blvd."),
+                   "en-US");
+  personal_data_.AddProfile(profile1);
 
-  std::unique_ptr<AutofillProfile> profile2 =
-      std::make_unique<AutofillProfile>();
-  profile2->set_guid("00000000-0000-0000-0000-000000000124");
-  profile2->SetInfo(NAME_FIRST, ASCIIToUTF16("Carl"), "en-US");
-  profile2->SetInfo(NAME_MIDDLE, ASCIIToUTF16("Shawn Smith"), "en-US");
-  profile2->SetInfo(NAME_LAST, ASCIIToUTF16("Grimes"), "en-US");
-  profile2->SetInfo(ADDRESS_HOME_LINE1, ASCIIToUTF16("1234 Smith Blvd."),
-                    "en-US");
-  autofill_manager_->AddProfile(std::move(profile2));
+  AutofillProfile profile2;
+  profile2.set_guid("00000000-0000-0000-0000-000000000124");
+  profile2.SetInfo(NAME_FIRST, ASCIIToUTF16("Carl"), "en-US");
+  profile2.SetInfo(NAME_MIDDLE, ASCIIToUTF16("Shawn Smith"), "en-US");
+  profile2.SetInfo(NAME_LAST, ASCIIToUTF16("Grimes"), "en-US");
+  profile2.SetInfo(ADDRESS_HOME_LINE1, ASCIIToUTF16("1234 Smith Blvd."),
+                   "en-US");
+  personal_data_.AddProfile(profile2);
 
   FormFieldData field;
   test::CreateTestFormField("Middle Name", "middlename", "S", "text", &field);
@@ -6158,7 +6022,7 @@
   // Add a local card to allow data matching for upload votes.
   CreditCard credit_card =
       autofill::test::GetRandomCreditCard(CreditCard::LOCAL_CARD);
-  autofill_manager_->AddCreditCard(credit_card);
+  personal_data_.AddCreditCard(credit_card);
 
   // Set up the form.
   FormData form;
diff --git a/components/autofill/core/browser/autofill_metrics.cc b/components/autofill/core/browser/autofill_metrics.cc
index 5ffd70c..871a204 100644
--- a/components/autofill/core/browser/autofill_metrics.cc
+++ b/components/autofill/core/browser/autofill_metrics.cc
@@ -13,8 +13,8 @@
 #include "base/metrics/histogram_macros.h"
 #include "base/metrics/sparse_histogram.h"
 #include "base/metrics/user_metrics.h"
+#include "base/strings/strcat.h"
 #include "base/strings/string_piece.h"
-#include "base/strings/string_util.h"
 #include "base/time/time.h"
 #include "components/autofill/core/browser/autofill_experiments.h"
 #include "components/autofill/core/browser/autofill_field.h"
@@ -344,11 +344,11 @@
   const char* source = GetQualityMetricPredictionSource(prediction_source);
   const char* suffix = GetQualityMetricTypeSuffix(metric_type);
   std::string raw_data_histogram =
-      base::JoinString({"Autofill.FieldPrediction.", source, suffix}, "");
-  std::string aggregate_histogram = base::JoinString(
-      {"Autofill.FieldPredictionQuality.Aggregate.", source, suffix}, "");
-  std::string type_specific_histogram = base::JoinString(
-      {"Autofill.FieldPredictionQuality.ByFieldType.", source, suffix}, "");
+      base::StrCat({"Autofill.FieldPrediction.", source, suffix});
+  std::string aggregate_histogram = base::StrCat(
+      {"Autofill.FieldPredictionQuality.Aggregate.", source, suffix});
+  std::string type_specific_histogram = base::StrCat(
+      {"Autofill.FieldPredictionQuality.ByFieldType.", source, suffix});
 
   const ServerFieldTypeSet& possible_types =
       metric_type == AutofillMetrics::TYPE_AUTOCOMPLETE_BASED
diff --git a/components/autofill/core/browser/country_combobox_model_unittest.cc b/components/autofill/core/browser/country_combobox_model_unittest.cc
index ca3e9f0..59726dd 100644
--- a/components/autofill/core/browser/country_combobox_model_unittest.cc
+++ b/components/autofill/core/browser/country_combobox_model_unittest.cc
@@ -21,14 +21,14 @@
  public:
   CountryComboboxModelTest()
       : pref_service_(autofill::test::PrefServiceForTesting()) {
-    manager_.SetTestingPrefService(pref_service_.get());
+    manager_.SetPrefService(pref_service_.get());
     manager_.set_timezone_country_code("KR");
     model_.reset(new CountryComboboxModel());
     model_->SetCountries(manager_, base::Callback<bool(const std::string&)>(),
                          "en-US");
   }
 
-  void TearDown() override { manager_.SetTestingPrefService(nullptr); }
+  void TearDown() override { manager_.SetPrefService(nullptr); }
 
   TestPersonalDataManager* manager() { return &manager_; }
   CountryComboboxModel* model() { return model_.get(); }
diff --git a/components/autofill/core/browser/credit_card_save_manager_unittest.cc b/components/autofill/core/browser/credit_card_save_manager_unittest.cc
index 96bb3b5..17927a00 100644
--- a/components/autofill/core/browser/credit_card_save_manager_unittest.cc
+++ b/components/autofill/core/browser/credit_card_save_manager_unittest.cc
@@ -36,6 +36,7 @@
 #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_driver.h"
+#include "components/autofill/core/browser/test_personal_data_manager.h"
 #include "components/autofill/core/browser/validation.h"
 #include "components/autofill/core/browser/webdata/autofill_webdata_service.h"
 #include "components/autofill/core/common/autofill_clock.h"
@@ -134,205 +135,6 @@
   DISALLOW_COPY_AND_ASSIGN(TestPaymentsClient);
 };
 
-class TestPersonalDataManager : public PersonalDataManager {
- public:
-  TestPersonalDataManager()
-      : PersonalDataManager("en-US"),
-        num_times_save_imported_profile_called_(0) {
-    CreateTestAutofillProfiles(&web_profiles_);
-    CreateTestCreditCards(&local_credit_cards_);
-  }
-
-  using PersonalDataManager::set_database;
-  using PersonalDataManager::SetPrefService;
-
-  int num_times_save_imported_profile_called() {
-    return num_times_save_imported_profile_called_;
-  }
-
-  std::string SaveImportedProfile(const AutofillProfile& profile) override {
-    num_times_save_imported_profile_called_++;
-    AddProfile(profile);
-    return profile.guid();
-  }
-
-  AutofillProfile* GetProfileWithGUID(const char* guid) {
-    for (AutofillProfile* profile : GetProfiles()) {
-      if (!profile->guid().compare(guid))
-        return profile;
-    }
-    return nullptr;
-  }
-
-  CreditCard* GetCreditCardWithGUID(const char* guid) {
-    for (CreditCard* card : GetCreditCards()) {
-      if (!card->guid().compare(guid))
-        return card;
-    }
-    return nullptr;
-  }
-
-  void AddProfile(const AutofillProfile& profile) override {
-    std::unique_ptr<AutofillProfile> profile_ptr =
-        std::make_unique<AutofillProfile>(profile);
-    profile_ptr->set_modification_date(AutofillClock::Now());
-    web_profiles_.push_back(std::move(profile_ptr));
-  }
-
-  void AddCreditCard(const CreditCard& credit_card) override {
-    std::unique_ptr<CreditCard> local_credit_card =
-        std::make_unique<CreditCard>(credit_card);
-    local_credit_card->set_modification_date(AutofillClock::Now());
-    local_credit_cards_.push_back(std::move(local_credit_card));
-  }
-
-  void AddFullServerCreditCard(const CreditCard& credit_card) override {
-    AddServerCreditCard(credit_card);
-  }
-
-  void RecordUseOf(const AutofillDataModel& data_model) override {
-    CreditCard* credit_card = GetCreditCardWithGUID(data_model.guid().c_str());
-    if (credit_card)
-      credit_card->RecordAndLogUse();
-
-    AutofillProfile* profile = GetProfileWithGUID(data_model.guid().c_str());
-    if (profile)
-      profile->RecordAndLogUse();
-  }
-
-  void RemoveByGUID(const std::string& guid) override {
-    CreditCard* credit_card = GetCreditCardWithGUID(guid.c_str());
-    if (credit_card) {
-      local_credit_cards_.erase(
-          std::find_if(local_credit_cards_.begin(), local_credit_cards_.end(),
-                       [credit_card](const std::unique_ptr<CreditCard>& ptr) {
-                         return ptr.get() == credit_card;
-                       }));
-    }
-
-    AutofillProfile* profile = GetProfileWithGUID(guid.c_str());
-    if (profile) {
-      web_profiles_.erase(
-          std::find_if(web_profiles_.begin(), web_profiles_.end(),
-                       [profile](const std::unique_ptr<AutofillProfile>& ptr) {
-                         return ptr.get() == profile;
-                       }));
-    }
-  }
-
-  void ClearAutofillProfiles() { web_profiles_.clear(); }
-
-  void ClearCreditCards() {
-    local_credit_cards_.clear();
-    server_credit_cards_.clear();
-  }
-
-  void AddServerCreditCard(const CreditCard& credit_card) {
-    std::unique_ptr<CreditCard> server_credit_card =
-        std::make_unique<CreditCard>(credit_card);
-    server_credit_card->set_modification_date(AutofillClock::Now());
-    server_credit_cards_.push_back(std::move(server_credit_card));
-  }
-
-  // Create Elvis card with whitespace in the credit card number.
-  void CreateTestCreditCardWithWhitespace() {
-    ClearCreditCards();
-    std::unique_ptr<CreditCard> credit_card = std::make_unique<CreditCard>();
-    test::SetCreditCardInfo(credit_card.get(), "Elvis Presley",
-                            "4234 5678 9012 3456",  // Visa
-                            "04", "2999", "1");
-    credit_card->set_guid("00000000-0000-0000-0000-000000000008");
-    local_credit_cards_.push_back(std::move(credit_card));
-  }
-
-  // Create Elvis card with separator characters in the credit card number.
-  void CreateTestCreditCardWithSeparators() {
-    ClearCreditCards();
-    std::unique_ptr<CreditCard> credit_card = std::make_unique<CreditCard>();
-    test::SetCreditCardInfo(credit_card.get(), "Elvis Presley",
-                            "4234-5678-9012-3456",  // Visa
-                            "04", "2999", "1");
-    credit_card->set_guid("00000000-0000-0000-0000-000000000009");
-    local_credit_cards_.push_back(std::move(credit_card));
-  }
-
-  void CreateTestCreditCardsYearAndMonth(const char* year, const char* month) {
-    ClearCreditCards();
-    std::unique_ptr<CreditCard> credit_card = std::make_unique<CreditCard>();
-    test::SetCreditCardInfo(credit_card.get(), "Miku Hatsune",
-                            "4234567890654321",  // Visa
-                            month, year, "1");
-    credit_card->set_guid("00000000-0000-0000-0000-000000000007");
-    local_credit_cards_.push_back(std::move(credit_card));
-  }
-
-  void CreateTestExpiredCreditCard() {
-    ClearCreditCards();
-    std::unique_ptr<CreditCard> credit_card = std::make_unique<CreditCard>();
-    test::SetCreditCardInfo(credit_card.get(), "Homer Simpson",
-                            "4234567890654321",  // Visa
-                            "05", "2000", "1");
-    credit_card->set_guid("00000000-0000-0000-0000-000000000009");
-    local_credit_cards_.push_back(std::move(credit_card));
-  }
-
- private:
-  void CreateTestAutofillProfiles(
-      std::vector<std::unique_ptr<AutofillProfile>>* profiles) {
-    std::unique_ptr<AutofillProfile> profile =
-        std::make_unique<AutofillProfile>();
-    test::SetProfileInfo(profile.get(), "Elvis", "Aaron", "Presley",
-                         "theking@gmail.com", "RCA", "3734 Elvis Presley Blvd.",
-                         "Apt. 10", "Memphis", "Tennessee", "38116", "US",
-                         "12345678901");
-    profile->set_guid("00000000-0000-0000-0000-000000000001");
-    profiles->push_back(std::move(profile));
-    profile = std::make_unique<AutofillProfile>();
-    test::SetProfileInfo(profile.get(), "Charles", "Hardin", "Holley",
-                         "buddy@gmail.com", "Decca", "123 Apple St.", "unit 6",
-                         "Lubbock", "Texas", "79401", "US", "23456789012");
-    profile->set_guid("00000000-0000-0000-0000-000000000002");
-    profiles->push_back(std::move(profile));
-    profile = std::make_unique<AutofillProfile>();
-    test::SetProfileInfo(profile.get(), "", "", "", "", "", "", "", "", "", "",
-                         "", "");
-    profile->set_guid("00000000-0000-0000-0000-000000000003");
-    profiles->push_back(std::move(profile));
-  }
-
-  void CreateTestCreditCards(
-      std::vector<std::unique_ptr<CreditCard>>* credit_cards) {
-    std::unique_ptr<CreditCard> credit_card = std::make_unique<CreditCard>();
-    test::SetCreditCardInfo(credit_card.get(), "Elvis Presley",
-                            "4234567890123456",  // Visa
-                            "04", "2999", "1");
-    credit_card->set_guid("00000000-0000-0000-0000-000000000004");
-    credit_card->set_use_count(10);
-    credit_card->set_use_date(AutofillClock::Now() -
-                              base::TimeDelta::FromDays(5));
-    credit_cards->push_back(std::move(credit_card));
-
-    credit_card = std::make_unique<CreditCard>();
-    test::SetCreditCardInfo(credit_card.get(), "Buddy Holly",
-                            "5187654321098765",  // Mastercard
-                            "10", "2998", "1");
-    credit_card->set_guid("00000000-0000-0000-0000-000000000005");
-    credit_card->set_use_count(5);
-    credit_card->set_use_date(AutofillClock::Now() -
-                              base::TimeDelta::FromDays(4));
-    credit_cards->push_back(std::move(credit_card));
-
-    credit_card = std::make_unique<CreditCard>();
-    test::SetCreditCardInfo(credit_card.get(), "", "", "", "", "");
-    credit_card->set_guid("00000000-0000-0000-0000-000000000006");
-    credit_cards->push_back(std::move(credit_card));
-  }
-
-  size_t num_times_save_imported_profile_called_;
-
-  DISALLOW_COPY_AND_ASSIGN(TestPersonalDataManager);
-};
-
 class TestFormDataImporter : public FormDataImporter {
  public:
   TestFormDataImporter(AutofillClient* client,
@@ -865,7 +667,7 @@
 }
 
 TEST_F(CreditCardSaveManagerTest, CreditCardDisabledDoesNotSave) {
-  personal_data_.ClearAutofillProfiles();
+  personal_data_.ClearProfiles();
   autofill_manager_->set_credit_card_enabled(false);
 
   // Create, fill and submit an address form in order to establish a recent
@@ -901,7 +703,7 @@
 
 TEST_F(CreditCardSaveManagerTest, UploadCreditCard) {
   personal_data_.ClearCreditCards();
-  personal_data_.ClearAutofillProfiles();
+  personal_data_.ClearProfiles();
   credit_card_save_manager_->set_credit_card_upload_enabled(true);
 
   // Create, fill and submit an address form in order to establish a recent
@@ -955,7 +757,7 @@
   EnableAutofillUpstreamRequestCvcIfMissingExperiment();
 
   personal_data_.ClearCreditCards();
-  personal_data_.ClearAutofillProfiles();
+  personal_data_.ClearProfiles();
   credit_card_save_manager_->set_credit_card_upload_enabled(true);
 
   // Create, fill and submit an address form in order to establish a recent
@@ -988,7 +790,7 @@
 
 TEST_F(CreditCardSaveManagerTest, UploadCreditCardAndSaveCopy) {
   personal_data_.ClearCreditCards();
-  personal_data_.ClearAutofillProfiles();
+  personal_data_.ClearProfiles();
   credit_card_save_manager_->set_credit_card_upload_enabled(true);
 
   const char* const server_id = "InstrumentData:1234";
@@ -1038,7 +840,7 @@
 }
 
 TEST_F(CreditCardSaveManagerTest, UploadCreditCard_FeatureNotEnabled) {
-  personal_data_.ClearAutofillProfiles();
+  personal_data_.ClearProfiles();
   credit_card_save_manager_->set_credit_card_upload_enabled(false);
 
   // Create, fill and submit an address form in order to establish a recent
@@ -1073,7 +875,7 @@
 }
 
 TEST_F(CreditCardSaveManagerTest, UploadCreditCard_CvcUnavailable) {
-  personal_data_.ClearAutofillProfiles();
+  personal_data_.ClearProfiles();
   credit_card_save_manager_->set_credit_card_upload_enabled(true);
 
   // Create, fill and submit an address form in order to establish a recent
@@ -1114,7 +916,7 @@
 }
 
 TEST_F(CreditCardSaveManagerTest, UploadCreditCard_CvcInvalidLength) {
-  personal_data_.ClearAutofillProfiles();
+  personal_data_.ClearProfiles();
   credit_card_save_manager_->set_credit_card_upload_enabled(true);
 
   // Create, fill and submit an address form in order to establish a recent
@@ -1157,7 +959,7 @@
   // Remove the profiles that were created in the TestPersonalDataManager
   // constructor because they would result in conflicting names that would
   // prevent the upload.
-  personal_data_.ClearAutofillProfiles();
+  personal_data_.ClearProfiles();
 
   // Create, fill and submit an address form in order to establish a recent
   // profile which can be selected for the upload request.
@@ -1219,7 +1021,7 @@
   // Remove the profiles that were created in the TestPersonalDataManager
   // constructor because they would result in conflicting names that would
   // prevent the upload.
-  personal_data_.ClearAutofillProfiles();
+  personal_data_.ClearProfiles();
 
   // Create, fill and submit an address form in order to establish a recent
   // profile which can be selected for the upload request.
@@ -1276,7 +1078,7 @@
   // Remove the profiles that were created in the TestPersonalDataManager
   // constructor because they would result in conflicting names that would
   // prevent the upload.
-  personal_data_.ClearAutofillProfiles();
+  personal_data_.ClearProfiles();
 
   // Create, fill and submit an address form in order to establish a recent
   // profile which can be selected for the upload request.
@@ -1336,7 +1138,7 @@
   // Remove the profiles that were created in the TestPersonalDataManager
   // constructor because they would result in conflicting names that would
   // prevent the upload.
-  personal_data_.ClearAutofillProfiles();
+  personal_data_.ClearProfiles();
 
   // Create, fill and submit an address form in order to establish a recent
   // profile which can be selected for the upload request.
@@ -1398,7 +1200,7 @@
   // Remove the profiles that were created in the TestPersonalDataManager
   // constructor because they would result in conflicting names that would
   // prevent the upload.
-  personal_data_.ClearAutofillProfiles();
+  personal_data_.ClearProfiles();
 
   // Create, fill and submit an address form in order to establish a recent
   // profile which can be selected for the upload request.
@@ -1467,7 +1269,7 @@
   // Remove the profiles that were created in the TestPersonalDataManager
   // constructor because they would result in conflicting names that would
   // prevent the upload.
-  personal_data_.ClearAutofillProfiles();
+  personal_data_.ClearProfiles();
 
   // Create, fill and submit an address form in order to establish a recent
   // profile which can be selected for the upload request.
@@ -1531,7 +1333,7 @@
   // Remove the profiles that were created in the TestPersonalDataManager
   // constructor because they would result in conflicting names that would
   // prevent the upload.
-  personal_data_.ClearAutofillProfiles();
+  personal_data_.ClearProfiles();
 
   // Create, fill and submit an address form in order to establish a recent
   // profile which can be selected for the upload request.
@@ -1587,7 +1389,7 @@
 TEST_F(CreditCardSaveManagerTest,
        UploadCreditCard_AddNewUiFlagStateToRequestIfExperimentOn) {
   EnableAutofillUpstreamShowNewUiExperiment();
-  personal_data_.ClearAutofillProfiles();
+  personal_data_.ClearProfiles();
   credit_card_save_manager_->set_credit_card_upload_enabled(true);
 
   // Create, fill and submit an address form in order to establish a recent
@@ -1620,7 +1422,7 @@
 
 TEST_F(CreditCardSaveManagerTest,
        UploadCreditCard_DoNotAddNewUiFlagStateToRequestIfExperimentOff) {
-  personal_data_.ClearAutofillProfiles();
+  personal_data_.ClearProfiles();
   credit_card_save_manager_->set_credit_card_upload_enabled(true);
 
   // Create, fill and submit an address form in order to establish a recent
@@ -1653,7 +1455,7 @@
 TEST_F(CreditCardSaveManagerTest,
        UploadCreditCard_AddShowGoogleLogoFlagStateToRequestIfExperimentOn) {
   EnableAutofillUpstreamShowGoogleLogoExperiment();
-  personal_data_.ClearAutofillProfiles();
+  personal_data_.ClearProfiles();
   credit_card_save_manager_->set_credit_card_upload_enabled(true);
 
   // Create, fill and submit an address form in order to establish a recent
@@ -1687,7 +1489,7 @@
 
 TEST_F(CreditCardSaveManagerTest,
        UploadCreditCard_DoNotAddShowGoogleLogoFlagStateToRequestIfExpOff) {
-  personal_data_.ClearAutofillProfiles();
+  personal_data_.ClearProfiles();
   credit_card_save_manager_->set_credit_card_upload_enabled(true);
 
   // Create, fill and submit an address form in order to establish a recent
@@ -1720,7 +1522,7 @@
 #endif
 
 TEST_F(CreditCardSaveManagerTest, UploadCreditCard_NoProfileAvailable) {
-  personal_data_.ClearAutofillProfiles();
+  personal_data_.ClearProfiles();
   credit_card_save_manager_->set_credit_card_upload_enabled(true);
 
   // Don't fill or submit an address form.
@@ -1757,7 +1559,7 @@
   TestAutofillClock test_clock;
   test_clock.SetNow(kArbitraryTime);
 
-  personal_data_.ClearAutofillProfiles();
+  personal_data_.ClearProfiles();
   credit_card_save_manager_->set_credit_card_upload_enabled(true);
 
   // Create, fill and submit an address form in order to establish a profile.
@@ -1804,7 +1606,7 @@
 
 TEST_F(CreditCardSaveManagerTest,
        UploadCreditCard_CvcUnavailableAndNoProfileAvailable) {
-  personal_data_.ClearAutofillProfiles();
+  personal_data_.ClearProfiles();
   credit_card_save_manager_->set_credit_card_upload_enabled(true);
 
   // Don't fill or submit an address form.
@@ -1844,7 +1646,7 @@
 }
 
 TEST_F(CreditCardSaveManagerTest, UploadCreditCard_NoNameAvailable) {
-  personal_data_.ClearAutofillProfiles();
+  personal_data_.ClearProfiles();
   credit_card_save_manager_->set_credit_card_upload_enabled(true);
 
   // Create, fill and submit an address form in order to establish a recent
@@ -1882,7 +1684,7 @@
 }
 
 TEST_F(CreditCardSaveManagerTest, UploadCreditCard_ZipCodesConflict) {
-  personal_data_.ClearAutofillProfiles();
+  personal_data_.ClearProfiles();
   credit_card_save_manager_->set_credit_card_upload_enabled(true);
 
   // Create, fill and submit two address forms with different zip codes.
@@ -1931,7 +1733,7 @@
 }
 
 TEST_F(CreditCardSaveManagerTest, UploadCreditCard_ZipCodesDiscardWhitespace) {
-  personal_data_.ClearAutofillProfiles();
+  personal_data_.ClearProfiles();
   credit_card_save_manager_->set_credit_card_upload_enabled(true);
 
   // Create, fill and submit two address forms with different zip codes.
@@ -1975,7 +1777,7 @@
 TEST_F(CreditCardSaveManagerTest,
        UploadCreditCard_ZipCodesDiscardWhitespace_ComparatorEnabled) {
   EnableAutofillUpstreamUseAutofillProfileComparator();
-  personal_data_.ClearAutofillProfiles();
+  personal_data_.ClearProfiles();
   credit_card_save_manager_->set_credit_card_upload_enabled(true);
 
   // Create, fill and submit two address forms with different zip codes.
@@ -2019,7 +1821,7 @@
 }
 
 TEST_F(CreditCardSaveManagerTest, UploadCreditCard_ZipCodesHavePrefixMatch) {
-  personal_data_.ClearAutofillProfiles();
+  personal_data_.ClearProfiles();
   credit_card_save_manager_->set_credit_card_upload_enabled(true);
 
   // Create, fill and submit two address forms with different zip codes.
@@ -2065,7 +1867,7 @@
 }
 
 TEST_F(CreditCardSaveManagerTest, UploadCreditCard_NoZipCodeAvailable) {
-  personal_data_.ClearAutofillProfiles();
+  personal_data_.ClearProfiles();
   credit_card_save_manager_->set_credit_card_upload_enabled(true);
 
   // Create, fill and submit an address form in order to establish a recent
@@ -2110,7 +1912,7 @@
 }
 
 TEST_F(CreditCardSaveManagerTest, UploadCreditCard_CCFormHasMiddleInitial) {
-  personal_data_.ClearAutofillProfiles();
+  personal_data_.ClearProfiles();
   credit_card_save_manager_->set_credit_card_upload_enabled(true);
 
   // Create, fill and submit two address forms with different names.
@@ -2158,7 +1960,7 @@
 TEST_F(CreditCardSaveManagerTest,
        UploadCreditCard_CCFormHasMiddleInitial_ComparatorEnabled) {
   EnableAutofillUpstreamUseAutofillProfileComparator();
-  personal_data_.ClearAutofillProfiles();
+  personal_data_.ClearProfiles();
   credit_card_save_manager_->set_credit_card_upload_enabled(true);
 
   // Create, fill and submit two address forms with different names.
@@ -2206,7 +2008,7 @@
 }
 
 TEST_F(CreditCardSaveManagerTest, UploadCreditCard_NoMiddleInitialInCCForm) {
-  personal_data_.ClearAutofillProfiles();
+  personal_data_.ClearProfiles();
   credit_card_save_manager_->set_credit_card_upload_enabled(true);
 
   // Create, fill and submit two address forms with different names.
@@ -2250,7 +2052,7 @@
 TEST_F(CreditCardSaveManagerTest,
        UploadCreditCard_NoMiddleInitialInCCForm_ComparatorEnabled) {
   EnableAutofillUpstreamUseAutofillProfileComparator();
-  personal_data_.ClearAutofillProfiles();
+  personal_data_.ClearProfiles();
   credit_card_save_manager_->set_credit_card_upload_enabled(true);
 
   // Create, fill and submit two address forms with different names.
@@ -2292,7 +2094,7 @@
 }
 
 TEST_F(CreditCardSaveManagerTest, UploadCreditCard_CCFormHasMiddleName) {
-  personal_data_.ClearAutofillProfiles();
+  personal_data_.ClearProfiles();
   credit_card_save_manager_->set_credit_card_upload_enabled(true);
 
   // Create, fill and submit address form without middle name.
@@ -2331,7 +2133,7 @@
 TEST_F(CreditCardSaveManagerTest,
        UploadCreditCard_CCFormHasMiddleName_ComparatorEnabled) {
   EnableAutofillUpstreamUseAutofillProfileComparator();
-  personal_data_.ClearAutofillProfiles();
+  personal_data_.ClearProfiles();
   credit_card_save_manager_->set_credit_card_upload_enabled(true);
 
   // Create, fill and submit address form without middle name.
@@ -2371,7 +2173,7 @@
 }
 
 TEST_F(CreditCardSaveManagerTest, UploadCreditCard_CCFormRemovesMiddleName) {
-  personal_data_.ClearAutofillProfiles();
+  personal_data_.ClearProfiles();
   credit_card_save_manager_->set_credit_card_upload_enabled(true);
 
   // Create, fill and submit address form with middle name.
@@ -2412,7 +2214,7 @@
 TEST_F(CreditCardSaveManagerTest,
        UploadCreditCard_CCFormRemovesMiddleName_ComparatorEnabled) {
   EnableAutofillUpstreamUseAutofillProfileComparator();
-  personal_data_.ClearAutofillProfiles();
+  personal_data_.ClearProfiles();
   credit_card_save_manager_->set_credit_card_upload_enabled(true);
 
   // Create, fill and submit address form with middle name.
@@ -2452,7 +2254,7 @@
 }
 
 TEST_F(CreditCardSaveManagerTest, UploadCreditCard_NamesHaveToMatch) {
-  personal_data_.ClearAutofillProfiles();
+  personal_data_.ClearProfiles();
   credit_card_save_manager_->set_credit_card_upload_enabled(true);
 
   // Create, fill and submit two address forms with different names.
@@ -2504,7 +2306,7 @@
   TestAutofillClock test_clock;
   test_clock.SetNow(kArbitraryTime);
 
-  personal_data_.ClearAutofillProfiles();
+  personal_data_.ClearProfiles();
   credit_card_save_manager_->set_credit_card_upload_enabled(true);
 
   // Create, fill and submit two address forms with different names.
@@ -2552,7 +2354,7 @@
   TestAutofillClock test_clock;
   test_clock.SetNow(kArbitraryTime);
 
-  personal_data_.ClearAutofillProfiles();
+  personal_data_.ClearProfiles();
   credit_card_save_manager_->set_credit_card_upload_enabled(true);
 
   // Create, fill and submit an address form in order to establish a recent
@@ -2596,7 +2398,7 @@
 }
 
 TEST_F(CreditCardSaveManagerTest, UploadCreditCard_UploadDetailsFails) {
-  personal_data_.ClearAutofillProfiles();
+  personal_data_.ClearProfiles();
   credit_card_save_manager_->set_credit_card_upload_enabled(true);
 
   // Anything other than "en-US" will cause GetUploadDetails to return a failure
@@ -2642,7 +2444,7 @@
 TEST_F(CreditCardSaveManagerTest, DuplicateMaskedCreditCard) {
   EnableAutofillOfferLocalSaveIfServerCardManuallyEnteredExperiment();
 
-  personal_data_.ClearAutofillProfiles();
+  personal_data_.ClearProfiles();
   credit_card_save_manager_->set_credit_card_upload_enabled(true);
   credit_card_save_manager_->SetAppLocale("en-US");
 
@@ -2681,7 +2483,7 @@
 }
 
 TEST_F(CreditCardSaveManagerTest, DuplicateMaskedCreditCard_ExperimentOff) {
-  personal_data_.ClearAutofillProfiles();
+  personal_data_.ClearProfiles();
   credit_card_save_manager_->set_credit_card_upload_enabled(true);
   credit_card_save_manager_->SetAppLocale("en-US");
 
diff --git a/components/autofill/core/browser/test_personal_data_manager.cc b/components/autofill/core/browser/test_personal_data_manager.cc
index 18413eec..65cb6fe 100644
--- a/components/autofill/core/browser/test_personal_data_manager.cc
+++ b/components/autofill/core/browser/test_personal_data_manager.cc
@@ -4,7 +4,6 @@
 
 #include "components/autofill/core/browser/test_personal_data_manager.h"
 
-#include "base/memory/ptr_util.h"
 #include "components/autofill/core/browser/personal_data_manager_observer.h"
 
 namespace autofill {
@@ -14,48 +13,92 @@
 
 TestPersonalDataManager::~TestPersonalDataManager() {}
 
-void TestPersonalDataManager::SetTestingPrefService(PrefService* pref_service) {
-  SetPrefService(pref_service);
-}
+void TestPersonalDataManager::RecordUseOf(const AutofillDataModel& data_model) {
+  CreditCard* credit_card = GetCreditCardWithGUID(data_model.guid().c_str());
+  if (credit_card)
+    credit_card->RecordAndLogUse();
 
-void TestPersonalDataManager::AddTestingProfile(AutofillProfile* profile) {
-  profiles_.push_back(profile);
-  NotifyPersonalDataChanged();
-}
-
-void TestPersonalDataManager::AddTestingCreditCard(CreditCard* credit_card) {
-  credit_cards_.push_back(credit_card);
-  NotifyPersonalDataChanged();
-}
-
-void TestPersonalDataManager::AddTestingServerCreditCard(
-    const CreditCard& credit_card) {
-  server_credit_cards_.push_back(base::MakeUnique<CreditCard>(credit_card));
-}
-
-std::vector<AutofillProfile*> TestPersonalDataManager::GetProfiles() const {
-  return profiles_;
-}
-
-std::vector<CreditCard*> TestPersonalDataManager::GetCreditCards() const {
-  return credit_cards_;
+  AutofillProfile* profile = GetProfileWithGUID(data_model.guid().c_str());
+  if (profile)
+    profile->RecordAndLogUse();
 }
 
 std::string TestPersonalDataManager::SaveImportedProfile(
     const AutofillProfile& imported_profile) {
-  imported_profile_ = imported_profile;
+  num_times_save_imported_profile_called_++;
+  AddProfile(imported_profile);
   return imported_profile.guid();
 }
 
 std::string TestPersonalDataManager::SaveImportedCreditCard(
     const CreditCard& imported_credit_card) {
-  imported_credit_card_ = imported_credit_card;
+  AddCreditCard(imported_credit_card);
   return imported_credit_card.guid();
 }
 
-std::string TestPersonalDataManager::CountryCodeForCurrentTimezone()
-    const {
-  return timezone_country_code_;
+void TestPersonalDataManager::AddProfile(const AutofillProfile& profile) {
+  std::unique_ptr<AutofillProfile> profile_ptr =
+      std::make_unique<AutofillProfile>(profile);
+  web_profiles_.push_back(std::move(profile_ptr));
+  NotifyPersonalDataChanged();
+}
+
+void TestPersonalDataManager::RemoveByGUID(const std::string& guid) {
+  CreditCard* credit_card = GetCreditCardWithGUID(guid.c_str());
+  if (credit_card) {
+    local_credit_cards_.erase(
+        std::find_if(local_credit_cards_.begin(), local_credit_cards_.end(),
+                     [credit_card](const std::unique_ptr<CreditCard>& ptr) {
+                       return ptr.get() == credit_card;
+                     }));
+  }
+
+  AutofillProfile* profile = GetProfileWithGUID(guid.c_str());
+  if (profile) {
+    web_profiles_.erase(
+        std::find_if(web_profiles_.begin(), web_profiles_.end(),
+                     [profile](const std::unique_ptr<AutofillProfile>& ptr) {
+                       return ptr.get() == profile;
+                     }));
+  }
+}
+
+void TestPersonalDataManager::AddCreditCard(const CreditCard& credit_card) {
+  std::unique_ptr<CreditCard> local_credit_card =
+      std::make_unique<CreditCard>(credit_card);
+  local_credit_cards_.push_back(std::move(local_credit_card));
+  NotifyPersonalDataChanged();
+}
+
+void TestPersonalDataManager::AddFullServerCreditCard(
+    const CreditCard& credit_card) {
+  // Though the name is AddFullServerCreditCard, this test class treats masked
+  // and full server cards equally, relying on their preset RecordType to
+  // differentiate them.
+  AddServerCreditCard(credit_card);
+}
+
+std::vector<AutofillProfile*> TestPersonalDataManager::GetProfiles() const {
+  std::vector<AutofillProfile*> result;
+  result.reserve(web_profiles_.size());
+  for (const auto& profile : web_profiles_)
+    result.push_back(profile.get());
+  return result;
+}
+
+std::vector<CreditCard*> TestPersonalDataManager::GetCreditCards() const {
+  // TODO(crbug.com/778436): The real PersonalDataManager relies on its
+  // |pref_service_| to decide what to return. Since the lack of a pref_service_
+  // makes this fake class crash, it might be useful to refactor the real
+  // GetCreditCards()'s logic into overrideable methods and then remove this
+  // function.
+  std::vector<CreditCard*> result;
+  result.reserve(local_credit_cards_.size() + server_credit_cards_.size());
+  for (const auto& card : local_credit_cards_)
+    result.push_back(card.get());
+  for (const auto& card : server_credit_cards_)
+    result.push_back(card.get());
+  return result;
 }
 
 const std::string& TestPersonalDataManager::GetDefaultCountryCodeForNewAddress()
@@ -66,4 +109,42 @@
   return default_country_code_;
 }
 
+std::string TestPersonalDataManager::CountryCodeForCurrentTimezone()
+    const {
+  return timezone_country_code_;
+}
+
+void TestPersonalDataManager::ClearProfiles() {
+  web_profiles_.clear();
+}
+
+void TestPersonalDataManager::ClearCreditCards() {
+  local_credit_cards_.clear();
+  server_credit_cards_.clear();
+}
+
+AutofillProfile* TestPersonalDataManager::GetProfileWithGUID(const char* guid) {
+  for (AutofillProfile* profile : GetProfiles()) {
+    if (!profile->guid().compare(guid))
+      return profile;
+  }
+  return nullptr;
+}
+
+CreditCard* TestPersonalDataManager::GetCreditCardWithGUID(const char* guid) {
+  for (CreditCard* card : GetCreditCards()) {
+    if (!card->guid().compare(guid))
+      return card;
+  }
+  return nullptr;
+}
+
+void TestPersonalDataManager::AddServerCreditCard(
+    const CreditCard& credit_card) {
+  std::unique_ptr<CreditCard> server_credit_card =
+      std::make_unique<CreditCard>(credit_card);
+  server_credit_cards_.push_back(std::move(server_credit_card));
+  NotifyPersonalDataChanged();
+}
+
 }  // namespace autofill
diff --git a/components/autofill/core/browser/test_personal_data_manager.h b/components/autofill/core/browser/test_personal_data_manager.h
index 8811e61..8c481e5 100644
--- a/components/autofill/core/browser/test_personal_data_manager.h
+++ b/components/autofill/core/browser/test_personal_data_manager.h
@@ -11,10 +11,6 @@
 #include "components/autofill/core/browser/credit_card.h"
 #include "components/autofill/core/browser/personal_data_manager.h"
 
-namespace syncer {
-class SyncService;
-}
-
 namespace autofill {
 
 // A simplistic PersonalDataManager used for testing.
@@ -23,33 +19,44 @@
   TestPersonalDataManager();
   ~TestPersonalDataManager() override;
 
-  // PersonalDataManager:
+  using PersonalDataManager::set_database;
+  using PersonalDataManager::SetPrefService;
+
+  // PersonalDataManager overrides.  These functions are overridden as needed
+  // for various tests, whether to skip calls to uncreated databases/services,
+  // or to make things easier in general to toggle.
   void OnSyncServiceInitialized(syncer::SyncService* sync_service) override {}
-
-  // Sets which PrefService to use and observe. |pref_service| is not owned by
-  // this class and must outlive |this|.
-  void SetTestingPrefService(PrefService* pref_service);
-
-  // Adds |profile| to |profiles_|. This does not take ownership of |profile|.
-  void AddTestingProfile(AutofillProfile* profile);
-
-  // Adds |credit_card| to |credit_cards_|. This does not take ownership of
-  // |credit_card|.
-  void AddTestingCreditCard(CreditCard* credit_card);
-
-  // Adds |credit_card| to |server_credit_cards_| by copying.
-  void AddTestingServerCreditCard(const CreditCard& credit_card);
-
-  std::vector<AutofillProfile*> GetProfiles() const override;
-  std::vector<CreditCard*> GetCreditCards() const override;
-
+  void RecordUseOf(const AutofillDataModel& data_model) override;
   std::string SaveImportedProfile(
       const AutofillProfile& imported_profile) override;
   std::string SaveImportedCreditCard(
       const CreditCard& imported_credit_card) override;
-
-  std::string CountryCodeForCurrentTimezone() const override;
+  void AddProfile(const AutofillProfile& profile) override;
+  void RemoveByGUID(const std::string& guid) override;
+  void AddCreditCard(const CreditCard& credit_card) override;
+  void AddFullServerCreditCard(const CreditCard& credit_card) override;
+  std::vector<AutofillProfile*> GetProfiles() const override;
+  std::vector<CreditCard*> GetCreditCards() const override;
   const std::string& GetDefaultCountryCodeForNewAddress() const override;
+  std::string CountryCodeForCurrentTimezone() const override;
+
+  // Unique to TestPersonalDataManager:
+
+  // Clears |web_profiles_|.
+  void ClearProfiles();
+
+  // Clears |local_credit_cards_| and |server_credit_cards_|.
+  void ClearCreditCards();
+
+  // Gets a profile based on the provided |guid|.
+  AutofillProfile* GetProfileWithGUID(const char* guid);
+
+  // Gets a credit card based on the provided |guid| (local or server).
+  CreditCard* GetCreditCardWithGUID(const char* guid);
+
+  // Adds a card to |server_credit_cards_|.  Functionally identical to
+  // AddFullServerCreditCard().
+  void AddServerCreditCard(const CreditCard& credit_card);
 
   void set_timezone_country_code(const std::string& timezone_country_code) {
     timezone_country_code_ = timezone_country_code;
@@ -58,16 +65,16 @@
     default_country_code_ = default_country_code;
   }
 
-  const AutofillProfile& imported_profile() { return imported_profile_; }
-  const CreditCard& imported_credit_card() { return imported_credit_card_; }
+  int num_times_save_imported_profile_called() const {
+    return num_times_save_imported_profile_called_;
+  }
 
  private:
-  std::vector<AutofillProfile*> profiles_;
-  std::vector<CreditCard*> credit_cards_;
-  AutofillProfile imported_profile_;
-  CreditCard imported_credit_card_;
   std::string timezone_country_code_;
   std::string default_country_code_;
+  int num_times_save_imported_profile_called_ = 0;
+
+  DISALLOW_COPY_AND_ASSIGN(TestPersonalDataManager);
 };
 
 }  // namespace autofill
diff --git a/components/cast_channel/cast_auth_util.cc b/components/cast_channel/cast_auth_util.cc
index 1b6b75d..3844026 100644
--- a/components/cast_channel/cast_auth_util.cc
+++ b/components/cast_channel/cast_auth_util.cc
@@ -22,6 +22,7 @@
 #include "crypto/random.h"
 #include "net/cert/internal/signature_algorithm.h"
 #include "net/cert/x509_certificate.h"
+#include "net/cert/x509_util.h"
 #include "net/der/parse_values.h"
 
 namespace cast_channel {
@@ -304,13 +305,8 @@
                                 std::string* peer_cert_der,
                                 const base::Time& verification_time) {
   // Get the DER-encoded form of the certificate.
-  if (!net::X509Certificate::GetDEREncoded(peer_cert.os_cert_handle(),
-                                           peer_cert_der) ||
-      peer_cert_der->empty()) {
-    return AuthResult::CreateWithParseError(
-        "Could not create DER-encoded peer cert.",
-        AuthResult::ERROR_CERT_PARSING_FAILED);
-  }
+  *peer_cert_der = std::string(
+      net::x509_util::CryptoBufferAsStringPiece(peer_cert.cert_buffer()));
 
   // Ensure the peer cert is valid and doesn't have an excessive remaining
   // lifetime. Although it is not verified as an X.509 certificate, the entire
diff --git a/components/certificate_reporting/error_report.cc b/components/certificate_reporting/error_report.cc
index ae70506..2026db8 100644
--- a/components/certificate_reporting/error_report.cc
+++ b/components/certificate_reporting/error_report.cc
@@ -7,6 +7,7 @@
 #include <vector>
 
 #include "base/stl_util.h"
+#include "base/strings/strcat.h"
 #include "base/strings/string_util.h"
 #include "base/time/time.h"
 #include "components/network_time/network_time_tracker.h"
@@ -57,7 +58,7 @@
   if (!cert->GetPEMEncodedChain(&pem_encoded_chain))
     return false;
 
-  *result = base::JoinString(pem_encoded_chain, "");
+  *result = base::StrCat(pem_encoded_chain);
   return true;
 }
 
diff --git a/components/cronet/android/BUILD.gn b/components/cronet/android/BUILD.gn
index 7611781..9cf1ed7 100644
--- a/components/cronet/android/BUILD.gn
+++ b/components/cronet/android/BUILD.gn
@@ -926,7 +926,7 @@
   sources = []
   foreach(dep, deps) {
     sources += [ get_label_info(dep, "target_gen_dir") + "/" +
-                 get_label_info(dep, "name") + "__compile_java.javac.jar" ]
+                 get_label_info(dep, "name") + ".javac.jar" ]
   }
 
   _rebased_sources = rebase_path(sources, root_build_dir)
@@ -1232,8 +1232,8 @@
   _deps = []
   foreach(dep, invoker.deps) {
     _dep_name = get_label_info(dep, "name")
-    _source_jar = get_label_info(dep, "target_gen_dir") + "/" + _dep_name +
-                  "__compile_java.javac.jar"
+    _source_jar =
+        get_label_info(dep, "target_gen_dir") + "/" + _dep_name + ".javac.jar"
     _output_jar = "$_package_dir/" + _dep_name + ".jar"
 
     # cronet_api.jar is a special case. Its file name is
@@ -1242,9 +1242,7 @@
       _output_jar = "$_package_dir/" + "cronet_api.jar"
     }
 
-    _copy_dep = ":" + _dep_name + "__compile_java__javac"
     _copy_target_name = "${target_name}_${dep}"
-
     copy(_copy_target_name) {
       sources = [
         _source_jar,
@@ -1253,7 +1251,7 @@
         _output_jar,
       ]
       deps = [
-        _copy_dep,
+        ":$_dep_name",
       ]
     }
     _deps += [ ":" + _copy_target_name ]
diff --git a/components/cronet/android/cert/cert_verifier_cache_serializer.cc b/components/cronet/android/cert/cert_verifier_cache_serializer.cc
index e0c4b9a..5d02b14 100644
--- a/components/cronet/android/cert/cert_verifier_cache_serializer.cc
+++ b/components/cronet/android/cert/cert_verifier_cache_serializer.cc
@@ -15,6 +15,7 @@
 #include "net/cert/caching_cert_verifier.h"
 #include "net/cert/cert_verify_result.h"
 #include "net/cert/x509_certificate.h"
+#include "net/cert/x509_util.h"
 
 namespace cronet {
 
@@ -27,40 +28,27 @@
 
 // Determine if |cert_handle| was already serialized. If so, simply return a
 // reference to that entry. Otherwise, add a new entry to the set of certs to
-// be serialized (|serialized_certs|). Returns true if |cert_handle| is
-// serialized correctly.
-bool SerializeCertHandle(const net::X509Certificate::OSCertHandle& cert_handle,
-                         SerializedCertMap* serialized_certs,
-                         size_t* cert_number) {
-  std::string encoded;
-  if (!net::X509Certificate::GetDEREncoded(cert_handle, &encoded))
-    return false;
-  auto result =
-      serialized_certs->insert({encoded, serialized_certs->size() + 1});
-  *cert_number = result.first->second;
-  return true;
+// be serialized (|serialized_certs|).
+size_t SerializeCertHandle(const CRYPTO_BUFFER* cert_handle,
+                           SerializedCertMap* serialized_certs) {
+  auto result = serialized_certs->insert(
+      {std::string(net::x509_util::CryptoBufferAsStringPiece(cert_handle)),
+       serialized_certs->size() + 1});
+  return result.first->second;
 }
 
 // Update |certificate| with certificate number and updates |serialized_certs|
 // with DER-encoded representation of certificate if the certicate is not in
 // |serialized_certs|. Returns true if data is serialized correctly.
-bool SerializeCertificate(net::X509Certificate* cert,
+void SerializeCertificate(net::X509Certificate* cert,
                           SerializedCertMap* serialized_certs,
                           cronet_pb::CertVerificationCertificate* certificate) {
-  size_t cert_number = 0;
-  if (!SerializeCertHandle(cert->os_cert_handle(), serialized_certs,
-                           &cert_number)) {
-    return false;
+  certificate->add_cert_numbers(
+      SerializeCertHandle(cert->cert_buffer(), serialized_certs));
+  for (const auto& intermediate : cert->intermediate_buffers()) {
+    certificate->add_cert_numbers(
+        SerializeCertHandle(intermediate.get(), serialized_certs));
   }
-  certificate->add_cert_numbers(cert_number);
-  const net::X509Certificate::X509Certificate::OSCertHandles&
-      intermediate_ca_certs = cert->GetIntermediateCertificates();
-  for (auto* const intermediate : intermediate_ca_certs) {
-    if (!SerializeCertHandle(intermediate, serialized_certs, &cert_number))
-      return false;
-    certificate->add_cert_numbers(cert_number);
-  }
-  return true;
 }
 
 // Deserializes |certificate| using the certificate database provided in
@@ -87,31 +75,27 @@
 // Serializes |params| into |request_params|, updating |serialized_certs| with
 // the set of raw certificates that will be needed to deserialize the
 // certificate in |request_params| via DeserializeCertificate().
-bool SerializeRequestParams(
+void SerializeRequestParams(
     const net::CertVerifier::RequestParams& params,
     SerializedCertMap* serialized_certs,
     cronet_pb::CertVerificationRequestParams* request_params) {
   cronet_pb::CertVerificationCertificate* certificate =
       request_params->mutable_certificate();
-  if (!SerializeCertificate(params.certificate().get(), serialized_certs,
-                            certificate)) {
-    return false;
-  }
+  SerializeCertificate(params.certificate().get(), serialized_certs,
+                       certificate);
   request_params->set_hostname(params.hostname());
   request_params->set_flags(params.flags());
   request_params->set_ocsp_response(params.ocsp_response());
   for (const auto& cert : params.additional_trust_anchors()) {
     certificate = request_params->add_additional_trust_anchors();
-    if (!SerializeCertificate(cert.get(), serialized_certs, certificate))
-      return false;
+    SerializeCertificate(cert.get(), serialized_certs, certificate);
   }
-  return true;
 }
 
 // Serializes |result| into |cached_result|, updating |serialized_certs| with
 // the set of raw certificates that will be needed to deserialize the
 // certificate in |cached_result| via DeserializeCertificate().
-bool SerializeCachedResult(
+void SerializeCachedResult(
     const net::CertVerifyResult& result,
     SerializedCertMap* serialized_certs,
     cronet_pb::CertVerificationCachedResult* cached_result) {
@@ -119,10 +103,8 @@
       cached_result->mutable_result();
   cronet_pb::CertVerificationCertificate* certificate =
       cert_verification_result->mutable_verified_cert();
-  if (!SerializeCertificate(result.verified_cert.get(), serialized_certs,
-                            certificate)) {
-    return false;
-  }
+  SerializeCertificate(result.verified_cert.get(), serialized_certs,
+                       certificate);
   cert_verification_result->set_cert_status(result.cert_status);
   cert_verification_result->set_has_md2(result.has_md2);
   cert_verification_result->set_has_md4(result.has_md4);
@@ -137,7 +119,6 @@
       result.is_issued_by_additional_trust_anchor);
   cert_verification_result->set_common_name_fallback_used(
       result.common_name_fallback_used);
-  return true;
 }
 
 // Deserializes |cached_result| using the certificate database provided in
@@ -192,7 +173,7 @@
 // |cert_cache|, updating |serialized_certs| with the set of raw certificates
 // that will be needed to deserialize the certificate in |cert_cache| via
 // DeserializeCertificate().
-bool SerializeCachedEntry(const net::CachingCertVerifier::RequestParams& params,
+void SerializeCachedEntry(const net::CachingCertVerifier::RequestParams& params,
                           int error,
                           const net::CertVerifyResult& verify_result,
                           base::Time verification_time,
@@ -203,17 +184,14 @@
 
   cronet_pb::CertVerificationRequestParams* request_params =
       cache_entry->mutable_request_params();
-  if (!SerializeRequestParams(params, serialized_certs, request_params))
-    return false;
+  SerializeRequestParams(params, serialized_certs, request_params);
 
   cronet_pb::CertVerificationCachedResult* cached_result =
       cache_entry->mutable_cached_result();
-  if (!SerializeCachedResult(verify_result, serialized_certs, cached_result))
-    return false;
+  SerializeCachedResult(verify_result, serialized_certs, cached_result);
   cached_result->set_error(error);
 
   cache_entry->set_verification_time(verification_time.ToInternalValue());
-  return true;
 }
 
 class CacheVisitor : public net::CachingCertVerifier::CacheVisitor {
@@ -226,11 +204,8 @@
                   const net::CertVerifyResult& verify_result,
                   base::Time verification_time,
                   base::Time expiration_time) override {
-    if (!SerializeCachedEntry(params, error, verify_result, verification_time,
-                              &cert_cache_, &serialized_certs_)) {
-      Reset();
-      return false;
-    }
+    SerializeCachedEntry(params, error, verify_result, verification_time,
+                         &cert_cache_, &serialized_certs_);
     return true;
   }
 
diff --git a/components/cronet/android/cert/cert_verifier_cache_serializer_unittest.cc b/components/cronet/android/cert/cert_verifier_cache_serializer_unittest.cc
index 237d6566..84366d3 100644
--- a/components/cronet/android/cert/cert_verifier_cache_serializer_unittest.cc
+++ b/components/cronet/android/cert/cert_verifier_cache_serializer_unittest.cc
@@ -9,7 +9,6 @@
 
 #include "base/android/path_utils.h"
 #include "base/files/file_path.h"
-#include "base/memory/ptr_util.h"
 #include "base/memory/ref_counted.h"
 #include "components/cronet/android/cert/proto/cert_verification.pb.h"
 #include "net/base/net_errors.h"
@@ -19,6 +18,7 @@
 #include "net/cert/cert_verify_result.h"
 #include "net/cert/mock_cert_verifier.h"
 #include "net/cert/x509_certificate.h"
+#include "net/cert/x509_util.h"
 #include "net/log/net_log_with_source.h"
 #include "net/test/cert_test_util.h"
 #include "net/test/test_data_directory.h"
@@ -55,13 +55,13 @@
 TEST(CertVerifierCacheSerializerTest, RestoreEmptyData) {
   // Restoring empty data should fail.
   cronet_pb::CertVerificationCache cert_cache;
-  net::CachingCertVerifier verifier(base::MakeUnique<net::MockCertVerifier>());
+  net::CachingCertVerifier verifier(std::make_unique<net::MockCertVerifier>());
   EXPECT_FALSE(DeserializeCertVerifierCache(cert_cache, &verifier));
 }
 
 TEST(CertVerifierCacheSerializerTest, SerializeCache) {
   net::CertVerifyResult verify_result;
-  net::CachingCertVerifier verifier(base::MakeUnique<net::MockCertVerifier>());
+  net::CachingCertVerifier verifier(std::make_unique<net::MockCertVerifier>());
   ASSERT_NO_FATAL_FAILURE(
       VerifyCert("ok_cert.pem", "www.example.com", &verifier, &verify_result));
   cronet_pb::CertVerificationCache cert_cache =
@@ -87,7 +87,7 @@
   // Verify www.example.com host's certificate.
   std::string example_hostname("www.example.com");
   net::CertVerifyResult verifier1_result1;
-  net::CachingCertVerifier verifier(base::MakeUnique<net::MockCertVerifier>());
+  net::CachingCertVerifier verifier(std::make_unique<net::MockCertVerifier>());
   ASSERT_NO_FATAL_FAILURE(VerifyCert("ok_cert.pem", example_hostname, &verifier,
                                      &verifier1_result1));
 
@@ -97,10 +97,12 @@
 
   // Create a certificate that contains both a leaf and an intermediate/root and
   // use that certificate for www2.example.com.
-  net::X509Certificate::OSCertHandles chain;
-  chain.push_back(root_cert->os_cert_handle());
+  std::vector<bssl::UniquePtr<CRYPTO_BUFFER>> chain;
+  chain.push_back(net::x509_util::DupCryptoBuffer(root_cert->cert_buffer()));
   const scoped_refptr<net::X509Certificate> combined_cert =
-      net::X509Certificate::CreateFromHandle(ok_cert->os_cert_handle(), chain);
+      net::X509Certificate::CreateFromBuffer(
+          net::x509_util::DupCryptoBuffer(ok_cert->cert_buffer()),
+          std::move(chain));
   ASSERT_TRUE(combined_cert);
 
   ignore_result(callback.GetResult(verifier.Verify(
@@ -115,7 +117,7 @@
   DCHECK_EQ(2, cert_cache.cert_entry_size());
   DCHECK_EQ(2, cert_cache.cache_entry_size());
 
-  net::CachingCertVerifier verifier2(base::MakeUnique<net::MockCertVerifier>());
+  net::CachingCertVerifier verifier2(std::make_unique<net::MockCertVerifier>());
 
   // Populate |verifier2|'s cache.
   EXPECT_TRUE(DeserializeCertVerifierCache(cert_cache, &verifier2));
@@ -146,7 +148,7 @@
 // Should not deserialize a corrupted cert_entry.
 TEST(CertVerifierCacheSerializerTest, DeserializeCorruptedCerts) {
   net::CertVerifyResult verify_result;
-  net::CachingCertVerifier verifier(base::MakeUnique<net::MockCertVerifier>());
+  net::CachingCertVerifier verifier(std::make_unique<net::MockCertVerifier>());
   ASSERT_NO_FATAL_FAILURE(
       VerifyCert("ok_cert.pem", "www.example.com", &verifier, &verify_result));
   cronet_pb::CertVerificationCache cert_cache =
@@ -156,7 +158,7 @@
 
   cert_cache.clear_cert_entry();
 
-  net::CachingCertVerifier verifier2(base::MakeUnique<net::MockCertVerifier>());
+  net::CachingCertVerifier verifier2(std::make_unique<net::MockCertVerifier>());
   EXPECT_FALSE(DeserializeCertVerifierCache(cert_cache, &verifier2));
 }
 
@@ -164,7 +166,7 @@
 // deserialized. Should not deserialize a corrupted |cert_entry|.
 TEST(CertVerifierCacheSerializerTest, DeserializeCorruptedCacheEntry) {
   net::CertVerifyResult verify_result;
-  net::CachingCertVerifier verifier(base::MakeUnique<net::MockCertVerifier>());
+  net::CachingCertVerifier verifier(std::make_unique<net::MockCertVerifier>());
   ASSERT_NO_FATAL_FAILURE(
       VerifyCert("ok_cert.pem", "www.example.com", &verifier, &verify_result));
   cronet_pb::CertVerificationCache cert_cache =
@@ -175,7 +177,7 @@
   // Corrupt |cache_entry|.
   cert_cache.clear_cache_entry();
 
-  net::CachingCertVerifier verifier2(base::MakeUnique<net::MockCertVerifier>());
+  net::CachingCertVerifier verifier2(std::make_unique<net::MockCertVerifier>());
   EXPECT_FALSE(DeserializeCertVerifierCache(cert_cache, &verifier2));
 }
 
@@ -183,7 +185,7 @@
 // deserialized. Should not deserialize a corrupted |request_params|.
 TEST(CertVerifierCacheSerializerTest, DeserializeCorruptedRequestParams) {
   net::CertVerifyResult verify_result;
-  net::CachingCertVerifier verifier(base::MakeUnique<net::MockCertVerifier>());
+  net::CachingCertVerifier verifier(std::make_unique<net::MockCertVerifier>());
   ASSERT_NO_FATAL_FAILURE(
       VerifyCert("ok_cert.pem", "www.example.com", &verifier, &verify_result));
   cronet_pb::CertVerificationCache cert_cache =
@@ -198,7 +200,7 @@
     cache_entry->clear_request_params();
   }
 
-  net::CachingCertVerifier verifier2(base::MakeUnique<net::MockCertVerifier>());
+  net::CachingCertVerifier verifier2(std::make_unique<net::MockCertVerifier>());
   EXPECT_FALSE(DeserializeCertVerifierCache(cert_cache, &verifier2));
 }
 
@@ -206,7 +208,7 @@
 // fail to be deserialized. Should not deserialize a corrupted |certificate|.
 TEST(CertVerifierCacheSerializerTest, DeserializeRequestParamsNoCertificate) {
   net::CertVerifyResult verify_result;
-  net::CachingCertVerifier verifier(base::MakeUnique<net::MockCertVerifier>());
+  net::CachingCertVerifier verifier(std::make_unique<net::MockCertVerifier>());
   ASSERT_NO_FATAL_FAILURE(
       VerifyCert("ok_cert.pem", "www.example.com", &verifier, &verify_result));
   cronet_pb::CertVerificationCache cert_cache =
@@ -223,7 +225,7 @@
     request_params->clear_certificate();
   }
 
-  net::CachingCertVerifier verifier2(base::MakeUnique<net::MockCertVerifier>());
+  net::CachingCertVerifier verifier2(std::make_unique<net::MockCertVerifier>());
   EXPECT_FALSE(DeserializeCertVerifierCache(cert_cache, &verifier2));
 }
 
@@ -231,7 +233,7 @@
 // fail to be deserialized. Should not deserialize a corrupted |hostname|.
 TEST(CertVerifierCacheSerializerTest, DeserializeRequestParamsNoHostname) {
   net::CertVerifyResult verify_result;
-  net::CachingCertVerifier verifier(base::MakeUnique<net::MockCertVerifier>());
+  net::CachingCertVerifier verifier(std::make_unique<net::MockCertVerifier>());
   ASSERT_NO_FATAL_FAILURE(
       VerifyCert("ok_cert.pem", "www.example.com", &verifier, &verify_result));
   cronet_pb::CertVerificationCache cert_cache =
@@ -248,7 +250,7 @@
     request_params->clear_hostname();
   }
 
-  net::CachingCertVerifier verifier2(base::MakeUnique<net::MockCertVerifier>());
+  net::CachingCertVerifier verifier2(std::make_unique<net::MockCertVerifier>());
   EXPECT_FALSE(DeserializeCertVerifierCache(cert_cache, &verifier2));
 }
 
@@ -256,7 +258,7 @@
 // fail to be deserialized. Should not deserialize an invalid |hostname|.
 TEST(CertVerifierCacheSerializerTest, DeserializeRequestParamsEmptyHostname) {
   net::CertVerifyResult verify_result;
-  net::CachingCertVerifier verifier(base::MakeUnique<net::MockCertVerifier>());
+  net::CachingCertVerifier verifier(std::make_unique<net::MockCertVerifier>());
   ASSERT_NO_FATAL_FAILURE(
       VerifyCert("ok_cert.pem", "www.example.com", &verifier, &verify_result));
   cronet_pb::CertVerificationCache cert_cache =
@@ -273,7 +275,7 @@
     request_params->set_hostname("");
   }
 
-  net::CachingCertVerifier verifier2(base::MakeUnique<net::MockCertVerifier>());
+  net::CachingCertVerifier verifier2(std::make_unique<net::MockCertVerifier>());
   EXPECT_FALSE(DeserializeCertVerifierCache(cert_cache, &verifier2));
 }
 
@@ -281,7 +283,7 @@
 // fail to be deserialized. Should not deserialize a corrupted |flags|.
 TEST(CertVerifierCacheSerializerTest, DeserializeRequestParamsNoFlags) {
   net::CertVerifyResult verify_result;
-  net::CachingCertVerifier verifier(base::MakeUnique<net::MockCertVerifier>());
+  net::CachingCertVerifier verifier(std::make_unique<net::MockCertVerifier>());
   ASSERT_NO_FATAL_FAILURE(
       VerifyCert("ok_cert.pem", "www.example.com", &verifier, &verify_result));
   cronet_pb::CertVerificationCache cert_cache =
@@ -298,7 +300,7 @@
     request_params->clear_flags();
   }
 
-  net::CachingCertVerifier verifier2(base::MakeUnique<net::MockCertVerifier>());
+  net::CachingCertVerifier verifier2(std::make_unique<net::MockCertVerifier>());
   EXPECT_FALSE(DeserializeCertVerifierCache(cert_cache, &verifier2));
 }
 
@@ -306,7 +308,7 @@
 // fail to be deserialized. Should not deserialize a corrupted |ocsp_response|.
 TEST(CertVerifierCacheSerializerTest, DeserializeRequestParamsNoOcspResponse) {
   net::CertVerifyResult verify_result;
-  net::CachingCertVerifier verifier(base::MakeUnique<net::MockCertVerifier>());
+  net::CachingCertVerifier verifier(std::make_unique<net::MockCertVerifier>());
   ASSERT_NO_FATAL_FAILURE(
       VerifyCert("ok_cert.pem", "www.example.com", &verifier, &verify_result));
   cronet_pb::CertVerificationCache cert_cache =
@@ -323,7 +325,7 @@
     request_params->clear_ocsp_response();
   }
 
-  net::CachingCertVerifier verifier2(base::MakeUnique<net::MockCertVerifier>());
+  net::CachingCertVerifier verifier2(std::make_unique<net::MockCertVerifier>());
   EXPECT_FALSE(DeserializeCertVerifierCache(cert_cache, &verifier2));
 }
 
@@ -332,7 +334,7 @@
 TEST(CertVerifierCacheSerializerTest,
      DeserializeRequestParamsCertificateNoCertNumbers) {
   net::CertVerifyResult verify_result;
-  net::CachingCertVerifier verifier(base::MakeUnique<net::MockCertVerifier>());
+  net::CachingCertVerifier verifier(std::make_unique<net::MockCertVerifier>());
   ASSERT_NO_FATAL_FAILURE(
       VerifyCert("ok_cert.pem", "www.example.com", &verifier, &verify_result));
   cronet_pb::CertVerificationCache cert_cache =
@@ -351,7 +353,7 @@
     certificate->clear_cert_numbers();
   }
 
-  net::CachingCertVerifier verifier2(base::MakeUnique<net::MockCertVerifier>());
+  net::CachingCertVerifier verifier2(std::make_unique<net::MockCertVerifier>());
   EXPECT_FALSE(DeserializeCertVerifierCache(cert_cache, &verifier2));
 }
 
@@ -361,7 +363,7 @@
 TEST(CertVerifierCacheSerializerTest,
      DeserializeCorruptedRequestParamsCertNumbers) {
   net::CertVerifyResult verify_result;
-  net::CachingCertVerifier verifier(base::MakeUnique<net::MockCertVerifier>());
+  net::CachingCertVerifier verifier(std::make_unique<net::MockCertVerifier>());
   ASSERT_NO_FATAL_FAILURE(
       VerifyCert("ok_cert.pem", "www.example.com", &verifier, &verify_result));
   cronet_pb::CertVerificationCache cert_cache =
@@ -380,7 +382,7 @@
     certificate->set_cert_numbers(0, 100);
   }
 
-  net::CachingCertVerifier verifier2(base::MakeUnique<net::MockCertVerifier>());
+  net::CachingCertVerifier verifier2(std::make_unique<net::MockCertVerifier>());
   EXPECT_FALSE(DeserializeCertVerifierCache(cert_cache, &verifier2));
 }
 
@@ -409,7 +411,7 @@
   net::TestCompletionCallback callback;
   std::unique_ptr<net::CertVerifier::Request> request;
 
-  net::CachingCertVerifier verifier(base::MakeUnique<net::MockCertVerifier>());
+  net::CachingCertVerifier verifier(std::make_unique<net::MockCertVerifier>());
   // Verify the |cert| with |trust_anchors|.
   ignore_result(callback.GetResult(verifier.Verify(
       net::CertVerifier::RequestParams(cert, "www.example.com", 0,
@@ -435,7 +437,7 @@
     }
   }
 
-  net::CachingCertVerifier verifier2(base::MakeUnique<net::MockCertVerifier>());
+  net::CachingCertVerifier verifier2(std::make_unique<net::MockCertVerifier>());
   EXPECT_FALSE(DeserializeCertVerifierCache(cert_cache, &verifier2));
 }
 
@@ -443,7 +445,7 @@
 // deserialized. Should not deserialize a corrupted |cached_result|.
 TEST(CertVerifierCacheSerializerTest, DeserializeCorruptedCachedResult) {
   net::CertVerifyResult verify_result;
-  net::CachingCertVerifier verifier(base::MakeUnique<net::MockCertVerifier>());
+  net::CachingCertVerifier verifier(std::make_unique<net::MockCertVerifier>());
   ASSERT_NO_FATAL_FAILURE(
       VerifyCert("ok_cert.pem", "www.example.com", &verifier, &verify_result));
   cronet_pb::CertVerificationCache cert_cache =
@@ -458,7 +460,7 @@
     cache_entry->clear_cached_result();
   }
 
-  net::CachingCertVerifier verifier2(base::MakeUnique<net::MockCertVerifier>());
+  net::CachingCertVerifier verifier2(std::make_unique<net::MockCertVerifier>());
   EXPECT_FALSE(DeserializeCertVerifierCache(cert_cache, &verifier2));
 }
 
@@ -466,7 +468,7 @@
 // Should not deserialize a corrupted |error|.
 TEST(CertVerifierCacheSerializerTest, DeserializeCachedResultNoError) {
   net::CertVerifyResult verify_result;
-  net::CachingCertVerifier verifier(base::MakeUnique<net::MockCertVerifier>());
+  net::CachingCertVerifier verifier(std::make_unique<net::MockCertVerifier>());
   ASSERT_NO_FATAL_FAILURE(
       VerifyCert("ok_cert.pem", "www.example.com", &verifier, &verify_result));
   cronet_pb::CertVerificationCache cert_cache =
@@ -483,7 +485,7 @@
     cached_result->clear_error();
   }
 
-  net::CachingCertVerifier verifier2(base::MakeUnique<net::MockCertVerifier>());
+  net::CachingCertVerifier verifier2(std::make_unique<net::MockCertVerifier>());
   EXPECT_FALSE(DeserializeCertVerifierCache(cert_cache, &verifier2));
 }
 
@@ -491,7 +493,7 @@
 // Should not deserialize a corrupted |result|.
 TEST(CertVerifierCacheSerializerTest, DeserializeCachedResultNoResult) {
   net::CertVerifyResult verify_result;
-  net::CachingCertVerifier verifier(base::MakeUnique<net::MockCertVerifier>());
+  net::CachingCertVerifier verifier(std::make_unique<net::MockCertVerifier>());
   ASSERT_NO_FATAL_FAILURE(
       VerifyCert("ok_cert.pem", "www.example.com", &verifier, &verify_result));
   cronet_pb::CertVerificationCache cert_cache =
@@ -508,7 +510,7 @@
     cached_result->clear_result();
   }
 
-  net::CachingCertVerifier verifier2(base::MakeUnique<net::MockCertVerifier>());
+  net::CachingCertVerifier verifier2(std::make_unique<net::MockCertVerifier>());
   EXPECT_FALSE(DeserializeCertVerifierCache(cert_cache, &verifier2));
 }
 
@@ -516,7 +518,7 @@
 // deserialized. Should not deserialize a corrupted |cert_status|.
 TEST(CertVerifierCacheSerializerTest, DeserializeCachedResultNoCertStatus) {
   net::CertVerifyResult verify_result;
-  net::CachingCertVerifier verifier(base::MakeUnique<net::MockCertVerifier>());
+  net::CachingCertVerifier verifier(std::make_unique<net::MockCertVerifier>());
   ASSERT_NO_FATAL_FAILURE(
       VerifyCert("ok_cert.pem", "www.example.com", &verifier, &verify_result));
   cronet_pb::CertVerificationCache cert_cache =
@@ -534,7 +536,7 @@
     result->clear_cert_status();
   }
 
-  net::CachingCertVerifier verifier2(base::MakeUnique<net::MockCertVerifier>());
+  net::CachingCertVerifier verifier2(std::make_unique<net::MockCertVerifier>());
   EXPECT_FALSE(DeserializeCertVerifierCache(cert_cache, &verifier2));
 }
 
@@ -542,7 +544,7 @@
 // deserialized. Should not deserialize a corrupted |verification_time|.
 TEST(CertVerifierCacheSerializerTest, DeserializeCachedResultNoVerifiedCert) {
   net::CertVerifyResult verify_result;
-  net::CachingCertVerifier verifier(base::MakeUnique<net::MockCertVerifier>());
+  net::CachingCertVerifier verifier(std::make_unique<net::MockCertVerifier>());
   ASSERT_NO_FATAL_FAILURE(
       VerifyCert("ok_cert.pem", "www.example.com", &verifier, &verify_result));
   cronet_pb::CertVerificationCache cert_cache =
@@ -560,7 +562,7 @@
     result->clear_verified_cert();
   }
 
-  net::CachingCertVerifier verifier2(base::MakeUnique<net::MockCertVerifier>());
+  net::CachingCertVerifier verifier2(std::make_unique<net::MockCertVerifier>());
   EXPECT_FALSE(DeserializeCertVerifierCache(cert_cache, &verifier2));
 }
 
@@ -569,7 +571,7 @@
 TEST(CertVerifierCacheSerializerTest,
      DeserializeCachedResultNoVerifiedCertNumber) {
   net::CertVerifyResult verify_result;
-  net::CachingCertVerifier verifier(base::MakeUnique<net::MockCertVerifier>());
+  net::CachingCertVerifier verifier(std::make_unique<net::MockCertVerifier>());
   ASSERT_NO_FATAL_FAILURE(
       VerifyCert("ok_cert.pem", "www.example.com", &verifier, &verify_result));
   cronet_pb::CertVerificationCache cert_cache =
@@ -590,7 +592,7 @@
     certificate->clear_cert_numbers();
   }
 
-  net::CachingCertVerifier verifier2(base::MakeUnique<net::MockCertVerifier>());
+  net::CachingCertVerifier verifier2(std::make_unique<net::MockCertVerifier>());
   EXPECT_FALSE(DeserializeCertVerifierCache(cert_cache, &verifier2));
 }
 
@@ -600,7 +602,7 @@
 TEST(CertVerifierCacheSerializerTest,
      DeserializeCorruptedCachedResultVerifiedCertNumber) {
   net::CertVerifyResult verify_result;
-  net::CachingCertVerifier verifier(base::MakeUnique<net::MockCertVerifier>());
+  net::CachingCertVerifier verifier(std::make_unique<net::MockCertVerifier>());
   ASSERT_NO_FATAL_FAILURE(
       VerifyCert("ok_cert.pem", "www.example.com", &verifier, &verify_result));
   cronet_pb::CertVerificationCache cert_cache =
@@ -620,7 +622,7 @@
     certificate->set_cert_numbers(0, 100);
   }
 
-  net::CachingCertVerifier verifier2(base::MakeUnique<net::MockCertVerifier>());
+  net::CachingCertVerifier verifier2(std::make_unique<net::MockCertVerifier>());
   EXPECT_FALSE(DeserializeCertVerifierCache(cert_cache, &verifier2));
 }
 
@@ -629,7 +631,7 @@
 TEST(CertVerifierCacheSerializerTest,
      DeserializeCorruptedCachedResultPublicKeyHashes) {
   net::CertVerifyResult verify_result;
-  net::CachingCertVerifier verifier(base::MakeUnique<net::MockCertVerifier>());
+  net::CachingCertVerifier verifier(std::make_unique<net::MockCertVerifier>());
   ASSERT_NO_FATAL_FAILURE(
       VerifyCert("ok_cert.pem", "www.example.com", &verifier, &verify_result));
   cronet_pb::CertVerificationCache cert_cache =
@@ -647,7 +649,7 @@
     result->add_public_key_hashes("");
   }
 
-  net::CachingCertVerifier verifier2(base::MakeUnique<net::MockCertVerifier>());
+  net::CachingCertVerifier verifier2(std::make_unique<net::MockCertVerifier>());
   EXPECT_FALSE(DeserializeCertVerifierCache(cert_cache, &verifier2));
 }
 
@@ -655,7 +657,7 @@
 // deserialized. Should not deserialize a corrupted |verification_time|.
 TEST(CertVerifierCacheSerializerTest, DeserializeCorruptedVerificationTime) {
   net::CertVerifyResult verify_result;
-  net::CachingCertVerifier verifier(base::MakeUnique<net::MockCertVerifier>());
+  net::CachingCertVerifier verifier(std::make_unique<net::MockCertVerifier>());
   ASSERT_NO_FATAL_FAILURE(
       VerifyCert("ok_cert.pem", "www.example.com", &verifier, &verify_result));
   cronet_pb::CertVerificationCache cert_cache =
@@ -670,7 +672,7 @@
     cache_entry->clear_verification_time();
   }
 
-  net::CachingCertVerifier verifier2(base::MakeUnique<net::MockCertVerifier>());
+  net::CachingCertVerifier verifier2(std::make_unique<net::MockCertVerifier>());
   EXPECT_FALSE(DeserializeCertVerifierCache(cert_cache, &verifier2));
 }
 
diff --git a/components/cronet/android/cronet_upload_data_stream_adapter.cc b/components/cronet/android/cronet_upload_data_stream_adapter.cc
index 994769a..8955788 100644
--- a/components/cronet/android/cronet_upload_data_stream_adapter.cc
+++ b/components/cronet/android/cronet_upload_data_stream_adapter.cc
@@ -4,6 +4,7 @@
 
 #include "components/cronet/android/cronet_upload_data_stream_adapter.h"
 
+#include <memory>
 #include <string>
 #include <utility>
 
@@ -11,7 +12,6 @@
 #include "base/android/jni_string.h"
 #include "base/bind.h"
 #include "base/logging.h"
-#include "base/memory/ptr_util.h"
 #include "base/single_thread_task_runner.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "components/cronet/android/cronet_url_request_adapter.h"
@@ -52,7 +52,7 @@
   // ones used last time.
   if (!(buffer_ && buffer_->io_buffer()->data() == buffer->data() &&
         buffer_->io_buffer_len() == buf_len)) {
-    buffer_ = base::MakeUnique<ByteBufferWithIOBuffer>(env, buffer, buf_len);
+    buffer_ = std::make_unique<ByteBufferWithIOBuffer>(env, buffer, buf_len);
   }
   Java_CronetUploadDataStream_readData(env, jupload_data_stream_,
                                        buffer_->byte_buffer());
diff --git a/components/cronet/android/cronet_url_request_context_adapter.cc b/components/cronet/android/cronet_url_request_context_adapter.cc
index 743acba..658f234 100644
--- a/components/cronet/android/cronet_url_request_context_adapter.cc
+++ b/components/cronet/android/cronet_url_request_context_adapter.cc
@@ -26,7 +26,6 @@
 #include "base/lazy_instance.h"
 #include "base/logging.h"
 #include "base/macros.h"
-#include "base/memory/ptr_util.h"
 #include "base/message_loop/message_loop.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/metrics/statistics_recorder.h"
@@ -361,14 +360,14 @@
   if (config->enable_network_quality_estimator) {
     DCHECK(!network_quality_estimator_);
     std::unique_ptr<net::NetworkQualityEstimatorParams> nqe_params =
-        base::MakeUnique<net::NetworkQualityEstimatorParams>(
+        std::make_unique<net::NetworkQualityEstimatorParams>(
             std::map<std::string, std::string>());
     if (config->nqe_forced_effective_connection_type) {
       nqe_params->SetForcedEffectiveConnectionType(
           config->nqe_forced_effective_connection_type.value());
     }
 
-    network_quality_estimator_ = base::MakeUnique<net::NetworkQualityEstimator>(
+    network_quality_estimator_ = std::make_unique<net::NetworkQualityEstimator>(
         std::unique_ptr<net::ExternalEstimateProvider>(), std::move(nqe_params),
         g_net_log.Get().net_log());
     network_quality_estimator_->AddEffectiveConnectionTypeObserver(this);
@@ -819,7 +818,7 @@
   URLRequestContextConfig* config =
       reinterpret_cast<URLRequestContextConfig*>(jurl_request_context_config);
   config->quic_hints.push_back(
-      base::MakeUnique<URLRequestContextConfig::QuicHint>(
+      std::make_unique<URLRequestContextConfig::QuicHint>(
           base::android::ConvertJavaStringToUTF8(env, jhost), jport,
           jalternate_port));
 }
diff --git a/components/cronet/android/test/mock_cert_verifier.cc b/components/cronet/android/test/mock_cert_verifier.cc
index cba033f..3002d254f 100644
--- a/components/cronet/android/test/mock_cert_verifier.cc
+++ b/components/cronet/android/test/mock_cert_verifier.cc
@@ -16,6 +16,7 @@
 #include "net/cert/cert_verifier.h"
 #include "net/cert/cert_verify_result.h"
 #include "net/cert/mock_cert_verifier.h"
+#include "net/cert/x509_util.h"
 #include "net/test/cert_test_util.h"
 #include "net/test/test_data_directory.h"
 
@@ -29,16 +30,11 @@
 // Returns true on success.
 static bool CalculatePublicKeySha256(const net::X509Certificate& cert,
                                      net::HashValue* out_hash_value) {
-  // Convert the cert to DER encoded bytes.
-  std::string der_cert_bytes;
-  net::X509Certificate::OSCertHandle cert_handle = cert.os_cert_handle();
-  if (!net::X509Certificate::GetDEREncoded(cert_handle, &der_cert_bytes)) {
-    LOG(INFO) << "Unable to convert the given cert to DER encoding";
-    return false;
-  }
   // Extract the public key from the cert.
   base::StringPiece spki_bytes;
-  if (!net::asn1::ExtractSPKIFromDERCert(der_cert_bytes, &spki_bytes)) {
+  if (!net::asn1::ExtractSPKIFromDERCert(
+          net::x509_util::CryptoBufferAsStringPiece(cert.cert_buffer()),
+          &spki_bytes)) {
     LOG(INFO) << "Unable to retrieve the public key from the DER cert";
     return false;
   }
diff --git a/components/cronet/cronet_prefs_manager.cc b/components/cronet/cronet_prefs_manager.cc
index 14c7525..c1d4ae7e1 100644
--- a/components/cronet/cronet_prefs_manager.cc
+++ b/components/cronet/cronet_prefs_manager.cc
@@ -4,6 +4,8 @@
 
 #include "components/cronet/cronet_prefs_manager.h"
 
+#include <memory>
+
 #include "base/files/file_path.h"
 #include "base/files/file_util.h"
 #include "base/location.h"
@@ -227,7 +229,7 @@
   factory.set_user_prefs(json_pref_store_);
   scoped_refptr<PrefRegistrySimple> registry(new PrefRegistrySimple());
   registry->RegisterDictionaryPref(kHttpServerPropertiesPref,
-                                   base::MakeUnique<base::DictionaryValue>());
+                                   std::make_unique<base::DictionaryValue>());
 
   if (enable_network_quality_estimator) {
     // Use lossy prefs to limit the overhead of reading/writing the prefs.
@@ -263,8 +265,8 @@
     net::NetworkQualityEstimator* nqe) {
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
   network_qualities_prefs_manager_ =
-      base::MakeUnique<net::NetworkQualitiesPrefsManager>(
-          base::MakeUnique<NetworkQualitiesPrefDelegateImpl>(
+      std::make_unique<net::NetworkQualitiesPrefsManager>(
+          std::make_unique<NetworkQualitiesPrefDelegateImpl>(
               pref_service_.get()));
 
   network_qualities_prefs_manager_->InitializeOnNetworkThread(nqe);
@@ -276,7 +278,7 @@
     net::NetLog* net_log) {
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
   host_cache_persistence_manager_ =
-      base::MakeUnique<HostCachePersistenceManager>(
+      std::make_unique<HostCachePersistenceManager>(
           host_cache, pref_service_.get(), kHostCachePref,
           base::TimeDelta::FromMilliseconds(host_cache_persistence_delay_ms),
           net_log);
diff --git a/components/cronet/host_cache_persistence_manager_unittest.cc b/components/cronet/host_cache_persistence_manager_unittest.cc
index 9acaa277..c93da37f6 100644
--- a/components/cronet/host_cache_persistence_manager_unittest.cc
+++ b/components/cronet/host_cache_persistence_manager_unittest.cc
@@ -19,12 +19,12 @@
  protected:
   void SetUp() override {
     cache_ = net::HostCache::CreateDefaultCache();
-    pref_service_ = base::MakeUnique<TestingPrefServiceSimple>();
+    pref_service_ = std::make_unique<TestingPrefServiceSimple>();
     pref_service_->registry()->RegisterListPref(kPrefName);
   }
 
   void MakePersistenceManager(base::TimeDelta delay) {
-    persistence_manager_ = base::MakeUnique<HostCachePersistenceManager>(
+    persistence_manager_ = std::make_unique<HostCachePersistenceManager>(
         cache_.get(), pref_service_.get(), kPrefName, delay, nullptr);
   }
 
diff --git a/components/cronet/ios/Cronet.mm b/components/cronet/ios/Cronet.mm
index 713573b..fdab2aa 100644
--- a/components/cronet/ios/Cronet.mm
+++ b/components/cronet/ios/Cronet.mm
@@ -11,7 +11,6 @@
 #include "base/logging.h"
 #include "base/mac/bundle_locations.h"
 #include "base/mac/scoped_block.h"
-#include "base/memory/ptr_util.h"
 #include "base/strings/sys_string_conversions.h"
 #include "base/synchronization/lock.h"
 #include "components/cronet/ios/accept_languages_table.h"
@@ -132,7 +131,7 @@
     (cronet::CronetEnvironment*)cronetEnvironment {
   if (gEnableTestCertVerifierForTesting) {
     std::unique_ptr<TestCertVerifier> test_cert_verifier =
-        base::MakeUnique<TestCertVerifier>();
+        std::make_unique<TestCertVerifier>();
     cronetEnvironment->set_mock_cert_verifier(std::move(test_cert_verifier));
   }
   if (gMockCertVerifier) {
@@ -204,7 +203,7 @@
   }
 
   gQuicHints.push_back(
-      base::MakeUnique<cronet::URLRequestContextConfig::QuicHint>(
+      std::make_unique<cronet::URLRequestContextConfig::QuicHint>(
           quic_host, port, altPort));
 
   return YES;
@@ -267,7 +266,7 @@
     return NO;
   }
 
-  auto pkp = base::MakeUnique<cronet::URLRequestContextConfig::Pkp>(
+  auto pkp = std::make_unique<cronet::URLRequestContextConfig::Pkp>(
       base::SysNSStringToUTF8(host), includeSubdomains,
       base::Time::FromCFAbsoluteTime(
           [expirationDate timeIntervalSinceReferenceDate]));
diff --git a/components/cronet/ios/cronet_environment.mm b/components/cronet/ios/cronet_environment.mm
index 2b59932..0b343e27 100644
--- a/components/cronet/ios/cronet_environment.mm
+++ b/components/cronet/ios/cronet_environment.mm
@@ -16,7 +16,6 @@
 #include "base/mac/bind_objc_block.h"
 #include "base/mac/foundation_util.h"
 #include "base/macros.h"
-#include "base/memory/ptr_util.h"
 #include "base/message_loop/message_loop.h"
 #include "base/metrics/statistics_recorder.h"
 #include "base/path_service.h"
@@ -386,7 +385,7 @@
   [[NSHTTPCookieStorage sharedHTTPCookieStorage]
       setCookieAcceptPolicy:NSHTTPCookieAcceptPolicyAlways];
   std::unique_ptr<net::CookieStore> cookie_store =
-      base::MakeUnique<net::CookieStoreIOS>(
+      std::make_unique<net::CookieStoreIOS>(
           [NSHTTPCookieStorage sharedHTTPCookieStorage]);
   context_builder.SetCookieAndChannelIdStores(std::move(cookie_store), nullptr);
 
diff --git a/components/cronet/ios/empty.cc b/components/cronet/ios/empty.cc
index 98d8bdf..f59ef9b 100644
--- a/components/cronet/ios/empty.cc
+++ b/components/cronet/ios/empty.cc
@@ -3,4 +3,4 @@
 // found in the LICENSE file.
 
 // An empty C++ file that is needed to trigger the usage of clang++ instead of
-// clang.
\ No newline at end of file
+// clang.
diff --git a/components/cronet/ios/test/cronet_test_base.mm b/components/cronet/ios/test/cronet_test_base.mm
index f43e84d..4970459f 100644
--- a/components/cronet/ios/test/cronet_test_base.mm
+++ b/components/cronet/ios/test/cronet_test_base.mm
@@ -9,6 +9,7 @@
 #include "net/base/net_errors.h"
 #include "net/cert/asn1_util.h"
 #include "net/cert/mock_cert_verifier.h"
+#include "net/cert/x509_util.h"
 #include "net/test/cert_test_util.h"
 #include "net/test/test_data_directory.h"
 
@@ -250,16 +251,11 @@
 
 bool CronetTestBase::CalculatePublicKeySha256(const net::X509Certificate& cert,
                                               net::HashValue* out_hash_value) {
-  // Convert the cert to DER encoded bytes.
-  std::string der_cert_bytes;
-  net::X509Certificate::OSCertHandle cert_handle = cert.os_cert_handle();
-  if (!net::X509Certificate::GetDEREncoded(cert_handle, &der_cert_bytes)) {
-    LOG(INFO) << "Unable to convert the given cert to DER encoding";
-    return false;
-  }
   // Extract the public key from the cert.
   base::StringPiece spki_bytes;
-  if (!net::asn1::ExtractSPKIFromDERCert(der_cert_bytes, &spki_bytes)) {
+  if (!net::asn1::ExtractSPKIFromDERCert(
+          net::x509_util::CryptoBufferAsStringPiece(cert.cert_buffer()),
+          &spki_bytes)) {
     LOG(INFO) << "Unable to retrieve the public key from the DER cert";
     return false;
   }
diff --git a/components/cronet/ios/test/test_server.cc b/components/cronet/ios/test/test_server.cc
index c306e5e..24cf1c4e 100644
--- a/components/cronet/ios/test/test_server.cc
+++ b/components/cronet/ios/test/test_server.cc
@@ -4,12 +4,12 @@
 
 #include "components/cronet/ios/test/test_server.h"
 
+#include <memory>
 #include <utility>
 
 #include "base/bind.h"
 #include "base/format_macros.h"
 #include "base/lazy_instance.h"
-#include "base/memory/ptr_util.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
@@ -41,7 +41,7 @@
   auto it = request.headers.find(header_name);
   if (it != request.headers.end())
     header_value = it->second;
-  auto http_response = base::MakeUnique<net::test_server::BasicHttpResponse>();
+  auto http_response = std::make_unique<net::test_server::BasicHttpResponse>();
   http_response->set_code(net::HTTP_OK);
   http_response->set_content(header_value);
   return std::move(http_response);
@@ -54,7 +54,7 @@
                           base::CompareCase::INSENSITIVE_ASCII));
 
   encoding = request.relative_url.substr(strlen(kUseEncodingPath));
-  auto http_response = base::MakeUnique<net::test_server::BasicHttpResponse>();
+  auto http_response = std::make_unique<net::test_server::BasicHttpResponse>();
   if (!encoding.compare("brotli")) {
     const char quickfoxCompressed[] = {
         0x0b, 0x15, -0x80, 0x54, 0x68, 0x65, 0x20, 0x71, 0x75, 0x69, 0x63, 0x6b,
@@ -76,7 +76,7 @@
   DCHECK(base::StartsWith(request.relative_url, kEchoRequestBodyPath,
                           base::CompareCase::INSENSITIVE_ASCII));
   std::string request_content = request.content;
-  auto http_response = base::MakeUnique<net::test_server::BasicHttpResponse>();
+  auto http_response = std::make_unique<net::test_server::BasicHttpResponse>();
   http_response->set_code(net::HTTP_OK);
   http_response->set_content(request_content);
   return http_response;
@@ -90,7 +90,7 @@
   int64_t data_size;
   CHECK(base::StringToInt64(base::StringPiece(data_size_str), &data_size));
   CHECK(data_size == static_cast<int64_t>(g_big_data_body.Get().size()));
-  return base::MakeUnique<net::test_server::RawHttpResponse>(
+  return std::make_unique<net::test_server::RawHttpResponse>(
       std::string(), g_big_data_body.Get());
 }
 
@@ -100,7 +100,7 @@
   DCHECK(base::StartsWith(request.relative_url, kSetCookiePath,
                           base::CompareCase::INSENSITIVE_ASCII));
   cookie_line = request.relative_url.substr(strlen(kSetCookiePath));
-  auto http_response = base::MakeUnique<net::test_server::BasicHttpResponse>();
+  auto http_response = std::make_unique<net::test_server::BasicHttpResponse>();
   http_response->set_code(net::HTTP_OK);
   http_response->set_content(cookie_line);
   http_response->AddCustomHeader("Set-Cookie", cookie_line);
@@ -129,7 +129,7 @@
                        base::CompareCase::INSENSITIVE_ASCII)) {
     return EchoResponseBody(request);
   }
-  return base::MakeUnique<net::test_server::BasicHttpResponse>();
+  return std::make_unique<net::test_server::BasicHttpResponse>();
 }
 
 }  // namespace
@@ -139,7 +139,7 @@
 /* static */
 bool TestServer::Start() {
   DCHECK(!g_test_server.get());
-  g_test_server = base::MakeUnique<net::EmbeddedTestServer>(
+  g_test_server = std::make_unique<net::EmbeddedTestServer>(
       net::EmbeddedTestServer::TYPE_HTTP);
   g_test_server->RegisterRequestHandler(base::Bind(&CronetTestRequestHandler));
   CHECK(g_test_server->Start());
diff --git a/components/cronet/tools/generators/cronet_bindings_generator.py b/components/cronet/tools/generators/cronet_bindings_generator.py
index 846242e9..65696da 100755
--- a/components/cronet/tools/generators/cronet_bindings_generator.py
+++ b/components/cronet/tools/generators/cronet_bindings_generator.py
@@ -209,7 +209,6 @@
             variant=args.variant, bytecode_path=args.bytecode_path,
             for_blink=args.for_blink,
             use_once_callback=args.use_once_callback,
-            js_bindings_mode=args.js_bindings_mode,
             export_attribute=args.export_attribute,
             export_header=args.export_header,
             generate_non_variant_code=args.generate_non_variant_code,
@@ -343,13 +342,6 @@
       "--use_once_callback", action="store_true",
       help="Use base::OnceCallback instead of base::RepeatingCallback.")
   generate_parser.add_argument(
-      "--js_bindings_mode", choices=["new", "both", "old"], default="new",
-      help="This option only affects the JavaScript bindings. The value could "
-      "be: \"new\" - generate only the new-style JS bindings, which use the "
-      "new module loading approach and the core api exposed by Web IDL; "
-      "\"both\" - generate both the old- and new-style bindings; \"old\" - "
-      "generate only the old-style bindings.")
-  generate_parser.add_argument(
       "--export_attribute", default="",
       help="Optional attribute to specify on class declaration to export it "
       "for the component build.")
diff --git a/components/cronet/url_request_context_config.cc b/components/cronet/url_request_context_config.cc
index 88ad51b..19e7cfd 100644
--- a/components/cronet/url_request_context_config.cc
+++ b/components/cronet/url_request_context_config.cc
@@ -8,7 +8,6 @@
 
 #include "base/json/json_reader.h"
 #include "base/logging.h"
-#include "base/memory/ptr_util.h"
 #include "base/sequenced_task_runner.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_piece.h"
@@ -502,7 +501,7 @@
   if (mock_cert_verifier) {
     // Because |context_builder| expects CachingCertVerifier, wrap
     // |mock_cert_verifier| into a CachingCertVerifier.
-    cert_verifier = base::MakeUnique<net::CachingCertVerifier>(
+    cert_verifier = std::make_unique<net::CachingCertVerifier>(
         std::move(mock_cert_verifier));
   } else {
     // net::CertVerifier::CreateDefault() returns a CachingCertVerifier.
@@ -512,9 +511,9 @@
   // Certificate Transparency is intentionally ignored in Cronet.
   // See //net/docs/certificate-transparency.md for more details.
   context_builder->set_ct_verifier(
-      base::MakeUnique<net::DoNothingCTVerifier>());
+      std::make_unique<net::DoNothingCTVerifier>());
   context_builder->set_ct_policy_enforcer(
-      base::MakeUnique<DoNothingCTPolicyEnforcer>());
+      std::make_unique<DoNothingCTPolicyEnforcer>());
   // TODO(mef): Use |config| to set cookies.
 }
 
@@ -523,7 +522,7 @@
 
 std::unique_ptr<URLRequestContextConfig>
 URLRequestContextConfigBuilder::Build() {
-  return base::MakeUnique<URLRequestContextConfig>(
+  return std::make_unique<URLRequestContextConfig>(
       enable_quic, quic_user_agent_id, enable_spdy, enable_brotli, http_cache,
       http_cache_max_size, load_disable_cache, storage_path, user_agent,
       experimental_options, std::move(mock_cert_verifier),
diff --git a/components/cronet/url_request_context_config_unittest.cc b/components/cronet/url_request_context_config_unittest.cc
index bcd063d..3627616fd 100644
--- a/components/cronet/url_request_context_config_unittest.cc
+++ b/components/cronet/url_request_context_config_unittest.cc
@@ -4,7 +4,6 @@
 
 #include "components/cronet/url_request_context_config.h"
 
-#include "base/memory/ptr_util.h"
 #include "base/test/scoped_task_environment.h"
 #include "base/values.h"
 #include "net/cert/cert_verifier.h"
@@ -71,7 +70,7 @@
   EXPECT_FALSE(config.effective_experimental_options->HasKey("UnknownOption"));
   // Set a ProxyConfigService to avoid DCHECK failure when building.
   builder.set_proxy_config_service(
-      base::MakeUnique<net::ProxyConfigServiceFixed>(
+      std::make_unique<net::ProxyConfigServiceFixed>(
           net::ProxyConfig::CreateDirect()));
   std::unique_ptr<net::URLRequestContext> context(builder.Build());
   const net::HttpNetworkSession::Params* params =
@@ -155,7 +154,7 @@
   config.ConfigureURLRequestContextBuilder(&builder, &net_log);
   // Set a ProxyConfigService to avoid DCHECK failure when building.
   builder.set_proxy_config_service(
-      base::MakeUnique<net::ProxyConfigServiceFixed>(
+      std::make_unique<net::ProxyConfigServiceFixed>(
           net::ProxyConfig::CreateDirect()));
   std::unique_ptr<net::URLRequestContext> context(builder.Build());
   const net::HttpNetworkSession::Params* params =
@@ -207,7 +206,7 @@
   config.ConfigureURLRequestContextBuilder(&builder, &net_log);
   // Set a ProxyConfigService to avoid DCHECK failure when building.
   builder.set_proxy_config_service(
-      base::MakeUnique<net::ProxyConfigServiceFixed>(
+      std::make_unique<net::ProxyConfigServiceFixed>(
           net::ProxyConfig::CreateDirect()));
   std::unique_ptr<net::URLRequestContext> context(builder.Build());
   const net::HttpNetworkSession::Params* params =
@@ -257,7 +256,7 @@
   config.ConfigureURLRequestContextBuilder(&builder, &net_log);
   // Set a ProxyConfigService to avoid DCHECK failure when building.
   builder.set_proxy_config_service(
-      base::MakeUnique<net::ProxyConfigServiceFixed>(
+      std::make_unique<net::ProxyConfigServiceFixed>(
           net::ProxyConfig::CreateDirect()));
   std::unique_ptr<net::URLRequestContext> context(builder.Build());
   const net::HttpNetworkSession::Params* params =
@@ -310,7 +309,7 @@
   config.ConfigureURLRequestContextBuilder(&builder, &net_log);
   // Set a ProxyConfigService to avoid DCHECK failure when building.
   builder.set_proxy_config_service(
-      base::MakeUnique<net::ProxyConfigServiceFixed>(
+      std::make_unique<net::ProxyConfigServiceFixed>(
           net::ProxyConfig::CreateDirect()));
   std::unique_ptr<net::URLRequestContext> context(builder.Build());
   const net::HttpNetworkSession::Params* params =
diff --git a/components/exo/surface.cc b/components/exo/surface.cc
index 18109528..52ddffba 100644
--- a/components/exo/surface.cc
+++ b/components/exo/surface.cc
@@ -614,8 +614,8 @@
     return nullptr;
 
   auto rects = std::make_unique<aura::WindowTargeter::HitTestRects>();
-  for (cc::Region::Iterator it(hit_test_region_); it.has_rect(); it.next())
-    rects->push_back(it.rect());
+  for (gfx::Rect rect : hit_test_region_)
+    rects->push_back(rect);
   return rects;
 }
 
diff --git a/components/grpc_support/bidirectional_stream_unittest.cc b/components/grpc_support/bidirectional_stream_unittest.cc
index 589f802..1abaad5 100644
--- a/components/grpc_support/bidirectional_stream_unittest.cc
+++ b/components/grpc_support/bidirectional_stream_unittest.cc
@@ -10,7 +10,7 @@
 #include "base/logging.h"
 #include "base/macros.h"
 #include "base/memory/ptr_util.h"
-#include "base/strings/string_util.h"
+#include "base/strings/strcat.h"
 #include "base/synchronization/waitable_event.h"
 #include "components/grpc_support/include/bidirectional_stream_c.h"
 #include "components/grpc_support/test/get_stream_engine.h"
@@ -285,7 +285,7 @@
   ASSERT_EQ(std::string(kHelloBodyValue, 2), test.read_data.front());
   // Verify that individual read data joined using empty separator match
   // expected body.
-  ASSERT_EQ(std::string(kHelloBodyValue), base::JoinString(test.read_data, ""));
+  ASSERT_EQ(std::string(kHelloBodyValue), base::StrCat(test.read_data));
   ASSERT_EQ(std::string(kHelloTrailerValue),
             test.response_trailers[kHelloTrailerName]);
   bidirectional_stream_destroy(test.stream);
@@ -329,7 +329,7 @@
   ASSERT_EQ(std::string(kHelloHeaderValue),
             test.response_headers[kHelloHeaderName]);
   ASSERT_EQ(TestBidirectionalStreamCallback::ON_SUCCEEDED, test.response_step);
-  ASSERT_EQ(std::string(kHelloBodyValue), base::JoinString(test.read_data, ""));
+  ASSERT_EQ(std::string(kHelloBodyValue), base::StrCat(test.read_data));
   ASSERT_EQ(std::string(kHelloTrailerValue),
             test.response_trailers[kHelloTrailerName]);
   // Flush after done is ignored.
@@ -356,7 +356,7 @@
   ASSERT_EQ(std::string(kHelloHeaderValue),
             test.response_headers[kHelloHeaderName]);
   ASSERT_EQ(TestBidirectionalStreamCallback::ON_SUCCEEDED, test.response_step);
-  ASSERT_EQ(std::string(kHelloBodyValue), base::JoinString(test.read_data, ""));
+  ASSERT_EQ(std::string(kHelloBodyValue), base::StrCat(test.read_data));
   ASSERT_EQ(std::string(kHelloTrailerValue),
             test.response_trailers[kHelloTrailerName]);
   // Flush after done is ignored.
@@ -386,7 +386,7 @@
   ASSERT_EQ(std::string(kHelloHeaderValue),
             test.response_headers[kHelloHeaderName]);
   ASSERT_EQ(TestBidirectionalStreamCallback::ON_SUCCEEDED, test.response_step);
-  ASSERT_EQ(std::string(kHelloBodyValue), base::JoinString(test.read_data, ""));
+  ASSERT_EQ(std::string(kHelloBodyValue), base::StrCat(test.read_data));
   ASSERT_EQ(std::string(kHelloTrailerValue),
             test.response_trailers[kHelloTrailerName]);
   // Flush after done is ignored.
@@ -413,7 +413,7 @@
   ASSERT_EQ(std::string(kHelloHeaderValue),
             test.response_headers[kHelloHeaderName]);
   ASSERT_EQ(TestBidirectionalStreamCallback::ON_SUCCEEDED, test.response_step);
-  ASSERT_EQ(std::string(kHelloBodyValue), base::JoinString(test.read_data, ""));
+  ASSERT_EQ(std::string(kHelloBodyValue), base::StrCat(test.read_data));
   ASSERT_EQ(std::string(kHelloTrailerValue),
             test.response_trailers[kHelloTrailerName]);
   // Flush after done is ignored.
diff --git a/components/metrics/enabled_state_provider.cc b/components/metrics/enabled_state_provider.cc
index eb7b47a..31f2964 100644
--- a/components/metrics/enabled_state_provider.cc
+++ b/components/metrics/enabled_state_provider.cc
@@ -6,7 +6,7 @@
 
 namespace metrics {
 
-bool EnabledStateProvider::IsReportingEnabled() {
+bool EnabledStateProvider::IsReportingEnabled() const {
   return IsConsentGiven();
 }
 
diff --git a/components/metrics/enabled_state_provider.h b/components/metrics/enabled_state_provider.h
index cc05785..266194d 100644
--- a/components/metrics/enabled_state_provider.h
+++ b/components/metrics/enabled_state_provider.h
@@ -13,11 +13,11 @@
   virtual ~EnabledStateProvider() {}
 
   // Indicates that the user has provided consent to collect and report metrics.
-  virtual bool IsConsentGiven() = 0;
+  virtual bool IsConsentGiven() const = 0;
 
   // Should collection and reporting be enabled. This should depend on consent
   // being given.
-  virtual bool IsReportingEnabled();
+  virtual bool IsReportingEnabled() const;
 };
 
 }  // namespace metrics
diff --git a/components/metrics/test_enabled_state_provider.cc b/components/metrics/test_enabled_state_provider.cc
index 6e40a8d..d8c59e44 100644
--- a/components/metrics/test_enabled_state_provider.cc
+++ b/components/metrics/test_enabled_state_provider.cc
@@ -6,11 +6,11 @@
 
 namespace metrics {
 
-bool TestEnabledStateProvider::IsConsentGiven() {
+bool TestEnabledStateProvider::IsConsentGiven() const {
   return consent_;
 }
 
-bool TestEnabledStateProvider::IsReportingEnabled() {
+bool TestEnabledStateProvider::IsReportingEnabled() const {
   return enabled_;
 }
 
diff --git a/components/metrics/test_enabled_state_provider.h b/components/metrics/test_enabled_state_provider.h
index 001601b60..29fd7f17 100644
--- a/components/metrics/test_enabled_state_provider.h
+++ b/components/metrics/test_enabled_state_provider.h
@@ -19,8 +19,8 @@
   ~TestEnabledStateProvider() override {}
 
   // EnabledStateProvider
-  bool IsConsentGiven() override;
-  bool IsReportingEnabled() override;
+  bool IsConsentGiven() const override;
+  bool IsReportingEnabled() const override;
 
   void set_consent(bool consent) { consent_ = consent; }
   void set_enabled(bool enabled) { enabled_ = enabled; }
diff --git a/components/navigation_interception/intercept_navigation_throttle.cc b/components/navigation_interception/intercept_navigation_throttle.cc
index db7a1dd1..81acec4 100644
--- a/components/navigation_interception/intercept_navigation_throttle.cc
+++ b/components/navigation_interception/intercept_navigation_throttle.cc
@@ -4,6 +4,9 @@
 
 #include "components/navigation_interception/intercept_navigation_throttle.h"
 
+#include "base/metrics/histogram_macros.h"
+#include "base/time/time.h"
+#include "base/timer/elapsed_timer.h"
 #include "components/navigation_interception/navigation_params.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/navigation_handle.h"
@@ -23,7 +26,12 @@
 content::NavigationThrottle::ThrottleCheckResult
 InterceptNavigationThrottle::WillStartRequest() {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
-  return CheckIfShouldIgnoreNavigation(false);
+  base::ElapsedTimer timer;
+
+  auto result = CheckIfShouldIgnoreNavigation(false);
+  UMA_HISTOGRAM_COUNTS_10M("Navigation.Intercept.WillStart",
+                           timer.Elapsed().InMicroseconds());
+  return result;
 }
 
 content::NavigationThrottle::ThrottleCheckResult
diff --git a/components/offline_pages/OWNERS b/components/offline_pages/OWNERS
index 16116cc..0e619a5 100644
--- a/components/offline_pages/OWNERS
+++ b/components/offline_pages/OWNERS
@@ -1,3 +1,4 @@
+carlosk@chromium.org
 chili@chromium.org
 dewittj@chromium.org
 dimich@chromium.org
diff --git a/components/offline_pages/core/offline_page_metadata_store_sql.cc b/components/offline_pages/core/offline_page_metadata_store_sql.cc
index 45aa4bf..28648612 100644
--- a/components/offline_pages/core/offline_page_metadata_store_sql.cc
+++ b/components/offline_pages/core/offline_page_metadata_store_sql.cc
@@ -640,7 +640,6 @@
 
 void OfflinePageMetadataStoreSQL::InitializeInternal(
     base::OnceClosure pending_command) {
-  // TODO(fgorski): Set state to initializing/loading.
   DCHECK_EQ(state_, StoreState::NOT_LOADED);
 
   if (!last_closing_time_.is_null()) {
@@ -654,6 +653,7 @@
     ReportStoreEvent(OfflinePagesStoreEvent::STORE_OPENED_FIRST_TIME);
   }
 
+  state_ = StoreState::INITIALIZING;
   db_.reset(new sql::Connection());
   base::PostTaskAndReplyWithResult(
       background_task_runner_.get(), FROM_HERE,
@@ -675,6 +675,14 @@
   CHECK(!pending_command.is_null());
   std::move(pending_command).Run();
 
+  // Execute other pending commands.
+  for (auto command_iter = pending_commands_.begin();
+       command_iter != pending_commands_.end();) {
+    std::move(*command_iter++).Run();
+  }
+
+  pending_commands_.clear();
+
   if (state_ == StoreState::FAILED_LOADING)
     state_ = StoreState::NOT_LOADED;
 }
diff --git a/components/offline_pages/core/offline_page_metadata_store_sql.h b/components/offline_pages/core/offline_page_metadata_store_sql.h
index 7ecd0d1..797ae20 100644
--- a/components/offline_pages/core/offline_page_metadata_store_sql.h
+++ b/components/offline_pages/core/offline_page_metadata_store_sql.h
@@ -122,6 +122,16 @@
       return;
     }
 
+    // This if allows to run commands later, after store was given a chance to
+    // initialize. They would be failing immediately otherwise.
+    if (state_ == StoreState::INITIALIZING) {
+      pending_commands_.push_back(
+          base::BindOnce(&OfflinePageMetadataStoreSQL::Execute<T>,
+                         weak_ptr_factory_.GetWeakPtr(),
+                         std::move(run_callback), std::move(result_callback)));
+      return;
+    }
+
     // Ensure that any scheduled close operations are canceled.
     closing_weak_ptr_factory_.InvalidateWeakPtrs();
 
@@ -180,6 +190,9 @@
   // State of the store.
   StoreState state_;
 
+  // Pending commands.
+  std::vector<base::OnceClosure> pending_commands_;
+
   // Time of the last time the store was closed. Kept for metrics reporting.
   base::Time last_closing_time_;
 
diff --git a/components/offline_pages/core/offline_page_metadata_store_unittest.cc b/components/offline_pages/core/offline_page_metadata_store_unittest.cc
index 5d3e00e..b7b414a 100644
--- a/components/offline_pages/core/offline_page_metadata_store_unittest.cc
+++ b/components/offline_pages/core/offline_page_metadata_store_unittest.cc
@@ -432,6 +432,7 @@
   }
 
   std::unique_ptr<OfflinePageMetadataStore> BuildStore();
+  std::unique_ptr<OfflinePageMetadataStore> BuildStoreWithoutInit();
   std::unique_ptr<OfflinePageMetadataStore> BuildStoreWithSchemaFromM52();
   std::unique_ptr<OfflinePageMetadataStore> BuildStoreWithSchemaFromM53();
   std::unique_ptr<OfflinePageMetadataStore> BuildStoreWithSchemaFromM54();
@@ -466,6 +467,7 @@
 
  protected:
   CalledCallback last_called_callback_;
+  int get_callback_counter_;
   Status last_status_;
   std::unique_ptr<OfflinePagesUpdateResult> last_update_result_;
   std::vector<OfflinePageItem> offline_pages_;
@@ -478,6 +480,7 @@
 
 OfflinePageMetadataStoreTest::OfflinePageMetadataStoreTest()
     : last_called_callback_(NONE),
+      get_callback_counter_(0),
       last_status_(STATUS_NONE),
       task_runner_(new base::TestMockTimeTaskRunner),
       task_runner_handle_(task_runner_) {
@@ -501,6 +504,7 @@
 void OfflinePageMetadataStoreTest::GetOfflinePagesCallback(
     std::vector<OfflinePageItem> offline_pages) {
   last_called_callback_ = LOAD;
+  get_callback_counter_++;
   offline_pages_.swap(offline_pages);
 }
 
@@ -588,6 +592,13 @@
 }
 
 std::unique_ptr<OfflinePageMetadataStore>
+OfflinePageMetadataStoreTest::BuildStoreWithoutInit() {
+  std::unique_ptr<OfflinePageMetadataStore> store(
+      factory_.BuildStore(temp_directory_.GetPath()));
+  return store;
+}
+
+std::unique_ptr<OfflinePageMetadataStore>
 OfflinePageMetadataStoreTest::BuildStoreWithSchemaFromM52() {
   std::unique_ptr<OfflinePageMetadataStore> store(
       factory_.BuildStoreM52(temp_directory_.GetPath()));
@@ -1169,5 +1180,32 @@
   EXPECT_EQ(0U, offline_pages_.size());
 }
 
+TEST_F(OfflinePageMetadataStoreTest, MultiplePendingCalls) {
+  std::unique_ptr<OfflinePageMetadataStore> store(BuildStoreWithoutInit());
+  EXPECT_FALSE(task_runner()->HasPendingTask());
+  EXPECT_EQ(StoreState::NOT_LOADED, store->state());
+
+  // First call flips the state to initializing.
+  store->GetOfflinePages(base::BindRepeating(
+      &OfflinePageMetadataStoreTest::GetOfflinePagesCallback,
+      base::Unretained(this)));
+
+  EXPECT_EQ(StoreState::INITIALIZING, store->state());
+
+  // Subsequent calls should be pending until store is initialized.
+  store->GetOfflinePages(base::BindRepeating(
+      &OfflinePageMetadataStoreTest::GetOfflinePagesCallback,
+      base::Unretained(this)));
+  store->GetOfflinePages(base::BindRepeating(
+      &OfflinePageMetadataStoreTest::GetOfflinePagesCallback,
+      base::Unretained(this)));
+  PumpLoop();
+
+  EXPECT_EQ(StoreState::LOADED, store->state());
+  EXPECT_EQ(LOAD, last_called_callback_);
+  EXPECT_EQ(0U, offline_pages_.size());
+  EXPECT_EQ(3, get_callback_counter_);
+}
+
 }  // namespace
 }  // namespace offline_pages
diff --git a/components/offline_pages/core/offline_store_types.h b/components/offline_pages/core/offline_store_types.h
index aa95914..65d1e4bd 100644
--- a/components/offline_pages/core/offline_store_types.h
+++ b/components/offline_pages/core/offline_store_types.h
@@ -21,6 +21,7 @@
   LOADED,          // Store is properly loaded and operational.
   FAILED_LOADING,  // Store initialization failed.
   FAILED_RESET,    // Resetting the store failed.
+  INITIALIZING,    // Store is in the process of initializing.
 };
 
 // Statuses referring to actions taken on items in the stores.
diff --git a/components/offline_pages/core/stub_offline_page_model.h b/components/offline_pages/core/stub_offline_page_model.h
index 5ebf05e6..d2f72d74 100644
--- a/components/offline_pages/core/stub_offline_page_model.h
+++ b/components/offline_pages/core/stub_offline_page_model.h
@@ -9,16 +9,15 @@
 #include <string>
 #include <vector>
 
-#include "components/keyed_service/core/keyed_service.h"
 #include "components/offline_pages/core/client_policy_controller.h"
-#include "components/offline_pages/core/offline_page_model.h"
+#include "components/offline_pages/core/offline_page_model_impl.h"
 
 namespace offline_pages {
 
 // Stub implementation of OfflinePageModel interface for testing. Besides using
 // as a stub for tests, it may also be subclassed to mock specific methods
 // needed for a set of tests.
-class StubOfflinePageModel : public OfflinePageModel, public KeyedService {
+class StubOfflinePageModel : public OfflinePageModelImpl {
  public:
   StubOfflinePageModel();
   ~StubOfflinePageModel() override;
diff --git a/components/payments/content/payment_request_state_unittest.cc b/components/payments/content/payment_request_state_unittest.cc
index ecf1e29..08db80fc 100644
--- a/components/payments/content/payment_request_state_unittest.cc
+++ b/components/payments/content/payment_request_state_unittest.cc
@@ -33,10 +33,10 @@
                         test_payment_request_delegate_.GetUkmRecorder()),
         address_(autofill::test::GetFullProfile()),
         credit_card_visa_(autofill::test::GetCreditCard()) {
-    test_personal_data_manager_.AddTestingProfile(&address_);
+    test_personal_data_manager_.AddProfile(address_);
     credit_card_visa_.set_billing_address_id(address_.guid());
     credit_card_visa_.set_use_count(5u);
-    test_personal_data_manager_.AddTestingCreditCard(&credit_card_visa_);
+    test_personal_data_manager_.AddCreditCard(credit_card_visa_);
   }
   ~PaymentRequestStateTest() override {}
 
diff --git a/components/payments/content/payment_response_helper_unittest.cc b/components/payments/content/payment_response_helper_unittest.cc
index 706cbba..ee3bc1e 100644
--- a/components/payments/content/payment_response_helper_unittest.cc
+++ b/components/payments/content/payment_response_helper_unittest.cc
@@ -30,9 +30,9 @@
       : test_payment_request_delegate_(&test_personal_data_manager_),
         address_(autofill::test::GetFullProfile()),
         billing_addresses_({&address_}) {
-    test_personal_data_manager_.AddTestingProfile(&address_);
+    test_personal_data_manager_.AddProfile(address_);
 
-    // Setup the autofill payment instrument.
+    // Set up the autofill payment instrument.
     autofill::CreditCard visa_card = autofill::test::GetCreditCard();
     visa_card.set_billing_address_id(address_.guid());
     visa_card.set_use_count(5u);
diff --git a/components/policy/content/BUILD.gn b/components/policy/content/BUILD.gn
new file mode 100644
index 0000000..fda6e2f
--- /dev/null
+++ b/components/policy/content/BUILD.gn
@@ -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.
+
+import("//build/config/features.gni")
+
+assert(!is_ios, "Policy Throttle should not be referenced on iOS")
+
+source_set("content") {
+  sources = [
+    "policy_blacklist_navigation_throttle.cc",
+    "policy_blacklist_navigation_throttle.h",
+  ]
+
+  deps = [
+    "//base",
+    "//components/keyed_service/content:content",
+    "//components/policy/core/browser",
+    "//components/prefs",
+    "//components/user_prefs:user_prefs",
+    "//content/public/browser",
+    "//net",
+  ]
+}
diff --git a/components/policy/content/DEPS b/components/policy/content/DEPS
new file mode 100644
index 0000000..3b9caa8
--- /dev/null
+++ b/components/policy/content/DEPS
@@ -0,0 +1,8 @@
+include_rules = [
+  "+content/public",
+  "+components/policy",
+  "+components/keyed_service",
+  "+components/prefs",
+  "+components/user_prefs",
+  "+net/base",
+]
diff --git a/components/policy/content/policy_blacklist_navigation_throttle.cc b/components/policy/content/policy_blacklist_navigation_throttle.cc
new file mode 100644
index 0000000..d53091d3
--- /dev/null
+++ b/components/policy/content/policy_blacklist_navigation_throttle.cc
@@ -0,0 +1,80 @@
+// 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/policy/content/policy_blacklist_navigation_throttle.h"
+
+#include "components/keyed_service/content/browser_context_dependency_manager.h"
+#include "components/user_prefs/user_prefs.h"
+#include "content/public/browser/browser_context.h"
+#include "content/public/browser/navigation_handle.h"
+
+PolicyBlacklistService::PolicyBlacklistService(
+    std::unique_ptr<policy::URLBlacklistManager> url_blacklist_manager)
+    : url_blacklist_manager_(std::move(url_blacklist_manager)) {}
+
+PolicyBlacklistService::~PolicyBlacklistService() {}
+
+bool PolicyBlacklistService::IsURLBlocked(const GURL& url) const {
+  return url_blacklist_manager_->IsURLBlocked(url);
+}
+
+policy::URLBlacklist::URLBlacklistState
+PolicyBlacklistService::GetURLBlacklistState(const GURL& url) const {
+  return url_blacklist_manager_->GetURLBlacklistState(url);
+}
+
+// static
+PolicyBlacklistFactory* PolicyBlacklistFactory::GetInstance() {
+  return base::Singleton<PolicyBlacklistFactory>::get();
+}
+
+// static
+PolicyBlacklistService* PolicyBlacklistFactory::GetForProfile(
+    content::BrowserContext* context) {
+  return static_cast<PolicyBlacklistService*>(
+      GetInstance()->GetServiceForBrowserContext(context, true));
+}
+
+PolicyBlacklistFactory::PolicyBlacklistFactory()
+    : BrowserContextKeyedServiceFactory(
+          "PolicyBlacklist",
+          BrowserContextDependencyManager::GetInstance()) {}
+
+PolicyBlacklistFactory::~PolicyBlacklistFactory() {}
+
+void PolicyBlacklistFactory::SetBlacklistOverride(
+    policy::URLBlacklistManager::OverrideBlacklistCallback callback) {
+  override_blacklist_ = callback;
+}
+
+KeyedService* PolicyBlacklistFactory::BuildServiceInstanceFor(
+    content::BrowserContext* context) const {
+  PrefService* pref_service = user_prefs::UserPrefs::Get(context);
+  auto url_blacklist_manager = std::make_unique<policy::URLBlacklistManager>(
+      pref_service, override_blacklist_);
+  return new PolicyBlacklistService(std::move(url_blacklist_manager));
+}
+
+PolicyBlacklistNavigationThrottle::PolicyBlacklistNavigationThrottle(
+    content::NavigationHandle* navigation_handle,
+    content::BrowserContext* context)
+    : NavigationThrottle(navigation_handle) {
+  blacklist_service_ = PolicyBlacklistFactory::GetForProfile(context);
+}
+
+PolicyBlacklistNavigationThrottle::~PolicyBlacklistNavigationThrottle() {}
+
+content::NavigationThrottle::ThrottleCheckResult
+PolicyBlacklistNavigationThrottle::WillStartRequest() {
+  if (blacklist_service_ &&
+      blacklist_service_->IsURLBlocked(navigation_handle()->GetURL())) {
+    return ThrottleCheckResult(BLOCK_REQUEST,
+                               net::ERR_BLOCKED_BY_ADMINISTRATOR);
+  }
+  return PROCEED;
+}
+
+const char* PolicyBlacklistNavigationThrottle::GetNameForLogging() {
+  return "PolicyBlacklistNavigationThrottle";
+}
diff --git a/components/policy/content/policy_blacklist_navigation_throttle.h b/components/policy/content/policy_blacklist_navigation_throttle.h
new file mode 100644
index 0000000..6ff6194b
--- /dev/null
+++ b/components/policy/content/policy_blacklist_navigation_throttle.h
@@ -0,0 +1,78 @@
+// 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_POLICY_CONTENT_POLICY_BLACKLIST_NAVIGATION_THROTTLE_H_
+#define COMPONENTS_POLICY_CONTENT_POLICY_BLACKLIST_NAVIGATION_THROTTLE_H_
+
+#include "base/memory/singleton.h"
+#include "components/keyed_service/content/browser_context_keyed_service_factory.h"
+#include "components/keyed_service/core/keyed_service.h"
+#include "components/policy/core/browser/url_blacklist_manager.h"
+#include "content/public/browser/navigation_throttle.h"
+
+// PolicyBlacklistService and PolicyBlacklistFactory provide a way for
+// us to access URLBlacklistManager, a policy block list service based on
+// the Preference Service. The URLBlacklistManager responses to permission
+// changes and is per Profile.  From the PolicyBlacklistNavigationThrottle,
+// we access this service to provide information about what we should block.
+class PolicyBlacklistService : public KeyedService {
+ public:
+  explicit PolicyBlacklistService(
+      std::unique_ptr<policy::URLBlacklistManager> url_blacklist_manager);
+  ~PolicyBlacklistService() override;
+
+  bool IsURLBlocked(const GURL& url) const;
+  policy::URLBlacklist::URLBlacklistState GetURLBlacklistState(
+      const GURL& url) const;
+
+ private:
+  std::unique_ptr<policy::URLBlacklistManager> url_blacklist_manager_;
+
+  DISALLOW_COPY_AND_ASSIGN(PolicyBlacklistService);
+};
+
+class PolicyBlacklistFactory : public BrowserContextKeyedServiceFactory {
+ public:
+  static PolicyBlacklistFactory* GetInstance();
+  static PolicyBlacklistService* GetForProfile(
+      content::BrowserContext* context);
+
+  // Sets the OverrideBlacklistCallback for the underlying URLBlacklistManager.
+  // Must be called before BuildServiceInstanceFor().
+  void SetBlacklistOverride(
+      policy::URLBlacklistManager::OverrideBlacklistCallback);
+
+ private:
+  PolicyBlacklistFactory();
+  ~PolicyBlacklistFactory() override;
+  friend struct base::DefaultSingletonTraits<PolicyBlacklistFactory>;
+
+  // BrowserContextKeyedServiceFactory implementation
+  KeyedService* BuildServiceInstanceFor(
+      content::BrowserContext* context) const override;
+
+  policy::URLBlacklistManager::OverrideBlacklistCallback override_blacklist_;
+
+  DISALLOW_COPY_AND_ASSIGN(PolicyBlacklistFactory);
+};
+
+// PolicyBlacklistNavigationThrottle provides a simple way to block a navigation
+// based on the URLBlacklistManager.
+class PolicyBlacklistNavigationThrottle : public content::NavigationThrottle {
+ public:
+  PolicyBlacklistNavigationThrottle(
+      content::NavigationHandle* navigation_handle,
+      content::BrowserContext* context);
+  ~PolicyBlacklistNavigationThrottle() override;
+
+  // NavigationThrottle overrides.
+  ThrottleCheckResult WillStartRequest() override;
+  const char* GetNameForLogging() override;
+
+ private:
+  PolicyBlacklistService* blacklist_service_;
+  DISALLOW_COPY_AND_ASSIGN(PolicyBlacklistNavigationThrottle);
+};
+
+#endif  // COMPONENTS_POLICY_CONTENT_POLICY_BLACKLIST_NAVIGATION_THROTTLE_H_
diff --git a/components/policy/core/browser/url_blacklist_manager.cc b/components/policy/core/browser/url_blacklist_manager.cc
index 21a2802..a892193 100644
--- a/components/policy/core/browser/url_blacklist_manager.cc
+++ b/components/policy/core/browser/url_blacklist_manager.cc
@@ -19,8 +19,8 @@
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_util.h"
 #include "base/task_runner_util.h"
-#include "base/threading/thread_task_runner_handle.h"
-#include "base/values.h"
+#include "base/task_scheduler/post_task.h"
+#include "base/threading/sequenced_task_runner_handle.h"
 #include "base/values.h"
 #include "components/policy/core/common/policy_pref_names.h"
 #include "components/pref_registry/pref_registry_syncable.h"
@@ -428,17 +428,17 @@
 
 URLBlacklistManager::URLBlacklistManager(
     PrefService* pref_service,
-    const scoped_refptr<base::SequencedTaskRunner>& background_task_runner,
-    const scoped_refptr<base::SequencedTaskRunner>& io_task_runner,
     OverrideBlacklistCallback override_blacklist)
     : pref_service_(pref_service),
-      background_task_runner_(background_task_runner),
-      io_task_runner_(io_task_runner),
       override_blacklist_(override_blacklist),
-      ui_task_runner_(base::ThreadTaskRunnerHandle::Get()),
       blacklist_(new URLBlacklist),
-      ui_weak_ptr_factory_(this),
-      io_weak_ptr_factory_(this) {
+      ui_weak_ptr_factory_(this) {
+  // This class assumes that it is created on the same thread that
+  // |pref_service_| lives on.
+  ui_task_runner_ = base::SequencedTaskRunnerHandle::Get();
+  background_task_runner_ = base::CreateSequencedTaskRunnerWithTraits(
+      {base::MayBlock(), base::TaskPriority::BACKGROUND});
+
   pref_change_registrar_.Init(pref_service_);
   base::Closure callback = base::Bind(&URLBlacklistManager::ScheduleUpdate,
                                       base::Unretained(this));
@@ -452,14 +452,9 @@
     Update();
 }
 
-void URLBlacklistManager::ShutdownOnUIThread() {
-  DCHECK(ui_task_runner_->RunsTasksInCurrentSequence());
-  // Cancel any pending updates, and stop listening for pref change updates.
-  ui_weak_ptr_factory_.InvalidateWeakPtrs();
-  pref_change_registrar_.RemoveAll();
-}
-
 URLBlacklistManager::~URLBlacklistManager() {
+  DCHECK(ui_task_runner_->RunsTasksInCurrentSequence());
+  pref_change_registrar_.RemoveAll();
 }
 
 void URLBlacklistManager::ScheduleUpdate() {
@@ -483,39 +478,24 @@
   std::unique_ptr<base::ListValue> allow(
       pref_service_->GetList(policy_prefs::kUrlWhitelist)->DeepCopy());
 
-  // Go through the IO thread to grab a WeakPtr to |this|. This is safe from
-  // here, since this task will always execute before a potential deletion of
-  // ProfileIOData on IO.
-  io_task_runner_->PostTask(FROM_HERE,
-                            base::Bind(&URLBlacklistManager::UpdateOnIO,
-                                       base::Unretained(this),
-                                       base::Passed(&block),
-                                       base::Passed(&allow)));
-}
-
-void URLBlacklistManager::UpdateOnIO(std::unique_ptr<base::ListValue> block,
-                                     std::unique_ptr<base::ListValue> allow) {
-  DCHECK(io_task_runner_->RunsTasksInCurrentSequence());
-  // The URLBlacklist is built on a worker thread. Once it's ready, it is passed
-  // to the URLBlacklistManager on IO.
+  // The URLBlacklist is built on a background task. Once it's ready, it is
+  // passed to the URLBlacklistManager on the same thread as the
+  // background_task_runner_.
   base::PostTaskAndReplyWithResult(
-      background_task_runner_.get(),
-      FROM_HERE,
-      base::Bind(&BuildBlacklist,
-                 base::Passed(&block),
-                 base::Passed(&allow)),
-      base::Bind(&URLBlacklistManager::SetBlacklist,
-                 io_weak_ptr_factory_.GetWeakPtr()));
+      background_task_runner_.get(), FROM_HERE,
+      base::BindOnce(&BuildBlacklist, std::move(block), std::move(allow)),
+      base::BindOnce(&URLBlacklistManager::SetBlacklist,
+                     ui_weak_ptr_factory_.GetWeakPtr()));
 }
 
 void URLBlacklistManager::SetBlacklist(
     std::unique_ptr<URLBlacklist> blacklist) {
-  DCHECK(io_task_runner_->RunsTasksInCurrentSequence());
+  DCHECK(ui_task_runner_->RunsTasksInCurrentSequence());
   blacklist_ = std::move(blacklist);
 }
 
 bool URLBlacklistManager::IsURLBlocked(const GURL& url) const {
-  DCHECK(io_task_runner_->RunsTasksInCurrentSequence());
+  DCHECK(ui_task_runner_->RunsTasksInCurrentSequence());
   // Ignore blob scheme for two reasons:
   // 1) PlzNavigate uses it to deliver the response to the renderer.
   // 2) A whitelisted page can use blob URLs internally.
@@ -524,13 +504,13 @@
 
 URLBlacklist::URLBlacklistState URLBlacklistManager::GetURLBlacklistState(
     const GURL& url) const {
-  DCHECK(io_task_runner_->RunsTasksInCurrentSequence());
+  DCHECK(ui_task_runner_->RunsTasksInCurrentSequence());
   return blacklist_->GetURLBlacklistState(url);
 }
 
 bool URLBlacklistManager::ShouldBlockRequestForFrame(const GURL& url,
                                                      int* reason) const {
-  DCHECK(io_task_runner_->RunsTasksInCurrentSequence());
+  DCHECK(ui_task_runner_->RunsTasksInCurrentSequence());
 
   bool block = false;
   if (override_blacklist_.Run(url, &block, reason))
diff --git a/components/policy/core/browser/url_blacklist_manager.h b/components/policy/core/browser/url_blacklist_manager.h
index 6cebaa0c..d46e4e436 100644
--- a/components/policy/core/browser/url_blacklist_manager.h
+++ b/components/policy/core/browser/url_blacklist_manager.h
@@ -123,22 +123,6 @@
 };
 
 // Tracks the blacklist policies for a given profile, and updates it on changes.
-//
-// This class interacts with both the UI thread, where notifications of pref
-// changes are received from, and the IO thread, which owns it (in the
-// ProfileIOData) and checks for blacklisted URLs (from ChromeNetworkDelegate).
-//
-// It must be constructed on the UI thread, to set up |ui_weak_ptr_factory_| and
-// the prefs listeners.
-//
-// ShutdownOnUIThread must be called from UI before destruction, to release
-// the prefs listeners on the UI thread. This is done from ProfileIOData.
-//
-// Update tasks from the UI thread can post safely to the IO thread, since the
-// destruction order of Profile and ProfileIOData guarantees that if this
-// exists in UI, then a potential destruction on IO will come after any task
-// posted to IO from that method on UI. This is used to go through IO before
-// the actual update starts, and grab a WeakPtr.
 class POLICY_EXPORT URLBlacklistManager {
  public:
   // Returns true if the blacklist should be overridden for |url| and sets
@@ -148,21 +132,11 @@
       OverrideBlacklistCallback;
 
   // Must be constructed on the UI thread.
-  // |background_task_runner| is used to build the blacklist in a background
-  // thread.
-  // |io_task_runner| must be backed by the IO thread.
-  URLBlacklistManager(
-      PrefService* pref_service,
-      const scoped_refptr<base::SequencedTaskRunner>& background_task_runner,
-      const scoped_refptr<base::SequencedTaskRunner>& io_task_runner,
-      OverrideBlacklistCallback override_blacklist);
+  URLBlacklistManager(PrefService* pref_service,
+                      OverrideBlacklistCallback override_blacklist);
   virtual ~URLBlacklistManager();
 
-  // Must be called on the UI thread, before destruction.
-  void ShutdownOnUIThread();
-
-  // Returns true if |url| is blocked by the current blacklist. Must be called
-  // from the IO thread.
+  // Returns true if |url| is blocked by the current blacklist.
   bool IsURLBlocked(const GURL& url) const;
 
   URLBlacklist::URLBlacklistState GetURLBlacklistState(const GURL& url) const;
@@ -176,10 +150,9 @@
   //
   // |reason| is populated with the exact reason for blocking the url if and
   // only if the return value is true otherwise it is left untouched.
-  // Must be called from the IO thread.
   bool ShouldBlockRequestForFrame(const GURL& url, int* reason) const;
 
-  // Replaces the current blacklist. Must be called on the IO thread.
+  // Replaces the current blacklist.
   // Virtual for testing.
   virtual void SetBlacklist(std::unique_ptr<URLBlacklist> blacklist);
 
@@ -195,16 +168,7 @@
   // Virtual for testing.
   virtual void Update();
 
-  // Starts the blacklist update on the IO thread, using the filters in
-  // |block| and |allow|. Protected for testing.
-  void UpdateOnIO(std::unique_ptr<base::ListValue> block,
-                  std::unique_ptr<base::ListValue> allow);
-
  private:
-  // ---------
-  // UI thread
-  // ---------
-
   // Used to track the policies and update the blacklist on changes.
   PrefChangeRegistrar pref_change_registrar_;
   PrefService* pref_service_;  // Weak.
@@ -212,17 +176,15 @@
   // Used to post tasks to a background thread.
   scoped_refptr<base::SequencedTaskRunner> background_task_runner_;
 
-  // Used to post tasks to the IO thread.
-  scoped_refptr<base::SequencedTaskRunner> io_task_runner_;
-
   // Used to optionally skip blacklisting for some URLs.
   OverrideBlacklistCallback override_blacklist_;
 
-  // ---------
-  // IO thread
-  // ---------
-
-  // Used to post tasks to the UI thread.
+  // Used to schedule tasks on the main loop to avoid rebuilding the blocklist
+  // multiple times during a message loop process. This can happen if two
+  // preferences that change the blacklist are updated in one message loop
+  // cycle.  In addition, we use this task runner to ensure that the
+  // URLBlocklistManager is only access from the thread call the constructor for
+  // data accesses.
   scoped_refptr<base::SequencedTaskRunner> ui_task_runner_;
 
   // The current blacklist.
@@ -231,9 +193,6 @@
   // Used to post update tasks to the UI thread.
   base::WeakPtrFactory<URLBlacklistManager> ui_weak_ptr_factory_;
 
-  // Used to get |weak_ptr_| to self on the IO thread.
-  base::WeakPtrFactory<URLBlacklistManager> io_weak_ptr_factory_;
-
   DISALLOW_COPY_AND_ASSIGN(URLBlacklistManager);
 };
 
diff --git a/components/policy/core/browser/url_blacklist_manager_unittest.cc b/components/policy/core/browser/url_blacklist_manager_unittest.cc
index 9b5f783..c1cfbb33 100644
--- a/components/policy/core/browser/url_blacklist_manager_unittest.cc
+++ b/components/policy/core/browser/url_blacklist_manager_unittest.cc
@@ -14,6 +14,7 @@
 #include "base/macros.h"
 #include "base/message_loop/message_loop.h"
 #include "base/run_loop.h"
+#include "base/test/scoped_task_environment.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "base/values.h"
 #include "components/policy/core/common/policy_pref_names.h"
@@ -38,8 +39,6 @@
  public:
   explicit TestingURLBlacklistManager(PrefService* pref_service)
       : URLBlacklistManager(pref_service,
-                            base::ThreadTaskRunnerHandle::Get(),
-                            base::ThreadTaskRunnerHandle::Get(),
                             base::Bind(OverrideBlacklistForURL)),
         update_called_(0),
         set_blacklist_called_(false) {}
@@ -49,14 +48,6 @@
   // Make this method public for testing.
   using URLBlacklistManager::ScheduleUpdate;
 
-  // Makes a direct call to UpdateOnIO during tests.
-  void UpdateOnIOForTesting() {
-    std::unique_ptr<base::ListValue> block(new base::ListValue);
-    block->AppendString("example.com");
-    std::unique_ptr<base::ListValue> allow(new base::ListValue);
-    URLBlacklistManager::UpdateOnIO(std::move(block), std::move(allow));
-  }
-
   // URLBlacklistManager overrides:
   void SetBlacklist(std::unique_ptr<URLBlacklist> blacklist) override {
     set_blacklist_called_ = true;
@@ -86,21 +77,19 @@
     pref_service_.registry()->RegisterListPref(policy_prefs::kUrlBlacklist);
     pref_service_.registry()->RegisterListPref(policy_prefs::kUrlWhitelist);
     blacklist_manager_.reset(new TestingURLBlacklistManager(&pref_service_));
-    base::RunLoop().RunUntilIdle();
+    scoped_task_environment_.RunUntilIdle();
   }
 
   void TearDown() override {
     if (blacklist_manager_.get())
-      blacklist_manager_->ShutdownOnUIThread();
-    base::RunLoop().RunUntilIdle();
-    // Delete |blacklist_manager_| while |io_thread_| is mapping IO to
-    // |loop_|.
+      scoped_task_environment_.RunUntilIdle();
     blacklist_manager_.reset();
   }
 
-  base::MessageLoopForIO loop_;
   TestingPrefServiceSimple pref_service_;
   std::unique_ptr<TestingURLBlacklistManager> blacklist_manager_;
+
+  base::test::ScopedTaskEnvironment scoped_task_environment_;
 };
 
 // Parameters for the FilterToComponents test.
@@ -227,10 +216,8 @@
   list->AppendString("example.com");
   pref_service_.SetManagedPref(policy_prefs::kUrlBlacklist, std::move(list));
   auto manager = base::MakeUnique<URLBlacklistManager>(
-      &pref_service_, base::ThreadTaskRunnerHandle::Get(),
-      base::ThreadTaskRunnerHandle::Get(),
-      URLBlacklistManager::OverrideBlacklistCallback());
-  base::RunLoop().RunUntilIdle();
+      &pref_service_, URLBlacklistManager::OverrideBlacklistCallback());
+  scoped_task_environment_.RunUntilIdle();
   EXPECT_EQ(URLBlacklist::URL_IN_BLACKLIST,
             manager->GetURLBlacklistState(GURL("http://example.com")));
 }
@@ -240,10 +227,8 @@
   list->AppendString("example.com");
   pref_service_.SetManagedPref(policy_prefs::kUrlWhitelist, std::move(list));
   auto manager = base::MakeUnique<URLBlacklistManager>(
-      &pref_service_, base::ThreadTaskRunnerHandle::Get(),
-      base::ThreadTaskRunnerHandle::Get(),
-      URLBlacklistManager::OverrideBlacklistCallback());
-  base::RunLoop().RunUntilIdle();
+      &pref_service_, URLBlacklistManager::OverrideBlacklistCallback());
+  scoped_task_environment_.RunUntilIdle();
   EXPECT_EQ(URLBlacklist::URL_IN_WHITELIST,
             manager->GetURLBlacklistState(GURL("http://example.com")));
 }
@@ -257,45 +242,11 @@
                                std::move(blacklist));
   pref_service_.SetManagedPref(policy_prefs::kUrlBlacklist,
                                std::move(whitelist));
-  base::RunLoop().RunUntilIdle();
+  scoped_task_environment_.RunUntilIdle();
 
   EXPECT_EQ(1, blacklist_manager_->update_called());
 }
 
-TEST_F(URLBlacklistManagerTest, ShutdownWithPendingTask0) {
-  // Post an update task to the UI thread.
-  blacklist_manager_->ScheduleUpdate();
-  // Shutdown comes before the task is executed.
-  blacklist_manager_->ShutdownOnUIThread();
-  blacklist_manager_.reset();
-  // Run the task after shutdown and deletion.
-  base::RunLoop().RunUntilIdle();
-}
-
-TEST_F(URLBlacklistManagerTest, ShutdownWithPendingTask1) {
-  // Post an update task.
-  blacklist_manager_->ScheduleUpdate();
-  // Shutdown comes before the task is executed.
-  blacklist_manager_->ShutdownOnUIThread();
-  // Run the task after shutdown, but before deletion.
-  base::RunLoop().RunUntilIdle();
-
-  EXPECT_EQ(0, blacklist_manager_->update_called());
-  blacklist_manager_.reset();
-  base::RunLoop().RunUntilIdle();
-}
-
-TEST_F(URLBlacklistManagerTest, ShutdownWithPendingTask2) {
-  // This posts a task to the FILE thread.
-  blacklist_manager_->UpdateOnIOForTesting();
-  // But shutdown happens before it is done.
-  blacklist_manager_->ShutdownOnUIThread();
-
-  EXPECT_FALSE(blacklist_manager_->set_blacklist_called());
-  blacklist_manager_.reset();
-  base::RunLoop().RunUntilIdle();
-}
-
 INSTANTIATE_TEST_CASE_P(
     URLBlacklistFilterToComponentsTestInstance,
     URLBlacklistFilterToComponentsTest,
diff --git a/components/previews/content/previews_io_data.cc b/components/previews/content/previews_io_data.cc
index e220c6a..7980750e1 100644
--- a/components/previews/content/previews_io_data.cc
+++ b/components/previews/content/previews_io_data.cc
@@ -18,6 +18,7 @@
 #include "components/previews/content/previews_ui_service.h"
 #include "components/previews/core/previews_experiments.h"
 #include "components/previews/core/previews_opt_out_store.h"
+#include "components/previews/core/previews_user_data.h"
 #include "net/base/load_flags.h"
 #include "net/nqe/network_quality_estimator.h"
 #include "net/url_request/url_request.h"
@@ -147,10 +148,12 @@
 void PreviewsIOData::LogPreviewNavigation(const GURL& url,
                                           bool opt_out,
                                           PreviewsType type,
-                                          base::Time time) const {
+                                          base::Time time,
+                                          uint64_t page_id) const {
   ui_task_runner_->PostTask(
-      FROM_HERE, base::Bind(&PreviewsUIService::LogPreviewNavigation,
-                            previews_ui_service_, url, type, opt_out, time));
+      FROM_HERE,
+      base::BindOnce(&PreviewsUIService::LogPreviewNavigation,
+                     previews_ui_service_, url, type, opt_out, time, page_id));
 }
 
 void PreviewsIOData::LogPreviewDecisionMade(
@@ -158,21 +161,23 @@
     const GURL& url,
     base::Time time,
     PreviewsType type,
-    std::vector<PreviewsEligibilityReason>&& passed_reasons) const {
+    std::vector<PreviewsEligibilityReason>&& passed_reasons,
+    uint64_t page_id) const {
   LogPreviewsEligibilityReason(reason, type);
   ui_task_runner_->PostTask(
       FROM_HERE, base::Bind(&PreviewsUIService::LogPreviewDecisionMade,
                             previews_ui_service_, reason, url, time, type,
-                            base::Passed(std::move(passed_reasons))));
+                            base::Passed(std::move(passed_reasons)), page_id));
 }
 
 void PreviewsIOData::AddPreviewNavigation(const GURL& url,
                                           bool opt_out,
-                                          PreviewsType type) {
+                                          PreviewsType type,
+                                          uint64_t page_id) {
   DCHECK(io_task_runner_->BelongsToCurrentThread());
   base::Time time =
       previews_black_list_->AddPreviewNavigation(url, opt_out, type);
-  LogPreviewNavigation(url, opt_out, type, time);
+  LogPreviewNavigation(url, opt_out, type, time, page_id);
 }
 
 void PreviewsIOData::ClearBlackList(base::Time begin_time,
@@ -209,10 +214,11 @@
   }
 
   std::vector<PreviewsEligibilityReason> passed_reasons;
+  uint64_t page_id = PreviewsUserData::GetData(request)->page_id();
   if (is_enabled_callback_.is_null() || !previews_black_list_) {
     LogPreviewDecisionMade(PreviewsEligibilityReason::BLACKLIST_UNAVAILABLE,
                            request.url(), base::Time::Now(), type,
-                           std::move(passed_reasons));
+                           std::move(passed_reasons), page_id);
     return false;
   }
   passed_reasons.push_back(PreviewsEligibilityReason::BLACKLIST_UNAVAILABLE);
@@ -227,7 +233,7 @@
         request.url(), type, &passed_reasons);
     if (status != PreviewsEligibilityReason::ALLOWED) {
       LogPreviewDecisionMade(status, request.url(), base::Time::Now(), type,
-                             std::move(passed_reasons));
+                             std::move(passed_reasons), page_id);
       return false;
     }
   }
@@ -241,7 +247,7 @@
             net::EFFECTIVE_CONNECTION_TYPE_OFFLINE) {
       LogPreviewDecisionMade(
           PreviewsEligibilityReason::NETWORK_QUALITY_UNAVAILABLE, request.url(),
-          base::Time::Now(), type, std::move(passed_reasons));
+          base::Time::Now(), type, std::move(passed_reasons), page_id);
       return false;
     }
     passed_reasons.push_back(
@@ -251,7 +257,7 @@
         effective_connection_type_threshold) {
       LogPreviewDecisionMade(PreviewsEligibilityReason::NETWORK_NOT_SLOW,
                              request.url(), base::Time::Now(), type,
-                             std::move(passed_reasons));
+                             std::move(passed_reasons), page_id);
       return false;
     }
     passed_reasons.push_back(PreviewsEligibilityReason::NETWORK_NOT_SLOW);
@@ -264,7 +270,7 @@
           (net::LOAD_VALIDATE_CACHE | net::LOAD_BYPASS_CACHE)) {
     LogPreviewDecisionMade(PreviewsEligibilityReason::RELOAD_DISALLOWED,
                            request.url(), base::Time::Now(), type,
-                           std::move(passed_reasons));
+                           std::move(passed_reasons), page_id);
     return false;
   }
   passed_reasons.push_back(PreviewsEligibilityReason::RELOAD_DISALLOWED);
@@ -276,7 +282,7 @@
       host_blacklist_from_server.end()) {
     LogPreviewDecisionMade(
         PreviewsEligibilityReason::HOST_BLACKLISTED_BY_SERVER, request.url(),
-        base::Time::Now(), type, std::move(passed_reasons));
+        base::Time::Now(), type, std::move(passed_reasons), page_id);
     return false;
   }
   passed_reasons.push_back(
@@ -290,7 +296,8 @@
           !previews_opt_guide_->IsWhitelisted(request, type)) {
         LogPreviewDecisionMade(
             PreviewsEligibilityReason::HOST_NOT_WHITELISTED_BY_SERVER,
-            request.url(), base::Time::Now(), type, std::move(passed_reasons));
+            request.url(), base::Time::Now(), type, std::move(passed_reasons),
+            page_id);
         return false;
       }
       passed_reasons.push_back(
@@ -300,13 +307,15 @@
       // but with qualified eligibility reason.
       LogPreviewDecisionMade(
           PreviewsEligibilityReason::ALLOWED_WITHOUT_OPTIMIZATION_HINTS,
-          request.url(), base::Time::Now(), type, std::move(passed_reasons));
+          request.url(), base::Time::Now(), type, std::move(passed_reasons),
+          page_id);
       return true;
     }
   }
 
   LogPreviewDecisionMade(PreviewsEligibilityReason::ALLOWED, request.url(),
-                         base::Time::Now(), type, std::move(passed_reasons));
+                         base::Time::Now(), type, std::move(passed_reasons),
+                         page_id);
   return true;
 }
 
diff --git a/components/previews/content/previews_io_data.h b/components/previews/content/previews_io_data.h
index d361c4fe..a1ce94df 100644
--- a/components/previews/content/previews_io_data.h
+++ b/components/previews/content/previews_io_data.h
@@ -65,20 +65,27 @@
   void LogPreviewNavigation(const GURL& url,
                             bool opt_out,
                             PreviewsType type,
-                            base::Time time) const;
+                            base::Time time,
+                            uint64_t page_id) const;
 
   // Adds log message of preview decision made asynchronously. |passed_reasons|
   // are PreviewsEligibilityReasons that got passed the decision before
-  // |reason|. The method takes ownership of |passed_reasons|.
+  // |reason|. The method takes ownership of |passed_reasons|. |page_id| is
+  // generated by PreviewsIOData, and used to group decisions into groups on the
+  // page, messages that don't need to be grouped can pass in 0 as page_id.
   void LogPreviewDecisionMade(
       PreviewsEligibilityReason reason,
       const GURL& url,
       base::Time time,
       PreviewsType type,
-      std::vector<PreviewsEligibilityReason>&& passed_reasons) const;
+      std::vector<PreviewsEligibilityReason>&& passed_reasons,
+      uint64_t page_id) const;
 
   // Adds a navigation to |url| to the black list with result |opt_out|.
-  void AddPreviewNavigation(const GURL& url, bool opt_out, PreviewsType type);
+  void AddPreviewNavigation(const GURL& url,
+                            bool opt_out,
+                            PreviewsType type,
+                            uint64_t page_id);
 
   // Clears the history of the black list between |begin_time| and |end_time|,
   // both inclusive.
diff --git a/components/previews/content/previews_io_data_unittest.cc b/components/previews/content/previews_io_data_unittest.cc
index c0e4040..b00298ad 100644
--- a/components/previews/content/previews_io_data_unittest.cc
+++ b/components/previews/content/previews_io_data_unittest.cc
@@ -33,6 +33,7 @@
 #include "components/previews/core/previews_features.h"
 #include "components/previews/core/previews_logger.h"
 #include "components/previews/core/previews_opt_out_store.h"
+#include "components/previews/core/previews_user_data.h"
 #include "components/variations/variations_associated_data.h"
 #include "net/base/load_flags.h"
 #include "net/nqe/effective_connection_type.h"
@@ -48,6 +49,9 @@
 
 namespace {
 
+// A fake default page_id for testing.
+const uint64_t kDefaultPageId = 123456;
+
 // This method simulates the actual behavior of the passed in callback, which is
 // validated in other tests. For simplicity, offline, lite page, and server LoFi
 // use the offline previews check. Client LoFi uses a seperate check to verify
@@ -172,11 +176,11 @@
   const std::vector<base::Time>& decision_times() const {
     return decision_times_;
   }
-
   const std::vector<std::vector<PreviewsEligibilityReason>>&
   decision_passed_reasons() const {
     return decision_passed_reasons_;
   }
+  const std::vector<uint64_t>& decision_ids() const { return decision_ids_; }
 
   // Expose passed in LogPreviewsNavigation parameters.
   const std::vector<GURL>& navigation_urls() const { return navigation_urls_; }
@@ -189,6 +193,9 @@
   const std::vector<PreviewsType>& navigation_types() const {
     return navigation_types_;
   }
+  const std::vector<uint64_t>& navigation_page_ids() const {
+    return navigation_page_ids_;
+  }
 
   // Expose passed in params for hosts and user blacklist event.
   std::string host_blacklisted() const { return host_blacklisted_; }
@@ -204,11 +211,13 @@
   void LogPreviewNavigation(const GURL& url,
                             PreviewsType type,
                             bool opt_out,
-                            base::Time time) override {
+                            base::Time time,
+                            uint64_t page_id) override {
     navigation_urls_.push_back(url);
     navigation_opt_outs_.push_back(opt_out);
     navigation_types_.push_back(type);
     navigation_times_.push_back(time);
+    navigation_page_ids_.push_back(page_id);
   }
 
   void LogPreviewDecisionMade(
@@ -216,12 +225,14 @@
       const GURL& url,
       base::Time time,
       PreviewsType type,
-      std::vector<PreviewsEligibilityReason>&& passed_reasons) override {
+      std::vector<PreviewsEligibilityReason>&& passed_reasons,
+      uint64_t page_id) override {
     decision_reasons_.push_back(reason);
     decision_urls_.push_back(GURL(url));
     decision_times_.push_back(time);
     decision_types_.push_back(type);
     decision_passed_reasons_.push_back(std::move(passed_reasons));
+    decision_ids_.push_back(page_id);
   }
 
   // Passed in params for blacklist status events.
@@ -236,12 +247,14 @@
   std::vector<PreviewsType> decision_types_;
   std::vector<base::Time> decision_times_;
   std::vector<std::vector<PreviewsEligibilityReason>> decision_passed_reasons_;
+  std::vector<uint64_t> decision_ids_;
 
   // Passed in LogPreviewsNavigation parameters.
   std::vector<GURL> navigation_urls_;
   std::vector<bool> navigation_opt_outs_;
   std::vector<base::Time> navigation_times_;
   std::vector<PreviewsType> navigation_types_;
+  std::vector<uint64_t> navigation_page_ids_;
 
   // Whether the blacklist decisions are ignored or not.
   bool blacklist_ignored_;
@@ -350,16 +363,22 @@
   }
 
   std::unique_ptr<net::URLRequest> CreateRequest() const {
-    return CreateRequestWithURL(GURL("http://example.com"));
+    std::unique_ptr<net::URLRequest> request =
+        CreateRequestWithURL(GURL("http://example.com"));
+    return request;
   }
 
   std::unique_ptr<net::URLRequest> CreateHttpsRequest() const {
-    return CreateRequestWithURL(GURL("https://secure.example.com"));
+    std::unique_ptr<net::URLRequest> request =
+        CreateRequestWithURL(GURL("https://secure.example.com"));
+    return request;
   }
 
   std::unique_ptr<net::URLRequest> CreateRequestWithURL(const GURL& url) const {
-    return context_.CreateRequest(url, net::DEFAULT_PRIORITY, nullptr,
-                                  TRAFFIC_ANNOTATION_FOR_TESTS);
+    std::unique_ptr<net::URLRequest> request = context_.CreateRequest(
+        url, net::DEFAULT_PRIORITY, nullptr, TRAFFIC_ANNOTATION_FOR_TESTS);
+    PreviewsUserData::Create(request.get(), kDefaultPageId);
+    return request;
   }
 
   TestPreviewsIOData* io_data() { return &io_data_; }
@@ -651,6 +670,7 @@
     std::unique_ptr<net::URLRequest> request =
         context()->CreateRequest(GURL(test.url), net::DEFAULT_PRIORITY, nullptr,
                                  TRAFFIC_ANNOTATION_FOR_TESTS);
+    PreviewsUserData::Create(request.get(), 54321 /* page_id, not used */);
 
     EXPECT_EQ(test.expected_client_lofi_allowed,
               io_data()->ShouldAllowPreviewAtECT(
@@ -744,12 +764,13 @@
 
 TEST_F(PreviewsIODataTest, LogPreviewNavigationPassInCorrectParams) {
   InitializeUIService();
-  GURL url("http://www.url_a.com/url_a");
-  bool opt_out = true;
-  PreviewsType type = PreviewsType::OFFLINE;
-  base::Time time = base::Time::Now();
+  const GURL url("http://www.url_a.com/url_a");
+  const bool opt_out = true;
+  const PreviewsType type = PreviewsType::OFFLINE;
+  const base::Time time = base::Time::Now();
+  const uint64_t page_id = 1234;
 
-  io_data()->LogPreviewNavigation(url, opt_out, type, time);
+  io_data()->LogPreviewNavigation(url, opt_out, type, time, page_id);
   base::RunLoop().RunUntilIdle();
 
   EXPECT_THAT(ui_service()->navigation_urls(), ::testing::ElementsAre(url));
@@ -757,15 +778,17 @@
               ::testing::ElementsAre(opt_out));
   EXPECT_THAT(ui_service()->navigation_types(), ::testing::ElementsAre(type));
   EXPECT_THAT(ui_service()->navigation_times(), ::testing::ElementsAre(time));
+  EXPECT_THAT(ui_service()->navigation_page_ids(),
+              ::testing::ElementsAre(page_id));
 }
 
 TEST_F(PreviewsIODataTest, LogPreviewDecisionMadePassInCorrectParams) {
   InitializeUIService();
-  PreviewsEligibilityReason reason(
+  const PreviewsEligibilityReason reason(
       PreviewsEligibilityReason::BLACKLIST_UNAVAILABLE);
-  GURL url("http://www.url_a.com/url_a");
-  base::Time time = base::Time::Now();
-  PreviewsType type = PreviewsType::OFFLINE;
+  const GURL url("http://www.url_a.com/url_a");
+  const base::Time time = base::Time::Now();
+  const PreviewsType type = PreviewsType::OFFLINE;
   std::vector<PreviewsEligibilityReason> passed_reasons = {
       PreviewsEligibilityReason::NETWORK_NOT_SLOW,
       PreviewsEligibilityReason::USER_RECENTLY_OPTED_OUT,
@@ -773,15 +796,17 @@
   };
   const std::vector<PreviewsEligibilityReason> expected_passed_reasons(
       passed_reasons);
+  const uint64_t page_id = 1234;
 
   io_data()->LogPreviewDecisionMade(reason, url, time, type,
-                                    std::move(passed_reasons));
+                                    std::move(passed_reasons), page_id);
   base::RunLoop().RunUntilIdle();
 
   EXPECT_THAT(ui_service()->decision_reasons(), ::testing::ElementsAre(reason));
   EXPECT_THAT(ui_service()->decision_urls(), ::testing::ElementsAre(url));
   EXPECT_THAT(ui_service()->decision_types(), ::testing::ElementsAre(type));
   EXPECT_THAT(ui_service()->decision_times(), ::testing::ElementsAre(time));
+  EXPECT_THAT(ui_service()->decision_ids(), ::testing::ElementsAre(page_id));
 
   auto actual_passed_reasons = ui_service()->decision_passed_reasons();
   EXPECT_EQ(1UL, actual_passed_reasons.size());
diff --git a/components/previews/content/previews_ui_service.cc b/components/previews/content/previews_ui_service.cc
index 3753aa1..d31dd5e 100644
--- a/components/previews/content/previews_ui_service.cc
+++ b/components/previews/content/previews_ui_service.cc
@@ -37,19 +37,21 @@
 
 void PreviewsUIService::AddPreviewNavigation(const GURL& url,
                                              PreviewsType type,
-                                             bool opt_out) {
+                                             bool opt_out,
+                                             uint64_t page_id) {
   DCHECK(thread_checker_.CalledOnValidThread());
   io_task_runner_->PostTask(
       FROM_HERE, base::Bind(&PreviewsIOData::AddPreviewNavigation, io_data_,
-                            url, opt_out, type));
+                            url, opt_out, type, page_id));
 }
 
 void PreviewsUIService::LogPreviewNavigation(const GURL& url,
                                              PreviewsType type,
                                              bool opt_out,
-                                             base::Time time) {
+                                             base::Time time,
+                                             uint64_t page_id) {
   DCHECK(thread_checker_.CalledOnValidThread());
-  logger_->LogPreviewNavigation(url, type, opt_out, time);
+  logger_->LogPreviewNavigation(url, type, opt_out, time, page_id);
 }
 
 void PreviewsUIService::LogPreviewDecisionMade(
@@ -57,10 +59,11 @@
     const GURL& url,
     base::Time time,
     PreviewsType type,
-    std::vector<PreviewsEligibilityReason>&& passed_reasons) {
+    std::vector<PreviewsEligibilityReason>&& passed_reasons,
+    uint64_t page_id) {
   DCHECK(thread_checker_.CalledOnValidThread());
   logger_->LogPreviewDecisionMade(reason, url, time, type,
-                                  std::move(passed_reasons));
+                                  std::move(passed_reasons), page_id);
 }
 
 void PreviewsUIService::OnNewBlacklistedHost(const std::string& host,
diff --git a/components/previews/content/previews_ui_service.h b/components/previews/content/previews_ui_service.h
index 7215ec2..44f356c 100644
--- a/components/previews/content/previews_ui_service.h
+++ b/components/previews/content/previews_ui_service.h
@@ -46,7 +46,10 @@
   virtual void SetIOData(base::WeakPtr<PreviewsIOData> io_data);
 
   // Adds a navigation to |url| to the black list with result |opt_out|.
-  void AddPreviewNavigation(const GURL& url, PreviewsType type, bool opt_out);
+  void AddPreviewNavigation(const GURL& url,
+                            PreviewsType type,
+                            bool opt_out,
+                            uint64_t page_id);
 
   // Clears the history of the black list between |begin_time| and |end_time|.
   void ClearBlackList(base::Time begin_time, base::Time end_time);
@@ -79,17 +82,22 @@
   virtual void LogPreviewNavigation(const GURL& url,
                                     PreviewsType type,
                                     bool opt_out,
-                                    base::Time time);
+                                    base::Time time,
+                                    uint64_t page_id);
 
   // Log the made decision of previews to PreviewsLogger. |passed_reasons| is a
   // collection of PreviewsEligibilityReasons passed the checks before |reason|.
-  // The method takes ownership of |passed_reasons|. Virtualized in testing.
+  // The method takes ownership of |passed_reasons|. |page_id| is generated by
+  // PreviewsIOData, and used to group decisions into groups on the page,
+  // messages that don't need to be grouped can pass in 0 as page_id.
+  // Virtualized in testing.
   virtual void LogPreviewDecisionMade(
       PreviewsEligibilityReason reason,
       const GURL& url,
       base::Time time,
       PreviewsType type,
-      std::vector<PreviewsEligibilityReason>&& passed_reasons);
+      std::vector<PreviewsEligibilityReason>&& passed_reasons,
+      uint64_t page_id);
 
   // Expose the pointer to PreviewsLogger to extract logging messages. This
   // pointer's life time is the same as of |this|, and it is guaranteed to not
diff --git a/components/previews/content/previews_ui_service_unittest.cc b/components/previews/content/previews_ui_service_unittest.cc
index 87082be..82fd127 100644
--- a/components/previews/content/previews_ui_service_unittest.cc
+++ b/components/previews/content/previews_ui_service_unittest.cc
@@ -56,7 +56,8 @@
 class TestPreviewsLogger : public PreviewsLogger {
  public:
   TestPreviewsLogger()
-      : navigation_opt_out_(false),
+      : decision_page_id_(0),
+        navigation_opt_out_(false),
         user_blacklisted_(false),
         blacklist_ignored_(false) {}
 
@@ -64,11 +65,13 @@
   void LogPreviewNavigation(const GURL& url,
                             PreviewsType type,
                             bool opt_out,
-                            base::Time time) override {
+                            base::Time time,
+                            uint64_t page_id) override {
     navigation_url_ = url;
     navigation_opt_out_ = opt_out;
     navigation_type_ = type;
     navigation_time_ = base::Time(time);
+    navigation_page_id_ = page_id;
   }
 
   void LogPreviewDecisionMade(
@@ -76,12 +79,14 @@
       const GURL& url,
       base::Time time,
       PreviewsType type,
-      std::vector<PreviewsEligibilityReason>&& passed_reasons) override {
+      std::vector<PreviewsEligibilityReason>&& passed_reasons,
+      uint64_t page_id) override {
     decision_reason_ = reason;
     decision_url_ = GURL(url);
     decision_time_ = time;
     decision_type_ = type;
     decision_passed_reasons_ = std::move(passed_reasons);
+    decision_page_id_ = page_id;
   }
 
   void OnNewBlacklistedHost(const std::string& host, base::Time time) override {
@@ -110,12 +115,14 @@
       const {
     return decision_passed_reasons_;
   }
+  uint64_t decision_page_id() const { return decision_page_id_; }
 
   // Return the passed in LogPreviewNavigation parameters.
   GURL navigation_url() const { return navigation_url_; }
   bool navigation_opt_out() const { return navigation_opt_out_; }
   base::Time navigation_time() const { return navigation_time_; }
   PreviewsType navigation_type() const { return navigation_type_; }
+  uint64_t navigation_page_id() const { return navigation_page_id_; }
 
   // Return the passed in OnBlacklist events.
   std::string host_blacklisted() const { return host_blacklisted_; }
@@ -133,12 +140,14 @@
   PreviewsType decision_type_;
   base::Time decision_time_;
   std::vector<PreviewsEligibilityReason> decision_passed_reasons_;
+  uint64_t decision_page_id_;
 
   // Passed in LogPreviewsNavigation parameters.
   GURL navigation_url_;
   bool navigation_opt_out_;
   base::Time navigation_time_;
   PreviewsType navigation_type_;
+  uint64_t navigation_page_id_;
 
   // Passed in OnBlacklist events.
   std::string host_blacklisted_;
@@ -216,28 +225,34 @@
 
 TEST_F(PreviewsUIServiceTest, TestLogPreviewNavigationPassInCorrectParams) {
   const GURL url_a = GURL("http://www.url_a.com/url_a");
-  PreviewsType type_a = PreviewsType::LOFI;
-  bool opt_out_a = true;
-  base::Time time_a = base::Time::Now();
+  const PreviewsType type_a = PreviewsType::LOFI;
+  const bool opt_out_a = true;
+  const base::Time time_a = base::Time::Now();
+  const uint64_t page_id_a = 1234;
 
-  ui_service()->LogPreviewNavigation(url_a, type_a, opt_out_a, time_a);
+  ui_service()->LogPreviewNavigation(url_a, type_a, opt_out_a, time_a,
+                                     page_id_a);
 
   EXPECT_EQ(url_a, logger_ptr_->navigation_url());
   EXPECT_EQ(type_a, logger_ptr_->navigation_type());
   EXPECT_EQ(opt_out_a, logger_ptr_->navigation_opt_out());
   EXPECT_EQ(time_a, logger_ptr_->navigation_time());
+  EXPECT_EQ(page_id_a, logger_ptr_->navigation_page_id());
 
   const GURL url_b = GURL("http://www.url_b.com/url_b");
-  PreviewsType type_b = PreviewsType::OFFLINE;
-  bool opt_out_b = false;
-  base::Time time_b = base::Time::Now();
+  const PreviewsType type_b = PreviewsType::OFFLINE;
+  const bool opt_out_b = false;
+  const base::Time time_b = base::Time::Now();
+  const uint64_t page_id_b = 4321;
 
-  ui_service()->LogPreviewNavigation(url_b, type_b, opt_out_b, time_b);
+  ui_service()->LogPreviewNavigation(url_b, type_b, opt_out_b, time_b,
+                                     page_id_b);
 
   EXPECT_EQ(url_b, logger_ptr_->navigation_url());
   EXPECT_EQ(type_b, logger_ptr_->navigation_type());
   EXPECT_EQ(opt_out_b, logger_ptr_->navigation_opt_out());
   EXPECT_EQ(time_b, logger_ptr_->navigation_time());
+  EXPECT_EQ(page_id_b, logger_ptr_->navigation_page_id());
 }
 
 TEST_F(PreviewsUIServiceTest, TestLogPreviewDecisionMadePassesCorrectParams) {
@@ -253,14 +268,17 @@
   };
   const std::vector<PreviewsEligibilityReason> expected_passed_reasons_a(
       passed_reasons_a);
+  const uint64_t page_id_a = 1234;
 
   ui_service()->LogPreviewDecisionMade(reason_a, url_a, time_a, type_a,
-                                       std::move(passed_reasons_a));
+                                       std::move(passed_reasons_a), page_id_a);
 
   EXPECT_EQ(reason_a, logger_ptr_->decision_reason());
   EXPECT_EQ(url_a, logger_ptr_->decision_url());
   EXPECT_EQ(time_a, logger_ptr_->decision_time());
   EXPECT_EQ(type_a, logger_ptr_->decision_type());
+  EXPECT_EQ(expected_passed_reasons_a, logger_ptr_->decision_passed_reasons());
+  EXPECT_EQ(page_id_a, logger_ptr_->decision_page_id());
 
   auto actual_passed_reasons_a = logger_ptr_->decision_passed_reasons();
   EXPECT_EQ(3UL, actual_passed_reasons_a.size());
@@ -279,14 +297,16 @@
   };
   const std::vector<PreviewsEligibilityReason> expected_passed_reasons_b(
       passed_reasons_b);
+  const uint64_t page_id_b = 4321;
 
   ui_service()->LogPreviewDecisionMade(reason_b, url_b, time_b, type_b,
-                                       std::move(passed_reasons_b));
+                                       std::move(passed_reasons_b), page_id_b);
 
   EXPECT_EQ(reason_b, logger_ptr_->decision_reason());
   EXPECT_EQ(url_b, logger_ptr_->decision_url());
   EXPECT_EQ(type_b, logger_ptr_->decision_type());
   EXPECT_EQ(time_b, logger_ptr_->decision_time());
+  EXPECT_EQ(page_id_b, logger_ptr_->decision_page_id());
 
   auto actual_passed_reasons_b = logger_ptr_->decision_passed_reasons();
   EXPECT_EQ(2UL, actual_passed_reasons_b.size());
diff --git a/components/previews/core/previews_amp_converter.cc b/components/previews/core/previews_amp_converter.cc
index 30b6f9c..2465d11 100644
--- a/components/previews/core/previews_amp_converter.cc
+++ b/components/previews/core/previews_amp_converter.cc
@@ -11,6 +11,7 @@
 #include "base/memory/ptr_util.h"
 #include "base/metrics/field_trial.h"
 #include "base/metrics/field_trial_params.h"
+#include "base/strings/strcat.h"
 #include "base/strings/string_util.h"
 #include "base/values.h"
 #include "components/previews/core/previews_features.h"
@@ -165,7 +166,7 @@
   if (!entry.prefix.empty() || !entry.suffix.empty() ||
       !entry.suffix_html.empty()) {
     DCHECK(entry.prefix.empty() || entry.prefix[0] == '/');
-    path = base::JoinString({entry.prefix, url.path(), entry.suffix}, "");
+    path = base::StrCat({entry.prefix, url.path(), entry.suffix});
     if (!entry.suffix_html.empty() &&
         base::EndsWith(path, ".html", base::CompareCase::SENSITIVE)) {
       // Insert suffix_html before the .html extension.
diff --git a/components/previews/core/previews_logger.cc b/components/previews/core/previews_logger.cc
index 01a52db..f1520e2 100644
--- a/components/previews/core/previews_logger.cc
+++ b/components/previews/core/previews_logger.cc
@@ -86,17 +86,20 @@
 PreviewsLogger::MessageLog::MessageLog(const std::string& event_type,
                                        const std::string& event_description,
                                        const GURL& url,
-                                       base::Time time)
+                                       base::Time time,
+                                       uint64_t page_id)
     : event_type(event_type),
       event_description(event_description),
       url(url),
-      time(time) {}
+      time(time),
+      page_id(page_id) {}
 
 PreviewsLogger::MessageLog::MessageLog(const MessageLog& other)
     : event_type(other.event_type),
       event_description(other.event_description),
       url(other.url),
-      time(other.time) {}
+      time(other.time),
+      page_id(other.page_id) {}
 
 PreviewsLogger::PreviewsLogger() : blacklist_ignored_(false) {}
 
@@ -153,24 +156,26 @@
 void PreviewsLogger::LogMessage(const std::string& event_type,
                                 const std::string& event_description,
                                 const GURL& url,
-                                base::Time time) {
+                                base::Time time,
+                                uint64_t page_id) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   // Notify observers about the new MessageLog.
   for (auto& observer : observer_list_) {
     observer.OnNewMessageLogAdded(
-        MessageLog(event_type, event_description, url, time));
+        MessageLog(event_type, event_description, url, time, page_id));
   }
 }
 
 void PreviewsLogger::LogPreviewNavigation(const GURL& url,
                                           PreviewsType type,
                                           bool opt_out,
-                                          base::Time time) {
+                                          base::Time time,
+                                          uint64_t page_id) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   DCHECK_GE(kMaximumNavigationLogs, navigations_logs_.size());
 
   std::string description = GetDescriptionForPreviewsNavigation(type, opt_out);
-  LogMessage(kPreviewNavigationEventType, description, url, time);
+  LogMessage(kPreviewNavigationEventType, description, url, time, page_id);
 
   // Pop out the oldest message when the list is full.
   if (navigations_logs_.size() >= kMaximumNavigationLogs) {
@@ -178,7 +183,7 @@
   }
 
   navigations_logs_.emplace_back(kPreviewNavigationEventType, description, url,
-                                 time);
+                                 time, page_id);
 }
 
 void PreviewsLogger::LogPreviewDecisionMade(
@@ -186,7 +191,8 @@
     const GURL& url,
     base::Time time,
     PreviewsType type,
-    std::vector<PreviewsEligibilityReason>&& passed_reasons) {
+    std::vector<PreviewsEligibilityReason>&& passed_reasons,
+    uint64_t page_id) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   DCHECK_GE(kMaximumDecisionLogs, decisions_logs_.size());
 
@@ -194,14 +200,15 @@
   for (auto decision : passed_reasons) {
     std::string decision_description = GetDescriptionForPreviewsDecision(
         decision, type, false /* final_reason */);
-    LogMessage(kPreviewDecisionMadeEventType, decision_description, url, time);
+    LogMessage(kPreviewDecisionMadeEventType, decision_description, url, time,
+               page_id);
     decisions_logs_.emplace_back(kPreviewDecisionMadeEventType,
-                                 decision_description, url, time);
+                                 decision_description, url, time, page_id);
   }
 
   std::string description =
       GetDescriptionForPreviewsDecision(reason, type, true /* final_reason */);
-  LogMessage(kPreviewDecisionMadeEventType, description, url, time);
+  LogMessage(kPreviewDecisionMadeEventType, description, url, time, page_id);
 
   // Pop out the older messages when the list is full.
   while (decisions_logs_.size() >= kMaximumDecisionLogs) {
@@ -209,7 +216,7 @@
   }
 
   decisions_logs_.emplace_back(kPreviewDecisionMadeEventType, description, url,
-                               time);
+                               time, page_id);
 }
 
 void PreviewsLogger::OnNewBlacklistedHost(const std::string& host,
diff --git a/components/previews/core/previews_logger.h b/components/previews/core/previews_logger.h
index 03b033b..d94273d 100644
--- a/components/previews/core/previews_logger.h
+++ b/components/previews/core/previews_logger.h
@@ -38,7 +38,8 @@
     MessageLog(const std::string& event_type,
                const std::string& event_description,
                const GURL& url,
-               base::Time time);
+               base::Time time,
+               uint64_t page_id);
 
     MessageLog(const MessageLog& other);
 
@@ -53,6 +54,9 @@
 
     // The time of when the event happened.
     const base::Time time;
+
+    // The ID associated with the request.
+    const uint64_t page_id;
   };
 
   PreviewsLogger();
@@ -68,29 +72,36 @@
 
   // Add MessageLog using the given information. Pop out the oldest log if the
   // size of |log_messages_| grows larger than a threshold. Virtualized in
-  // testing.
+  // testing. |page_id| generated by PreviewsIOData, used for grouping log
+  // messages together, messages that don't need to be grouped can pass in 0 as
+  // page_id.
   virtual void LogMessage(const std::string& event_type,
                           const std::string& event_description,
                           const GURL& url,
-                          base::Time time);
+                          base::Time time,
+                          uint64_t page_id);
 
   // Convert |navigation| to a MessageLog, and add that message to
   // |log_messages_|. Virtualized in testing.
   virtual void LogPreviewNavigation(const GURL& url,
                                     PreviewsType type,
                                     bool opt_out,
-                                    base::Time time);
+                                    base::Time time,
+                                    uint64_t page_id);
 
   // Add a MessageLog for the a decision that was made about the state of
   // previews and blacklist. |passed_reasons| is an ordered list of
   // PreviewsEligibilityReasons that got pass the decision. The method takes
-  // ownership of |passed_reasons|. Virtualized in testing.
+  // ownership of |passed_reasons|. |page_id| generated by PreviewsIOData, used
+  // for grouping log messages together, messages that don't need to be grouped
+  // can pass in 0 as page_id. Virtualized in testing.
   virtual void LogPreviewDecisionMade(
       PreviewsEligibilityReason reason,
       const GURL& url,
       base::Time time,
       PreviewsType type,
-      std::vector<PreviewsEligibilityReason>&& passed_reasons);
+      std::vector<PreviewsEligibilityReason>&& passed_reasons,
+      uint64_t page_id);
 
   // Notify observers that |host| is blacklisted at |time|. Virtualized in
   // testing.
diff --git a/components/previews/core/previews_logger_unittest.cc b/components/previews/core/previews_logger_unittest.cc
index 734f809d..8d31b9a4 100644
--- a/components/previews/core/previews_logger_unittest.cc
+++ b/components/previews/core/previews_logger_unittest.cc
@@ -122,16 +122,18 @@
     const base::Time time = base::Time::Now();
     PreviewsType type = PreviewsType::OFFLINE;
     const GURL url("http://www.url_a.com/url");
+    const uint64_t page_id = 1234;
     TestPreviewsLoggerObserver observer;
     logger_->AddAndNotifyObserver(&observer);
     if (final_reason) {
       std::vector<PreviewsEligibilityReason> passed_reasons = {};
       logger_->LogPreviewDecisionMade(reason, url, time, type,
-                                      std::move(passed_reasons));
+                                      std::move(passed_reasons), page_id);
     } else {
       std::vector<PreviewsEligibilityReason> passed_reasons = {reason};
       logger_->LogPreviewDecisionMade(PreviewsEligibilityReason::ALLOWED, url,
-                                      time, type, std::move(passed_reasons));
+                                      time, type, std::move(passed_reasons),
+                                      page_id);
     }
 
     auto actual = observer.messages();
@@ -165,14 +167,16 @@
   };
   const GURL url_a("http://www.url_a.com/url_a");
   const GURL url_b("http://www.url_b.com/url_b");
+  const uint64_t page_id_a = 1234;
+  const uint64_t page_id_b = 4321;
 
   TestPreviewsLoggerObserver observer;
   logger_->AddAndNotifyObserver(&observer);
 
   logger_->LogPreviewDecisionMade(reason_a, url_a, time, type_a,
-                                  std::move(passed_reasons_a));
+                                  std::move(passed_reasons_a), page_id_a);
   logger_->LogPreviewDecisionMade(reason_b, url_b, time, type_b,
-                                  std::move(passed_reasons_b));
+                                  std::move(passed_reasons_b), page_id_b);
 
   auto actual = observer.messages();
   const size_t expected_size = 4;  // reason_a, reason_b, and passed_reasons_b
@@ -184,24 +188,28 @@
   EXPECT_EQ(expected_description_a, actual[0].event_description);
   EXPECT_EQ(url_a, actual[0].url);
   EXPECT_EQ(time, actual[0].time);
+  EXPECT_EQ(page_id_a, actual[0].page_id);
 
   std::string expected_passed_0 = "LoFi preview - Network quality available";
   EXPECT_EQ(kPreviewsDecisionMadeEventType, actual[1].event_type);
   EXPECT_EQ(expected_passed_0, actual[1].event_description);
   EXPECT_EQ(url_b, actual[1].url);
   EXPECT_EQ(time, actual[1].time);
+  EXPECT_EQ(page_id_b, actual[1].page_id);
 
   std::string expected_passed_1 = "LoFi preview - Page reloads allowed";
   EXPECT_EQ(kPreviewsDecisionMadeEventType, actual[2].event_type);
   EXPECT_EQ(expected_passed_1, actual[2].event_description);
   EXPECT_EQ(url_b, actual[2].url);
   EXPECT_EQ(time, actual[2].time);
+  EXPECT_EQ(page_id_b, actual[2].page_id);
 
   std::string expected_description_b = "LoFi preview - Network not slow";
   EXPECT_EQ(kPreviewsDecisionMadeEventType, actual[3].event_type);
   EXPECT_EQ(expected_description_b, actual[3].event_description);
   EXPECT_EQ(url_b, actual[3].url);
   EXPECT_EQ(time, actual[3].time);
+  EXPECT_EQ(page_id_b, actual[3].page_id);
 }
 
 TEST_F(PreviewsLoggerTest, LogPreviewNavigationLogMessage) {
@@ -211,12 +219,16 @@
   PreviewsType type_b = PreviewsType::LOFI;
   const GURL url_a("http://www.url_a.com/url_a");
   const GURL url_b("http://www.url_b.com/url_b");
+  const uint64_t page_id_a = 1234;
+  const uint64_t page_id_b = 1234;
 
   TestPreviewsLoggerObserver observer;
   logger_->AddAndNotifyObserver(&observer);
 
-  logger_->LogPreviewNavigation(url_a, type_a, true /* opt_out */, time);
-  logger_->LogPreviewNavigation(url_b, type_b, false /* opt_out */, time);
+  logger_->LogPreviewNavigation(url_a, type_a, true /* opt_out */, time,
+                                page_id_a);
+  logger_->LogPreviewNavigation(url_b, type_b, false /* opt_out */, time,
+                                page_id_b);
 
   auto actual = observer.messages();
 
@@ -228,12 +240,14 @@
   EXPECT_EQ(expected_description_a, actual[0].event_description);
   EXPECT_EQ(url_a, actual[0].url);
   EXPECT_EQ(time, actual[0].time);
+  EXPECT_EQ(page_id_a, actual[0].page_id);
 
   std::string expected_description_b = "LoFi preview - user opt-out: False";
   EXPECT_EQ(kPreviewsNavigationEventType, actual[1].event_type);
   EXPECT_EQ(expected_description_b, actual[1].event_description);
   EXPECT_EQ(url_b, actual[1].url);
   EXPECT_EQ(time, actual[1].time);
+  EXPECT_EQ(page_id_b, actual[1].page_id);
 }
 
 TEST_F(PreviewsLoggerTest, PreviewsLoggerOnlyKeepsCertainNumberOfDecisionLogs) {
@@ -242,11 +256,12 @@
       PreviewsEligibilityReason::BLACKLIST_UNAVAILABLE;
   const base::Time time = base::Time::Now();
   const GURL url("http://www.url_.com/url_");
+  const uint64_t page_id = 1234;
 
   for (size_t i = 0; i < 2 * kMaximumDecisionLogs; i++) {
     std::vector<PreviewsEligibilityReason> passed_reasons = {};
     logger_->LogPreviewDecisionMade(reason, url, time, type,
-                                    std::move(passed_reasons));
+                                    std::move(passed_reasons), page_id);
   }
 
   TestPreviewsLoggerObserver observer;
@@ -259,9 +274,10 @@
   PreviewsType type = PreviewsType::OFFLINE;
   const GURL url("http://www.url_.com/url_");
   const base::Time time = base::Time::Now();
+  const uint64_t page_id = 1234;
 
   for (size_t i = 0; i < 2 * kMaximumNavigationLogs; ++i) {
-    logger_->LogPreviewNavigation(url, type, true /* opt_out */, time);
+    logger_->LogPreviewNavigation(url, type, true /* opt_out */, time, page_id);
   }
 
   TestPreviewsLoggerObserver observer;
@@ -273,7 +289,8 @@
        ObserverIsNotifiedOfHistoricalNavigationsAndDecisionsWhenAdded) {
   // Non historical log event.
   logger_->LogMessage("Event_", "Some description_",
-                      GURL("http://www.url_.com/url_"), base::Time::Now());
+                      GURL("http://www.url_.com/url_"), base::Time::Now(),
+                      1234 /* page_id */);
 
   PreviewsType type = PreviewsType::LOFI;
   PreviewsEligibilityReason final_reason =
@@ -290,11 +307,13 @@
       base::Time::FromJsTime(-413696806000),  // Same as above.
       base::Time::FromJsTime(758620800000),   // Jan 15 1994 08:00:00 UTC
   };
+  const uint64_t page_ids[] = {1233, 1233, 5678 /* Navigation page_id */};
 
   // Logging decisions and navigations events.
   logger_->LogPreviewDecisionMade(final_reason, urls[0], times[0], type,
-                                  std::move(passed_reasons));
-  logger_->LogPreviewNavigation(urls[2], type, true /* opt_out */, times[2]);
+                                  std::move(passed_reasons), page_ids[0]);
+  logger_->LogPreviewNavigation(urls[2], type, true /* opt_out */, times[2],
+                                page_ids[2]);
 
   TestPreviewsLoggerObserver observer;
   logger_->AddAndNotifyObserver(&observer);
@@ -314,6 +333,7 @@
     EXPECT_EQ(expected_types[i], received_messages[i].event_type);
     EXPECT_EQ(urls[i], received_messages[i].url);
     EXPECT_EQ(times[i], received_messages[i].time);
+    EXPECT_EQ(page_ids[i], received_messages[i].page_id);
   }
 }
 
@@ -325,11 +345,12 @@
     logger_->AddAndNotifyObserver(&observers[i]);
   }
 
-  std::string type = "Event_";
-  std::string description = "Some description";
-  GURL url("http://www.url_.com/url_");
-  base::Time now = base::Time::Now();
-  logger_->LogMessage(type, description, url, now);
+  const std::string type = "Event_";
+  const std::string description = "Some description";
+  const GURL url("http://www.url_.com/url_");
+  const base::Time now = base::Time::Now();
+  const uint64_t page_id = 1234;
+  logger_->LogMessage(type, description, url, now, page_id);
 
   const size_t expected_size = 1;
   for (size_t i = 0; i < number_of_obs; i++) {
@@ -338,6 +359,7 @@
     EXPECT_EQ(description, observers[i].message()->event_description);
     EXPECT_EQ(url, observers[i].message()->url);
     EXPECT_EQ(now, observers[i].message()->time);
+    EXPECT_EQ(page_id, observers[i].message()->page_id);
   }
 }
 
@@ -352,11 +374,12 @@
   const size_t removed_observer = 1;
   logger_->RemoveObserver(&observers[removed_observer]);
 
-  std::string type = "Event_";
-  std::string description = "Some description";
-  GURL url("http://www.url_.com/url_");
-  base::Time now = base::Time::Now();
-  logger_->LogMessage(type, description, url, now);
+  const std::string type = "Event_";
+  const std::string description = "Some description";
+  const GURL url("http://www.url_.com/url_");
+  const base::Time now = base::Time::Now();
+  const uint64_t page_id = 1234;
+  logger_->LogMessage(type, description, url, now, page_id);
 
   const size_t expected_size = 0;
   EXPECT_EQ(expected_size, observers[removed_observer].messages().size());
@@ -367,6 +390,7 @@
       EXPECT_EQ(description, observers[i].message()->event_description);
       EXPECT_EQ(url, observers[i].message()->url);
       EXPECT_EQ(now, observers[i].message()->time);
+      EXPECT_EQ(page_id, observers[i].message()->page_id);
     }
   }
 }
@@ -723,11 +747,13 @@
 }
 
 TEST_F(PreviewsLoggerTest, ClearBufferLogsWhenBlacklistCleared) {
-  std::string type = "Event_";
-  std::string description = "Some description";
-  GURL url("http://www.url_.com/url_");
-  base::Time now = base::Time::Now();
-  logger_->LogMessage(type, description, url, now);
+  const std::string type = "Event_";
+  const std::string description = "Some description";
+  const GURL url("http://www.url_.com/url_");
+  const base::Time now = base::Time::Now();
+  const uint64_t page_id = 1234;
+
+  logger_->LogMessage(type, description, url, now, page_id);
 
   logger_->OnBlacklistCleared(base::Time::Now());
 
diff --git a/components/proximity_auth/webui/proximity_auth_webui_handler.cc b/components/proximity_auth/webui/proximity_auth_webui_handler.cc
index 4a75ba5..e492dc8 100644
--- a/components/proximity_auth/webui/proximity_auth_webui_handler.cc
+++ b/components/proximity_auth/webui/proximity_auth_webui_handler.cc
@@ -74,7 +74,7 @@
 const char kExternalDeviceBluetoothAddress[] = "bluetoothAddress";
 const char kExternalDeviceUnlockKey[] = "unlockKey";
 const char kExternalDeviceMobileHotspot[] = "hasMobileHotspot";
-const char kExternalDeviceSupportsArcPlusPlus[] = "supportsArcPlusPlus";
+const char kExternalDeviceIsArcPlusPlusEnrollment[] = "isArcPlusPlusEnrollment";
 const char kExternalDeviceIsPixelPhone[] = "isPixelPhone";
 const char kExternalDeviceConnectionStatus[] = "connectionStatus";
 const char kExternalDeviceRemoteState[] = "remoteState";
@@ -533,7 +533,7 @@
   dictionary->SetBoolean(kExternalDeviceUnlockKey, device_info.unlock_key());
   dictionary->SetBoolean(kExternalDeviceMobileHotspot,
                          device_info.mobile_hotspot_supported());
-  dictionary->SetBoolean(kExternalDeviceSupportsArcPlusPlus,
+  dictionary->SetBoolean(kExternalDeviceIsArcPlusPlusEnrollment,
                          device_info.arc_plus_plus());
   dictionary->SetBoolean(kExternalDeviceIsPixelPhone,
                          device_info.pixel_phone());
diff --git a/components/proximity_auth/webui/resources/proximity_auth.html b/components/proximity_auth/webui/resources/proximity_auth.html
index 4e56122..99a4be00 100644
--- a/components/proximity_auth/webui/resources/proximity_auth.html
+++ b/components/proximity_auth/webui/resources/proximity_auth.html
@@ -106,8 +106,8 @@
           <td class='supports-mobile-hotspot'></td>
         </tr>
         <tr>
-          <td>Supports ARC++</td>
-          <td class='supports-arc-plus-plus'></td>
+          <td>Is ARC++ Enrollment</td>
+          <td class='is-arc-plus-plus-enrollment'></td>
         </tr>
         <tr>
           <td>Is Pixel Phone</td>
diff --git a/components/proximity_auth/webui/resources/proximity_auth.js b/components/proximity_auth/webui/resources/proximity_auth.js
index e629168..922b7906 100644
--- a/components/proximity_auth/webui/resources/proximity_auth.js
+++ b/components/proximity_auth/webui/resources/proximity_auth.js
@@ -175,7 +175,7 @@
   createRemoteDeviceItem_(remoteDevice) {
     var isUnlockKey = !!remoteDevice['unlockKey'];
     var hasMobileHotspot = !!remoteDevice['hasMobileHotspot'];
-    var supportsArcPlusPlus = !!remoteDevice['supportsArcPlusPlus'];
+    var isArcPlusPlusEnrollment = !!remoteDevice['isArcPlusPlusEnrollment'];
     var isPixelPhone = !!remoteDevice['isPixelPhone'];
 
     var t = this.remoteDeviceTemplate_.content;
@@ -187,8 +187,8 @@
         remoteDevice['publicKeyTruncated'];
     t.querySelector('.is-unlock-key').textContent = isUnlockKey;
     t.querySelector('.supports-mobile-hotspot').textContent = hasMobileHotspot;
-    t.querySelector('.supports-arc-plus-plus').textContent =
-        supportsArcPlusPlus;
+    t.querySelector('.is-arc-plus-plus-enrollment').textContent =
+        isArcPlusPlusEnrollment;
     t.querySelector('.is-pixel-phone').textContent = isPixelPhone;
     if (!!remoteDevice['bluetoothAddress']) {
       t.querySelector('.bluetooth-address-row').classList.remove('hidden');
diff --git a/components/security_interstitials/core/common_string_util.cc b/components/security_interstitials/core/common_string_util.cc
index bb740060..6c36f648 100644
--- a/components/security_interstitials/core/common_string_util.cc
+++ b/components/security_interstitials/core/common_string_util.cc
@@ -6,7 +6,7 @@
 
 #include "base/i18n/rtl.h"
 #include "base/i18n/time_formatting.h"
-#include "base/strings/string_util.h"
+#include "base/strings/strcat.h"
 #include "components/strings/grit/components_strings.h"
 #include "components/url_formatter/url_formatter.h"
 #include "net/base/net_errors.h"
@@ -46,8 +46,7 @@
                             base::TimeFormatShortDate(time_triggered));
   std::vector<std::string> encoded_chain;
   ssl_info.cert->GetPEMEncodedChain(&encoded_chain);
-  load_time_data->SetString(
-      "pem", base::JoinString(encoded_chain, base::StringPiece()));
+  load_time_data->SetString("pem", base::StrCat(encoded_chain));
 }
 
 }  // namespace common_string_util
diff --git a/components/ssl_errors/error_classification.cc b/components/ssl_errors/error_classification.cc
index da10872..e7df9cb 100644
--- a/components/ssl_errors/error_classification.cc
+++ b/components/ssl_errors/error_classification.cc
@@ -163,7 +163,7 @@
         RecordSSLInterstitialCause(overridable, LOCALHOST);
       if (IsHostnameNonUniqueOrDotless(hostname))
         RecordSSLInterstitialCause(overridable, PRIVATE_URL);
-      if (net::X509Certificate::IsSelfSigned(cert.os_cert_handle()))
+      if (net::X509Certificate::IsSelfSigned(cert.cert_buffer()))
         RecordSSLInterstitialCause(overridable, SELF_SIGNED);
       break;
     }
diff --git a/components/suggestions/webui/suggestions_source.cc b/components/suggestions/webui/suggestions_source.cc
index ab9b927..c2e34512 100644
--- a/components/suggestions/webui/suggestions_source.cc
+++ b/components/suggestions/webui/suggestions_source.cc
@@ -7,6 +7,7 @@
 #include "base/barrier_closure.h"
 #include "base/base64.h"
 #include "base/bind.h"
+#include "base/strings/strcat.h"
 #include "base/strings/string16.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_piece.h"
@@ -83,7 +84,7 @@
   }
   out.push_back("</ul>");
   out.push_back(kHtmlFooter);
-  return base::JoinString(out, base::StringPiece());
+  return base::StrCat(out);
 }
 
 // Returns the HTML needed to display that no suggestions are available.
@@ -96,7 +97,7 @@
   out.push_back("<p>You have no suggestions.</p>\n");
   out.push_back(GetRefreshHtml(base_url, is_refresh));
   out.push_back(kHtmlFooter);
-  return base::JoinString(out, base::StringPiece());
+  return base::StrCat(out);
 }
 
 }  // namespace
diff --git a/components/task_scheduler_util/common/variations_util.cc b/components/task_scheduler_util/common/variations_util.cc
index d83362b5..eaef402 100644
--- a/components/task_scheduler_util/common/variations_util.cc
+++ b/components/task_scheduler_util/common/variations_util.cc
@@ -7,6 +7,7 @@
 #include "base/command_line.h"
 #include "base/logging.h"
 #include "base/memory/ptr_util.h"
+#include "base/strings/strcat.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_split.h"
 #include "base/strings/string_util.h"
@@ -48,9 +49,8 @@
     const std::map<std::string, std::string>& variation_params,
     base::SchedulerBackwardCompatibility backward_compatibility =
         base::SchedulerBackwardCompatibility::DISABLED) {
-
-  auto pool_descriptor_it = variation_params.find(
-      base::JoinString({variation_param_prefix, pool_name}, ""));
+  auto pool_descriptor_it =
+      variation_params.find(base::StrCat({variation_param_prefix, pool_name}));
   if (pool_descriptor_it == variation_params.end())
     return nullptr;
   const auto& pool_descriptor = pool_descriptor_it->second;
diff --git a/components/update_client/protocol_builder.cc b/components/update_client/protocol_builder.cc
index 06520d3..487e88a 100644
--- a/components/update_client/protocol_builder.cc
+++ b/components/update_client/protocol_builder.cc
@@ -8,6 +8,7 @@
 
 #include "base/guid.h"
 #include "base/logging.h"
+#include "base/strings/strcat.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
@@ -385,13 +386,13 @@
       base::StringPrintf("<app appid=\"%s\"", component.id().c_str());
   base::StringAppendF(&app, " version=\"%s\"",
                       component.previous_version().GetString().c_str());
-  if (component.next_version().IsValid())
-    base::StringAppendF(&app, " nextversion=\"%s\"",
-                        component.next_version().GetString().c_str());
-  base::StringAppendF(&app, ">");
-  base::StringAppendF(&app, "%s",
-                      base::JoinString(component.events(), "").c_str());
-  base::StringAppendF(&app, "</app>");
+  if (component.next_version().IsValid()) {
+    base::StrAppend(
+        &app, {" nextversion=\"", component.next_version().GetString(), "\""});
+  }
+  app.push_back('>');
+  base::StrAppend(&app, component.events());
+  app.append("</app>");
 
   // The ping request does not include any updater state.
   return BuildProtocolRequest(
diff --git a/components/viz/service/BUILD.gn b/components/viz/service/BUILD.gn
index db3aa8a..26cb7aff 100644
--- a/components/viz/service/BUILD.gn
+++ b/components/viz/service/BUILD.gn
@@ -99,7 +99,6 @@
     "frame_sinks/compositor_frame_sink_support_manager.h",
     "frame_sinks/direct_layer_tree_frame_sink.cc",
     "frame_sinks/direct_layer_tree_frame_sink.h",
-    "frame_sinks/frame_sink_manager_client.h",
     "frame_sinks/frame_sink_manager_impl.cc",
     "frame_sinks/frame_sink_manager_impl.h",
     "frame_sinks/primary_begin_frame_source.cc",
diff --git a/components/viz/service/display/direct_renderer.cc b/components/viz/service/display/direct_renderer.cc
index 4d1043d..a8f5c80 100644
--- a/components/viz/service/display/direct_renderer.cc
+++ b/components/viz/service/display/direct_renderer.cc
@@ -285,7 +285,8 @@
   // Attempt to replace some or all of the quads of the root render pass with
   // overlays.
   overlay_processor_->ProcessForOverlays(
-      resource_provider_, render_passes_in_draw_order, render_pass_filters_,
+      resource_provider_, render_passes_in_draw_order,
+      output_surface_->color_matrix(), render_pass_filters_,
       render_pass_background_filters_, &current_frame()->overlay_list,
       &current_frame()->ca_layer_overlay_list,
       &current_frame()->dc_layer_overlay_list,
diff --git a/components/viz/service/display/display.cc b/components/viz/service/display/display.cc
index 66fd00e..9965e63 100644
--- a/components/viz/service/display/display.cc
+++ b/components/viz/service/display/display.cc
@@ -166,6 +166,23 @@
     scheduler_->DisplayResized();
 }
 
+void Display::SetColorMatrix(const SkMatrix44& matrix) {
+  if (output_surface_)
+    output_surface_->set_color_matrix(matrix);
+
+  // Force a redraw.
+  if (aggregator_) {
+    if (current_surface_id_.is_valid())
+      aggregator_->SetFullDamageForSurface(current_surface_id_);
+  }
+
+  if (scheduler_) {
+    BeginFrameAck ack;
+    ack.has_damage = true;
+    scheduler_->ProcessSurfaceDamage(current_surface_id_, ack, true);
+  }
+}
+
 void Display::SetColorSpace(const gfx::ColorSpace& blending_color_space,
                             const gfx::ColorSpace& device_color_space) {
   blending_color_space_ = blending_color_space;
@@ -352,6 +369,13 @@
   if (should_swap) {
     swapped_since_resize_ = true;
 
+    if (scheduler_) {
+      frame.metadata.latency_info.emplace_back(ui::SourceEventType::FRAME);
+      frame.metadata.latency_info.back().AddLatencyNumberWithTimestamp(
+          ui::LATENCY_BEGIN_FRAME_DISPLAY_COMPOSITOR_COMPONENT, 0, 0,
+          scheduler_->CurrentFrameTime(), 1);
+    }
+
     DLOG_IF(WARNING, !presented_callbacks_.empty())
         << "DidReceiveSwapBuffersAck() is not called for the last SwapBuffers!";
     for (const auto& id_entry : aggregator_->previous_contained_surfaces()) {
@@ -361,28 +385,41 @@
         presented_callbacks_.push_back(std::move(callback));
     }
 
-    for (auto& latency : frame.metadata.latency_info) {
-      TRACE_EVENT_WITH_FLOW1(
-          "input,benchmark", "LatencyInfo.Flow",
-          TRACE_ID_DONT_MANGLE(latency.trace_id()),
-          TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT, "step",
-          "Display::DrawAndSwap");
-    }
+    ui::LatencyInfo::TraceIntermediateFlowEvents(frame.metadata.latency_info,
+                                                 "Display::DrawAndSwap");
+
     cc::benchmark_instrumentation::IssueDisplayRenderingStatsEvent();
     renderer_->SwapBuffers(std::move(frame.metadata.latency_info));
     if (scheduler_)
       scheduler_->DidSwapBuffers();
   } else {
-    if (have_damage && !size_matches)
-      aggregator_->SetFullDamageForSurface(current_surface_id_);
     TRACE_EVENT_INSTANT0("viz", "Swap skipped.", TRACE_EVENT_SCOPE_THREAD);
 
-    // Do not store more that the allowed size.
-    if (ui::LatencyInfo::Verify(frame.metadata.latency_info,
-                                "Display::DrawAndSwap")) {
-      stored_latency_info_.insert(stored_latency_info_.end(),
-                                  frame.metadata.latency_info.begin(),
-                                  frame.metadata.latency_info.end());
+    if (have_damage && !size_matches)
+      aggregator_->SetFullDamageForSurface(current_surface_id_);
+
+    if (have_damage) {
+      // Do not store more than the allowed size.
+      if (ui::LatencyInfo::Verify(frame.metadata.latency_info,
+                                  "Display::DrawAndSwap")) {
+        stored_latency_info_.swap(frame.metadata.latency_info);
+      }
+    } else {
+      // There was no damage, so tracking latency info at this point isn't
+      // useful unless there's a snapshot request.
+      base::TimeTicks now = base::TimeTicks::Now();
+      while (!frame.metadata.latency_info.empty()) {
+        auto& latency = frame.metadata.latency_info.back();
+        if (latency.FindLatency(ui::BROWSER_SNAPSHOT_FRAME_NUMBER_COMPONENT,
+                                nullptr)) {
+          stored_latency_info_.push_back(std::move(latency));
+        } else {
+          latency.AddLatencyNumberWithTimestamp(
+              ui::INPUT_EVENT_LATENCY_TERMINATED_NO_SWAP_COMPONENT, 0, 0, now,
+              1);
+        }
+        frame.metadata.latency_info.pop_back();
+      }
     }
 
     if (scheduler_) {
diff --git a/components/viz/service/display/display.h b/components/viz/service/display/display.h
index 9f4441ce..3679944 100644
--- a/components/viz/service/display/display.h
+++ b/components/viz/service/display/display.h
@@ -83,6 +83,11 @@
   void SetLocalSurfaceId(const LocalSurfaceId& id, float device_scale_factor);
   void SetVisible(bool visible);
   void Resize(const gfx::Size& new_size);
+
+  // Sets the color matrix that will be used to transform the output of this
+  // display. This is only supported for GPU compositing.
+  void SetColorMatrix(const SkMatrix44& matrix);
+
   void SetColorSpace(const gfx::ColorSpace& blending_color_space,
                      const gfx::ColorSpace& device_color_space);
   void SetOutputIsSecure(bool secure);
@@ -108,9 +113,6 @@
 
   bool has_scheduler() const { return !!scheduler_; }
   DirectRenderer* renderer_for_testing() const { return renderer_.get(); }
-  size_t stored_latency_info_size_for_testing() const {
-    return stored_latency_info_.size();
-  }
 
   void ForceImmediateDrawAndSwapIfPossible();
   void SetNeedsOneBeginFrame();
diff --git a/components/viz/service/display/display_scheduler.h b/components/viz/service/display/display_scheduler.h
index c1048a6..df4d8c2 100644
--- a/components/viz/service/display/display_scheduler.h
+++ b/components/viz/service/display/display_scheduler.h
@@ -50,6 +50,9 @@
   void SetRootSurfaceResourcesLocked(bool locked);
   void ForceImmediateSwapIfPossible();
   void SetNeedsOneBeginFrame();
+  base::TimeTicks CurrentFrameTime() {
+    return current_begin_frame_args_.frame_time;
+  }
   virtual void DisplayResized();
   virtual void SetNewRootSurface(const SurfaceId& root_surface_id);
   virtual void ProcessSurfaceDamage(const SurfaceId& surface_id,
diff --git a/components/viz/service/display/display_unittest.cc b/components/viz/service/display/display_unittest.cc
index 4f376a7..5fef6f6 100644
--- a/components/viz/service/display/display_unittest.cc
+++ b/components/viz/service/display/display_unittest.cc
@@ -166,6 +166,8 @@
     run_loop.RunUntilIdle();
   }
 
+  void LatencyInfoCapTest(bool over_capacity);
+
   FrameSinkManagerImpl manager_;
   std::unique_ptr<CompositorFrameSinkSupport> support_;
   LocalSurfaceIdAllocator id_allocator_;
@@ -241,8 +243,9 @@
   EXPECT_EQ(gfx::Size(100, 100),
             software_output_device_->viewport_pixel_size());
   EXPECT_EQ(gfx::Rect(0, 0, 100, 100), software_output_device_->damage_rect());
+
+  // Only damaged portion should be swapped.
   {
-    // Only damaged portion should be swapped.
     pass = RenderPass::Create();
     pass->output_rect = gfx::Rect(0, 0, 100, 100);
     pass->damage_rect = gfx::Rect(10, 10, 1, 1);
@@ -265,10 +268,13 @@
     EXPECT_EQ(gfx::Size(100, 100),
               software_output_device_->viewport_pixel_size());
     EXPECT_EQ(gfx::Rect(10, 10, 1, 1), software_output_device_->damage_rect());
+
+    // Display should inject its own LatencyInfo.
+    EXPECT_EQ(1u, output_surface_->last_sent_frame()->latency_info.size());
   }
 
+  // Pass has no damage so shouldn't be swapped.
   {
-    // Pass has no damage so shouldn't be swapped.
     pass = RenderPass::Create();
     pass->output_rect = gfx::Rect(0, 0, 100, 100);
     pass->damage_rect = gfx::Rect(10, 10, 0, 0);
@@ -287,19 +293,22 @@
     EXPECT_EQ(2u, output_surface_->num_sent_frames());
   }
 
+  // Pass is wrong size so shouldn't be swapped. However, damage should
+  // result in latency info being stored for the next swap.
   {
-    // Pass is wrong size so shouldn't be swapped.
-    pass = RenderPass::Create();
-    pass->output_rect = gfx::Rect(0, 0, 99, 99);
-    pass->damage_rect = gfx::Rect(10, 10, 10, 10);
-    pass->id = 1u;
-
     local_surface_id = id_allocator_.GenerateId();
     display_->SetLocalSurfaceId(local_surface_id, 1.f);
 
-    pass_list.push_back(std::move(pass));
     scheduler_->ResetDamageForTest();
-    SubmitCompositorFrame(&pass_list, local_surface_id);
+
+    constexpr gfx::Rect kOutputRect(0, 0, 99, 99);
+    constexpr gfx::Rect kDamageRect(10, 10, 10, 10);
+    CompositorFrame frame = CompositorFrameBuilder()
+                                .AddRenderPass(kOutputRect, kDamageRect)
+                                .AddLatencyInfo(ui::LatencyInfo())
+                                .Build();
+
+    support_->SubmitCompositorFrame(local_surface_id, std::move(frame));
     EXPECT_TRUE(scheduler_->damaged);
     EXPECT_FALSE(scheduler_->display_resized_);
     EXPECT_FALSE(scheduler_->has_new_root_surface);
@@ -310,8 +319,8 @@
     EXPECT_EQ(2u, output_surface_->num_sent_frames());
   }
 
+  // Previous frame wasn't swapped, so next swap should have full damage.
   {
-    // Previous frame wasn't swapped, so next swap should have full damage.
     pass = RenderPass::Create();
     pass->output_rect = gfx::Rect(0, 0, 100, 100);
     pass->damage_rect = gfx::Rect(10, 10, 0, 0);
@@ -333,10 +342,14 @@
     EXPECT_EQ(3u, output_surface_->num_sent_frames());
     EXPECT_EQ(gfx::Rect(0, 0, 100, 100),
               software_output_device_->damage_rect());
+
+    // Latency info from previous frame should be sent now, along with the
+    // Display's info.
+    EXPECT_EQ(2u, output_surface_->last_sent_frame()->latency_info.size());
   }
 
+  // Pass has copy output request so should be swapped.
   {
-    // Pass has copy output request so should be swapped.
     pass = RenderPass::Create();
     pass->output_rect = gfx::Rect(0, 0, 100, 100);
     pass->damage_rect = gfx::Rect(10, 10, 0, 0);
@@ -360,8 +373,8 @@
     EXPECT_TRUE(copy_called);
   }
 
-  // Pass has no damage, so shouldn't be swapped, but latency info should be
-  // saved for next swap.
+  // Pass has no damage, so shouldn't be swapped and latency info should be
+  // discarded.
   {
     scheduler_->ResetDamageForTest();
 
@@ -377,6 +390,7 @@
     EXPECT_FALSE(scheduler_->display_resized_);
     EXPECT_FALSE(scheduler_->has_new_root_surface);
 
+    frame.metadata.latency_info.push_back(ui::LatencyInfo());
     scheduler_->swapped = false;
     display_->DrawAndSwap();
     EXPECT_TRUE(scheduler_->swapped);
@@ -409,14 +423,15 @@
     EXPECT_TRUE(scheduler_->swapped);
     EXPECT_EQ(5u, output_surface_->num_sent_frames());
 
-    // Latency info from previous frame should be sent now.
+    // Latency info from previous frame should have been discarded since
+    // there was no damage. So we only get the Display's LatencyInfo.
     EXPECT_EQ(1u, output_surface_->last_sent_frame()->latency_info.size());
   }
 
+  // Surface that's damaged completely should be resized and swapped.
   {
     local_surface_id = id_allocator_.GenerateId();
     display_->SetLocalSurfaceId(local_surface_id, 1.0f);
-    // Surface that's damaged completely should be resized and swapped.
     pass = RenderPass::Create();
     pass->output_rect = gfx::Rect(0, 0, 99, 99);
     pass->damage_rect = gfx::Rect(0, 0, 99, 99);
@@ -437,67 +452,85 @@
               software_output_device_->viewport_pixel_size());
     EXPECT_EQ(gfx::Rect(0, 0, 100, 100),
               software_output_device_->damage_rect());
-    EXPECT_EQ(0u, output_surface_->last_sent_frame()->latency_info.size());
+
+    // Only expect the Display's LatencyInfo.
+    EXPECT_EQ(1u, output_surface_->last_sent_frame()->latency_info.size());
   }
   TearDownDisplay();
 }
 
-// Check LatencyInfo storage is cleaned up if it exceeds the limit.
-TEST_F(DisplayTest, MaxLatencyInfoCap) {
+// Verifies latency info is stored only up to a limit if a swap fails.
+void DisplayTest::LatencyInfoCapTest(bool over_capacity) {
   RendererSettings settings;
-  settings.partial_swap_enabled = true;
   settings.finish_rendering_on_resize = true;
   SetUpDisplay(settings, nullptr);
-  gfx::ColorSpace color_space_1 = gfx::ColorSpace::CreateXYZD50();
-  gfx::ColorSpace color_space_2 = gfx::ColorSpace::CreateSCRGBLinear();
 
   StubDisplayClient client;
   display_->Initialize(&client, manager_.surface_manager());
-  display_->SetColorSpace(color_space_1, color_space_1);
 
   LocalSurfaceId local_surface_id(id_allocator_.GenerateId());
   display_->SetLocalSurfaceId(local_surface_id, 1.f);
 
-  scheduler_->ResetDamageForTest();
   display_->Resize(gfx::Size(100, 100));
 
-  RenderPassList pass_list;
-  auto pass = RenderPass::Create();
-  pass->output_rect = gfx::Rect(0, 0, 100, 100);
-  pass->damage_rect = gfx::Rect(10, 10, 1, 1);
-  pass->id = 1u;
-  pass_list.push_back(std::move(pass));
-
-  scheduler_->ResetDamageForTest();
-  SubmitCompositorFrame(&pass_list, local_surface_id);
+  // Start off with a successful swap so output_surface_->last_sent_frame() is
+  // valid.
+  constexpr gfx::Rect kOutputRect(0, 0, 100, 100);
+  constexpr gfx::Rect kDamageRect(10, 10, 1, 1);
+  CompositorFrame frame1 =
+      CompositorFrameBuilder().AddRenderPass(kOutputRect, kDamageRect).Build();
+  support_->SubmitCompositorFrame(local_surface_id, std::move(frame1));
 
   display_->DrawAndSwap();
+  EXPECT_EQ(1u, output_surface_->num_sent_frames());
+  EXPECT_EQ(1u, output_surface_->last_sent_frame()->latency_info.size());
+
+  // Resize so the swap fails even though there's damage, which triggers
+  // the case where we store latency info to append to a future swap.
+  display_->Resize(gfx::Size(200, 200));
 
   // This is the same as LatencyInfo::kMaxLatencyInfoNumber.
   const size_t max_latency_info_count = 100;
-  for (size_t i = 0; i <= max_latency_info_count; ++i) {
-    scheduler_->ResetDamageForTest();
+  size_t latency_count = max_latency_info_count;
+  if (over_capacity)
+    latency_count++;
+  std::vector<ui::LatencyInfo> latency_info(latency_count, ui::LatencyInfo());
 
-    constexpr gfx::Rect kOutputRect(0, 0, 100, 100);
-    constexpr gfx::Rect kDamageRect(10, 10, 0, 0);
-    CompositorFrame frame = CompositorFrameBuilder()
-                                .AddRenderPass(kOutputRect, kDamageRect)
-                                .AddLatencyInfo(ui::LatencyInfo())
-                                .Build();
+  CompositorFrame frame2 = CompositorFrameBuilder()
+                               .AddRenderPass(kOutputRect, kDamageRect)
+                               .AddLatencyInfos(std::move(latency_info))
+                               .Build();
+  support_->SubmitCompositorFrame(local_surface_id, std::move(frame2));
 
-    support_->SubmitCompositorFrame(local_surface_id, std::move(frame));
+  EXPECT_TRUE(display_->DrawAndSwap());
+  EXPECT_EQ(1u, output_surface_->num_sent_frames());
+  EXPECT_EQ(1u, output_surface_->last_sent_frame()->latency_info.size());
 
-    display_->DrawAndSwap();
+  // Run a successful swap and verify whether or not LatencyInfo was discarded.
+  display_->Resize(gfx::Size(100, 100));
+  CompositorFrame frame3 =
+      CompositorFrameBuilder().AddRenderPass(kOutputRect, kDamageRect).Build();
+  support_->SubmitCompositorFrame(local_surface_id, std::move(frame3));
 
-    if (i < max_latency_info_count)
-      EXPECT_EQ(i + 1, display_->stored_latency_info_size_for_testing());
-    else
-      EXPECT_EQ(0u, display_->stored_latency_info_size_for_testing());
-  }
+  // Verify whether or not LatencyInfo was dropped.
+  size_t expected_size = 1;  // The Display adds its own latency info.
+  if (!over_capacity)
+    expected_size += max_latency_info_count;
+  EXPECT_EQ(2u, output_surface_->num_sent_frames());
+  EXPECT_EQ(expected_size,
+            output_surface_->last_sent_frame()->latency_info.size());
 
   TearDownDisplay();
 }
 
+TEST_F(DisplayTest, UnderLatencyInfoCap) {
+  LatencyInfoCapTest(false);
+}
+
+TEST_F(DisplayTest, OverLatencyInfoCap) {
+  LatencyInfoCapTest(true);
+}
+
 class MockedContext : public cc::TestWebGraphicsContext3D {
  public:
   MOCK_METHOD0(shallowFinishCHROMIUM, void());
diff --git a/components/viz/service/display/gl_renderer.cc b/components/viz/service/display/gl_renderer.cc
index b82eb0f..b342b165 100644
--- a/components/viz/service/display/gl_renderer.cc
+++ b/components/viz/service/display/gl_renderer.cc
@@ -2993,6 +2993,14 @@
       GetColorTransform(src_color_space, dst_color_space);
   program_key.SetColorTransform(color_transform);
 
+  const bool is_root_render_pass =
+      current_frame()->current_render_pass == current_frame()->root_render_pass;
+  const SkMatrix44& output_color_matrix = output_surface_->color_matrix();
+  const bool has_output_color_matrix =
+      is_root_render_pass && !output_color_matrix.isIdentity();
+
+  program_key.set_has_output_color_matrix(has_output_color_matrix);
+
   // Create and set the program if needed.
   std::unique_ptr<Program>& program = program_cache_[program_key];
   if (!program) {
@@ -3029,6 +3037,14 @@
     gl_->Uniform1f(current_program_->lut_size_location(), lut.size);
     gl_->ActiveTexture(GL_TEXTURE0);
   }
+
+  if (has_output_color_matrix) {
+    DCHECK_NE(current_program_->output_color_matrix_location(), -1);
+    float matrix[16];
+    output_color_matrix.asColMajorf(matrix);
+    gl_->UniformMatrix4fv(current_program_->output_color_matrix_location(), 1,
+                          false, matrix);
+  }
 }
 
 const Program* GLRenderer::GetProgramIfInitialized(
diff --git a/components/viz/service/display/gl_renderer.h b/components/viz/service/display/gl_renderer.h
index c6b86a9..d0a86aa5 100644
--- a/components/viz/service/display/gl_renderer.h
+++ b/components/viz/service/display/gl_renderer.h
@@ -156,6 +156,7 @@
   friend class GLRendererCopierPixelTest;
   friend class GLRendererShaderPixelTest;
   friend class GLRendererShaderTest;
+  friend class GLRendererTest;
 
   // If any of the following functions returns false, then it means that drawing
   // is not possible.
diff --git a/components/viz/service/display/gl_renderer_unittest.cc b/components/viz/service/display/gl_renderer_unittest.cc
index 2700021..9e83e50 100644
--- a/components/viz/service/display/gl_renderer_unittest.cc
+++ b/components/viz/service/display/gl_renderer_unittest.cc
@@ -72,6 +72,10 @@
     renderer->DrawFrame(&render_passes_in_draw_order_, 1.f, viewport_size);
   }
 
+  static const Program* current_program(GLRenderer* renderer) {
+    return renderer->current_program_;
+  }
+
   RenderPassList render_passes_in_draw_order_;
 };
 
@@ -136,8 +140,11 @@
     ASSERT_FALSE(renderer()->IsContextLost());
   }
 
-  void TestShader(const ProgramKey& program_key) {
-    renderer()->SetCurrentFrameForTesting(GLRenderer::DrawingFrame());
+  void TestShaderWithDrawingFrame(
+      const ProgramKey& program_key,
+      const DirectRenderer::DrawingFrame& drawing_frame,
+      bool validate_output_color_matrix) {
+    renderer()->SetCurrentFrameForTesting(drawing_frame);
     const size_t kNumSrcColorSpaces = 4;
     gfx::ColorSpace src_color_spaces[kNumSrcColorSpaces] = {
         gfx::ColorSpace::CreateSRGB(),
@@ -157,14 +164,51 @@
         renderer()->SetUseProgram(program_key, src_color_spaces[j],
                                   dst_color_spaces[i]);
         EXPECT_TRUE(renderer()->current_program_->initialized());
+        if (validate_output_color_matrix) {
+          EXPECT_NE(
+              -1, renderer()->current_program_->output_color_matrix_location());
+        }
       }
     }
   }
 
+  void TestShader(const ProgramKey& program_key) {
+    TestShaderWithDrawingFrame(program_key, GLRenderer::DrawingFrame(), false);
+  }
+
+  void TestShadersWithOutputColorMatrix(const ProgramKey& program_key) {
+    GLRenderer::DrawingFrame frame;
+
+    RenderPassList render_passes_in_draw_order;
+    gfx::Size viewport_size(100, 100);
+    RenderPassId root_pass_id = 1;
+    RenderPass* root_pass = cc::AddRenderPass(
+        &render_passes_in_draw_order, root_pass_id, gfx::Rect(viewport_size),
+        gfx::Transform(), cc::FilterOperations());
+    root_pass->damage_rect = gfx::Rect(0, 0, 25, 25);
+
+    frame.root_render_pass = root_pass;
+    frame.current_render_pass = root_pass;
+    frame.render_passes_in_draw_order = &render_passes_in_draw_order;
+
+    // Set a non-identity color matrix on the output surface.
+    SkMatrix44 color_matrix(SkMatrix44::kIdentity_Constructor);
+    color_matrix.set(0, 0, 0.7f);
+    color_matrix.set(1, 1, 0.4f);
+    color_matrix.set(2, 2, 0.5f);
+    renderer()->output_surface_->set_color_matrix(color_matrix);
+
+    TestShaderWithDrawingFrame(program_key, frame, true);
+  }
+
   void TestBasicShaders() {
     TestShader(ProgramKey::DebugBorder());
     TestShader(ProgramKey::SolidColor(NO_AA));
     TestShader(ProgramKey::SolidColor(USE_AA));
+
+    TestShadersWithOutputColorMatrix(ProgramKey::DebugBorder());
+    TestShadersWithOutputColorMatrix(ProgramKey::SolidColor(NO_AA));
+    TestShadersWithOutputColorMatrix(ProgramKey::SolidColor(USE_AA));
   }
 
   void TestColorShaders() {
@@ -1895,8 +1939,9 @@
     Strategy() = default;
     ~Strategy() override = default;
 
-    MOCK_METHOD4(Attempt,
-                 bool(cc::DisplayResourceProvider* resource_provider,
+    MOCK_METHOD5(Attempt,
+                 bool(const SkMatrix44& output_color_matrix,
+                      cc::DisplayResourceProvider* resource_provider,
                       RenderPass* render_pass,
                       cc::OverlayCandidateList* candidates,
                       std::vector<gfx::Rect>* content_bounds));
@@ -2020,7 +2065,7 @@
   // added a fake strategy, so checking for Attempt calls checks if there was
   // any attempt to overlay, which there shouldn't be. We can't use the quad
   // list because the render pass is cleaned up by DrawFrame.
-  EXPECT_CALL(processor->strategy(), Attempt(_, _, _, _)).Times(0);
+  EXPECT_CALL(processor->strategy(), Attempt(_, _, _, _, _)).Times(0);
   EXPECT_CALL(*validator, AllowCALayerOverlays()).Times(0);
   EXPECT_CALL(*validator, AllowDCLayerOverlays()).Times(0);
   DrawFrame(&renderer, viewport_size);
@@ -2045,7 +2090,7 @@
   EXPECT_CALL(*validator, AllowDCLayerOverlays())
       .Times(1)
       .WillOnce(::testing::Return(false));
-  EXPECT_CALL(processor->strategy(), Attempt(_, _, _, _)).Times(1);
+  EXPECT_CALL(processor->strategy(), Attempt(_, _, _, _, _)).Times(1);
   DrawFrame(&renderer, viewport_size);
 
   // If the CALayerOverlay path is taken, then the ordinary overlay path should
@@ -2064,7 +2109,7 @@
   EXPECT_CALL(*validator, AllowCALayerOverlays())
       .Times(1)
       .WillOnce(::testing::Return(true));
-  EXPECT_CALL(processor->strategy(), Attempt(_, _, _, _)).Times(0);
+  EXPECT_CALL(processor->strategy(), Attempt(_, _, _, _, _)).Times(0);
   DrawFrame(&renderer, viewport_size);
 
   // Transfer resources back from the parent to the child. Set no resources as
@@ -2234,6 +2279,88 @@
                                                           ResourceIdSet());
 }
 
+class OutputColorMatrixMockGLES2Interface : public cc::TestGLES2Interface {
+ public:
+  OutputColorMatrixMockGLES2Interface() = default;
+
+  MOCK_METHOD4(UniformMatrix4fv,
+               void(GLint location,
+                    GLsizei count,
+                    GLboolean transpose,
+                    const GLfloat* value));
+};
+
+TEST_F(GLRendererTest, OutputColorMatrixTest) {
+  // Initialize the mock GL interface, the output surface and the renderer.
+  auto gl_owned = std::make_unique<OutputColorMatrixMockGLES2Interface>();
+  auto* gl = gl_owned.get();
+  auto provider = cc::TestContextProvider::Create(std::move(gl_owned));
+  provider->BindToCurrentThread();
+  std::unique_ptr<cc::FakeOutputSurface> output_surface(
+      cc::FakeOutputSurface::Create3d(std::move(provider)));
+  cc::FakeOutputSurfaceClient output_surface_client;
+  output_surface->BindToClient(&output_surface_client);
+  std::unique_ptr<cc::DisplayResourceProvider> resource_provider =
+      cc::FakeResourceProvider::CreateDisplayResourceProvider(
+          output_surface->context_provider(), nullptr);
+  RendererSettings settings;
+  FakeRendererGL renderer(&settings, output_surface.get(),
+                          resource_provider.get());
+  renderer.Initialize();
+  renderer.SetVisible(true);
+
+  // Set a non-identity color matrix on the output surface.
+  SkMatrix44 color_matrix(SkMatrix44::kIdentity_Constructor);
+  color_matrix.set(0, 0, 0.7f);
+  color_matrix.set(1, 1, 0.4f);
+  color_matrix.set(2, 2, 0.5f);
+  output_surface->set_color_matrix(color_matrix);
+
+  // Create a root and a child passes to test that the output color matrix is
+  // registered only for the root pass.
+  gfx::Size viewport_size(100, 100);
+  RenderPassId child_pass_id = 2;
+  RenderPass* child_pass =
+      cc::AddRenderPass(&render_passes_in_draw_order_, child_pass_id,
+                        gfx::Rect(viewport_size) + gfx::Vector2d(1, 2),
+                        gfx::Transform(), cc::FilterOperations());
+  RenderPassId root_pass_id = 1;
+  RenderPass* root_pass = cc::AddRenderPass(
+      &render_passes_in_draw_order_, root_pass_id, gfx::Rect(viewport_size),
+      gfx::Transform(), cc::FilterOperations());
+  root_pass->damage_rect = gfx::Rect(0, 0, 25, 25);
+  cc::AddRenderPassQuad(root_pass, child_pass);
+
+  // Verify that UniformMatrix4fv() is called only once on the root pass with
+  // the correct matrix values.
+  int call_count = 0;
+  bool output_color_matrix_invoked = false;
+  EXPECT_CALL(*gl, UniformMatrix4fv(_, 1, false, _))
+      .WillRepeatedly(testing::WithArgs<0, 3>(testing::Invoke(
+          [&color_matrix, &renderer, &call_count, &output_color_matrix_invoked](
+              int matrix_location, const GLfloat* gl_matrix) {
+            DCHECK(current_program(&renderer));
+            const int color_matrix_location =
+                current_program(&renderer)->output_color_matrix_location();
+
+            if (matrix_location != color_matrix_location)
+              return;
+
+            call_count++;
+            output_color_matrix_invoked = true;
+            float expected_matrix[16];
+            color_matrix.asColMajorf(expected_matrix);
+            for (int i = 0; i < 16; ++i)
+              EXPECT_FLOAT_EQ(expected_matrix[i], gl_matrix[i]);
+          })));
+
+  renderer.DecideRenderPassAllocationsForFrame(render_passes_in_draw_order_);
+  DrawFrame(&renderer, viewport_size);
+
+  EXPECT_EQ(1, call_count);
+  EXPECT_TRUE(output_color_matrix_invoked);
+}
+
 class PartialSwapMockGLES2Interface : public cc::TestGLES2Interface {
  public:
   explicit PartialSwapMockGLES2Interface(bool support_dc_layers)
@@ -2545,7 +2672,8 @@
         : content_bounds_(content_bounds) {}
     ~Strategy() override = default;
 
-    bool Attempt(cc::DisplayResourceProvider* resource_provider,
+    bool Attempt(const SkMatrix44& output_color_matrix,
+                 cc::DisplayResourceProvider* resource_provider,
                  RenderPass* render_pass,
                  cc::OverlayCandidateList* candidates,
                  std::vector<gfx::Rect>* content_bounds) override {
diff --git a/components/viz/service/display/output_surface.h b/components/viz/service/display/output_surface.h
index 8c71bb73..73b7b88 100644
--- a/components/viz/service/display/output_surface.h
+++ b/components/viz/service/display/output_surface.h
@@ -77,6 +77,11 @@
     return software_device_.get();
   }
 
+  void set_color_matrix(const SkMatrix44& color_matrix) {
+    color_matrix_ = color_matrix;
+  }
+  const SkMatrix44& color_matrix() const { return color_matrix_; }
+
   virtual void BindToClient(OutputSurfaceClient* client) = 0;
 
   virtual void EnsureBackbuffer() = 0;
@@ -180,6 +185,8 @@
   std::unique_ptr<SoftwareOutputDevice> software_device_;
 
  private:
+  SkMatrix44 color_matrix_;
+
   DISALLOW_COPY_AND_ASSIGN(OutputSurface);
 };
 
diff --git a/components/viz/service/display/overlay_processor.cc b/components/viz/service/display/overlay_processor.cc
index f227d05..002e0535 100644
--- a/components/viz/service/display/overlay_processor.cc
+++ b/components/viz/service/display/overlay_processor.cc
@@ -113,6 +113,7 @@
 void OverlayProcessor::ProcessForOverlays(
     cc::DisplayResourceProvider* resource_provider,
     RenderPassList* render_passes,
+    const SkMatrix44& output_color_matrix,
     const OverlayProcessor::FilterOperationsMap& render_pass_filters,
     const OverlayProcessor::FilterOperationsMap& render_pass_background_filters,
     cc::OverlayCandidateList* candidates,
@@ -158,9 +159,11 @@
 
   // Only if that fails, attempt hardware overlay strategies.
   for (const auto& strategy : strategies_) {
-    if (!strategy->Attempt(resource_provider, render_passes->back().get(),
-                           candidates, content_bounds))
+    if (!strategy->Attempt(output_color_matrix, resource_provider,
+                           render_passes->back().get(), candidates,
+                           content_bounds)) {
       continue;
+    }
 
     UpdateDamageRect(candidates, previous_frame_underlay_rect, damage_rect);
     break;
diff --git a/components/viz/service/display/overlay_processor.h b/components/viz/service/display/overlay_processor.h
index df7a737c..3822f52 100644
--- a/components/viz/service/display/overlay_processor.h
+++ b/components/viz/service/display/overlay_processor.h
@@ -31,7 +31,8 @@
     // current set of render passes. Returns true if the strategy was successful
     // and adds any additional passes necessary to represent overlays to
     // |render_passes|.
-    virtual bool Attempt(cc::DisplayResourceProvider* resource_provider,
+    virtual bool Attempt(const SkMatrix44& output_color_matrix,
+                         cc::DisplayResourceProvider* resource_provider,
                          RenderPass* render_pass,
                          cc::OverlayCandidateList* candidates,
                          std::vector<gfx::Rect>* content_bounds) = 0;
@@ -53,6 +54,7 @@
   void ProcessForOverlays(
       cc::DisplayResourceProvider* resource_provider,
       RenderPassList* render_passes,
+      const SkMatrix44& output_color_matrix,
       const FilterOperationsMap& render_pass_filters,
       const FilterOperationsMap& render_pass_background_filters,
       cc::OverlayCandidateList* overlay_candidates,
diff --git a/components/viz/service/display/overlay_strategy_fullscreen.cc b/components/viz/service/display/overlay_strategy_fullscreen.cc
index 8e1deb6..e5d5056 100644
--- a/components/viz/service/display/overlay_strategy_fullscreen.cc
+++ b/components/viz/service/display/overlay_strategy_fullscreen.cc
@@ -21,6 +21,7 @@
 OverlayStrategyFullscreen::~OverlayStrategyFullscreen() {}
 
 bool OverlayStrategyFullscreen::Attempt(
+    const SkMatrix44& output_color_matrix,
     cc::DisplayResourceProvider* resource_provider,
     RenderPass* render_pass,
     cc::OverlayCandidateList* candidate_list,
@@ -42,8 +43,8 @@
     return false;
 
   cc::OverlayCandidate candidate;
-  if (!cc::OverlayCandidate::FromDrawQuad(resource_provider, quad,
-                                          &candidate)) {
+  if (!cc::OverlayCandidate::FromDrawQuad(
+          resource_provider, output_color_matrix, quad, &candidate)) {
     return false;
   }
 
diff --git a/components/viz/service/display/overlay_strategy_fullscreen.h b/components/viz/service/display/overlay_strategy_fullscreen.h
index edec004..1ce04ef 100644
--- a/components/viz/service/display/overlay_strategy_fullscreen.h
+++ b/components/viz/service/display/overlay_strategy_fullscreen.h
@@ -22,7 +22,8 @@
       OverlayCandidateValidator* capability_checker);
   ~OverlayStrategyFullscreen() override;
 
-  bool Attempt(cc::DisplayResourceProvider* resource_provider,
+  bool Attempt(const SkMatrix44& output_color_matrix,
+               cc::DisplayResourceProvider* resource_provider,
                RenderPass* render_pass,
                cc::OverlayCandidateList* candidate_list,
                std::vector<gfx::Rect>* content_bounds) override;
diff --git a/components/viz/service/display/overlay_strategy_single_on_top.cc b/components/viz/service/display/overlay_strategy_single_on_top.cc
index ae9b20f9..836d98f 100644
--- a/components/viz/service/display/overlay_strategy_single_on_top.cc
+++ b/components/viz/service/display/overlay_strategy_single_on_top.cc
@@ -24,6 +24,7 @@
 OverlayStrategySingleOnTop::~OverlayStrategySingleOnTop() {}
 
 bool OverlayStrategySingleOnTop::Attempt(
+    const SkMatrix44& output_color_matrix,
     cc::DisplayResourceProvider* resource_provider,
     RenderPass* render_pass,
     cc::OverlayCandidateList* candidate_list,
@@ -34,8 +35,8 @@
   auto best_quad_it = quad_list->end();
   for (auto it = quad_list->begin(); it != quad_list->end(); ++it) {
     cc::OverlayCandidate candidate;
-    if (cc::OverlayCandidate::FromDrawQuad(resource_provider, *it,
-                                           &candidate) &&
+    if (cc::OverlayCandidate::FromDrawQuad(
+            resource_provider, output_color_matrix, *it, &candidate) &&
         !cc::OverlayCandidate::IsOccluded(candidate, quad_list->cbegin(), it)) {
       // We currently reject quads with alpha that do not request alpha blending
       // since the alpha channel might not be set to 1 and we're not disabling
diff --git a/components/viz/service/display/overlay_strategy_single_on_top.h b/components/viz/service/display/overlay_strategy_single_on_top.h
index fe5b78d0..0a50ffa 100644
--- a/components/viz/service/display/overlay_strategy_single_on_top.h
+++ b/components/viz/service/display/overlay_strategy_single_on_top.h
@@ -20,7 +20,8 @@
       OverlayCandidateValidator* capability_checker);
   ~OverlayStrategySingleOnTop() override;
 
-  bool Attempt(cc::DisplayResourceProvider* resource_provider,
+  bool Attempt(const SkMatrix44& output_color_matrix,
+               cc::DisplayResourceProvider* resource_provider,
                RenderPass* render_pass,
                cc::OverlayCandidateList* candidate_list,
                std::vector<gfx::Rect>* content_bounds) override;
diff --git a/components/viz/service/display/overlay_strategy_underlay.cc b/components/viz/service/display/overlay_strategy_underlay.cc
index c1da310..0460321 100644
--- a/components/viz/service/display/overlay_strategy_underlay.cc
+++ b/components/viz/service/display/overlay_strategy_underlay.cc
@@ -19,6 +19,7 @@
 OverlayStrategyUnderlay::~OverlayStrategyUnderlay() {}
 
 bool OverlayStrategyUnderlay::Attempt(
+    const SkMatrix44& output_color_matrix,
     cc::DisplayResourceProvider* resource_provider,
     RenderPass* render_pass,
     cc::OverlayCandidateList* candidate_list,
@@ -26,8 +27,10 @@
   QuadList& quad_list = render_pass->quad_list;
   for (auto it = quad_list.begin(); it != quad_list.end(); ++it) {
     cc::OverlayCandidate candidate;
-    if (!cc::OverlayCandidate::FromDrawQuad(resource_provider, *it, &candidate))
+    if (!cc::OverlayCandidate::FromDrawQuad(
+            resource_provider, output_color_matrix, *it, &candidate)) {
       continue;
+    }
 
     // Add the overlay.
     cc::OverlayCandidateList new_candidate_list = *candidate_list;
diff --git a/components/viz/service/display/overlay_strategy_underlay.h b/components/viz/service/display/overlay_strategy_underlay.h
index 33a533d2..4537177 100644
--- a/components/viz/service/display/overlay_strategy_underlay.h
+++ b/components/viz/service/display/overlay_strategy_underlay.h
@@ -25,7 +25,8 @@
       OverlayCandidateValidator* capability_checker);
   ~OverlayStrategyUnderlay() override;
 
-  bool Attempt(cc::DisplayResourceProvider* resource_provider,
+  bool Attempt(const SkMatrix44& output_color_matrix,
+               cc::DisplayResourceProvider* resource_provider,
                RenderPass* render_pass,
                cc::OverlayCandidateList* candidate_list,
                std::vector<gfx::Rect>* content_bounds) override;
diff --git a/components/viz/service/display/overlay_strategy_underlay_cast.cc b/components/viz/service/display/overlay_strategy_underlay_cast.cc
index 5e9bec8..3466447 100644
--- a/components/viz/service/display/overlay_strategy_underlay_cast.cc
+++ b/components/viz/service/display/overlay_strategy_underlay_cast.cc
@@ -18,6 +18,7 @@
 OverlayStrategyUnderlayCast::~OverlayStrategyUnderlayCast() {}
 
 bool OverlayStrategyUnderlayCast::Attempt(
+    const SkMatrix44& output_color_matrix,
     cc::DisplayResourceProvider* resource_provider,
     RenderPass* render_pass,
     cc::OverlayCandidateList* candidate_list,
@@ -36,8 +37,8 @@
     bool is_underlay = false;
     if (!found_underlay) {
       cc::OverlayCandidate candidate;
-      is_underlay = cc::OverlayCandidate::FromDrawQuad(resource_provider, quad,
-                                                       &candidate);
+      is_underlay = cc::OverlayCandidate::FromDrawQuad(
+          resource_provider, output_color_matrix, quad, &candidate);
       found_underlay = is_underlay;
     }
 
@@ -55,7 +56,8 @@
   }
 
   const bool result = OverlayStrategyUnderlay::Attempt(
-      resource_provider, render_pass, candidate_list, content_bounds);
+      output_color_matrix, resource_provider, render_pass, candidate_list,
+      content_bounds);
   DCHECK(content_bounds && content_bounds->empty());
   DCHECK(result == found_underlay);
   if (found_underlay) {
diff --git a/components/viz/service/display/overlay_strategy_underlay_cast.h b/components/viz/service/display/overlay_strategy_underlay_cast.h
index dff9682..d8dec12 100644
--- a/components/viz/service/display/overlay_strategy_underlay_cast.h
+++ b/components/viz/service/display/overlay_strategy_underlay_cast.h
@@ -21,7 +21,8 @@
       OverlayCandidateValidator* capability_checker);
   ~OverlayStrategyUnderlayCast() override;
 
-  bool Attempt(cc::DisplayResourceProvider* resource_provider,
+  bool Attempt(const SkMatrix44& output_color_matrix,
+               cc::DisplayResourceProvider* resource_provider,
                RenderPass* render_pass,
                cc::OverlayCandidateList* candidate_list,
                std::vector<gfx::Rect>* content_bounds) override;
diff --git a/components/viz/service/display/overlay_unittest.cc b/components/viz/service/display/overlay_unittest.cc
index 3020bde8..f1fc201e 100644
--- a/components/viz/service/display/overlay_unittest.cc
+++ b/components/viz/service/display/overlay_unittest.cc
@@ -477,6 +477,17 @@
   }
 }
 
+SkMatrix44 GetIdentityColorMatrix() {
+  return SkMatrix44(SkMatrix44::kIdentity_Constructor);
+}
+
+SkMatrix GetNonIdentityColorMatrix() {
+  SkMatrix44 matrix = GetIdentityColorMatrix();
+  matrix.set(1, 1, 0.5f);
+  matrix.set(2, 2, 0.5f);
+  return matrix;
+}
+
 template <typename OverlayCandidateValidatorType>
 class OverlayTest : public testing::Test {
   using OutputSurfaceType = OverlayOutputSurface<OverlayCandidateValidatorType>;
@@ -575,9 +586,9 @@
   pass_list.push_back(std::move(pass));
 
   overlay_processor_->ProcessForOverlays(
-      resource_provider_.get(), &pass_list, render_pass_filters,
-      render_pass_background_filters, &candidate_list, nullptr, nullptr,
-      &damage_rect_, &content_bounds_);
+      resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
+      render_pass_filters, render_pass_background_filters, &candidate_list,
+      nullptr, nullptr, &damage_rect_, &content_bounds_);
   ASSERT_EQ(1U, candidate_list.size());
 
   // Check that all the quads are gone.
@@ -591,6 +602,36 @@
   EXPECT_EQ(output_rect, overlay_damage_rect);
 }
 
+TEST_F(FullscreenOverlayTest, FailOnOutputColorMatrix) {
+  std::unique_ptr<RenderPass> pass = CreateRenderPass();
+  CreateFullscreenCandidateQuad(
+      resource_provider_.get(), child_resource_provider_.get(),
+      pass->shared_quad_state_list.back(), pass.get());
+
+  // Add something behind it.
+  CreateFullscreenOpaqueQuad(resource_provider_.get(),
+                             pass->shared_quad_state_list.back(), pass.get());
+
+  // Check for potential candidates.
+  cc::OverlayCandidateList candidate_list;
+  OverlayProcessor::FilterOperationsMap render_pass_filters;
+  OverlayProcessor::FilterOperationsMap render_pass_background_filters;
+  RenderPassList pass_list;
+  RenderPass* main_pass = pass.get();
+  pass_list.push_back(std::move(pass));
+
+  // This is passing a non-identity color matrix which will result in disabling
+  // overlays since color matrices are not supported yet.
+  overlay_processor_->ProcessForOverlays(
+      resource_provider_.get(), &pass_list, GetNonIdentityColorMatrix(),
+      render_pass_filters, render_pass_background_filters, &candidate_list,
+      nullptr, nullptr, &damage_rect_, &content_bounds_);
+  ASSERT_EQ(0U, candidate_list.size());
+
+  // Check that the 2 quads are not gone.
+  EXPECT_EQ(2U, main_pass->quad_list.size());
+}
+
 TEST_F(FullscreenOverlayTest, AlphaFail) {
   std::unique_ptr<RenderPass> pass = CreateRenderPass();
   CreateTransparentCandidateQuadAt(
@@ -606,9 +647,9 @@
   pass_list.push_back(std::move(pass));
 
   overlay_processor_->ProcessForOverlays(
-      resource_provider_.get(), &pass_list, render_pass_filters,
-      render_pass_background_filters, &candidate_list, nullptr, nullptr,
-      &damage_rect_, &content_bounds_);
+      resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
+      render_pass_filters, render_pass_background_filters, &candidate_list,
+      nullptr, nullptr, &damage_rect_, &content_bounds_);
 
   // Check that all the quads are gone.
   EXPECT_EQ(1U, main_pass->quad_list.size());
@@ -632,9 +673,9 @@
   pass_list.push_back(std::move(pass));
 
   overlay_processor_->ProcessForOverlays(
-      resource_provider_.get(), &pass_list, render_pass_filters,
-      render_pass_background_filters, &candidate_list, nullptr, nullptr,
-      &damage_rect_, &content_bounds_);
+      resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
+      render_pass_filters, render_pass_background_filters, &candidate_list,
+      nullptr, nullptr, &damage_rect_, &content_bounds_);
   ASSERT_EQ(0U, candidate_list.size());
 
   // Check that the quad is not gone.
@@ -662,9 +703,9 @@
   pass_list.push_back(std::move(pass));
 
   overlay_processor_->ProcessForOverlays(
-      resource_provider_.get(), &pass_list, render_pass_filters,
-      render_pass_background_filters, &candidate_list, nullptr, nullptr,
-      &damage_rect_, &content_bounds_);
+      resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
+      render_pass_filters, render_pass_background_filters, &candidate_list,
+      nullptr, nullptr, &damage_rect_, &content_bounds_);
   ASSERT_EQ(0U, candidate_list.size());
 
   // Check that the 2 quads are not gone.
@@ -687,9 +728,9 @@
   RenderPass* main_pass = pass.get();
   pass_list.push_back(std::move(pass));
   overlay_processor_->ProcessForOverlays(
-      resource_provider_.get(), &pass_list, render_pass_filters,
-      render_pass_background_filters, &candidate_list, nullptr, nullptr,
-      &damage_rect_, &content_bounds_);
+      resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
+      render_pass_filters, render_pass_background_filters, &candidate_list,
+      nullptr, nullptr, &damage_rect_, &content_bounds_);
   ASSERT_EQ(0U, candidate_list.size());
 
   // Check that the quad is not gone.
@@ -719,9 +760,9 @@
   RenderPass* main_pass = pass.get();
   pass_list.push_back(std::move(pass));
   overlay_processor_->ProcessForOverlays(
-      resource_provider_.get(), &pass_list, render_pass_filters,
-      render_pass_background_filters, &candidate_list, nullptr, nullptr,
-      &damage_rect_, &content_bounds_);
+      resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
+      render_pass_filters, render_pass_background_filters, &candidate_list,
+      nullptr, nullptr, &damage_rect_, &content_bounds_);
   ASSERT_EQ(1U, candidate_list.size());
 
   // Check that the fullscreen quad is gone.
@@ -751,9 +792,9 @@
   RenderPass* main_pass = pass.get();
   pass_list.push_back(std::move(pass));
   overlay_processor_->ProcessForOverlays(
-      resource_provider_.get(), &pass_list, render_pass_filters,
-      render_pass_background_filters, &candidate_list, nullptr, nullptr,
-      &damage_rect_, &content_bounds_);
+      resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
+      render_pass_filters, render_pass_background_filters, &candidate_list,
+      nullptr, nullptr, &damage_rect_, &content_bounds_);
   ASSERT_EQ(1U, candidate_list.size());
 
   // Check that the quad is gone.
@@ -800,9 +841,9 @@
   RenderPass* main_pass = pass.get();
   pass_list.push_back(std::move(pass));
   overlay_processor_->ProcessForOverlays(
-      resource_provider_.get(), &pass_list, render_pass_filters,
-      render_pass_background_filters, &candidate_list, nullptr, nullptr,
-      &damage_rect_, &content_bounds_);
+      resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
+      render_pass_filters, render_pass_background_filters, &candidate_list,
+      nullptr, nullptr, &damage_rect_, &content_bounds_);
   ASSERT_EQ(1U, candidate_list.size());
 
   // Check that one quad is gone.
@@ -841,9 +882,9 @@
   RenderPassList pass_list;
   pass_list.push_back(std::move(pass));
   overlay_processor_->ProcessForOverlays(
-      resource_provider_.get(), &pass_list, render_pass_filters,
-      render_pass_background_filters, &candidate_list, nullptr, nullptr,
-      &damage_rect_, &content_bounds_);
+      resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
+      render_pass_filters, render_pass_background_filters, &candidate_list,
+      nullptr, nullptr, &damage_rect_, &content_bounds_);
   EXPECT_TRUE(damage_rect_.IsEmpty());
 }
 
@@ -864,9 +905,9 @@
   OverlayProcessor::FilterOperationsMap render_pass_filters;
   OverlayProcessor::FilterOperationsMap render_pass_background_filters;
   overlay_processor_->ProcessForOverlays(
-      resource_provider_.get(), &pass_list, render_pass_filters,
-      render_pass_background_filters, &candidate_list, nullptr, nullptr,
-      &damage_rect_, &content_bounds_);
+      resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
+      render_pass_filters, render_pass_background_filters, &candidate_list,
+      nullptr, nullptr, &damage_rect_, &content_bounds_);
   EXPECT_EQ(0U, candidate_list.size());
   // There should be nothing new here.
   CompareRenderPassLists(pass_list, original_pass_list);
@@ -893,9 +934,9 @@
   OverlayProcessor::FilterOperationsMap render_pass_filters;
   OverlayProcessor::FilterOperationsMap render_pass_background_filters;
   overlay_processor_->ProcessForOverlays(
-      resource_provider_.get(), &pass_list, render_pass_filters,
-      render_pass_background_filters, &candidate_list, nullptr, nullptr,
-      &damage_rect_, &content_bounds_);
+      resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
+      render_pass_filters, render_pass_background_filters, &candidate_list,
+      nullptr, nullptr, &damage_rect_, &content_bounds_);
   EXPECT_EQ(0U, candidate_list.size());
   // There should be nothing new here.
   CompareRenderPassLists(pass_list, original_pass_list);
@@ -921,9 +962,9 @@
   RenderPassList pass_list;
   pass_list.push_back(std::move(pass));
   overlay_processor_->ProcessForOverlays(
-      resource_provider_.get(), &pass_list, render_pass_filters,
-      render_pass_background_filters, &candidate_list, nullptr, nullptr,
-      &damage_rect_, &content_bounds_);
+      resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
+      render_pass_filters, render_pass_background_filters, &candidate_list,
+      nullptr, nullptr, &damage_rect_, &content_bounds_);
   EXPECT_EQ(1U, candidate_list.size());
 }
 
@@ -941,9 +982,9 @@
   RenderPassList pass_list;
   pass_list.push_back(std::move(pass));
   overlay_processor_->ProcessForOverlays(
-      resource_provider_.get(), &pass_list, render_pass_filters,
-      render_pass_background_filters, &candidate_list, nullptr, nullptr,
-      &damage_rect_, &content_bounds_);
+      resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
+      render_pass_filters, render_pass_background_filters, &candidate_list,
+      nullptr, nullptr, &damage_rect_, &content_bounds_);
   EXPECT_EQ(1U, candidate_list.size());
   EXPECT_FALSE(damage_rect_.IsEmpty());
   gfx::Rect overlay_damage_rect =
@@ -964,9 +1005,9 @@
   RenderPassList pass_list;
   pass_list.push_back(std::move(pass));
   overlay_processor_->ProcessForOverlays(
-      resource_provider_.get(), &pass_list, render_pass_filters,
-      render_pass_background_filters, &candidate_list, nullptr, nullptr,
-      &damage_rect_, &content_bounds_);
+      resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
+      render_pass_filters, render_pass_background_filters, &candidate_list,
+      nullptr, nullptr, &damage_rect_, &content_bounds_);
   EXPECT_EQ(0U, candidate_list.size());
 }
 
@@ -983,9 +1024,9 @@
   RenderPassList pass_list;
   pass_list.push_back(std::move(pass));
   overlay_processor_->ProcessForOverlays(
-      resource_provider_.get(), &pass_list, render_pass_filters,
-      render_pass_background_filters, &candidate_list, nullptr, nullptr,
-      &damage_rect_, &content_bounds_);
+      resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
+      render_pass_filters, render_pass_background_filters, &candidate_list,
+      nullptr, nullptr, &damage_rect_, &content_bounds_);
   EXPECT_EQ(0U, candidate_list.size());
 }
 
@@ -1002,9 +1043,9 @@
   RenderPassList pass_list;
   pass_list.push_back(std::move(pass));
   overlay_processor_->ProcessForOverlays(
-      resource_provider_.get(), &pass_list, render_pass_filters,
-      render_pass_background_filters, &candidate_list, nullptr, nullptr,
-      &damage_rect_, &content_bounds_);
+      resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
+      render_pass_filters, render_pass_background_filters, &candidate_list,
+      nullptr, nullptr, &damage_rect_, &content_bounds_);
   EXPECT_EQ(0U, candidate_list.size());
 }
 
@@ -1022,9 +1063,9 @@
   RenderPassList pass_list;
   pass_list.push_back(std::move(pass));
   overlay_processor_->ProcessForOverlays(
-      resource_provider_.get(), &pass_list, render_pass_filters,
-      render_pass_background_filters, &candidate_list, nullptr, nullptr,
-      &damage_rect_, &content_bounds_);
+      resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
+      render_pass_filters, render_pass_background_filters, &candidate_list,
+      nullptr, nullptr, &damage_rect_, &content_bounds_);
   EXPECT_EQ(0U, candidate_list.size());
 }
 
@@ -1042,9 +1083,9 @@
   RenderPassList pass_list;
   pass_list.push_back(std::move(pass));
   overlay_processor_->ProcessForOverlays(
-      resource_provider_.get(), &pass_list, render_pass_filters,
-      render_pass_background_filters, &candidate_list, nullptr, nullptr,
-      &damage_rect_, &content_bounds_);
+      resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
+      render_pass_filters, render_pass_background_filters, &candidate_list,
+      nullptr, nullptr, &damage_rect_, &content_bounds_);
   EXPECT_EQ(1U, candidate_list.size());
 }
 
@@ -1064,9 +1105,9 @@
   RenderPassList pass_list;
   pass_list.push_back(std::move(pass));
   overlay_processor_->ProcessForOverlays(
-      resource_provider_.get(), &pass_list, render_pass_filters,
-      render_pass_background_filters, &candidate_list, nullptr, nullptr,
-      &damage_rect_, &content_bounds_);
+      resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
+      render_pass_filters, render_pass_background_filters, &candidate_list,
+      nullptr, nullptr, &damage_rect_, &content_bounds_);
   ASSERT_EQ(1U, candidate_list.size());
   EXPECT_EQ(gfx::OVERLAY_TRANSFORM_FLIP_VERTICAL,
             candidate_list.back().transform);
@@ -1089,9 +1130,9 @@
   RenderPassList pass_list;
   pass_list.push_back(std::move(pass));
   overlay_processor_->ProcessForOverlays(
-      resource_provider_.get(), &pass_list, render_pass_filters,
-      render_pass_background_filters, &candidate_list, nullptr, nullptr,
-      &damage_rect_, &content_bounds_);
+      resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
+      render_pass_filters, render_pass_background_filters, &candidate_list,
+      nullptr, nullptr, &damage_rect_, &content_bounds_);
   ASSERT_EQ(1U, candidate_list.size());
   EXPECT_EQ(gfx::OVERLAY_TRANSFORM_FLIP_HORIZONTAL,
             candidate_list.back().transform);
@@ -1112,9 +1153,9 @@
   RenderPassList pass_list;
   pass_list.push_back(std::move(pass));
   overlay_processor_->ProcessForOverlays(
-      resource_provider_.get(), &pass_list, render_pass_filters,
-      render_pass_background_filters, &candidate_list, nullptr, nullptr,
-      &damage_rect_, &content_bounds_);
+      resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
+      render_pass_filters, render_pass_background_filters, &candidate_list,
+      nullptr, nullptr, &damage_rect_, &content_bounds_);
   EXPECT_EQ(1U, candidate_list.size());
 }
 
@@ -1134,9 +1175,9 @@
   RenderPassList pass_list;
   pass_list.push_back(std::move(pass));
   overlay_processor_->ProcessForOverlays(
-      resource_provider_.get(), &pass_list, render_pass_filters,
-      render_pass_background_filters, &candidate_list, nullptr, nullptr,
-      &damage_rect_, &content_bounds_);
+      resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
+      render_pass_filters, render_pass_background_filters, &candidate_list,
+      nullptr, nullptr, &damage_rect_, &content_bounds_);
   ASSERT_EQ(1U, candidate_list.size());
 }
 
@@ -1156,9 +1197,9 @@
   RenderPassList pass_list;
   pass_list.push_back(std::move(pass));
   overlay_processor_->ProcessForOverlays(
-      resource_provider_.get(), &pass_list, render_pass_filters,
-      render_pass_background_filters, &candidate_list, nullptr, nullptr,
-      &damage_rect_, &content_bounds_);
+      resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
+      render_pass_filters, render_pass_background_filters, &candidate_list,
+      nullptr, nullptr, &damage_rect_, &content_bounds_);
   ASSERT_EQ(1U, candidate_list.size());
   EXPECT_EQ(gfx::OVERLAY_TRANSFORM_ROTATE_90, candidate_list.back().transform);
 }
@@ -1179,9 +1220,9 @@
   RenderPassList pass_list;
   pass_list.push_back(std::move(pass));
   overlay_processor_->ProcessForOverlays(
-      resource_provider_.get(), &pass_list, render_pass_filters,
-      render_pass_background_filters, &candidate_list, nullptr, nullptr,
-      &damage_rect_, &content_bounds_);
+      resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
+      render_pass_filters, render_pass_background_filters, &candidate_list,
+      nullptr, nullptr, &damage_rect_, &content_bounds_);
   ASSERT_EQ(1U, candidate_list.size());
   EXPECT_EQ(gfx::OVERLAY_TRANSFORM_ROTATE_180, candidate_list.back().transform);
 }
@@ -1202,9 +1243,9 @@
   RenderPassList pass_list;
   pass_list.push_back(std::move(pass));
   overlay_processor_->ProcessForOverlays(
-      resource_provider_.get(), &pass_list, render_pass_filters,
-      render_pass_background_filters, &candidate_list, nullptr, nullptr,
-      &damage_rect_, &content_bounds_);
+      resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
+      render_pass_filters, render_pass_background_filters, &candidate_list,
+      nullptr, nullptr, &damage_rect_, &content_bounds_);
   ASSERT_EQ(1U, candidate_list.size());
   EXPECT_EQ(gfx::OVERLAY_TRANSFORM_ROTATE_270, candidate_list.back().transform);
 }
@@ -1227,9 +1268,9 @@
   RenderPassList pass_list;
   pass_list.push_back(std::move(pass));
   overlay_processor_->ProcessForOverlays(
-      resource_provider_.get(), &pass_list, render_pass_filters,
-      render_pass_background_filters, &candidate_list, nullptr, nullptr,
-      &damage_rect_, &content_bounds_);
+      resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
+      render_pass_filters, render_pass_background_filters, &candidate_list,
+      nullptr, nullptr, &damage_rect_, &content_bounds_);
   EXPECT_EQ(1U, candidate_list.size());
 }
 
@@ -1254,9 +1295,9 @@
   RenderPassList pass_list;
   pass_list.push_back(std::move(pass));
   overlay_processor_->ProcessForOverlays(
-      resource_provider_.get(), &pass_list, render_pass_filters,
-      render_pass_background_filters, &candidate_list, nullptr, nullptr,
-      &damage_rect_, &content_bounds_);
+      resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
+      render_pass_filters, render_pass_background_filters, &candidate_list,
+      nullptr, nullptr, &damage_rect_, &content_bounds_);
   EXPECT_EQ(1U, candidate_list.size());
 }
 
@@ -1278,9 +1319,9 @@
   RenderPassList pass_list;
   pass_list.push_back(std::move(pass));
   overlay_processor_->ProcessForOverlays(
-      resource_provider_.get(), &pass_list, render_pass_filters,
-      render_pass_background_filters, &candidate_list, nullptr, nullptr,
-      &damage_rect_, &content_bounds_);
+      resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
+      render_pass_filters, render_pass_background_filters, &candidate_list,
+      nullptr, nullptr, &damage_rect_, &content_bounds_);
   EXPECT_EQ(1U, candidate_list.size());
 }
 
@@ -1302,9 +1343,9 @@
   RenderPassList pass_list;
   pass_list.push_back(std::move(pass));
   overlay_processor_->ProcessForOverlays(
-      resource_provider_.get(), &pass_list, render_pass_filters,
-      render_pass_background_filters, &candidate_list, nullptr, nullptr,
-      &damage_rect_, &content_bounds_);
+      resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
+      render_pass_filters, render_pass_background_filters, &candidate_list,
+      nullptr, nullptr, &damage_rect_, &content_bounds_);
   EXPECT_EQ(0U, candidate_list.size());
 }
 
@@ -1324,9 +1365,9 @@
   RenderPassList pass_list;
   pass_list.push_back(std::move(pass));
   overlay_processor_->ProcessForOverlays(
-      resource_provider_.get(), &pass_list, render_pass_filters,
-      render_pass_background_filters, &candidate_list, nullptr, nullptr,
-      &damage_rect_, &content_bounds_);
+      resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
+      render_pass_filters, render_pass_background_filters, &candidate_list,
+      nullptr, nullptr, &damage_rect_, &content_bounds_);
   EXPECT_EQ(0U, candidate_list.size());
 }
 
@@ -1342,9 +1383,9 @@
   RenderPassList pass_list;
   pass_list.push_back(std::move(pass));
   overlay_processor_->ProcessForOverlays(
-      resource_provider_.get(), &pass_list, render_pass_filters,
-      render_pass_background_filters, &candidate_list, nullptr, nullptr,
-      &damage_rect_, &content_bounds_);
+      resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
+      render_pass_filters, render_pass_background_filters, &candidate_list,
+      nullptr, nullptr, &damage_rect_, &content_bounds_);
   EXPECT_EQ(0U, candidate_list.size());
 }
 
@@ -1360,9 +1401,9 @@
   RenderPassList pass_list;
   pass_list.push_back(std::move(pass));
   overlay_processor_->ProcessForOverlays(
-      resource_provider_.get(), &pass_list, render_pass_filters,
-      render_pass_background_filters, &candidate_list, nullptr, nullptr,
-      &damage_rect_, &content_bounds_);
+      resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
+      render_pass_filters, render_pass_background_filters, &candidate_list,
+      nullptr, nullptr, &damage_rect_, &content_bounds_);
   EXPECT_EQ(1U, candidate_list.size());
 }
 
@@ -1378,9 +1419,9 @@
   RenderPassList pass_list;
   pass_list.push_back(std::move(pass));
   overlay_processor_->ProcessForOverlays(
-      resource_provider_.get(), &pass_list, render_pass_filters,
-      render_pass_background_filters, &candidate_list, nullptr, nullptr,
-      &damage_rect_, &content_bounds_);
+      resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
+      render_pass_filters, render_pass_background_filters, &candidate_list,
+      nullptr, nullptr, &damage_rect_, &content_bounds_);
   EXPECT_EQ(1U, candidate_list.size());
 }
 
@@ -1396,9 +1437,9 @@
   RenderPassList pass_list;
   pass_list.push_back(std::move(pass));
   overlay_processor_->ProcessForOverlays(
-      resource_provider_.get(), &pass_list, render_pass_filters,
-      render_pass_background_filters, &candidate_list, nullptr, nullptr,
-      &damage_rect_, &content_bounds_);
+      resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
+      render_pass_filters, render_pass_background_filters, &candidate_list,
+      nullptr, nullptr, &damage_rect_, &content_bounds_);
   EXPECT_EQ(1U, candidate_list.size());
 }
 
@@ -1414,9 +1455,9 @@
   RenderPassList pass_list;
   pass_list.push_back(std::move(pass));
   overlay_processor_->ProcessForOverlays(
-      resource_provider_.get(), &pass_list, render_pass_filters,
-      render_pass_background_filters, &candidate_list, nullptr, nullptr,
-      &damage_rect_, &content_bounds_);
+      resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
+      render_pass_filters, render_pass_background_filters, &candidate_list,
+      nullptr, nullptr, &damage_rect_, &content_bounds_);
   EXPECT_EQ(1U, candidate_list.size());
 }
 
@@ -1438,9 +1479,9 @@
   RenderPass* main_pass = pass.get();
   pass_list.push_back(std::move(pass));
   overlay_processor_->ProcessForOverlays(
-      resource_provider_.get(), &pass_list, render_pass_filters,
-      render_pass_background_filters, &candidate_list, nullptr, nullptr,
-      &damage_rect_, &content_bounds_);
+      resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
+      render_pass_filters, render_pass_background_filters, &candidate_list,
+      nullptr, nullptr, &damage_rect_, &content_bounds_);
   ASSERT_EQ(1U, candidate_list.size());
   EXPECT_EQ(-1, candidate_list[0].plane_z_order);
   EXPECT_EQ(2U, main_pass->quad_list.size());
@@ -1468,9 +1509,9 @@
   RenderPass* main_pass = pass.get();
   pass_list.push_back(std::move(pass));
   overlay_processor_->ProcessForOverlays(
-      resource_provider_.get(), &pass_list, render_pass_filters,
-      render_pass_background_filters, &candidate_list, nullptr, nullptr,
-      &damage_rect_, &content_bounds_);
+      resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
+      render_pass_filters, render_pass_background_filters, &candidate_list,
+      nullptr, nullptr, &damage_rect_, &content_bounds_);
   ASSERT_EQ(1U, candidate_list.size());
   EXPECT_EQ(-1, candidate_list[0].plane_z_order);
   // The overlay quad should have changed to a SOLID_COLOR quad.
@@ -1496,9 +1537,9 @@
   RenderPassList pass_list;
   pass_list.push_back(std::move(pass));
   overlay_processor_->ProcessForOverlays(
-      resource_provider_.get(), &pass_list, render_pass_filters,
-      render_pass_background_filters, &candidate_list, nullptr, nullptr,
-      &damage_rect_, &content_bounds_);
+      resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
+      render_pass_filters, render_pass_background_filters, &candidate_list,
+      nullptr, nullptr, &damage_rect_, &content_bounds_);
 
   EXPECT_EQ(kOverlayRect, damage_rect_);
 }
@@ -1524,9 +1565,9 @@
     RenderPassList pass_list;
     pass_list.push_back(std::move(pass));
     overlay_processor_->ProcessForOverlays(
-        resource_provider_.get(), &pass_list, render_pass_filters,
-        render_pass_background_filters, &candidate_list, nullptr, nullptr,
-        &damage_rect_, &content_bounds_);
+        resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
+        render_pass_filters, render_pass_background_filters, &candidate_list,
+        nullptr, nullptr, &damage_rect_, &content_bounds_);
   }
 
   // The second time the same overlay rect is scheduled it will be subtracted
@@ -1556,9 +1597,9 @@
     RenderPassList pass_list;
     pass_list.push_back(std::move(pass));
     overlay_processor_->ProcessForOverlays(
-        resource_provider_.get(), &pass_list, render_pass_filters,
-        render_pass_background_filters, &candidate_list, nullptr, nullptr,
-        &damage_rect_, &content_bounds_);
+        resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
+        render_pass_filters, render_pass_background_filters, &candidate_list,
+        nullptr, nullptr, &damage_rect_, &content_bounds_);
 
     EXPECT_EQ(overlay_rects[i], damage_rect_);
   }
@@ -1590,9 +1631,9 @@
     RenderPassList pass_list;
     pass_list.push_back(std::move(pass));
     overlay_processor_->ProcessForOverlays(
-        resource_provider_.get(), &pass_list, render_pass_filters,
-        render_pass_background_filters, &candidate_list, nullptr, nullptr,
-        &damage_rect_, &content_bounds_);
+        resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
+        render_pass_filters, render_pass_background_filters, &candidate_list,
+        nullptr, nullptr, &damage_rect_, &content_bounds_);
   }
 
   EXPECT_EQ(kOverlayRect, damage_rect_);
@@ -1616,9 +1657,9 @@
     RenderPassList pass_list;
     pass_list.push_back(std::move(pass));
     overlay_processor_->ProcessForOverlays(
-        resource_provider_.get(), &pass_list, render_pass_filters,
-        render_pass_background_filters, &candidate_list, nullptr, nullptr,
-        &damage_rect_, &content_bounds_);
+        resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
+        render_pass_filters, render_pass_background_filters, &candidate_list,
+        nullptr, nullptr, &damage_rect_, &content_bounds_);
   }
 
   EXPECT_EQ(kOverlayRect, damage_rect_);
@@ -1647,9 +1688,9 @@
     RenderPassList pass_list;
     pass_list.push_back(std::move(pass));
     overlay_processor_->ProcessForOverlays(
-        resource_provider_.get(), &pass_list, render_pass_filters,
-        render_pass_background_filters, &candidate_list, nullptr, nullptr,
-        &damage_rect_, &content_bounds_);
+        resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
+        render_pass_filters, render_pass_background_filters, &candidate_list,
+        nullptr, nullptr, &damage_rect_, &content_bounds_);
   }
 
   EXPECT_TRUE(damage_rect_.IsEmpty());
@@ -1668,9 +1709,9 @@
   RenderPassList pass_list;
   pass_list.push_back(std::move(pass));
   overlay_processor_->ProcessForOverlays(
-      resource_provider_.get(), &pass_list, render_pass_filters,
-      render_pass_background_filters, &candidate_list, nullptr, nullptr,
-      &damage_rect_, &content_bounds_);
+      resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
+      render_pass_filters, render_pass_background_filters, &candidate_list,
+      nullptr, nullptr, &damage_rect_, &content_bounds_);
   EXPECT_EQ(0U, content_bounds_.size());
 }
 
@@ -1686,9 +1727,9 @@
   RenderPassList pass_list;
   pass_list.push_back(std::move(pass));
   overlay_processor_->ProcessForOverlays(
-      resource_provider_.get(), &pass_list, render_pass_filters,
-      render_pass_background_filters, &candidate_list, nullptr, nullptr,
-      &damage_rect_, &content_bounds_);
+      resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
+      render_pass_filters, render_pass_background_filters, &candidate_list,
+      nullptr, nullptr, &damage_rect_, &content_bounds_);
 
   EXPECT_EQ(1U, content_bounds_.size());
   EXPECT_TRUE(content_bounds_[0].IsEmpty());
@@ -1718,9 +1759,9 @@
   RenderPassList pass_list;
   pass_list.push_back(std::move(pass));
   overlay_processor_->ProcessForOverlays(
-      resource_provider_.get(), &pass_list, render_pass_filters,
-      render_pass_background_filters, &candidate_list, nullptr, nullptr,
-      &damage_rect_, &content_bounds_);
+      resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
+      render_pass_filters, render_pass_background_filters, &candidate_list,
+      nullptr, nullptr, &damage_rect_, &content_bounds_);
 
   EXPECT_EQ(1U, content_bounds_.size());
   EXPECT_TRUE(content_bounds_[0].IsEmpty());
@@ -1741,9 +1782,9 @@
   RenderPassList pass_list;
   pass_list.push_back(std::move(pass));
   overlay_processor_->ProcessForOverlays(
-      resource_provider_.get(), &pass_list, render_pass_filters,
-      render_pass_background_filters, &candidate_list, nullptr, nullptr,
-      &damage_rect_, &content_bounds_);
+      resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
+      render_pass_filters, render_pass_background_filters, &candidate_list,
+      nullptr, nullptr, &damage_rect_, &content_bounds_);
 
   EXPECT_EQ(1U, content_bounds_.size());
   EXPECT_EQ(kOverlayTopLeftRect, content_bounds_[0]);
@@ -1767,9 +1808,9 @@
   RenderPassList pass_list;
   pass_list.push_back(std::move(pass));
   overlay_processor_->ProcessForOverlays(
-      resource_provider_.get(), &pass_list, render_pass_filters,
-      render_pass_background_filters, &candidate_list, nullptr, nullptr,
-      &damage_rect_, &content_bounds_);
+      resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
+      render_pass_filters, render_pass_background_filters, &candidate_list,
+      nullptr, nullptr, &damage_rect_, &content_bounds_);
 
   EXPECT_EQ(1U, content_bounds_.size());
   EXPECT_EQ(kOverlayRect, content_bounds_[0]);
@@ -1799,9 +1840,9 @@
   RenderPassList pass_list;
   pass_list.push_back(std::move(pass));
   overlay_processor_->ProcessForOverlays(
-      resource_provider_.get(), &pass_list, render_pass_filters,
-      render_pass_background_filters, &candidate_list, nullptr, nullptr,
-      &damage_rect_, &content_bounds_);
+      resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
+      render_pass_filters, render_pass_background_filters, &candidate_list,
+      nullptr, nullptr, &damage_rect_, &content_bounds_);
 
   EXPECT_EQ(1U, content_bounds_.size());
   EXPECT_EQ(gfx::Rect(0, 0, 11, 11), content_bounds_[0]);
@@ -1832,9 +1873,9 @@
   RenderPassList pass_list;
   pass_list.push_back(std::move(pass));
   overlay_processor_->ProcessForOverlays(
-      resource_provider_.get(), &pass_list, render_pass_filters,
-      render_pass_background_filters, &candidate_list, nullptr, nullptr,
-      &damage_rect_, &content_bounds_);
+      resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
+      render_pass_filters, render_pass_background_filters, &candidate_list,
+      nullptr, nullptr, &damage_rect_, &content_bounds_);
 
   EXPECT_EQ(1U, content_bounds_.size());
   EXPECT_EQ(kOverlayRect, content_bounds_[0]);
@@ -1867,9 +1908,9 @@
   RenderPassList pass_list;
   pass_list.push_back(std::move(pass));
   overlay_processor_->ProcessForOverlays(
-      resource_provider_.get(), &pass_list, render_pass_filters,
-      render_pass_background_filters, &overlay_list, &ca_layer_list, nullptr,
-      &damage_rect_, &content_bounds_);
+      resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
+      render_pass_filters, render_pass_background_filters, &overlay_list,
+      &ca_layer_list, nullptr, &damage_rect_, &content_bounds_);
   EXPECT_EQ(gfx::Rect(), damage_rect);
   EXPECT_EQ(0U, overlay_list.size());
   EXPECT_EQ(1U, ca_layer_list.size());
@@ -1891,9 +1932,9 @@
   RenderPassList pass_list;
   pass_list.push_back(std::move(pass));
   overlay_processor_->ProcessForOverlays(
-      resource_provider_.get(), &pass_list, render_pass_filters,
-      render_pass_background_filters, &overlay_list, &ca_layer_list, nullptr,
-      &damage_rect_, &content_bounds_);
+      resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
+      render_pass_filters, render_pass_background_filters, &overlay_list,
+      &ca_layer_list, nullptr, &damage_rect_, &content_bounds_);
   EXPECT_EQ(0U, overlay_list.size());
   EXPECT_EQ(1U, ca_layer_list.size());
   gfx::Transform expected_transform;
@@ -1919,9 +1960,9 @@
   RenderPassList pass_list;
   pass_list.push_back(std::move(pass));
   overlay_processor_->ProcessForOverlays(
-      resource_provider_.get(), &pass_list, render_pass_filters,
-      render_pass_background_filters, &overlay_list, &ca_layer_list, nullptr,
-      &damage_rect_, &content_bounds_);
+      resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
+      render_pass_filters, render_pass_background_filters, &overlay_list,
+      &ca_layer_list, nullptr, &damage_rect_, &content_bounds_);
   EXPECT_EQ(gfx::Rect(), damage_rect);
   EXPECT_EQ(0U, overlay_list.size());
   EXPECT_EQ(1U, ca_layer_list.size());
@@ -1944,9 +1985,9 @@
   RenderPassList pass_list;
   pass_list.push_back(std::move(pass));
   overlay_processor_->ProcessForOverlays(
-      resource_provider_.get(), &pass_list, render_pass_filters,
-      render_pass_background_filters, &overlay_list, &ca_layer_list, nullptr,
-      &damage_rect_, &content_bounds_);
+      resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
+      render_pass_filters, render_pass_background_filters, &overlay_list,
+      &ca_layer_list, nullptr, &damage_rect_, &content_bounds_);
   EXPECT_EQ(gfx::Rect(), damage_rect);
   EXPECT_EQ(0U, overlay_list.size());
   EXPECT_EQ(1U, ca_layer_list.size());
@@ -1971,9 +2012,9 @@
   RenderPassList pass_list;
   pass_list.push_back(std::move(pass));
   overlay_processor_->ProcessForOverlays(
-      resource_provider_.get(), &pass_list, render_pass_filters,
-      render_pass_background_filters, &overlay_list, &ca_layer_list, nullptr,
-      &damage_rect_, &content_bounds_);
+      resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
+      render_pass_filters, render_pass_background_filters, &overlay_list,
+      &ca_layer_list, nullptr, &damage_rect_, &content_bounds_);
   EXPECT_EQ(gfx::Rect(), damage_rect);
   EXPECT_EQ(0U, overlay_list.size());
   EXPECT_EQ(0U, ca_layer_list.size());
@@ -2013,9 +2054,9 @@
   RenderPassList pass_list;
   pass_list.push_back(std::move(pass));
   overlay_processor_->ProcessForOverlays(
-      resource_provider_.get(), &pass_list, render_pass_filters,
-      render_pass_background_filters, &overlay_list, nullptr, &dc_layer_list,
-      &damage_rect_, &content_bounds_);
+      resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
+      render_pass_filters, render_pass_background_filters, &overlay_list,
+      nullptr, &dc_layer_list, &damage_rect_, &content_bounds_);
   EXPECT_EQ(gfx::Rect(), damage_rect);
   EXPECT_EQ(0U, overlay_list.size());
   EXPECT_EQ(1U, dc_layer_list.size());
@@ -2045,9 +2086,9 @@
   RenderPassList pass_list;
   pass_list.push_back(std::move(pass));
   overlay_processor_->ProcessForOverlays(
-      resource_provider_.get(), &pass_list, render_pass_filters,
-      render_pass_background_filters, &overlay_list, nullptr, &dc_layer_list,
-      &damage_rect_, &content_bounds_);
+      resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
+      render_pass_filters, render_pass_background_filters, &overlay_list,
+      nullptr, &dc_layer_list, &damage_rect_, &content_bounds_);
   EXPECT_EQ(gfx::Rect(), damage_rect);
   EXPECT_EQ(0U, overlay_list.size());
   ASSERT_EQ(1U, dc_layer_list.size());
@@ -2077,9 +2118,9 @@
     RenderPassList pass_list;
     pass_list.push_back(std::move(pass));
     overlay_processor_->ProcessForOverlays(
-        resource_provider_.get(), &pass_list, render_pass_filters,
-        render_pass_background_filters, &overlay_list, nullptr, &dc_layer_list,
-        &damage_rect_, &content_bounds_);
+        resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
+        render_pass_filters, render_pass_background_filters, &overlay_list,
+        nullptr, &dc_layer_list, &damage_rect_, &content_bounds_);
     EXPECT_EQ(gfx::Rect(), damage_rect);
     EXPECT_EQ(0U, overlay_list.size());
     EXPECT_EQ(1U, dc_layer_list.size());
@@ -2106,9 +2147,9 @@
     RenderPassList pass_list;
     pass_list.push_back(std::move(pass));
     overlay_processor_->ProcessForOverlays(
-        resource_provider_.get(), &pass_list, render_pass_filters,
-        render_pass_background_filters, &overlay_list, nullptr, &dc_layer_list,
-        &damage_rect_, &content_bounds_);
+        resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
+        render_pass_filters, render_pass_background_filters, &overlay_list,
+        nullptr, &dc_layer_list, &damage_rect_, &content_bounds_);
     EXPECT_EQ(gfx::Rect(), damage_rect);
     EXPECT_EQ(0U, overlay_list.size());
     EXPECT_EQ(1U, dc_layer_list.size());
@@ -2136,9 +2177,9 @@
     RenderPassList pass_list;
     pass_list.push_back(std::move(pass));
     overlay_processor_->ProcessForOverlays(
-        resource_provider_.get(), &pass_list, render_pass_filters,
-        render_pass_background_filters, &overlay_list, nullptr, &dc_layer_list,
-        &damage_rect_, &content_bounds_);
+        resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
+        render_pass_filters, render_pass_background_filters, &overlay_list,
+        nullptr, &dc_layer_list, &damage_rect_, &content_bounds_);
     EXPECT_EQ(gfx::Rect(), damage_rect);
     EXPECT_EQ(0U, overlay_list.size());
     EXPECT_EQ(1U, dc_layer_list.size());
@@ -2191,9 +2232,9 @@
     pass_list.push_back(std::move(pass1));
     pass_list.push_back(std::move(pass2));
     overlay_processor_->ProcessForOverlays(
-        resource_provider_.get(), &pass_list, render_pass_filters,
-        render_pass_background_filters, &overlay_list, nullptr, &dc_layer_list,
-        &damage_rect_, &content_bounds_);
+        resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
+        render_pass_filters, render_pass_background_filters, &overlay_list,
+        nullptr, &dc_layer_list, &damage_rect_, &content_bounds_);
     EXPECT_EQ(gfx::Rect(), damage_rect);
     EXPECT_EQ(0U, overlay_list.size());
     EXPECT_EQ(0U, output_surface_->bind_framebuffer_count());
@@ -2253,9 +2294,9 @@
     pass_list.push_back(std::move(pass));
     damage_rect_ = gfx::Rect(1, 1, 10, 10);
     overlay_processor_->ProcessForOverlays(
-        resource_provider_.get(), &pass_list, render_pass_filters,
-        render_pass_background_filters, &overlay_list, nullptr, &dc_layer_list,
-        &damage_rect_, &content_bounds_);
+        resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
+        render_pass_filters, render_pass_background_filters, &overlay_list,
+        nullptr, &dc_layer_list, &damage_rect_, &content_bounds_);
     EXPECT_EQ(0U, overlay_list.size());
     EXPECT_EQ(1U, dc_layer_list.size());
     // Because of clip rects the overlay isn't occluded and shouldn't be an
@@ -2290,9 +2331,9 @@
     RenderPassList pass_list;
     pass_list.push_back(std::move(pass));
     overlay_processor_->ProcessForOverlays(
-        resource_provider_.get(), &pass_list, render_pass_filters,
-        render_pass_background_filters, &overlay_list, nullptr, &dc_layer_list,
-        &damage_rect_, &content_bounds_);
+        resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
+        render_pass_filters, render_pass_background_filters, &overlay_list,
+        nullptr, &dc_layer_list, &damage_rect_, &content_bounds_);
     EXPECT_EQ(0U, overlay_list.size());
     EXPECT_EQ(1U, dc_layer_list.size());
     EXPECT_EQ(1, dc_layer_list.back().shared_state->z_order);
@@ -2848,9 +2889,9 @@
   void ProcessForOverlays() {
     overlay_list_ = BackbufferOverlayList(pass_);
     overlay_processor_->ProcessForOverlays(
-        resource_provider_.get(), &pass_list_, render_pass_filters_,
-        render_pass_background_filters_, &overlay_list_, &ca_layer_list_,
-        nullptr, &damage_rect_, &content_bounds_);
+        resource_provider_.get(), &pass_list_, GetIdentityColorMatrix(),
+        render_pass_filters_, render_pass_background_filters_, &overlay_list_,
+        &ca_layer_list_, nullptr, &damage_rect_, &content_bounds_);
   }
   RenderPassList pass_list_;
   RenderPass* pass_;
diff --git a/components/viz/service/display/program_binding.cc b/components/viz/service/display/program_binding.cc
index 631cf9da..3124169 100644
--- a/components/viz/service/display/program_binding.cc
+++ b/components/viz/service/display/program_binding.cc
@@ -34,7 +34,8 @@
          yuv_alpha_texture_mode_ == other.yuv_alpha_texture_mode_ &&
          uv_texture_mode_ == other.uv_texture_mode_ &&
          color_conversion_mode_ == other.color_conversion_mode_ &&
-         color_transform_ == other.color_transform_;
+         color_transform_ == other.color_transform_ &&
+         has_output_color_matrix_ == other.has_output_color_matrix_;
 }
 
 bool ProgramKey::operator!=(const ProgramKey& other) const {
diff --git a/components/viz/service/display/program_binding.h b/components/viz/service/display/program_binding.h
index 70f1ff9..c7899a5 100644
--- a/components/viz/service/display/program_binding.h
+++ b/components/viz/service/display/program_binding.h
@@ -108,6 +108,11 @@
 
   void SetColorTransform(const gfx::ColorTransform* transform);
 
+  bool has_output_color_matrix() const { return has_output_color_matrix_; }
+  void set_has_output_color_matrix(bool value) {
+    has_output_color_matrix_ = value;
+  }
+
  private:
   friend struct ProgramKeyHash;
   friend class Program;
@@ -134,6 +139,8 @@
   const gfx::ColorTransform* color_transform_ = nullptr;
 
   bool has_tex_clamp_rect_ = false;
+
+  bool has_output_color_matrix_ = false;
 };
 
 struct ProgramKeyHash {
@@ -153,7 +160,8 @@
            (static_cast<size_t>(key.yuv_alpha_texture_mode_) << 24) ^
            (static_cast<size_t>(key.uv_texture_mode_) << 25) ^
            (static_cast<size_t>(key.color_conversion_mode_) << 26) ^
-           (static_cast<size_t>(key.has_tex_clamp_rect_) << 28);
+           (static_cast<size_t>(key.has_tex_clamp_rect_) << 28) ^
+           (static_cast<size_t>(key.has_output_color_matrix_) << 29);
   }
 };
 
@@ -174,6 +182,7 @@
     fragment_shader_.mask_for_background_ = key.mask_for_background_;
     fragment_shader_.color_conversion_mode_ = key.color_conversion_mode_;
     fragment_shader_.color_transform_ = key.color_transform_;
+    fragment_shader_.has_output_color_matrix_ = key.has_output_color_matrix_;
 
     switch (key.type_) {
       case PROGRAM_TYPE_DEBUG_BORDER:
@@ -296,6 +305,9 @@
   int uv_clamp_rect_location() const {
     return fragment_shader_.uv_clamp_rect_location_;
   }
+  int output_color_matrix_location() const {
+    return fragment_shader_.output_color_matrix_location_;
+  }
 
  private:
   void InitializeDebugBorderProgram() {
diff --git a/components/viz/service/display/renderer_pixeltest.cc b/components/viz/service/display/renderer_pixeltest.cc
index 1026d47eb..702af281f 100644
--- a/components/viz/service/display/renderer_pixeltest.cc
+++ b/components/viz/service/display/renderer_pixeltest.cc
@@ -17,6 +17,7 @@
 #include "cc/test/fake_raster_source.h"
 #include "cc/test/fake_recording_source.h"
 #include "cc/test/pixel_test.h"
+#include "cc/test/render_pass_test_utils.h"
 #include "cc/test/test_in_process_context_provider.h"
 #include "components/viz/common/quads/picture_draw_quad.h"
 #include "components/viz/common/quads/texture_draw_quad.h"
@@ -895,6 +896,73 @@
       cc::FuzzyPixelOffByOneComparator(true)));
 }
 
+TEST_F(GLRendererPixelTest, SolidColorWithTemperature) {
+  gfx::Rect rect(this->device_viewport_size_);
+
+  int id = 1;
+  std::unique_ptr<RenderPass> pass = CreateTestRootRenderPass(id, rect);
+
+  SharedQuadState* shared_state =
+      CreateTestSharedQuadState(gfx::Transform(), rect, pass.get());
+
+  auto* color_quad = pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
+  color_quad->SetNew(shared_state, rect, rect, SK_ColorYELLOW, false);
+
+  RenderPassList pass_list;
+  pass_list.push_back(std::move(pass));
+
+  SkMatrix44 color_matrix(SkMatrix44::kIdentity_Constructor);
+  color_matrix.set(0, 0, 0.7f);
+  color_matrix.set(1, 1, 0.4f);
+  color_matrix.set(2, 2, 0.5f);
+  output_surface_->set_color_matrix(color_matrix);
+
+  EXPECT_TRUE(this->RunPixelTest(
+      &pass_list, base::FilePath(FILE_PATH_LITERAL("temperature_brown.png")),
+      cc::FuzzyPixelOffByOneComparator(true)));
+}
+
+TEST_F(GLRendererPixelTest, SolidColorWithTemperature_NonRootRenderPass) {
+  // Create a root and a child passes with two different solid color quads.
+  RenderPassList render_passes_in_draw_order;
+  gfx::Rect viewport_rect(this->device_viewport_size_);
+  gfx::Rect root_rect(0, 0, viewport_rect.width(), viewport_rect.height() / 2);
+  gfx::Rect child_rect(0, root_rect.bottom(), viewport_rect.width(),
+                       root_rect.height());
+
+  // Child pass.
+  int child_pass_id = 2;
+  RenderPass* child_pass = cc::AddRenderPass(
+      &render_passes_in_draw_order, child_pass_id, viewport_rect,
+      gfx::Transform(), cc::FilterOperations());
+  cc::AddQuad(child_pass, child_rect, SK_ColorGREEN);
+
+  // Root pass.
+  int root_pass_id = 1;
+  RenderPass* root_pass = cc::AddRenderPass(
+      &render_passes_in_draw_order, root_pass_id, viewport_rect,
+      gfx::Transform(), cc::FilterOperations());
+  cc::AddQuad(root_pass, root_rect, SK_ColorYELLOW);
+
+  SharedQuadState* pass_shared_state =
+      CreateTestSharedQuadState(gfx::Transform(), viewport_rect, root_pass);
+  CreateTestRenderPassDrawQuad(pass_shared_state, viewport_rect, child_pass_id,
+                               root_pass);
+
+  // Set a non-identity output color matrix on the output surface, and expect
+  // that the colors will be transformed.
+  SkMatrix44 color_matrix(SkMatrix44::kIdentity_Constructor);
+  color_matrix.set(0, 0, 0.7f);
+  color_matrix.set(1, 1, 0.4f);
+  color_matrix.set(2, 2, 0.5f);
+  output_surface_->set_color_matrix(color_matrix);
+
+  EXPECT_TRUE(this->RunPixelTest(
+      &render_passes_in_draw_order,
+      base::FilePath(FILE_PATH_LITERAL("temperature_brown_non_root.png")),
+      cc::FuzzyPixelOffByOneComparator(true)));
+}
+
 TEST_F(GLRendererPixelTest,
        PremultipliedTextureWithBackgroundAndVertexOpacity) {
   gfx::Rect rect(this->device_viewport_size_);
@@ -3279,8 +3347,8 @@
 
   cc::Region outside(layer_rect);
   outside.Subtract(gfx::ToEnclosingRect(union_layer_rect));
-  for (cc::Region::Iterator iter(outside); iter.has_rect(); iter.next()) {
-    recording->add_draw_rect_with_flags(iter.rect(), red_flags);
+  for (gfx::Rect rect : outside) {
+    recording->add_draw_rect_with_flags(rect, red_flags);
   }
 
   cc::PaintFlags blue_flags;
diff --git a/components/viz/service/display/shader.cc b/components/viz/service/display/shader.cc
index 14bec059..655bc84 100644
--- a/components/viz/service/display/shader.cc
+++ b/components/viz/service/display/shader.cc
@@ -469,6 +469,8 @@
     uniforms.push_back("lut_texture");
     uniforms.push_back("lut_size");
   }
+  if (has_output_color_matrix_)
+    uniforms.emplace_back("output_color_matrix");
 
   locations.resize(uniforms.size());
 
@@ -525,6 +527,10 @@
     lut_texture_location_ = locations[index++];
     lut_size_location_ = locations[index++];
   }
+
+  if (has_output_color_matrix_)
+    output_color_matrix_location_ = locations[index++];
+
   DCHECK_EQ(index, locations.size());
 }
 
@@ -1011,6 +1017,13 @@
     SRC("texColor = texColor.bgra;\n");
   }
 
+  // Finally apply the output color matrix to texColor.
+  if (has_output_color_matrix_) {
+    HDR("uniform mat4 output_color_matrix;");
+    SRC("// Apply the output color matrix");
+    SRC("texColor = output_color_matrix * texColor;");
+  }
+
   // Include header text for alpha.
   if (has_uniform_alpha_) {
     HDR("uniform float alpha;");
diff --git a/components/viz/service/display/shader.h b/components/viz/service/display/shader.h
index d79802ba..a51e584 100644
--- a/components/viz/service/display/shader.h
+++ b/components/viz/service/display/shader.h
@@ -294,6 +294,9 @@
   ColorConversionMode color_conversion_mode_ = COLOR_CONVERSION_MODE_NONE;
   const gfx::ColorTransform* color_transform_ = nullptr;
 
+  bool has_output_color_matrix_ = false;
+  int output_color_matrix_location_ = -1;
+
   // YUV uniform locations.
   int y_texture_location_ = -1;
   int u_texture_location_ = -1;
diff --git a/components/viz/service/frame_sinks/compositor_frame_sink_support.cc b/components/viz/service/frame_sinks/compositor_frame_sink_support.cc
index be6c364..29c778f 100644
--- a/components/viz/service/frame_sinks/compositor_frame_sink_support.cc
+++ b/components/viz/service/frame_sinks/compositor_frame_sink_support.cc
@@ -24,17 +24,29 @@
     const FrameSinkId& frame_sink_id,
     bool is_root,
     bool needs_sync_tokens) {
-  std::unique_ptr<CompositorFrameSinkSupport> support =
-      base::WrapUnique(new CompositorFrameSinkSupport(
-          client, frame_sink_id, is_root, needs_sync_tokens));
-  support->Init(frame_sink_manager);
-  return support;
+  return std::make_unique<CompositorFrameSinkSupport>(
+      client, frame_sink_manager, frame_sink_id, is_root, needs_sync_tokens);
+}
+
+CompositorFrameSinkSupport::CompositorFrameSinkSupport(
+    mojom::CompositorFrameSinkClient* client,
+    FrameSinkManagerImpl* frame_sink_manager,
+    const FrameSinkId& frame_sink_id,
+    bool is_root,
+    bool needs_sync_tokens)
+    : client_(client),
+      frame_sink_manager_(frame_sink_manager),
+      surface_manager_(frame_sink_manager->surface_manager()),
+      frame_sink_id_(frame_sink_id),
+      surface_resource_holder_(this),
+      is_root_(is_root),
+      needs_sync_tokens_(needs_sync_tokens),
+      weak_factory_(this) {
+  // This may result in SetBeginFrameSource() being called.
+  frame_sink_manager_->RegisterCompositorFrameSinkSupport(frame_sink_id_, this);
 }
 
 CompositorFrameSinkSupport::~CompositorFrameSinkSupport() {
-  // No video capture clients should remain at this point.
-  DCHECK(capture_clients_.empty());
-
   if (!destruction_callback_.is_null())
     std::move(destruction_callback_).Run();
 
@@ -51,7 +63,10 @@
   }
 
   EvictCurrentSurface();
-  frame_sink_manager_->UnregisterFrameSinkManagerClient(frame_sink_id_);
+  frame_sink_manager_->UnregisterCompositorFrameSinkSupport(frame_sink_id_);
+
+  // No video capture clients should remain at this point.
+  DCHECK(capture_clients_.empty());
 }
 
 void CompositorFrameSinkSupport::SetAggregatedDamageCallback(
@@ -64,6 +79,16 @@
   destruction_callback_ = std::move(callback);
 }
 
+void CompositorFrameSinkSupport::SetBeginFrameSource(
+    BeginFrameSource* begin_frame_source) {
+  if (begin_frame_source_ && added_frame_observer_) {
+    begin_frame_source_->RemoveObserver(this);
+    added_frame_observer_ = false;
+  }
+  begin_frame_source_ = begin_frame_source;
+  UpdateNeedsBeginFramesInternal();
+}
+
 void CompositorFrameSinkSupport::OnSurfaceActivated(Surface* surface) {
   DCHECK(surface);
   DCHECK(surface->HasActiveFrame());
@@ -103,16 +128,6 @@
   surface_resource_holder_.ReceiveFromChild(resources);
 }
 
-void CompositorFrameSinkSupport::SetBeginFrameSource(
-    BeginFrameSource* begin_frame_source) {
-  if (begin_frame_source_ && added_frame_observer_) {
-    begin_frame_source_->RemoveObserver(this);
-    added_frame_observer_ = false;
-  }
-  begin_frame_source_ = begin_frame_source;
-  UpdateNeedsBeginFramesInternal();
-}
-
 void CompositorFrameSinkSupport::EvictCurrentSurface() {
   if (!current_surface_id_.is_valid())
     return;
@@ -330,25 +345,6 @@
   }
 }
 
-CompositorFrameSinkSupport::CompositorFrameSinkSupport(
-    mojom::CompositorFrameSinkClient* client,
-    const FrameSinkId& frame_sink_id,
-    bool is_root,
-    bool needs_sync_tokens)
-    : client_(client),
-      frame_sink_id_(frame_sink_id),
-      surface_resource_holder_(this),
-      is_root_(is_root),
-      needs_sync_tokens_(needs_sync_tokens),
-      weak_factory_(this) {}
-
-void CompositorFrameSinkSupport::Init(
-    FrameSinkManagerImpl* frame_sink_manager) {
-  frame_sink_manager_ = frame_sink_manager;
-  surface_manager_ = frame_sink_manager->surface_manager();
-  frame_sink_manager_->RegisterFrameSinkManagerClient(frame_sink_id_, this);
-}
-
 void CompositorFrameSinkSupport::OnBeginFrame(const BeginFrameArgs& args) {
   UpdateNeedsBeginFramesInternal();
   if (current_surface_id_.is_valid())
diff --git a/components/viz/service/frame_sinks/compositor_frame_sink_support.h b/components/viz/service/frame_sinks/compositor_frame_sink_support.h
index 897e878..d6187c9 100644
--- a/components/viz/service/frame_sinks/compositor_frame_sink_support.h
+++ b/components/viz/service/frame_sinks/compositor_frame_sink_support.h
@@ -15,7 +15,6 @@
 #include "components/viz/common/frame_sinks/begin_frame_source.h"
 #include "components/viz/common/quads/compositor_frame.h"
 #include "components/viz/common/surfaces/surface_info.h"
-#include "components/viz/service/frame_sinks/frame_sink_manager_client.h"
 #include "components/viz/service/frame_sinks/referenced_surface_tracker.h"
 #include "components/viz/service/frame_sinks/surface_resource_holder.h"
 #include "components/viz/service/frame_sinks/surface_resource_holder_client.h"
@@ -34,7 +33,6 @@
 class VIZ_SERVICE_EXPORT CompositorFrameSinkSupport
     : public BeginFrameObserver,
       public SurfaceResourceHolderClient,
-      public FrameSinkManagerClient,
       public SurfaceClient,
       public CapturableFrameSink,
       public mojom::CompositorFrameSink {
@@ -45,6 +43,7 @@
 
   static const uint64_t kFrameIndexStart = 2;
 
+  // DEPRECATED(kylechar): It's now possible to use the constructor directly.
   static std::unique_ptr<CompositorFrameSinkSupport> Create(
       mojom::CompositorFrameSinkClient* client,
       FrameSinkManagerImpl* frame_sink_manager,
@@ -52,6 +51,11 @@
       bool is_root,
       bool needs_sync_tokens);
 
+  CompositorFrameSinkSupport(mojom::CompositorFrameSinkClient* client,
+                             FrameSinkManagerImpl* frame_sink_manager,
+                             const FrameSinkId& frame_sink_id,
+                             bool is_root,
+                             bool needs_sync_tokens);
   ~CompositorFrameSinkSupport() override;
 
   const FrameSinkId& frame_sink_id() const { return frame_sink_id_; }
@@ -71,6 +75,9 @@
   // Sets callback called on destruction.
   void SetDestructionCallback(base::OnceCallback<void()> callback);
 
+  // This allows the FrameSinkManagerImpl to pass a BeginFrameSource to use.
+  void SetBeginFrameSource(BeginFrameSource* begin_frame_source);
+
   // SurfaceClient implementation.
   void OnSurfaceActivated(Surface* surface) override;
   void RefResources(
@@ -80,9 +87,6 @@
   void ReceiveFromChild(
       const std::vector<TransferableResource>& resources) override;
 
-  // FrameSinkManagerClient implementation.
-  void SetBeginFrameSource(BeginFrameSource* begin_frame_source) override;
-
   // mojom::CompositorFrameSink implementation.
   void SetNeedsBeginFrame(bool needs_begin_frame) override;
   void DidNotProduceFrame(const BeginFrameAck& ack) override;
@@ -114,13 +118,6 @@
  private:
   friend class FrameSinkManagerTest;
 
-  CompositorFrameSinkSupport(mojom::CompositorFrameSinkClient* client,
-                             const FrameSinkId& frame_sink_id,
-                             bool is_root,
-                             bool needs_sync_tokens);
-
-  void Init(FrameSinkManagerImpl* frame_sink_manager);
-
   // Updates surface references using |active_referenced_surfaces| from the most
   // recent CompositorFrame. This will add and remove top-level root references
   // if |is_root_| is true and |local_surface_id| has changed. Modifies surface
@@ -152,8 +149,8 @@
 
   mojom::CompositorFrameSinkClient* const client_;
 
-  FrameSinkManagerImpl* frame_sink_manager_ = nullptr;
-  SurfaceManager* surface_manager_ = nullptr;
+  FrameSinkManagerImpl* const frame_sink_manager_;
+  SurfaceManager* const surface_manager_;
 
   const FrameSinkId frame_sink_id_;
   SurfaceId current_surface_id_;
diff --git a/components/viz/service/frame_sinks/frame_sink_manager_client.h b/components/viz/service/frame_sinks/frame_sink_manager_client.h
deleted file mode 100644
index 1dc5d33..0000000
--- a/components/viz/service/frame_sinks/frame_sink_manager_client.h
+++ /dev/null
@@ -1,26 +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_VIZ_SERVICE_FRAME_SINKS_FRAME_SINK_MANAGER_CLIENT_H_
-#define COMPONENTS_VIZ_SERVICE_FRAME_SINKS_FRAME_SINK_MANAGER_CLIENT_H_
-
-#include "components/viz/service/viz_service_export.h"
-
-namespace cc {
-class BeginFrameSource;
-}
-
-namespace viz {
-
-class VIZ_SERVICE_EXPORT FrameSinkManagerClient {
- public:
-  virtual ~FrameSinkManagerClient() = default;
-
-  // This allows the FrameSinkManagerImpl to pass a BeginFrameSource to use.
-  virtual void SetBeginFrameSource(BeginFrameSource* begin_frame_source) = 0;
-};
-
-}  // namespace viz
-
-#endif  // COMPONENTS_VIZ_SERVICE_FRAME_SINKS_FRAME_SINK_MANAGER_CLIENT_H_
diff --git a/components/viz/service/frame_sinks/frame_sink_manager_impl.cc b/components/viz/service/frame_sinks/frame_sink_manager_impl.cc
index fd50f6c..a916e31a 100644
--- a/components/viz/service/frame_sinks/frame_sink_manager_impl.cc
+++ b/components/viz/service/frame_sinks/frame_sink_manager_impl.cc
@@ -12,7 +12,6 @@
 #include "components/viz/service/display_embedder/display_provider.h"
 #include "components/viz/service/frame_sinks/compositor_frame_sink_impl.h"
 #include "components/viz/service/frame_sinks/compositor_frame_sink_support.h"
-#include "components/viz/service/frame_sinks/frame_sink_manager_client.h"
 #include "components/viz/service/frame_sinks/primary_begin_frame_source.h"
 #include "components/viz/service/frame_sinks/root_compositor_frame_sink_impl.h"
 #include "components/viz/service/frame_sinks/video_capture/capturable_frame_sink.h"
@@ -34,8 +33,14 @@
 
 FrameSinkManagerImpl::SinkAndSupport::SinkAndSupport() = default;
 
+FrameSinkManagerImpl::SinkAndSupport::SinkAndSupport(SinkAndSupport&& other) =
+    default;
+
 FrameSinkManagerImpl::SinkAndSupport::~SinkAndSupport() = default;
 
+FrameSinkManagerImpl::SinkAndSupport& FrameSinkManagerImpl::SinkAndSupport::
+operator=(SinkAndSupport&& other) = default;
+
 FrameSinkManagerImpl::FrameSinkManagerImpl(
     SurfaceManager::LifetimeType lifetime_type,
     DisplayProvider* display_provider)
@@ -52,7 +57,6 @@
   // All FrameSinks should be unregistered prior to FrameSinkManager
   // destruction.
   compositor_frame_sinks_.clear();
-  DCHECK_EQ(clients_.size(), 0u);
   DCHECK_EQ(registered_sources_.size(), 0u);
   surface_manager_.RemoveObserver(this);
   surface_manager_.RemoveObserver(&hit_test_manager_);
@@ -88,10 +92,16 @@
 void FrameSinkManagerImpl::InvalidateFrameSinkId(
     const FrameSinkId& frame_sink_id) {
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  compositor_frame_sinks_.erase(frame_sink_id);
   surface_manager_.InvalidateFrameSinkId(frame_sink_id);
   if (video_detector_)
     video_detector_->OnFrameSinkIdInvalidated(frame_sink_id);
+
+  // Destroy the [Root]CompositorFrameSinkImpl if there is one. This will result
+  // in UnregisterCompositorFrameSinkSupport() being called and |iter| will be
+  // invalidated afterwards
+  auto iter = compositor_frame_sinks_.find(frame_sink_id);
+  if (iter != compositor_frame_sinks_.end())
+    iter->second.sink.reset();
 }
 
 void FrameSinkManagerImpl::SetFrameSinkDebugLabel(
@@ -123,7 +133,7 @@
       std::move(request), std::move(client),
       std::move(display_private_request));
   SinkAndSupport& entry = compositor_frame_sinks_[frame_sink_id];
-  entry.support = frame_sink->support();
+  DCHECK(entry.support);  // |entry| was created by RootCompositorFrameSinkImpl.
   entry.sink = std::move(frame_sink);
 }
 
@@ -137,7 +147,7 @@
   auto frame_sink = std::make_unique<CompositorFrameSinkImpl>(
       this, frame_sink_id, std::move(request), std::move(client));
   SinkAndSupport& entry = compositor_frame_sinks_[frame_sink_id];
-  entry.support = frame_sink->support();
+  DCHECK(entry.support);  // |entry| was created by CompositorFrameSinkImpl.
   entry.sink = std::move(frame_sink);
 }
 
@@ -150,8 +160,7 @@
 
   std::vector<FrameSinkId>& children =
       frame_sink_source_map_[parent_frame_sink_id].children;
-  for (size_t i = 0; i < children.size(); ++i)
-    DCHECK(children[i] != child_frame_sink_id);
+  DCHECK(!base::ContainsValue(children, child_frame_sink_id));
   children.push_back(child_frame_sink_id);
 
   // If the parent has no source, then attaching it to this child will
@@ -192,8 +201,8 @@
   // The CompositorFrameSinkSupport and hierarchy can be registered/unregistered
   // in either order, so empty frame_sink_source_map entries need to be
   // checked when removing either clients or relationships.
-  if (!iter->second.has_children() && !clients_.count(parent_frame_sink_id) &&
-      !iter->second.source) {
+  if (!iter->second.has_children() && !iter->second.source &&
+      !compositor_frame_sinks_.count(parent_frame_sink_id)) {
     frame_sink_source_map_.erase(iter);
     return;
   }
@@ -219,31 +228,24 @@
   surface_manager_.DropTemporaryReference(surface_id);
 }
 
-void FrameSinkManagerImpl::RegisterFrameSinkManagerClient(
+void FrameSinkManagerImpl::RegisterCompositorFrameSinkSupport(
     const FrameSinkId& frame_sink_id,
-    FrameSinkManagerClient* client) {
-  DCHECK(client);
+    CompositorFrameSinkSupport* support) {
+  DCHECK(support);
 
-  clients_[frame_sink_id] = client;
+  SinkAndSupport& entry = compositor_frame_sinks_[frame_sink_id];
+  DCHECK(!entry.support);
+  entry.support = support;
 
   auto it = frame_sink_source_map_.find(frame_sink_id);
-  if (it != frame_sink_source_map_.end()) {
-    if (it->second.source)
-      client->SetBeginFrameSource(it->second.source);
-  }
+  if (it != frame_sink_source_map_.end() && it->second.source)
+    support->SetBeginFrameSource(it->second.source);
 }
 
-void FrameSinkManagerImpl::UnregisterFrameSinkManagerClient(
+void FrameSinkManagerImpl::UnregisterCompositorFrameSinkSupport(
     const FrameSinkId& frame_sink_id) {
-  auto client_iter = clients_.find(frame_sink_id);
-  DCHECK(client_iter != clients_.end());
-
-  auto source_iter = frame_sink_source_map_.find(frame_sink_id);
-  if (source_iter != frame_sink_source_map_.end()) {
-    if (source_iter->second.source)
-      client_iter->second->SetBeginFrameSource(nullptr);
-  }
-  clients_.erase(client_iter);
+  DCHECK_EQ(compositor_frame_sinks_.count(frame_sink_id), 1u);
+  compositor_frame_sinks_.erase(frame_sink_id);
 }
 
 void FrameSinkManagerImpl::RegisterBeginFrameSource(
@@ -290,9 +292,9 @@
   FrameSinkSourceMapping& mapping = frame_sink_source_map_[frame_sink_id];
   if (!mapping.source) {
     mapping.source = source;
-    auto client_iter = clients_.find(frame_sink_id);
-    if (client_iter != clients_.end())
-      client_iter->second->SetBeginFrameSource(source);
+    auto client_iter = compositor_frame_sinks_.find(frame_sink_id);
+    if (client_iter != compositor_frame_sinks_.end())
+      client_iter->second.support->SetBeginFrameSource(source);
   }
   for (size_t i = 0; i < mapping.children.size(); ++i) {
     // |frame_sink_source_map_| is a container that can allocate new memory and
@@ -312,12 +314,13 @@
     return;
   if (iter->second.source == source) {
     iter->second.source = nullptr;
-    auto client_iter = clients_.find(frame_sink_id);
-    if (client_iter != clients_.end())
-      client_iter->second->SetBeginFrameSource(nullptr);
+    auto client_iter = compositor_frame_sinks_.find(frame_sink_id);
+    if (client_iter != compositor_frame_sinks_.end())
+      client_iter->second.support->SetBeginFrameSource(nullptr);
   }
 
-  if (!iter->second.has_children() && !clients_.count(frame_sink_id)) {
+  if (!iter->second.has_children() &&
+      !compositor_frame_sinks_.count(frame_sink_id)) {
     frame_sink_source_map_.erase(iter);
     return;
   }
diff --git a/components/viz/service/frame_sinks/frame_sink_manager_impl.h b/components/viz/service/frame_sinks/frame_sink_manager_impl.h
index ecbebd8e..784b586 100644
--- a/components/viz/service/frame_sinks/frame_sink_manager_impl.h
+++ b/components/viz/service/frame_sinks/frame_sink_manager_impl.h
@@ -26,22 +26,11 @@
 #include "services/viz/privileged/interfaces/compositing/frame_sink_manager.mojom.h"
 #include "services/viz/public/interfaces/compositing/video_detector_observer.mojom.h"
 
-namespace cc {
-
-class BeginFrameSource;
-
-namespace test {
-class SurfaceSynchronizationTest;
-}
-
-}  // namespace cc
-
 namespace viz {
 
 class CapturableFrameSink;
 class CompositorFrameSinkSupport;
 class DisplayProvider;
-class FrameSinkManagerClient;
 
 // FrameSinkManagerImpl manages BeginFrame hierarchy. This is the implementation
 // detail for FrameSinkManagerImpl.
@@ -100,12 +89,11 @@
   // However, DelegatedFrameHost can register itself as a client before its
   // relationship with the ui::Compositor is known.
 
-  // Associates a FrameSinkManagerClient with the frame_sink_id it uses.
-  // FrameSinkManagerClient and framesink allocators have a 1:1 mapping.
-  // Caller guarantees the client is alive between register/unregister.
-  void RegisterFrameSinkManagerClient(const FrameSinkId& frame_sink_id,
-                                      FrameSinkManagerClient* client);
-  void UnregisterFrameSinkManagerClient(const FrameSinkId& frame_sink_id);
+  // Registers a CompositorFrameSinkSupport for |frame_sink_id|. |frame_sink_id|
+  // must be unregistered when |support| is destroyed.
+  void RegisterCompositorFrameSinkSupport(const FrameSinkId& frame_sink_id,
+                                          CompositorFrameSinkSupport* support);
+  void UnregisterCompositorFrameSinkSupport(const FrameSinkId& frame_sink_id);
 
   // Associates a |source| with a particular framesink.  That framesink and
   // any children of that framesink with valid clients can potentially use
@@ -170,7 +158,31 @@
                            uint32_t frame_token);
 
  private:
-  friend class cc::test::SurfaceSynchronizationTest;
+  // BeginFrameSource routing information for a FrameSinkId.
+  struct FrameSinkSourceMapping {
+    FrameSinkSourceMapping();
+    FrameSinkSourceMapping(const FrameSinkSourceMapping& other);
+    ~FrameSinkSourceMapping();
+    bool has_children() const { return !children.empty(); }
+    // The currently assigned begin frame source for this client.
+    BeginFrameSource* source = nullptr;
+    // This represents a dag of parent -> children mapping.
+    std::vector<FrameSinkId> children;
+  };
+
+  struct SinkAndSupport {
+    SinkAndSupport();
+    SinkAndSupport(SinkAndSupport&& other);
+    ~SinkAndSupport();
+    SinkAndSupport& operator=(SinkAndSupport&& other);
+
+    // CompositorFrameSinks owned here. This will be null if a
+    // CompositorFrameSinkSupport is owned externally.
+    std::unique_ptr<mojom::CompositorFrameSink> sink;
+
+    // This can be owned by |sink| or owned externally.
+    CompositorFrameSinkSupport* support = nullptr;
+  };
 
   void RecursivelyAttachBeginFrameSource(const FrameSinkId& frame_sink_id,
                                          BeginFrameSource* source);
@@ -187,24 +199,9 @@
   bool ChildContains(const FrameSinkId& child_frame_sink_id,
                      const FrameSinkId& search_frame_sink_id) const;
 
-  // Begin frame source routing. Both BeginFrameSource and
-  // CompositorFrameSinkSupport pointers guaranteed alive by callers until
-  // unregistered.
-  struct FrameSinkSourceMapping {
-    FrameSinkSourceMapping();
-    FrameSinkSourceMapping(const FrameSinkSourceMapping& other);
-    ~FrameSinkSourceMapping();
-    bool has_children() const { return !children.empty(); }
-    // The currently assigned begin frame source for this client.
-    BeginFrameSource* source = nullptr;
-    // This represents a dag of parent -> children mapping.
-    std::vector<FrameSinkId> children;
-  };
-
   // Provides a Display for CreateRootCompositorFrameSink().
   DisplayProvider* const display_provider_;
 
-  base::flat_map<FrameSinkId, FrameSinkManagerClient*> clients_;
   std::unordered_map<FrameSinkId, FrameSinkSourceMapping, FrameSinkIdHash>
       frame_sink_source_map_;
 
@@ -221,14 +218,7 @@
 
   HitTestManager hit_test_manager_;
 
-  struct SinkAndSupport {
-    SinkAndSupport();
-    ~SinkAndSupport();
-    std::unique_ptr<mojom::CompositorFrameSink> sink;
-    CompositorFrameSinkSupport* support;  // Owned by |sink|.
-  };
-  std::unordered_map<FrameSinkId, SinkAndSupport, FrameSinkIdHash>
-      compositor_frame_sinks_;
+  base::flat_map<FrameSinkId, SinkAndSupport> compositor_frame_sinks_;
 
   THREAD_CHECKER(thread_checker_);
 
diff --git a/components/viz/service/frame_sinks/root_compositor_frame_sink_impl.cc b/components/viz/service/frame_sinks/root_compositor_frame_sink_impl.cc
index 7072e33af..8dc2f4a7 100644
--- a/components/viz/service/frame_sinks/root_compositor_frame_sink_impl.cc
+++ b/components/viz/service/frame_sinks/root_compositor_frame_sink_impl.cc
@@ -52,6 +52,11 @@
   display_->SetVisible(visible);
 }
 
+void RootCompositorFrameSinkImpl::SetDisplayColorMatrix(
+    const gfx::Transform& color_matrix) {
+  display_->SetColorMatrix(color_matrix.matrix());
+}
+
 void RootCompositorFrameSinkImpl::SetDisplayColorSpace(
     const gfx::ColorSpace& blending_color_space,
     const gfx::ColorSpace& device_color_space) {
diff --git a/components/viz/service/frame_sinks/root_compositor_frame_sink_impl.h b/components/viz/service/frame_sinks/root_compositor_frame_sink_impl.h
index 14e0bfe..ee5fef2 100644
--- a/components/viz/service/frame_sinks/root_compositor_frame_sink_impl.h
+++ b/components/viz/service/frame_sinks/root_compositor_frame_sink_impl.h
@@ -45,6 +45,7 @@
 
   // mojom::DisplayPrivate:
   void SetDisplayVisible(bool visible) override;
+  void SetDisplayColorMatrix(const gfx::Transform& color_matrix) override;
   void SetDisplayColorSpace(const gfx::ColorSpace& blending_color_space,
                             const gfx::ColorSpace& device_color_space) override;
   void SetOutputIsSecure(bool secure) override;
diff --git a/components/viz/test/compositor_frame_helpers.cc b/components/viz/test/compositor_frame_helpers.cc
index 3790bd3..89436b80 100644
--- a/components/viz/test/compositor_frame_helpers.cc
+++ b/components/viz/test/compositor_frame_helpers.cc
@@ -88,6 +88,18 @@
   return *this;
 }
 
+CompositorFrameBuilder& CompositorFrameBuilder::AddLatencyInfos(
+    std::vector<ui::LatencyInfo> latency_info) {
+  if (frame_->metadata.latency_info.empty()) {
+    frame_->metadata.latency_info.swap(latency_info);
+  } else {
+    for (auto& latency : latency_info) {
+      frame_->metadata.latency_info.push_back(std::move(latency));
+    }
+  }
+  return *this;
+}
+
 CompositorFrameBuilder& CompositorFrameBuilder::SetActivationDependencies(
     std::vector<SurfaceId> activation_dependencies) {
   frame_->metadata.activation_dependencies = std::move(activation_dependencies);
diff --git a/components/viz/test/compositor_frame_helpers.h b/components/viz/test/compositor_frame_helpers.h
index 0cf7ba7..8e8e88cd 100644
--- a/components/viz/test/compositor_frame_helpers.h
+++ b/components/viz/test/compositor_frame_helpers.h
@@ -50,6 +50,8 @@
   CompositorFrameBuilder& SetBeginFrameAck(const BeginFrameAck& ack);
   CompositorFrameBuilder& SetDeviceScaleFactor(float device_scale_factor);
   CompositorFrameBuilder& AddLatencyInfo(ui::LatencyInfo latency_info);
+  CompositorFrameBuilder& AddLatencyInfos(
+      std::vector<ui::LatencyInfo> latency_info);
   CompositorFrameBuilder& SetReferencedSurfaces(
       std::vector<SurfaceId> referenced_surfaces);
   CompositorFrameBuilder& SetActivationDependencies(
diff --git a/components/viz/test/data/temperature_brown.png b/components/viz/test/data/temperature_brown.png
new file mode 100644
index 0000000..8937061
--- /dev/null
+++ b/components/viz/test/data/temperature_brown.png
Binary files differ
diff --git a/components/viz/test/data/temperature_brown_non_root.png b/components/viz/test/data/temperature_brown_non_root.png
new file mode 100644
index 0000000..6b4f7cc
--- /dev/null
+++ b/components/viz/test/data/temperature_brown_non_root.png
Binary files differ
diff --git a/content/browser/BUILD.gn b/content/browser/BUILD.gn
index 7d3cbc4..2e9b1cd 100644
--- a/content/browser/BUILD.gn
+++ b/content/browser/BUILD.gn
@@ -107,7 +107,6 @@
     "//mojo/common",
     "//mojo/edk/system",
     "//mojo/public/cpp/bindings",
-    "//mojo/public/js",
     "//mojo/public/js:resources",
     "//net",
     "//net:extras",
diff --git a/content/browser/android/ime_adapter_android.cc b/content/browser/android/ime_adapter_android.cc
index 8e1ed00..267c9ae2 100644
--- a/content/browser/android/ime_adapter_android.cc
+++ b/content/browser/android/ime_adapter_android.cc
@@ -184,6 +184,14 @@
                               state.composition_end, state.reply_to_request);
 }
 
+void ImeAdapterAndroid::UpdateAfterViewSizeChanged() {
+  JNIEnv* env = AttachCurrentThread();
+  ScopedJavaLocalRef<jobject> obj = java_ime_adapter_.get(env);
+  if (obj.is_null())
+    return;
+  Java_ImeAdapter_updateAfterViewSizeChanged(env, obj);
+}
+
 void ImeAdapterAndroid::UpdateFrameInfo(
     const gfx::SelectionBound& selection_start,
     float dip_scale,
diff --git a/content/browser/android/ime_adapter_android.h b/content/browser/android/ime_adapter_android.h
index 9e591fe..58891af 100644
--- a/content/browser/android/ime_adapter_android.h
+++ b/content/browser/android/ime_adapter_android.h
@@ -105,6 +105,7 @@
   }
 
   void UpdateState(const TextInputState& state);
+  void UpdateAfterViewSizeChanged();
 
   void AdvanceFocusInForm(JNIEnv*,
                           const base::android::JavaParamRef<jobject>&,
diff --git a/content/browser/bad_message.h b/content/browser/bad_message.h
index 68d2a000..7c9123c 100644
--- a/content/browser/bad_message.h
+++ b/content/browser/bad_message.h
@@ -211,6 +211,8 @@
   WEBUI_BAD_SCHEME_ACCESS = 185,
   CSDH_UNEXPECTED_OPERATION = 186,
   RMF_BAD_URL_CACHEABLE_METADATA = 187,
+  RFH_INTERFACE_PROVIDER_MISSING = 188,
+  RFH_INTERFACE_PROVIDER_SUPERFLUOUS = 189,
 
   // Please add new elements here. The naming convention is abbreviated class
   // name (e.g. RenderFrameHost becomes RFH) plus a unique description of the
diff --git a/content/browser/devtools/protocol/security_handler.cc b/content/browser/devtools/protocol/security_handler.cc
index 1b617a1..8ec8635 100644
--- a/content/browser/devtools/protocol/security_handler.cc
+++ b/content/browser/devtools/protocol/security_handler.cc
@@ -19,6 +19,7 @@
 #include "content/public/browser/web_contents.h"
 #include "content/public/browser/web_contents_delegate.h"
 #include "net/cert/x509_certificate.h"
+#include "net/cert/x509_util.h"
 #include "third_party/WebKit/public/platform/WebMixedContentContextType.h"
 
 namespace content {
@@ -72,19 +73,15 @@
     std::unique_ptr<protocol::Array<String>> certificate =
         protocol::Array<String>::create();
     if (it.certificate) {
-      std::string der;
       std::string encoded;
-      bool rv = net::X509Certificate::GetDEREncoded(
-          it.certificate->os_cert_handle(), &der);
-      DCHECK(rv);
-      base::Base64Encode(der, &encoded);
-
+      base::Base64Encode(net::x509_util::CryptoBufferAsStringPiece(
+                             it.certificate->cert_buffer()),
+                         &encoded);
       certificate->addItem(encoded);
 
-      for (auto* cert : it.certificate->GetIntermediateCertificates()) {
-        rv = net::X509Certificate::GetDEREncoded(cert, &der);
-        DCHECK(rv);
-        base::Base64Encode(der, &encoded);
+      for (const auto& cert : it.certificate->intermediate_buffers()) {
+        base::Base64Encode(
+            net::x509_util::CryptoBufferAsStringPiece(cert.get()), &encoded);
         certificate->addItem(encoded);
       }
     }
diff --git a/content/browser/frame_host/navigation_controller_impl_browsertest.cc b/content/browser/frame_host/navigation_controller_impl_browsertest.cc
index 69cdeea0..1229a3e 100644
--- a/content/browser/frame_host/navigation_controller_impl_browsertest.cc
+++ b/content/browser/frame_host/navigation_controller_impl_browsertest.cc
@@ -6209,7 +6209,9 @@
   // DidCommitProvisionalLoadInterceptor:
   void WillDispatchDidCommitProvisionalLoad(
       RenderFrameHost* render_frame_host,
-      ::FrameHostMsg_DidCommitProvisionalLoad_Params* params) override {
+      ::FrameHostMsg_DidCommitProvisionalLoad_Params* params,
+      service_manager::mojom::InterfaceProviderRequest*
+          interface_provider_request) override {
     if (!render_frame_host->GetParent() && params->url == url_) {
       did_trigger_history_navigation_ = true;
       web_contents()->GetController().GoBack();
diff --git a/content/browser/frame_host/navigation_request.cc b/content/browser/frame_host/navigation_request.cc
index 234e2041..f423eb5 100644
--- a/content/browser/frame_host/navigation_request.cc
+++ b/content/browser/frame_host/navigation_request.cc
@@ -971,12 +971,17 @@
       result.action() == NavigationThrottle::CANCEL ||
       result.action() == NavigationThrottle::BLOCK_REQUEST ||
       result.action() == NavigationThrottle::BLOCK_REQUEST_AND_COLLAPSE) {
+#if DCHECK_IS_ON()
+    if (result.action() == NavigationThrottle::BLOCK_REQUEST) {
+      DCHECK(result.net_error_code() == net::ERR_BLOCKED_BY_CLIENT ||
+             result.net_error_code() == net::ERR_BLOCKED_BY_ADMINISTRATOR);
+    }
     // TODO(clamy): distinguish between CANCEL and CANCEL_AND_IGNORE.
-    DCHECK_EQ((result.action() == NavigationThrottle::CANCEL ||
-               result.action() == NavigationThrottle::CANCEL_AND_IGNORE)
-                  ? net::ERR_ABORTED
-                  : net::ERR_BLOCKED_BY_CLIENT,
-              result.net_error_code());
+    else if ((result.action() == NavigationThrottle::CANCEL ||
+              result.action() == NavigationThrottle::CANCEL_AND_IGNORE)) {
+      DCHECK_EQ(result.net_error_code(), net::ERR_ABORTED);
+    }
+#endif
 
     // If the start checks completed synchronously, which could happen if there
     // is no onbeforeunload handler or if a NavigationThrottle cancelled it,
diff --git a/content/browser/frame_host/render_frame_host_feature_policy_unittest.cc b/content/browser/frame_host/render_frame_host_feature_policy_unittest.cc
index cd89cfe..74d963f 100644
--- a/content/browser/frame_host/render_frame_host_feature_policy_unittest.cc
+++ b/content/browser/frame_host/render_frame_host_feature_policy_unittest.cc
@@ -57,7 +57,7 @@
                                      const std::vector<std::string>& origins) {
     RenderFrameHost* current = *rfh;
     SimulateNavigation(&current, current->GetLastCommittedURL());
-    static_cast<TestRenderFrameHost*>(current)->OnDidSetFramePolicyHeaders(
+    static_cast<TestRenderFrameHost*>(current)->DidSetFramePolicyHeaders(
         blink::WebSandboxFlags::kNone, CreateFPHeader(feature, origins));
     *rfh = current;
   }
diff --git a/content/browser/frame_host/render_frame_host_impl.cc b/content/browser/frame_host/render_frame_host_impl.cc
index 5202167e..3e91634 100644
--- a/content/browser/frame_host/render_frame_host_impl.cc
+++ b/content/browser/frame_host/render_frame_host_impl.cc
@@ -503,7 +503,7 @@
       waiting_for_init_(renderer_initiated_creation),
       has_focused_editable_element_(false),
       active_sandbox_flags_(blink::WebSandboxFlags::kNone),
-      interface_provider_binding_(this),
+      document_scoped_interface_provider_binding_(this),
       keep_alive_timeout_(base::TimeDelta::FromSeconds(30)),
       weak_ptr_factory_(this) {
   frame_tree_->AddRenderViewHostRef(render_view_host_);
@@ -909,13 +909,8 @@
     IPC_MESSAGE_HANDLER(FrameHostMsg_DidAccessInitialDocument,
                         OnDidAccessInitialDocument)
     IPC_MESSAGE_HANDLER(FrameHostMsg_DidChangeOpener, OnDidChangeOpener)
-    IPC_MESSAGE_HANDLER(FrameHostMsg_DidChangeName, OnDidChangeName)
-    IPC_MESSAGE_HANDLER(FrameHostMsg_DidSetFramePolicyHeaders,
-                        OnDidSetFramePolicyHeaders)
     IPC_MESSAGE_HANDLER(FrameHostMsg_DidAddContentSecurityPolicies,
                         OnDidAddContentSecurityPolicies)
-    IPC_MESSAGE_HANDLER(FrameHostMsg_EnforceInsecureRequestPolicy,
-                        OnEnforceInsecureRequestPolicy)
     IPC_MESSAGE_HANDLER(FrameHostMsg_DidChangeFramePolicy,
                         OnDidChangeFramePolicy)
     IPC_MESSAGE_HANDLER(FrameHostMsg_DidChangeFrameOwnerProperties,
@@ -1522,7 +1517,9 @@
 // notification containing parameters identifying the navigation.
 void RenderFrameHostImpl::DidCommitProvisionalLoad(
     std::unique_ptr<FrameHostMsg_DidCommitProvisionalLoad_Params>
-        validated_params) {
+        validated_params,
+    service_manager::mojom::InterfaceProviderRequest
+        interface_provider_request) {
   ScopedCommitStateResetter commit_state_resetter(this);
   RenderProcessHost* process = GetProcess();
 
@@ -1548,6 +1545,52 @@
     OnBeforeUnloadACK(true, approx_renderer_start_time, base::TimeTicks::Now());
   }
 
+  // Retroactive sanity check:
+  // - If this is the first real load committing in this frame, then by this
+  //   time the RenderFrameHost's InterfaceProvider implementation should have
+  //   already been bound to a message pipe whose client end is used to service
+  //   interface requests from the initial empty document.
+  // - Otherwise, the InterfaceProvider implementation should at this point be
+  //   bound to an interface connection servicing interface requests coming from
+  //   the document of the previously committed navigation.
+  DCHECK(document_scoped_interface_provider_binding_.is_bound());
+
+  if (validated_params->was_within_same_document) {
+    // The security origin never changes for same-document navigations, the
+    // RenderFrame is expected to keep using the existing interface connection.
+    if (interface_provider_request.is_pending()) {
+      bad_message::ReceivedBadMessage(
+          process, bad_message::RFH_INTERFACE_PROVIDER_SUPERFLUOUS);
+      return;
+    }
+  } else if (interface_provider_request.is_pending()) {
+    // Otherwise, as a general rule, expect the RenderFrame to have supplied the
+    // request end of a new InterfaceProvider connection that will be used by
+    // the new document to issue interface requests to access RenderFrameHost
+    // services.
+    document_scoped_interface_provider_binding_.Close();
+    BindInterfaceProviderRequest(std::move(interface_provider_request));
+  } else {
+    // If there had already been a real load committed in the frame, and this is
+    // not a same-document navigation, then both the active document as well as
+    // the global object was replaced in this browsing context. The RenderFrame
+    // should have rebound its InterfaceProvider to a new pipe, but failed to do
+    // so. Kill the renderer, and close the old binding to ensure that any
+    // pending interface requests originating from the previous document, hence
+    // possibly from a different security origin, will no longer dispatched.
+    if (frame_tree_node_->has_committed_real_load()) {
+      document_scoped_interface_provider_binding_.Close();
+      bad_message::ReceivedBadMessage(
+          process, bad_message::RFH_INTERFACE_PROVIDER_MISSING);
+      return;
+    }
+
+    // Otherwise, it is the first real load commited, for which the RenderFrame
+    // is allowed to, and will re-use the existing InterfaceProvider connection
+    // if the new document is same-origin with the initial empty document, and
+    // therefore the global object is not replaced.
+  }
+
   // If we're waiting for an unload ack from this renderer and we receive a
   // Navigate message, then the renderer was navigating before it received the
   // unload request.  It will either respond to the unload request soon or our
@@ -1883,7 +1926,7 @@
   // reset.
   SetRenderFrameCreated(false);
   InvalidateMojoConnection();
-  interface_provider_binding_.Close();
+  document_scoped_interface_provider_binding_.Close();
 
   // Execute any pending AX tree snapshot callbacks with an empty response,
   // since we're never going to get a response from this renderer.
@@ -2221,8 +2264,8 @@
                                                       GetSiteInstance());
 }
 
-void RenderFrameHostImpl::OnDidChangeName(const std::string& name,
-                                          const std::string& unique_name) {
+void RenderFrameHostImpl::DidChangeName(const std::string& name,
+                                        const std::string& unique_name) {
   if (GetParent() != nullptr) {
     // TODO(lukasza): Call ReceivedBadMessage when |unique_name| is empty.
     DCHECK(!unique_name.empty());
@@ -2238,7 +2281,7 @@
   delegate_->DidChangeName(this, name);
 }
 
-void RenderFrameHostImpl::OnDidSetFramePolicyHeaders(
+void RenderFrameHostImpl::DidSetFramePolicyHeaders(
     blink::WebSandboxFlags sandbox_flags,
     const blink::ParsedFeaturePolicy& parsed_header) {
   if (!is_active())
@@ -2265,7 +2308,7 @@
   frame_tree_node()->AddContentSecurityPolicies(headers);
 }
 
-void RenderFrameHostImpl::OnEnforceInsecureRequestPolicy(
+void RenderFrameHostImpl::EnforceInsecureRequestPolicy(
     blink::WebInsecureRequestPolicy policy) {
   frame_tree_node()->SetInsecureRequestPolicy(policy);
 }
@@ -2768,11 +2811,12 @@
 void RenderFrameHostImpl::BindInterfaceProviderRequest(
     service_manager::mojom::InterfaceProviderRequest
         interface_provider_request) {
-  DCHECK(!interface_provider_binding_.is_bound());
+  DCHECK(!document_scoped_interface_provider_binding_.is_bound());
   DCHECK(interface_provider_request.is_pending());
-  interface_provider_binding_.Bind(FilterRendererExposedInterfaces(
-      mojom::kNavigation_FrameSpec, GetProcess()->GetID(),
-      std::move(interface_provider_request)));
+  document_scoped_interface_provider_binding_.Bind(
+      FilterRendererExposedInterfaces(mojom::kNavigation_FrameSpec,
+                                      GetProcess()->GetID(),
+                                      std::move(interface_provider_request)));
 }
 
 void RenderFrameHostImpl::SetKeepAliveTimeoutForTesting(
@@ -4314,6 +4358,9 @@
 void RenderFrameHostImpl::GetInterface(
     const std::string& interface_name,
     mojo::ScopedMessagePipeHandle interface_pipe) {
+  // Requests are serviced on |document_scoped_interface_provider_binding_|. It
+  // is therefore safe to assume that every incoming interface request is coming
+  // from the currently active document in the corresponding RenderFrame.
   if (!registry_ ||
       !registry_->TryBindInterface(interface_name, &interface_pipe)) {
     delegate_->OnInterfaceRequest(this, interface_name, &interface_pipe);
diff --git a/content/browser/frame_host/render_frame_host_impl.h b/content/browser/frame_host/render_frame_host_impl.h
index 5c92e60b..0285f51 100644
--- a/content/browser/frame_host/render_frame_host_impl.h
+++ b/content/browser/frame_host/render_frame_host_impl.h
@@ -696,6 +696,10 @@
     return frame_host_associated_binding_;
   }
 
+  mojo::Binding<service_manager::mojom::InterfaceProvider>&
+  document_scoped_interface_provider_binding_for_testing() {
+    return document_scoped_interface_provider_binding_;
+  }
   void SetKeepAliveTimeoutForTesting(base::TimeDelta timeout);
 
   blink::WebSandboxFlags active_sandbox_flags() {
@@ -797,16 +801,11 @@
                                           uint32_t end_offset);
   void OnDidAccessInitialDocument();
   void OnDidChangeOpener(int32_t opener_routing_id);
-  void OnDidChangeName(const std::string& name, const std::string& unique_name);
-  void OnDidSetFramePolicyHeaders(
-      blink::WebSandboxFlags sandbox_flags,
-      const blink::ParsedFeaturePolicy& parsed_header);
 
   // A new set of CSP |policies| has been added to the document.
   void OnDidAddContentSecurityPolicies(
       const std::vector<ContentSecurityPolicy>& policies);
 
-  void OnEnforceInsecureRequestPolicy(blink::WebInsecureRequestPolicy policy);
   void OnDidChangeFramePolicy(int32_t frame_routing_id,
                               const blink::FramePolicy& frame_policy);
   void OnDidChangeFrameOwnerProperties(int32_t frame_routing_id,
@@ -882,7 +881,9 @@
   void IssueKeepAliveHandle(mojom::KeepAliveHandleRequest request) override;
   void DidCommitProvisionalLoad(
       std::unique_ptr<FrameHostMsg_DidCommitProvisionalLoad_Params>
-          validated_params) override;
+          validated_params,
+      service_manager::mojom::InterfaceProviderRequest
+          interface_provider_request) override;
   void BeginNavigation(const CommonNavigationParams& common_params,
                        mojom::BeginNavigationParamsPtr begin_params) override;
   void SubresourceResponseStarted(const GURL& url,
@@ -891,6 +892,13 @@
                                   ResourceType resource_type,
                                   const std::string& ip,
                                   uint32_t cert_status) override;
+  void DidChangeName(const std::string& name,
+                     const std::string& unique_name) override;
+  void EnforceInsecureRequestPolicy(
+      blink::WebInsecureRequestPolicy policy) override;
+  void DidSetFramePolicyHeaders(
+      blink::WebSandboxFlags sandbox_flags,
+      const blink::ParsedFeaturePolicy& parsed_header) override;
 
   // Registers Mojo interfaces that this frame host makes available.
   void RegisterMojoInterfaces();
@@ -1379,17 +1387,38 @@
   std::unique_ptr<JavaInterfaceProvider> java_interface_registry_;
 #endif
 
-  // Binding for the InterfaceProvider through which this RFHI exposes Mojo
-  // services to the corresonding RenderFrame.
+  // Binding for the InterfaceProvider through which this RenderFrameHostImpl
+  // exposes frame-scoped Mojo services to the currently active document in the
+  // corresponding RenderFrame.
   //
-  // Normally, whoever creates this RFHI, is responsible for creating a message
-  // pipe, then supplying the request end to BindInterfaceProviderRequest(), and
-  // plumbing the client end to the RenderFrame in the renderer process.
+  // GetInterface messages dispatched through this binding are guaranteed to
+  // originate from the document corresponding to the last committed navigation;
+  // or the inital empty document if no real navigation has ever been committed.
   //
-  // Currently the only exception to this rule are out-of-process iframes, where
-  // the child RFHI takes care of this internally in CreateRenderFrame().
+  // The InterfaceProvider interface connection is established as follows:
+  //
+  // 1) For the initial empty document, the call site that creates this
+  //    RenderFrameHost is responsible for creating a message pipe, binding its
+  //    request end to this instance by calling BindInterfaceProviderRequest(),
+  //    and plumbing the client end to the renderer process, and ultimately
+  //    supplying it to the RenderFrame synchronously at construction time.
+  //
+  //    The only exception to this rule are out-of-process child frames, whose
+  //    RenderFrameHosts take care of this internally in CreateRenderFrame().
+  //
+  // 2) For subsequent documents, the RenderFrame creates a new message pipe
+  //    every time a cross-document navigation is committed, and pushes its
+  //    request end to the browser process as part of DidCommitProvisionalLoad.
+  //    The client end will be used by the new document corresponding to the
+  //    committed naviagation to access services exposed by the RenderFrameHost.
+  //
+  // This is required to prevent GetInterface messages racing with navigation
+  // commit from being serviced in the security context corresponding to the
+  // wrong document in the RenderFrame. The benefit of the approach taken is
+  // that it does not necessitate using channel-associated InterfaceProvider
+  // interfaces.
   mojo::Binding<service_manager::mojom::InterfaceProvider>
-      interface_provider_binding_;
+      document_scoped_interface_provider_binding_;
 
   // IPC-friendly token that represents this host for AndroidOverlays, if we
   // have created one yet.
diff --git a/content/browser/frame_host/render_frame_host_impl_browsertest.cc b/content/browser/frame_host/render_frame_host_impl_browsertest.cc
index 40fa602a..be6b073 100644
--- a/content/browser/frame_host/render_frame_host_impl_browsertest.cc
+++ b/content/browser/frame_host/render_frame_host_impl_browsertest.cc
@@ -6,9 +6,13 @@
 
 #include <utility>
 
-#include "base/macros.h"
+#include "base/bind.h"
+#include "base/bind_helpers.h"
 #include "base/run_loop.h"
+#include "base/test/bind_test_util.h"
+#include "base/test/mock_callback.h"
 #include "content/browser/frame_host/navigation_handle_impl.h"
+#include "content/browser/interface_provider_filtering.h"
 #include "content/browser/web_contents/web_contents_impl.h"
 #include "content/common/frame_messages.h"
 #include "content/public/browser/javascript_dialog_manager.h"
@@ -24,10 +28,13 @@
 #include "content/public/test/test_navigation_observer.h"
 #include "content/public/test/test_utils.h"
 #include "content/shell/browser/shell.h"
+#include "content/test/did_commit_provisional_load_interceptor.h"
+#include "content/test/frame_host_test_interface.mojom.h"
 #include "content/test/test_content_browser_client.h"
 #include "net/dns/mock_host_resolver.h"
 #include "net/test/embedded_test_server/embedded_test_server.h"
 #include "net/test/embedded_test_server/http_request.h"
+#include "testing/gmock/include/gmock/gmock.h"
 #include "third_party/WebKit/common/page/page_visibility_state.mojom.h"
 
 namespace content {
@@ -62,7 +69,6 @@
 
   DISALLOW_COPY_AND_ASSIGN(PrerenderTestContentBrowserClient);
 };
-
 }  // anonymous namespace
 
 // TODO(mlamouri): part of these tests were removed because they were dependent
@@ -875,4 +881,333 @@
   EXPECT_EQ("\"Second part received\"", second_part_received);
 }
 
+namespace {
+
+// Allows injecting a fake, test-provided |interface_provider_request| into
+// DidCommitProvisionalLoad messages in a given |web_contents| instead of the
+// real one coming from the renderer process.
+class ScopedFakeInterfaceProviderRequestInjector
+    : public DidCommitProvisionalLoadInterceptor {
+ public:
+  explicit ScopedFakeInterfaceProviderRequestInjector(WebContents* web_contents)
+      : DidCommitProvisionalLoadInterceptor(web_contents) {}
+  ~ScopedFakeInterfaceProviderRequestInjector() override = default;
+
+  // Sets the fake InterfaceProvider |request| to inject into the next incoming
+  // DidCommitProvisionalLoad message.
+  void set_fake_request_for_next_commit(
+      service_manager::mojom::InterfaceProviderRequest request) {
+    next_fake_request_ = std::move(request);
+  }
+
+  const GURL& url_of_last_commit() const { return url_of_last_commit_; }
+
+  const service_manager::mojom::InterfaceProviderRequest&
+  original_request_of_last_commit() const {
+    return original_request_of_last_commit_;
+  }
+
+ protected:
+  void WillDispatchDidCommitProvisionalLoad(
+      RenderFrameHost* render_frame_host,
+      ::FrameHostMsg_DidCommitProvisionalLoad_Params* params,
+      service_manager::mojom::InterfaceProviderRequest*
+          interface_provider_request) override {
+    url_of_last_commit_ = params->url;
+    original_request_of_last_commit_ = std::move(*interface_provider_request);
+    *interface_provider_request = std::move(next_fake_request_);
+  }
+
+ private:
+  service_manager::mojom::InterfaceProviderRequest next_fake_request_;
+  service_manager::mojom::InterfaceProviderRequest
+      original_request_of_last_commit_;
+  GURL url_of_last_commit_;
+
+  DISALLOW_COPY_AND_ASSIGN(ScopedFakeInterfaceProviderRequestInjector);
+};
+
+// Monitors the |document_scoped_interface_provider_binding_| of the given
+// |render_frame_host| for incoming interface requests for |interface_name|, and
+// invokes |callback| synchronously just before such a request would be
+// dispatched.
+class ScopedInterfaceRequestMonitor
+    : public service_manager::mojom::InterfaceProviderInterceptorForTesting {
+ public:
+  ScopedInterfaceRequestMonitor(RenderFrameHost* render_frame_host,
+                                base::StringPiece interface_name,
+                                base::RepeatingClosure callback)
+      : rfhi_(static_cast<RenderFrameHostImpl*>(render_frame_host)),
+        impl_(binding().SwapImplForTesting(this)),
+        interface_name_(interface_name),
+        request_callback_(callback) {}
+
+  ~ScopedInterfaceRequestMonitor() override {
+    auto* old_impl = binding().SwapImplForTesting(impl_);
+    DCHECK_EQ(old_impl, this);
+  }
+
+ protected:
+  // service_manager::mojom::InterfaceProviderInterceptorForTesting:
+  service_manager::mojom::InterfaceProvider* GetForwardingInterface() override {
+    return impl_;
+  }
+
+  void GetInterface(const std::string& interface_name,
+                    mojo::ScopedMessagePipeHandle pipe) override {
+    if (interface_name == interface_name_)
+      request_callback_.Run();
+    GetForwardingInterface()->GetInterface(interface_name, std::move(pipe));
+  }
+
+ private:
+  mojo::Binding<service_manager::mojom::InterfaceProvider>& binding() {
+    return rfhi_->document_scoped_interface_provider_binding_for_testing();
+  }
+
+  RenderFrameHostImpl* rfhi_;
+  service_manager::mojom::InterfaceProvider* impl_;
+
+  std::string interface_name_;
+  base::RepeatingClosure request_callback_;
+
+  DISALLOW_COPY_AND_ASSIGN(ScopedInterfaceRequestMonitor);
+};
+
+// Calls |callback| whenever a navigation finishes in |render_frame_host|.
+class DidFinishNavigationObserver : public WebContentsObserver {
+ public:
+  DidFinishNavigationObserver(RenderFrameHost* render_frame_host,
+                              base::RepeatingClosure callback)
+      : WebContentsObserver(
+            WebContents::FromRenderFrameHost(render_frame_host)),
+        callback_(callback) {}
+
+ protected:
+  // WebContentsObserver:
+  void DidFinishNavigation(NavigationHandle* navigation_handle) override {
+    callback_.Run();
+  }
+
+ private:
+  base::RepeatingClosure callback_;
+  DISALLOW_COPY_AND_ASSIGN(DidFinishNavigationObserver);
+};
+
+}  // namespace
+
+// For cross-document navigations, the DidCommitProvisionalLoad message from
+// the renderer process will have its |interface_provider_request| argument set
+// to the request end of a new InterfaceProvider interface connection that will
+// be used by the newly committed document to access services exposed by the
+// RenderFrameHost.
+//
+// This test verifies that even if that |interface_provider_request| already has
+// pending interface requests, the RenderFrameHost binds the InterfaceProvider
+// request in such a way that these pending interface requests are dispatched
+// strictly after WebContentsObserver::DidFinishNavigation has fired, so that
+// the requests will be served correctly in the security context of the newly
+// committed document (i.e. GetLastCommittedURL/Origin will have been updated).
+IN_PROC_BROWSER_TEST_F(
+    RenderFrameHostImplBrowserTest,
+    EarlyInterfaceRequestsFromNewDocumentDispatchedAfterNavigationFinished) {
+  const GURL first_url(embedded_test_server()->GetURL("/title1.html"));
+  const GURL second_url(embedded_test_server()->GetURL("/title2.html"));
+
+  // Load a URL that maps to the same SiteInstance as the second URL, to make
+  // sure the second navigation will not be cross-process.
+  ASSERT_TRUE(NavigateToURL(shell(), first_url));
+
+  // Prepare an InterfaceProviderRequest with pending interface requests.
+  service_manager::mojom::InterfaceProviderPtr
+      interface_provider_with_pending_request;
+  service_manager::mojom::InterfaceProviderRequest
+      interface_provider_request_with_pending_request =
+          mojo::MakeRequest(&interface_provider_with_pending_request);
+  mojom::FrameHostTestInterfacePtr test_interface;
+  interface_provider_with_pending_request->GetInterface(
+      mojom::FrameHostTestInterface::Name_,
+      mojo::MakeRequest(&test_interface).PassMessagePipe());
+
+  // Replace the |interface_provider_request| argument in the next
+  // DidCommitProvisionalLoad message coming from the renderer with the
+  // rigged |interface_provider_with_pending_request| from above.
+  ScopedFakeInterfaceProviderRequestInjector injector(shell()->web_contents());
+  injector.set_fake_request_for_next_commit(
+      std::move(interface_provider_request_with_pending_request));
+
+  // Set up |dispatched_interface_request_callback| to be invoked when the
+  // interface request for FrameHostTestInterface is dispatched to the
+  // RenderFrameHostImpl.
+  base::MockCallback<base::RepeatingClosure>
+      dispatched_interface_request_callback;
+  auto* main_rfh = shell()->web_contents()->GetMainFrame();
+  ScopedInterfaceRequestMonitor monitor(
+      main_rfh, mojom::FrameHostTestInterface::Name_,
+      dispatched_interface_request_callback.Get());
+
+  // Set up |navigation_finished_callback| to be fired on
+  // WebContentsObserver::DidFinishNavigation.
+  base::MockCallback<base::RepeatingClosure> navigation_finished_callback;
+  DidFinishNavigationObserver navigation_finish_observer(
+      main_rfh, navigation_finished_callback.Get());
+
+  // Expect that DidFinishNavigation takes place first, and dispatching second.
+  testing::InSequence in_sequence;
+  EXPECT_CALL(navigation_finished_callback, Run());
+  EXPECT_CALL(dispatched_interface_request_callback, Run());
+
+  // Start the same-process navigation.
+  test::ScopedInterfaceFilterBypass filter_bypass;
+  ASSERT_TRUE(NavigateToURL(shell(), second_url));
+  ASSERT_EQ(main_rfh, shell()->web_contents()->GetMainFrame());
+  ASSERT_EQ(second_url, injector.url_of_last_commit());
+  ASSERT_TRUE(injector.original_request_of_last_commit().is_pending());
+}
+
+// The InterfaceProvider interface, which is used by the RenderFrame to access
+// Mojo services exposed by the RenderFrameHost, is not Channel-associated,
+// thus not synchronized with navigation IPC messages. As a result, when the
+// renderer commits a load, the DidCommitProvisional message might be at race
+// with GetInterface messages, for example, an interface request issued by the
+// previous document in its unload handler might arrive to the browser process
+// just a moment after DidCommitProvisionalLoad.
+//
+// This test verifies that even if there is such a last-second GetInterface
+// message originating from the previous document, it is no longer serviced.
+IN_PROC_BROWSER_TEST_F(RenderFrameHostImplBrowserTest,
+                       LateInterfaceRequestsFromOldDocumentNotDispatched) {
+  const GURL first_url(embedded_test_server()->GetURL("/title1.html"));
+  const GURL second_url(embedded_test_server()->GetURL("/title2.html"));
+
+  // Prepare an InterfaceProviderRequest with no pending requests.
+  service_manager::mojom::InterfaceProviderPtr interface_provider;
+  service_manager::mojom::InterfaceProviderRequest interface_provider_request =
+      mojo::MakeRequest(&interface_provider);
+
+  // Set up a cunning mechnism to replace the |interface_provider_request|
+  // argument in next DidCommitProvisionalLoad message with the rigged
+  // |interface_provider_request| from above, whose client end is controlled by
+  // this test; then trigger a navigation.
+  {
+    ScopedFakeInterfaceProviderRequestInjector injector(
+        shell()->web_contents());
+    test::ScopedInterfaceFilterBypass filter_bypass;
+    injector.set_fake_request_for_next_commit(
+        std::move(interface_provider_request));
+
+    ASSERT_TRUE(NavigateToURL(shell(), first_url));
+    ASSERT_EQ(first_url, injector.url_of_last_commit());
+    ASSERT_TRUE(injector.original_request_of_last_commit().is_pending());
+  }
+
+  // Prepare an interface request for FrameHostTestInterface.
+  mojom::FrameHostTestInterfacePtr test_interface;
+  auto test_interface_request = mojo::MakeRequest(&test_interface);
+
+  // Set up |dispatched_interface_request_callback| that would be invoked if the
+  // interface request for FrameHostTestInterface was ever dispatched to the
+  // RenderFrameHostImpl.
+  base::MockCallback<base::RepeatingClosure>
+      dispatched_interface_request_callback;
+  auto* main_rfh = shell()->web_contents()->GetMainFrame();
+  ScopedInterfaceRequestMonitor monitor(
+      main_rfh, mojom::FrameHostTestInterface::Name_,
+      dispatched_interface_request_callback.Get());
+
+  // Set up the |test_interface request| to arrive on the InterfaceProvider
+  // connection corresponding to the old document in the middle of the firing of
+  // WebContentsObserver::DidFinishNavigation.
+  // TODO(engedy): Should we PostTask() this instead just before synchronously
+  // invoking DidCommitProvisionalLoad?
+  //
+  // Also set up |navigation_finished_callback| to be invoked afterwards, as a
+  // sanity check to ensure that the request injection is actually executed.
+  base::MockCallback<base::RepeatingClosure> navigation_finished_callback;
+  DidFinishNavigationObserver navigation_finish_observer(
+      main_rfh, base::BindLambdaForTesting([&]() {
+        interface_provider->GetInterface(
+            mojom::FrameHostTestInterface::Name_,
+            test_interface_request.PassMessagePipe());
+        std::move(navigation_finished_callback).Run();
+      }));
+
+  // The InterfaceProvider connection that semantically belongs to the old
+  // document, but whose client end is actually controlled by this test, should
+  // still be alive and well.
+  ASSERT_TRUE(test_interface.is_bound());
+  ASSERT_FALSE(test_interface.encountered_error());
+
+  // Expect that the GetInterface message will never be dispatched, but the
+  // DidFinishNavigation callback wll be invoked.
+  EXPECT_CALL(dispatched_interface_request_callback, Run()).Times(0);
+  EXPECT_CALL(navigation_finished_callback, Run());
+
+  // Start the same-process navigation.
+  ASSERT_TRUE(NavigateToURL(shell(), second_url));
+
+  // Wait for a connection error on the |test_interface| as a signal, after
+  // which it can be safely assumed that no GetInterface message will ever be
+  // dispatched from that old InterfaceConnection.
+  base::RunLoop run_loop;
+  test_interface.set_connection_error_handler(run_loop.QuitWhenIdleClosure());
+  run_loop.Run();
+
+  EXPECT_TRUE(test_interface.encountered_error());
+}
+
+// Test the edge case where the `window` global object asssociated with the
+// initial empty document is re-used for document corresponding to the first
+// real committed load. This happens when the security origins of the two
+// documents are the same. We do not want to recalculate this in the browser
+// process, however, so for the first commit we leave it up to the renderer
+// whether it wants to replace the InterfaceProvider connection or not.
+IN_PROC_BROWSER_TEST_F(RenderFrameHostImplBrowserTest,
+                       InterfaceProviderRequestIsOptionalForFirstCommit) {
+  const GURL main_frame_url(embedded_test_server()->GetURL("/title1.html"));
+  const GURL subframe_url(embedded_test_server()->GetURL("/title2.html"));
+
+  service_manager::mojom::InterfaceProviderPtr interface_provider;
+  auto stub_interface_provider_request = mojo::MakeRequest(&interface_provider);
+  service_manager::mojom::InterfaceProviderRequest
+      null_interface_provider_request(nullptr);
+
+  for (auto* interface_provider_request :
+       {&stub_interface_provider_request, &null_interface_provider_request}) {
+    SCOPED_TRACE(interface_provider_request->is_pending());
+
+    ASSERT_TRUE(NavigateToURL(shell(), main_frame_url));
+
+    ScopedFakeInterfaceProviderRequestInjector injector(
+        shell()->web_contents());
+    injector.set_fake_request_for_next_commit(
+        std::move(*interface_provider_request));
+
+    // Must set 'src` before adding the iframe element to the DOM, otherwise it
+    // will load `about:blank` as the first real load instead of |subframe_url|.
+    // See: https://crbug.com/778318.
+    //
+    // Note that the child frame will first cycle through loading the initial
+    // empty document regardless of when/how/if the `src` attribute is set.
+    const auto script = base::StringPrintf(
+        "let f = document.createElement(\"iframe\");"
+        "f.src=\"%s\"; "
+        "document.body.append(f);",
+        subframe_url.spec().c_str());
+    ASSERT_TRUE(ExecuteScript(shell(), script));
+
+    WaitForLoadStop(shell()->web_contents());
+
+    FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
+                              ->GetFrameTree()
+                              ->root();
+    ASSERT_EQ(1u, root->child_count());
+    FrameTreeNode* child = root->child_at(0u);
+
+    EXPECT_FALSE(injector.original_request_of_last_commit().is_pending());
+    EXPECT_TRUE(child->has_committed_real_load());
+    EXPECT_EQ(subframe_url, child->current_url());
+  }
+}
+
 }  // namespace content
diff --git a/content/browser/frame_host/render_frame_host_manager.cc b/content/browser/frame_host/render_frame_host_manager.cc
index 53b0f5b..ba8ac7b 100644
--- a/content/browser/frame_host/render_frame_host_manager.cc
+++ b/content/browser/frame_host/render_frame_host_manager.cc
@@ -730,8 +730,17 @@
     // not be recreated if the URL didn't change. So instead of calling
     // CleanUpNavigation just discard the speculative RenderFrameHost if one
     // exists.
-    if (speculative_render_frame_host_)
+    if (speculative_render_frame_host_) {
+      // If the speculative RenderFrameHost is trying to commit a navigation,
+      // inform the NavigationController that the load of the corresponding
+      // NavigationEntry stopped.
+      if (speculative_render_frame_host_->navigation_handle()) {
+        frame_tree_node_->navigator()->DiscardPendingEntryIfNeeded(
+            speculative_render_frame_host_->navigation_handle()
+                ->pending_nav_entry_id());
+      }
       DiscardUnusedFrame(UnsetSpeculativeRenderFrameHost());
+    }
 
     // Short-term solution: avoid creating a WebUI for subframes because
     // non-PlzNavigate code path doesn't do it and some WebUI pages don't
@@ -855,6 +864,14 @@
 void RenderFrameHostManager::CleanUpNavigation() {
   CHECK(IsBrowserSideNavigationEnabled());
   if (speculative_render_frame_host_) {
+    // If the speculative RenderFrameHost is trying to commit a navigation,
+    // inform the NavigationController that the load of the corresponding
+    // NavigationEntry stopped.
+    if (speculative_render_frame_host_->navigation_handle()) {
+      frame_tree_node_->navigator()->DiscardPendingEntryIfNeeded(
+          speculative_render_frame_host_->navigation_handle()
+              ->pending_nav_entry_id());
+    }
     bool was_loading = speculative_render_frame_host_->is_loading();
     DiscardUnusedFrame(UnsetSpeculativeRenderFrameHost());
     if (was_loading)
diff --git a/content/browser/frame_host/render_frame_host_manager_browsertest.cc b/content/browser/frame_host/render_frame_host_manager_browsertest.cc
index 84ad085..3977e14 100644
--- a/content/browser/frame_host/render_frame_host_manager_browsertest.cc
+++ b/content/browser/frame_host/render_frame_host_manager_browsertest.cc
@@ -47,6 +47,7 @@
 #include "content/public/test/browser_test_utils.h"
 #include "content/public/test/content_browser_test.h"
 #include "content/public/test/content_browser_test_utils.h"
+#include "content/public/test/controllable_http_response.h"
 #include "content/public/test/test_frame_navigation_observer.h"
 #include "content/public/test/test_navigation_observer.h"
 #include "content/public/test/test_utils.h"
@@ -1498,6 +1499,103 @@
   EXPECT_FALSE(contents->GetController().GetVisibleEntry());
 }
 
+// Ensures that a pending navigation's URL  is no longer visible after the
+// speculative RFH is discarded due to a concurrent renderer-initiated
+// navigation.  See https://crbug.com/760342.
+IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
+                       ResetVisibleURLOnCrossProcessNavigationInterrupted) {
+  if (!IsBrowserSideNavigationEnabled())
+    return;
+  const std::string kVictimPath = "/victim.html";
+  const std::string kAttackPath = "/attack.html";
+  ControllableHttpResponse victim_response(embedded_test_server(), kVictimPath);
+  ControllableHttpResponse attack_response(embedded_test_server(), kAttackPath);
+  EXPECT_TRUE(embedded_test_server()->Start());
+
+  const GURL kVictimURL = embedded_test_server()->GetURL("a.com", kVictimPath);
+  const GURL kAttackURL = embedded_test_server()->GetURL("b.com", kAttackPath);
+
+  // First navigate to the attacker page. This page will be cross-site compared
+  // to the next navigations we will attempt.
+  const GURL kAttackInitialURL =
+      embedded_test_server()->GetURL("b.com", "/title1.html");
+  NavigateToURL(shell(), kAttackInitialURL);
+  EXPECT_EQ(kAttackInitialURL, shell()->web_contents()->GetVisibleURL());
+
+  // Now, start a browser-initiated cross-site navigation to a new page that
+  // will hang at ready to commit stage.
+  TestNavigationManager victim_navigation(shell()->web_contents(), kVictimURL);
+  shell()->LoadURL(kVictimURL);
+  EXPECT_TRUE(victim_navigation.WaitForRequestStart());
+  victim_navigation.ResumeNavigation();
+
+  victim_response.WaitForRequest();
+  victim_response.Send(
+      "HTTP/1.1 200 OK\r\n"
+      "Content-Type: text/html; charset=utf-8\r\n"
+      "\r\n");
+  EXPECT_TRUE(victim_navigation.WaitForResponse());
+  victim_navigation.ResumeNavigation();
+
+  // The navigation is ready to commit: it has been handed to the speculative
+  // RenderFrameHost for commit.
+  RenderFrameHostImpl* speculative_rfh =
+      static_cast<WebContentsImpl*>(shell()->web_contents())
+          ->GetFrameTree()
+          ->root()
+          ->render_manager()
+          ->speculative_frame_host();
+  CHECK(speculative_rfh);
+  EXPECT_TRUE(speculative_rfh->is_loading());
+
+  // Since we have a browser-initiated pending navigation, the navigation URL is
+  // showing in the address bar.
+  EXPECT_EQ(kVictimURL, shell()->web_contents()->GetVisibleURL());
+
+  // The attacker page requests a navigation to a new document while the
+  // browser-initiated navigation hasn't committed yet.
+  TestNavigationManager attack_navigation(shell()->web_contents(), kAttackURL);
+  EXPECT_TRUE(ExecuteScriptWithoutUserGesture(
+      shell()->web_contents(),
+      "location.href = \"" + kAttackURL.spec() + "\";"));
+  EXPECT_TRUE(attack_navigation.WaitForRequestStart());
+
+  // This deletes the speculative RenderFrameHost that was supposed to commit
+  // the browser-initiated navigation.
+  speculative_rfh = static_cast<WebContentsImpl*>(shell()->web_contents())
+                        ->GetFrameTree()
+                        ->root()
+                        ->render_manager()
+                        ->speculative_frame_host();
+  EXPECT_FALSE(speculative_rfh);
+
+  // The URL of the browser-initiated navigation should no longer be shown in
+  // the address bar since the RenderFrameHost that was supposed to commit it
+  // has been discarded. Instead, we should be showing the URL of the current
+  // page as we do not show the URL of pending navigations when they are
+  // renderer-initiated.
+  EXPECT_NE(kVictimURL, shell()->web_contents()->GetVisibleURL());
+  EXPECT_EQ(kAttackInitialURL, shell()->web_contents()->GetVisibleURL());
+
+  // The attacker navigation results in a 204.
+  attack_navigation.ResumeNavigation();
+  attack_response.WaitForRequest();
+  attack_response.Send(
+      "HTTP/1.1 204 OK\r\n"
+      "Connection: close\r\n"
+      "\r\n");
+  attack_navigation.WaitForNavigationFinished();
+  speculative_rfh = static_cast<WebContentsImpl*>(shell()->web_contents())
+                        ->GetFrameTree()
+                        ->root()
+                        ->render_manager()
+                        ->speculative_frame_host();
+  EXPECT_FALSE(speculative_rfh);
+
+  // We are still showing the URL of the current page.
+  EXPECT_EQ(kAttackInitialURL, shell()->web_contents()->GetVisibleURL());
+}
+
 // Test for crbug.com/9682.  We should not show the URL for a pending renderer-
 // initiated navigation in a new tab if it is not the initial navigation.  In
 // this case, the renderer will not notify us of a modification, so we cannot
diff --git a/content/browser/interface_provider_filtering.cc b/content/browser/interface_provider_filtering.cc
index d330e24..239566b 100644
--- a/content/browser/interface_provider_filtering.cc
+++ b/content/browser/interface_provider_filtering.cc
@@ -14,6 +14,8 @@
 namespace content {
 namespace {
 
+bool g_bypass_interface_filtering_for_testing = false;
+
 void FilterInterfacesImpl(
     const char* spec,
     int process_id,
@@ -40,6 +42,9 @@
     const char* spec,
     int process_id,
     service_manager::mojom::InterfaceProviderRequest request) {
+  if (g_bypass_interface_filtering_for_testing)
+    return request;
+
   service_manager::mojom::InterfaceProviderPtr provider;
   auto filtered_request = mojo::MakeRequest(&provider);
   if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
@@ -54,4 +59,18 @@
   return filtered_request;
 }
 
+namespace test {
+
+ScopedInterfaceFilterBypass::ScopedInterfaceFilterBypass() {
+  // Nesting not supported.
+  DCHECK(!g_bypass_interface_filtering_for_testing);
+  g_bypass_interface_filtering_for_testing = true;
+}
+
+ScopedInterfaceFilterBypass::~ScopedInterfaceFilterBypass() {
+  g_bypass_interface_filtering_for_testing = false;
+}
+
+}  // namespace test
+
 }  // namespace content
diff --git a/content/browser/interface_provider_filtering.h b/content/browser/interface_provider_filtering.h
index 9d0d84ce..205c50b 100644
--- a/content/browser/interface_provider_filtering.h
+++ b/content/browser/interface_provider_filtering.h
@@ -5,7 +5,11 @@
 #ifndef CONTENT_BROWSER_INTERFACE_PROVIDER_FILTERING_H_
 #define CONTENT_BROWSER_INTERFACE_PROVIDER_FILTERING_H_
 
+#include <memory>
+
+#include "base/macros.h"
 #include "base/strings/string_piece.h"
+#include "content/common/content_export.h"
 #include "services/service_manager/public/interfaces/interface_provider.mojom.h"
 
 namespace content {
@@ -25,5 +29,23 @@
     int process_id,
     service_manager::mojom::InterfaceProviderRequest request);
 
+namespace test {
+
+// Allows through all interface requests while in scope. For testing only.
+//
+// TODO(https://crbug.com/792407): See if browser tests can just set up the
+// service_Manager::Connector properly instead of this heavy-handed solution.
+class CONTENT_EXPORT ScopedInterfaceFilterBypass {
+ public:
+  ScopedInterfaceFilterBypass();
+  ~ScopedInterfaceFilterBypass();
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(ScopedInterfaceFilterBypass);
+};
+
+}  // namespace test
+
 }  // namespace content
+
 #endif  // CONTENT_BROWSER_INTERFACE_PROVIDER_FILTERING_H_
diff --git a/content/browser/loader/resource_loader.cc b/content/browser/loader/resource_loader.cc
index e64c2587..58ba7dd 100644
--- a/content/browser/loader/resource_loader.cc
+++ b/content/browser/loader/resource_loader.cc
@@ -35,6 +35,7 @@
 #include "net/base/io_buffer.h"
 #include "net/base/load_flags.h"
 #include "net/cert/symantec_certs.h"
+#include "net/cert/x509_util.h"
 #include "net/http/http_response_headers.h"
 #include "net/nqe/effective_connection_type.h"
 #include "net/nqe/network_quality_estimator.h"
@@ -120,16 +121,13 @@
           request->ssl_info().key_exchange_group;
       response->head.signed_certificate_timestamps =
           request->ssl_info().signed_certificate_timestamps;
-      std::string encoded;
-      bool rv = net::X509Certificate::GetDEREncoded(
-          request->ssl_info().cert->os_cert_handle(), &encoded);
-      DCHECK(rv);
-      response->head.certificate.push_back(encoded);
-      for (auto* cert :
-           request->ssl_info().cert->GetIntermediateCertificates()) {
-        rv = net::X509Certificate::GetDEREncoded(cert, &encoded);
-        DCHECK(rv);
-        response->head.certificate.push_back(encoded);
+      response->head.certificate.emplace_back(
+          net::x509_util::CryptoBufferAsStringPiece(
+              request->ssl_info().cert->cert_buffer()));
+      for (const auto& cert :
+           request->ssl_info().cert->intermediate_buffers()) {
+        response->head.certificate.emplace_back(
+            net::x509_util::CryptoBufferAsStringPiece(cert.get()));
       }
     }
   } else {
diff --git a/content/browser/quota_dispatcher_host.cc b/content/browser/quota_dispatcher_host.cc
index 7206494f..ab3061f 100644
--- a/content/browser/quota_dispatcher_host.cc
+++ b/content/browser/quota_dispatcher_host.cc
@@ -14,7 +14,7 @@
 #include "mojo/public/cpp/bindings/strong_binding.h"
 #include "net/base/url_util.h"
 #include "storage/browser/quota/quota_manager.h"
-#include "url/gurl.h"
+#include "url/origin.h"
 
 using storage::QuotaClient;
 using storage::QuotaManager;
@@ -48,11 +48,11 @@
       weak_factory_(this) {}
 
 void QuotaDispatcherHost::QueryStorageUsageAndQuota(
-    const GURL& origin_url,
+    const url::Origin& origin,
     storage::StorageType storage_type,
     QueryStorageUsageAndQuotaCallback callback) {
   quota_manager_->GetUsageAndQuotaForWebApps(
-      origin_url, storage_type,
+      origin.GetURL(), storage_type,
       base::Bind(&QuotaDispatcherHost::DidQueryStorageUsageAndQuota,
                  weak_factory_.GetWeakPtr(),
                  base::Passed(std::move(callback))));
@@ -60,7 +60,7 @@
 
 void QuotaDispatcherHost::RequestStorageQuota(
     int64_t render_frame_id,
-    const GURL& origin_url,
+    const url::Origin& origin,
     storage::StorageType storage_type,
     uint64_t requested_size,
     mojom::QuotaDispatcherHost::RequestStorageQuotaCallback callback) {
@@ -75,14 +75,14 @@
          storage_type == storage::kStorageTypePersistent);
   if (storage_type == storage::kStorageTypePersistent) {
     quota_manager_->GetUsageAndQuotaForWebApps(
-        origin_url, storage_type,
+        origin.GetURL(), storage_type,
         base::Bind(&QuotaDispatcherHost::DidGetPersistentUsageAndQuota,
-                   weak_factory_.GetWeakPtr(), render_frame_id, origin_url,
+                   weak_factory_.GetWeakPtr(), render_frame_id, origin,
                    storage_type, requested_size,
                    base::Passed(std::move(callback))));
   } else {
     quota_manager_->GetUsageAndQuotaForWebApps(
-        origin_url, storage_type,
+        origin.GetURL(), storage_type,
         base::Bind(&QuotaDispatcherHost::DidGetTemporaryUsageAndQuota,
                    weak_factory_.GetWeakPtr(), requested_size,
                    base::Passed(std::move(callback))));
@@ -99,7 +99,7 @@
 
 void QuotaDispatcherHost::DidGetPersistentUsageAndQuota(
     int64_t render_frame_id,
-    const GURL& origin_url,
+    const url::Origin& origin,
     storage::StorageType storage_type,
     uint64_t requested_quota,
     RequestStorageQuotaCallback callback,
@@ -117,7 +117,7 @@
   // TODO(nhiroki): The backend should accept uint64_t values.
   int64_t requested_quota_signed =
       base::saturated_cast<int64_t>(requested_quota);
-  if (quota_manager_->IsStorageUnlimited(origin_url, storage_type) ||
+  if (quota_manager_->IsStorageUnlimited(origin.GetURL(), storage_type) ||
       requested_quota_signed <= current_quota) {
     std::move(callback).Run(storage::kQuotaStatusOk, current_usage,
                             requested_quota);
@@ -129,20 +129,20 @@
   DCHECK(permission_context_);
   StorageQuotaParams params;
   params.render_frame_id = render_frame_id;
-  params.origin_url = origin_url;
+  params.origin_url = origin.GetURL();
   params.storage_type = storage_type;
   params.requested_size = requested_quota;
 
   permission_context_->RequestQuotaPermission(
       params, process_id_,
       base::Bind(&QuotaDispatcherHost::DidGetPermissionResponse,
-                 weak_factory_.GetWeakPtr(), origin_url, requested_quota,
+                 weak_factory_.GetWeakPtr(), origin, requested_quota,
                  current_usage, current_quota,
                  base::Passed(std::move(callback))));
 }
 
 void QuotaDispatcherHost::DidGetPermissionResponse(
-    const GURL& origin_url,
+    const url::Origin& origin,
     uint64_t requested_quota,
     int64_t current_usage,
     int64_t current_quota,
@@ -156,8 +156,11 @@
   }
 
   // Otherwise, return the new quota.
+  // TODO(sashab): net::GetHostOrSpecFromURL(origin.GetURL()) potentially does
+  // wasted work, e.g. if the origin has a host it can return that early. Maybe
+  // rewrite to just convert the host to a string directly.
   quota_manager_->SetPersistentHostQuota(
-      net::GetHostOrSpecFromURL(origin_url), requested_quota,
+      net::GetHostOrSpecFromURL(origin.GetURL()), requested_quota,
       base::Bind(&QuotaDispatcherHost::DidSetHostQuota,
                  weak_factory_.GetWeakPtr(), current_usage,
                  base::Passed(std::move(callback))));
diff --git a/content/browser/quota_dispatcher_host.h b/content/browser/quota_dispatcher_host.h
index b26612c..01e6999 100644
--- a/content/browser/quota_dispatcher_host.h
+++ b/content/browser/quota_dispatcher_host.h
@@ -10,12 +10,14 @@
 #include "content/public/browser/quota_permission_context.h"
 #include "storage/common/quota/quota_status_code.h"
 
-class GURL;
-
 namespace storage {
 class QuotaManager;
 }
 
+namespace url {
+class Origin;
+}
+
 namespace content {
 class QuotaPermissionContext;
 
@@ -34,11 +36,11 @@
 
   // content::mojom::QuotaDispatcherHost:
   void QueryStorageUsageAndQuota(
-      const GURL& origin_url,
+      const url::Origin& origin,
       storage::StorageType storage_type,
       QueryStorageUsageAndQuotaCallback callback) override;
   void RequestStorageQuota(int64_t render_frame_id,
-                           const GURL& origin_url,
+                           const url::Origin& origin,
                            storage::StorageType storage_type,
                            uint64_t requested_size,
                            RequestStorageQuotaCallback callback) override;
@@ -49,7 +51,7 @@
                                     int64_t usage,
                                     int64_t quota);
   void DidGetPersistentUsageAndQuota(int64_t render_frame_id,
-                                     const GURL& origin_url,
+                                     const url::Origin& origin,
                                      storage::StorageType storage_type,
                                      uint64_t requested_quota,
                                      RequestStorageQuotaCallback callback,
@@ -57,7 +59,7 @@
                                      int64_t usage,
                                      int64_t quota);
   void DidGetPermissionResponse(
-      const GURL& origin_url,
+      const url::Origin& origin,
       uint64_t requested_quota,
       int64_t current_usage,
       int64_t current_quota,
diff --git a/content/browser/renderer_host/media/media_stream_manager_unittest.cc b/content/browser/renderer_host/media/media_stream_manager_unittest.cc
index db870f3..6947037 100644
--- a/content/browser/renderer_host/media/media_stream_manager_unittest.cc
+++ b/content/browser/renderer_host/media/media_stream_manager_unittest.cc
@@ -18,6 +18,7 @@
 #include "content/browser/browser_thread_impl.h"
 #include "content/browser/renderer_host/media/media_stream_manager.h"
 #include "content/browser/renderer_host/media/media_stream_ui_proxy.h"
+#include "content/browser/renderer_host/media/mock_video_capture_provider.h"
 #include "content/public/common/content_switches.h"
 #include "content/public/test/test_browser_thread_bundle.h"
 #include "media/audio/audio_device_description.h"
@@ -43,6 +44,7 @@
 #endif
 
 using testing::_;
+using testing::Invoke;
 
 namespace content {
 
@@ -138,9 +140,19 @@
     audio_manager_ = std::make_unique<MockAudioManager>();
     audio_system_ =
         std::make_unique<media::AudioSystemImpl>(audio_manager_.get());
+    auto video_capture_provider = std::make_unique<MockVideoCaptureProvider>();
+    video_capture_provider_ = video_capture_provider.get();
     media_stream_manager_ = std::make_unique<MediaStreamManager>(
-        audio_system_.get(), audio_manager_->GetTaskRunner());
+        audio_system_.get(), audio_manager_->GetTaskRunner(),
+        std::move(video_capture_provider));
     base::RunLoop().RunUntilIdle();
+
+    ON_CALL(*video_capture_provider_, DoGetDeviceInfosAsync(_))
+        .WillByDefault(Invoke(
+            [](VideoCaptureProvider::GetDeviceInfosCallback& result_callback) {
+              std::vector<media::VideoCaptureDeviceInfo> stub_results;
+              base::ResetAndReturn(&result_callback).Run(stub_results);
+            }));
   }
 
   ~MediaStreamManagerTest() override { audio_manager_->Shutdown(); }
@@ -176,6 +188,7 @@
   content::TestBrowserThreadBundle thread_bundle_;
   std::unique_ptr<MockAudioManager> audio_manager_;
   std::unique_ptr<media::AudioSystem> audio_system_;
+  MockVideoCaptureProvider* video_capture_provider_;
   base::RunLoop run_loop_;
 
  private:
diff --git a/content/browser/renderer_host/media/service_video_capture_provider.cc b/content/browser/renderer_host/media/service_video_capture_provider.cc
index b837db09..6b73cd1 100644
--- a/content/browser/renderer_host/media/service_video_capture_provider.cc
+++ b/content/browser/renderer_host/media/service_video_capture_provider.cc
@@ -20,20 +20,28 @@
  public:
   ServiceConnectorImpl() {
     DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
-    connector_ = content::ServiceManagerConnection::GetForProcess()
-                     ->GetConnector()
-                     ->Clone();
-    DETACH_FROM_SEQUENCE(sequence_checker_);
+    // In unit test environments, there may not be any connector.
+    auto* connection = content::ServiceManagerConnection::GetForProcess();
+    if (!connection)
+      return;
+    auto* connector = connection->GetConnector();
+    if (!connector)
+      return;
+    connector_ = connector->Clone();
   }
 
   void BindFactoryProvider(
       video_capture::mojom::DeviceFactoryProviderPtr* provider) override {
+    if (!connector_) {
+      CHECK(false) << "Attempted to connect to the video capture service from "
+                      "a process that does not provide a "
+                      "ServiceManagerConnection";
+    }
     connector_->BindInterface(video_capture::mojom::kServiceName, provider);
   }
 
  private:
   std::unique_ptr<service_manager::Connector> connector_;
-  SEQUENCE_CHECKER(sequence_checker_);
 };
 
 }  // anonymous namespace
diff --git a/content/browser/renderer_host/pepper/pepper_socket_utils.cc b/content/browser/renderer_host/pepper/pepper_socket_utils.cc
index d1bf34b4..ab54673 100644
--- a/content/browser/renderer_host/pepper/pepper_socket_utils.cc
+++ b/content/browser/renderer_host/pepper/pepper_socket_utils.cc
@@ -21,6 +21,7 @@
 #include "net/base/ip_address.h"
 #include "net/base/ip_endpoint.h"
 #include "net/cert/x509_certificate.h"
+#include "net/cert/x509_util.h"
 #include "ppapi/c/private/ppb_net_address_private.h"
 #include "ppapi/shared_impl/private/net_address_private_impl.h"
 #include "ppapi/shared_impl/private/ppb_x509_certificate_private_shared.h"
@@ -123,11 +124,11 @@
   fields->SetField(
       PP_X509CERTIFICATE_PRIVATE_VALIDITY_NOT_AFTER,
       std::make_unique<base::Value>(cert.valid_expiry().ToDoubleT()));
-  std::string der;
-  net::X509Certificate::GetDEREncoded(cert.os_cert_handle(), &der);
-  fields->SetField(
-      PP_X509CERTIFICATE_PRIVATE_RAW,
-      base::Value::CreateWithCopiedBuffer(der.data(), der.length()));
+  base::StringPiece cert_der =
+      net::x509_util::CryptoBufferAsStringPiece(cert.cert_buffer());
+  fields->SetField(PP_X509CERTIFICATE_PRIVATE_RAW,
+                   std::make_unique<base::Value>(base::Value::BlobStorage(
+                       cert_der.begin(), cert_der.end())));
   return true;
 }
 
diff --git a/content/browser/renderer_host/render_widget_host_view_android.cc b/content/browser/renderer_host/render_widget_host_view_android.cc
index b12edad..d3bc8fe 100644
--- a/content/browser/renderer_host/render_widget_host_view_android.cc
+++ b/content/browser/renderer_host/render_widget_host_view_android.cc
@@ -2230,6 +2230,13 @@
   SendGestureEvent(web_gesture);
 }
 
+void RenderWidgetHostViewAndroid::OnSizeChanged() {
+  if (ime_adapter_android_)
+    ime_adapter_android_->UpdateAfterViewSizeChanged();
+  if (popup_zoomer_)
+    popup_zoomer_->HidePopup();
+}
+
 void RenderWidgetHostViewAndroid::OnPhysicalBackingSizeChanged() {
   EvictFrameIfNecessary();
   WasResized();
diff --git a/content/browser/renderer_host/render_widget_host_view_android.h b/content/browser/renderer_host/render_widget_host_view_android.h
index 67dbc3f..de85fa47 100644
--- a/content/browser/renderer_host/render_widget_host_view_android.h
+++ b/content/browser/renderer_host/render_widget_host_view_android.h
@@ -199,6 +199,7 @@
   bool OnMouseEvent(const ui::MotionEventAndroid& m) override;
   bool OnMouseWheelEvent(const ui::MotionEventAndroid& event) override;
   bool OnGestureEvent(const ui::GestureEventAndroid& event) override;
+  void OnSizeChanged() override;
   void OnPhysicalBackingSizeChanged() override;
 
   // ui::ViewAndroidObserver implementation:
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 7e978f0..8764c129 100644
--- a/content/browser/renderer_host/render_widget_host_view_browsertest.cc
+++ b/content/browser/renderer_host/render_widget_host_view_browsertest.cc
@@ -219,7 +219,9 @@
   // DidCommitProvisionalLoadInterceptor:
   void WillDispatchDidCommitProvisionalLoad(
       RenderFrameHost* render_frame_host,
-      ::FrameHostMsg_DidCommitProvisionalLoad_Params*) override {
+      ::FrameHostMsg_DidCommitProvisionalLoad_Params* params,
+      service_manager::mojom::InterfaceProviderRequest*
+          interface_provider_request) override {
     base::MessageLoop::ScopedNestableTaskAllower allow(
         base::MessageLoop::current());
     FrameWatcher(web_contents()).WaitFrames(1);
diff --git a/content/browser/security_exploit_browsertest.cc b/content/browser/security_exploit_browsertest.cc
index 503162b..cd00757 100644
--- a/content/browser/security_exploit_browsertest.cc
+++ b/content/browser/security_exploit_browsertest.cc
@@ -43,6 +43,7 @@
 #include "content/public/test/test_utils.h"
 #include "content/shell/browser/shell.h"
 #include "content/test/content_browser_test_utils_internal.h"
+#include "content/test/did_commit_provisional_load_interceptor.h"
 #include "content/test/mock_widget_impl.h"
 #include "content/test/test_content_browser_client.h"
 #include "ipc/ipc_security_test_util.h"
@@ -563,7 +564,7 @@
   params->origin = url::Origin::Create(GURL("http://bar.com/"));
 
   static_cast<mojom::FrameHost*>(root->current_frame_host())
-      ->DidCommitProvisionalLoad(std::move(params));
+      ->DidCommitProvisionalLoad(std::move(params), nullptr);
 
   // When the IPC message is received and validation fails, the process is
   // terminated. However, the notification for that should be processed in a
@@ -576,6 +577,90 @@
   ResourceDispatcherHost::Get()->SetDelegate(nullptr);
 }
 
+namespace {
+
+// Interceptor that replaces |interface_provider_request| with the specified
+// value for the first DidCommitProvisionalLoad message it observes in the given
+// |web_contents| while in scope.
+class ScopedInterfaceProviderRequestReplacer
+    : public DidCommitProvisionalLoadInterceptor {
+ public:
+  ScopedInterfaceProviderRequestReplacer(
+      WebContents* web_contents,
+      service_manager::mojom::InterfaceProviderRequest
+          interface_provider_request_override)
+      : DidCommitProvisionalLoadInterceptor(web_contents),
+        interface_provider_request_override_(
+            std::move(interface_provider_request_override)) {}
+  ~ScopedInterfaceProviderRequestReplacer() override = default;
+
+ protected:
+  void WillDispatchDidCommitProvisionalLoad(
+      RenderFrameHost* render_frame_host,
+      ::FrameHostMsg_DidCommitProvisionalLoad_Params* params,
+      service_manager::mojom::InterfaceProviderRequest*
+          interface_provider_request) override {
+    ASSERT_TRUE(interface_provider_request_override_.has_value());
+    *interface_provider_request =
+        std::move(interface_provider_request_override_).value();
+  }
+
+ private:
+  base::Optional<service_manager::mojom::InterfaceProviderRequest>
+      interface_provider_request_override_;
+
+  DISALLOW_COPY_AND_ASSIGN(ScopedInterfaceProviderRequestReplacer);
+};
+
+}  // namespace
+
+// Test that, as a general rule, not receiving a new InterfaceProviderRequest
+// for a cross-document navigation properly terminates the renderer process.
+// There is one exception to this rule, see: RenderFrameHostImplBrowserTest.
+// InterfaceProviderRequestIsOptionalForFirstCommit.
+IN_PROC_BROWSER_TEST_F(SecurityExploitBrowserTest,
+                       MissingInterfaceProviderOnNonSameDocumentCommit) {
+  const GURL start_url(embedded_test_server()->GetURL("/title1.html"));
+  const GURL non_same_document_url(
+      embedded_test_server()->GetURL("/title2.html"));
+
+  EXPECT_TRUE(NavigateToURL(shell(), start_url));
+
+  RenderProcessHostWatcher exit_observer(
+      shell()->web_contents()->GetMainFrame()->GetProcess(),
+      RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
+
+  ScopedInterfaceProviderRequestReplacer replacer(shell()->web_contents(),
+                                                  nullptr);
+  NavigateToURLAndExpectNoCommit(shell(), non_same_document_url);
+  exit_observer.Wait();
+
+  EXPECT_FALSE(exit_observer.did_exit_normally());
+}
+
+// Test that receiving a new InterfaceProviderRequest for a same-document
+// navigation properly terminates the renderer process.
+IN_PROC_BROWSER_TEST_F(SecurityExploitBrowserTest,
+                       SuperfluousInterfaceProviderOnSameDocumentCommit) {
+  const GURL start_url(embedded_test_server()->GetURL("/title1.html"));
+  const GURL same_document_url(
+      embedded_test_server()->GetURL("/title1.html#ref"));
+
+  EXPECT_TRUE(NavigateToURL(shell(), start_url));
+
+  RenderProcessHostWatcher exit_observer(
+      shell()->web_contents()->GetMainFrame()->GetProcess(),
+      RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
+
+  service_manager::mojom::InterfaceProviderPtr interface_provider;
+  ScopedInterfaceProviderRequestReplacer replacer(
+      shell()->web_contents(), mojo::MakeRequest(&interface_provider));
+  NavigateToURLAndExpectNoCommit(shell(), same_document_url);
+  exit_observer.Wait();
+
+  EXPECT_FALSE(exit_observer.did_exit_normally());
+}
+
 // Test that a compromised renderer cannot ask to upload an arbitrary file in
 // OpenURL.  This is a regression test for https://crbug.com/726067.
 IN_PROC_BROWSER_TEST_F(SecurityExploitBrowserTest,
@@ -680,8 +765,10 @@
   params->page_state = PageState::CreateFromURL(GURL("data:text/html,foo"));
   params->origin = url::Origin::Create(GURL("about:blank"));
 
+  service_manager::mojom::InterfaceProviderPtr isolated_interface_provider;
   static_cast<mojom::FrameHost*>(child0_0->current_frame_host())
-      ->DidCommitProvisionalLoad(std::move(params));
+      ->DidCommitProvisionalLoad(
+          std::move(params), mojo::MakeRequest(&isolated_interface_provider));
 
   // Make sure we haven't changed the FrameNavigationEntry.  An attack would
   // modify the PageState but leave the SiteInstance as it was.
diff --git a/content/browser/web_contents/web_contents_impl_unittest.cc b/content/browser/web_contents/web_contents_impl_unittest.cc
index 183999c9..2e9ea19 100644
--- a/content/browser/web_contents/web_contents_impl_unittest.cc
+++ b/content/browser/web_contents/web_contents_impl_unittest.cc
@@ -2150,6 +2150,10 @@
   interstitial->Show();
   TestRenderFrameHost* interstitial_rfh =
       static_cast<TestRenderFrameHost*>(interstitial->GetMainFrame());
+
+  // Ensure the InterfaceProvider for the initial empty document is bound.
+  interstitial_rfh->InitializeRenderFrameIfNeeded();
+
   // The interstitial should not show until its navigation has committed.
   EXPECT_FALSE(interstitial->is_showing());
   EXPECT_FALSE(contents()->ShowingInterstitialPage());
diff --git a/content/browser/webauth/authenticator_impl.cc b/content/browser/webauth/authenticator_impl.cc
index eb72298..48a68feb 100644
--- a/content/browser/webauth/authenticator_impl.cc
+++ b/content/browser/webauth/authenticator_impl.cc
@@ -7,6 +7,7 @@
 #include <utility>
 
 #include "base/logging.h"
+#include "base/time/tick_clock.h"
 #include "content/public/browser/render_frame_host.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/common/service_manager_connection.h"
@@ -48,7 +49,19 @@
 }  // namespace
 
 AuthenticatorImpl::AuthenticatorImpl(RenderFrameHost* render_frame_host)
-    : render_frame_host_(render_frame_host), weak_factory_(this) {
+    : timer_(std::make_unique<base::OneShotTimer>()),
+      render_frame_host_(render_frame_host),
+      weak_factory_(this) {
+  DCHECK(render_frame_host_);
+}
+
+AuthenticatorImpl::AuthenticatorImpl(RenderFrameHost* render_frame_host,
+                                     service_manager::Connector* connector,
+                                     std::unique_ptr<base::OneShotTimer> timer)
+    : timer_(std::move(timer)),
+      render_frame_host_(render_frame_host),
+      connector_(connector),
+      weak_factory_(this) {
   DCHECK(render_frame_host_);
 }
 
@@ -63,10 +76,9 @@
     webauth::mojom::MakePublicKeyCredentialOptionsPtr options,
     MakeCredentialCallback callback) {
   // Ensure no other operations are in flight.
-  // TODO(kpaulhamus): Do this properly. http://crbug.com/785954.
   if (u2f_request_) {
     std::move(callback).Run(
-        webauth::mojom::AuthenticatorStatus::NOT_ALLOWED_ERROR, nullptr);
+        webauth::mojom::AuthenticatorStatus::PENDING_REQUEST, nullptr);
     return;
   }
 
@@ -100,14 +112,15 @@
     return;
   }
 
-  std::unique_ptr<CollectedClientData> client_data =
-      CollectedClientData::Create(authenticator_utils::kCreateType,
-                                  caller_origin.Serialize(),
-                                  std::move(options->challenge));
+  DCHECK(make_credential_response_callback_.is_null());
+  make_credential_response_callback_ = std::move(callback);
+  client_data_ = CollectedClientData::Create(authenticator_utils::kCreateType,
+                                             caller_origin.Serialize(),
+                                             std::move(options->challenge));
 
   // SHA-256 hash of the JSON data structure
   std::vector<uint8_t> client_data_hash(crypto::kSHA256Length);
-  crypto::SHA256HashString(client_data->SerializeToJson(),
+  crypto::SHA256HashString(client_data_->SerializeToJson(),
                            client_data_hash.data(), client_data_hash.size());
 
   // The application parameter is the SHA-256 hash of the UTF-8 encoding of
@@ -117,26 +130,25 @@
   crypto::SHA256HashString(relying_party_id, application_parameter.data(),
                            application_parameter.size());
 
-  auto copyable_callback = base::AdaptCallbackForRepeating(std::move(callback));
-
   // Start the timer (step 16 - https://w3c.github.io/webauthn/#makeCredential).
-  timer_.Start(FROM_HERE, options->adjusted_timeout,
-               base::Bind(&AuthenticatorImpl::OnTimeout, base::Unretained(this),
-                          copyable_callback));
+  DCHECK(timer_);
+  timer_->Start(
+      FROM_HERE, options->adjusted_timeout,
+      base::Bind(&AuthenticatorImpl::OnTimeout, base::Unretained(this)));
 
-  service_manager::Connector* connector =
-      ServiceManagerConnection::GetForProcess()->GetConnector();
+  if (!connector_) {
+    connector_ = ServiceManagerConnection::GetForProcess()->GetConnector();
+  }
 
   std::vector<std::unique_ptr<device::U2fDiscovery>> discoveries;
-  discoveries.push_back(std::make_unique<device::U2fHidDiscovery>(connector));
+  discoveries.push_back(std::make_unique<device::U2fHidDiscovery>(connector_));
 
   // Per fido-u2f-raw-message-formats:
   // The challenge parameter is the SHA-256 hash of the Client Data,
   // Among other things, the Client Data contains the challenge from the
   // relying party (hence the name of the parameter).
   device::U2fRegister::ResponseCallback response_callback = base::Bind(
-      &AuthenticatorImpl::OnDeviceResponse, weak_factory_.GetWeakPtr(),
-      copyable_callback, base::Passed(&client_data));
+      &AuthenticatorImpl::OnDeviceResponse, weak_factory_.GetWeakPtr());
 
   // Extract list of credentials to exclude.
   std::vector<std::vector<uint8_t>> registered_keys;
@@ -144,7 +156,8 @@
     registered_keys.push_back(credential->id);
   }
 
-  // TODO(kpaulhamus): Mock U2fRegister for unit tests. http://crbug.com/785955.
+  // TODO(kpaulhamus): Mock U2fRegister for unit tests.
+  // http://crbug.com/785955.
   u2f_request_ = device::U2fRegister::TryRegistration(
       registered_keys, client_data_hash, application_parameter,
       std::move(discoveries), response_callback);
@@ -154,38 +167,43 @@
 // |data| is returned for both successful sign and register responses, whereas
 //  |key_handle| is only returned for successful sign responses.
 void AuthenticatorImpl::OnDeviceResponse(
-    MakeCredentialCallback callback,
-    std::unique_ptr<CollectedClientData> client_data,
     device::U2fReturnCode status_code,
     const std::vector<uint8_t>& u2f_register_response,
     const std::vector<uint8_t>& key_handle) {
-  timer_.Stop();
+  timer_->Stop();
 
-  if (status_code == device::U2fReturnCode::SUCCESS) {
-    // TODO(kpaulhamus): Add fuzzers for the response parsers.
-    // http//crbug.com/785957.
-    std::unique_ptr<RegisterResponseData> response =
-        RegisterResponseData::CreateFromU2fRegisterResponse(
-            std::move(client_data), std::move(u2f_register_response));
-    std::move(callback).Run(webauth::mojom::AuthenticatorStatus::SUCCESS,
-                            CreatePublicKeyCredentialInfo(std::move(response)));
-  } else if (status_code == device::U2fReturnCode::FAILURE ||
-             status_code == device::U2fReturnCode::INVALID_PARAMS) {
-    std::move(callback).Run(webauth::mojom::AuthenticatorStatus::UNKNOWN_ERROR,
-                            nullptr);
+  switch (status_code) {
+    case device::U2fReturnCode::CONDITIONS_NOT_SATISFIED:
+      // Duplicate registration.
+      std::move(make_credential_response_callback_)
+          .Run(webauth::mojom::AuthenticatorStatus::NOT_ALLOWED_ERROR, nullptr);
+      break;
+    case device::U2fReturnCode::FAILURE:
+    case device::U2fReturnCode::INVALID_PARAMS:
+      std::move(make_credential_response_callback_)
+          .Run(webauth::mojom::AuthenticatorStatus::UNKNOWN_ERROR, nullptr);
+      break;
+    case device::U2fReturnCode::SUCCESS:
+      // TODO(kpaulhamus): Add fuzzers for the response parsers.
+      // http//crbug.com/785957.
+      std::unique_ptr<RegisterResponseData> response =
+          RegisterResponseData::CreateFromU2fRegisterResponse(
+              std::move(client_data_), std::move(u2f_register_response));
+      std::move(make_credential_response_callback_)
+          .Run(webauth::mojom::AuthenticatorStatus::SUCCESS,
+               CreatePublicKeyCredentialInfo(std::move(response)));
+      break;
   }
 
   u2f_request_.reset();
 }
 
-// TODO(kpaulhamus): Add unit test for this. http://crbug.com/785950.
-void AuthenticatorImpl::OnTimeout(
-    base::OnceCallback<void(webauth::mojom::AuthenticatorStatus,
-                            webauth::mojom::PublicKeyCredentialInfoPtr)>
-        callback) {
+void AuthenticatorImpl::OnTimeout() {
+  DCHECK(make_credential_response_callback_);
   u2f_request_.reset();
-  std::move(callback).Run(
-      webauth::mojom::AuthenticatorStatus::NOT_ALLOWED_ERROR, nullptr);
+  client_data_.reset();
+  std::move(make_credential_response_callback_)
+      .Run(webauth::mojom::AuthenticatorStatus::NOT_ALLOWED_ERROR, nullptr);
 }
 
 }  // namespace content
diff --git a/content/browser/webauth/authenticator_impl.h b/content/browser/webauth/authenticator_impl.h
index bf645f9..f3e5cc4 100644
--- a/content/browser/webauth/authenticator_impl.h
+++ b/content/browser/webauth/authenticator_impl.h
@@ -26,6 +26,10 @@
 enum class U2fReturnCode : uint8_t;
 }  // namespace device
 
+namespace service_manager {
+class Connector;
+}  // namespace service_manager
+
 namespace content {
 
 class RenderFrameHost;
@@ -34,6 +38,11 @@
 class CONTENT_EXPORT AuthenticatorImpl : public webauth::mojom::Authenticator {
  public:
   explicit AuthenticatorImpl(RenderFrameHost* render_frame_host);
+
+  // Permits setting connector and timer for testing.
+  explicit AuthenticatorImpl(RenderFrameHost* render_frame_host,
+                             service_manager::Connector*,
+                             std::unique_ptr<base::OneShotTimer>);
   ~AuthenticatorImpl() override;
 
   // Creates a binding between this object and |request|. Note that a
@@ -47,25 +56,24 @@
                       MakeCredentialCallback callback) override;
 
   // Callback to handle the async response from a U2fDevice.
-  void OnDeviceResponse(MakeCredentialCallback callback,
-                        std::unique_ptr<CollectedClientData> client_data,
-                        device::U2fReturnCode status_code,
+  void OnDeviceResponse(device::U2fReturnCode status_code,
                         const std::vector<uint8_t>& data,
                         const std::vector<uint8_t>& key_handle);
 
   // Runs when timer expires and cancels all issued requests to a U2fDevice.
-  void OnTimeout(
-      base::OnceCallback<void(webauth::mojom::AuthenticatorStatus,
-                              webauth::mojom::PublicKeyCredentialInfoPtr)>
-          callback);
+  void OnTimeout();
 
   // Owns pipes to this Authenticator from |render_frame_host_|.
   mojo::BindingSet<webauth::mojom::Authenticator> bindings_;
   std::unique_ptr<device::U2fRequest> u2f_request_;
-  base::OneShotTimer timer_;
-  RenderFrameHost* render_frame_host_;
-  base::WeakPtrFactory<AuthenticatorImpl> weak_factory_;
+  MakeCredentialCallback make_credential_response_callback_;
 
+  // Holds the client data to be returned to the caller.
+  std::unique_ptr<CollectedClientData> client_data_;
+  std::unique_ptr<base::OneShotTimer> timer_;
+  RenderFrameHost* render_frame_host_;
+  service_manager::Connector* connector_;
+  base::WeakPtrFactory<AuthenticatorImpl> weak_factory_;
   DISALLOW_COPY_AND_ASSIGN(AuthenticatorImpl);
 };
 
diff --git a/content/browser/webauth/authenticator_impl_unittest.cc b/content/browser/webauth/authenticator_impl_unittest.cc
index f9fc3eb..ee6be79 100644
--- a/content/browser/webauth/authenticator_impl_unittest.cc
+++ b/content/browser/webauth/authenticator_impl_unittest.cc
@@ -7,8 +7,12 @@
 #include <string>
 
 #include "base/base64url.h"
+#include "base/message_loop/message_loop.h"
 #include "base/run_loop.h"
 #include "base/test/gtest_util.h"
+#include "base/test/test_mock_time_task_runner.h"
+#include "base/time/tick_clock.h"
+#include "base/time/time.h"
 #include "content/browser/webauth/attestation_object.h"
 #include "content/browser/webauth/attested_credential_data.h"
 #include "content/browser/webauth/authenticator_data.h"
@@ -23,7 +27,9 @@
 #include "content/public/test/navigation_simulator.h"
 #include "content/public/test/test_renderer_host.h"
 #include "content/test/test_render_frame_host.h"
+#include "device/u2f/fake_hid_impl_for_testing.h"
 #include "mojo/public/cpp/bindings/binding.h"
+#include "services/device/public/interfaces/constants.mojom.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -464,6 +470,16 @@
     return authenticator;
   }
 
+  AuthenticatorPtr ConnectToAuthenticator(
+      service_manager::Connector* connector,
+      std::unique_ptr<base::OneShotTimer> timer) {
+    authenticator_impl_.reset(
+        new AuthenticatorImpl(main_rfh(), connector, std::move(timer)));
+    AuthenticatorPtr authenticator;
+    authenticator_impl_->Bind(mojo::MakeRequest(&authenticator));
+    return authenticator;
+  }
+
  private:
   std::unique_ptr<AuthenticatorImpl> authenticator_impl_;
 };
@@ -660,4 +676,44 @@
             response->GetCBOREncodedAttestationObject());
 }
 
+TEST_F(AuthenticatorImplTest, TestTimeout) {
+  SimulateNavigation(GURL(kTestOrigin1));
+  MakePublicKeyCredentialOptionsPtr options =
+      GetTestMakePublicKeyCredentialOptions();
+  TestMakeCredentialCallback cb;
+
+  // Set up service_manager::Connector for tests.
+  std::unique_ptr<device::FakeHidManager> fake_hid_manager =
+      std::make_unique<device::FakeHidManager>();
+  service_manager::mojom::ConnectorRequest request;
+  std::unique_ptr<service_manager::Connector> connector =
+      service_manager::Connector::Create(&request);
+  service_manager::Connector::TestApi test_api(connector.get());
+  test_api.OverrideBinderForTesting(
+      device::mojom::kServiceName, device::mojom::HidManager::Name_,
+      base::Bind(&device::FakeHidManager::AddBinding,
+                 base::Unretained(fake_hid_manager.get())));
+
+  // Set up a timer for testing.
+  scoped_refptr<base::TestMockTimeTaskRunner> task_runner(
+      new base::TestMockTimeTaskRunner(base::Time::Now(),
+                                       base::TimeTicks::Now()));
+  std::unique_ptr<base::TickClock> tick_clock = task_runner->GetMockTickClock();
+  auto timer = base::MakeUnique<base::OneShotTimer>(tick_clock.get());
+  timer->SetTaskRunner(task_runner);
+  AuthenticatorPtr authenticator =
+      ConnectToAuthenticator(connector.get(), std::move(timer));
+
+  authenticator->MakeCredential(std::move(options), cb.callback());
+
+  // Trigger timer.
+  base::RunLoop().RunUntilIdle();
+  task_runner->FastForwardBy(base::TimeDelta::FromMinutes(1));
+  std::pair<webauth::mojom::AuthenticatorStatus,
+            webauth::mojom::PublicKeyCredentialInfoPtr>& response =
+      cb.WaitForCallback();
+  EXPECT_EQ(webauth::mojom::AuthenticatorStatus::NOT_ALLOWED_ERROR,
+            response.first);
+}
+
 }  // namespace content
diff --git a/content/common/BUILD.gn b/content/common/BUILD.gn
index 8357828..b677488e 100644
--- a/content/common/BUILD.gn
+++ b/content/common/BUILD.gn
@@ -630,6 +630,7 @@
     "//services/viz/public/interfaces",
     "//skia/public/interfaces",
     "//storage/common:mojo_bindings",
+    "//third_party/WebKit/common:mojo_platform_bindings",
     "//third_party/WebKit/public:mojo_bindings",
     "//ui/base/mojo:mojo_bindings",
     "//ui/gfx/geometry/mojo",
@@ -638,6 +639,9 @@
     "//url/mojo:url_mojom_origin",
   ]
 
+  overridden_deps = [ "//third_party/WebKit/common:mojo_platform_bindings" ]
+  component_deps = [ "//third_party/WebKit/common:blink_common" ]
+
   component_output_prefix = "content_common_mojo_bindings"
   export_class_attribute = "CONTENT_EXPORT"
   export_define = "CONTENT_IMPLEMENTATION=1"
diff --git a/content/common/frame.mojom b/content/common/frame.mojom
index 46064ca..27bfead 100644
--- a/content/common/frame.mojom
+++ b/content/common/frame.mojom
@@ -11,6 +11,7 @@
 import "content/public/common/window_container_type.mojom";
 import "mojo/common/unguessable_token.mojom";
 import "services/service_manager/public/interfaces/interface_provider.mojom";
+import "third_party/WebKit/common/feature_policy/feature_policy.mojom";
 import "third_party/WebKit/public/platform/referrer.mojom";
 import "third_party/WebKit/public/web/window_features.mojom";
 import "ui/base/mojo/window_open_disposition.mojom";
@@ -170,8 +171,22 @@
   IssueKeepAliveHandle(KeepAliveHandle& keep_alive_handle);
 
   // Sent by the renderer when a navigation commits in the frame.
+  //
+  // If |interface_provider_request| is non-empty, the FrameHost implementation
+  // must unbind the old InterfaceProvider connection, and drop any interface
+  // requests pending on it. Then it should bind |interface_provider_request|
+  // and start servicing GetInterface messages coming in on this new connection
+  // in a security context that is appropriate for the committed navigation.
+  //
+  // The FrameHost implementation must enforce that |interface_provider_request|
+  // is set for cross-document navigations. This prevents origin confusion by
+  // ensuring that interface requests racing with navigation commit will be
+  // either ignored, or serviced correctly in the security context of the
+  // document they originated from (based on which InterfaceProvider connection
+  // the GetInterface messages arrive on).
   DidCommitProvisionalLoad(
-      DidCommitProvisionalLoadParams params);
+      DidCommitProvisionalLoadParams params,
+      service_manager.mojom.InterfaceProvider&? interface_provider_request);
 
   // Sent by the renderer to request a navigation.
   BeginNavigation(
@@ -186,5 +201,28 @@
       ResourceType resource_type,
       string ip,
       uint32 cert_status);
+
+  // Sent when the frame changes its window.name.
+  DidChangeName(string name, string unique_name);
+
+  // Sent when the frame starts enforcing an insecure request policy. Sending
+  // this information in DidCommitProvisionalLoad isn't sufficient; this
+  // message is needed because, for example, a document can dynamically insert
+  // a <meta> tag that causes strict mixed content checking to be enforced.
+  //
+  // Argument |policy_bitmap| represents blink::WebInsecureRequestPolicy uint8
+  // bitfield.
+  EnforceInsecureRequestPolicy(uint8 policy_bitmap);
+
+  // Notifies the browser process that HTTP headers which affect the frame
+  // polices were delivered with the document being loaded into the frame. This
+  // can be either or both of 'Feature-Policy' or 'Content-Security-Policy' (
+  // which can set sandbox flags).
+  //
+  // |parsed_header| is a list of an origin whitelist for each feature in the
+  // policy.
+  DidSetFramePolicyHeaders(
+      blink.mojom.WebSandboxFlags sandbox_flags,
+      array<blink.mojom.ParsedFeaturePolicyDeclaration> parsed_header);
 };
 
diff --git a/content/common/frame_messages.h b/content/common/frame_messages.h
index ebc3a5b..2f4e41d7 100644
--- a/content/common/frame_messages.h
+++ b/content/common/frame_messages.h
@@ -1160,19 +1160,6 @@
 // Notifies the browser that this frame has new session history information.
 IPC_MESSAGE_ROUTED1(FrameHostMsg_UpdateState, content::PageState /* state */)
 
-// Sent when the frame changes its window.name.
-IPC_MESSAGE_ROUTED2(FrameHostMsg_DidChangeName,
-                    std::string /* name */,
-                    std::string /* unique_name */)
-
-// Notifies the browser process that HTTP headers which affect the frame
-// polices were delivered with the document being lodaded into the frame. This
-// can be either or both of 'Feature-Policy' or 'Content-Security-Policy' (which
-// can set sandbox flags).
-IPC_MESSAGE_ROUTED2(FrameHostMsg_DidSetFramePolicyHeaders,
-                    blink::WebSandboxFlags,
-                    blink::ParsedFeaturePolicy /* parsed_header */)
-
 // Notifies the browser process about a new Content Security Policy that needs
 // to be applies to the frame.  This message is sent when a frame commits
 // navigation to a new location (reporting accumulated policies from HTTP
@@ -1182,13 +1169,6 @@
 IPC_MESSAGE_ROUTED1(FrameHostMsg_DidAddContentSecurityPolicies,
                     std::vector<content::ContentSecurityPolicy> /* policies */)
 
-// Sent when the frame starts enforcing an insecure request policy. Sending
-// this information in DidCommitProvisionalLoad isn't sufficient; this
-// message is needed because, for example, a document can dynamically insert
-// a <meta> tag that causes strict mixed content checking to be enforced.
-IPC_MESSAGE_ROUTED1(FrameHostMsg_EnforceInsecureRequestPolicy,
-                    blink::WebInsecureRequestPolicy)
-
 // Sent when the renderer changed the progress of a load.
 IPC_MESSAGE_ROUTED1(FrameHostMsg_DidChangeLoadProgress,
                     double /* load_progress */)
diff --git a/content/common/quota_dispatcher_host.mojom b/content/common/quota_dispatcher_host.mojom
index 385860d..9e1ca2b8 100644
--- a/content/common/quota_dispatcher_host.mojom
+++ b/content/common/quota_dispatcher_host.mojom
@@ -5,7 +5,7 @@
 module content.mojom;
 
 import "storage/common/quota/quota_types.mojom";
-import "url/mojo/url.mojom";
+import "url/mojo/origin.mojom";
 
 // API for the renderer process to request quota information from the browser
 // process.
@@ -13,11 +13,10 @@
 // success.
 // TODO(sashab): Remove origin_url and render_frame_id, moving this interface to
 // be per-execution context instead of per-process.
-// TODO(sashab): Change origin_url to a url.mojom.Origin instead.
 // TODO(sashab): Move this API and the necessary types to WebKit/common/.
 interface QuotaDispatcherHost {
   // Renderer process queries storage usage and quota from the browser process.
-  QueryStorageUsageAndQuota(url.mojom.Url origin_url,
+  QueryStorageUsageAndQuota(url.mojom.Origin origin,
                             storage.mojom.StorageType storage_type) =>
       (storage.mojom.QuotaStatusCode error,
        int64 current_usage,
@@ -26,7 +25,7 @@
   // Renderer process requests storage quota from the browser process.
   // render_frame_id is used for showing the permissions UI.
   RequestStorageQuota(int64 render_frame_id,
-                      url.mojom.Url origin_url,
+                      url.mojom.Origin origin,
                       storage.mojom.StorageType storage_type,
                       uint64 requested_size) =>
       (storage.mojom.QuotaStatusCode error,
diff --git a/content/public/android/java/src/org/chromium/content/browser/ContentView.java b/content/public/android/java/src/org/chromium/content/browser/ContentView.java
index 1be53582..f47f7884 100644
--- a/content/public/android/java/src/org/chromium/content/browser/ContentView.java
+++ b/content/public/android/java/src/org/chromium/content/browser/ContentView.java
@@ -128,17 +128,6 @@
     }
 
     @Override
-    protected void onSizeChanged(int w, int h, int ow, int oh) {
-        try {
-            TraceEvent.begin("ContentView.onSizeChanged");
-            super.onSizeChanged(w, h, ow, oh);
-            mContentViewCore.onSizeChanged(w, h, ow, oh);
-        } finally {
-            TraceEvent.end("ContentView.onSizeChanged");
-        }
-    }
-
-    @Override
     public InputConnection onCreateInputConnection(EditorInfo outAttrs) {
         return mContentViewCore.onCreateInputConnection(outAttrs);
     }
diff --git a/content/public/android/java/src/org/chromium/content/browser/ContentViewCore.java b/content/public/android/java/src/org/chromium/content/browser/ContentViewCore.java
index 89f01ccd..ad24321f 100644
--- a/content/public/android/java/src/org/chromium/content/browser/ContentViewCore.java
+++ b/content/public/android/java/src/org/chromium/content/browser/ContentViewCore.java
@@ -325,11 +325,6 @@
     void onConfigurationChanged(Configuration newConfig);
 
     /**
-     * @see View#onSizeChanged(int, int, int, int)
-     */
-    void onSizeChanged(int wPix, int hPix, int owPix, int ohPix);
-
-    /**
      * @see View#onGenericMotionEvent(MotionEvent)
      */
     boolean onGenericMotionEvent(MotionEvent event);
diff --git a/content/public/android/java/src/org/chromium/content/browser/ContentViewCoreImpl.java b/content/public/android/java/src/org/chromium/content/browser/ContentViewCoreImpl.java
index 08436a7f..ff27619 100644
--- a/content/public/android/java/src/org/chromium/content/browser/ContentViewCoreImpl.java
+++ b/content/public/android/java/src/org/chromium/content/browser/ContentViewCoreImpl.java
@@ -809,12 +809,6 @@
         }
     }
 
-    @SuppressWarnings("javadoc")
-    @Override
-    public void onSizeChanged(int wPix, int hPix, int owPix, int ohPix) {
-        updateAfterSizeChanged();
-    }
-
     @CalledByNative
     private void onTouchDown(MotionEvent event) {
         if (mShouldRequestUnbufferedDispatch) requestUnbufferedDispatch(event);
diff --git a/content/public/android/java/src/org/chromium/content/browser/input/ImeAdapter.java b/content/public/android/java/src/org/chromium/content/browser/input/ImeAdapter.java
index a8b5426..949ca066 100644
--- a/content/public/android/java/src/org/chromium/content/browser/input/ImeAdapter.java
+++ b/content/public/android/java/src/org/chromium/content/browser/input/ImeAdapter.java
@@ -442,6 +442,25 @@
         return mFocusPreOSKViewportRect;
     }
 
+    @CalledByNative
+    private void updateAfterViewSizeChanged() {
+        // Execute a delayed form focus operation because the OSK was brought up earlier.
+        if (!mFocusPreOSKViewportRect.isEmpty()) {
+            Rect rect = new Rect();
+            mContainerView.getWindowVisibleDisplayFrame(rect);
+            if (!rect.equals(mFocusPreOSKViewportRect)) {
+                // Only assume the OSK triggered the onSizeChanged if width was preserved.
+                if (rect.width() == mFocusPreOSKViewportRect.width()) {
+                    assert mWebContents != null;
+                    mWebContents.scrollFocusedEditableNodeIntoView();
+                }
+                // Zero the rect to prevent the above operation from issuing the delayed
+                // form focus event.
+                mFocusPreOSKViewportRect.setEmpty();
+            }
+        }
+    }
+
     @VisibleForTesting
     public ResultReceiver getNewShowKeyboardReceiver() {
         if (mShowKeyboardResultReceiver == null) {
diff --git a/content/public/app/mojo/content_utility_manifest.json b/content/public/app/mojo/content_utility_manifest.json
index b5a463a..645b7fe 100644
--- a/content/public/app/mojo/content_utility_manifest.json
+++ b/content/public/app/mojo/content_utility_manifest.json
@@ -10,7 +10,7 @@
           "content::mojom::ChildHistogramFetcher",
           "content::mojom::ChildHistogramFetcherFactory",
           "IPC::mojom::ChannelBootstrap",
-          "printing::mojom::PDFToPWGRasterConverter",
+          "printing::mojom::PdfToPwgRasterConverter",
           "service_manager::mojom::ServiceFactory"
         ],
         "service_manager:service_factory": [
diff --git a/content/public/common/bindings_policy.h b/content/public/common/bindings_policy.h
index 08d1e4a..07920915 100644
--- a/content/public/common/bindings_policy.h
+++ b/content/public/common/bindings_policy.h
@@ -11,13 +11,10 @@
 // to renderers.
 enum BindingsPolicy {
   // HTML-based UI bindings that allows the JS content to send JSON-encoded
-  // data back to the browser process and to access Mojo system API and
-  // ServiceRegistry modules. The system API modules are defined in
-  // //mojo/public/js and provide the ability to create Mojo primitives such as
-  // message and data pipes. The Connector and InterfaceProvider modules (see
-  // //content/renderer/mojo) in turn allows these Mojo primitives to be used to
-  // connect to named services exposed by the browser. These bindings should not
-  // be exposed to normal web contents.
+  // data back to the browser process and to access Mojo system API. The Mojo
+  // system API provides the ability to create Mojo primitives such as message
+  // and data pipes, as well as connecting to named services exposed by the
+  // browser. These bindings should not be exposed to normal web contents.
   BINDINGS_POLICY_WEB_UI = 1 << 0,
   // DOM automation bindings that allows the JS content to send JSON-encoded
   // data back to automation in the parent process.  (By default this isn't
diff --git a/content/public/common/storage_quota_params.h b/content/public/common/storage_quota_params.h
index fdc2c3a8..8ba04b91 100644
--- a/content/public/common/storage_quota_params.h
+++ b/content/public/common/storage_quota_params.h
@@ -23,6 +23,7 @@
         requested_size(0) {}
 
   int render_frame_id;
+  // TODO(sashab): Change this to url::Origin, crbug.com/598424.
   GURL origin_url;
   storage::StorageType storage_type;
   uint64_t requested_size;
diff --git a/content/public/network/ignore_errors_cert_verifier.cc b/content/public/network/ignore_errors_cert_verifier.cc
index 5cf6565..9c0798a 100644
--- a/content/public/network/ignore_errors_cert_verifier.cc
+++ b/content/public/network/ignore_errors_cert_verifier.cc
@@ -21,6 +21,7 @@
 #include "net/cert/asn1_util.h"
 #include "net/cert/cert_verify_result.h"
 #include "net/cert/x509_certificate.h"
+#include "net/cert/x509_util.h"
 
 using ::net::CertVerifier;
 using ::net::CompletionCallback;
@@ -80,19 +81,20 @@
                                      std::unique_ptr<Request>* out_req,
                                      const net::NetLogWithSource& net_log) {
   SPKIHashSet spki_fingerprints;
-  std::string cert_der;
   base::StringPiece cert_spki;
   SHA256HashValue hash;
-  if (X509Certificate::GetDEREncoded(params.certificate()->os_cert_handle(),
-                                     &cert_der) &&
-      net::asn1::ExtractSPKIFromDERCert(cert_der, &cert_spki)) {
+  if (net::asn1::ExtractSPKIFromDERCert(
+          net::x509_util::CryptoBufferAsStringPiece(
+              params.certificate()->cert_buffer()),
+          &cert_spki)) {
     crypto::SHA256HashString(cert_spki, &hash, sizeof(SHA256HashValue));
     spki_fingerprints.insert(hash);
   }
-  for (const X509Certificate::OSCertHandle& intermediate :
-       params.certificate()->GetIntermediateCertificates()) {
-    if (X509Certificate::GetDEREncoded(intermediate, &cert_der) &&
-        net::asn1::ExtractSPKIFromDERCert(cert_der, &cert_spki)) {
+  for (const auto& intermediate :
+       params.certificate()->intermediate_buffers()) {
+    if (net::asn1::ExtractSPKIFromDERCert(
+            net::x509_util::CryptoBufferAsStringPiece(intermediate.get()),
+            &cert_spki)) {
       crypto::SHA256HashString(cert_spki, &hash, sizeof(SHA256HashValue));
       spki_fingerprints.insert(hash);
     }
diff --git a/content/public/network/ignore_errors_cert_verifier_unittest.cc b/content/public/network/ignore_errors_cert_verifier_unittest.cc
index a7dc3bdb..d719245 100644
--- a/content/public/network/ignore_errors_cert_verifier_unittest.cc
+++ b/content/public/network/ignore_errors_cert_verifier_unittest.cc
@@ -17,6 +17,7 @@
 #include "net/cert/asn1_util.h"
 #include "net/cert/mock_cert_verifier.h"
 #include "net/cert/x509_certificate.h"
+#include "net/cert/x509_util.h"
 #include "net/log/net_log_with_source.h"
 #include "net/test/cert_test_util.h"
 #include "net/test/gtest_util.h"
@@ -50,11 +51,12 @@
   base::FilePath certs_dir = net::GetTestCertsDirectory();
   net::CertificateList certs = net::CreateCertificateListFromFile(
       certs_dir, "x509_verify_results.chain.pem", X509Certificate::FORMAT_AUTO);
-  std::string cert_der, hash_base64;
+  std::string hash_base64;
   base::StringPiece cert_spki;
   SHA256HashValue hash;
-  X509Certificate::GetDEREncoded(certs[1]->os_cert_handle(), &cert_der);
-  net::asn1::ExtractSPKIFromDERCert(cert_der, &cert_spki);
+  net::asn1::ExtractSPKIFromDERCert(
+      net::x509_util::CryptoBufferAsStringPiece(certs[1]->cert_buffer()),
+      &cert_spki);
 
   crypto::SHA256HashString(cert_spki, &hash, sizeof(SHA256HashValue));
   base::Base64Encode(base::StringPiece(reinterpret_cast<const char*>(hash.data),
@@ -100,17 +102,10 @@
 
 static void GetWhitelistedTestCert(scoped_refptr<X509Certificate>* out) {
   base::FilePath certs_dir = net::GetTestCertsDirectory();
-  net::CertificateList certs = net::CreateCertificateListFromFile(
+  *out = net::CreateCertificateChainFromFile(
       certs_dir, "x509_verify_results.chain.pem", X509Certificate::FORMAT_AUTO);
-  ASSERT_EQ(3U, certs.size());
-  X509Certificate::OSCertHandles intermediates;
-  intermediates.push_back(certs[1]->os_cert_handle());
-  intermediates.push_back(certs[2]->os_cert_handle());
-  scoped_refptr<X509Certificate> cert_chain = X509Certificate::CreateFromHandle(
-      certs[0]->os_cert_handle(), intermediates);
-  ASSERT_TRUE(cert_chain);
-  ASSERT_EQ(2U, cert_chain->GetIntermediateCertificates().size());
-  out->swap(cert_chain);
+  ASSERT_TRUE(*out);
+  ASSERT_EQ(2U, (*out)->intermediate_buffers().size());
 }
 
 TEST_F(IgnoreErrorsCertVerifierTest, TestNoMatchCertOk) {
diff --git a/content/public/renderer/render_frame.h b/content/public/renderer/render_frame.h
index 229f73c8..42baf32 100644
--- a/content/public/renderer/render_frame.h
+++ b/content/public/renderer/render_frame.h
@@ -46,12 +46,6 @@
 class Origin;
 }
 
-namespace v8 {
-template <typename T> class Local;
-class Context;
-class Isolate;
-}
-
 namespace content {
 class ChildURLLoaderFactoryGetter;
 class ContextMenuClient;
@@ -232,11 +226,6 @@
                                size_t offset,
                                const gfx::Range& range) = 0;
 
-  // Ensures that builtin mojo bindings modules are available in |context|.
-  virtual void EnsureMojoBuiltinsAreAvailable(
-      v8::Isolate* isolate,
-      v8::Local<v8::Context> context) = 0;
-
   // Adds |message| to the DevTools console.
   virtual void AddMessageToConsole(ConsoleMessageLevel level,
                                    const std::string& message) = 0;
diff --git a/content/public/test/android/javatests/src/org/chromium/content/browser/test/util/TestContentViewCore.java b/content/public/test/android/javatests/src/org/chromium/content/browser/test/util/TestContentViewCore.java
index 9312dba6..9e2a710e 100644
--- a/content/public/test/android/javatests/src/org/chromium/content/browser/test/util/TestContentViewCore.java
+++ b/content/public/test/android/javatests/src/org/chromium/content/browser/test/util/TestContentViewCore.java
@@ -223,9 +223,6 @@
     public void onConfigurationChanged(Configuration newConfig) {}
 
     @Override
-    public void onSizeChanged(int wPix, int hPix, int owPix, int ohPix) {}
-
-    @Override
     public boolean onGenericMotionEvent(MotionEvent event) {
         return false;
     }
diff --git a/content/public/test/mock_render_thread.cc b/content/public/test/mock_render_thread.cc
index d70ba1af5..b1d930a67 100644
--- a/content/public/test/mock_render_thread.cc
+++ b/content/public/test/mock_render_thread.cc
@@ -94,21 +94,12 @@
   MockRenderThread* const thread_;
 };
 
-// Returns an InterfaceProvider that is safe to call into, but will not actually
-// service any interface requests.
-service_manager::mojom::InterfaceProviderPtrInfo CreateStubInterfaceProvider() {
-  ::service_manager::mojom::InterfaceProviderPtrInfo info;
-  mojo::MakeRequest(&info);
-  return info;
-}
-
 }  // namespace
 
 MockRenderThread::MockRenderThread()
     : routing_id_(0),
       opener_id_(0),
       new_window_routing_id_(0),
-      new_window_main_frame_routing_id_(0),
       new_window_main_frame_widget_routing_id_(0),
       new_frame_routing_id_(0),
       mock_render_message_filter_(new MockRenderMessageFilterImpl(this)) {
@@ -301,6 +292,29 @@
   *route_id = routing_id_;
 }
 
+service_manager::mojom::InterfaceProviderRequest
+MockRenderThread::TakeInitialInterfaceProviderRequestForFrame(
+    int32_t routing_id) {
+  auto it =
+      frame_routing_id_to_initial_interface_provider_requests_.find(routing_id);
+  if (it == frame_routing_id_to_initial_interface_provider_requests_.end())
+    return nullptr;
+  auto interface_provider_request = std::move(it->second);
+  frame_routing_id_to_initial_interface_provider_requests_.erase(it);
+  return interface_provider_request;
+}
+
+void MockRenderThread::PassInitialInterfaceProviderRequestForFrame(
+    int32_t routing_id,
+    service_manager::mojom::InterfaceProviderRequest
+        interface_provider_request) {
+  bool did_insertion = false;
+  std::tie(std::ignore, did_insertion) =
+      frame_routing_id_to_initial_interface_provider_requests_.emplace(
+          routing_id, std::move(interface_provider_request));
+  DCHECK(did_insertion);
+}
+
 // The Frame expects to be returned a valid route_id different from its own.
 void MockRenderThread::OnCreateChildFrame(
     const FrameHostMsg_CreateChildFrame_Params& params,
@@ -308,8 +322,11 @@
     mojo::MessagePipeHandle* new_interface_provider,
     base::UnguessableToken* devtools_frame_token) {
   *new_render_frame_id = new_frame_routing_id_++;
+  service_manager::mojom::InterfaceProviderPtr interface_provider;
+  frame_routing_id_to_initial_interface_provider_requests_.emplace(
+      *new_render_frame_id, mojo::MakeRequest(&interface_provider));
   *new_interface_provider =
-      CreateStubInterfaceProvider().PassHandle().release();
+      interface_provider.PassInterface().PassHandle().release();
   *devtools_frame_token = base::UnguessableToken::Create();
 }
 
@@ -347,10 +364,13 @@
 void MockRenderThread::OnCreateWindow(
     const mojom::CreateNewWindowParams& params,
     mojom::CreateNewWindowReply* reply) {
-  reply->route_id = new_window_routing_id_;
-  reply->main_frame_route_id = new_window_main_frame_routing_id_;
-  reply->main_frame_interface_provider = CreateStubInterfaceProvider();
-  reply->main_frame_widget_route_id = new_window_main_frame_widget_routing_id_;
+  reply->route_id = new_window_routing_id_++;
+  reply->main_frame_route_id = new_frame_routing_id_++;
+  frame_routing_id_to_initial_interface_provider_requests_.emplace(
+      reply->main_frame_route_id,
+      mojo::MakeRequest(&reply->main_frame_interface_provider));
+  reply->main_frame_widget_route_id =
+      new_window_main_frame_widget_routing_id_++;
   reply->cloned_session_storage_namespace_id = 0;
 }
 
diff --git a/content/public/test/mock_render_thread.h b/content/public/test/mock_render_thread.h
index 2a5fdf1..adaa338 100644
--- a/content/public/test/mock_render_thread.h
+++ b/content/public/test/mock_render_thread.h
@@ -128,6 +128,22 @@
   void OnCreateWidget(int opener_id,
                       blink::WebPopupType popup_type,
                       int* route_id);
+
+  // Returns the request end of the InterfaceProvider interface whose client end
+  // was passed in to construct RenderFrame with |routing_id|; if any. The
+  // client end will be used by the RenderFrame to service interface requests
+  // originating from the original the initial empty document.
+  service_manager::mojom::InterfaceProviderRequest
+  TakeInitialInterfaceProviderRequestForFrame(int32_t routing_id);
+
+  // Called from the RenderViewTest harness to supply the request end of the
+  // InterfaceProvider interface connection that the harness used to service the
+  // initial empty document in the RenderFrame with |routing_id|.
+  void PassInitialInterfaceProviderRequestForFrame(
+      int32_t routing_id,
+      service_manager::mojom::InterfaceProviderRequest
+          interface_provider_request);
+
  protected:
   // This function operates as a regular IPC listener. Subclasses
   // overriding this should first delegate to this implementation.
@@ -152,12 +168,15 @@
   // Opener id reported by the Widget.
   int32_t opener_id_;
 
-  // Routing id that will be assigned to a CreateWindow Widget.
+  // Routing id that will be assigned to a CreateWindow Widget and/or child
+  // frames.
   int32_t new_window_routing_id_;
-  int32_t new_window_main_frame_routing_id_;
   int32_t new_window_main_frame_widget_routing_id_;
   int32_t new_frame_routing_id_;
 
+  std::map<int32_t, service_manager::mojom::InterfaceProviderRequest>
+      frame_routing_id_to_initial_interface_provider_requests_;
+
   // The last known good deserializer for sync messages.
   std::unique_ptr<IPC::MessageReplyDeserializer> reply_deserializer_;
 
diff --git a/content/public/test/navigation_simulator.cc b/content/public/test/navigation_simulator.cc
index 496957a..791505a 100644
--- a/content/public/test/navigation_simulator.cc
+++ b/content/public/test/navigation_simulator.cc
@@ -249,6 +249,9 @@
     else
       transition_ = ui::PAGE_TRANSITION_MANUAL_SUBFRAME;
   }
+
+  service_manager::mojom::InterfaceProviderPtr stub_interface_provider;
+  interface_provider_request_ = mojo::MakeRequest(&stub_interface_provider);
 }
 
 NavigationSimulator::~NavigationSimulator() {}
@@ -484,7 +487,11 @@
       navigation_url_, params.item_sequence_number,
       params.document_sequence_number);
 
-  render_frame_host_->SendNavigateWithParams(&params);
+  if (params.was_within_same_document)
+    interface_provider_request_ = nullptr;
+
+  render_frame_host_->SendNavigateWithParamsAndInterfaceProvider(
+      &params, std::move(interface_provider_request_));
 
   // Simulate the UnloadACK in the old RenderFrameHost if it was swapped out at
   // commit time.
@@ -596,7 +603,8 @@
       navigation_url_, params.item_sequence_number,
       params.document_sequence_number);
 
-  render_frame_host_->SendNavigateWithParams(&params);
+  render_frame_host_->SendNavigateWithParamsAndInterfaceProvider(
+      &params, std::move(interface_provider_request_));
 
   // Simulate the UnloadACK in the old RenderFrameHost if it was swapped out at
   // commit time.
@@ -642,7 +650,9 @@
   params.page_state =
       PageState::CreateForTesting(navigation_url_, false, nullptr, nullptr);
 
-  render_frame_host_->SendNavigateWithParams(&params);
+  interface_provider_request_ = nullptr;
+  render_frame_host_->SendNavigateWithParamsAndInterfaceProvider(
+      &params, nullptr /* interface_provider_request */);
 
   state_ = FINISHED;
 
@@ -695,6 +705,14 @@
   socket_address_ = socket_address;
 }
 
+void NavigationSimulator::SetInterfaceProviderRequest(
+    service_manager::mojom::InterfaceProviderRequest request) {
+  CHECK_LE(state_, STARTED) << "The InterfaceProviderRequest cannot be set "
+                               "after the navigation has committed or failed";
+  CHECK(request.is_pending());
+  interface_provider_request_ = std::move(request);
+}
+
 NavigationThrottle::ThrottleCheckResult
 NavigationSimulator::GetLastThrottleCheckResult() {
   return last_throttle_check_result_.value();
diff --git a/content/public/test/navigation_simulator.h b/content/public/test/navigation_simulator.h
index 2b52458..23955ff 100644
--- a/content/public/test/navigation_simulator.h
+++ b/content/public/test/navigation_simulator.h
@@ -15,6 +15,7 @@
 #include "content/public/browser/web_contents_observer.h"
 #include "content/public/common/referrer.h"
 #include "net/base/host_port_pair.h"
+#include "services/service_manager/public/cpp/interface_provider.h"
 #include "ui/base/page_transition_types.h"
 
 class GURL;
@@ -222,6 +223,16 @@
   // commits. They should be specified before calling |Fail| or |Commit|.
   virtual void SetSocketAddress(const net::HostPortPair& socket_address);
 
+  // Sets the InterfaceProvider interface request to pass in as an argument to
+  // DidCommitProvisionalLoad for cross-document navigations. If not called,
+  // a stub will be passed in (which will never receive any interface requests).
+  //
+  // This interface connection would normally be created by the RenderFrame,
+  // with the client end bound to |remote_interfaces_| to allow the new document
+  // to access services exposed by the RenderFrameHost.
+  virtual void SetInterfaceProviderRequest(
+      service_manager::mojom::InterfaceProviderRequest request);
+
   // --------------------------------------------------------------------------
 
   // Gets the last throttle check result computed by the navigation throttles.
@@ -340,6 +351,7 @@
   ReloadType reload_type_ = ReloadType::NONE;
   int session_history_offset_ = 0;
   bool has_user_gesture_ = true;
+  service_manager::mojom::InterfaceProviderRequest interface_provider_request_;
 
   // These are used to sanity check the content/public/ API calls emitted as
   // part of the navigation.
diff --git a/content/public/test/render_view_test.cc b/content/public/test/render_view_test.cc
index 6978fa06..0061fcb2 100644
--- a/content/public/test/render_view_test.cc
+++ b/content/public/test/render_view_test.cc
@@ -75,15 +75,16 @@
 
 namespace {
 
-const int32_t kRouteId = 5;
-const int32_t kMainFrameRouteId = 6;
+const int32_t kRouteId = 101;
+const int32_t kMainFrameRouteId = 201;
 // TODO(avi): Widget routing IDs should be distinct from the view routing IDs,
 // once RenderWidgetHost is distilled from RenderViewHostImpl.
 // https://crbug.com/545684
-const int32_t kMainFrameWidgetRouteId = 5;
-const int32_t kNewWindowRouteId = 7;
-const int32_t kNewFrameRouteId = 10;
-const int32_t kNewFrameWidgetRouteId = 7;
+const int32_t kMainFrameWidgetRouteId = 101;
+
+const int32_t kNewWindowRouteId = 211;
+const int32_t kNewFrameRouteId = 111;
+const int32_t kNewFrameWidgetRouteId = 211;
 
 // Converts |ascii_character| into |key_code| and returns true on success.
 // Handles only the characters needed by tests.
@@ -309,8 +310,10 @@
   view_params->renderer_preferences = RendererPreferences();
   view_params->web_preferences = WebPreferences();
   view_params->view_id = kRouteId;
+  render_thread_->PassInitialInterfaceProviderRequestForFrame(
+      kMainFrameRouteId,
+      mojo::MakeRequest(&view_params->main_frame_interface_provider));
   view_params->main_frame_routing_id = kMainFrameRouteId;
-  mojo::MakeRequest(&view_params->main_frame_interface_provider);
   view_params->main_frame_widget_routing_id = kMainFrameWidgetRouteId;
   view_params->session_storage_namespace_id = kInvalidSessionStorageNamespaceId;
   view_params->swapped_out = false;
diff --git a/content/renderer/BUILD.gn b/content/renderer/BUILD.gn
index 2c733eed..d88a57d 100644
--- a/content/renderer/BUILD.gn
+++ b/content/renderer/BUILD.gn
@@ -349,14 +349,10 @@
     "menu_item_builder.cc",
     "menu_item_builder.h",
     "message_delivery_policy.h",
-    "mojo/blink_connector_js_wrapper.cc",
-    "mojo/blink_connector_js_wrapper.h",
     "mojo/blink_interface_provider_impl.cc",
     "mojo/blink_interface_provider_impl.h",
     "mojo/blink_interface_registry_impl.cc",
     "mojo/blink_interface_registry_impl.h",
-    "mojo/interface_provider_js_wrapper.cc",
-    "mojo/interface_provider_js_wrapper.h",
     "mouse_lock_dispatcher.cc",
     "mouse_lock_dispatcher.h",
     "navigation_state_impl.cc",
@@ -599,9 +595,7 @@
     "//media/mojo/interfaces",
     "//media/mojo/interfaces:remoting",
     "//mojo/common",
-    "//mojo/edk/js",
     "//mojo/public/cpp/bindings",
-    "//mojo/public/js",
     "//net",
     "//ppapi/features",
     "//printing/features",
diff --git a/content/renderer/media/audio_ipc_factory.cc b/content/renderer/media/audio_ipc_factory.cc
index 5ab138a..d7fb393 100644
--- a/content/renderer/media/audio_ipc_factory.cc
+++ b/content/renderer/media/audio_ipc_factory.cc
@@ -97,7 +97,7 @@
   // Unretained is safe because |this| owns the binding, so a connection error
   // cannot trigger after destruction.
   emplaced_factory.set_connection_error_handler(
-      base::BindOnce(&AudioIPCFactory::MaybeDeregisterRemoteFactory,
+      base::BindOnce(&AudioIPCFactory::MaybeDeregisterRemoteFactoryOnIOThread,
                      base::Unretained(this), frame_id));
 }
 
diff --git a/content/renderer/media/media_factory.cc b/content/renderer/media/media_factory.cc
index f322e93a..fbb2af1d 100644
--- a/content/renderer/media/media_factory.cc
+++ b/content/renderer/media/media_factory.cc
@@ -374,8 +374,7 @@
   // level uses the MediaPlayerRenderer as its underlying media::Renderer.
   auto mojo_media_player_renderer_factory =
       std::make_unique<media::MojoRendererFactory>(
-          media::MojoRendererFactory::GetGpuFactoriesCB(),
-          remote_interfaces_->get());
+          media::MojoRendererFactory::GetGpuFactoriesCB(), remote_interfaces_);
 
   // Always give |factory_selector| a MediaPlayerRendererClient factory. WMPI
   // might fallback to it if the final redirected URL is an HLS url.
@@ -567,8 +566,7 @@
 MediaFactory::CreateVideoDecodeStatsRecorder() {
   DCHECK(remote_interfaces_);
   media::mojom::VideoDecodeStatsRecorderPtr recorder_ptr;
-  service_manager::GetInterface(remote_interfaces_->get(), &recorder_ptr);
-
+  remote_interfaces_->GetInterface(&recorder_ptr);
   return recorder_ptr;
 }
 
diff --git a/content/renderer/mojo/blink_connector_js_wrapper.cc b/content/renderer/mojo/blink_connector_js_wrapper.cc
deleted file mode 100644
index e074f8d7..0000000
--- a/content/renderer/mojo/blink_connector_js_wrapper.cc
+++ /dev/null
@@ -1,72 +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 "content/renderer/mojo/blink_connector_js_wrapper.h"
-
-#include <memory>
-#include <utility>
-
-#include "mojo/edk/js/handle.h"
-#include "services/service_manager/public/cpp/connector.h"
-#include "services/service_manager/public/interfaces/connector.mojom.h"
-#include "third_party/WebKit/public/web/WebLocalFrame.h"
-
-namespace content {
-
-gin::WrapperInfo BlinkConnectorJsWrapper::kWrapperInfo = {
-    gin::kEmbedderNativeGin};
-const char BlinkConnectorJsWrapper::kModuleName[] =
-    "content/public/renderer/connector";
-
-BlinkConnectorJsWrapper::~BlinkConnectorJsWrapper() {}
-
-// static
-gin::Handle<BlinkConnectorJsWrapper> BlinkConnectorJsWrapper::Create(
-    v8::Isolate* isolate,
-    v8::Local<v8::Context> context,
-    service_manager::Connector* connector) {
-  return gin::CreateHandle(
-      isolate,
-      new BlinkConnectorJsWrapper(isolate, context, connector->GetWeakPtr()));
-}
-
-gin::ObjectTemplateBuilder BlinkConnectorJsWrapper::GetObjectTemplateBuilder(
-    v8::Isolate* isolate) {
-  return Wrappable<BlinkConnectorJsWrapper>::GetObjectTemplateBuilder(isolate)
-      .SetMethod("bindInterface", &BlinkConnectorJsWrapper::BindInterface);
-}
-
-mojo::Handle BlinkConnectorJsWrapper::BindInterface(
-    const std::string& service_name,
-    const std::string& interface_name) {
-  mojo::MessagePipe pipe;
-  if (connector_) {
-    connector_->BindInterface(
-        service_manager::Identity(service_name,
-                                  service_manager::mojom::kInheritUserID),
-        interface_name, std::move(pipe.handle0));
-  }
-  return pipe.handle1.release();
-}
-
-BlinkConnectorJsWrapper::BlinkConnectorJsWrapper(
-    v8::Isolate* isolate,
-    v8::Local<v8::Context> context,
-    base::WeakPtr<service_manager::Connector> connector)
-    : isolate_(isolate),
-      context_(isolate, context),
-      connector_(connector),
-      weak_factory_(this) {
-  context_.SetWeak(this, &BlinkConnectorJsWrapper::ClearContext,
-                   v8::WeakCallbackType::kParameter);
-}
-
-// static
-void BlinkConnectorJsWrapper::ClearContext(
-    const v8::WeakCallbackInfo<BlinkConnectorJsWrapper>& data) {
-  BlinkConnectorJsWrapper* registry = data.GetParameter();
-  registry->context_.Reset();
-}
-
-}  // namespace content
diff --git a/content/renderer/mojo/blink_connector_js_wrapper.h b/content/renderer/mojo/blink_connector_js_wrapper.h
deleted file mode 100644
index 40fad97..0000000
--- a/content/renderer/mojo/blink_connector_js_wrapper.h
+++ /dev/null
@@ -1,71 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CONTENT_RENDERER_MOJO_BLINK_CONNECTOR_JS_WRAPPER_H_
-#define CONTENT_RENDERER_MOJO_BLINK_CONNECTOR_JS_WRAPPER_H_
-
-#include <string>
-
-#include "base/macros.h"
-#include "content/common/content_export.h"
-#include "gin/handle.h"
-#include "gin/object_template_builder.h"
-#include "gin/wrappable.h"
-#include "mojo/public/cpp/system/message_pipe.h"
-#include "v8/include/v8.h"
-
-namespace service_manager {
-class Connector;
-}
-
-namespace content {
-
-// A JS wrapper around service_manager::Connector that allows connecting to
-// remote services.
-class CONTENT_EXPORT BlinkConnectorJsWrapper
-    : public gin::Wrappable<BlinkConnectorJsWrapper> {
- public:
-  ~BlinkConnectorJsWrapper() override;
-  static gin::Handle<BlinkConnectorJsWrapper> Create(
-      v8::Isolate* isolate,
-      v8::Local<v8::Context> context,
-      service_manager::Connector* remote_interfaces);
-
-  // gin::Wrappable<BlinkConnectorJsWrapper> overrides.
-  gin::ObjectTemplateBuilder GetObjectTemplateBuilder(
-      v8::Isolate* isolate) override;
-
-  // JS interface implementation.
-  mojo::Handle BindInterface(const std::string& service_name,
-                             const std::string& interface_name);
-
-  static gin::WrapperInfo kWrapperInfo;
-  static const char kModuleName[];
-
- private:
-  using ScopedJsFactory =
-      v8::Persistent<v8::Function, v8::CopyablePersistentTraits<v8::Function>>;
-
-  BlinkConnectorJsWrapper(v8::Isolate* isolate,
-                          v8::Local<v8::Context> context,
-                          base::WeakPtr<service_manager::Connector> connector);
-
-  void CallJsFactory(const ScopedJsFactory& factory,
-                     mojo::ScopedMessagePipeHandle pipe);
-
-  static void ClearContext(
-      const v8::WeakCallbackInfo<BlinkConnectorJsWrapper>& data);
-
-  v8::Isolate* isolate_;
-  v8::Global<v8::Context> context_;
-  base::WeakPtr<service_manager::Connector> connector_;
-
-  base::WeakPtrFactory<BlinkConnectorJsWrapper> weak_factory_;
-
-  DISALLOW_COPY_AND_ASSIGN(BlinkConnectorJsWrapper);
-};
-
-}  // namespace content
-
-#endif  // CONTENT_RENDERER_MOJO_BLINK_CONNECTOR_JS_WRAPPER_H_
diff --git a/content/renderer/mojo/interface_provider_js_wrapper.cc b/content/renderer/mojo/interface_provider_js_wrapper.cc
deleted file mode 100644
index 220105b..0000000
--- a/content/renderer/mojo/interface_provider_js_wrapper.cc
+++ /dev/null
@@ -1,102 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "content/renderer/mojo/interface_provider_js_wrapper.h"
-
-#include <memory>
-#include <utility>
-
-#include "content/public/common/service_names.mojom.h"
-#include "mojo/edk/js/handle.h"
-#include "services/service_manager/public/cpp/connector.h"
-#include "services/service_manager/public/cpp/interface_provider.h"
-
-namespace content {
-
-gin::WrapperInfo InterfaceProviderJsWrapper::kWrapperInfo = {
-    gin::kEmbedderNativeGin};
-const char InterfaceProviderJsWrapper::kPerFrameModuleName[] =
-    "content/public/renderer/frame_interfaces";
-const char InterfaceProviderJsWrapper::kPerProcessModuleName[] =
-    "content/public/renderer/interfaces";
-
-InterfaceProviderJsWrapper::~InterfaceProviderJsWrapper() {
-}
-
-// static
-gin::Handle<InterfaceProviderJsWrapper> InterfaceProviderJsWrapper::Create(
-    v8::Isolate* isolate,
-    v8::Local<v8::Context> context,
-    service_manager::Connector* connector) {
-  return gin::CreateHandle(
-      isolate, new InterfaceProviderJsWrapper(isolate, context,
-                                              connector->GetWeakPtr()));
-}
-
-// static
-gin::Handle<InterfaceProviderJsWrapper> InterfaceProviderJsWrapper::Create(
-    v8::Isolate* isolate,
-    v8::Local<v8::Context> context,
-    service_manager::InterfaceProvider* remote_interfaces) {
-  return gin::CreateHandle(
-      isolate,
-      new InterfaceProviderJsWrapper(
-          isolate, context,
-        remote_interfaces->GetWeakPtr()));
-}
-
-gin::ObjectTemplateBuilder
-InterfaceProviderJsWrapper::GetObjectTemplateBuilder(v8::Isolate* isolate) {
-  return Wrappable<InterfaceProviderJsWrapper>::GetObjectTemplateBuilder(
-             isolate)
-      .SetMethod("getInterface", &InterfaceProviderJsWrapper::GetInterface);
-}
-
-mojo::Handle InterfaceProviderJsWrapper::GetInterface(
-    const std::string& interface_name) {
-  mojo::MessagePipe pipe;
-  if (connector_) {
-    connector_->BindInterface(
-        service_manager::Identity(mojom::kBrowserServiceName,
-                                  service_manager::mojom::kInheritUserID),
-        interface_name, std::move(pipe.handle0));
-  } else if (remote_interfaces_) {
-    remote_interfaces_->GetInterface(
-        interface_name, std::move(pipe.handle0));
-  }
-  return pipe.handle1.release();
-}
-
-InterfaceProviderJsWrapper::InterfaceProviderJsWrapper(
-    v8::Isolate* isolate,
-    v8::Local<v8::Context> context,
-    base::WeakPtr<service_manager::Connector> connector)
-    : isolate_(isolate),
-      context_(isolate, context),
-      connector_(connector),
-      weak_factory_(this) {
-  context_.SetWeak(this, &InterfaceProviderJsWrapper::ClearContext,
-                   v8::WeakCallbackType::kParameter);
-}
-
-InterfaceProviderJsWrapper::InterfaceProviderJsWrapper(
-    v8::Isolate* isolate,
-    v8::Local<v8::Context> context,
-    base::WeakPtr<service_manager::InterfaceProvider> remote_interfaces)
-    : isolate_(isolate),
-      context_(isolate, context),
-      remote_interfaces_(remote_interfaces),
-      weak_factory_(this) {
-  context_.SetWeak(this, &InterfaceProviderJsWrapper::ClearContext,
-                   v8::WeakCallbackType::kParameter);
-}
-
-// static
-void InterfaceProviderJsWrapper::ClearContext(
-    const v8::WeakCallbackInfo<InterfaceProviderJsWrapper>& data) {
-  InterfaceProviderJsWrapper* registry = data.GetParameter();
-  registry->context_.Reset();
-}
-
-}  // namespace content
diff --git a/content/renderer/mojo/interface_provider_js_wrapper.h b/content/renderer/mojo/interface_provider_js_wrapper.h
deleted file mode 100644
index b0f00b27..0000000
--- a/content/renderer/mojo/interface_provider_js_wrapper.h
+++ /dev/null
@@ -1,84 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CONTENT_RENDERER_MOJO_INTERFACE_PROVIDER_JS_WRAPPER_H_
-#define CONTENT_RENDERER_MOJO_INTERFACE_PROVIDER_JS_WRAPPER_H_
-
-#include <string>
-
-#include "base/macros.h"
-#include "content/common/content_export.h"
-#include "gin/handle.h"
-#include "gin/object_template_builder.h"
-#include "gin/wrappable.h"
-#include "mojo/public/cpp/system/message_pipe.h"
-#include "v8/include/v8.h"
-
-namespace service_manager {
-class Connector;
-class InterfaceProvider;
-}
-
-namespace content {
-
-// A JS wrapper around service_manager::Connector/InterfaceProvider that allows
-// script to bind interfaces exposed by the browser.
-class CONTENT_EXPORT InterfaceProviderJsWrapper
-    : public gin::Wrappable<InterfaceProviderJsWrapper> {
- public:
-  ~InterfaceProviderJsWrapper() override;
-  static gin::Handle<InterfaceProviderJsWrapper> Create(
-      v8::Isolate* isolate,
-      v8::Local<v8::Context> context,
-      service_manager::Connector* connector);
-  static gin::Handle<InterfaceProviderJsWrapper> Create(
-      v8::Isolate* isolate,
-      v8::Local<v8::Context> context,
-      service_manager::InterfaceProvider* remote_interfaces);
-
-  // gin::Wrappable<InterfaceProviderJsWrapper> overrides.
-  gin::ObjectTemplateBuilder GetObjectTemplateBuilder(
-      v8::Isolate* isolate) override;
-
-  // JS interface implementation.
-  mojo::Handle GetInterface(const std::string& interface_name);
-
-  static gin::WrapperInfo kWrapperInfo;
-  static const char kPerFrameModuleName[];
-  static const char kPerProcessModuleName[];
-
- private:
-  using ScopedJsFactory =
-      v8::Persistent<v8::Function, v8::CopyablePersistentTraits<v8::Function>>;
-  using BindCallback = base::Callback<void(mojo::ScopedMessagePipeHandle)>;
-
-  InterfaceProviderJsWrapper(
-      v8::Isolate* isolate,
-      v8::Local<v8::Context> context,
-      base::WeakPtr<service_manager::Connector> connector);
-  InterfaceProviderJsWrapper(
-      v8::Isolate* isolate,
-      v8::Local<v8::Context> context,
-      base::WeakPtr<service_manager::InterfaceProvider> remote_interfaces);
-
-  void CallJsFactory(const ScopedJsFactory& factory,
-                     mojo::ScopedMessagePipeHandle pipe);
-
-  static void ClearContext(
-      const v8::WeakCallbackInfo<InterfaceProviderJsWrapper>& data);
-
-  v8::Isolate* isolate_;
-  v8::Global<v8::Context> context_;
-  // Either one of the following two fields will be non-null.
-  base::WeakPtr<service_manager::Connector> connector_;
-  base::WeakPtr<service_manager::InterfaceProvider> remote_interfaces_;
-
-  base::WeakPtrFactory<InterfaceProviderJsWrapper> weak_factory_;
-
-  DISALLOW_COPY_AND_ASSIGN(InterfaceProviderJsWrapper);
-};
-
-}  // namespace content
-
-#endif  // CONTENT_RENDERER_MOJO_INTERFACE_PROVIDER_JS_WRAPPER_H_
diff --git a/content/renderer/quota_dispatcher.cc b/content/renderer/quota_dispatcher.cc
index daa181a..399ce386 100644
--- a/content/renderer/quota_dispatcher.cc
+++ b/content/renderer/quota_dispatcher.cc
@@ -16,7 +16,7 @@
 #include "services/service_manager/public/cpp/connector.h"
 #include "third_party/WebKit/public/platform/WebStorageQuotaCallbacks.h"
 #include "third_party/WebKit/public/platform/WebStorageQuotaType.h"
-#include "url/gurl.h"
+#include "url/origin.h"
 
 using blink::WebStorageQuotaCallbacks;
 using blink::WebStorageQuotaError;
@@ -109,19 +109,19 @@
 }
 
 void QuotaDispatcher::QueryStorageUsageAndQuota(
-    const GURL& origin_url,
+    const url::Origin& origin,
     StorageType type,
     std::unique_ptr<Callback> callback) {
   DCHECK(callback);
   int request_id = pending_quota_callbacks_.Add(std::move(callback));
   quota_host_->QueryStorageUsageAndQuota(
-      origin_url, type,
+      origin, type,
       base::BindOnce(&QuotaDispatcher::DidQueryStorageUsageAndQuota,
                      base::Unretained(this), request_id));
 }
 
 void QuotaDispatcher::RequestStorageQuota(int render_frame_id,
-                                          const GURL& origin_url,
+                                          const url::Origin& origin,
                                           StorageType type,
                                           int64_t requested_size,
                                           std::unique_ptr<Callback> callback) {
@@ -130,7 +130,7 @@
       << "Requests may show permission UI and are not allowed from workers.";
   int request_id = pending_quota_callbacks_.Add(std::move(callback));
   quota_host_->RequestStorageQuota(
-      render_frame_id, origin_url, type, requested_size,
+      render_frame_id, origin, type, requested_size,
       base::BindOnce(&QuotaDispatcher::DidGrantStorageQuota,
                      base::Unretained(this), request_id));
 }
diff --git a/content/renderer/quota_dispatcher.h b/content/renderer/quota_dispatcher.h
index ef1af82..308d280 100644
--- a/content/renderer/quota_dispatcher.h
+++ b/content/renderer/quota_dispatcher.h
@@ -16,12 +16,14 @@
 #include "content/common/quota_dispatcher_host.mojom.h"
 #include "content/public/renderer/worker_thread.h"
 
-class GURL;
-
 namespace blink {
 class WebStorageQuotaCallbacks;
 }
 
+namespace url {
+class Origin;
+}
+
 namespace content {
 
 // Dispatches and sends quota related messages sent to/from a child
@@ -51,11 +53,11 @@
   // WorkerThread::Observer implementation.
   void WillStopCurrentWorkerThread() override;
 
-  void QueryStorageUsageAndQuota(const GURL& gurl,
+  void QueryStorageUsageAndQuota(const url::Origin& origin,
                                  storage::StorageType type,
                                  std::unique_ptr<Callback> callback);
   void RequestStorageQuota(int render_frame_id,
-                           const GURL& gurl,
+                           const url::Origin& origin,
                            storage::StorageType type,
                            int64_t requested_size,
                            std::unique_ptr<Callback> callback);
diff --git a/content/renderer/render_frame_impl.cc b/content/renderer/render_frame_impl.cc
index 99d7b8e..86153593 100644
--- a/content/renderer/render_frame_impl.cc
+++ b/content/renderer/render_frame_impl.cc
@@ -124,9 +124,7 @@
 #include "content/renderer/media/media_permission_dispatcher.h"
 #include "content/renderer/media/media_stream_device_observer.h"
 #include "content/renderer/media/user_media_client_impl.h"
-#include "content/renderer/mojo/blink_connector_js_wrapper.h"
 #include "content/renderer/mojo/blink_interface_registry_impl.h"
-#include "content/renderer/mojo/interface_provider_js_wrapper.h"
 #include "content/renderer/navigation_state_impl.h"
 #include "content/renderer/pepper/pepper_audio_controller.h"
 #include "content/renderer/pepper/plugin_instance_throttler_impl.h"
@@ -156,12 +154,7 @@
 #include "content/renderer/web_ui_extension.h"
 #include "content/renderer/web_ui_extension_data.h"
 #include "crypto/sha2.h"
-#include "gin/modules/console.h"
-#include "gin/modules/module_registry.h"
-#include "gin/modules/timer.h"
 #include "media/blink/webmediaplayer_util.h"
-#include "mojo/edk/js/core.h"
-#include "mojo/edk/js/support.h"
 #include "net/base/data_url.h"
 #include "net/base/load_flags.h"
 #include "net/base/net_errors.h"
@@ -177,6 +170,7 @@
 #include "third_party/WebKit/common/associated_interfaces/associated_interface_provider.h"
 #include "third_party/WebKit/common/frame_policy.h"
 #include "third_party/WebKit/common/page/page_visibility_state.mojom.h"
+#include "third_party/WebKit/common/sandbox_flags.h"
 #include "third_party/WebKit/public/platform/FilePathConversion.h"
 #include "third_party/WebKit/public/platform/InterfaceProvider.h"
 #include "third_party/WebKit/public/platform/URLConversion.h"
@@ -2978,40 +2972,6 @@
                                          static_cast<uint32_t>(offset), range));
 }
 
-void RenderFrameImpl::EnsureMojoBuiltinsAreAvailable(
-    v8::Isolate* isolate,
-    v8::Local<v8::Context> context) {
-  gin::ModuleRegistry* registry = gin::ModuleRegistry::From(context);
-  if (registry->available_modules().count(mojo::edk::js::Core::kModuleName))
-    return;
-
-  v8::HandleScope handle_scope(isolate);
-
-  registry->AddBuiltinModule(isolate, gin::Console::kModuleName,
-                             gin::Console::GetModule(isolate));
-  registry->AddBuiltinModule(isolate, gin::TimerModule::kName,
-                             gin::TimerModule::GetModule(isolate));
-  registry->AddBuiltinModule(isolate, mojo::edk::js::Core::kModuleName,
-                             mojo::edk::js::Core::GetModule(isolate));
-  registry->AddBuiltinModule(isolate, mojo::edk::js::Support::kModuleName,
-                             mojo::edk::js::Support::GetModule(isolate));
-  registry->AddBuiltinModule(
-      isolate, InterfaceProviderJsWrapper::kPerFrameModuleName,
-      InterfaceProviderJsWrapper::Create(isolate, context, &remote_interfaces_)
-          .ToV8());
-  registry->AddBuiltinModule(
-      isolate, InterfaceProviderJsWrapper::kPerProcessModuleName,
-      InterfaceProviderJsWrapper::Create(isolate, context,
-                                         RenderThread::Get()->GetConnector())
-          .ToV8());
-  registry->AddBuiltinModule(
-      isolate, BlinkConnectorJsWrapper::kModuleName,
-      BlinkConnectorJsWrapper::Create(
-          isolate, context,
-          RenderThreadImpl::current_blink_platform_impl()->GetConnector())
-          .ToV8());
-}
-
 void RenderFrameImpl::AddMessageToConsole(ConsoleMessageLevel level,
                                           const std::string& message) {
   blink::WebConsoleMessage::Level target_level =
@@ -3576,8 +3536,7 @@
     // avoid breaking back/forward navigations: https://crbug.com/607205
     unique_name_helper_.UpdateName(name.Utf8());
   }
-  Send(new FrameHostMsg_DidChangeName(routing_id_, name.Utf8(),
-                                      unique_name_helper_.value()));
+  GetFrameHost()->DidChangeName(name.Utf8(), unique_name_helper_.value());
 
   if (!committed_first_load_)
     name_changed_before_first_commit_ = true;
@@ -3585,7 +3544,7 @@
 
 void RenderFrameImpl::DidEnforceInsecureRequestPolicy(
     blink::WebInsecureRequestPolicy policy) {
-  Send(new FrameHostMsg_EnforceInsecureRequestPolicy(routing_id_, policy));
+  GetFrameHost()->EnforceInsecureRequestPolicy(policy);
 }
 
 void RenderFrameImpl::DidChangeFramePolicy(
@@ -3603,8 +3562,7 @@
   // If either Feature Policy or Sandbox Flags are different from the default
   // (empty) values, then send them to the browser.
   if (!parsed_header.empty() || flags != blink::WebSandboxFlags::kNone) {
-    Send(new FrameHostMsg_DidSetFramePolicyHeaders(routing_id_, flags,
-                                                   parsed_header));
+    GetFrameHost()->DidSetFramePolicyHeaders(flags, parsed_header);
   }
 }
 
@@ -3910,7 +3868,8 @@
 
 void RenderFrameImpl::DidCommitProvisionalLoad(
     const blink::WebHistoryItem& item,
-    blink::WebHistoryCommitType commit_type) {
+    blink::WebHistoryCommitType commit_type,
+    blink::WebGlobalObjectReusePolicy global_object_reuse_policy) {
   TRACE_EVENT2("navigation,rail", "RenderFrameImpl::didCommitProvisionalLoad",
                "id", routing_id_,
                "url", GetLoadingUrl().possibly_invalid_spec());
@@ -4041,6 +4000,43 @@
     }
   }
 
+  service_manager::mojom::InterfaceProviderRequest
+      remote_interface_provider_request;
+  if (!navigation_state->WasWithinSameDocument() &&
+      global_object_reuse_policy !=
+          blink::WebGlobalObjectReusePolicy::kUseExisting) {
+    // If we're navigating to a new document, bind |remote_interfaces_| to a new
+    // message pipe. The request end of the new InterfaceProvider interface will
+    // be sent over as part of DidCommitProvisionalLoad. After the RFHI receives
+    // the commit confirmation, it will immediately close the old message pipe
+    // to avoid GetInterface calls racing with navigation commit, and bind the
+    // request end of the message pipe created here.
+    service_manager::mojom::InterfaceProviderPtr interfaces_provider;
+    remote_interface_provider_request = mojo::MakeRequest(&interfaces_provider);
+
+    // Must initialize |remote_interfaces_| with a new working pipe *before*
+    // observers receive DidCommitProvisionalLoad, so they can already request
+    // remote interfaces. The interface requests will be serviced once the
+    // InterfaceProvider interface request is bound by the RenderFrameHostImpl.
+    remote_interfaces_.Close();
+    remote_interfaces_.Bind(std::move(interfaces_provider));
+
+    // AudioIPCFactory may be null in tests.
+    if (auto* factory = AudioIPCFactory::get()) {
+      // The RendererAudioOutputStreamFactory must be readily accessible on the
+      // IO thread when it's needed, because the main thread may block while
+      // waiting for the factory call to finish on the IO thread, so if we tried
+      // to lazily initialize it, we could deadlock.
+      //
+      // TODO(https://crbug.com/668275): Still, it is odd for one specific
+      // factory to be registered here, make this a RenderFrameObserver.
+      // code.
+      factory->MaybeDeregisterRemoteFactory(GetRoutingID());
+      factory->MaybeRegisterRemoteFactory(GetRoutingID(),
+                                          GetRemoteInterfaces());
+    }
+  }
+
   if (commit_type == blink::WebHistoryCommitType::kWebBackForwardCommit)
     render_view_->DidCommitProvisionalHistoryLoad();
 
@@ -4077,7 +4073,8 @@
   // new navigation.
   navigation_state->set_request_committed(true);
 
-  SendDidCommitProvisionalLoad(frame_, commit_type);
+  SendDidCommitProvisionalLoad(frame_, commit_type,
+                               std::move(remote_interface_provider_request));
 
   // Check whether we have new encoding name.
   UpdateEncoding(frame_, frame_->View()->PageEncoding().Utf8());
@@ -4323,7 +4320,8 @@
   static_cast<NavigationStateImpl*>(document_state->navigation_state())
       ->set_was_within_same_document(true);
 
-  DidCommitProvisionalLoad(item, commit_type);
+  DidCommitProvisionalLoad(item, commit_type,
+                           blink::WebGlobalObjectReusePolicy::kUseExisting);
 }
 
 void RenderFrameImpl::DidUpdateCurrentHistoryItem() {
@@ -4909,8 +4907,8 @@
     return;
   }
   RenderThreadImpl::current()->quota_dispatcher()->RequestStorageQuota(
-      routing_id_, url::Origin(origin).GetURL(),
-      static_cast<storage::StorageType>(type), requested_size,
+      routing_id_, origin, static_cast<storage::StorageType>(type),
+      requested_size,
       QuotaDispatcher::CreateWebStorageQuotaCallbacksWrapper(callbacks));
 }
 
@@ -5162,7 +5160,9 @@
 // Tell the embedding application that the URL of the active page has changed.
 void RenderFrameImpl::SendDidCommitProvisionalLoad(
     blink::WebLocalFrame* frame,
-    blink::WebHistoryCommitType commit_type) {
+    blink::WebHistoryCommitType commit_type,
+    service_manager::mojom::InterfaceProviderRequest
+        remote_interface_provider_request) {
   DCHECK_EQ(frame_, frame);
   WebDocumentLoader* document_loader = frame->GetDocumentLoader();
   DCHECK(document_loader);
@@ -5383,7 +5383,8 @@
   // 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));
+  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.
diff --git a/content/renderer/render_frame_impl.h b/content/renderer/render_frame_impl.h
index 29a2a85..81d9b66b 100644
--- a/content/renderer/render_frame_impl.h
+++ b/content/renderer/render_frame_impl.h
@@ -483,8 +483,6 @@
   void SetSelectedText(const base::string16& selection_text,
                        size_t offset,
                        const gfx::Range& range) override;
-  void EnsureMojoBuiltinsAreAvailable(v8::Isolate* isolate,
-                                      v8::Local<v8::Context> context) override;
   void AddMessageToConsole(ConsoleMessageLevel level,
                            const std::string& message) override;
   void DetachDevToolsForTest() override;
@@ -611,7 +609,8 @@
                               blink::WebHistoryCommitType commit_type) override;
   void DidCommitProvisionalLoad(
       const blink::WebHistoryItem& item,
-      blink::WebHistoryCommitType commit_type) override;
+      blink::WebHistoryCommitType commit_type,
+      blink::WebGlobalObjectReusePolicy global_object_reuse_policy) override;
   void DidCreateNewDocument() override;
   void DidClearWindowObject() override;
   void DidCreateDocumentElement() override;
@@ -943,8 +942,11 @@
   const RenderFrameImpl* GetLocalRoot() const;
 
   // Builds and sends DidCommitProvisionalLoad to the host.
-  void SendDidCommitProvisionalLoad(blink::WebLocalFrame* frame,
-                                    blink::WebHistoryCommitType commit_type);
+  void SendDidCommitProvisionalLoad(
+      blink::WebLocalFrame* frame,
+      blink::WebHistoryCommitType commit_type,
+      service_manager::mojom::InterfaceProviderRequest
+          remote_interface_provider_request);
 
   // Swaps the current frame into the frame tree, replacing the
   // RenderFrameProxy it is associated with.  Return value indicates whether
diff --git a/content/renderer/render_frame_impl_browsertest.cc b/content/renderer/render_frame_impl_browsertest.cc
index 548dfa4b..10d237324 100644
--- a/content/renderer/render_frame_impl_browsertest.cc
+++ b/content/renderer/render_frame_impl_browsertest.cc
@@ -3,17 +3,23 @@
 // found in the LICENSE file.
 
 #include <stdint.h>
+#include <tuple>
+#include <utility>
 
+#include "base/bind.h"
+#include "base/bind_helpers.h"
 #include "base/command_line.h"
 #include "base/debug/leak_annotations.h"
 #include "base/run_loop.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/test/bind_test_util.h"
 #include "build/build_config.h"
 #include "content/common/frame_messages.h"
 #include "content/common/frame_owner_properties.h"
 #include "content/common/renderer.mojom.h"
 #include "content/common/view_messages.h"
 #include "content/public/common/previews_state.h"
+#include "content/public/renderer/content_renderer_client.h"
 #include "content/public/renderer/document_state.h"
 #include "content/public/test/frame_load_waiter.h"
 #include "content/public/test/render_view_test.h"
@@ -24,6 +30,11 @@
 #include "content/renderer/render_frame_impl.h"
 #include "content/renderer/render_view_impl.h"
 #include "content/test/fake_compositor_dependencies.h"
+#include "content/test/frame_host_test_interface.mojom.h"
+#include "content/test/test_render_frame.h"
+#include "services/service_manager/public/cpp/interface_provider.h"
+#include "services/service_manager/public/interfaces/interface_provider.mojom.h"
+#include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/WebKit/public/platform/WebEffectiveConnectionType.h"
 #include "third_party/WebKit/public/platform/WebRuntimeFeatures.h"
@@ -38,15 +49,17 @@
 using blink::WebString;
 using blink::WebURLRequest;
 
-namespace {
-const int32_t kSubframeRouteId = 20;
-const int32_t kSubframeWidgetRouteId = 21;
-const int32_t kFrameProxyRouteId = 22;
-const int32_t kEmbeddedSubframeRouteId = 23;
-}  // namespace
-
 namespace content {
 
+namespace {
+
+constexpr int32_t kSubframeRouteId = 20;
+constexpr int32_t kSubframeWidgetRouteId = 21;
+constexpr int32_t kFrameProxyRouteId = 22;
+constexpr int32_t kEmbeddedSubframeRouteId = 23;
+
+}  // namespace
+
 // RenderFrameImplTest creates a RenderFrameImpl that is a child of the
 // main frame, and has its own RenderWidget. This behaves like an out
 // of process frame even though it is in the same process as its parent.
@@ -84,7 +97,8 @@
         base::UnguessableToken::Create(), frame_replication_state,
         &compositor_deps_, widget_params, FrameOwnerProperties());
 
-    frame_ = RenderFrameImpl::FromRoutingID(kSubframeRouteId);
+    frame_ = static_cast<TestRenderFrame*>(
+        RenderFrameImpl::FromRoutingID(kSubframeRouteId));
     EXPECT_FALSE(frame_->is_main_frame_);
   }
 
@@ -106,11 +120,11 @@
     frame->effective_connection_type_ = type;
   }
 
-  RenderFrameImpl* GetMainRenderFrame() {
-    return static_cast<RenderFrameImpl*>(view_->GetMainRenderFrame());
+  TestRenderFrame* GetMainRenderFrame() {
+    return static_cast<TestRenderFrame*>(view_->GetMainRenderFrame());
   }
 
-  RenderFrameImpl* frame() { return frame_; }
+  TestRenderFrame* frame() { return frame_; }
 
   content::RenderWidget* frame_widget() const {
     return frame_->render_widget_.get();
@@ -125,7 +139,7 @@
 #endif
 
  private:
-  RenderFrameImpl* frame_;
+  TestRenderFrame* frame_;
   FakeCompositorDependencies compositor_deps_;
 };
 
@@ -251,7 +265,9 @@
   static_cast<NavigationStateImpl*>(document_state->navigation_state())
       ->set_was_within_same_document(false);
 
-  frame()->DidCommitProvisionalLoad(item, blink::kWebStandardCommit);
+  frame()->DidCommitProvisionalLoad(
+      item, blink::kWebStandardCommit,
+      blink::WebGlobalObjectReusePolicy::kCreateNew);
   EXPECT_EQ(SERVER_LOFI_ON, frame()->GetPreviewsState());
 
   // The main frame's LoFi state should be reset to off on commit.
@@ -262,8 +278,9 @@
 
   // Calling didCommitProvisionalLoad is not representative of a full navigation
   // but serves the purpose of testing the LoFi state logic.
-  GetMainRenderFrame()->DidCommitProvisionalLoad(item,
-                                                 blink::kWebStandardCommit);
+  GetMainRenderFrame()->DidCommitProvisionalLoad(
+      item, blink::kWebStandardCommit,
+      blink::WebGlobalObjectReusePolicy::kCreateNew);
   EXPECT_EQ(PREVIEWS_OFF, GetMainRenderFrame()->GetPreviewsState());
   // The subframe would be deleted here after a cross-document navigation. It
   // happens to be left around in this test because this does not simulate the
@@ -309,7 +326,9 @@
     static_cast<NavigationStateImpl*>(document_state->navigation_state())
         ->set_was_within_same_document(false);
 
-    frame()->DidCommitProvisionalLoad(item, blink::kWebStandardCommit);
+    frame()->DidCommitProvisionalLoad(
+        item, blink::kWebStandardCommit,
+        blink::WebGlobalObjectReusePolicy::kCreateNew);
     EXPECT_EQ(tests[i].type, frame()->GetEffectiveConnectionType());
 
     // The main frame's effective connection type should be reset on commit.
@@ -318,8 +337,9 @@
     static_cast<NavigationStateImpl*>(document_state->navigation_state())
         ->set_was_within_same_document(false);
 
-    GetMainRenderFrame()->DidCommitProvisionalLoad(item,
-                                                   blink::kWebStandardCommit);
+    GetMainRenderFrame()->DidCommitProvisionalLoad(
+        item, blink::kWebStandardCommit,
+        blink::WebGlobalObjectReusePolicy::kCreateNew);
     EXPECT_EQ(blink::WebEffectiveConnectionType::kTypeUnknown,
               GetMainRenderFrame()->GetEffectiveConnectionType());
 
@@ -617,4 +637,569 @@
   }
 }
 
+// RenderFrameRemoteInterfacesTest ------------------------------------
+
+namespace {
+
+constexpr char kTestFirstURL[] = "http://foo.com/1";
+constexpr char kTestSecondURL[] = "http://foo.com/2";
+// constexpr char kTestCrossOriginURL[] = "http://bar.com/";
+constexpr char kAboutBlankURL[] = "about:blank";
+
+constexpr char kFrameEventDidCreateNewFrame[] = "did-create-new-frame";
+constexpr char kFrameEventDidCreateNewDocument[] = "did-create-new-document";
+constexpr char kFrameEventDidCreateDocumentElement[] =
+    "did-create-document-element";
+constexpr char kFrameEventWillCommitProvisionalLoad[] =
+    "will-commit-provisional-load";
+constexpr char kFrameEventDidCommitProvisionalLoad[] =
+    "did-commit-provisional-load";
+constexpr char kFrameEventDidCommitSameDocumentLoad[] =
+    "did-commit-same-document-load";
+constexpr char kFrameEventAfterCommit[] = "after-commit";
+
+constexpr char kNoDocumentMarkerURL[] = "data:,No document.";
+
+// A simple testing implementation of mojom::InterfaceProvider that binds
+// interface requests only for one hard-coded kind of interface.
+class TestSimpleInterfaceProviderImpl
+    : public service_manager::mojom::InterfaceProvider {
+ public:
+  using BinderCallback =
+      base::RepeatingCallback<void(mojo::ScopedMessagePipeHandle)>;
+
+  // Incoming interface requests for |interface_name| will invoke |binder|.
+  // Everything else is ignored.
+  TestSimpleInterfaceProviderImpl(const std::string& interface_name,
+                                  BinderCallback binder_callback)
+      : binding_(this),
+        interface_name_(interface_name),
+        binder_callback_(binder_callback) {}
+
+  void BindAndFlush(service_manager::mojom::InterfaceProviderRequest request) {
+    ASSERT_FALSE(binding_.is_bound());
+    binding_.Bind(std::move(request));
+    binding_.FlushForTesting();
+  }
+
+ private:
+  // mojom::InterfaceProvider:
+  void GetInterface(const std::string& interface_name,
+                    mojo::ScopedMessagePipeHandle handle) override {
+    if (interface_name == interface_name_)
+      binder_callback_.Run(std::move(handle));
+  }
+
+  mojo::Binding<service_manager::mojom::InterfaceProvider> binding_;
+
+  std::string interface_name_;
+  BinderCallback binder_callback_;
+
+  DISALLOW_COPY_AND_ASSIGN(TestSimpleInterfaceProviderImpl);
+};
+
+// Used to annotate the source of an interface request.
+struct SourceAnnotation {
+  // The URL of the active document in the frame, at the time the interface was
+  // requested by the RenderFrame.
+  GURL document_url;
+
+  // The RenderFrameObserver event in response to which the interface is
+  // requested by the RenderFrame.
+  std::string render_frame_event;
+
+  bool operator==(const SourceAnnotation& rhs) const {
+    return document_url == rhs.document_url &&
+           render_frame_event == rhs.render_frame_event;
+  }
+};
+
+std::ostream& operator<<(std::ostream& os, const SourceAnnotation& a) {
+  return os << "[" << a.document_url << ", " << a.render_frame_event << "]";
+}
+
+class FrameHostTestInterfaceImpl : public mojom::FrameHostTestInterface {
+ public:
+  FrameHostTestInterfaceImpl() : binding_(this) {}
+  ~FrameHostTestInterfaceImpl() override {}
+
+  void BindAndFlush(mojom::FrameHostTestInterfaceRequest request) {
+    binding_.Bind(std::move(request));
+    binding_.WaitForIncomingMethodCall();
+  }
+
+  const base::Optional<SourceAnnotation>& ping_source() const {
+    return ping_source_;
+  }
+
+ protected:
+  void Ping(const GURL& url, const std::string& event) override {
+    ping_source_ = SourceAnnotation{url, event};
+  }
+
+ private:
+  mojo::Binding<mojom::FrameHostTestInterface> binding_;
+  base::Optional<SourceAnnotation> ping_source_;
+
+  DISALLOW_COPY_AND_ASSIGN(FrameHostTestInterfaceImpl);
+};
+
+// RenderFrameObserver that issues FrameHostTestInterface interface requests
+// through the RenderFrame's |remote_interfaces_| in response to observing
+// important milestones in a frame's lifecycle.
+class FrameHostTestInterfaceRequestIssuer : public RenderFrameObserver {
+ public:
+  explicit FrameHostTestInterfaceRequestIssuer(RenderFrame* render_frame)
+      : RenderFrameObserver(render_frame) {}
+
+  void RequestTestInterfaceOnFrameEvent(const std::string& event) {
+    mojom::FrameHostTestInterfacePtr ptr;
+    render_frame()->GetRemoteInterfaces()->GetInterface(
+        mojo::MakeRequest(&ptr));
+
+    blink::WebDocument document = render_frame()->GetWebFrame()->GetDocument();
+    ptr->Ping(
+        !document.IsNull() ? GURL(document.Url()) : GURL(kNoDocumentMarkerURL),
+        event);
+  }
+
+ private:
+  // RenderFrameObserver:
+  void OnDestruct() override {}
+
+  void DidCreateDocumentElement() override {
+    RequestTestInterfaceOnFrameEvent(kFrameEventDidCreateDocumentElement);
+  }
+
+  void DidCreateNewDocument() override {
+    RequestTestInterfaceOnFrameEvent(kFrameEventDidCreateNewDocument);
+  }
+
+  void WillCommitProvisionalLoad() override {
+    RequestTestInterfaceOnFrameEvent(kFrameEventWillCommitProvisionalLoad);
+  }
+
+  void DidStartProvisionalLoad(
+      blink::WebDocumentLoader* document_loader) override {}
+
+  void DidFailProvisionalLoad(const blink::WebURLError& error) override {}
+
+  void DidCommitProvisionalLoad(bool is_new_navigation,
+                                bool is_same_document_navigation) override {
+    RequestTestInterfaceOnFrameEvent(is_same_document_navigation
+                                         ? kFrameEventDidCommitSameDocumentLoad
+                                         : kFrameEventDidCommitProvisionalLoad);
+  }
+
+  DISALLOW_COPY_AND_ASSIGN(FrameHostTestInterfaceRequestIssuer);
+};
+
+// RenderFrameObserver that can be used to wait for the next commit in a frame.
+class FrameCommitWaiter : public RenderFrameObserver {
+ public:
+  explicit FrameCommitWaiter(RenderFrame* render_frame)
+      : RenderFrameObserver(render_frame) {}
+
+  void Wait() {
+    if (did_commit_)
+      return;
+    run_loop_.Run();
+  }
+
+ private:
+  // RenderFrameObserver:
+  void OnDestruct() override {}
+
+  void DidCommitProvisionalLoad(bool is_new_navigation,
+                                bool is_same_document_navigation) override {
+    did_commit_ = true;
+    run_loop_.Quit();
+  }
+
+  base::RunLoop run_loop_;
+  bool did_commit_ = false;
+
+  DISALLOW_COPY_AND_ASSIGN(FrameCommitWaiter);
+};
+
+// Testing ContentRendererClient implementation that fires the |callback|
+// whenever a new frame is created.
+class FrameCreationObservingRendererClient : public ContentRendererClient {
+ public:
+  using FrameCreatedCallback = base::RepeatingCallback<void(TestRenderFrame*)>;
+
+  FrameCreationObservingRendererClient() {}
+  ~FrameCreationObservingRendererClient() override {}
+
+  void set_callback(FrameCreatedCallback callback) {
+    callback_ = std::move(callback);
+  }
+
+  void reset_callback() { callback_.Reset(); }
+
+ protected:
+  void RenderFrameCreated(RenderFrame* render_frame) override {
+    ContentRendererClient::RenderFrameCreated(render_frame);
+    if (callback_)
+      callback_.Run(static_cast<TestRenderFrame*>(render_frame));
+  }
+
+ private:
+  FrameCreatedCallback callback_;
+
+  DISALLOW_COPY_AND_ASSIGN(FrameCreationObservingRendererClient);
+};
+
+// Expects observing the creation of a new frame, and creates an instance of
+// FrameHostTestInterfaceRequestIssuerRenderFrame for that new frame to exercise
+// its RemoteInterfaceProvider interface.
+class ScopedNewFrameInterfaceProviderExerciser {
+ public:
+  explicit ScopedNewFrameInterfaceProviderExerciser(
+      FrameCreationObservingRendererClient* frame_creation_observer,
+      const base::Optional<GURL>& url_override_for_first_load = base::nullopt)
+      : frame_creation_observer_(frame_creation_observer),
+        url_override_for_first_load_(url_override_for_first_load) {
+    frame_creation_observer_->set_callback(base::BindRepeating(
+        &ScopedNewFrameInterfaceProviderExerciser::OnFrameCreated,
+        base::Unretained(this)));
+  }
+
+  ~ScopedNewFrameInterfaceProviderExerciser() {
+    frame_creation_observer_->reset_callback();
+  }
+
+  void ExpectNewFrameAndWaitForLoad(const GURL& expected_loaded_url) {
+    ASSERT_NE(nullptr, frame_);
+    frame_commit_waiter_->Wait();
+
+    ASSERT_FALSE(frame_->current_history_item().IsNull());
+    ASSERT_FALSE(frame_->GetWebFrame()->GetDocument().IsNull());
+    EXPECT_EQ(expected_loaded_url,
+              GURL(frame_->GetWebFrame()->GetDocument().Url()));
+
+    interface_request_for_first_document_ =
+        frame_->TakeLastInterfaceProviderRequest();
+  }
+
+  service_manager::mojom::InterfaceProviderRequest
+  interface_request_for_initial_empty_document() {
+    return std::move(interface_request_for_initial_empty_document_);
+  };
+
+  service_manager::mojom::InterfaceProviderRequest
+  interface_request_for_first_document() {
+    return std::move(interface_request_for_first_document_);
+  }
+
+ private:
+  void OnFrameCreated(TestRenderFrame* frame) {
+    ASSERT_EQ(nullptr, frame_);
+    frame_ = frame;
+    frame_commit_waiter_.emplace(frame);
+
+    if (url_override_for_first_load_.has_value()) {
+      frame_->SetURLOverrideForNextWebURLRequest(
+          std::move(url_override_for_first_load_).value());
+    }
+
+    // The FrameHostTestInterfaceRequestIssuer needs to stay alive even after
+    // this method returns, so that it continues to observe RenderFrame
+    // lifecycle events and request test interfaces in response.
+    test_request_issuer_.emplace(frame);
+    test_request_issuer_->RequestTestInterfaceOnFrameEvent(
+        kFrameEventDidCreateNewFrame);
+
+    interface_request_for_initial_empty_document_ =
+        frame->TakeLastInterfaceProviderRequest();
+    EXPECT_TRUE(frame->current_history_item().IsNull());
+  }
+
+  FrameCreationObservingRendererClient* frame_creation_observer_;
+  TestRenderFrame* frame_ = nullptr;
+  base::Optional<GURL> url_override_for_first_load_;
+  GURL first_committed_url_;
+
+  base::Optional<FrameCommitWaiter> frame_commit_waiter_;
+  base::Optional<FrameHostTestInterfaceRequestIssuer> test_request_issuer_;
+
+  service_manager::mojom::InterfaceProviderRequest
+      interface_request_for_initial_empty_document_;
+  service_manager::mojom::InterfaceProviderRequest
+      interface_request_for_first_document_;
+
+  DISALLOW_COPY_AND_ASSIGN(ScopedNewFrameInterfaceProviderExerciser);
+};
+
+// Extracts all interface requests for FrameHostTestInterface pending on the
+// specified |interface_provider_request|, and returns a list of the source
+// annotations that are provided in the pending Ping() call for each of these
+// FrameHostTestInterface requests.
+void ExpectPendingInterfaceRequestsFromSources(
+    service_manager::mojom::InterfaceProviderRequest interface_provider_request,
+    std::vector<SourceAnnotation> expected_sources) {
+  std::vector<SourceAnnotation> sources;
+  ASSERT_TRUE(interface_provider_request.is_pending());
+  TestSimpleInterfaceProviderImpl provider(
+      mojom::FrameHostTestInterface::Name_,
+      base::BindLambdaForTesting(
+          [&sources](mojo::ScopedMessagePipeHandle handle) {
+            FrameHostTestInterfaceImpl impl;
+            impl.BindAndFlush(
+                mojom::FrameHostTestInterfaceRequest(std::move(handle)));
+            ASSERT_TRUE(impl.ping_source().has_value());
+            sources.push_back(impl.ping_source().value());
+          }));
+  provider.BindAndFlush(std::move(interface_provider_request));
+  EXPECT_THAT(sources, ::testing::ElementsAreArray(expected_sources));
+}
+
+}  // namespace
+
+class RenderFrameRemoteInterfacesTest : public RenderViewTest {
+ public:
+  RenderFrameRemoteInterfacesTest() {}
+  ~RenderFrameRemoteInterfacesTest() override {}
+
+ protected:
+  void SetUp() override {
+    RenderViewTest::SetUp();
+    LoadHTML("Nothing to see here.");
+  }
+
+  void TearDown() override {
+#if defined(LEAK_SANITIZER)
+    // Do this before shutting down V8 in RenderViewTest::TearDown().
+    // http://crbug.com/328552
+    __lsan_do_leak_check();
+#endif
+    RenderViewTest::TearDown();
+  }
+
+  FrameCreationObservingRendererClient* frame_creation_observer() {
+    DCHECK(frame_creation_observer_);
+    return frame_creation_observer_;
+  }
+
+  TestRenderFrame* GetMainRenderFrame() {
+    return static_cast<TestRenderFrame*>(view_->GetMainRenderFrame());
+  }
+
+  ContentRendererClient* CreateContentRendererClient() override {
+    frame_creation_observer_ = new FrameCreationObservingRendererClient();
+    return frame_creation_observer_;
+  }
+
+ private:
+  // Owned by RenderViewTest.
+  FrameCreationObservingRendererClient* frame_creation_observer_ = nullptr;
+
+  DISALLOW_COPY_AND_ASSIGN(RenderFrameRemoteInterfacesTest);
+};
+
+// Expect that |remote_interfaces_| is bound before the first committed load in
+// a child frame, and then re-bound on the first commit.
+TEST_F(RenderFrameRemoteInterfacesTest, ChildFrameAtFirstCommittedLoad) {
+  constexpr struct {
+    const char* main_frame_url_override;
+    const char* child_frame_url;
+  } kTestCases[] = {
+      {kTestFirstURL, kAboutBlankURL},
+      {kTestSecondURL, "data:text/html,Child"},
+      {kAboutBlankURL, kAboutBlankURL},
+  };
+
+  for (const auto& test_case : kTestCases) {
+    SCOPED_TRACE(::testing::Message()
+                 << "main_frame_url = " << test_case.main_frame_url_override
+                 << ", child_frame_url = " << test_case.child_frame_url);
+
+    ScopedNewFrameInterfaceProviderExerciser child_frame_exerciser(
+        frame_creation_observer());
+    const std::string html = base::StringPrintf("<iframe src=\"%s\"></iframe>",
+                                                test_case.child_frame_url);
+    LoadHTMLWithUrlOverride(html.c_str(), test_case.main_frame_url_override);
+
+    const GURL child_frame_url(test_case.child_frame_url);
+    ASSERT_NO_FATAL_FAILURE(
+        child_frame_exerciser.ExpectNewFrameAndWaitForLoad(child_frame_url));
+
+    // TODO(https://crbug.com/792410): It is unfortunate how many internal
+    // details of frame/document creation this encodes. Need to decouple.
+    const GURL initial_empty_url(kAboutBlankURL);
+    ExpectPendingInterfaceRequestsFromSources(
+        child_frame_exerciser.interface_request_for_initial_empty_document(),
+        {{GURL(kNoDocumentMarkerURL), kFrameEventDidCreateNewFrame},
+         {initial_empty_url, kFrameEventDidCreateNewDocument},
+         {initial_empty_url, kFrameEventDidCreateDocumentElement},
+         {initial_empty_url, kFrameEventWillCommitProvisionalLoad},
+         // TODO(https://crbug.com/555773): It seems strange that the new
+         // document is created and DidCreateNewDocument is invoked *before* the
+         // provisional load would have even committed.
+         {child_frame_url, kFrameEventDidCreateNewDocument}});
+    ExpectPendingInterfaceRequestsFromSources(
+        child_frame_exerciser.interface_request_for_first_document(),
+        {{child_frame_url, kFrameEventDidCommitProvisionalLoad},
+         {child_frame_url, kFrameEventDidCreateDocumentElement}});
+  }
+}
+
+// Expect that |remote_interfaces_| is bound before the first committed load in
+// the main frame of an opened window, and then re-bound on the first commit.
+TEST_F(RenderFrameRemoteInterfacesTest,
+       MainFrameOfOpenedWindowAtFirstCommittedLoad) {
+  constexpr struct {
+    const char* main_frame_url_override;
+    const char* new_window_url;
+  } kTestCases[] = {
+      {kTestFirstURL, kAboutBlankURL},
+      {kTestSecondURL, "data:text/html,NewWindow"},
+      {kAboutBlankURL, kAboutBlankURL},
+  };
+
+  for (const auto& test_case : kTestCases) {
+    SCOPED_TRACE(::testing::Message()
+                 << "main_frame_url = " << test_case.main_frame_url_override
+                 << ", new_window_url = " << test_case.new_window_url);
+
+    const GURL new_window_url(test_case.new_window_url);
+    ScopedNewFrameInterfaceProviderExerciser main_frame_exerciser(
+        frame_creation_observer(), new_window_url);
+    const std::string html =
+        base::StringPrintf("<script>window.open(\"%s\", \"_blank\")</script>",
+                           test_case.new_window_url);
+    LoadHTMLWithUrlOverride(html.c_str(), test_case.main_frame_url_override);
+    ASSERT_NO_FATAL_FAILURE(
+        main_frame_exerciser.ExpectNewFrameAndWaitForLoad(new_window_url));
+
+    // The URL of the initial empty document is "" for opened windows, in
+    // contrast to child frames, where it is "about:blank". See
+    // Document::Document and Document::SetURL for more details.
+    //
+    // Furthermore, for main frames, InitializeCoreFrame is invoked first, and
+    // RenderFrameImpl::Initialize is invoked second, in contrast to child
+    // frames where it is vice versa. ContentRendererClient::RenderFrameCreated
+    // is invoked from RenderFrameImpl::Initialize, so we miss the events
+    // related to initial empty document that is created from
+    // InitializeCoreFrame, and there is already a document when
+    // RenderFrameCreated is invoked.
+    //
+    // TODO(https://crbug.com/792410): It is unfortunate how many internal
+    // details of frame/document creation this encodes. Need to decouple.
+    const GURL initial_empty_url;
+    ExpectPendingInterfaceRequestsFromSources(
+        main_frame_exerciser.interface_request_for_initial_empty_document(),
+        {{initial_empty_url, kFrameEventDidCreateNewFrame},
+         {initial_empty_url, kFrameEventWillCommitProvisionalLoad},
+         {new_window_url, kFrameEventDidCreateNewDocument}});
+    ExpectPendingInterfaceRequestsFromSources(
+        main_frame_exerciser.interface_request_for_first_document(),
+        {{new_window_url, kFrameEventDidCommitProvisionalLoad},
+         {new_window_url, kFrameEventDidCreateDocumentElement}});
+  }
+}
+
+// Expect that |remote_interfaces_| is not bound to a new pipe if the first
+// committed load in the child frame has the same security origin as that of the
+// initial empty document.
+//
+// In this case, the LocalDOMWindow object associated with the initial empty
+// document will be re-used for the newly committed document. Here, we must
+// continue using the InterfaceProvider connection created for the initial empty
+// document to support the following use-case:
+//  1) Parent frame dynamically injects an <iframe>.
+//  2) The parent frame calls `child.contentDocument.write(...)` to inject
+//     Javascript that may stash objects on the child frame's global object
+//     (LocalDOMWindow). Internally, these objects may be using Mojo services
+//     exposed by the RenderFrameHost. The InterfaceRequests for these services
+//     might still be en-route to the RemnderFrameHost's InterfaceProvider.
+//  3) The `child` frame commits the first real load, and it is same-origin.
+//  4) The global object in the child frame's browsing context is re-used.
+//  5) Javascript objects stashed on the global object should continue to work.
+//
+// TODO(https://crbug.com/778318): Once the Window object inheritance is fixed,
+// add a similar test for: <iframe src="javascript:'html'"></iframe>.
+TEST_F(RenderFrameRemoteInterfacesTest,
+       ChildFrameReusingWindowOfInitialDocument) {
+  const GURL main_frame_url(kTestFirstURL);
+  const GURL initial_empty_url(kAboutBlankURL);
+  const GURL child_frame_url(kTestSecondURL);
+
+  // Override the URL for the first navigation in the newly created frame to
+  // |child_frame_url|.
+  ScopedNewFrameInterfaceProviderExerciser child_frame_exerciser(
+      frame_creation_observer(), child_frame_url);
+
+  constexpr char kHTML[] = "<iframe srcdoc=\"Foo\"></iframe>";
+  LoadHTMLWithUrlOverride(kHTML, main_frame_url.spec().c_str());
+
+  ASSERT_NO_FATAL_FAILURE(
+      child_frame_exerciser.ExpectNewFrameAndWaitForLoad(child_frame_url));
+
+  ExpectPendingInterfaceRequestsFromSources(
+      child_frame_exerciser.interface_request_for_initial_empty_document(),
+      {{GURL(kNoDocumentMarkerURL), kFrameEventDidCreateNewFrame},
+       {initial_empty_url, kFrameEventDidCreateNewDocument},
+       {initial_empty_url, kFrameEventDidCreateDocumentElement},
+       {initial_empty_url, kFrameEventWillCommitProvisionalLoad},
+       {child_frame_url, kFrameEventDidCreateNewDocument},
+       {child_frame_url, kFrameEventDidCommitProvisionalLoad},
+       {child_frame_url, kFrameEventDidCreateDocumentElement}});
+
+  auto request = child_frame_exerciser.interface_request_for_first_document();
+  ASSERT_FALSE(request.is_pending());
+}
+
+// Expect that |remote_interfaces_| is bound to a new pipe on cross-document
+// navigations.
+TEST_F(RenderFrameRemoteInterfacesTest, ReplacedOnNonSameDocumentNavigation) {
+  LoadHTMLWithUrlOverride("", kTestFirstURL);
+
+  auto interface_provider_request_for_first_document =
+      GetMainRenderFrame()->TakeLastInterfaceProviderRequest();
+
+  FrameHostTestInterfaceRequestIssuer requester(GetMainRenderFrame());
+  requester.RequestTestInterfaceOnFrameEvent(kFrameEventAfterCommit);
+
+  LoadHTMLWithUrlOverride("", kTestSecondURL);
+
+  auto interface_provider_request_for_second_document =
+      GetMainRenderFrame()->TakeLastInterfaceProviderRequest();
+
+  ASSERT_TRUE(interface_provider_request_for_first_document.is_pending());
+  ExpectPendingInterfaceRequestsFromSources(
+      std::move(interface_provider_request_for_first_document),
+      {{GURL(kTestFirstURL), kFrameEventAfterCommit},
+       {GURL(kTestFirstURL), kFrameEventWillCommitProvisionalLoad},
+       {GURL(kTestSecondURL), kFrameEventDidCreateNewDocument}});
+
+  ASSERT_TRUE(interface_provider_request_for_second_document.is_pending());
+  ExpectPendingInterfaceRequestsFromSources(
+      std::move(interface_provider_request_for_second_document),
+      {{GURL(kTestSecondURL), kFrameEventDidCommitProvisionalLoad},
+       {GURL(kTestSecondURL), kFrameEventDidCreateDocumentElement}});
+}
+
+// Expect that |remote_interfaces_| is not bound to a new pipe on same-document
+// navigations, i.e. the existing InterfaceProvider connection is continued to
+// be used.
+TEST_F(RenderFrameRemoteInterfacesTest, ReusedOnSameDocumentNavigation) {
+  LoadHTMLWithUrlOverride("", kTestFirstURL);
+
+  auto interface_provider_request =
+      GetMainRenderFrame()->TakeLastInterfaceProviderRequest();
+
+  FrameHostTestInterfaceRequestIssuer requester(GetMainRenderFrame());
+  OnSameDocumentNavigation(GetMainFrame(), true /* is_new_navigation */,
+                           true /* is_contenet_initiated */);
+
+  EXPECT_FALSE(
+      GetMainRenderFrame()->TakeLastInterfaceProviderRequest().is_pending());
+
+  ASSERT_TRUE(interface_provider_request.is_pending());
+  ExpectPendingInterfaceRequestsFromSources(
+      std::move(interface_provider_request),
+      {{GURL(kTestFirstURL), kFrameEventDidCommitSameDocumentLoad}});
+}
+
 }  // namespace content
diff --git a/content/renderer/renderer_blink_platform_impl.cc b/content/renderer/renderer_blink_platform_impl.cc
index 5b40a17..8873a2b 100644
--- a/content/renderer/renderer_blink_platform_impl.cc
+++ b/content/renderer/renderer_blink_platform_impl.cc
@@ -1364,7 +1364,7 @@
 //------------------------------------------------------------------------------
 
 void RendererBlinkPlatformImpl::QueryStorageUsageAndQuota(
-    const blink::WebURL& storage_partition,
+    const blink::WebSecurityOrigin& storage_partition,
     blink::WebStorageQuotaType type,
     blink::WebStorageQuotaCallbacks callbacks) {
   QuotaDispatcher::ThreadSpecificInstance(default_task_runner_)
diff --git a/content/renderer/renderer_blink_platform_impl.h b/content/renderer/renderer_blink_platform_impl.h
index 7264910..9f7bb41 100644
--- a/content/renderer/renderer_blink_platform_impl.h
+++ b/content/renderer/renderer_blink_platform_impl.h
@@ -207,9 +207,10 @@
   void StartListening(blink::WebPlatformEventType,
                       blink::WebPlatformEventListener*) override;
   void StopListening(blink::WebPlatformEventType) override;
-  void QueryStorageUsageAndQuota(const blink::WebURL& storage_partition,
-                                 blink::WebStorageQuotaType,
-                                 blink::WebStorageQuotaCallbacks) override;
+  void QueryStorageUsageAndQuota(
+      const blink::WebSecurityOrigin& storage_partition,
+      blink::WebStorageQuotaType,
+      blink::WebStorageQuotaCallbacks) override;
   blink::WebThread* CurrentThread() override;
   blink::BlameContext* GetTopLevelBlameContext() override;
   void RecordRappor(const char* metric,
diff --git a/content/renderer/service_worker/embedded_worker_instance_client_impl.cc b/content/renderer/service_worker/embedded_worker_instance_client_impl.cc
index 218f6ff..a5f666b8 100644
--- a/content/renderer/service_worker/embedded_worker_instance_client_impl.cc
+++ b/content/renderer/service_worker/embedded_worker_instance_client_impl.cc
@@ -9,6 +9,7 @@
 #include "base/memory/ptr_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "content/child/scoped_child_process_reference.h"
+#include "content/child/thread_safe_sender.h"
 #include "content/common/service_worker/embedded_worker_messages.h"
 #include "content/common/service_worker/service_worker_utils.h"
 #include "content/public/common/content_client.h"
@@ -76,7 +77,8 @@
       ServiceWorkerUtils::IsScriptStreamingEnabled() && installed_scripts_info,
       std::move(dispatcher_request), std::move(controller_request),
       std::move(service_worker_host), std::move(instance_host),
-      std::move(provider_info), std::move(temporal_self_));
+      std::move(provider_info), std::move(temporal_self_),
+      ChildThreadImpl::current()->thread_safe_sender(), io_thread_runner_);
   client->set_blink_initialized_time(blink_initialized_time_);
   client->set_start_worker_received_time(base::TimeTicks::Now());
   wrapper_ = StartWorkerContext(
diff --git a/content/renderer/service_worker/service_worker_context_client.cc b/content/renderer/service_worker/service_worker_context_client.cc
index 0ac2c32b..bc28bf28 100644
--- a/content/renderer/service_worker/service_worker_context_client.cc
+++ b/content/renderer/service_worker/service_worker_context_client.cc
@@ -61,6 +61,7 @@
 #include "storage/common/blob_storage/blob_handle.h"
 #include "third_party/WebKit/common/blob/blob.mojom.h"
 #include "third_party/WebKit/common/blob/blob_registry.mojom.h"
+#include "third_party/WebKit/common/message_port/message_port_channel.h"
 #include "third_party/WebKit/common/service_worker/service_worker_error_type.mojom.h"
 #include "third_party/WebKit/common/service_worker/service_worker_event_status.mojom.h"
 #include "third_party/WebKit/common/service_worker/service_worker_object.mojom.h"
@@ -623,14 +624,16 @@
     blink::mojom::ServiceWorkerHostAssociatedPtrInfo service_worker_host,
     mojom::EmbeddedWorkerInstanceHostAssociatedPtrInfo instance_host,
     mojom::ServiceWorkerProviderInfoForStartWorkerPtr provider_info,
-    std::unique_ptr<EmbeddedWorkerInstanceClientImpl> embedded_worker_client)
+    std::unique_ptr<EmbeddedWorkerInstanceClientImpl> embedded_worker_client,
+    scoped_refptr<ThreadSafeSender> sender,
+    scoped_refptr<base::SingleThreadTaskRunner> io_thread_task_runner)
     : embedded_worker_id_(embedded_worker_id),
       service_worker_version_id_(service_worker_version_id),
       service_worker_scope_(service_worker_scope),
       script_url_(script_url),
-      sender_(ChildThreadImpl::current()->thread_safe_sender()),
+      sender_(sender),
       main_thread_task_runner_(base::ThreadTaskRunnerHandle::Get()),
-      io_thread_task_runner_(ChildThreadImpl::current()->GetIOTaskRunner()),
+      io_thread_task_runner_(io_thread_task_runner),
       proxy_(nullptr),
       pending_dispatcher_request_(std::move(dispatcher_request)),
       pending_controller_request_(std::move(controller_request)),
@@ -643,7 +646,7 @@
   // Create a content::ServiceWorkerNetworkProvider for this data source so
   // we can observe its requests.
   pending_network_provider_ = ServiceWorkerNetworkProvider::CreateForController(
-      std::move(provider_info));
+      std::move(provider_info), sender_);
   provider_context_ = pending_network_provider_->context();
 
   TRACE_EVENT_NESTABLE_ASYNC_BEGIN1("ServiceWorker",
@@ -1840,4 +1843,9 @@
   return context_->weak_factory.GetWeakPtr();
 }
 
+// static
+void ServiceWorkerContextClient::ResetThreadSpecificInstanceForTesting() {
+  g_worker_client_tls.Pointer()->Set(nullptr);
+}
+
 }  // namespace content
diff --git a/content/renderer/service_worker/service_worker_context_client.h b/content/renderer/service_worker/service_worker_context_client.h
index c31234a4..6ea6432 100644
--- a/content/renderer/service_worker/service_worker_context_client.h
+++ b/content/renderer/service_worker/service_worker_context_client.h
@@ -75,8 +75,9 @@
 //
 // Unless otherwise noted (here or in base class documentation), all methods are
 // called on the worker thread.
-class ServiceWorkerContextClient : public blink::WebServiceWorkerContextClient,
-                                   public mojom::ServiceWorkerEventDispatcher {
+class CONTENT_EXPORT ServiceWorkerContextClient
+    : public blink::WebServiceWorkerContextClient,
+      public mojom::ServiceWorkerEventDispatcher {
  public:
   // Returns a thread-specific client instance.  This does NOT create a
   // new instance.
@@ -96,7 +97,9 @@
       blink::mojom::ServiceWorkerHostAssociatedPtrInfo service_worker_host,
       mojom::EmbeddedWorkerInstanceHostAssociatedPtrInfo instance_host,
       mojom::ServiceWorkerProviderInfoForStartWorkerPtr provider_info,
-      std::unique_ptr<EmbeddedWorkerInstanceClientImpl> embedded_worker_client);
+      std::unique_ptr<EmbeddedWorkerInstanceClientImpl> embedded_worker_client,
+      scoped_refptr<ThreadSafeSender> sender,
+      scoped_refptr<base::SingleThreadTaskRunner> io_thread_task_runner);
   ~ServiceWorkerContextClient() override;
 
   // Called on the main thread.
@@ -253,6 +256,7 @@
   struct WorkerContextData;
   class NavigationPreloadRequest;
   friend class ControllerServiceWorkerImpl;
+  friend class ServiceWorkerContextClientTest;
 
   // Get routing_id for sending message to the ServiceWorkerVersion
   // in the browser process.
@@ -381,6 +385,8 @@
 
   base::WeakPtr<ServiceWorkerContextClient> GetWeakPtr();
 
+  static void ResetThreadSpecificInstanceForTesting();
+
   const int embedded_worker_id_;
   const int64_t service_worker_version_id_;
   const GURL service_worker_scope_;
diff --git a/content/renderer/service_worker/service_worker_context_client_unittest.cc b/content/renderer/service_worker/service_worker_context_client_unittest.cc
new file mode 100644
index 0000000..78a44b77
--- /dev/null
+++ b/content/renderer/service_worker/service_worker_context_client_unittest.cc
@@ -0,0 +1,278 @@
+// 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/renderer/service_worker/service_worker_context_client.h"
+
+#include "base/message_loop/message_loop.h"
+#include "base/run_loop.h"
+#include "content/child/thread_safe_sender.h"
+#include "content/renderer/service_worker/embedded_worker_instance_client_impl.h"
+#include "content/renderer/service_worker/service_worker_dispatcher.h"
+#include "content/renderer/worker_thread_registry.h"
+#include "ipc/ipc_sync_message_filter.h"
+#include "ipc/ipc_test_sink.h"
+#include "mojo/public/cpp/bindings/associated_interface_ptr.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/WebKit/common/message_port/message_port_channel.h"
+#include "third_party/WebKit/common/service_worker/service_worker_registration.mojom.h"
+#include "third_party/WebKit/public/platform/WebDataConsumerHandle.h"
+#include "third_party/WebKit/public/platform/WebString.h"
+#include "third_party/WebKit/public/platform/WebURLResponse.h"
+#include "third_party/WebKit/public/platform/modules/background_fetch/WebBackgroundFetchSettledFetch.h"
+#include "third_party/WebKit/public/platform/modules/notifications/WebNotificationData.h"
+#include "third_party/WebKit/public/platform/modules/payments/WebPaymentRequestEventData.h"
+#include "third_party/WebKit/public/platform/modules/serviceworker/WebServiceWorkerClientsInfo.h"
+#include "third_party/WebKit/public/platform/modules/serviceworker/WebServiceWorkerError.h"
+#include "third_party/WebKit/public/platform/modules/serviceworker/WebServiceWorkerRequest.h"
+#include "third_party/WebKit/public/web/modules/serviceworker/WebServiceWorkerContextProxy.h"
+
+namespace content {
+
+namespace {
+
+// Pipes connected to the context client.
+struct ContextClientPipes {
+  // From the browser to ServiceWorkerContextClient.
+  mojom::ServiceWorkerEventDispatcherPtr event_dispatcher;
+  mojom::ControllerServiceWorkerPtr controller;
+  blink::mojom::ServiceWorkerRegistrationObjectAssociatedPtr registration;
+
+  // From ServiceWorkerContextClient to the browser.
+  blink::mojom::ServiceWorkerHostAssociatedRequest service_worker_host_request;
+  mojom::EmbeddedWorkerInstanceHostAssociatedRequest
+      embedded_worker_host_request;
+  blink::mojom::ServiceWorkerRegistrationObjectHostAssociatedRequest
+      registration_host_request;
+};
+
+class TestSender : public ThreadSafeSender {
+ public:
+  explicit TestSender(IPC::TestSink* ipc_sink)
+      : ThreadSafeSender(nullptr, nullptr), ipc_sink_(ipc_sink) {}
+
+  bool Send(IPC::Message* message) override { return ipc_sink_->Send(message); }
+
+ private:
+  ~TestSender() override = default;
+
+  IPC::TestSink* ipc_sink_;
+
+  DISALLOW_COPY_AND_ASSIGN(TestSender);
+};
+
+class MockWebServiceWorkerContextProxy
+    : public blink::WebServiceWorkerContextProxy {
+ public:
+  ~MockWebServiceWorkerContextProxy() override = default;
+
+  void SetRegistration(
+      std::unique_ptr<blink::WebServiceWorkerRegistration::Handle> handle)
+      override {
+    registration_handle_ = std::move(handle);
+  }
+  bool HasFetchEventHandler() override { return false; }
+
+  void DispatchActivateEvent(int event_id) override { NOTREACHED(); }
+  void DispatchBackgroundFetchAbortEvent(
+      int event_id,
+      const blink::WebString& developer_id) override {
+    NOTREACHED();
+  }
+  void DispatchBackgroundFetchClickEvent(int event_id,
+                                         const blink::WebString& developer_id,
+                                         BackgroundFetchState status) override {
+    NOTREACHED();
+  }
+  void DispatchBackgroundFetchFailEvent(
+      int event_id,
+      const blink::WebString& developer_id,
+      const blink::WebVector<blink::WebBackgroundFetchSettledFetch>& fetches)
+      override {
+    NOTREACHED();
+  }
+  void DispatchBackgroundFetchedEvent(
+      int event_id,
+      const blink::WebString& developer_id,
+      const blink::WebString& unique_id,
+      const blink::WebVector<blink::WebBackgroundFetchSettledFetch>& fetches)
+      override {
+    NOTREACHED();
+  }
+  void DispatchExtendableMessageEvent(
+      int event_id,
+      const blink::WebString& message,
+      const blink::WebSecurityOrigin& source_origin,
+      blink::WebVector<blink::MessagePortChannel>,
+      const blink::WebServiceWorkerClientInfo&) override {
+    NOTREACHED();
+  }
+  void DispatchExtendableMessageEvent(
+      int event_id,
+      const blink::WebString& message,
+      const blink::WebSecurityOrigin& source_origin,
+      blink::WebVector<blink::MessagePortChannel>,
+      std::unique_ptr<blink::WebServiceWorker::Handle>) override {
+    NOTREACHED();
+  }
+  void DispatchInstallEvent(int event_id) override { NOTREACHED(); }
+  void DispatchFetchEvent(int fetch_event_id,
+                          const blink::WebServiceWorkerRequest& web_request,
+                          bool navigation_preload_sent) override {
+    NOTREACHED();
+  }
+  void DispatchNotificationClickEvent(int event_id,
+                                      const blink::WebString& notification_id,
+                                      const blink::WebNotificationData&,
+                                      int action_index,
+                                      const blink::WebString& reply) override {
+    NOTREACHED();
+  }
+  void DispatchNotificationCloseEvent(
+      int event_id,
+      const blink::WebString& notification_id,
+      const blink::WebNotificationData&) override {
+    NOTREACHED();
+  }
+  void DispatchPushEvent(int event_id, const blink::WebString& data) override {
+    NOTREACHED();
+  }
+  void DispatchSyncEvent(int sync_event_id,
+                         const blink::WebString& tag,
+                         LastChanceOption) override {
+    NOTREACHED();
+  }
+  void DispatchAbortPaymentEvent(int event_id) override { NOTREACHED(); }
+  void DispatchCanMakePaymentEvent(
+      int event_id,
+      const blink::WebCanMakePaymentEventData&) override {
+    NOTREACHED();
+  }
+  void DispatchPaymentRequestEvent(
+      int event_id,
+      const blink::WebPaymentRequestEventData&) override {
+    NOTREACHED();
+  }
+  void OnNavigationPreloadResponse(
+      int fetch_event_id,
+      std::unique_ptr<blink::WebURLResponse>,
+      std::unique_ptr<blink::WebDataConsumerHandle>) override {
+    NOTREACHED();
+  }
+  void OnNavigationPreloadError(
+      int fetch_event_id,
+      std::unique_ptr<blink::WebServiceWorkerError>) override {
+    NOTREACHED();
+  }
+  void OnNavigationPreloadComplete(int fetch_event_id,
+                                   double completion_time,
+                                   int64_t encoded_data_length,
+                                   int64_t encoded_body_length,
+                                   int64_t decoded_body_length) override {
+    NOTREACHED();
+  }
+
+ private:
+  std::unique_ptr<blink::WebServiceWorkerRegistration::Handle>
+      registration_handle_;
+};
+
+}  // namespace
+
+class ServiceWorkerContextClientTest : public testing::Test {
+ public:
+  ServiceWorkerContextClientTest() = default;
+
+ protected:
+  void SetUp() override {
+    sender_ = base::MakeRefCounted<TestSender>(&ipc_sink_);
+    // Use this thread as the worker thread.
+    WorkerThreadRegistry::Instance()->DidStartCurrentWorkerThread();
+  }
+
+  void TearDown() override {
+    ServiceWorkerContextClient::ResetThreadSpecificInstanceForTesting();
+    ServiceWorkerDispatcher::GetOrCreateThreadSpecificInstance(
+        sender_, main_task_runner())
+        ->AllowReinstantiationForTesting();
+    // Unregister this thread from worker threads.
+    WorkerThreadRegistry::Instance()->WillStopCurrentWorkerThread();
+  }
+
+  // Creates an empty struct to initialize ServiceWorkerProviderContext.
+  mojom::ServiceWorkerProviderInfoForStartWorkerPtr CreateProviderInfo(
+      blink::mojom::ServiceWorkerRegistrationObjectHostAssociatedRequest*
+          out_request,
+      blink::mojom::ServiceWorkerRegistrationObjectAssociatedPtr* out_ptr) {
+    auto info = mojom::ServiceWorkerProviderInfoForStartWorker::New();
+    info->registration =
+        blink::mojom::ServiceWorkerRegistrationObjectInfo::New();
+    blink::mojom::ServiceWorkerRegistrationObjectHostAssociatedPtr host_ptr;
+    *out_request = mojo::MakeRequestAssociatedWithDedicatedPipe(&host_ptr);
+    info->registration->host_ptr_info = host_ptr.PassInterface();
+    info->registration->request =
+        mojo::MakeRequestAssociatedWithDedicatedPipe(out_ptr);
+
+    info->registration->installing =
+        blink::mojom::ServiceWorkerObjectInfo::New();
+    info->registration->registration_id = 100;  // dummy
+    info->registration->waiting = blink::mojom::ServiceWorkerObjectInfo::New();
+    info->registration->active = blink::mojom::ServiceWorkerObjectInfo::New();
+    return info;
+  }
+
+  // Creates an ContextClient, whose pipes are connected to |out_pipes|.
+  std::unique_ptr<ServiceWorkerContextClient> CreateContextClient(
+      ContextClientPipes* out_pipes) {
+    auto event_dispatcher_request =
+        mojo::MakeRequest(&out_pipes->event_dispatcher);
+    auto controller_request = mojo::MakeRequest(&out_pipes->controller);
+    blink::mojom::ServiceWorkerHostAssociatedPtr sw_host_ptr;
+    out_pipes->service_worker_host_request =
+        mojo::MakeRequestAssociatedWithDedicatedPipe(&sw_host_ptr);
+    mojom::EmbeddedWorkerInstanceHostAssociatedPtr embedded_worker_host_ptr;
+    out_pipes->embedded_worker_host_request =
+        mojo::MakeRequestAssociatedWithDedicatedPipe(&embedded_worker_host_ptr);
+    EXPECT_TRUE(sender_);
+    return std::make_unique<ServiceWorkerContextClient>(
+        1 /* embeded_worker_id */, 1 /* service_worker_version_id */,
+        GURL("https://example.com") /* scope */,
+        GURL("https://example.com/SW.js") /* script_URL */,
+        false /* is_script_streaming */, std::move(event_dispatcher_request),
+        std::move(controller_request), sw_host_ptr.PassInterface(),
+        embedded_worker_host_ptr.PassInterface(),
+        CreateProviderInfo(&out_pipes->registration_host_request,
+                           &out_pipes->registration),
+        nullptr /* embedded_worker_client */, sender_, io_task_runner());
+  }
+
+ private:
+  scoped_refptr<base::SingleThreadTaskRunner> main_task_runner() {
+    // Use this thread as the main thread.
+    return message_loop_.task_runner();
+  }
+
+  scoped_refptr<base::SingleThreadTaskRunner> io_task_runner() {
+    // Use this thread as the IO thread.
+    return message_loop_.task_runner();
+  }
+
+  base::MessageLoop message_loop_;
+  IPC::TestSink ipc_sink_;
+  scoped_refptr<TestSender> sender_;
+};
+
+TEST_F(ServiceWorkerContextClientTest, Ping) {
+  ContextClientPipes pipes;
+  std::unique_ptr<ServiceWorkerContextClient> context_client =
+      CreateContextClient(&pipes);
+  MockWebServiceWorkerContextProxy mock_proxy;
+  context_client->WorkerContextStarted(&mock_proxy);
+
+  // Ping() should invoke the passed callback.
+  base::RunLoop loop;
+  pipes.event_dispatcher->Ping(loop.QuitClosure());
+  loop.Run();
+}
+
+}  // namespace content
diff --git a/content/renderer/service_worker/service_worker_dispatcher.cc b/content/renderer/service_worker/service_worker_dispatcher.cc
index d3432cd..d4ce0f10 100644
--- a/content/renderer/service_worker/service_worker_dispatcher.cc
+++ b/content/renderer/service_worker/service_worker_dispatcher.cc
@@ -43,14 +43,18 @@
 }  // namespace
 
 ServiceWorkerDispatcher::ServiceWorkerDispatcher(
-    ThreadSafeSender* thread_safe_sender,
-    base::SingleThreadTaskRunner* main_thread_task_runner)
-    : thread_safe_sender_(thread_safe_sender),
-      main_thread_task_runner_(main_thread_task_runner) {
+    scoped_refptr<ThreadSafeSender> thread_safe_sender,
+    scoped_refptr<base::SingleThreadTaskRunner> main_thread_task_runner)
+    : thread_safe_sender_(std::move(thread_safe_sender)),
+      main_thread_task_runner_(std::move(main_thread_task_runner)) {
   g_dispatcher_tls.Pointer()->Set(static_cast<void*>(this));
 }
 
 ServiceWorkerDispatcher::~ServiceWorkerDispatcher() {
+  if (allow_reinstantiation_) {
+    g_dispatcher_tls.Pointer()->Set(nullptr);
+    return;
+  }
   g_dispatcher_tls.Pointer()->Set(kHasBeenDeleted);
 }
 
@@ -70,8 +74,8 @@
 
 ServiceWorkerDispatcher*
 ServiceWorkerDispatcher::GetOrCreateThreadSpecificInstance(
-    ThreadSafeSender* thread_safe_sender,
-    base::SingleThreadTaskRunner* main_thread_task_runner) {
+    scoped_refptr<ThreadSafeSender> thread_safe_sender,
+    scoped_refptr<base::SingleThreadTaskRunner> main_thread_task_runner) {
   if (g_dispatcher_tls.Pointer()->Get() == kHasBeenDeleted) {
     NOTREACHED() << "Re-instantiating TLS ServiceWorkerDispatcher.";
     g_dispatcher_tls.Pointer()->Set(nullptr);
@@ -80,8 +84,8 @@
     return static_cast<ServiceWorkerDispatcher*>(
         g_dispatcher_tls.Pointer()->Get());
 
-  ServiceWorkerDispatcher* dispatcher =
-      new ServiceWorkerDispatcher(thread_safe_sender, main_thread_task_runner);
+  ServiceWorkerDispatcher* dispatcher = new ServiceWorkerDispatcher(
+      std::move(thread_safe_sender), std::move(main_thread_task_runner));
   if (WorkerThread::GetCurrentId())
     WorkerThread::AddObserver(dispatcher);
   return dispatcher;
@@ -94,6 +98,10 @@
       g_dispatcher_tls.Pointer()->Get());
 }
 
+void ServiceWorkerDispatcher::AllowReinstantiationForTesting() {
+  allow_reinstantiation_ = true;
+}
+
 void ServiceWorkerDispatcher::WillStopCurrentWorkerThread() {
   delete this;
 }
diff --git a/content/renderer/service_worker/service_worker_dispatcher.h b/content/renderer/service_worker/service_worker_dispatcher.h
index 11c7488..c5e1559 100644
--- a/content/renderer/service_worker/service_worker_dispatcher.h
+++ b/content/renderer/service_worker/service_worker_dispatcher.h
@@ -47,8 +47,8 @@
 class CONTENT_EXPORT ServiceWorkerDispatcher : public WorkerThread::Observer {
  public:
   ServiceWorkerDispatcher(
-      ThreadSafeSender* thread_safe_sender,
-      base::SingleThreadTaskRunner* main_thread_task_runner);
+      scoped_refptr<ThreadSafeSender> thread_safe_sender,
+      scoped_refptr<base::SingleThreadTaskRunner> main_thread_task_runner);
   ~ServiceWorkerDispatcher() override;
 
   void OnMessageReceived(const IPC::Message& msg);
@@ -59,8 +59,8 @@
       std::unique_ptr<ServiceWorkerHandleReference> handle_ref);
 
   static ServiceWorkerDispatcher* GetOrCreateThreadSpecificInstance(
-      ThreadSafeSender* thread_safe_sender,
-      base::SingleThreadTaskRunner* main_thread_task_runner);
+      scoped_refptr<ThreadSafeSender> thread_safe_sender,
+      scoped_refptr<base::SingleThreadTaskRunner> main_thread_task_runner);
 
   // Unlike GetOrCreateThreadSpecificInstance() this doesn't create a new
   // instance if thread-local instance doesn't exist.
@@ -77,9 +77,12 @@
  private:
   using WorkerObjectMap = std::map<int, WebServiceWorkerImpl*>;
 
+  friend class ServiceWorkerContextClientTest;
   friend class ServiceWorkerDispatcherTest;
   friend class WebServiceWorkerImpl;
 
+  void AllowReinstantiationForTesting();
+
   // WorkerThread::Observer implementation.
   void WillStopCurrentWorkerThread() override;
 
@@ -91,6 +94,10 @@
   void AddServiceWorker(int handle_id, WebServiceWorkerImpl* worker);
   void RemoveServiceWorker(int handle_id);
 
+  // True if another dispatcher is allowed to be created on the same thread
+  // after this instance is destructed.
+  bool allow_reinstantiation_ = false;
+
   WorkerObjectMap service_workers_;
 
   scoped_refptr<ThreadSafeSender> thread_safe_sender_;
diff --git a/content/renderer/service_worker/service_worker_network_provider.cc b/content/renderer/service_worker/service_worker_network_provider.cc
index 588ec2c..08e94744 100644
--- a/content/renderer/service_worker/service_worker_network_provider.cc
+++ b/content/renderer/service_worker/service_worker_network_provider.cc
@@ -219,8 +219,10 @@
 // static
 std::unique_ptr<ServiceWorkerNetworkProvider>
 ServiceWorkerNetworkProvider::CreateForController(
-    mojom::ServiceWorkerProviderInfoForStartWorkerPtr info) {
-  return base::WrapUnique(new ServiceWorkerNetworkProvider(std::move(info)));
+    mojom::ServiceWorkerProviderInfoForStartWorkerPtr info,
+    scoped_refptr<ThreadSafeSender> sender) {
+  return base::WrapUnique(
+      new ServiceWorkerNetworkProvider(std::move(info), std::move(sender)));
 }
 
 // static
@@ -301,12 +303,12 @@
 
 // Constructor for service worker execution contexts.
 ServiceWorkerNetworkProvider::ServiceWorkerNetworkProvider(
-    mojom::ServiceWorkerProviderInfoForStartWorkerPtr info) {
+    mojom::ServiceWorkerProviderInfoForStartWorkerPtr info,
+    scoped_refptr<ThreadSafeSender> sender) {
   // Initialize the provider context with info for
   // ServiceWorkerGlobalScope#registration.
-  ThreadSafeSender* sender = ChildThreadImpl::current()->thread_safe_sender();
   ServiceWorkerDispatcher::GetOrCreateThreadSpecificInstance(
-      sender, base::ThreadTaskRunnerHandle::Get().get());
+      sender, base::ThreadTaskRunnerHandle::Get());
   // TODO(kinuko): Split ServiceWorkerProviderContext ctor for
   // controller and controllee.
   context_ = base::MakeRefCounted<ServiceWorkerProviderContext>(
diff --git a/content/renderer/service_worker/service_worker_network_provider.h b/content/renderer/service_worker/service_worker_network_provider.h
index e52ab07a..9cffa225 100644
--- a/content/renderer/service_worker/service_worker_network_provider.h
+++ b/content/renderer/service_worker/service_worker_network_provider.h
@@ -33,6 +33,7 @@
 struct RequestNavigationParams;
 class ServiceWorkerProviderContext;
 class ChildURLLoaderFactoryGetter;
+class ThreadSafeSender;
 
 // ServiceWorkerNetworkProvider enables the browser process to recognize
 // resource requests from Blink that should be handled by service worker
@@ -79,7 +80,8 @@
   // Creates a ServiceWorkerNetworkProvider for a "controller" (i.e.
   // a service worker execution context).
   static std::unique_ptr<ServiceWorkerNetworkProvider> CreateForController(
-      mojom::ServiceWorkerProviderInfoForStartWorkerPtr info);
+      mojom::ServiceWorkerProviderInfoForStartWorkerPtr info,
+      scoped_refptr<ThreadSafeSender> sender);
 
   // Valid only for WebServiceWorkerNetworkProvider created by
   // CreateForNavigation.
@@ -122,7 +124,8 @@
 
   // This is for controllers, used in CreateForController.
   explicit ServiceWorkerNetworkProvider(
-      mojom::ServiceWorkerProviderInfoForStartWorkerPtr info);
+      mojom::ServiceWorkerProviderInfoForStartWorkerPtr info,
+      scoped_refptr<ThreadSafeSender> sender);
 
   scoped_refptr<ServiceWorkerProviderContext> context_;
   mojom::ServiceWorkerDispatcherHostAssociatedPtr dispatcher_host_;
diff --git a/content/shell/BUILD.gn b/content/shell/BUILD.gn
index 5727bcf..0d5e28b 100644
--- a/content/shell/BUILD.gn
+++ b/content/shell/BUILD.gn
@@ -259,7 +259,6 @@
     "//media",
     "//media/capture",
     "//media/mojo:features",
-    "//mojo/edk/js",
     "//net",
     "//net:net_resources",
     "//net:test_support",
@@ -742,7 +741,9 @@
     # use rpath-based loading.
     # TODO(rsesek): After GYP is gone, re-write content_shell_main to be like
     # chrome_main and use dlopen() instead of a linked framework.
-    ldflags = [ "-Wl,-install_name,@rpath/Frameworks/$output_name.framework/$output_name" ]
+    ldflags = [
+      "-Wl,-install_name,@rpath/Frameworks/$output_name.framework/$output_name",
+    ]
 
     if (is_component_build) {
       # Set up the rpath for the framework so that it can find dylibs in the
diff --git a/content/shell/test_runner/web_frame_test_client.cc b/content/shell/test_runner/web_frame_test_client.cc
index d3a4a7f..219c33a 100644
--- a/content/shell/test_runner/web_frame_test_client.cc
+++ b/content/shell/test_runner/web_frame_test_client.cc
@@ -443,7 +443,8 @@
 
 void WebFrameTestClient::DidCommitProvisionalLoad(
     const blink::WebHistoryItem& history_item,
-    blink::WebHistoryCommitType history_type) {
+    blink::WebHistoryCommitType history_type,
+    blink::WebGlobalObjectReusePolicy) {
   if (test_runner()->shouldDumpFrameLoadCallbacks()) {
     PrintFrameDescription(delegate_, web_frame_test_proxy_base_->web_frame());
     delegate_->PrintMessage(" - didCommitLoadForFrame\n");
diff --git a/content/shell/test_runner/web_frame_test_client.h b/content/shell/test_runner/web_frame_test_client.h
index 319c4df..f0b1eac 100644
--- a/content/shell/test_runner/web_frame_test_client.h
+++ b/content/shell/test_runner/web_frame_test_client.h
@@ -62,9 +62,9 @@
   void DidReceiveServerRedirectForProvisionalLoad() override;
   void DidFailProvisionalLoad(const blink::WebURLError& error,
                               blink::WebHistoryCommitType commit_type) override;
-  void DidCommitProvisionalLoad(
-      const blink::WebHistoryItem& history_item,
-      blink::WebHistoryCommitType history_type) override;
+  void DidCommitProvisionalLoad(const blink::WebHistoryItem& history_item,
+                                blink::WebHistoryCommitType history_type,
+                                blink::WebGlobalObjectReusePolicy) override;
   void DidReceiveTitle(const blink::WebString& title,
                        blink::WebTextDirection direction) override;
   void DidChangeIcon(blink::WebIconURL::Type icon_type) override;
diff --git a/content/shell/test_runner/web_frame_test_proxy.h b/content/shell/test_runner/web_frame_test_proxy.h
index 7848300..4a82dd8a 100644
--- a/content/shell/test_runner/web_frame_test_proxy.h
+++ b/content/shell/test_runner/web_frame_test_proxy.h
@@ -118,9 +118,12 @@
 
   void DidCommitProvisionalLoad(
       const blink::WebHistoryItem& item,
-      blink::WebHistoryCommitType commit_type) override {
-    test_client()->DidCommitProvisionalLoad(item, commit_type);
-    Base::DidCommitProvisionalLoad(item, commit_type);
+      blink::WebHistoryCommitType commit_type,
+      blink::WebGlobalObjectReusePolicy global_object_reuse_policy) override {
+    test_client()->DidCommitProvisionalLoad(item, commit_type,
+                                            global_object_reuse_policy);
+    Base::DidCommitProvisionalLoad(item, commit_type,
+                                   global_object_reuse_policy);
   }
 
   void DidReceiveTitle(const blink::WebString& title,
diff --git a/content/test/BUILD.gn b/content/test/BUILD.gn
index c07b4b1..036c780 100644
--- a/content/test/BUILD.gn
+++ b/content/test/BUILD.gn
@@ -530,8 +530,12 @@
 mojom("content_test_mojo_bindings") {
   sources = [
     "../public/test/test_service.mojom",
+    "frame_host_test_interface.mojom",
     "test_browser_associated_interfaces.mojom",
   ]
+  public_deps = [
+    "//url/mojo:url_mojom_gurl",
+  ]
 }
 
 mojom("web_ui_test_mojo_bindings") {
@@ -861,7 +865,6 @@
     "//media:test_support",
     "//mojo/edk/system",
     "//mojo/public/cpp/bindings",
-    "//mojo/public/js",
     "//net:test_support",
     "//ppapi/features",
     "//services/catalog:lib",
@@ -1570,6 +1573,7 @@
     "../renderer/render_thread_impl_unittest.cc",
     "../renderer/render_widget_unittest.cc",
     "../renderer/scheduler/resource_dispatch_throttler_unittest.cc",
+    "../renderer/service_worker/service_worker_context_client_unittest.cc",
     "../renderer/service_worker/service_worker_dispatcher_unittest.cc",
     "../renderer/service_worker/service_worker_provider_context_unittest.cc",
     "../renderer/service_worker/service_worker_subresource_loader_unittest.cc",
@@ -1880,9 +1884,7 @@
   # Screen capture unit tests.
   if (is_linux || is_mac || is_win) {
     deps += [ "//third_party/libyuv" ]
-    sources += [
-      "../browser/media/capture/web_contents_video_capture_device_unittest.cc",
-    ]
+    sources += [ "../browser/media/capture/web_contents_video_capture_device_unittest.cc" ]
     if (use_aura) {
       sources += [ "../browser/media/capture/cursor_renderer_aura_unittest.cc" ]
     }
@@ -1955,11 +1957,17 @@
       "../browser/speech/endpointer/endpointer_unittest.cc",
       "../browser/speech/speech_recognition_engine_unittest.cc",
       "../browser/speech/speech_recognizer_impl_unittest.cc",
-      "../browser/webauth/authenticator_impl_unittest.cc",
     ]
     deps += [ "//third_party/libvpx" ]
   }
 
+  # HID support is not available without udev.
+  is_linux_without_udev = is_linux && !use_udev
+  if (!is_linux_without_udev && !is_android) {
+    sources += [ "../browser/webauth/authenticator_impl_unittest.cc" ]
+    deps += [ "//device/u2f:test_support" ]
+  }
+
   if (use_aura) {
     deps += [
       "//ui/aura:test_support",
diff --git a/content/test/did_commit_provisional_load_interceptor.cc b/content/test/did_commit_provisional_load_interceptor.cc
index 46bd05a..964b938 100644
--- a/content/test/did_commit_provisional_load_interceptor.cc
+++ b/content/test/did_commit_provisional_load_interceptor.cc
@@ -38,10 +38,13 @@
   // mojom::FrameHostInterceptorForTesting:
   FrameHost* GetForwardingInterface() override { return impl_; }
   void DidCommitProvisionalLoad(
-      std::unique_ptr<::FrameHostMsg_DidCommitProvisionalLoad_Params> params)
-      override {
-    interceptor_->WillDispatchDidCommitProvisionalLoad(rfhi_, params.get());
-    GetForwardingInterface()->DidCommitProvisionalLoad(std::move(params));
+      std::unique_ptr<::FrameHostMsg_DidCommitProvisionalLoad_Params> params,
+      ::service_manager::mojom::InterfaceProviderRequest
+          interface_provider_request) override {
+    interceptor_->WillDispatchDidCommitProvisionalLoad(
+        rfhi_, params.get(), &interface_provider_request);
+    GetForwardingInterface()->DidCommitProvisionalLoad(
+        std::move(params), std::move(interface_provider_request));
   }
 
  private:
@@ -56,8 +59,10 @@
 DidCommitProvisionalLoadInterceptor::DidCommitProvisionalLoadInterceptor(
     WebContents* web_contents)
     : WebContentsObserver(web_contents) {
-  for (auto* rfh : web_contents->GetAllFrames())
-    RenderFrameCreated(rfh);
+  for (auto* rfh : web_contents->GetAllFrames()) {
+    if (rfh->IsRenderFrameLive())
+      RenderFrameCreated(rfh);
+  }
 }
 
 DidCommitProvisionalLoadInterceptor::~DidCommitProvisionalLoadInterceptor() =
diff --git a/content/test/did_commit_provisional_load_interceptor.h b/content/test/did_commit_provisional_load_interceptor.h
index 2a046247..26270f5 100644
--- a/content/test/did_commit_provisional_load_interceptor.h
+++ b/content/test/did_commit_provisional_load_interceptor.h
@@ -27,11 +27,13 @@
   explicit DidCommitProvisionalLoadInterceptor(WebContents* web_contents);
   ~DidCommitProvisionalLoadInterceptor() override;
 
-  // Called just before DidCommitProvisionalLoad with |params| would be
-  // dispatched to |render_frame_host|.
+  // Called just before DidCommitProvisionalLoad with |params| and
+  // |interface_provider_request| would be dispatched to |render_frame_host|.
   virtual void WillDispatchDidCommitProvisionalLoad(
       RenderFrameHost* render_frame_host,
-      ::FrameHostMsg_DidCommitProvisionalLoad_Params* params) = 0;
+      ::FrameHostMsg_DidCommitProvisionalLoad_Params* params,
+      service_manager::mojom::InterfaceProviderRequest*
+          interface_provider_request) = 0;
 
  private:
   class FrameAgent;
diff --git a/content/test/frame_host_test_interface.mojom b/content/test/frame_host_test_interface.mojom
new file mode 100644
index 0000000..68c09eb
--- /dev/null
+++ b/content/test/frame_host_test_interface.mojom
@@ -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.
+
+module content.mojom;
+
+import "url/mojo/url.mojom";
+
+// Test interface used in RenderFrame and RenderFrameHost tests to exercise
+// requesting document-scoped interfaces from the RenderFrameHost through
+// the InterfaceProvider interface.
+//
+// The `Ping` method is invoked by clients immediately after making the
+// FrameHostTestInterfaceRequest, so as to annotate where the request
+// originates from. This allows verification that the request was delivered /
+// not delivered to a certain InterfaceProvider implementation.
+interface FrameHostTestInterface {
+  Ping(url.mojom.Url source_url, string source_event);
+};
diff --git a/content/test/test_render_frame.cc b/content/test/test_render_frame.cc
index 424e39c..fe25617f 100644
--- a/content/test/test_render_frame.cc
+++ b/content/test/test_render_frame.cc
@@ -4,6 +4,11 @@
 
 #include "content/test/test_render_frame.h"
 
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "base/debug/stack_trace.h"
 #include "base/memory/ptr_util.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "content/common/frame_messages.h"
@@ -28,6 +33,21 @@
     return std::move(last_commit_params_);
   }
 
+  service_manager::mojom::InterfaceProviderRequest
+  TakeLastInterfaceProviderRequest() {
+    return std::move(last_interface_provider_request_);
+  }
+
+  // Holds on to the request end of the InterfaceProvider interface whose client
+  // end is bound to the corresponding RenderFrame's |remote_interfaces_| to
+  // facilitate retrieving the most recent |interface_provider_request| in
+  // tests.
+  void PassLastInterfaceProviderRequest(
+      service_manager::mojom::InterfaceProviderRequest
+          interface_provider_request) {
+    last_interface_provider_request_ = std::move(interface_provider_request);
+  }
+
  protected:
   // mojom::FrameHost:
   void CreateNewWindow(mojom::CreateNewWindowParamsPtr,
@@ -49,9 +69,10 @@
   void IssueKeepAliveHandle(mojom::KeepAliveHandleRequest request) override {}
 
   void DidCommitProvisionalLoad(
-      std::unique_ptr<FrameHostMsg_DidCommitProvisionalLoad_Params> params)
-      override {
+      std::unique_ptr<FrameHostMsg_DidCommitProvisionalLoad_Params> params,
+      service_manager::mojom::InterfaceProviderRequest request) override {
     last_commit_params_ = std::move(params);
+    last_interface_provider_request_ = std::move(request);
   }
 
   void BeginNavigation(const CommonNavigationParams& common_params,
@@ -64,9 +85,21 @@
                                   const std::string& ip,
                                   uint32_t cert_status) override {}
 
+  void DidChangeName(const std::string& name,
+                     const std::string& unique_name) override {}
+
+  void EnforceInsecureRequestPolicy(
+      blink::WebInsecureRequestPolicy policy) override {}
+
+  void DidSetFramePolicyHeaders(
+      blink::WebSandboxFlags sandbox_flags,
+      const blink::ParsedFeaturePolicy& parsed_header) override {}
+
  private:
   std::unique_ptr<FrameHostMsg_DidCommitProvisionalLoad_Params>
       last_commit_params_;
+  service_manager::mojom::InterfaceProviderRequest
+      last_interface_provider_request_;
 
   DISALLOW_COPY_AND_ASSIGN(MockFrameHost);
 };
@@ -79,10 +112,26 @@
 
 TestRenderFrame::TestRenderFrame(RenderFrameImpl::CreateParams params)
     : RenderFrameImpl(std::move(params)),
-      mock_frame_host_(std::make_unique<MockFrameHost>()) {}
+      mock_frame_host_(std::make_unique<MockFrameHost>()) {
+  MockRenderThread* mock_render_thread =
+      static_cast<MockRenderThread*>(RenderThread::Get());
+  mock_frame_host_->PassLastInterfaceProviderRequest(
+      mock_render_thread->TakeInitialInterfaceProviderRequestForFrame(
+          params.routing_id));
+}
 
 TestRenderFrame::~TestRenderFrame() {}
 
+void TestRenderFrame::SetURLOverrideForNextWebURLRequest(const GURL& url) {
+  next_request_url_override_ = url;
+}
+
+void TestRenderFrame::WillSendRequest(blink::WebURLRequest& request) {
+  if (next_request_url_override_.has_value())
+    request.SetURL(std::move(next_request_url_override_).value());
+  RenderFrameImpl::WillSendRequest(request);
+}
+
 void TestRenderFrame::Navigate(const CommonNavigationParams& common_params,
                                const StartNavigationParams& start_params,
                                const RequestNavigationParams& request_params) {
@@ -139,7 +188,8 @@
     const blink::WebFrameClient::NavigationPolicyInfo& info) {
   if (IsBrowserSideNavigationEnabled() &&
       info.url_request.CheckForBrowserSideNavigation() &&
-      GetWebFrame()->Parent() && info.form.IsNull()) {
+      ((GetWebFrame()->Parent() && info.form.IsNull()) ||
+       next_request_url_override_.has_value())) {
     // RenderViewTest::LoadHTML already disables PlzNavigate for the main frame
     // requests. However if the loaded html has a subframe, the WebURLRequest
     // will be created inside Blink and it won't have this flag set.
@@ -153,6 +203,11 @@
   return mock_frame_host_->TakeLastCommitParams();
 }
 
+service_manager::mojom::InterfaceProviderRequest
+TestRenderFrame::TakeLastInterfaceProviderRequest() {
+  return mock_frame_host_->TakeLastInterfaceProviderRequest();
+}
+
 mojom::FrameHost* TestRenderFrame::GetFrameHost() {
   // Need to mock this interface directly without going through a binding,
   // otherwise calling its sync methods could lead to a deadlock.
diff --git a/content/test/test_render_frame.h b/content/test/test_render_frame.h
index 1a263529..c6bd440b 100644
--- a/content/test/test_render_frame.h
+++ b/content/test/test_render_frame.h
@@ -8,6 +8,7 @@
 #include <memory>
 
 #include "base/macros.h"
+#include "base/optional.h"
 #include "content/common/frame.mojom.h"
 #include "content/renderer/render_frame_impl.h"
 #include "mojo/public/cpp/bindings/scoped_interface_endpoint_handle.h"
@@ -34,6 +35,12 @@
     return current_history_item_;
   }
 
+  // Overrides the URL in the next WebURLRequest originating from the frame.
+  // This will also short-circuit browser-side navigation for main resource
+  // loads, FrameLoader will always carry out the load renderer-side.
+  void SetURLOverrideForNextWebURLRequest(const GURL& url);
+
+  void WillSendRequest(blink::WebURLRequest& request) override;
   void Navigate(const CommonNavigationParams& common_params,
                 const StartNavigationParams& start_params,
                 const RequestNavigationParams& request_params);
@@ -57,12 +64,16 @@
   std::unique_ptr<FrameHostMsg_DidCommitProvisionalLoad_Params>
   TakeLastCommitParams();
 
+  service_manager::mojom::InterfaceProviderRequest
+  TakeLastInterfaceProviderRequest();
+
  private:
   explicit TestRenderFrame(RenderFrameImpl::CreateParams params);
 
   mojom::FrameHost* GetFrameHost() override;
 
   std::unique_ptr<MockFrameHost> mock_frame_host_;
+  base::Optional<GURL> next_request_url_override_;
 
   DISALLOW_COPY_AND_ASSIGN(TestRenderFrame);
 };
diff --git a/content/test/test_render_frame_host.cc b/content/test/test_render_frame_host.cc
index e5d60501..d34a542 100644
--- a/content/test/test_render_frame_host.cc
+++ b/content/test/test_render_frame_host.cc
@@ -318,7 +318,7 @@
   header[0].feature = feature;
   header[0].matches_all_origins = false;
   header[0].origins = whitelist;
-  OnDidSetFramePolicyHeaders(blink::WebSandboxFlags::kNone, header);
+  DidSetFramePolicyHeaders(blink::WebSandboxFlags::kNone, header);
 }
 
 const std::vector<std::string>& TestRenderFrameHost::GetConsoleMessages() {
@@ -450,15 +450,28 @@
 
 void TestRenderFrameHost::SendNavigateWithParams(
     FrameHostMsg_DidCommitProvisionalLoad_Params* params) {
+  service_manager::mojom::InterfaceProviderPtr interface_provider;
+  service_manager::mojom::InterfaceProviderRequest interface_provider_request;
+  if (!params->was_within_same_document)
+    interface_provider_request = mojo::MakeRequest(&interface_provider);
+
+  SendNavigateWithParamsAndInterfaceProvider(
+      params, std::move(interface_provider_request));
+}
+
+void TestRenderFrameHost::SendNavigateWithParamsAndInterfaceProvider(
+    FrameHostMsg_DidCommitProvisionalLoad_Params* params,
+    service_manager::mojom::InterfaceProviderRequest request) {
   if (navigation_handle()) {
     scoped_refptr<net::HttpResponseHeaders> response_headers =
         new net::HttpResponseHeaders(std::string());
-    response_headers->AddHeader(
-        std::string("Content-Type: ") + contents_mime_type_);
+    response_headers->AddHeader(std::string("Content-Type: ") +
+                                contents_mime_type_);
     navigation_handle()->set_response_headers_for_testing(response_headers);
   }
   DidCommitProvisionalLoad(
-      std::make_unique<FrameHostMsg_DidCommitProvisionalLoad_Params>(*params));
+      std::make_unique<FrameHostMsg_DidCommitProvisionalLoad_Params>(*params),
+      std::move(request));
   last_commit_was_error_page_ = params->url_is_unreachable;
 }
 
@@ -495,7 +508,7 @@
 
 void TestRenderFrameHost::DidEnforceInsecureRequestPolicy(
     blink::WebInsecureRequestPolicy policy) {
-  OnEnforceInsecureRequestPolicy(policy);
+  EnforceInsecureRequestPolicy(policy);
 }
 
 void TestRenderFrameHost::PrepareForCommit() {
@@ -594,7 +607,7 @@
 void TestRenderFrameHost::SendFramePolicy(
     blink::WebSandboxFlags sandbox_flags,
     const blink::ParsedFeaturePolicy& declared_policy) {
-  OnDidSetFramePolicyHeaders(sandbox_flags, declared_policy);
+  DidSetFramePolicyHeaders(sandbox_flags, declared_policy);
 }
 
 mojom::FrameNavigationControl* TestRenderFrameHost::GetNavigationControl() {
diff --git a/content/test/test_render_frame_host.h b/content/test/test_render_frame_host.h
index ef6570ee..7a6715f46 100644
--- a/content/test/test_render_frame_host.h
+++ b/content/test/test_render_frame_host.h
@@ -100,6 +100,9 @@
       const ModificationCallback& callback);
   void SendNavigateWithParams(
       FrameHostMsg_DidCommitProvisionalLoad_Params* params);
+  void SendNavigateWithParamsAndInterfaceProvider(
+      FrameHostMsg_DidCommitProvisionalLoad_Params* params,
+      service_manager::mojom::InterfaceProviderRequest request);
 
   // Simulates a navigation to |url| failing with the error code |error_code|.
   // DEPRECATED: use NavigationSimulator instead.
@@ -181,6 +184,9 @@
     return last_commit_was_error_page_;
   }
 
+  // Exposes the interface registry to be manipulated for testing.
+  service_manager::BinderRegistry& binder_registry() { return *registry_; }
+
   // Returns a pending InterfaceProvider request that is safe to bind to an
   // implementation, but will never receive any interface requests.
   static service_manager::mojom::InterfaceProviderRequest
diff --git a/device/BUILD.gn b/device/BUILD.gn
index e2b54e4..1144edb 100644
--- a/device/BUILD.gn
+++ b/device/BUILD.gn
@@ -64,6 +64,7 @@
     "bluetooth/test/test_bluetooth_local_gatt_service_delegate.cc",
     "bluetooth/test/test_bluetooth_local_gatt_service_delegate.h",
     "bluetooth/uribeacon/uri_encoder_unittest.cc",
+    "gamepad/abstract_haptic_gamepad_unittest.cc",
     "gamepad/gamepad_provider_unittest.cc",
     "gamepad/gamepad_service_unittest.cc",
     "gamepad/public/interfaces/gamepad_struct_traits_unittest.cc",
@@ -115,12 +116,11 @@
   # Linux, requires udev.
   if (!is_linux_without_udev && !is_android) {
     sources += [
-      "u2f/fake_hid_impl_for_testing.cc",
-      "u2f/fake_hid_impl_for_testing.h",
       "u2f/u2f_hid_device_unittest.cc",
       "u2f/u2f_hid_discovery_unittest.cc",
     ]
     deps += [
+      "//device/u2f:test_support",
       "//services/device/public/cpp/hid",
       "//services/device/public/interfaces",
       "//services/service_manager/public/cpp",
@@ -280,7 +280,9 @@
 }
 
 if (is_android) {
-  bluetooth_java_sources_needing_jni = [ "bluetooth/test/android/java/src/org/chromium/device/bluetooth/Fakes.java" ]
+  bluetooth_java_sources_needing_jni = [
+    "bluetooth/test/android/java/src/org/chromium/device/bluetooth/Fakes.java",
+  ]
 
   generate_jni("bluetooth_test_jni_headers") {
     sources = bluetooth_java_sources_needing_jni
diff --git a/device/gamepad/BUILD.gn b/device/gamepad/BUILD.gn
index 2f313f9..f02d81b 100644
--- a/device/gamepad/BUILD.gn
+++ b/device/gamepad/BUILD.gn
@@ -13,6 +13,8 @@
   output_name = "device_gamepad"
 
   sources = [
+    "abstract_haptic_gamepad.cc",
+    "abstract_haptic_gamepad.h",
     "game_controller_data_fetcher_mac.h",
     "game_controller_data_fetcher_mac.mm",
     "gamepad_consumer.cc",
diff --git a/device/gamepad/abstract_haptic_gamepad.cc b/device/gamepad/abstract_haptic_gamepad.cc
new file mode 100644
index 0000000..059b85f7
--- /dev/null
+++ b/device/gamepad/abstract_haptic_gamepad.cc
@@ -0,0 +1,126 @@
+// 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/gamepad/abstract_haptic_gamepad.h"
+
+namespace device {
+
+AbstractHapticGamepad::AbstractHapticGamepad() : sequence_id_(0) {}
+
+AbstractHapticGamepad::~AbstractHapticGamepad() {
+  if (playing_effect_callback_) {
+    SetZeroVibration();
+    RunCallbackOnMojoThread(
+        mojom::GamepadHapticsResult::GamepadHapticsResultPreempted);
+  }
+}
+
+void AbstractHapticGamepad::SetZeroVibration() {
+  SetVibration(0.0, 0.0);
+}
+
+base::TimeDelta AbstractHapticGamepad::TaskDelayFromMilliseconds(
+    double delay_millis) {
+  return base::TimeDelta::FromMillisecondsD(delay_millis);
+}
+
+void AbstractHapticGamepad::PlayEffect(
+    mojom::GamepadHapticEffectType type,
+    mojom::GamepadEffectParametersPtr params,
+    mojom::GamepadHapticsManager::PlayVibrationEffectOnceCallback callback) {
+  if (type !=
+      mojom::GamepadHapticEffectType::GamepadHapticEffectTypeDualRumble) {
+    // Only dual-rumble effects are supported.
+    std::move(callback).Run(
+        mojom::GamepadHapticsResult::GamepadHapticsResultNotSupported);
+    return;
+  }
+
+  int sequence_id = ++sequence_id_;
+
+  if (playing_effect_callback_) {
+    if (params->start_delay > 0.0)
+      SetZeroVibration();
+    RunCallbackOnMojoThread(
+        mojom::GamepadHapticsResult::GamepadHapticsResultPreempted);
+  }
+
+  playing_effect_task_runner_ = base::ThreadTaskRunnerHandle::Get();
+  playing_effect_callback_ = std::move(callback);
+
+  PlayDualRumbleEffect(sequence_id, params->duration, params->start_delay,
+                       params->strong_magnitude, params->weak_magnitude);
+}
+
+void AbstractHapticGamepad::ResetVibration(
+    mojom::GamepadHapticsManager::ResetVibrationActuatorCallback callback) {
+  sequence_id_++;
+
+  if (playing_effect_callback_) {
+    SetZeroVibration();
+    RunCallbackOnMojoThread(
+        mojom::GamepadHapticsResult::GamepadHapticsResultPreempted);
+  }
+
+  std::move(callback).Run(
+      mojom::GamepadHapticsResult::GamepadHapticsResultComplete);
+}
+
+void AbstractHapticGamepad::PlayDualRumbleEffect(int sequence_id,
+                                                 double duration,
+                                                 double start_delay,
+                                                 double strong_magnitude,
+                                                 double weak_magnitude) {
+  base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+      FROM_HERE,
+      base::BindOnce(&AbstractHapticGamepad::StartVibration,
+                     base::Unretained(this), sequence_id_, duration,
+                     strong_magnitude, weak_magnitude),
+      TaskDelayFromMilliseconds(start_delay));
+}
+
+void AbstractHapticGamepad::StartVibration(int sequence_id,
+                                           double duration,
+                                           double strong_magnitude,
+                                           double weak_magnitude) {
+  if (sequence_id != sequence_id_)
+    return;
+  SetVibration(strong_magnitude, weak_magnitude);
+
+  base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+      FROM_HERE,
+      base::BindOnce(&AbstractHapticGamepad::StopVibration,
+                     base::Unretained(this), sequence_id),
+      TaskDelayFromMilliseconds(duration));
+}
+
+void AbstractHapticGamepad::StopVibration(int sequence_id) {
+  if (sequence_id != sequence_id_)
+    return;
+  SetZeroVibration();
+
+  RunCallbackOnMojoThread(
+      mojom::GamepadHapticsResult::GamepadHapticsResultComplete);
+}
+
+void AbstractHapticGamepad::RunCallbackOnMojoThread(
+    mojom::GamepadHapticsResult result) {
+  if (playing_effect_task_runner_->RunsTasksInCurrentSequence()) {
+    DoRunCallback(std::move(playing_effect_callback_), result);
+    return;
+  }
+
+  playing_effect_task_runner_->PostTask(
+      FROM_HERE, base::BindOnce(&AbstractHapticGamepad::DoRunCallback,
+                                std::move(playing_effect_callback_), result));
+}
+
+// static
+void AbstractHapticGamepad::DoRunCallback(
+    mojom::GamepadHapticsManager::PlayVibrationEffectOnceCallback callback,
+    mojom::GamepadHapticsResult result) {
+  std::move(callback).Run(result);
+}
+
+}  // namespace device
diff --git a/device/gamepad/abstract_haptic_gamepad.h b/device/gamepad/abstract_haptic_gamepad.h
new file mode 100644
index 0000000..6f7d67f
--- /dev/null
+++ b/device/gamepad/abstract_haptic_gamepad.h
@@ -0,0 +1,77 @@
+// 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_GAMEPAD_ABSTRACT_HAPTIC_GAMEPAD_
+#define DEVICE_GAMEPAD_ABSTRACT_HAPTIC_GAMEPAD_
+
+#include "base/memory/scoped_refptr.h"
+#include "base/sequenced_task_runner.h"
+#include "base/time/time.h"
+#include "device/gamepad/gamepad_export.h"
+#include "device/gamepad/public/interfaces/gamepad.mojom.h"
+
+namespace device {
+
+// AbstractHapticGamepad is a base class for gamepads that support dual-rumble
+// vibration effects. To use it, override the SetVibration method so that it
+// sets the vibration intensity on the device. Then, calling PlayEffect or
+// ResetVibration will call your SetVibration method at the appropriate times
+// to produce the desired vibration effect. When the effect is complete, or when
+// it has been preempted by another effect, the callback is invoked with a
+// result code.
+//
+// By default, SetZeroVibration simply calls SetVibration with both parameters
+// set to zero. You may optionally override SetZeroVibration if the device has a
+// more efficient means of stopping an ongoing effect.
+class DEVICE_GAMEPAD_EXPORT AbstractHapticGamepad {
+ public:
+  AbstractHapticGamepad();
+  virtual ~AbstractHapticGamepad();
+
+  // Start playing an effect.
+  void PlayEffect(
+      mojom::GamepadHapticEffectType,
+      mojom::GamepadEffectParametersPtr,
+      mojom::GamepadHapticsManager::PlayVibrationEffectOnceCallback);
+
+  // Reset vibration on the gamepad, perhaps interrupting an ongoing effect.
+  void ResetVibration(
+      mojom::GamepadHapticsManager::ResetVibrationActuatorCallback);
+
+ private:
+  // Set the vibration magnitude for the strong and weak vibration actuators.
+  virtual void SetVibration(double strong_magnitude, double weak_magnitude) = 0;
+
+  // Set the vibration magnitude for both actuators to zero.
+  virtual void SetZeroVibration();
+
+  // For testing.
+  virtual base::TimeDelta TaskDelayFromMilliseconds(double delay_millis);
+
+  void PlayDualRumbleEffect(int sequence_id,
+                            double duration,
+                            double start_delay,
+                            double strong_magnitude,
+                            double weak_magnitude);
+  void StartVibration(int sequence_id,
+                      double duration,
+                      double strong_magnitude,
+                      double weak_magnitude);
+  void StopVibration(int sequence_id);
+
+  void RunCallbackOnMojoThread(mojom::GamepadHapticsResult result);
+
+  static void DoRunCallback(
+      mojom::GamepadHapticsManager::PlayVibrationEffectOnceCallback,
+      mojom::GamepadHapticsResult);
+
+  int sequence_id_;
+  scoped_refptr<base::SequencedTaskRunner> playing_effect_task_runner_;
+  mojom::GamepadHapticsManager::PlayVibrationEffectOnceCallback
+      playing_effect_callback_;
+};
+
+}  // namespace device
+
+#endif  // DEVICE_GAMEPAD_ABSTRACT_HAPTIC_GAMEPAD_
diff --git a/device/gamepad/abstract_haptic_gamepad_unittest.cc b/device/gamepad/abstract_haptic_gamepad_unittest.cc
new file mode 100644
index 0000000..c36e6303
--- /dev/null
+++ b/device/gamepad/abstract_haptic_gamepad_unittest.cc
@@ -0,0 +1,343 @@
+// 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/gamepad/abstract_haptic_gamepad.h"
+
+#include <memory>
+
+#include "base/macros.h"
+#include "base/run_loop.h"
+#include "base/test/test_simple_task_runner.h"
+#include "device/gamepad/public/interfaces/gamepad.mojom.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace device {
+
+namespace {
+
+// An implementation of AbstractHapticGamepad that records how many times its
+// SetVibration and SetZeroVibration methods have been called.
+class FakeHapticGamepad : public AbstractHapticGamepad {
+ public:
+  FakeHapticGamepad() : set_vibration_count_(0), set_zero_vibration_count_(0) {}
+  ~FakeHapticGamepad() override = default;
+
+  void SetVibration(double strong_magnitude, double weak_magnitude) override {
+    set_vibration_count_++;
+  }
+
+  void SetZeroVibration() override { set_zero_vibration_count_++; }
+
+  base::TimeDelta TaskDelayFromMilliseconds(double delay_millis) override {
+    // Remove delays for testing.
+    return base::TimeDelta();
+  }
+
+  int set_vibration_count_;
+  int set_zero_vibration_count_;
+};
+
+// Main test fixture
+class AbstractHapticGamepadTest : public testing::Test {
+ public:
+  AbstractHapticGamepadTest()
+      : first_callback_count_(0),
+        second_callback_count_(0),
+        first_callback_result_(
+            mojom::GamepadHapticsResult::GamepadHapticsResultError),
+        second_callback_result_(
+            mojom::GamepadHapticsResult::GamepadHapticsResultError),
+        gamepad_(std::make_unique<FakeHapticGamepad>()),
+        task_runner_(new base::TestSimpleTaskRunner) {}
+
+  void PostPlayEffect(
+      mojom::GamepadHapticEffectType type,
+      double duration,
+      double start_delay,
+      mojom::GamepadHapticsManager::PlayVibrationEffectOnceCallback callback) {
+    task_runner_->PostDelayedTask(
+        FROM_HERE,
+        base::BindOnce(&FakeHapticGamepad::PlayEffect,
+                       base::Unretained(gamepad_.get()), type,
+                       mojom::GamepadEffectParameters::New(
+                           duration, start_delay, 1.0, 1.0),
+                       std::move(callback)),
+        base::TimeDelta());
+  }
+
+  void PostResetVibration(
+      mojom::GamepadHapticsManager::ResetVibrationActuatorCallback callback) {
+    task_runner_->PostDelayedTask(
+        FROM_HERE,
+        base::BindOnce(&FakeHapticGamepad::ResetVibration,
+                       base::Unretained(gamepad_.get()), std::move(callback)),
+        base::TimeDelta());
+  }
+
+  void FirstCallback(mojom::GamepadHapticsResult result) {
+    first_callback_count_++;
+    first_callback_result_ = result;
+  }
+
+  void SecondCallback(mojom::GamepadHapticsResult result) {
+    second_callback_count_++;
+    second_callback_result_ = result;
+  }
+
+  int first_callback_count_;
+  int second_callback_count_;
+  mojom::GamepadHapticsResult first_callback_result_;
+  mojom::GamepadHapticsResult second_callback_result_;
+  std::unique_ptr<FakeHapticGamepad> gamepad_;
+  scoped_refptr<base::TestSimpleTaskRunner> task_runner_;
+
+  DISALLOW_COPY_AND_ASSIGN(AbstractHapticGamepadTest);
+};
+
+TEST_F(AbstractHapticGamepadTest, PlayEffectTest) {
+  EXPECT_EQ(0, gamepad_->set_vibration_count_);
+  EXPECT_EQ(0, gamepad_->set_zero_vibration_count_);
+  EXPECT_EQ(0, first_callback_count_);
+
+  PostPlayEffect(
+      mojom::GamepadHapticEffectType::GamepadHapticEffectTypeDualRumble, 1.0,
+      0.0,
+      base::BindOnce(&AbstractHapticGamepadTest::FirstCallback,
+                     base::Unretained(this)));
+
+  // Run the queued task, but stop before executing any new tasks queued by that
+  // task. This should pause before calling SetVibration.
+  task_runner_->RunPendingTasks();
+
+  EXPECT_EQ(0, gamepad_->set_vibration_count_);
+  EXPECT_EQ(0, gamepad_->set_zero_vibration_count_);
+  EXPECT_EQ(0, first_callback_count_);
+  EXPECT_TRUE(task_runner_->HasPendingTask());
+
+  // Run the next task, but pause before completing the effect.
+  task_runner_->RunPendingTasks();
+
+  EXPECT_EQ(1, gamepad_->set_vibration_count_);
+  EXPECT_EQ(0, gamepad_->set_zero_vibration_count_);
+  EXPECT_EQ(0, first_callback_count_);
+  EXPECT_TRUE(task_runner_->HasPendingTask());
+
+  // Complete the effect and issue the callback. After this, there should be no
+  // more pending tasks.
+  task_runner_->RunPendingTasks();
+
+  EXPECT_EQ(1, gamepad_->set_vibration_count_);
+  EXPECT_EQ(1, gamepad_->set_zero_vibration_count_);
+  EXPECT_EQ(1, first_callback_count_);
+  EXPECT_EQ(mojom::GamepadHapticsResult::GamepadHapticsResultComplete,
+            first_callback_result_);
+  EXPECT_FALSE(task_runner_->HasPendingTask());
+}
+
+TEST_F(AbstractHapticGamepadTest, ResetVibrationTest) {
+  EXPECT_EQ(0, gamepad_->set_vibration_count_);
+  EXPECT_EQ(0, gamepad_->set_zero_vibration_count_);
+  EXPECT_EQ(0, first_callback_count_);
+
+  PostResetVibration(base::BindOnce(&AbstractHapticGamepadTest::FirstCallback,
+                                    base::Unretained(this)));
+
+  task_runner_->RunUntilIdle();
+
+  // ResetVibration should return a "complete" result without calling
+  // SetVibration or SetZeroVibration.
+  EXPECT_EQ(0, gamepad_->set_vibration_count_);
+  EXPECT_EQ(0, gamepad_->set_zero_vibration_count_);
+  EXPECT_EQ(1, first_callback_count_);
+  EXPECT_EQ(mojom::GamepadHapticsResult::GamepadHapticsResultComplete,
+            first_callback_result_);
+}
+
+TEST_F(AbstractHapticGamepadTest, UnsupportedEffectTypeTest) {
+  EXPECT_EQ(0, gamepad_->set_vibration_count_);
+  EXPECT_EQ(0, gamepad_->set_zero_vibration_count_);
+  EXPECT_EQ(0, first_callback_count_);
+
+  mojom::GamepadHapticEffectType unsupported_effect_type =
+      static_cast<mojom::GamepadHapticEffectType>(123);
+  PostPlayEffect(unsupported_effect_type, 1.0, 0.0,
+                 base::BindOnce(&AbstractHapticGamepadTest::FirstCallback,
+                                base::Unretained(this)));
+
+  task_runner_->RunUntilIdle();
+
+  // An unsupported effect should return a "not-supported" result without
+  // calling SetVibration or SetZeroVibration.
+  EXPECT_EQ(0, gamepad_->set_vibration_count_);
+  EXPECT_EQ(0, gamepad_->set_zero_vibration_count_);
+  EXPECT_EQ(1, first_callback_count_);
+  EXPECT_EQ(mojom::GamepadHapticsResult::GamepadHapticsResultNotSupported,
+            first_callback_result_);
+}
+
+TEST_F(AbstractHapticGamepadTest, StartDelayTest) {
+  EXPECT_EQ(0, gamepad_->set_vibration_count_);
+  EXPECT_EQ(0, gamepad_->set_zero_vibration_count_);
+  EXPECT_EQ(0, first_callback_count_);
+
+  // This test establishes the behavior for the start_delay parameter when
+  // PlayEffect is called without preempting an existing effect.
+  PostPlayEffect(
+      mojom::GamepadHapticEffectType::GamepadHapticEffectTypeDualRumble, 1.0,
+      0.0,
+      base::BindOnce(&AbstractHapticGamepadTest::FirstCallback,
+                     base::Unretained(this)));
+
+  task_runner_->RunUntilIdle();
+
+  // With zero start_delay, SetVibration and SetZeroVibration should be called
+  // exactly once each, to start and stop the effect.
+  EXPECT_EQ(1, gamepad_->set_vibration_count_);
+  EXPECT_EQ(1, gamepad_->set_zero_vibration_count_);
+  EXPECT_EQ(1, first_callback_count_);
+  EXPECT_EQ(mojom::GamepadHapticsResult::GamepadHapticsResultComplete,
+            first_callback_result_);
+
+  PostPlayEffect(
+      mojom::GamepadHapticEffectType::GamepadHapticEffectTypeDualRumble, 1.0,
+      1.0,
+      base::BindOnce(&AbstractHapticGamepadTest::FirstCallback,
+                     base::Unretained(this)));
+
+  task_runner_->RunUntilIdle();
+
+  // With non-zero start_delay, we still SetVibration and SetZeroVibration to be
+  // called exactly once each.
+  EXPECT_EQ(2, gamepad_->set_vibration_count_);
+  EXPECT_EQ(2, gamepad_->set_zero_vibration_count_);
+  EXPECT_EQ(2, first_callback_count_);
+  EXPECT_EQ(mojom::GamepadHapticsResult::GamepadHapticsResultComplete,
+            first_callback_result_);
+}
+
+TEST_F(AbstractHapticGamepadTest, ZeroStartDelayPreemptionTest) {
+  EXPECT_EQ(0, gamepad_->set_vibration_count_);
+  EXPECT_EQ(0, gamepad_->set_zero_vibration_count_);
+  EXPECT_EQ(0, first_callback_count_);
+  EXPECT_EQ(0, second_callback_count_);
+
+  // Start an ongoing effect. We'll preempt this one with another effect.
+  PostPlayEffect(
+      mojom::GamepadHapticEffectType::GamepadHapticEffectTypeDualRumble, 1.0,
+      0.0,
+      base::BindOnce(&AbstractHapticGamepadTest::FirstCallback,
+                     base::Unretained(this)));
+
+  // Start a second effect with zero start_delay. This should cause the first
+  // effect to be preempted before it calls SetVibration.
+  PostPlayEffect(
+      mojom::GamepadHapticEffectType::GamepadHapticEffectTypeDualRumble, 1.0,
+      0.0,
+      base::BindOnce(&AbstractHapticGamepadTest::SecondCallback,
+                     base::Unretained(this)));
+
+  // Execute the pending tasks, but stop before executing any newly queued
+  // tasks.
+  task_runner_->RunPendingTasks();
+
+  // The first effect should have already returned with a "preempted" result.
+  EXPECT_EQ(0, gamepad_->set_vibration_count_);
+  EXPECT_EQ(0, gamepad_->set_zero_vibration_count_);
+  EXPECT_EQ(1, first_callback_count_);
+  EXPECT_EQ(0, second_callback_count_);
+  EXPECT_EQ(mojom::GamepadHapticsResult::GamepadHapticsResultPreempted,
+            first_callback_result_);
+
+  task_runner_->RunUntilIdle();
+
+  // Now the second effect should have returned with a "complete" result.
+  EXPECT_EQ(1, gamepad_->set_vibration_count_);
+  EXPECT_EQ(1, gamepad_->set_zero_vibration_count_);
+  EXPECT_EQ(1, first_callback_count_);
+  EXPECT_EQ(1, second_callback_count_);
+  EXPECT_EQ(mojom::GamepadHapticsResult::GamepadHapticsResultComplete,
+            second_callback_result_);
+}
+
+TEST_F(AbstractHapticGamepadTest, NonZeroStartDelayPreemptionTest) {
+  EXPECT_EQ(0, gamepad_->set_vibration_count_);
+  EXPECT_EQ(0, gamepad_->set_zero_vibration_count_);
+  EXPECT_EQ(0, first_callback_count_);
+  EXPECT_EQ(0, second_callback_count_);
+
+  // Start an ongoing effect. We'll preempt this one with another effect.
+  PostPlayEffect(
+      mojom::GamepadHapticEffectType::GamepadHapticEffectTypeDualRumble, 1.0,
+      0.0,
+      base::BindOnce(&AbstractHapticGamepadTest::FirstCallback,
+                     base::Unretained(this)));
+
+  // Start a second effect with non-zero start_delay. This should cause the
+  // first effect to be preempted before it calls SetVibration.
+  PostPlayEffect(
+      mojom::GamepadHapticEffectType::GamepadHapticEffectTypeDualRumble, 1.0,
+      1.0,
+      base::BindOnce(&AbstractHapticGamepadTest::SecondCallback,
+                     base::Unretained(this)));
+
+  // Execute the pending tasks, but stop before executing any newly queued
+  // tasks.
+  task_runner_->RunPendingTasks();
+
+  // The first effect should have already returned with a "preempted" result.
+  // Because the second effect has a non-zero start_delay and is preempting
+  // another effect, it will call SetZeroVibration to ensure no vibration
+  // occurs during its start_delay period.
+  EXPECT_EQ(0, gamepad_->set_vibration_count_);
+  EXPECT_EQ(1, gamepad_->set_zero_vibration_count_);
+  EXPECT_EQ(1, first_callback_count_);
+  EXPECT_EQ(0, second_callback_count_);
+  EXPECT_EQ(mojom::GamepadHapticsResult::GamepadHapticsResultPreempted,
+            first_callback_result_);
+
+  task_runner_->RunUntilIdle();
+
+  EXPECT_EQ(1, gamepad_->set_vibration_count_);
+  EXPECT_EQ(2, gamepad_->set_zero_vibration_count_);
+  EXPECT_EQ(1, first_callback_count_);
+  EXPECT_EQ(1, second_callback_count_);
+  EXPECT_EQ(mojom::GamepadHapticsResult::GamepadHapticsResultPreempted,
+            first_callback_result_);
+  EXPECT_EQ(mojom::GamepadHapticsResult::GamepadHapticsResultComplete,
+            second_callback_result_);
+}
+
+TEST_F(AbstractHapticGamepadTest, ResetVibrationPreemptionTest) {
+  EXPECT_EQ(0, gamepad_->set_vibration_count_);
+  EXPECT_EQ(0, gamepad_->set_zero_vibration_count_);
+  EXPECT_EQ(0, first_callback_count_);
+  EXPECT_EQ(0, second_callback_count_);
+
+  // Start an ongoing effect. We'll preempt it with a reset.
+  PostPlayEffect(
+      mojom::GamepadHapticEffectType::GamepadHapticEffectTypeDualRumble, 1.0,
+      0.0,
+      base::BindOnce(&AbstractHapticGamepadTest::FirstCallback,
+                     base::Unretained(this)));
+
+  // Reset vibration. This should cause the effect to be preempted before it
+  // calls SetVibration.
+  PostResetVibration(base::BindOnce(&AbstractHapticGamepadTest::SecondCallback,
+                                    base::Unretained(this)));
+
+  task_runner_->RunUntilIdle();
+
+  EXPECT_EQ(0, gamepad_->set_vibration_count_);
+  EXPECT_EQ(1, gamepad_->set_zero_vibration_count_);
+  EXPECT_EQ(1, first_callback_count_);
+  EXPECT_EQ(1, second_callback_count_);
+  EXPECT_EQ(mojom::GamepadHapticsResult::GamepadHapticsResultPreempted,
+            first_callback_result_);
+  EXPECT_EQ(mojom::GamepadHapticsResult::GamepadHapticsResultComplete,
+            second_callback_result_);
+}
+
+}  // namespace
+
+}  // namespace device
diff --git a/device/u2f/BUILD.gn b/device/u2f/BUILD.gn
index e94b708..3e0e89de 100644
--- a/device/u2f/BUILD.gn
+++ b/device/u2f/BUILD.gn
@@ -110,3 +110,23 @@
   ]
   libfuzzer_options = [ "max_len=65535" ]
 }
+
+is_linux_without_udev = is_linux && !use_udev
+
+source_set("test_support") {
+  testonly = true
+
+  # Android doesn't compile.
+  # Linux, requires udev.
+  if (!is_linux_without_udev && !is_android) {
+    sources = [
+      "fake_hid_impl_for_testing.cc",
+      "fake_hid_impl_for_testing.h",
+    ]
+    deps = [
+      "//base",
+      "//mojo/public/cpp/bindings",
+      "//services/device/public/interfaces",
+    ]
+  }
+}
diff --git a/device/vr/openvr/openvr_gamepad_data_fetcher.cc b/device/vr/openvr/openvr_gamepad_data_fetcher.cc
index 2cd0daf..73a1e91 100644
--- a/device/vr/openvr/openvr_gamepad_data_fetcher.cc
+++ b/device/vr/openvr/openvr_gamepad_data_fetcher.cc
@@ -100,18 +100,9 @@
       pad.pose.has_orientation = true;
       pad.pose.has_position = true;
 
-      vr::TrackedPropertyError error = vr::TrackedProp_Success;
-      char attached_device_id[vr::k_unMaxPropertyStringSize];
-      vr_system_->GetStringTrackedDeviceProperty(
-          i, vr::Prop_AttachedDeviceId_String, attached_device_id,
-          vr::k_unMaxPropertyStringSize, &error);
-
-      if (error == vr::TrackedProp_Success) {
-        swprintf(pad.id, Gamepad::kIdLengthCap,
-                 base::UTF8ToUTF16(attached_device_id).c_str());
-      } else {
-        swprintf(pad.id, Gamepad::kIdLengthCap, L"OpenVR Controller");
-      }
+      // The defacto standard says we set id to "OpenVR Gamepad".  WebXR input
+      // will provide a better solution.
+      swprintf(pad.id, Gamepad::kIdLengthCap, L"OpenVR Gamepad");
       swprintf(pad.mapping, Gamepad::kMappingLengthCap, L"");
 
       pad.display_id = display_id_;
diff --git a/extensions/BUILD.gn b/extensions/BUILD.gn
index c11f618..ddec015 100644
--- a/extensions/BUILD.gn
+++ b/extensions/BUILD.gn
@@ -52,7 +52,6 @@
   deps = [
     "//extensions/common:mojo_js",
     "//extensions/common/api:mojom_js",
-    "//mojo/public/js:bindings",
     "//services/device/public/interfaces:interfaces_js",
   ]
 }
diff --git a/extensions/browser/OWNERS b/extensions/browser/OWNERS
index 6e0ba74..2cf58a3 100644
--- a/extensions/browser/OWNERS
+++ b/extensions/browser/OWNERS
@@ -6,15 +6,9 @@
 per-file DEPS=rdevlin.cronin@chromium.org
 
 per-file extension_event_histogram_value.h=set noparent
-per-file extension_event_histogram_value.h=asvitkine@chromium.org
-per-file extension_event_histogram_value.h=isherman@chromium.org
-per-file extension_event_histogram_value.h=jar@chromium.org
-per-file extension_event_histogram_value.h=mpearson@chromium.org
+per-file extension_event_histogram_value.h=file://base/metrics/OWNERS
 per-file extension_function_histogram_value.h=set noparent
-per-file extension_function_histogram_value.h=asvitkine@chromium.org
-per-file extension_function_histogram_value.h=isherman@chromium.org
-per-file extension_function_histogram_value.h=jar@chromium.org
-per-file extension_function_histogram_value.h=mpearson@chromium.org
+per-file extension_function_histogram_value.h=file://base/metrics/OWNERS
 
 # DeviceLocalAccount reviewers.
 per-file device_local_account_util*=isandrk@chromium.org
diff --git a/extensions/common/feature_switch.cc b/extensions/common/feature_switch.cc
index a10f02ae..f30d0f3 100644
--- a/extensions/common/feature_switch.cc
+++ b/extensions/common/feature_switch.cc
@@ -6,7 +6,6 @@
 
 #include "base/command_line.h"
 #include "base/lazy_instance.h"
-#include "base/metrics/field_trial.h"
 #include "base/strings/string_util.h"
 #include "build/build_config.h"
 #include "extensions/common/switches.h"
@@ -117,26 +116,11 @@
                     switch_name,
                     default_value) {}
 
-FeatureSwitch::FeatureSwitch(const char* switch_name,
-                             const char* field_trial_name,
-                             DefaultValue default_value)
-    : FeatureSwitch(base::CommandLine::ForCurrentProcess(),
-                    switch_name,
-                    field_trial_name,
-                    default_value) {}
-
 FeatureSwitch::FeatureSwitch(const base::CommandLine* command_line,
                              const char* switch_name,
                              DefaultValue default_value)
-    : FeatureSwitch(command_line, switch_name, nullptr, default_value) {}
-
-FeatureSwitch::FeatureSwitch(const base::CommandLine* command_line,
-                             const char* switch_name,
-                             const char* field_trial_name,
-                             DefaultValue default_value)
     : command_line_(command_line),
       switch_name_(switch_name),
-      field_trial_name_(field_trial_name),
       default_value_(default_value == DEFAULT_ENABLED),
       override_value_(OVERRIDE_NONE) {}
 
@@ -162,24 +146,12 @@
   if (switch_value == "0")
     return false;
 
-  // TODO(imcheng): Don't check |default_value_|. Otherwise, we could improperly
-  // ignore an enable/disable switch if there is a field trial active.
-  // crbug.com/585569
-  if (!default_value_ && command_line_->HasSwitch(GetLegacyEnableFlag()))
+  if (command_line_->HasSwitch(GetLegacyEnableFlag()))
     return true;
 
-  if (default_value_ && command_line_->HasSwitch(GetLegacyDisableFlag()))
+  if (command_line_->HasSwitch(GetLegacyDisableFlag()))
     return false;
 
-  if (field_trial_name_) {
-    std::string group_name =
-        base::FieldTrialList::FindFullName(field_trial_name_);
-    if (base::StartsWith(group_name, "Enabled", base::CompareCase::SENSITIVE))
-      return true;
-    if (base::StartsWith(group_name, "Disabled", base::CompareCase::SENSITIVE))
-      return false;
-  }
-
   return default_value_;
 }
 
diff --git a/extensions/common/feature_switch.h b/extensions/common/feature_switch.h
index cc5b65689..5648c717 100644
--- a/extensions/common/feature_switch.h
+++ b/extensions/common/feature_switch.h
@@ -18,18 +18,14 @@
 
 // A switch that can turn a feature on or off. Typically controlled via
 // command-line switches but can be overridden, e.g., for testing.
-// Can also integrate with Finch's field trials.
 // A note about priority:
 // 1. If an override is present, the override state will be used.
 // 2. If there is no switch name, the default value will be used. This is
 //    because certain features are specifically designed *not* to be able to
-//    be turned off via command-line, so we can't consult it (or, by extension,
-//    the finch config).
+//    be turned off via command-line, so we can't consult it.
 // 3. If there is a switch name, and the switch is present in the command line,
 //    the command line value will be used.
-// 4. If there is a finch experiment associated and applicable to the machine,
-//    the finch value will be used.
-// 5. Otherwise, the default value is used.
+// 4. Otherwise, the default value is used.
 class FeatureSwitch {
  public:
   static FeatureSwitch* force_dev_mode_highlighting();
@@ -67,16 +63,9 @@
   // by the default and override values.
   FeatureSwitch(const char* switch_name,
                 DefaultValue default_value);
-  FeatureSwitch(const char* switch_name,
-                const char* field_trial_name,
-                DefaultValue default_value);
   FeatureSwitch(const base::CommandLine* command_line,
                 const char* switch_name,
                 DefaultValue default_value);
-  FeatureSwitch(const base::CommandLine* command_line,
-                const char* switch_name,
-                const char* field_trial_name,
-                DefaultValue default_value);
 
   // Consider using ScopedOverride instead.
   void SetOverrideValue(OverrideValue value);
@@ -92,7 +81,6 @@
 
   const base::CommandLine* command_line_;
   const char* switch_name_;
-  const char* field_trial_name_;
   bool default_value_;
   OverrideValue override_value_;
   mutable base::Optional<bool> cached_value_;
diff --git a/extensions/renderer/BUILD.gn b/extensions/renderer/BUILD.gn
index 8864de8..4358bb5 100644
--- a/extensions/renderer/BUILD.gn
+++ b/extensions/renderer/BUILD.gn
@@ -118,6 +118,8 @@
     "file_system_natives.h",
     "gc_callback.cc",
     "gc_callback.h",
+    "get_script_context.cc",
+    "get_script_context.h",
     "gin_port.cc",
     "gin_port.h",
     "guest_view/extensions_guest_view_container.cc",
@@ -191,10 +193,30 @@
     "resources/greasemonkey_api.js",
     "resources/guest_view/app_view/app_view.js",
     "resources/guest_view/extension_options/extension_options.js",
+    "resources/guest_view/extension_options/extension_options_attributes.js",
+    "resources/guest_view/extension_options/extension_options_constants.js",
+    "resources/guest_view/extension_options/extension_options_events.js",
     "resources/guest_view/extension_view/extension_view.js",
+    "resources/guest_view/extension_view/extension_view_api_methods.js",
+    "resources/guest_view/extension_view/extension_view_attributes.js",
+    "resources/guest_view/extension_view/extension_view_constants.js",
+    "resources/guest_view/extension_view/extension_view_events.js",
+    "resources/guest_view/extension_view/extension_view_internal.js",
+    "resources/guest_view/guest_view.js",
+    "resources/guest_view/guest_view_attributes.js",
+    "resources/guest_view/guest_view_container.js",
+    "resources/guest_view/guest_view_deny.js",
+    "resources/guest_view/guest_view_events.js",
+    "resources/guest_view/guest_view_iframe.js",
+    "resources/guest_view/guest_view_iframe_container.js",
     "resources/guest_view/web_view/web_view.js",
+    "resources/guest_view/web_view/web_view_action_requests.js",
+    "resources/guest_view/web_view/web_view_api_methods.js",
+    "resources/guest_view/web_view/web_view_attributes.js",
+    "resources/guest_view/web_view/web_view_constants.js",
     "resources/guest_view/web_view/web_view_events.js",
-    "resources/guest_view/web_view/web_view_iframe.js",
+    "resources/guest_view/web_view/web_view_internal.js",
+    "resources/guest_view/web_view/web_view_request_custom_bindings.js",
     "resources/i18n_custom_bindings.js",
     "resources/image_util.js",
     "resources/json_schema.js",
diff --git a/extensions/renderer/get_script_context.cc b/extensions/renderer/get_script_context.cc
new file mode 100644
index 0000000..0b4ba826
--- /dev/null
+++ b/extensions/renderer/get_script_context.cc
@@ -0,0 +1,31 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "extensions/renderer/get_script_context.h"
+
+#include "base/logging.h"
+#include "content/public/renderer/worker_thread.h"
+#include "extensions/renderer/script_context.h"
+#include "extensions/renderer/script_context_set.h"
+#include "extensions/renderer/worker_thread_dispatcher.h"
+
+namespace extensions {
+
+ScriptContext* GetScriptContextFromV8Context(v8::Local<v8::Context> context) {
+  ScriptContext* script_context =
+      content::WorkerThread::GetCurrentId() > 0
+          ? WorkerThreadDispatcher::GetScriptContext()
+          : ScriptContextSet::GetContextByV8Context(context);
+  DCHECK(!script_context || script_context->v8_context() == context);
+  return script_context;
+}
+
+ScriptContext* GetScriptContextFromV8ContextChecked(
+    v8::Local<v8::Context> context) {
+  ScriptContext* script_context = GetScriptContextFromV8Context(context);
+  CHECK(script_context);
+  return script_context;
+}
+
+}  // namespace extensions
diff --git a/extensions/renderer/get_script_context.h b/extensions/renderer/get_script_context.h
new file mode 100644
index 0000000..2dd8e9d4
--- /dev/null
+++ b/extensions/renderer/get_script_context.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 EXTENSIONS_RENDERER_GET_SCRIPT_CONTEXT_H_
+#define EXTENSIONS_RENDERER_GET_SCRIPT_CONTEXT_H_
+
+#include "v8/include/v8.h"
+
+namespace extensions {
+class ScriptContext;
+
+// TODO(devlin): This is a very random place for these. But there's not really
+// a better one - ScriptContextSet is (currently) thread-agnostic, and it'd be
+// nice to avoid changing that.
+
+// Returns the ScriptContext associated with the given v8::Context. This is
+// designed to work for both main thread and worker thread contexts.
+ScriptContext* GetScriptContextFromV8Context(v8::Local<v8::Context> context);
+
+// Same as above, but CHECK()s the result before returning.
+ScriptContext* GetScriptContextFromV8ContextChecked(
+    v8::Local<v8::Context> context);
+
+}  // namespace extensions
+
+#endif  // EXTENSIONS_RENDERER_GET_SCRIPT_CONTEXT_H_
diff --git a/extensions/renderer/native_extension_bindings_system.cc b/extensions/renderer/native_extension_bindings_system.cc
index cd90e2e..900d4ff4 100644
--- a/extensions/renderer/native_extension_bindings_system.cc
+++ b/extensions/renderer/native_extension_bindings_system.cc
@@ -11,7 +11,6 @@
 #include "base/timer/elapsed_timer.h"
 #include "content/public/common/console_message_level.h"
 #include "content/public/common/content_switches.h"
-#include "content/public/renderer/worker_thread.h"
 #include "extensions/common/constants.h"
 #include "extensions/common/event_filtering_info.h"
 #include "extensions/common/extension_api.h"
@@ -29,13 +28,12 @@
 #include "extensions/renderer/easy_unlock_proximity_required_stub.h"
 #include "extensions/renderer/extension_frame_helper.h"
 #include "extensions/renderer/extension_js_runner.h"
+#include "extensions/renderer/get_script_context.h"
 #include "extensions/renderer/ipc_message_sender.h"
 #include "extensions/renderer/module_system.h"
 #include "extensions/renderer/script_context.h"
-#include "extensions/renderer/script_context_set.h"
 #include "extensions/renderer/storage_area.h"
 #include "extensions/renderer/web_request_hooks.h"
-#include "extensions/renderer/worker_thread_dispatcher.h"
 #include "gin/converter.h"
 #include "gin/handle.h"
 #include "gin/per_context_data.h"
@@ -152,32 +150,13 @@
   return data;
 }
 
-// Returns the ScriptContext associated with the given v8::Context.
-// TODO(devlin): Does this belong here, or should it be curried in as a
-// callback? This is the only place we have knowledge of worker vs. non-worker
-// threads here.
-ScriptContext* GetScriptContext(v8::Local<v8::Context> context) {
-  ScriptContext* script_context =
-      content::WorkerThread::GetCurrentId() > 0
-          ? WorkerThreadDispatcher::GetScriptContext()
-          : ScriptContextSet::GetContextByV8Context(context);
-  DCHECK(!script_context || script_context->v8_context() == context);
-  return script_context;
-}
-
-// Same as above, but CHECKs the result.
-ScriptContext* GetScriptContextChecked(v8::Local<v8::Context> context) {
-  ScriptContext* script_context = GetScriptContext(context);
-  CHECK(script_context);
-  return script_context;
-}
-
 void AddConsoleError(v8::Local<v8::Context> context, const std::string& error) {
-  ScriptContext* script_context = GetScriptContext(context);
+  ScriptContext* script_context = GetScriptContextFromV8Context(context);
   // Note: |script_context| may be null. During context tear down, we remove the
   // script context from the ScriptContextSet, so it's not findable by
-  // GetScriptContext. In theory, we shouldn't be running any bindings code
-  // after this point, but it seems that we are in at least some places.
+  // GetScriptContextFromV8Context. In theory, we shouldn't be running any
+  // bindings code after this point, but it seems that we are in at least some
+  // places.
   // TODO(devlin): Investigate. At least one place this manifests is in
   // messaging binding tear down exhibited by
   // MessagingApiTest.MessagingBackgroundOnly.
@@ -198,7 +177,7 @@
 // |context|.
 bool IsAPIFeatureAvailable(v8::Local<v8::Context> context,
                            const std::string& name) {
-  ScriptContext* script_context = GetScriptContextChecked(context);
+  ScriptContext* script_context = GetScriptContextFromV8ContextChecked(context);
   return script_context->GetAvailability(name).is_available();
 }
 
@@ -624,7 +603,7 @@
     return value.As<v8::Object>();
   }
 
-  ScriptContext* script_context = GetScriptContextChecked(context);
+  ScriptContext* script_context = GetScriptContextFromV8ContextChecked(context);
   std::string api_name_string;
   CHECK(
       gin::Converter<std::string>::FromV8(isolate, api_name, &api_name_string));
@@ -697,7 +676,7 @@
 
   std::string api_name = gin::V8ToString(info[0]);
   const Feature* feature = FeatureProvider::GetAPIFeature(api_name);
-  ScriptContext* script_context = GetScriptContextChecked(context);
+  ScriptContext* script_context = GetScriptContextFromV8ContextChecked(context);
   if (!feature ||
       !script_context->IsAnyFeatureAvailableToContext(
           *feature, CheckAliasStatus::NOT_ALLOWED)) {
@@ -729,7 +708,7 @@
 void NativeExtensionBindingsSystem::SendRequest(
     std::unique_ptr<APIRequestHandler::Request> request,
     v8::Local<v8::Context> context) {
-  ScriptContext* script_context = GetScriptContextChecked(context);
+  ScriptContext* script_context = GetScriptContextFromV8ContextChecked(context);
 
   GURL url;
   blink::WebLocalFrame* frame = script_context->web_frame();
@@ -760,7 +739,7 @@
     const base::DictionaryValue* filter,
     bool update_lazy_listeners,
     v8::Local<v8::Context> context) {
-  ScriptContext* script_context = GetScriptContextChecked(context);
+  ScriptContext* script_context = GetScriptContextFromV8ContextChecked(context);
   // Note: Check context_type() first to avoid accessing ExtensionFrameHelper on
   // a worker thread.
   bool is_lazy =
diff --git a/extensions/renderer/runtime_hooks_delegate.cc b/extensions/renderer/runtime_hooks_delegate.cc
index a9eee77..70be943 100644
--- a/extensions/renderer/runtime_hooks_delegate.cc
+++ b/extensions/renderer/runtime_hooks_delegate.cc
@@ -12,6 +12,7 @@
 #include "extensions/common/extension.h"
 #include "extensions/common/manifest.h"
 #include "extensions/renderer/bindings/api_signature.h"
+#include "extensions/renderer/get_script_context.h"
 #include "extensions/renderer/message_target.h"
 #include "extensions/renderer/messaging_util.h"
 #include "extensions/renderer/native_renderer_messaging_service.h"
@@ -31,8 +32,7 @@
   v8::HandleScope handle_scope(isolate);
   v8::Local<v8::Context> context = info.Holder()->CreationContext();
 
-  ScriptContext* script_context =
-      ScriptContextSet::GetContextByV8Context(context);
+  ScriptContext* script_context = GetScriptContextFromV8Context(context);
   // This could potentially be invoked after the script context is removed
   // (unlike the handler calls, which should only be invoked for valid
   // contexts).
@@ -76,9 +76,7 @@
       {&RuntimeHooksDelegate::HandleSendNativeMessage, kSendNativeMessage},
   };
 
-  ScriptContext* script_context =
-      ScriptContextSet::GetContextByV8Context(context);
-  DCHECK(script_context);
+  ScriptContext* script_context = GetScriptContextFromV8ContextChecked(context);
 
   Handler handler = nullptr;
   for (const auto& handler_entry : kHandlers) {
diff --git a/gpu/command_buffer/client/buffer_tracker_unittest.cc b/gpu/command_buffer/client/buffer_tracker_unittest.cc
index b8d2a7d..c01197e 100644
--- a/gpu/command_buffer/client/buffer_tracker_unittest.cc
+++ b/gpu/command_buffer/client/buffer_tracker_unittest.cc
@@ -28,7 +28,7 @@
   MockClientCommandBufferImpl()
       : MockClientCommandBuffer(),
         context_lost_(false) {}
-  ~MockClientCommandBufferImpl() override {}
+  ~MockClientCommandBufferImpl() override = default;
 
   scoped_refptr<gpu::Buffer> CreateTransferBuffer(size_t size,
                                                   int32_t* id) override {
diff --git a/gpu/command_buffer/client/client_context_state.cc b/gpu/command_buffer/client/client_context_state.cc
index 1321423..5348624 100644
--- a/gpu/command_buffer/client/client_context_state.cc
+++ b/gpu/command_buffer/client/client_context_state.cc
@@ -9,11 +9,9 @@
 namespace gpu {
 namespace gles2 {
 
-ClientContextState::ClientContextState() {
-}
+ClientContextState::ClientContextState() = default;
 
-ClientContextState::~ClientContextState() {
-}
+ClientContextState::~ClientContextState() = default;
 
 void ClientContextState::SetViewport(
     GLint x, GLint y, GLsizei width, GLsizei height) {
diff --git a/gpu/command_buffer/client/client_test_helper.cc b/gpu/command_buffer/client/client_test_helper.cc
index cbfb70ee..3034dd0 100644
--- a/gpu/command_buffer/client/client_test_helper.cc
+++ b/gpu/command_buffer/client/client_test_helper.cc
@@ -20,9 +20,9 @@
 
 namespace gpu {
 
-FakeCommandBufferServiceBase::FakeCommandBufferServiceBase() {}
+FakeCommandBufferServiceBase::FakeCommandBufferServiceBase() = default;
 
-FakeCommandBufferServiceBase::~FakeCommandBufferServiceBase() {}
+FakeCommandBufferServiceBase::~FakeCommandBufferServiceBase() = default;
 
 CommandBuffer::State FakeCommandBufferServiceBase::GetState() {
   return state_;
@@ -105,7 +105,7 @@
   DelegateToFake();
 }
 
-MockClientCommandBuffer::~MockClientCommandBuffer() {}
+MockClientCommandBuffer::~MockClientCommandBuffer() = default;
 
 CommandBuffer::State MockClientCommandBuffer::GetLastState() {
   return GetState();
@@ -158,7 +158,7 @@
   DelegateToFake();
 }
 
-MockClientCommandBufferMockFlush::~MockClientCommandBufferMockFlush() {}
+MockClientCommandBufferMockFlush::~MockClientCommandBufferMockFlush() = default;
 
 void MockClientCommandBufferMockFlush::DelegateToFake() {
   MockClientCommandBuffer::DelegateToFake();
@@ -170,8 +170,8 @@
   MockClientCommandBuffer::Flush(put_offset);
 }
 
-MockClientGpuControl::MockClientGpuControl() {}
+MockClientGpuControl::MockClientGpuControl() = default;
 
-MockClientGpuControl::~MockClientGpuControl() {}
+MockClientGpuControl::~MockClientGpuControl() = default;
 
 }  // namespace gpu
diff --git a/gpu/command_buffer/client/command_buffer_direct_locked.h b/gpu/command_buffer/client/command_buffer_direct_locked.h
index a69ba1138..6a88e42 100644
--- a/gpu/command_buffer/client/command_buffer_direct_locked.h
+++ b/gpu/command_buffer/client/command_buffer_direct_locked.h
@@ -13,7 +13,7 @@
   explicit CommandBufferDirectLocked(
       TransferBufferManager* transfer_buffer_manager)
       : CommandBufferDirect(transfer_buffer_manager) {}
-  ~CommandBufferDirectLocked() override {}
+  ~CommandBufferDirectLocked() override = default;
 
   // Overridden from CommandBufferDirect
   void Flush(int32_t put_offset) override;
diff --git a/gpu/command_buffer/client/context_support.h b/gpu/command_buffer/client/context_support.h
index 92bccebe..f834281 100644
--- a/gpu/command_buffer/client/context_support.h
+++ b/gpu/command_buffer/client/context_support.h
@@ -80,8 +80,8 @@
       uint32_t texture_id) = 0;
 
  protected:
-  ContextSupport() {}
-  virtual ~ContextSupport() {}
+  ContextSupport() = default;
+  virtual ~ContextSupport() = default;
 };
 
 }
diff --git a/gpu/command_buffer/client/gles2_cmd_helper.cc b/gpu/command_buffer/client/gles2_cmd_helper.cc
index d52970a..362cadf7 100644
--- a/gpu/command_buffer/client/gles2_cmd_helper.cc
+++ b/gpu/command_buffer/client/gles2_cmd_helper.cc
@@ -11,8 +11,7 @@
     : CommandBufferHelper(command_buffer) {
 }
 
-GLES2CmdHelper::~GLES2CmdHelper() {
-}
+GLES2CmdHelper::~GLES2CmdHelper() = default;
 
 }  // namespace gles2
 }  // namespace gpu
diff --git a/gpu/command_buffer/client/gles2_implementation.cc b/gpu/command_buffer/client/gles2_implementation.cc
index ce225c9d..4daba143 100644
--- a/gpu/command_buffer/client/gles2_implementation.cc
+++ b/gpu/command_buffer/client/gles2_implementation.cc
@@ -107,11 +107,9 @@
 const unsigned int GLES2Implementation::kStartingOffset;
 #endif
 
-GLES2Implementation::GLStaticState::GLStaticState() {
-}
+GLES2Implementation::GLStaticState::GLStaticState() = default;
 
-GLES2Implementation::GLStaticState::~GLStaticState() {
-}
+GLES2Implementation::GLStaticState::~GLStaticState() = default;
 
 GLES2Implementation::SingleThreadChecker::SingleThreadChecker(
     GLES2Implementation* gles2_implementation)
diff --git a/gpu/command_buffer/client/gles2_implementation_unittest.cc b/gpu/command_buffer/client/gles2_implementation_unittest.cc
index b2d17463..2fd5ae0 100644
--- a/gpu/command_buffer/client/gles2_implementation_unittest.cc
+++ b/gpu/command_buffer/client/gles2_implementation_unittest.cc
@@ -130,7 +130,7 @@
     }
   }
 
-  ~MockTransferBuffer() override {}
+  ~MockTransferBuffer() override = default;
 
   base::SharedMemoryHandle shared_memory_handle() const override;
   bool Initialize(unsigned int starting_buffer_size,
diff --git a/gpu/command_buffer/client/gles2_interface.h b/gpu/command_buffer/client/gles2_interface.h
index 86a385f8..e1e1ef4 100644
--- a/gpu/command_buffer/client/gles2_interface.h
+++ b/gpu/command_buffer/client/gles2_interface.h
@@ -23,8 +23,8 @@
 // This class is the interface for all client side GL functions.
 class GLES2Interface {
  public:
-  GLES2Interface() {}
-  virtual ~GLES2Interface() {}
+  GLES2Interface() = default;
+  virtual ~GLES2Interface() = default;
 
   virtual void FreeSharedMemory(void*) {};
 
diff --git a/gpu/command_buffer/client/gles2_interface_stub.cc b/gpu/command_buffer/client/gles2_interface_stub.cc
index 3f4d7baf..eef1481 100644
--- a/gpu/command_buffer/client/gles2_interface_stub.cc
+++ b/gpu/command_buffer/client/gles2_interface_stub.cc
@@ -7,11 +7,9 @@
 namespace gpu {
 namespace gles2 {
 
-GLES2InterfaceStub::GLES2InterfaceStub() {
-}
+GLES2InterfaceStub::GLES2InterfaceStub() = default;
 
-GLES2InterfaceStub::~GLES2InterfaceStub() {
-}
+GLES2InterfaceStub::~GLES2InterfaceStub() = default;
 
 // Include the auto-generated part of this class. We split this because
 // it means we can easily edit the non-auto generated parts right here in
diff --git a/gpu/command_buffer/client/gles2_trace_implementation.cc b/gpu/command_buffer/client/gles2_trace_implementation.cc
index 782a7cd..8e5c2f9 100644
--- a/gpu/command_buffer/client/gles2_trace_implementation.cc
+++ b/gpu/command_buffer/client/gles2_trace_implementation.cc
@@ -12,8 +12,7 @@
     : gl_(gl) {
 }
 
-GLES2TraceImplementation::~GLES2TraceImplementation() {
-}
+GLES2TraceImplementation::~GLES2TraceImplementation() = default;
 
 // Include the auto-generated part of this file. We split this because it means
 // we can easily edit the non-auto generated parts right here in this file
diff --git a/gpu/command_buffer/client/gpu_control.h b/gpu/command_buffer/client/gpu_control.h
index 35eabb82..60dca3f 100644
--- a/gpu/command_buffer/client/gpu_control.h
+++ b/gpu/command_buffer/client/gpu_control.h
@@ -31,8 +31,8 @@
 // Common interface for GpuControl implementations.
 class GPU_EXPORT GpuControl {
  public:
-  GpuControl() {}
-  virtual ~GpuControl() {}
+  GpuControl() = default;
+  virtual ~GpuControl() = default;
 
   virtual void SetGpuControlClient(GpuControlClient* gpu_control_client) = 0;
 
diff --git a/gpu/command_buffer/client/gpu_memory_buffer_manager.cc b/gpu/command_buffer/client/gpu_memory_buffer_manager.cc
index dbfa593..ecd7306 100644
--- a/gpu/command_buffer/client/gpu_memory_buffer_manager.cc
+++ b/gpu/command_buffer/client/gpu_memory_buffer_manager.cc
@@ -6,10 +6,8 @@
 
 namespace gpu {
 
-GpuMemoryBufferManager::GpuMemoryBufferManager() {
-}
+GpuMemoryBufferManager::GpuMemoryBufferManager() = default;
 
-GpuMemoryBufferManager::~GpuMemoryBufferManager() {
-}
+GpuMemoryBufferManager::~GpuMemoryBufferManager() = default;
 
 }  // namespace gpu
diff --git a/gpu/command_buffer/client/mapped_memory.cc b/gpu/command_buffer/client/mapped_memory.cc
index 067c926d..053c551e 100644
--- a/gpu/command_buffer/client/mapped_memory.cc
+++ b/gpu/command_buffer/client/mapped_memory.cc
@@ -40,7 +40,7 @@
                  helper,
                  shm->memory()) {}
 
-MemoryChunk::~MemoryChunk() {}
+MemoryChunk::~MemoryChunk() = default;
 
 MappedMemoryManager::MappedMemoryManager(CommandBufferHelper* helper,
                                          size_t unused_memory_reclaim_limit)
diff --git a/gpu/command_buffer/client/program_info_manager.cc b/gpu/command_buffer/client/program_info_manager.cc
index d16251d..bc15d41 100644
--- a/gpu/command_buffer/client/program_info_manager.cc
+++ b/gpu/command_buffer/client/program_info_manager.cc
@@ -34,8 +34,7 @@
       name(_name) {
 }
 
-ProgramInfoManager::Program::VertexAttrib::~VertexAttrib() {
-}
+ProgramInfoManager::Program::VertexAttrib::~VertexAttrib() = default;
 
 ProgramInfoManager::Program::UniformInfo::UniformInfo(
     GLsizei _size, GLenum _type, const std::string& _name)
@@ -49,8 +48,7 @@
 ProgramInfoManager::Program::UniformInfo::UniformInfo(
     const UniformInfo& other) = default;
 
-ProgramInfoManager::Program::UniformInfo::~UniformInfo() {
-}
+ProgramInfoManager::Program::UniformInfo::~UniformInfo() = default;
 
 ProgramInfoManager::Program::UniformES3::UniformES3()
     : block_index(-1),
@@ -60,8 +58,7 @@
       is_row_major(0) {
 }
 
-ProgramInfoManager::Program::UniformES3::~UniformES3() {
-}
+ProgramInfoManager::Program::UniformES3::~UniformES3() = default;
 
 ProgramInfoManager::Program::UniformBlock::UniformBlock()
     : binding(0),
@@ -73,8 +70,7 @@
 ProgramInfoManager::Program::UniformBlock::UniformBlock(
     const UniformBlock& other) = default;
 
-ProgramInfoManager::Program::UniformBlock::~UniformBlock() {
-}
+ProgramInfoManager::Program::UniformBlock::~UniformBlock() = default;
 
 ProgramInfoManager::Program::TransformFeedbackVarying::
 TransformFeedbackVarying()
@@ -83,8 +79,7 @@
 }
 
 ProgramInfoManager::Program::TransformFeedbackVarying::
-~TransformFeedbackVarying() {
-}
+    ~TransformFeedbackVarying() = default;
 
 ProgramInfoManager::Program::Program()
     : cached_es2_(false),
@@ -101,8 +96,7 @@
 
 ProgramInfoManager::Program::Program(const Program& other) = default;
 
-ProgramInfoManager::Program::~Program() {
-}
+ProgramInfoManager::Program::~Program() = default;
 
 // TODO(gman): Add a faster lookup.
 GLint ProgramInfoManager::Program::GetAttribLocation(
@@ -591,12 +585,9 @@
   }
 }
 
+ProgramInfoManager::ProgramInfoManager() = default;
 
-ProgramInfoManager::ProgramInfoManager() {
-}
-
-ProgramInfoManager::~ProgramInfoManager() {
-}
+ProgramInfoManager::~ProgramInfoManager() = default;
 
 ProgramInfoManager::Program* ProgramInfoManager::GetProgramInfo(
     GLES2Implementation* gl, GLuint program, ProgramInfoType type) {
diff --git a/gpu/command_buffer/client/program_info_manager_unittest.cc b/gpu/command_buffer/client/program_info_manager_unittest.cc
index 19aa12e..830ccade 100644
--- a/gpu/command_buffer/client/program_info_manager_unittest.cc
+++ b/gpu/command_buffer/client/program_info_manager_unittest.cc
@@ -26,8 +26,8 @@
 
 class ProgramInfoManagerTest : public testing::Test {
  public:
-  ProgramInfoManagerTest() {}
-  ~ProgramInfoManagerTest() override {}
+  ProgramInfoManagerTest() = default;
+  ~ProgramInfoManagerTest() override = default;
 
  protected:
   typedef ProgramInfoManager::Program Program;
diff --git a/gpu/command_buffer/client/query_tracker.h b/gpu/command_buffer/client/query_tracker.h
index 7d104ac..cbb6a28 100644
--- a/gpu/command_buffer/client/query_tracker.h
+++ b/gpu/command_buffer/client/query_tracker.h
@@ -58,7 +58,7 @@
   struct QueryInfo {
     QueryInfo(Bucket* bucket, uint32_t index)
         : bucket(bucket), sync(bucket->syncs + index) {}
-    QueryInfo() {}
+    QueryInfo() = default;
 
     uint32_t index() const { return sync - bucket->syncs; }
 
diff --git a/gpu/command_buffer/client/share_group.cc b/gpu/command_buffer/client/share_group.cc
index 5c4e4da2..f6947f5 100644
--- a/gpu/command_buffer/client/share_group.cc
+++ b/gpu/command_buffer/client/share_group.cc
@@ -20,7 +20,7 @@
 namespace gles2 {
 
 ShareGroupContextData::IdHandlerData::IdHandlerData() : flush_generation_(0) {}
-ShareGroupContextData::IdHandlerData::~IdHandlerData() {}
+ShareGroupContextData::IdHandlerData::~IdHandlerData() = default;
 
 static_assert(gpu::kInvalidResource == 0,
               "GL expects kInvalidResource to be 0");
@@ -28,8 +28,8 @@
 // The standard id handler.
 class IdHandler : public IdHandlerInterface {
  public:
-  IdHandler() { }
-  ~IdHandler() override {}
+  IdHandler() = default;
+  ~IdHandler() override = default;
 
   // Overridden from IdHandlerInterface.
   void MakeIds(GLES2Implementation* /* gl_impl */,
@@ -111,7 +111,7 @@
 class StrictIdHandler : public IdHandlerInterface {
  public:
   explicit StrictIdHandler(int id_namespace) : id_namespace_(id_namespace) {}
-  ~StrictIdHandler() override {}
+  ~StrictIdHandler() override = default;
 
   // Overridden from IdHandler.
   void MakeIds(GLES2Implementation* gl_impl,
@@ -263,7 +263,7 @@
 class NonReusedIdHandler : public IdHandlerInterface {
  public:
   NonReusedIdHandler() : last_id_(0) {}
-  ~NonReusedIdHandler() override {}
+  ~NonReusedIdHandler() override = default;
 
   // Overridden from IdHandlerInterface.
   void MakeIds(GLES2Implementation* /* gl_impl */,
@@ -322,7 +322,7 @@
 
 class RangeIdHandler : public RangeIdHandlerInterface {
  public:
-  RangeIdHandler() {}
+  RangeIdHandler() = default;
 
   void MakeIdRange(GLES2Implementation* /*gl_impl*/,
                    GLsizei n,
@@ -393,7 +393,7 @@
   program_info_manager_.reset(manager);
 }
 
-ShareGroup::~ShareGroup() {}
+ShareGroup::~ShareGroup() = default;
 
 }  // namespace gles2
 }  // namespace gpu
diff --git a/gpu/command_buffer/client/share_group.h b/gpu/command_buffer/client/share_group.h
index 102be11f..7d074d1a 100644
--- a/gpu/command_buffer/client/share_group.h
+++ b/gpu/command_buffer/client/share_group.h
@@ -58,8 +58,8 @@
 // Base class for IdHandlers
 class IdHandlerInterface {
  public:
-  IdHandlerInterface() { }
-  virtual ~IdHandlerInterface() { }
+  IdHandlerInterface() = default;
+  virtual ~IdHandlerInterface() = default;
 
   // Makes some ids at or above id_offset.
   virtual void MakeIds(
@@ -100,8 +100,8 @@
 
 class RangeIdHandlerInterface {
  public:
-  RangeIdHandlerInterface() {}
-  virtual ~RangeIdHandlerInterface() {}
+  RangeIdHandlerInterface() = default;
+  virtual ~RangeIdHandlerInterface() = default;
 
   // Makes a continuous range of ids. Stores the first allocated id to
   // |first_id| or 0 if allocation failed.
diff --git a/gpu/command_buffer/client/transfer_buffer.h b/gpu/command_buffer/client/transfer_buffer.h
index fda4ac2..565b0fd 100644
--- a/gpu/command_buffer/client/transfer_buffer.h
+++ b/gpu/command_buffer/client/transfer_buffer.h
@@ -30,8 +30,8 @@
 // Interface for managing the transfer buffer.
 class GPU_EXPORT TransferBufferInterface {
  public:
-  TransferBufferInterface() { }
-  virtual ~TransferBufferInterface() { }
+  TransferBufferInterface() = default;
+  virtual ~TransferBufferInterface() = default;
 
   // Returns the shared memory's handle when the back end is base::SharedMemory.
   // Otherwise, this returns an invalid handle.
diff --git a/gpu/command_buffer/client/transfer_buffer_unittest.cc b/gpu/command_buffer/client/transfer_buffer_unittest.cc
index 595798a..c6d6561b 100644
--- a/gpu/command_buffer/client/transfer_buffer_unittest.cc
+++ b/gpu/command_buffer/client/transfer_buffer_unittest.cc
@@ -256,10 +256,8 @@
 
 class MockClientCommandBufferCanFail : public MockClientCommandBufferMockFlush {
  public:
-  MockClientCommandBufferCanFail() {
-  }
-  virtual ~MockClientCommandBufferCanFail() {
-  }
+  MockClientCommandBufferCanFail() = default;
+  virtual ~MockClientCommandBufferCanFail() = default;
 
   MOCK_METHOD2(CreateTransferBuffer,
                scoped_refptr<Buffer>(size_t size, int32_t* id));
diff --git a/gpu/command_buffer/common/buffer.cc b/gpu/command_buffer/common/buffer.cc
index c5f0d554..ad95154 100644
--- a/gpu/command_buffer/common/buffer.cc
+++ b/gpu/command_buffer/common/buffer.cc
@@ -23,7 +23,7 @@
     size_t size)
     : shared_memory_(std::move(shared_memory)), size_(size) {}
 
-SharedMemoryBufferBacking::~SharedMemoryBufferBacking() {}
+SharedMemoryBufferBacking::~SharedMemoryBufferBacking() = default;
 
 base::SharedMemoryHandle SharedMemoryBufferBacking::shared_memory_handle()
     const {
@@ -43,7 +43,7 @@
   DCHECK(memory_) << "The memory must be mapped to create a Buffer";
 }
 
-Buffer::~Buffer() {}
+Buffer::~Buffer() = default;
 
 void* Buffer::GetDataAddress(uint32_t data_offset, uint32_t data_size) const {
   base::CheckedNumeric<uint32_t> end = data_offset;
diff --git a/gpu/command_buffer/common/buffer.h b/gpu/command_buffer/common/buffer.h
index 475056e5..c008df7 100644
--- a/gpu/command_buffer/common/buffer.h
+++ b/gpu/command_buffer/common/buffer.h
@@ -27,7 +27,7 @@
 
 class GPU_EXPORT BufferBacking {
  public:
-  virtual ~BufferBacking() {}
+  virtual ~BufferBacking() = default;
   virtual base::SharedMemoryHandle shared_memory_handle() const;
   virtual void* GetMemory() const = 0;
   virtual size_t GetSize() const = 0;
diff --git a/gpu/command_buffer/common/capabilities.cc b/gpu/command_buffer/common/capabilities.cc
index a15dbe8..f774c89 100644
--- a/gpu/command_buffer/common/capabilities.cc
+++ b/gpu/command_buffer/common/capabilities.cc
@@ -6,10 +6,9 @@
 
 namespace gpu {
 
-Capabilities::PerStagePrecisions::PerStagePrecisions() {
-}
+Capabilities::PerStagePrecisions::PerStagePrecisions() = default;
 
-Capabilities::Capabilities() {}
+Capabilities::Capabilities() = default;
 
 Capabilities::Capabilities(const Capabilities& other) = default;
 
diff --git a/gpu/command_buffer/common/command_buffer.h b/gpu/command_buffer/common/command_buffer.h
index a438ba04..a99e0ba 100644
--- a/gpu/command_buffer/common/command_buffer.h
+++ b/gpu/command_buffer/common/command_buffer.h
@@ -65,11 +65,9 @@
     std::string message;
   };
 
-  CommandBuffer() {
-  }
+  CommandBuffer() = default;
 
-  virtual ~CommandBuffer() {
-  }
+  virtual ~CommandBuffer() = default;
 
   // Check if a value is between a start and end value, inclusive, allowing
   // for wrapping if start > end.
diff --git a/gpu/command_buffer/common/debug_marker_manager.cc b/gpu/command_buffer/common/debug_marker_manager.cc
index 5ac37d08..79f5b24d 100644
--- a/gpu/command_buffer/common/debug_marker_manager.cc
+++ b/gpu/command_buffer/common/debug_marker_manager.cc
@@ -12,8 +12,7 @@
       marker_(name) {
 }
 
-DebugMarkerManager::Group::~Group() {
-}
+DebugMarkerManager::Group::~Group() = default;
 
 void DebugMarkerManager::Group::SetMarker(const std::string& marker) {
   marker_ = name_ + "." + marker;
@@ -24,8 +23,7 @@
   group_stack_.push(Group(std::string()));
 }
 
-DebugMarkerManager::~DebugMarkerManager() {
-}
+DebugMarkerManager::~DebugMarkerManager() = default;
 
 void DebugMarkerManager::SetMarker(const std::string& marker) {
   group_stack_.top().SetMarker(marker);
diff --git a/gpu/command_buffer/common/id_allocator.cc b/gpu/command_buffer/common/id_allocator.cc
index 13a4abaa..b39b701 100644
--- a/gpu/command_buffer/common/id_allocator.cc
+++ b/gpu/command_buffer/common/id_allocator.cc
@@ -21,7 +21,7 @@
   used_ids_.insert(std::make_pair(0u, 0u));
 }
 
-IdAllocator::~IdAllocator() {}
+IdAllocator::~IdAllocator() = default;
 
 ResourceId IdAllocator::AllocateID() {
   return AllocateIDRange(1u);
diff --git a/gpu/command_buffer/common/unittest_main.cc b/gpu/command_buffer/common/unittest_main.cc
index cba4c3e1..3e6aea3 100644
--- a/gpu/command_buffer/common/unittest_main.cc
+++ b/gpu/command_buffer/common/unittest_main.cc
@@ -24,7 +24,7 @@
 GpuTestSuite::GpuTestSuite(int argc, char** argv)
     : base::TestSuite(argc, argv) {}
 
-GpuTestSuite::~GpuTestSuite() {}
+GpuTestSuite::~GpuTestSuite() = default;
 
 }  // namespace
 
diff --git a/gpu/command_buffer/service/async_api_interface.h b/gpu/command_buffer/service/async_api_interface.h
index 2b46ff1af..b8f75d06 100644
--- a/gpu/command_buffer/service/async_api_interface.h
+++ b/gpu/command_buffer/service/async_api_interface.h
@@ -20,8 +20,8 @@
 // is responsible for de-multiplexing commands and their arguments.
 class GPU_EXPORT AsyncAPIInterface {
  public:
-  AsyncAPIInterface() {}
-  virtual ~AsyncAPIInterface() {}
+  AsyncAPIInterface() = default;
+  virtual ~AsyncAPIInterface() = default;
 
   virtual void BeginDecoding() = 0;
   virtual void EndDecoding() = 0;
diff --git a/gpu/command_buffer/service/buffer_manager.cc b/gpu/command_buffer/service/buffer_manager.cc
index 4668db7..bbe2c33a 100644
--- a/gpu/command_buffer/service/buffer_manager.cc
+++ b/gpu/command_buffer/service/buffer_manager.cc
@@ -117,8 +117,7 @@
   DCHECK(shm.get() && GetShmPointer());
 }
 
-Buffer::MappedRange::~MappedRange() {
-}
+Buffer::MappedRange::~MappedRange() = default;
 
 void* Buffer::MappedRange::GetShmPointer() const {
   DCHECK(shm.get());
diff --git a/gpu/command_buffer/service/command_buffer_service.cc b/gpu/command_buffer/service/command_buffer_service.cc
index 6bef7a2..3d989386 100644
--- a/gpu/command_buffer/service/command_buffer_service.cc
+++ b/gpu/command_buffer/service/command_buffer_service.cc
@@ -27,7 +27,7 @@
  public:
   explicit MemoryBufferBacking(size_t size)
       : memory_(new char[size]), size_(size) {}
-  ~MemoryBufferBacking() override {}
+  ~MemoryBufferBacking() override = default;
   void* GetMemory() const override { return memory_.get(); }
   size_t GetSize() const override { return size_; }
 
@@ -48,7 +48,7 @@
   state_.token = 0;
 }
 
-CommandBufferService::~CommandBufferService() {}
+CommandBufferService::~CommandBufferService() = default;
 
 void CommandBufferService::UpdateState() {
   ++state_.generation;
diff --git a/gpu/command_buffer/service/command_buffer_service.h b/gpu/command_buffer/service/command_buffer_service.h
index 2a723cc4..8028d0e 100644
--- a/gpu/command_buffer/service/command_buffer_service.h
+++ b/gpu/command_buffer/service/command_buffer_service.h
@@ -22,7 +22,7 @@
 
 class GPU_EXPORT CommandBufferServiceBase {
  public:
-  virtual ~CommandBufferServiceBase() {}
+  virtual ~CommandBufferServiceBase() = default;
 
   // Gets the current state of the service.
   virtual CommandBuffer::State GetState() = 0;
@@ -53,7 +53,7 @@
     kPauseExecution,
   };
 
-  virtual ~CommandBufferServiceClient() {}
+  virtual ~CommandBufferServiceClient() = default;
 
   // Called every time a batch of commands was processed by the
   // CommandBufferService. The return value indicates whether the
diff --git a/gpu/command_buffer/service/common_decoder.cc b/gpu/command_buffer/service/common_decoder.cc
index e6a55d6..3db0e428c 100644
--- a/gpu/command_buffer/service/common_decoder.cc
+++ b/gpu/command_buffer/service/common_decoder.cc
@@ -32,7 +32,7 @@
 
 CommonDecoder::Bucket::Bucket() : size_(0) {}
 
-CommonDecoder::Bucket::~Bucket() {}
+CommonDecoder::Bucket::~Bucket() = default;
 
 void* CommonDecoder::Bucket::GetData(size_t offset, size_t size) const {
   if (OffsetSizeValid(offset, size)) {
@@ -132,7 +132,7 @@
   DCHECK(command_buffer_service_);
 }
 
-CommonDecoder::~CommonDecoder() {}
+CommonDecoder::~CommonDecoder() = default;
 
 void* CommonDecoder::GetAddressAndCheckSize(unsigned int shm_id,
                                             unsigned int data_offset,
diff --git a/gpu/command_buffer/service/context_group_unittest.cc b/gpu/command_buffer/service/context_group_unittest.cc
index 58c5951..b2b5ce2 100644
--- a/gpu/command_buffer/service/context_group_unittest.cc
+++ b/gpu/command_buffer/service/context_group_unittest.cc
@@ -39,7 +39,7 @@
  public:
   static const bool kBindGeneratesResource = false;
 
-  ContextGroupTest() {}
+  ContextGroupTest() = default;
 
  protected:
   void SetUp() override {
diff --git a/gpu/command_buffer/service/context_state.cc b/gpu/command_buffer/service/context_state.cc
index 104a743..b125c60 100644
--- a/gpu/command_buffer/service/context_state.cc
+++ b/gpu/command_buffer/service/context_state.cc
@@ -91,8 +91,7 @@
 
 TextureUnit::TextureUnit(const TextureUnit& other) = default;
 
-TextureUnit::~TextureUnit() {
-}
+TextureUnit::~TextureUnit() = default;
 
 bool Vec4::Equal(const Vec4& other) const {
   if (type_ != other.type_)
@@ -226,8 +225,7 @@
   Initialize();
 }
 
-ContextState::~ContextState() {
-}
+ContextState::~ContextState() = default;
 
 void ContextState::SetLineWidthBounds(GLfloat min, GLfloat max) {
   line_width_min_ = min;
diff --git a/gpu/command_buffer/service/error_state.cc b/gpu/command_buffer/service/error_state.cc
index 6e05c37..72c18d2 100644
--- a/gpu/command_buffer/service/error_state.cc
+++ b/gpu/command_buffer/service/error_state.cc
@@ -74,9 +74,9 @@
   DISALLOW_COPY_AND_ASSIGN(ErrorStateImpl);
 };
 
-ErrorState::ErrorState() {}
+ErrorState::ErrorState() = default;
 
-ErrorState::~ErrorState() {}
+ErrorState::~ErrorState() = default;
 
 ErrorState* ErrorState::Create(ErrorStateClient* client, Logger* logger) {
   return new ErrorStateImpl(client, logger);
@@ -85,7 +85,7 @@
 ErrorStateImpl::ErrorStateImpl(ErrorStateClient* client, Logger* logger)
     : error_bits_(0), client_(client), logger_(logger) {}
 
-ErrorStateImpl::~ErrorStateImpl() {}
+ErrorStateImpl::~ErrorStateImpl() = default;
 
 uint32_t ErrorStateImpl::GetGLError() {
   // Check the GL error first, then our wrapped error.
diff --git a/gpu/command_buffer/service/error_state_mock.cc b/gpu/command_buffer/service/error_state_mock.cc
index f3925d74..7417dde 100644
--- a/gpu/command_buffer/service/error_state_mock.cc
+++ b/gpu/command_buffer/service/error_state_mock.cc
@@ -10,7 +10,7 @@
 MockErrorState::MockErrorState()
     : ErrorState() {}
 
-MockErrorState::~MockErrorState() {}
+MockErrorState::~MockErrorState() = default;
 
 }  // namespace gles2
 }  // namespace gpu
diff --git a/gpu/command_buffer/service/feature_info.cc b/gpu/command_buffer/service/feature_info.cc
index 7c834e6..cbcb964 100644
--- a/gpu/command_buffer/service/feature_info.cc
+++ b/gpu/command_buffer/service/feature_info.cc
@@ -207,7 +207,7 @@
 
 }  // anonymous namespace.
 
-FeatureInfo::FeatureFlags::FeatureFlags() {}
+FeatureInfo::FeatureFlags::FeatureFlags() = default;
 
 FeatureInfo::FeatureInfo() {
   InitializeBasicState(base::CommandLine::InitializedForCurrentProcess()
@@ -1762,8 +1762,7 @@
   extensions_.insert(extension);
 }
 
-FeatureInfo::~FeatureInfo() {
-}
+FeatureInfo::~FeatureInfo() = default;
 
 }  // namespace gles2
 }  // namespace gpu
diff --git a/gpu/command_buffer/service/feature_info_unittest.cc b/gpu/command_buffer/service/feature_info_unittest.cc
index c26ac6ed..a20c906d 100644
--- a/gpu/command_buffer/service/feature_info_unittest.cc
+++ b/gpu/command_buffer/service/feature_info_unittest.cc
@@ -50,8 +50,7 @@
     : public GpuServiceTest,
       public ::testing::WithParamInterface<MockedGLVersionKind> {
  public:
-  FeatureInfoTest() {
-  }
+  FeatureInfoTest() = default;
 
   void SetupInitExpectations(const char* extensions) {
     std::string extensions_str = extensions;
diff --git a/gpu/command_buffer/service/framebuffer_completeness_cache.cc b/gpu/command_buffer/service/framebuffer_completeness_cache.cc
index 183b023..46b7539 100644
--- a/gpu/command_buffer/service/framebuffer_completeness_cache.cc
+++ b/gpu/command_buffer/service/framebuffer_completeness_cache.cc
@@ -7,9 +7,9 @@
 namespace gpu {
 namespace gles2 {
 
-FramebufferCompletenessCache::FramebufferCompletenessCache() {}
+FramebufferCompletenessCache::FramebufferCompletenessCache() = default;
 
-FramebufferCompletenessCache::~FramebufferCompletenessCache() {}
+FramebufferCompletenessCache::~FramebufferCompletenessCache() = default;
 
 bool FramebufferCompletenessCache::IsComplete(
     const std::string& signature) const {
diff --git a/gpu/command_buffer/service/framebuffer_manager.cc b/gpu/command_buffer/service/framebuffer_manager.cc
index 86ef51ed..8105f17 100644
--- a/gpu/command_buffer/service/framebuffer_manager.cc
+++ b/gpu/command_buffer/service/framebuffer_manager.cc
@@ -25,8 +25,7 @@
       bound_draw_framebuffer(NULL) {
 }
 
-DecoderFramebufferState::~DecoderFramebufferState() {
-}
+DecoderFramebufferState::~DecoderFramebufferState() = default;
 
 class RenderbufferAttachment
     : public Framebuffer::Attachment {
@@ -125,7 +124,7 @@
   bool EmulatingRGB() const override { return false; }
 
  protected:
-  ~RenderbufferAttachment() override {}
+  ~RenderbufferAttachment() override = default;
 
  private:
   scoped_refptr<Renderbuffer> renderbuffer_;
@@ -303,7 +302,7 @@
   }
 
  protected:
-  ~TextureAttachment() override {}
+  ~TextureAttachment() override = default;
 
  private:
   scoped_refptr<TextureRef> texture_ref_;
diff --git a/gpu/command_buffer/service/framebuffer_manager.h b/gpu/command_buffer/service/framebuffer_manager.h
index c29dc64..78c3255 100644
--- a/gpu/command_buffer/service/framebuffer_manager.h
+++ b/gpu/command_buffer/service/framebuffer_manager.h
@@ -73,7 +73,7 @@
 
    protected:
     friend class base::RefCounted<Attachment>;
-    virtual ~Attachment() {}
+    virtual ~Attachment() = default;
   };
 
   Framebuffer(FramebufferManager* manager, GLuint service_id);
diff --git a/gpu/command_buffer/service/framebuffer_manager_unittest.cc b/gpu/command_buffer/service/framebuffer_manager_unittest.cc
index 01551f9..04b71c5 100644
--- a/gpu/command_buffer/service/framebuffer_manager_unittest.cc
+++ b/gpu/command_buffer/service/framebuffer_manager_unittest.cc
@@ -1297,7 +1297,7 @@
  public:
   FramebufferInfoFloatTest()
       : FramebufferInfoTestBase(CONTEXT_TYPE_OPENGLES3) {}
-  ~FramebufferInfoFloatTest() override {}
+  ~FramebufferInfoFloatTest() override = default;
 
  protected:
   void SetUp() override {
diff --git a/gpu/command_buffer/service/gl_context_mock.cc b/gpu/command_buffer/service/gl_context_mock.cc
index ce5d10f..2ffb56b 100644
--- a/gpu/command_buffer/service/gl_context_mock.cc
+++ b/gpu/command_buffer/service/gl_context_mock.cc
@@ -6,9 +6,7 @@
 
 namespace gpu {
 
-GLContextMock::GLContextMock() {
-}
-GLContextMock::~GLContextMock() {
-}
+GLContextMock::GLContextMock() = default;
+GLContextMock::~GLContextMock() = default;
 
 }  // namespace gpu
diff --git a/gpu/command_buffer/service/gl_context_virtual_unittest.cc b/gpu/command_buffer/service/gl_context_virtual_unittest.cc
index e2566c9..fb9ab6c2 100644
--- a/gpu/command_buffer/service/gl_context_virtual_unittest.cc
+++ b/gpu/command_buffer/service/gl_context_virtual_unittest.cc
@@ -23,7 +23,7 @@
  public:
   GLContextVirtualTest()
       : decoder_(new MockGLES2Decoder(&command_buffer_service_, &outputter_)) {}
-  ~GLContextVirtualTest() override {}
+  ~GLContextVirtualTest() override = default;
 
  protected:
   FakeCommandBufferServiceBase command_buffer_service_;
diff --git a/gpu/command_buffer/service/gl_state_restorer_impl.cc b/gpu/command_buffer/service/gl_state_restorer_impl.cc
index f6509031..0ddc18daf 100644
--- a/gpu/command_buffer/service/gl_state_restorer_impl.cc
+++ b/gpu/command_buffer/service/gl_state_restorer_impl.cc
@@ -14,8 +14,7 @@
     : decoder_(decoder) {
 }
 
-GLStateRestorerImpl::~GLStateRestorerImpl() {
-}
+GLStateRestorerImpl::~GLStateRestorerImpl() = default;
 
 bool GLStateRestorerImpl::IsInitialized() {
   DCHECK(decoder_.get());
diff --git a/gpu/command_buffer/service/gl_stream_texture_image.h b/gpu/command_buffer/service/gl_stream_texture_image.h
index 423d3ff..8fb647a 100644
--- a/gpu/command_buffer/service/gl_stream_texture_image.h
+++ b/gpu/command_buffer/service/gl_stream_texture_image.h
@@ -28,7 +28,7 @@
                                    int display_height) = 0;
 
  protected:
-  ~GLStreamTextureImage() override {}
+  ~GLStreamTextureImage() override = default;
 
   // Convenience function for subclasses that deal with SurfaceTextures, whose
   // coordinate system has (0,0) at the bottom left of the image.
diff --git a/gpu/command_buffer/service/gl_surface_mock.cc b/gpu/command_buffer/service/gl_surface_mock.cc
index 9706a18e..67f41a9 100644
--- a/gpu/command_buffer/service/gl_surface_mock.cc
+++ b/gpu/command_buffer/service/gl_surface_mock.cc
@@ -6,9 +6,7 @@
 
 namespace gpu {
 
-GLSurfaceMock::GLSurfaceMock() {
-}
+GLSurfaceMock::GLSurfaceMock() = default;
 
-GLSurfaceMock::~GLSurfaceMock() {
-}
+GLSurfaceMock::~GLSurfaceMock() = default;
 }  // namespace gpu
diff --git a/gpu/command_buffer/service/gles2_cmd_copy_tex_image.cc b/gpu/command_buffer/service/gles2_cmd_copy_tex_image.cc
index a6c8daa..0b6bc36 100644
--- a/gpu/command_buffer/service/gles2_cmd_copy_tex_image.cc
+++ b/gpu/command_buffer/service/gles2_cmd_copy_tex_image.cc
@@ -31,7 +31,7 @@
   DCHECK(feature_info->gl_version_info().is_desktop_core_profile);
 }
 
-CopyTexImageResourceManager::~CopyTexImageResourceManager() {}
+CopyTexImageResourceManager::~CopyTexImageResourceManager() = default;
 
 void CopyTexImageResourceManager::Initialize(
     const gles2::GLES2Decoder* decoder) {
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.cc b/gpu/command_buffer/service/gles2_cmd_decoder.cc
index 1d2f930..30cc6326 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder.cc
@@ -512,8 +512,7 @@
   DCHECK(outputter_);
 }
 
-GLES2Decoder::~GLES2Decoder() {
-}
+GLES2Decoder::~GLES2Decoder() = default;
 
 void GLES2Decoder::BeginDecoding() {}
 
@@ -2882,6 +2881,7 @@
                                                 GLenum format,
                                                 bool zero) {
   DCHECK(format == GL_RGB || format == GL_RGBA);
+  bool is_cleared = false;
   scoped_refptr<gl::GLImage> image =
       decoder_->GetContextGroup()->image_factory()->CreateAnonymousImage(
           size,
@@ -2898,7 +2898,7 @@
               gfx::BufferFormat::RGBX_8888
 #endif
               : gfx::BufferFormat::RGBA_8888,
-          gfx::BufferUsage::SCANOUT, format);
+          gfx::BufferUsage::SCANOUT, format, &is_cleared);
   if (!image || !image->BindTexImage(Target()))
     return false;
 
@@ -2915,7 +2915,7 @@
   bool needs_clear_for_rgb_emulation =
       !decoder_->offscreen_buffer_should_have_alpha_ &&
       decoder_->ChromiumImageNeedsRGBEmulation();
-  if (zero || needs_clear_for_rgb_emulation) {
+  if (!is_cleared || zero || needs_clear_for_rgb_emulation) {
     GLuint fbo;
     api()->glGenFramebuffersEXTFn(1, &fbo);
     {
@@ -3193,8 +3193,7 @@
   DCHECK(group);
 }
 
-GLES2DecoderImpl::~GLES2DecoderImpl() {
-}
+GLES2DecoderImpl::~GLES2DecoderImpl() = default;
 
 base::WeakPtr<GLES2Decoder> GLES2DecoderImpl::AsWeakPtr() {
   return weak_ptr_factory_.GetWeakPtr();
@@ -5021,6 +5020,9 @@
     transform_feedback_manager_.reset();
   }
 
+  // Record this value before resetting the frame buffer below.
+  bool is_offscreen = !!offscreen_target_frame_buffer_;
+
   offscreen_target_frame_buffer_.reset();
   offscreen_target_color_texture_.reset();
   offscreen_target_color_render_buffer_.reset();
@@ -5050,6 +5052,13 @@
     group_ = NULL;
   }
 
+  // If this is not an offscreen surface then it shouldn't be shared and we
+  // should have the only remaining ref. Logging to debug crbug.com/787086
+  if (!is_offscreen && surface_ && !surface_->HasOneRef()) {
+    LOG(ERROR) << "crbug.com/787086: Decoder is not the sole owner of "
+                  "|surface_| at destruction time";
+  }
+
   // Destroy the surface before the context, some surface destructors make GL
   // calls.
   surface_ = nullptr;
@@ -18040,19 +18049,24 @@
     return;
   }
 
+  bool is_cleared = false;
   scoped_refptr<gl::GLImage> image =
       GetContextGroup()->image_factory()->CreateAnonymousImage(
           gfx::Size(width, height), buffer_format, gfx::BufferUsage::SCANOUT,
-          untyped_format);
+          untyped_format, &is_cleared);
   if (!image || !image->BindTexImage(target)) {
     LOCAL_SET_GL_ERROR(GL_INVALID_OPERATION, "glTexStorage2DImageCHROMIUM",
                        "Failed to create or bind GL Image");
     return;
   }
 
+  gfx::Rect cleared_rect;
+  if (is_cleared)
+    cleared_rect = gfx::Rect(width, height);
+
   texture_manager()->SetLevelInfo(
       texture_ref, target, 0, image->GetInternalFormat(), width, height, 1, 0,
-      image->GetInternalFormat(), GL_UNSIGNED_BYTE, gfx::Rect(width, height));
+      image->GetInternalFormat(), GL_UNSIGNED_BYTE, cleared_rect);
   texture_manager()->SetLevelImage(texture_ref, target, 0, image.get(),
                                    Texture::BOUND);
 
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.h b/gpu/command_buffer/service/gles2_cmd_decoder.h
index 5961d656..1779f7d 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder.h
+++ b/gpu/command_buffer/service/gles2_cmd_decoder.h
@@ -60,7 +60,7 @@
 struct ContextState;
 
 struct DisallowedFeatures {
-  DisallowedFeatures() {}
+  DisallowedFeatures() = default;
 
   void AllowExtensions() {
     chromium_color_buffer_float_rgba = false;
@@ -83,7 +83,7 @@
 
 class GPU_EXPORT GLES2DecoderClient {
  public:
-  virtual ~GLES2DecoderClient() {}
+  virtual ~GLES2DecoderClient() = default;
 
   // Prints a message (error/warning) to the console.
   virtual void OnConsoleMessage(int32_t id, const std::string& message) = 0;
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_mock.cc b/gpu/command_buffer/service/gles2_cmd_decoder_mock.cc
index 50511a5..05b0163 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_mock.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_mock.cc
@@ -17,7 +17,7 @@
       .WillByDefault(testing::Return(true));
 }
 
-MockGLES2Decoder::~MockGLES2Decoder() {}
+MockGLES2Decoder::~MockGLES2Decoder() = default;
 
 base::WeakPtr<GLES2Decoder> MockGLES2Decoder::AsWeakPtr() {
   return weak_ptr_factory_.GetWeakPtr();
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_passthrough.cc b/gpu/command_buffer/service/gles2_cmd_decoder_passthrough.cc
index d67d813..b5d6095 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_passthrough.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_passthrough.cc
@@ -76,9 +76,9 @@
 
 }  // anonymous namespace
 
-PassthroughResources::PassthroughResources() {}
+PassthroughResources::PassthroughResources() = default;
 
-PassthroughResources::~PassthroughResources() {}
+PassthroughResources::~PassthroughResources() = default;
 
 void PassthroughResources::Destroy(gl::GLApi* api) {
   bool have_context = !!api;
@@ -453,7 +453,7 @@
   DCHECK(group);
 }
 
-GLES2DecoderPassthroughImpl::~GLES2DecoderPassthroughImpl() {}
+GLES2DecoderPassthroughImpl::~GLES2DecoderPassthroughImpl() = default;
 
 GLES2Decoder::Error GLES2DecoderPassthroughImpl::DoCommands(
     unsigned int num_commands,
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc b/gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc
index a8292947..ecd91f45 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc
@@ -1101,7 +1101,7 @@
   uint64_t ShareGroupTracingGUID() const override { return 0; }
 
  private:
-  virtual ~SizeOnlyMemoryTracker() {}
+  virtual ~SizeOnlyMemoryTracker() = default;
   struct PoolInfo {
     PoolInfo() : initial_size(0), size(0) {}
     size_t initial_size;
@@ -1586,8 +1586,7 @@
 
 class GLES2DecoderDescheduleUntilFinishedTest : public GLES2DecoderTest {
  public:
-  GLES2DecoderDescheduleUntilFinishedTest() {
-  }
+  GLES2DecoderDescheduleUntilFinishedTest() = default;
 
   void SetUp() override {
     InitState init;
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest.h b/gpu/command_buffer/service/gles2_cmd_decoder_unittest.h
index 1c52ef4..80c31cf 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest.h
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest.h
@@ -29,7 +29,7 @@
 
 class GLES2DecoderTest : public GLES2DecoderTestBase {
  public:
-  GLES2DecoderTest() {}
+  GLES2DecoderTest() = default;
 
  protected:
   void CheckReadPixelsOutOfRange(GLint in_read_x,
@@ -49,14 +49,14 @@
 
 class GLES2DecoderRGBBackbufferTest : public GLES2DecoderWithShaderTest {
  public:
-  GLES2DecoderRGBBackbufferTest() {}
+  GLES2DecoderRGBBackbufferTest() = default;
 
   void SetUp() override;
 };
 
 class GLES2DecoderManualInitTest : public GLES2DecoderWithShaderTest {
  public:
-  GLES2DecoderManualInitTest() {}
+  GLES2DecoderManualInitTest() = default;
 
   // Override default setup so nothing gets setup.
   void SetUp() override {}
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_1.cc b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_1.cc
index 0cbd66e..9ea6081 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_1.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_1.cc
@@ -30,7 +30,7 @@
 
 class GLES2DecoderTest1 : public GLES2DecoderTestBase {
  public:
-  GLES2DecoderTest1() { }
+  GLES2DecoderTest1() = default;
 };
 
 class GLES3DecoderTest1 : public GLES2DecoderTest1 {
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_2.cc b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_2.cc
index e5d4701..0886f44 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_2.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_2.cc
@@ -33,7 +33,7 @@
 
 class GLES2DecoderTest2 : public GLES2DecoderTestBase {
  public:
-  GLES2DecoderTest2() { }
+  GLES2DecoderTest2() = default;
 
   void TestAcceptedUniform(GLenum uniform_type,
                            uint32_t accepts_apis,
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_3.cc b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_3.cc
index 5ffc9d3..689711f 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_3.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_3.cc
@@ -33,7 +33,7 @@
 
 class GLES2DecoderTest3 : public GLES2DecoderTestBase {
  public:
-  GLES2DecoderTest3() { }
+  GLES2DecoderTest3() = default;
 };
 
 class GLES3DecoderTest3 : public GLES2DecoderTest3 {
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_attribs.cc b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_attribs.cc
index 8cfa0a4..296481c 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_attribs.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_attribs.cc
@@ -274,7 +274,7 @@
 
 class GLES2DecoderVertexArraysOESTest : public GLES2DecoderWithShaderTest {
  public:
-  GLES2DecoderVertexArraysOESTest() {}
+  GLES2DecoderVertexArraysOESTest() = default;
 
   bool vertex_array_deleted_manually_;
 
@@ -414,7 +414,7 @@
 class GLES2DecoderEmulatedVertexArraysOESTest
     : public GLES2DecoderVertexArraysOESTest {
  public:
-  GLES2DecoderEmulatedVertexArraysOESTest() {}
+  GLES2DecoderEmulatedVertexArraysOESTest() = default;
 
   void SetUp() override {
     InitState init;
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.cc b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.cc
index fd6f1fe..d354ffa 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.cc
@@ -134,7 +134,7 @@
   memset(immediate_buffer_, 0xEE, sizeof(immediate_buffer_));
 }
 
-GLES2DecoderTestBase::~GLES2DecoderTestBase() {}
+GLES2DecoderTestBase::~GLES2DecoderTestBase() = default;
 
 void GLES2DecoderTestBase::OnConsoleMessage(int32_t id,
                                             const std::string& message) {}
@@ -2252,7 +2252,7 @@
   context_creation_attribs_.context_type = context_type;
 }
 
-GLES2DecoderPassthroughTestBase::~GLES2DecoderPassthroughTestBase() {}
+GLES2DecoderPassthroughTestBase::~GLES2DecoderPassthroughTestBase() = default;
 
 void GLES2DecoderPassthroughTestBase::OnConsoleMessage(
     int32_t id,
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.h b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.h
index a33772a30..698502a 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.h
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.h
@@ -739,8 +739,7 @@
           bound_vertex_array_object_(0) {
     }
 
-    ~MockGLStates() {
-    }
+    ~MockGLStates() = default;
 
     void OnBindArrayBuffer(GLuint id) {
       bound_array_buffer_object_ = id;
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_context_state.cc b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_context_state.cc
index 6c629c2c..3765e69 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_context_state.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_context_state.cc
@@ -68,7 +68,7 @@
 
 class GLES2DecoderRestoreStateTest : public GLES2DecoderManualInitTest {
  public:
-  GLES2DecoderRestoreStateTest() {}
+  GLES2DecoderRestoreStateTest() = default;
 
  protected:
   void AddExpectationsForActiveTexture(GLenum unit);
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_extensions.cc b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_extensions.cc
index 051e428a..fa98245 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_extensions.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_extensions.cc
@@ -27,7 +27,7 @@
 // enabled or extension is not present.
 class GLES2DecoderTestDisabledExtensions : public GLES2DecoderTest {
  public:
-  GLES2DecoderTestDisabledExtensions() {}
+  GLES2DecoderTestDisabledExtensions() = default;
 };
 INSTANTIATE_TEST_CASE_P(Service,
                         GLES2DecoderTestDisabledExtensions,
@@ -482,7 +482,7 @@
 
 class GLES2DecoderTestWithBlendEquationAdvanced : public GLES2DecoderTest {
  public:
-  GLES2DecoderTestWithBlendEquationAdvanced() {}
+  GLES2DecoderTestWithBlendEquationAdvanced() = default;
   void SetUp() override {
     InitState init;
     init.gl_version = "opengl es 2.0";
@@ -503,7 +503,7 @@
 class GLES2DecoderTestWithEXTMultisampleCompatibility
     : public GLES2DecoderTest {
  public:
-  GLES2DecoderTestWithEXTMultisampleCompatibility() {}
+  GLES2DecoderTestWithEXTMultisampleCompatibility() = default;
 
   void SetUp() override {
     InitState init;
@@ -523,7 +523,7 @@
 
 class GLES2DecoderTestWithBlendFuncExtended : public GLES2DecoderTest {
  public:
-  GLES2DecoderTestWithBlendFuncExtended() {}
+  GLES2DecoderTestWithBlendFuncExtended() = default;
   void SetUp() override {
     InitState init;
     init.gl_version = "opengl es 3.0";
@@ -543,7 +543,7 @@
 class GLES2DecoderTestWithCHROMIUMFramebufferMixedSamples
     : public GLES2DecoderTest {
  public:
-  GLES2DecoderTestWithCHROMIUMFramebufferMixedSamples() {}
+  GLES2DecoderTestWithCHROMIUMFramebufferMixedSamples() = default;
   void SetUp() override {
     InitState init;
     init.gl_version = "opengl es 3.1";
@@ -1726,7 +1726,7 @@
 
 class GLES2DecoderTestWithCHROMIUMRasterTransport : public GLES2DecoderTest {
  public:
-  GLES2DecoderTestWithCHROMIUMRasterTransport() {}
+  GLES2DecoderTestWithCHROMIUMRasterTransport() = default;
   void SetUp() override {
     InitState init;
     init.gl_version = "opengl es 2.0";
@@ -1746,7 +1746,7 @@
 
 class GLES3DecoderTestWithEXTWindowRectangles : public GLES3DecoderTest {
  public:
-  GLES3DecoderTestWithEXTWindowRectangles() {}
+  GLES3DecoderTestWithEXTWindowRectangles() = default;
   void SetUp() override {
     InitState init;
     init.context_type = CONTEXT_TYPE_OPENGLES3;
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_framebuffers.cc b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_framebuffers.cc
index 7031be8..74630da 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_framebuffers.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_framebuffers.cc
@@ -58,7 +58,7 @@
 
 class GLES2DecoderTestWithExtensionsOnGLES2 : public GLES2DecoderTest {
  public:
-  GLES2DecoderTestWithExtensionsOnGLES2() {}
+  GLES2DecoderTestWithExtensionsOnGLES2() = default;
 
   void SetUp() override {}
   void Init(const char* extensions) {
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_textures.cc b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_textures.cc
index 955a875..8ad4925 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_textures.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_textures.cc
@@ -53,7 +53,7 @@
 namespace {
 class EmulatingRGBImageStub : public gl::GLImageStub {
  protected:
-  ~EmulatingRGBImageStub() override {}
+  ~EmulatingRGBImageStub() override = default;
   bool EmulatingRGB() const override {
     return true;
   }
@@ -3729,7 +3729,7 @@
 
 class MockGLImage : public gl::GLImage {
  public:
-  MockGLImage() {}
+  MockGLImage() = default;
 
   // Overridden from gl::GLImage:
   MOCK_METHOD0(GetSize, gfx::Size());
@@ -3752,7 +3752,7 @@
                     const std::string&));
 
  protected:
-  virtual ~MockGLImage() {}
+  virtual ~MockGLImage() = default;
 };
 
 TEST_P(GLES2DecoderWithShaderTest, CopyTexImage) {
@@ -4118,7 +4118,7 @@
 
 class GLES2DecoderCompressedFormatsTest : public GLES2DecoderManualInitTest {
  public:
-  GLES2DecoderCompressedFormatsTest() {}
+  GLES2DecoderCompressedFormatsTest() = default;
 
   static bool ValueInArray(GLint value, GLint* array, GLint count) {
     for (GLint ii = 0; ii < count; ++ii) {
@@ -4313,7 +4313,7 @@
 class GLES2DecoderTexStorageFormatAndTypeTest
     : public GLES2DecoderManualInitTest {
  public:
-  GLES2DecoderTexStorageFormatAndTypeTest() {}
+  GLES2DecoderTexStorageFormatAndTypeTest() = default;
 
   void DoTexStorageFormatAndType(const InitState& init,
                                  GLenum format,
diff --git a/gpu/command_buffer/service/gles2_cmd_srgb_converter.cc b/gpu/command_buffer/service/gles2_cmd_srgb_converter.cc
index 10fe75b..4ce108a 100644
--- a/gpu/command_buffer/service/gles2_cmd_srgb_converter.cc
+++ b/gpu/command_buffer/service/gles2_cmd_srgb_converter.cc
@@ -30,9 +30,7 @@
     : feature_info_(feature_info) {
 }
 
-SRGBConverter::~SRGBConverter() {}
-
-
+SRGBConverter::~SRGBConverter() = default;
 
 void SRGBConverter::InitializeSRGBConverterProgram() {
   if (srgb_converter_program_) {
diff --git a/gpu/command_buffer/service/gles2_cmd_validation.h b/gpu/command_buffer/service/gles2_cmd_validation.h
index 179946e..0368e63d 100644
--- a/gpu/command_buffer/service/gles2_cmd_validation.h
+++ b/gpu/command_buffer/service/gles2_cmd_validation.h
@@ -18,7 +18,7 @@
 template <typename T>
 class ValueValidator {
  public:
-  ValueValidator() {}
+  ValueValidator() = default;
 
   ValueValidator(const T* valid_values, int num_values) {
     AddValues(valid_values, num_values);
diff --git a/gpu/command_buffer/service/gpu_preferences.cc b/gpu/command_buffer/service/gpu_preferences.cc
index 2baca5ba..bc49a864 100644
--- a/gpu/command_buffer/service/gpu_preferences.cc
+++ b/gpu/command_buffer/service/gpu_preferences.cc
@@ -10,6 +10,6 @@
 
 GpuPreferences::GpuPreferences(const GpuPreferences& other) = default;
 
-GpuPreferences::~GpuPreferences() {}
+GpuPreferences::~GpuPreferences() = default;
 
 }  // namespace gpu
diff --git a/gpu/command_buffer/service/gpu_state_tracer.cc b/gpu/command_buffer/service/gpu_state_tracer.cc
index f26d3df..566fe289 100644
--- a/gpu/command_buffer/service/gpu_state_tracer.cc
+++ b/gpu/command_buffer/service/gpu_state_tracer.cc
@@ -22,7 +22,7 @@
  public:
   static std::unique_ptr<Snapshot> Create(const ContextState* state);
 
-  ~Snapshot() override {}
+  ~Snapshot() override = default;
 
   // Save a screenshot of the currently bound framebuffer.
   bool SaveScreenshot(const gfx::Size& size);
diff --git a/gpu/command_buffer/service/gpu_tracer.cc b/gpu/command_buffer/service/gpu_tracer.cc
index e3f8f63..748dcc7 100644
--- a/gpu/command_buffer/service/gpu_tracer.cc
+++ b/gpu/command_buffer/service/gpu_tracer.cc
@@ -41,7 +41,7 @@
 
 TraceMarker::TraceMarker(const TraceMarker& other) = default;
 
-TraceMarker::~TraceMarker() {}
+TraceMarker::~TraceMarker() = default;
 
 TraceOutputter::TraceOutputter() : named_thread_("Dummy Trace") {}
 
@@ -50,7 +50,7 @@
   named_thread_.Stop();
 }
 
-TraceOutputter::~TraceOutputter() {}
+TraceOutputter::~TraceOutputter() = default;
 
 void TraceOutputter::TraceDevice(GpuTracerSource source,
                                  const std::string& category,
@@ -130,7 +130,7 @@
     gpu_timer_ = gpu_timing_client->CreateGPUTimer(false);
 }
 
-GPUTrace::~GPUTrace() {}
+GPUTrace::~GPUTrace() = default;
 
 void GPUTrace::Destroy(bool have_context) {
   if (gpu_timer_.get()) {
@@ -188,7 +188,7 @@
   disjoint_time_ = gpu_timing_client_->GetCurrentCPUTime();
 }
 
-GPUTracer::~GPUTracer() {}
+GPUTracer::~GPUTracer() = default;
 
 void GPUTracer::Destroy(bool have_context) {
   ClearOngoingTraces(have_context);
diff --git a/gpu/command_buffer/service/gpu_tracer.h b/gpu/command_buffer/service/gpu_tracer.h
index 654c64c8..423ece7b 100644
--- a/gpu/command_buffer/service/gpu_tracer.h
+++ b/gpu/command_buffer/service/gpu_tracer.h
@@ -105,7 +105,7 @@
 
 class GPU_EXPORT Outputter {
  public:
-  virtual ~Outputter() {}
+  virtual ~Outputter() = default;
 
   virtual void TraceDevice(GpuTracerSource source,
                            const std::string& category,
diff --git a/gpu/command_buffer/service/gpu_tracer_unittest.cc b/gpu/command_buffer/service/gpu_tracer_unittest.cc
index 1b00d6c..2fe1ca8 100644
--- a/gpu/command_buffer/service/gpu_tracer_unittest.cc
+++ b/gpu/command_buffer/service/gpu_tracer_unittest.cc
@@ -33,8 +33,8 @@
 
 class MockOutputter : public Outputter {
  public:
-  MockOutputter() {}
-  ~MockOutputter() override {}
+  MockOutputter() = default;
+  ~MockOutputter() override = default;
 
   MOCK_METHOD5(TraceDevice,
                void(GpuTracerSource source,
@@ -61,7 +61,7 @@
     gpu_trace_dev_category = &tracing_enabled_;
   }
 
-  ~GPUTracerTester() override {}
+  ~GPUTracerTester() override = default;
 
   void SetTracingEnabled(bool enabled) {
     tracing_enabled_ = enabled ? 1 : 0;
diff --git a/gpu/command_buffer/service/id_manager.cc b/gpu/command_buffer/service/id_manager.cc
index be60d7b..5a508a55 100644
--- a/gpu/command_buffer/service/id_manager.cc
+++ b/gpu/command_buffer/service/id_manager.cc
@@ -8,9 +8,9 @@
 namespace gpu {
 namespace gles2 {
 
-IdManager::IdManager() {}
+IdManager::IdManager() = default;
 
-IdManager::~IdManager() {}
+IdManager::~IdManager() = default;
 
 bool IdManager::AddMapping(GLuint client_id, GLuint service_id) {
   std::pair<MapType::iterator, bool> result = id_map_.insert(
diff --git a/gpu/command_buffer/service/id_manager_unittest.cc b/gpu/command_buffer/service/id_manager_unittest.cc
index 9a6e56776..5a56d32 100644
--- a/gpu/command_buffer/service/id_manager_unittest.cc
+++ b/gpu/command_buffer/service/id_manager_unittest.cc
@@ -10,8 +10,7 @@
 
 class IdManagerTest : public testing::Test {
  public:
-  IdManagerTest() {
-  }
+  IdManagerTest() = default;
 
  protected:
   void SetUp() override {}
diff --git a/gpu/command_buffer/service/image_factory.cc b/gpu/command_buffer/service/image_factory.cc
index 0266ca0..9df2fb1 100644
--- a/gpu/command_buffer/service/image_factory.cc
+++ b/gpu/command_buffer/service/image_factory.cc
@@ -8,17 +8,16 @@
 
 namespace gpu {
 
-ImageFactory::ImageFactory() {
-}
+ImageFactory::ImageFactory() = default;
 
-ImageFactory::~ImageFactory() {
-}
+ImageFactory::~ImageFactory() = default;
 
 scoped_refptr<gl::GLImage> ImageFactory::CreateAnonymousImage(
     const gfx::Size& size,
     gfx::BufferFormat format,
     gfx::BufferUsage usage,
-    unsigned internalformat) {
+    unsigned internalformat,
+    bool* is_cleared) {
   NOTREACHED();
   return nullptr;
 }
diff --git a/gpu/command_buffer/service/image_factory.h b/gpu/command_buffer/service/image_factory.h
index 4f5c1fb..3e032fc4 100644
--- a/gpu/command_buffer/service/image_factory.h
+++ b/gpu/command_buffer/service/image_factory.h
@@ -38,7 +38,8 @@
       const gfx::Size& size,
       gfx::BufferFormat format,
       gfx::BufferUsage usage,
-      unsigned internalformat);
+      unsigned internalformat,
+      bool* is_cleared);
 
   // An image can only be bound to a texture with the appropriate type.
   virtual unsigned RequiredTextureType();
diff --git a/gpu/command_buffer/service/image_manager.cc b/gpu/command_buffer/service/image_manager.cc
index 6e9a5ba..5a0611c 100644
--- a/gpu/command_buffer/service/image_manager.cc
+++ b/gpu/command_buffer/service/image_manager.cc
@@ -12,11 +12,9 @@
 namespace gpu {
 namespace gles2 {
 
-ImageManager::ImageManager() {
-}
+ImageManager::ImageManager() = default;
 
-ImageManager::~ImageManager() {
-}
+ImageManager::~ImageManager() = default;
 
 void ImageManager::AddImage(gl::GLImage* image, int32_t service_id) {
   DCHECK(images_.find(service_id) == images_.end());
diff --git a/gpu/command_buffer/service/indexed_buffer_binding_host.cc b/gpu/command_buffer/service/indexed_buffer_binding_host.cc
index 454c306..967cb1cf 100644
--- a/gpu/command_buffer/service/indexed_buffer_binding_host.cc
+++ b/gpu/command_buffer/service/indexed_buffer_binding_host.cc
@@ -25,8 +25,8 @@
       effective_full_buffer_size(other.effective_full_buffer_size) {
 }
 
-IndexedBufferBindingHost::IndexedBufferBinding::~IndexedBufferBinding() {
-}
+IndexedBufferBindingHost::IndexedBufferBinding::~IndexedBufferBinding() =
+    default;
 
 bool IndexedBufferBindingHost::IndexedBufferBinding::operator==(
     const IndexedBufferBindingHost::IndexedBufferBinding& other) const {
@@ -84,8 +84,7 @@
   buffer_bindings_.resize(max_bindings);
 }
 
-IndexedBufferBindingHost::~IndexedBufferBindingHost() {
-}
+IndexedBufferBindingHost::~IndexedBufferBindingHost() = default;
 
 void IndexedBufferBindingHost::DoBindBufferBase(
     GLenum target, GLuint index, Buffer* buffer) {
diff --git a/gpu/command_buffer/service/indexed_buffer_binding_host_unittest.cc b/gpu/command_buffer/service/indexed_buffer_binding_host_unittest.cc
index bab9918..6d126f48 100644
--- a/gpu/command_buffer/service/indexed_buffer_binding_host_unittest.cc
+++ b/gpu/command_buffer/service/indexed_buffer_binding_host_unittest.cc
@@ -26,7 +26,7 @@
     DCHECK(buffer_.get());
   }
 
-  ~IndexedBufferBindingHostTest() override {}
+  ~IndexedBufferBindingHostTest() override = default;
 
  protected:
   void SetUp() override {
diff --git a/gpu/command_buffer/service/logger.cc b/gpu/command_buffer/service/logger.cc
index 61b2f0d..7b9d726 100644
--- a/gpu/command_buffer/service/logger.cc
+++ b/gpu/command_buffer/service/logger.cc
@@ -25,7 +25,7 @@
       base::HexEncode(&this_temp, sizeof(this_temp));
 }
 
-Logger::~Logger() {}
+Logger::~Logger() = default;
 
 void Logger::LogMessage(
     const char* filename, int line, const std::string& msg) {
diff --git a/gpu/command_buffer/service/mailbox_manager.h b/gpu/command_buffer/service/mailbox_manager.h
index 3c7234c..cf3db3e 100644
--- a/gpu/command_buffer/service/mailbox_manager.h
+++ b/gpu/command_buffer/service/mailbox_manager.h
@@ -23,7 +23,7 @@
 // Manages resources scoped beyond the context or context group level.
 class GPU_EXPORT MailboxManager {
  public:
-  virtual ~MailboxManager() {}
+  virtual ~MailboxManager() = default;
 
   // Look up the texture definition from the named mailbox.
   virtual TextureBase* ConsumeTexture(const Mailbox& mailbox) = 0;
diff --git a/gpu/command_buffer/service/mailbox_manager_impl.cc b/gpu/command_buffer/service/mailbox_manager_impl.cc
index a1df7f1..f62fce99 100644
--- a/gpu/command_buffer/service/mailbox_manager_impl.cc
+++ b/gpu/command_buffer/service/mailbox_manager_impl.cc
@@ -13,8 +13,7 @@
 namespace gpu {
 namespace gles2 {
 
-MailboxManagerImpl::MailboxManagerImpl() {
-}
+MailboxManagerImpl::MailboxManagerImpl() = default;
 
 MailboxManagerImpl::~MailboxManagerImpl() {
   DCHECK(mailbox_to_textures_.empty());
diff --git a/gpu/command_buffer/service/mailbox_manager_sync.cc b/gpu/command_buffer/service/mailbox_manager_sync.cc
index d26ee57..6427cd6a 100644
--- a/gpu/command_buffer/service/mailbox_manager_sync.cc
+++ b/gpu/command_buffer/service/mailbox_manager_sync.cc
@@ -97,8 +97,7 @@
     : definition_(definition) {
 }
 
-MailboxManagerSync::TextureGroup::~TextureGroup() {
-}
+MailboxManagerSync::TextureGroup::~TextureGroup() = default;
 
 void MailboxManagerSync::TextureGroup::AddName(const Mailbox& name) {
   g_lock.Get().AssertAcquired();
@@ -170,11 +169,9 @@
 MailboxManagerSync::TextureGroupRef::TextureGroupRef(
     const TextureGroupRef& other) = default;
 
-MailboxManagerSync::TextureGroupRef::~TextureGroupRef() {
-}
+MailboxManagerSync::TextureGroupRef::~TextureGroupRef() = default;
 
-MailboxManagerSync::MailboxManagerSync() {
-}
+MailboxManagerSync::MailboxManagerSync() = default;
 
 MailboxManagerSync::~MailboxManagerSync() {
   DCHECK_EQ(0U, texture_to_group_.size());
diff --git a/gpu/command_buffer/service/mailbox_manager_unittest.cc b/gpu/command_buffer/service/mailbox_manager_unittest.cc
index 846f259..2f5d755e 100644
--- a/gpu/command_buffer/service/mailbox_manager_unittest.cc
+++ b/gpu/command_buffer/service/mailbox_manager_unittest.cc
@@ -27,8 +27,8 @@
 
 class MailboxManagerTest : public GpuServiceTest {
  public:
-  MailboxManagerTest() {}
-  ~MailboxManagerTest() override {}
+  MailboxManagerTest() = default;
+  ~MailboxManagerTest() override = default;
 
  protected:
   void SetUp() override {
@@ -190,8 +190,8 @@
 
 class MailboxManagerSyncTest : public MailboxManagerTest {
  public:
-  MailboxManagerSyncTest() {}
-  ~MailboxManagerSyncTest() override {}
+  MailboxManagerSyncTest() = default;
+  ~MailboxManagerSyncTest() override = default;
 
  protected:
   void SetUp() override {
diff --git a/gpu/command_buffer/service/memory_program_cache.cc b/gpu/command_buffer/service/memory_program_cache.cc
index b15b10e..05680a8 100644
--- a/gpu/command_buffer/service/memory_program_cache.cc
+++ b/gpu/command_buffer/service/memory_program_cache.cc
@@ -297,7 +297,7 @@
       store_(ProgramMRUCache::NO_AUTO_EVICT),
       activity_flags_(activity_flags) {}
 
-MemoryProgramCache::~MemoryProgramCache() {}
+MemoryProgramCache::~MemoryProgramCache() = default;
 
 void MemoryProgramCache::ClearBackend() {
   store_.Clear();
diff --git a/gpu/command_buffer/service/memory_tracking.h b/gpu/command_buffer/service/memory_tracking.h
index 0c3fdd93..5de79952 100644
--- a/gpu/command_buffer/service/memory_tracking.h
+++ b/gpu/command_buffer/service/memory_tracking.h
@@ -39,8 +39,8 @@
 
  protected:
   friend class base::RefCounted<MemoryTracker>;
-  MemoryTracker() {}
-  virtual ~MemoryTracker() {};
+  MemoryTracker() = default;
+  virtual ~MemoryTracker() = default;
 
  private:
   DISALLOW_COPY_AND_ASSIGN(MemoryTracker);
diff --git a/gpu/command_buffer/service/mocks.cc b/gpu/command_buffer/service/mocks.cc
index e8e1b6e..c8eb568 100644
--- a/gpu/command_buffer/service/mocks.cc
+++ b/gpu/command_buffer/service/mocks.cc
@@ -24,7 +24,7 @@
   }
 }
 
-AsyncAPIMock::~AsyncAPIMock() {}
+AsyncAPIMock::~AsyncAPIMock() = default;
 
 error::Error AsyncAPIMock::FakeDoCommands(unsigned int num_commands,
                                           const volatile void* buffer,
@@ -72,15 +72,15 @@
 
 namespace gles2 {
 
-MockShaderTranslator::MockShaderTranslator() {}
+MockShaderTranslator::MockShaderTranslator() = default;
 
-MockShaderTranslator::~MockShaderTranslator() {}
+MockShaderTranslator::~MockShaderTranslator() = default;
 
 MockProgramCache::MockProgramCache() : ProgramCache(0) {}
-MockProgramCache::~MockProgramCache() {}
+MockProgramCache::~MockProgramCache() = default;
 
-MockMemoryTracker::MockMemoryTracker() {}
-MockMemoryTracker::~MockMemoryTracker() {}
+MockMemoryTracker::MockMemoryTracker() = default;
+MockMemoryTracker::~MockMemoryTracker() = default;
 
 }  // namespace gles2
 }  // namespace gpu
diff --git a/gpu/command_buffer/service/path_manager.cc b/gpu/command_buffer/service/path_manager.cc
index 3e0d257..e2155270 100644
--- a/gpu/command_buffer/service/path_manager.cc
+++ b/gpu/command_buffer/service/path_manager.cc
@@ -101,8 +101,7 @@
 
 }  // anonymous namespace
 
-PathManager::PathManager() {
-}
+PathManager::PathManager() = default;
 
 PathManager::~PathManager() {
   DCHECK(path_map_.empty());
diff --git a/gpu/command_buffer/service/path_manager_unittest.cc b/gpu/command_buffer/service/path_manager_unittest.cc
index 236a74d7..e1173d2 100644
--- a/gpu/command_buffer/service/path_manager_unittest.cc
+++ b/gpu/command_buffer/service/path_manager_unittest.cc
@@ -16,7 +16,7 @@
 
 class PathManagerTest : public GpuServiceTest {
  public:
-  PathManagerTest() {}
+  PathManagerTest() = default;
 
  protected:
   void SetUp() override {
diff --git a/gpu/command_buffer/service/program_cache.cc b/gpu/command_buffer/service/program_cache.cc
index f6661bd..e1834cf 100644
--- a/gpu/command_buffer/service/program_cache.cc
+++ b/gpu/command_buffer/service/program_cache.cc
@@ -18,7 +18,7 @@
 
 ProgramCache::ProgramCache(size_t max_cache_size_bytes)
     : max_size_bytes_(max_cache_size_bytes) {}
-ProgramCache::~ProgramCache() {}
+ProgramCache::~ProgramCache() = default;
 
 void ProgramCache::Clear() {
   ClearBackend();
diff --git a/gpu/command_buffer/service/program_manager.cc b/gpu/command_buffer/service/program_manager.cc
index fba8732..e3eeab1 100644
--- a/gpu/command_buffer/service/program_manager.cc
+++ b/gpu/command_buffer/service/program_manager.cc
@@ -382,7 +382,7 @@
 
 Program::UniformInfo::UniformInfo(const UniformInfo& other) = default;
 
-Program::UniformInfo::~UniformInfo() {}
+Program::UniformInfo::~UniformInfo() = default;
 
 bool ProgramManager::HasBuiltInPrefix(const std::string& name) {
   return name.length() >= 3 && name[0] == 'g' && name[1] == 'l' &&
diff --git a/gpu/command_buffer/service/program_manager_unittest.cc b/gpu/command_buffer/service/program_manager_unittest.cc
index bb3c6f8..0e8434f 100644
--- a/gpu/command_buffer/service/program_manager_unittest.cc
+++ b/gpu/command_buffer/service/program_manager_unittest.cc
@@ -2563,7 +2563,7 @@
       public testing::WithParamInterface<
           testing::tuple<const char*, const char*>> {
  public:
-  ProgramManagerDualSourceBlendingTest() {}
+  ProgramManagerDualSourceBlendingTest() = default;
 
  protected:
   void SetUpWithFeatureInfo(FeatureInfo* feature_info) {
diff --git a/gpu/command_buffer/service/query_manager.cc b/gpu/command_buffer/service/query_manager.cc
index d036a7c3..29bb90b 100644
--- a/gpu/command_buffer/service/query_manager.cc
+++ b/gpu/command_buffer/service/query_manager.cc
@@ -100,8 +100,7 @@
   }
 }
 
-AbstractIntegerQuery::~AbstractIntegerQuery() {
-}
+AbstractIntegerQuery::~AbstractIntegerQuery() = default;
 
 bool AbstractIntegerQuery::AreAllResultsAvailable() {
   GLuint available = 0;
@@ -128,8 +127,7 @@
                            QuerySync* sync)
     : AbstractIntegerQuery(manager, target, std::move(buffer), sync) {}
 
-BooleanQuery::~BooleanQuery() {
-}
+BooleanQuery::~BooleanQuery() = default;
 
 void BooleanQuery::Process(bool did_finish) {
   if (!AreAllResultsAvailable())
@@ -163,8 +161,7 @@
                                        QuerySync* sync)
     : AbstractIntegerQuery(manager, target, std::move(buffer), sync) {}
 
-SummedIntegerQuery::~SummedIntegerQuery() {
-}
+SummedIntegerQuery::~SummedIntegerQuery() = default;
 
 void SummedIntegerQuery::Process(bool did_finish) {
   if (!AreAllResultsAvailable())
@@ -239,8 +236,7 @@
   }
 }
 
-CommandsIssuedQuery::~CommandsIssuedQuery() {
-}
+CommandsIssuedQuery::~CommandsIssuedQuery() = default;
 
 class CommandLatencyQuery : public QueryManager::Query {
  public:
@@ -299,9 +295,7 @@
   }
 }
 
-CommandLatencyQuery::~CommandLatencyQuery() {
-}
-
+CommandLatencyQuery::~CommandLatencyQuery() = default;
 
 class AsyncReadPixelsCompletedQuery
     : public QueryManager::Query,
@@ -370,9 +364,7 @@
   }
 }
 
-AsyncReadPixelsCompletedQuery::~AsyncReadPixelsCompletedQuery() {
-}
-
+AsyncReadPixelsCompletedQuery::~AsyncReadPixelsCompletedQuery() = default;
 
 class GetErrorQuery : public QueryManager::Query {
  public:
@@ -432,8 +424,7 @@
   }
 }
 
-GetErrorQuery::~GetErrorQuery() {
-}
+GetErrorQuery::~GetErrorQuery() = default;
 
 class CommandsCompletedQuery : public QueryManager::Query {
  public:
@@ -513,7 +504,7 @@
   }
 }
 
-CommandsCompletedQuery::~CommandsCompletedQuery() {}
+CommandsCompletedQuery::~CommandsCompletedQuery() = default;
 
 class TimeElapsedQuery : public QueryManager::Query {
  public:
@@ -588,7 +579,7 @@
   gpu_timer_->Destroy(have_context);
 }
 
-TimeElapsedQuery::~TimeElapsedQuery() {}
+TimeElapsedQuery::~TimeElapsedQuery() = default;
 
 class TimeStampQuery : public QueryManager::Query {
  public:
@@ -674,7 +665,7 @@
   }
 }
 
-TimeStampQuery::~TimeStampQuery() {}
+TimeStampQuery::~TimeStampQuery() = default;
 
 QueryManager::QueryManager(
     GLES2Decoder* decoder,
diff --git a/gpu/command_buffer/service/query_manager_unittest.cc b/gpu/command_buffer/service/query_manager_unittest.cc
index 117528b..a76e844 100644
--- a/gpu/command_buffer/service/query_manager_unittest.cc
+++ b/gpu/command_buffer/service/query_manager_unittest.cc
@@ -41,9 +41,8 @@
   static const uint32_t kInitialResult = 0xBDBDBDBDu;
   static const uint8_t kInitialMemoryValue = 0xBDu;
 
-  QueryManagerTest() {
-  }
-  ~QueryManagerTest() override {}
+  QueryManagerTest() = default;
+  ~QueryManagerTest() override = default;
 
  protected:
   void SetUp() override {
diff --git a/gpu/command_buffer/service/scheduler_unittest.cc b/gpu/command_buffer/service/scheduler_unittest.cc
index 0989f1e2..2fa05c0f 100644
--- a/gpu/command_buffer/service/scheduler_unittest.cc
+++ b/gpu/command_buffer/service/scheduler_unittest.cc
@@ -99,7 +99,7 @@
 
 class SchedulerTaskRunOrderTest : public SchedulerTest {
  public:
-  SchedulerTaskRunOrderTest() {}
+  SchedulerTaskRunOrderTest() = default;
   ~SchedulerTaskRunOrderTest() override {
     for (auto info_it : sequence_info_) {
       info_it.second.release_state->Destroy();
diff --git a/gpu/command_buffer/service/service_discardable_manager_unittest.cc b/gpu/command_buffer/service/service_discardable_manager_unittest.cc
index 6d91264..79df555 100644
--- a/gpu/command_buffer/service/service_discardable_manager_unittest.cc
+++ b/gpu/command_buffer/service/service_discardable_manager_unittest.cc
@@ -62,8 +62,8 @@
 
 class ServiceDiscardableManagerTest : public GpuServiceTest {
  public:
-  ServiceDiscardableManagerTest() {}
-  ~ServiceDiscardableManagerTest() override {}
+  ServiceDiscardableManagerTest() = default;
+  ~ServiceDiscardableManagerTest() override = default;
 
  protected:
   void SetUp() override {
diff --git a/gpu/command_buffer/service/shader_manager.cc b/gpu/command_buffer/service/shader_manager.cc
index 77e0df23e..9a1a32c 100644
--- a/gpu/command_buffer/service/shader_manager.cc
+++ b/gpu/command_buffer/service/shader_manager.cc
@@ -38,8 +38,7 @@
         valid_(false) {
 }
 
-Shader::~Shader() {
-}
+Shader::~Shader() = default;
 
 void Shader::Destroy() {
   if (service_id_) {
diff --git a/gpu/command_buffer/service/shader_translator.cc b/gpu/command_buffer/service/shader_translator.cc
index dda5586..35f989c4 100644
--- a/gpu/command_buffer/service/shader_translator.cc
+++ b/gpu/command_buffer/service/shader_translator.cc
@@ -136,11 +136,9 @@
   return SH_GLSL_COMPATIBILITY_OUTPUT;
 }
 
-ShaderTranslator::DestructionObserver::DestructionObserver() {
-}
+ShaderTranslator::DestructionObserver::DestructionObserver() = default;
 
-ShaderTranslator::DestructionObserver::~DestructionObserver() {
-}
+ShaderTranslator::DestructionObserver::~DestructionObserver() = default;
 
 ShaderTranslator::ShaderTranslator()
     : compiler_(NULL),
diff --git a/gpu/command_buffer/service/shader_translator.h b/gpu/command_buffer/service/shader_translator.h
index 5d34463..eb11dcf 100644
--- a/gpu/command_buffer/service/shader_translator.h
+++ b/gpu/command_buffer/service/shader_translator.h
@@ -34,7 +34,7 @@
 class ShaderTranslatorInterface
     : public base::RefCounted<ShaderTranslatorInterface> {
  public:
-  ShaderTranslatorInterface() {}
+  ShaderTranslatorInterface() = default;
 
   // Initializes the translator.
   // Must be called once before using the translator object.
@@ -66,7 +66,7 @@
   GetStringForOptionsThatWouldAffectCompilation() const = 0;
 
  protected:
-  virtual ~ShaderTranslatorInterface() {}
+  virtual ~ShaderTranslatorInterface() = default;
 
  private:
   friend class base::RefCounted<ShaderTranslatorInterface>;
diff --git a/gpu/command_buffer/service/shader_translator_cache.h b/gpu/command_buffer/service/shader_translator_cache.h
index a5ae1c81..391ff34a 100644
--- a/gpu/command_buffer/service/shader_translator_cache.h
+++ b/gpu/command_buffer/service/shader_translator_cache.h
@@ -80,8 +80,9 @@
     }
 
    private:
-    ShaderTranslatorInitParams();
-    ShaderTranslatorInitParams& operator=(const ShaderTranslatorInitParams&);
+    ShaderTranslatorInitParams() = delete;
+    ShaderTranslatorInitParams& operator=(const ShaderTranslatorInitParams&) =
+        delete;
   };
 
   const GpuPreferences gpu_preferences_;
diff --git a/gpu/command_buffer/service/shader_translator_unittest.cc b/gpu/command_buffer/service/shader_translator_unittest.cc
index 94fce2b..d8d3033 100644
--- a/gpu/command_buffer/service/shader_translator_unittest.cc
+++ b/gpu/command_buffer/service/shader_translator_unittest.cc
@@ -19,7 +19,7 @@
             gl::GLVersionInfo("2.0", "", gl::ExtensionSet()));
   }
 
-  ~ShaderTranslatorTest() override {}
+  ~ShaderTranslatorTest() override = default;
 
  protected:
   void SetUp() override {
@@ -58,7 +58,7 @@
             gl::GLVersionInfo("3.0", "", gl::ExtensionSet()));
   }
 
-  ~ES3ShaderTranslatorTest() override {}
+  ~ES3ShaderTranslatorTest() override = default;
 
  protected:
   void SetUp() override {
diff --git a/gpu/command_buffer/service/sync_point_manager.cc b/gpu/command_buffer/service/sync_point_manager.cc
index 51fbfca..a3c4bf1 100644
--- a/gpu/command_buffer/service/sync_point_manager.cc
+++ b/gpu/command_buffer/service/sync_point_manager.cc
@@ -42,7 +42,7 @@
 
 SyncPointOrderData::OrderFence::OrderFence(const OrderFence& other) = default;
 
-SyncPointOrderData::OrderFence::~OrderFence() {}
+SyncPointOrderData::OrderFence::~OrderFence() = default;
 
 SyncPointOrderData::SyncPointOrderData(SyncPointManager* sync_point_manager,
                                        SequenceId sequence_id)
@@ -185,7 +185,7 @@
 SyncPointClientState::ReleaseCallback::ReleaseCallback(
     const ReleaseCallback& other) = default;
 
-SyncPointClientState::ReleaseCallback::~ReleaseCallback() {}
+SyncPointClientState::ReleaseCallback::~ReleaseCallback() = default;
 
 SyncPointClientState::SyncPointClientState(
     SyncPointManager* sync_point_manager,
diff --git a/gpu/command_buffer/service/sync_point_manager_unittest.cc b/gpu/command_buffer/service/sync_point_manager_unittest.cc
index 9a1e1e0f..fa32147 100644
--- a/gpu/command_buffer/service/sync_point_manager_unittest.cc
+++ b/gpu/command_buffer/service/sync_point_manager_unittest.cc
@@ -17,7 +17,7 @@
 class SyncPointManagerTest : public testing::Test {
  public:
   SyncPointManagerTest() : sync_point_manager_(new SyncPointManager) {}
-  ~SyncPointManagerTest() override {}
+  ~SyncPointManagerTest() override = default;
 
  protected:
   // Simple static function which can be used to test callbacks.
diff --git a/gpu/command_buffer/service/texture_definition.cc b/gpu/command_buffer/service/texture_definition.cc
index b925538..4105482a 100644
--- a/gpu/command_buffer/service/texture_definition.cc
+++ b/gpu/command_buffer/service/texture_definition.cc
@@ -179,7 +179,7 @@
 NativeImageBufferEGL::ClientInfo::ClientInfo(gl::GLImage* client)
     : client(client), needs_wait_before_read(true) {}
 
-NativeImageBufferEGL::ClientInfo::~ClientInfo() {}
+NativeImageBufferEGL::ClientInfo::~ClientInfo() = default;
 
 NativeImageBufferEGL::NativeImageBufferEGL(EGLDisplay display,
                                            EGLImageKHR image)
@@ -242,7 +242,7 @@
   NativeImageBufferStub() : NativeImageBuffer() {}
 
  private:
-  ~NativeImageBufferStub() override {}
+  ~NativeImageBufferStub() override = default;
   void AddClient(gl::GLImage* client) override {}
   void RemoveClient(gl::GLImage* client) override {}
   bool IsClient(gl::GLImage* client) override { return true; }
@@ -309,7 +309,7 @@
 
 TextureDefinition::LevelInfo::LevelInfo(const LevelInfo& other) = default;
 
-TextureDefinition::LevelInfo::~LevelInfo() {}
+TextureDefinition::LevelInfo::~LevelInfo() = default;
 
 TextureDefinition::TextureDefinition()
     : version_(0),
@@ -358,8 +358,7 @@
 
 TextureDefinition::TextureDefinition(const TextureDefinition& other) = default;
 
-TextureDefinition::~TextureDefinition() {
-}
+TextureDefinition::~TextureDefinition() = default;
 
 Texture* TextureDefinition::CreateTexture() const {
   GLuint texture_id;
diff --git a/gpu/command_buffer/service/texture_definition.h b/gpu/command_buffer/service/texture_definition.h
index 8dd7ce1..780a8f0 100644
--- a/gpu/command_buffer/service/texture_definition.h
+++ b/gpu/command_buffer/service/texture_definition.h
@@ -32,8 +32,8 @@
 
  protected:
   friend class base::RefCountedThreadSafe<NativeImageBuffer>;
-  NativeImageBuffer() {}
-  virtual ~NativeImageBuffer() {}
+  NativeImageBuffer() = default;
+  virtual ~NativeImageBuffer() = default;
 
   DISALLOW_COPY_AND_ASSIGN(NativeImageBuffer);
 };
diff --git a/gpu/command_buffer/service/texture_manager.cc b/gpu/command_buffer/service/texture_manager.cc
index 664460c..7e9559c 100644
--- a/gpu/command_buffer/service/texture_manager.cc
+++ b/gpu/command_buffer/service/texture_manager.cc
@@ -429,9 +429,9 @@
       unpack_image_height_workaround_with_unpack_buffer(
           workarounds.unpack_image_height_workaround_with_unpack_buffer) {}
 
-TextureManager::DestructionObserver::DestructionObserver() {}
+TextureManager::DestructionObserver::DestructionObserver() = default;
 
-TextureManager::DestructionObserver::~DestructionObserver() {}
+TextureManager::DestructionObserver::~DestructionObserver() = default;
 
 TextureManager::~TextureManager() {
   for (unsigned int i = 0; i < destruction_observers_.size(); i++)
@@ -648,8 +648,7 @@
       estimated_size(rhs.estimated_size),
       internal_workaround(rhs.internal_workaround) {}
 
-Texture::LevelInfo::~LevelInfo() {
-}
+Texture::LevelInfo::~LevelInfo() = default;
 
 Texture::FaceInfo::FaceInfo()
     : num_mip_levels(0) {
@@ -657,8 +656,7 @@
 
 Texture::FaceInfo::FaceInfo(const FaceInfo& other) = default;
 
-Texture::FaceInfo::~FaceInfo() {
-}
+Texture::FaceInfo::~FaceInfo() = default;
 
 Texture::CanRenderCondition Texture::GetCanRenderCondition() const {
   if (target_ == 0)
diff --git a/gpu/command_buffer/service/texture_manager_unittest.cc b/gpu/command_buffer/service/texture_manager_unittest.cc
index 6e4157c..4721c12 100644
--- a/gpu/command_buffer/service/texture_manager_unittest.cc
+++ b/gpu/command_buffer/service/texture_manager_unittest.cc
@@ -75,7 +75,7 @@
     feature_info_ = new FeatureInfo(gpu_driver_bug_workaround);
   }
 
-  ~TextureManagerTest() override {}
+  ~TextureManagerTest() override = default;
 
  protected:
   void SetUp() override {
@@ -145,7 +145,7 @@
 
 class GLStreamTextureImageStub : public GLStreamTextureImage {
  public:
-  GLStreamTextureImageStub() {}
+  GLStreamTextureImageStub() = default;
 
   // Overridden from GLImage:
   gfx::Size GetSize() override { return gfx::Size(); }
@@ -181,7 +181,7 @@
                            int display_height) override {}
 
  protected:
-  ~GLStreamTextureImageStub() override {}
+  ~GLStreamTextureImageStub() override = default;
 };
 
 TEST_F(TextureManagerTest, Basic) {
@@ -2203,7 +2203,7 @@
   uint64_t ShareGroupTracingGUID() const override { return 0; }
 
  private:
-  ~CountingMemoryTracker() override {}
+  ~CountingMemoryTracker() override = default;
 
   size_t current_size_;
   DISALLOW_COPY_AND_ASSIGN(CountingMemoryTracker);
@@ -2215,7 +2215,7 @@
 
   SharedTextureTest() : feature_info_(new FeatureInfo()) {}
 
-  ~SharedTextureTest() override {}
+  ~SharedTextureTest() override = default;
 
   void SetUp() override {
     GpuServiceTest::SetUp();
@@ -2500,8 +2500,8 @@
 
 class TextureFormatTypeValidationTest : public TextureManagerTest {
  public:
-  TextureFormatTypeValidationTest() {}
-  ~TextureFormatTypeValidationTest() override {}
+  TextureFormatTypeValidationTest() = default;
+  ~TextureFormatTypeValidationTest() override = default;
 
  protected:
   void ExpectValid(
diff --git a/gpu/command_buffer/service/transform_feedback_manager_unittest.cc b/gpu/command_buffer/service/transform_feedback_manager_unittest.cc
index 47e879f4..4aefb84 100644
--- a/gpu/command_buffer/service/transform_feedback_manager_unittest.cc
+++ b/gpu/command_buffer/service/transform_feedback_manager_unittest.cc
@@ -20,10 +20,9 @@
 
 class TransformFeedbackManagerTest : public GpuServiceTest {
  public:
-  TransformFeedbackManagerTest() {
-  }
+  TransformFeedbackManagerTest() = default;
 
-  ~TransformFeedbackManagerTest() override {}
+  ~TransformFeedbackManagerTest() override = default;
 
  protected:
   void SetUp() override {
diff --git a/gpu/command_buffer/service/vertex_array_manager_unittest.cc b/gpu/command_buffer/service/vertex_array_manager_unittest.cc
index a679cb5b..ac645c8 100644
--- a/gpu/command_buffer/service/vertex_array_manager_unittest.cc
+++ b/gpu/command_buffer/service/vertex_array_manager_unittest.cc
@@ -25,10 +25,9 @@
  public:
   static const uint32_t kNumVertexAttribs = 8;
 
-  VertexArrayManagerTest() {
-  }
+  VertexArrayManagerTest() = default;
 
-  ~VertexArrayManagerTest() override {}
+  ~VertexArrayManagerTest() override = default;
 
  protected:
   void SetUp() override {
diff --git a/gpu/command_buffer/service/vertex_attrib_manager.cc b/gpu/command_buffer/service/vertex_attrib_manager.cc
index 76eb9d9..bc61abd 100644
--- a/gpu/command_buffer/service/vertex_attrib_manager.cc
+++ b/gpu/command_buffer/service/vertex_attrib_manager.cc
@@ -43,8 +43,7 @@
 
 VertexAttrib::VertexAttrib(const VertexAttrib& other) = default;
 
-VertexAttrib::~VertexAttrib() {
-}
+VertexAttrib::~VertexAttrib() = default;
 
 void VertexAttrib::SetInfo(
     Buffer* buffer,
diff --git a/gpu/command_buffer/service/vertex_attrib_manager_unittest.cc b/gpu/command_buffer/service/vertex_attrib_manager_unittest.cc
index 5701162..83dd567 100644
--- a/gpu/command_buffer/service/vertex_attrib_manager_unittest.cc
+++ b/gpu/command_buffer/service/vertex_attrib_manager_unittest.cc
@@ -24,10 +24,9 @@
  public:
   static const uint32_t kNumVertexAttribs = 8;
 
-  VertexAttribManagerTest() {
-  }
+  VertexAttribManagerTest() = default;
 
-  ~VertexAttribManagerTest() override {}
+  ~VertexAttribManagerTest() override = default;
 
  protected:
   void SetUp() override {
diff --git a/gpu/command_buffer/tests/gl_manager.cc b/gpu/command_buffer/tests/gl_manager.cc
index 51840762..56a3aed 100644
--- a/gpu/command_buffer/tests/gl_manager.cc
+++ b/gpu/command_buffer/tests/gl_manager.cc
@@ -180,7 +180,7 @@
       : CommandBufferDirect(transfer_buffer_manager, sync_point_manager),
         context_lost_allowed_(context_lost_allowed) {}
 
-  ~CommandBufferCheckLostContext() override {}
+  ~CommandBufferCheckLostContext() override = default;
 
   void Flush(int32_t put_offset) override {
     CommandBufferDirect::Flush(put_offset);
diff --git a/gpu/command_buffer/tests/texture_image_factory.cc b/gpu/command_buffer/tests/texture_image_factory.cc
index bf92708..fe1a54f 100644
--- a/gpu/command_buffer/tests/texture_image_factory.cc
+++ b/gpu/command_buffer/tests/texture_image_factory.cc
@@ -45,7 +45,7 @@
                     const std::string& dump_name) override {}
 
  private:
-  ~TextureImage() override {}
+  ~TextureImage() override = default;
   gfx::Size size_;
 };
 
@@ -63,7 +63,9 @@
     const gfx::Size& size,
     gfx::BufferFormat format,
     gfx::BufferUsage usage,
-    unsigned internalformat) {
+    unsigned internalformat,
+    bool* is_cleared) {
+  *is_cleared = true;
   return new TextureImage(size);
 }
 
diff --git a/gpu/command_buffer/tests/texture_image_factory.h b/gpu/command_buffer/tests/texture_image_factory.h
index 8837b86..2878c27 100644
--- a/gpu/command_buffer/tests/texture_image_factory.h
+++ b/gpu/command_buffer/tests/texture_image_factory.h
@@ -17,11 +17,11 @@
       unsigned internalformat,
       int client_id,
       SurfaceHandle surface_handle) override;
-  scoped_refptr<gl::GLImage> CreateAnonymousImage(
-      const gfx::Size& size,
-      gfx::BufferFormat format,
-      gfx::BufferUsage usage,
-      unsigned internalformat) override;
+  scoped_refptr<gl::GLImage> CreateAnonymousImage(const gfx::Size& size,
+                                                  gfx::BufferFormat format,
+                                                  gfx::BufferUsage usage,
+                                                  unsigned internalformat,
+                                                  bool* is_cleared) override;
   unsigned RequiredTextureType() override;
   bool SupportsFormatRGB() override;
 
diff --git a/gpu/config/dx_diag_node.cc b/gpu/config/dx_diag_node.cc
index 48b9b691..7dcba27 100644
--- a/gpu/config/dx_diag_node.cc
+++ b/gpu/config/dx_diag_node.cc
@@ -6,10 +6,10 @@
 
 namespace gpu {
 
-DxDiagNode::DxDiagNode() {}
+DxDiagNode::DxDiagNode() = default;
 
 DxDiagNode::DxDiagNode(const DxDiagNode& other) = default;
 
-DxDiagNode::~DxDiagNode() {}
+DxDiagNode::~DxDiagNode() = default;
 
 }  // namespace gpu
diff --git a/gpu/config/gpu_blacklist.cc b/gpu/config/gpu_blacklist.cc
index 480de7d..61f2fcb 100644
--- a/gpu/config/gpu_blacklist.cc
+++ b/gpu/config/gpu_blacklist.cc
@@ -12,8 +12,7 @@
 GpuBlacklist::GpuBlacklist(const GpuControlListData& data)
     : GpuControlList(data) {}
 
-GpuBlacklist::~GpuBlacklist() {
-}
+GpuBlacklist::~GpuBlacklist() = default;
 
 // static
 std::unique_ptr<GpuBlacklist> GpuBlacklist::Create() {
diff --git a/gpu/config/gpu_blacklist_unittest.cc b/gpu/config/gpu_blacklist_unittest.cc
index 0f25e03..45bfe72c 100644
--- a/gpu/config/gpu_blacklist_unittest.cc
+++ b/gpu/config/gpu_blacklist_unittest.cc
@@ -13,8 +13,8 @@
 
 class GpuBlacklistTest : public testing::Test {
  public:
-  GpuBlacklistTest() { }
-  ~GpuBlacklistTest() override {}
+  GpuBlacklistTest() = default;
+  ~GpuBlacklistTest() override = default;
 
   const GPUInfo& gpu_info() const {
     return gpu_info_;
diff --git a/gpu/config/gpu_control_list.cc b/gpu/config/gpu_control_list.cc
index 5c3ef20..75d90cb 100644
--- a/gpu/config/gpu_control_list.cc
+++ b/gpu/config/gpu_control_list.cc
@@ -500,8 +500,7 @@
   max_entry_id_ = entries_[entry_count_ - 1].id;
 }
 
-GpuControlList::~GpuControlList() {
-}
+GpuControlList::~GpuControlList() = default;
 
 std::set<int32_t> GpuControlList::MakeDecision(GpuControlList::OsType os,
                                                const std::string& os_version,
diff --git a/gpu/config/gpu_control_list_entry_unittest.cc b/gpu/config/gpu_control_list_entry_unittest.cc
index 2ea1feca..a1c9971 100644
--- a/gpu/config/gpu_control_list_entry_unittest.cc
+++ b/gpu/config/gpu_control_list_entry_unittest.cc
@@ -26,8 +26,8 @@
  public:
   typedef GpuControlList::Entry Entry;
 
-  GpuControlListEntryTest() {}
-  ~GpuControlListEntryTest() override {}
+  GpuControlListEntryTest() = default;
+  ~GpuControlListEntryTest() override = default;
 
   const GPUInfo& gpu_info() const {
     return gpu_info_;
@@ -422,8 +422,8 @@
 
 class GpuControlListEntryDualGPUTest : public GpuControlListEntryTest {
  public:
-  GpuControlListEntryDualGPUTest() { }
-  ~GpuControlListEntryDualGPUTest() override {}
+  GpuControlListEntryDualGPUTest() = default;
+  ~GpuControlListEntryDualGPUTest() override = default;
 
   void SetUp() override {
     // Set up a NVIDIA/Intel dual, with NVIDIA as primary and Intel as
diff --git a/gpu/config/gpu_control_list_unittest.cc b/gpu/config/gpu_control_list_unittest.cc
index 72a213f..cf54d79 100644
--- a/gpu/config/gpu_control_list_unittest.cc
+++ b/gpu/config/gpu_control_list_unittest.cc
@@ -28,8 +28,8 @@
  public:
   typedef GpuControlList::Entry Entry;
 
-  GpuControlListTest() {}
-  ~GpuControlListTest() override {}
+  GpuControlListTest() = default;
+  ~GpuControlListTest() override = default;
 
   const GPUInfo& gpu_info() const {
     return gpu_info_;
diff --git a/gpu/config/gpu_control_list_version_unittest.cc b/gpu/config/gpu_control_list_version_unittest.cc
index 0a1bf03..7b2c4191 100644
--- a/gpu/config/gpu_control_list_version_unittest.cc
+++ b/gpu/config/gpu_control_list_version_unittest.cc
@@ -26,8 +26,8 @@
 
 class VersionTest : public testing::Test {
  public:
-  VersionTest() {}
-  ~VersionTest() override {}
+  VersionTest() = default;
+  ~VersionTest() override = default;
 
   typedef GpuControlList::Version Version;
 };
diff --git a/gpu/config/gpu_driver_bug_list.cc b/gpu/config/gpu_driver_bug_list.cc
index 68db9310..dd8066af 100644
--- a/gpu/config/gpu_driver_bug_list.cc
+++ b/gpu/config/gpu_driver_bug_list.cc
@@ -30,8 +30,7 @@
 GpuDriverBugList::GpuDriverBugList(const GpuControlListData& data)
     : GpuControlList(data) {}
 
-GpuDriverBugList::~GpuDriverBugList() {
-}
+GpuDriverBugList::~GpuDriverBugList() = default;
 
 // static
 std::unique_ptr<GpuDriverBugList> GpuDriverBugList::Create() {
diff --git a/gpu/config/gpu_driver_bug_list_unittest.cc b/gpu/config/gpu_driver_bug_list_unittest.cc
index cb4f67b..ff5bf3a9 100644
--- a/gpu/config/gpu_driver_bug_list_unittest.cc
+++ b/gpu/config/gpu_driver_bug_list_unittest.cc
@@ -14,8 +14,8 @@
 
 class GpuDriverBugListTest : public testing::Test {
  public:
-  GpuDriverBugListTest() {}
-  ~GpuDriverBugListTest() override {}
+  GpuDriverBugListTest() = default;
+  ~GpuDriverBugListTest() override = default;
 };
 
 #if defined(OS_ANDROID)
diff --git a/gpu/config/gpu_driver_bug_workarounds.cc b/gpu/config/gpu_driver_bug_workarounds.cc
index e46a32c..55aa4c5 100644
--- a/gpu/config/gpu_driver_bug_workarounds.cc
+++ b/gpu/config/gpu_driver_bug_workarounds.cc
@@ -53,7 +53,7 @@
 
 namespace gpu {
 
-GpuDriverBugWorkarounds::GpuDriverBugWorkarounds() {}
+GpuDriverBugWorkarounds::GpuDriverBugWorkarounds() = default;
 
 GpuDriverBugWorkarounds::GpuDriverBugWorkarounds(
     const std::vector<int>& enabled_driver_bug_workarounds) {
@@ -63,7 +63,7 @@
 GpuDriverBugWorkarounds::GpuDriverBugWorkarounds(
     const GpuDriverBugWorkarounds& other) = default;
 
-GpuDriverBugWorkarounds::~GpuDriverBugWorkarounds() {}
+GpuDriverBugWorkarounds::~GpuDriverBugWorkarounds() = default;
 
 void GpuDriverBugWorkarounds::Append(const GpuDriverBugWorkarounds& extra) {
 #define GPU_OP(type, name) name |= extra.name;
diff --git a/gpu/config/gpu_feature_info.cc b/gpu/config/gpu_feature_info.cc
index eee64b5e..ec38da1 100644
--- a/gpu/config/gpu_feature_info.cc
+++ b/gpu/config/gpu_feature_info.cc
@@ -20,7 +20,7 @@
 
 GpuFeatureInfo::GpuFeatureInfo(GpuFeatureInfo&&) = default;
 
-GpuFeatureInfo::~GpuFeatureInfo() {}
+GpuFeatureInfo::~GpuFeatureInfo() = default;
 
 GpuFeatureInfo& GpuFeatureInfo::operator=(const GpuFeatureInfo&) = default;
 
diff --git a/gpu/config/gpu_info.cc b/gpu/config/gpu_info.cc
index 96cf6dbc..bb275f8 100644
--- a/gpu/config/gpu_info.cc
+++ b/gpu/config/gpu_info.cc
@@ -55,7 +55,8 @@
 VideoDecodeAcceleratorCapabilities::VideoDecodeAcceleratorCapabilities(
     const VideoDecodeAcceleratorCapabilities& other) = default;
 
-VideoDecodeAcceleratorCapabilities::~VideoDecodeAcceleratorCapabilities() {}
+VideoDecodeAcceleratorCapabilities::~VideoDecodeAcceleratorCapabilities() =
+    default;
 
 GPUInfo::GPUDevice::GPUDevice()
     : vendor_id(0),
@@ -63,7 +64,7 @@
       active(false) {
 }
 
-GPUInfo::GPUDevice::~GPUDevice() { }
+GPUInfo::GPUDevice::~GPUDevice() = default;
 
 GPUInfo::GPUInfo()
     : optimus(false),
@@ -91,7 +92,7 @@
 
 GPUInfo::GPUInfo(const GPUInfo& other) = default;
 
-GPUInfo::~GPUInfo() { }
+GPUInfo::~GPUInfo() = default;
 
 const GPUInfo::GPUDevice& GPUInfo::active_gpu() const {
   if (gpu.active)
diff --git a/gpu/config/gpu_info.h b/gpu/config/gpu_info.h
index 5e84d800..1595d28 100644
--- a/gpu/config/gpu_info.h
+++ b/gpu/config/gpu_info.h
@@ -291,7 +291,7 @@
     virtual void EndAuxAttributes() = 0;
 
    protected:
-    virtual ~Enumerator() {}
+    virtual ~Enumerator() = default;
   };
 
   // Outputs the fields in this structure to the provided enumerator.
diff --git a/gpu/config/gpu_info_collector_unittest.cc b/gpu/config/gpu_info_collector_unittest.cc
index 631a6c1..0e43f7a 100644
--- a/gpu/config/gpu_info_collector_unittest.cc
+++ b/gpu/config/gpu_info_collector_unittest.cc
@@ -49,8 +49,8 @@
     : public testing::Test,
       public ::testing::WithParamInterface<MockedOperatingSystemKind> {
  public:
-  GPUInfoCollectorTest() {}
-  ~GPUInfoCollectorTest() override {}
+  GPUInfoCollectorTest() = default;
+  ~GPUInfoCollectorTest() override = default;
 
   void SetUp() override {
     testing::Test::SetUp();
@@ -248,8 +248,8 @@
 
 class CollectDriverInfoGLTest : public testing::Test {
  public:
-  CollectDriverInfoGLTest() {}
-  ~CollectDriverInfoGLTest() override {}
+  CollectDriverInfoGLTest() = default;
+  ~CollectDriverInfoGLTest() override = default;
 
   void SetUp() override {}
   void TearDown() override {}
diff --git a/gpu/config/gpu_test_config.cc b/gpu/config/gpu_test_config.cc
index 5e07aaf8..ed1a831b 100644
--- a/gpu/config/gpu_test_config.cc
+++ b/gpu/config/gpu_test_config.cc
@@ -86,8 +86,7 @@
 
 GPUTestConfig::GPUTestConfig(const GPUTestConfig& other) = default;
 
-GPUTestConfig::~GPUTestConfig() {
-}
+GPUTestConfig::~GPUTestConfig() = default;
 
 void GPUTestConfig::set_os(int32_t os) {
   DCHECK_EQ(0, os & ~(kOsAndroid | kOsWin | kOsMac | kOsLinux | kOsChromeOS));
@@ -154,8 +153,7 @@
   gpu_vendor_.clear();
 }
 
-GPUTestBotConfig::~GPUTestBotConfig() {
-}
+GPUTestBotConfig::~GPUTestBotConfig() = default;
 
 void GPUTestBotConfig::AddGPUVendor(uint32_t gpu_vendor) {
   DCHECK_EQ(0u, GPUTestConfig::gpu_vendor().size());
diff --git a/gpu/config/gpu_test_config.h b/gpu/config/gpu_test_config.h
index d92d2bcd..ba8e662 100644
--- a/gpu/config/gpu_test_config.h
+++ b/gpu/config/gpu_test_config.h
@@ -105,7 +105,7 @@
 
 class GPU_EXPORT GPUTestBotConfig : public GPUTestConfig {
  public:
-  GPUTestBotConfig() { }
+  GPUTestBotConfig() = default;
   ~GPUTestBotConfig() override;
 
   // This should only be called when no gpu_vendor is added.
diff --git a/gpu/config/gpu_test_config_unittest.cc b/gpu/config/gpu_test_config_unittest.cc
index e42a805..9934b872 100644
--- a/gpu/config/gpu_test_config_unittest.cc
+++ b/gpu/config/gpu_test_config_unittest.cc
@@ -10,9 +10,9 @@
 
 class GPUTestConfigTest : public testing::Test {
  public:
-  GPUTestConfigTest() { }
+  GPUTestConfigTest() = default;
 
-  ~GPUTestConfigTest() override {}
+  ~GPUTestConfigTest() override = default;
 
  protected:
   void SetUp() override {}
diff --git a/gpu/config/gpu_test_expectations_parser.cc b/gpu/config/gpu_test_expectations_parser.cc
index 7dc8b2a..c3997e7a 100644
--- a/gpu/config/gpu_test_expectations_parser.cc
+++ b/gpu/config/gpu_test_expectations_parser.cc
@@ -189,8 +189,7 @@
             sizeof(kErrorMessage) / sizeof(kErrorMessage[0]));
 }
 
-GPUTestExpectationsParser::~GPUTestExpectationsParser() {
-}
+GPUTestExpectationsParser::~GPUTestExpectationsParser() = default;
 
 bool GPUTestExpectationsParser::LoadTestExpectations(const std::string& data) {
   entries_.clear();
diff --git a/gpu/config/gpu_test_expectations_parser_unittest.cc b/gpu/config/gpu_test_expectations_parser_unittest.cc
index 4d8b90c..2d30b4a0 100644
--- a/gpu/config/gpu_test_expectations_parser_unittest.cc
+++ b/gpu/config/gpu_test_expectations_parser_unittest.cc
@@ -60,9 +60,9 @@
 
 class GPUTestExpectationsParserTest : public testing::Test {
  public:
-  GPUTestExpectationsParserTest() { }
+  GPUTestExpectationsParserTest() = default;
 
-  ~GPUTestExpectationsParserTest() override {}
+  ~GPUTestExpectationsParserTest() override = default;
 
   const GPUTestBotConfig& bot_config() const {
     return bot_config_;
@@ -93,9 +93,9 @@
     : public GPUTestExpectationsParserTest,
       public testing::WithParamInterface<TestOsWithFamily> {
  public:
-  GPUTestExpectationsParserParamTest() { }
+  GPUTestExpectationsParserParamTest() = default;
 
-  ~GPUTestExpectationsParserParamTest() override {}
+  ~GPUTestExpectationsParserParamTest() override = default;
 
  protected:
   const GPUTestBotConfig& GetBotConfig() {
diff --git a/gpu/gles2_conform_support/egl/config.cc b/gpu/gles2_conform_support/egl/config.cc
index 53bd440d..5c4767e 100644
--- a/gpu/gles2_conform_support/egl/config.cc
+++ b/gpu/gles2_conform_support/egl/config.cc
@@ -43,8 +43,7 @@
   DCHECK(surface_type == EGL_WINDOW_BIT || surface_type == EGL_PBUFFER_BIT);
 }
 
-Config::~Config() {
-}
+Config::~Config() = default;
 
 bool Config::Matches(const EGLint* attrib_list) const {
   DCHECK(ValidateAttributeList(attrib_list));
diff --git a/gpu/gles2_conform_support/egl/surface.cc b/gpu/gles2_conform_support/egl/surface.cc
index ae8c842..4ed35ce 100644
--- a/gpu/gles2_conform_support/egl/surface.cc
+++ b/gpu/gles2_conform_support/egl/surface.cc
@@ -12,8 +12,7 @@
       gl_surface_(gl_surface),
       config_(config) {}
 
-Surface::~Surface() {
-}
+Surface::~Surface() = default;
 
 gl::GLSurface* Surface::gl_surface() const {
   return gl_surface_.get();
diff --git a/gpu/gles2_conform_support/egl/thread_state.cc b/gpu/gles2_conform_support/egl/thread_state.cc
index e0f02ae71..2595644 100644
--- a/gpu/gles2_conform_support/egl/thread_state.cc
+++ b/gpu/gles2_conform_support/egl/thread_state.cc
@@ -151,7 +151,7 @@
 
 ThreadState::ThreadState() : error_code_(EGL_SUCCESS) {}
 
-ThreadState::~ThreadState() {}
+ThreadState::~ThreadState() = default;
 
 EGLint ThreadState::ConsumeErrorCode() {
   EGLint current_error_code = error_code_;
diff --git a/gpu/ipc/client/command_buffer_proxy_impl.h b/gpu/ipc/client/command_buffer_proxy_impl.h
index 56c65b3..51611db 100644
--- a/gpu/ipc/client/command_buffer_proxy_impl.h
+++ b/gpu/ipc/client/command_buffer_proxy_impl.h
@@ -71,7 +71,7 @@
     virtual void OnWillDeleteImpl() = 0;
 
    protected:
-    virtual ~DeletionObserver() {}
+    virtual ~DeletionObserver() = default;
   };
 
   typedef base::Callback<void(const std::string& msg, int id)>
diff --git a/gpu/ipc/client/gpu_channel_host.h b/gpu/ipc/client/gpu_channel_host.h
index 3de395f..a994816 100644
--- a/gpu/ipc/client/gpu_channel_host.h
+++ b/gpu/ipc/client/gpu_channel_host.h
@@ -46,7 +46,7 @@
 
 class GPU_EXPORT GpuChannelEstablishFactory {
  public:
-  virtual ~GpuChannelEstablishFactory() {}
+  virtual ~GpuChannelEstablishFactory() = default;
 
   virtual void EstablishGpuChannel(
       const GpuChannelEstablishedCallback& callback) = 0;
diff --git a/gpu/ipc/client/gpu_memory_buffer_impl_native_pixmap.cc b/gpu/ipc/client/gpu_memory_buffer_impl_native_pixmap.cc
index 830405e..00d0ca0 100644
--- a/gpu/ipc/client/gpu_memory_buffer_impl_native_pixmap.cc
+++ b/gpu/ipc/client/gpu_memory_buffer_impl_native_pixmap.cc
@@ -41,7 +41,7 @@
       planes_(planes),
       fd_(std::move(fd)) {}
 
-GpuMemoryBufferImplNativePixmap::~GpuMemoryBufferImplNativePixmap() {}
+GpuMemoryBufferImplNativePixmap::~GpuMemoryBufferImplNativePixmap() = default;
 
 // static
 std::unique_ptr<GpuMemoryBufferImplNativePixmap>
diff --git a/gpu/ipc/client/gpu_memory_buffer_impl_shared_memory.cc b/gpu/ipc/client/gpu_memory_buffer_impl_shared_memory.cc
index e629a5f..07506ca 100644
--- a/gpu/ipc/client/gpu_memory_buffer_impl_shared_memory.cc
+++ b/gpu/ipc/client/gpu_memory_buffer_impl_shared_memory.cc
@@ -35,7 +35,7 @@
   DCHECK(IsSizeValidForFormat(size, format));
 }
 
-GpuMemoryBufferImplSharedMemory::~GpuMemoryBufferImplSharedMemory() {}
+GpuMemoryBufferImplSharedMemory::~GpuMemoryBufferImplSharedMemory() = default;
 
 // static
 std::unique_ptr<GpuMemoryBufferImplSharedMemory>
diff --git a/gpu/ipc/common/memory_stats.cc b/gpu/ipc/common/memory_stats.cc
index 2a6cc48..aecaf4eb4 100644
--- a/gpu/ipc/common/memory_stats.cc
+++ b/gpu/ipc/common/memory_stats.cc
@@ -12,11 +12,11 @@
 VideoMemoryUsageStats::VideoMemoryUsageStats(
     const VideoMemoryUsageStats& other) = default;
 
-VideoMemoryUsageStats::~VideoMemoryUsageStats() {}
+VideoMemoryUsageStats::~VideoMemoryUsageStats() = default;
 
 VideoMemoryUsageStats::ProcessStats::ProcessStats()
     : video_memory(0), has_duplicates(false) {}
 
-VideoMemoryUsageStats::ProcessStats::~ProcessStats() {}
+VideoMemoryUsageStats::ProcessStats::~ProcessStats() = default;
 
 }  // namespace gpu
diff --git a/gpu/ipc/common/struct_traits_unittest.cc b/gpu/ipc/common/struct_traits_unittest.cc
index c8dd7b2..9f868dcd 100644
--- a/gpu/ipc/common/struct_traits_unittest.cc
+++ b/gpu/ipc/common/struct_traits_unittest.cc
@@ -19,7 +19,7 @@
 
 class StructTraitsTest : public testing::Test, public mojom::TraitsTestService {
  public:
-  StructTraitsTest() {}
+  StructTraitsTest() = default;
 
  protected:
   mojom::TraitsTestServicePtr GetTraitsTestProxy() {
diff --git a/gpu/ipc/gpu_in_process_thread_service.cc b/gpu/ipc/gpu_in_process_thread_service.cc
index b0da25e5..f79d1b8 100644
--- a/gpu/ipc/gpu_in_process_thread_service.cc
+++ b/gpu/ipc/gpu_in_process_thread_service.cc
@@ -50,6 +50,6 @@
   return false;
 }
 
-GpuInProcessThreadService::~GpuInProcessThreadService() {}
+GpuInProcessThreadService::~GpuInProcessThreadService() = default;
 
 }  // namespace gpu
diff --git a/gpu/ipc/host/shader_disk_cache.cc b/gpu/ipc/host/shader_disk_cache.cc
index 21ac628f..7504616 100644
--- a/gpu/ipc/host/shader_disk_cache.cc
+++ b/gpu/ipc/host/shader_disk_cache.cc
@@ -419,9 +419,9 @@
 ////////////////////////////////////////////////////////////////////////////////
 // ShaderCacheFactory
 
-ShaderCacheFactory::ShaderCacheFactory() {}
+ShaderCacheFactory::ShaderCacheFactory() = default;
 
-ShaderCacheFactory::~ShaderCacheFactory() {}
+ShaderCacheFactory::~ShaderCacheFactory() = default;
 
 void ShaderCacheFactory::SetCacheInfo(int32_t client_id,
                                       const base::FilePath& path) {
diff --git a/gpu/ipc/host/shader_disk_cache_unittest.cc b/gpu/ipc/host/shader_disk_cache_unittest.cc
index 80ecb3b..323a563 100644
--- a/gpu/ipc/host/shader_disk_cache_unittest.cc
+++ b/gpu/ipc/host/shader_disk_cache_unittest.cc
@@ -21,9 +21,9 @@
 
 class ShaderDiskCacheTest : public testing::Test {
  public:
-  ShaderDiskCacheTest() {}
+  ShaderDiskCacheTest() = default;
 
-  ~ShaderDiskCacheTest() override {}
+  ~ShaderDiskCacheTest() override = default;
 
   const base::FilePath& cache_path() { return temp_dir_.GetPath(); }
 
diff --git a/gpu/ipc/in_process_command_buffer.cc b/gpu/ipc/in_process_command_buffer.cc
index 6fd2adb..5b74a22 100644
--- a/gpu/ipc/in_process_command_buffer.cc
+++ b/gpu/ipc/in_process_command_buffer.cc
@@ -151,7 +151,7 @@
   }
 }
 
-InProcessCommandBuffer::Service::~Service() {}
+InProcessCommandBuffer::Service::~Service() = default;
 
 const GpuPreferences& InProcessCommandBuffer::Service::gpu_preferences() {
   return gpu_preferences_;
@@ -1182,6 +1182,6 @@
                                          uint32_t order_number)
     : callback(callback), order_number(order_number) {}
 
-InProcessCommandBuffer::GpuTask::~GpuTask() {}
+InProcessCommandBuffer::GpuTask::~GpuTask() = default;
 
 }  // namespace gpu
diff --git a/gpu/ipc/service/command_buffer_stub.cc b/gpu/ipc/service/command_buffer_stub.cc
index 4227d3a4c..fc052e88 100644
--- a/gpu/ipc/service/command_buffer_stub.cc
+++ b/gpu/ipc/service/command_buffer_stub.cc
@@ -176,7 +176,7 @@
  public:
   static std::unique_ptr<base::trace_event::ConvertableToTraceFormat>
   CreateForChannel(GpuChannel* channel);
-  ~DevToolsChannelData() override {}
+  ~DevToolsChannelData() override = default;
 
   void AppendAsTraceFormat(std::string* out) const override {
     std::string tmp;
diff --git a/gpu/ipc/service/command_buffer_stub.h b/gpu/ipc/service/command_buffer_stub.h
index 752ad88..e856cd9a 100644
--- a/gpu/ipc/service/command_buffer_stub.h
+++ b/gpu/ipc/service/command_buffer_stub.h
@@ -60,7 +60,7 @@
     virtual void OnWillDestroyStub() = 0;
 
    protected:
-    virtual ~DestructionObserver() {}
+    virtual ~DestructionObserver() = default;
   };
 
   CommandBufferStub(GpuChannel* channel,
diff --git a/gpu/ipc/service/gpu_channel_manager_delegate.h b/gpu/ipc/service/gpu_channel_manager_delegate.h
index cb1e078..b583e94d 100644
--- a/gpu/ipc/service/gpu_channel_manager_delegate.h
+++ b/gpu/ipc/service/gpu_channel_manager_delegate.h
@@ -50,7 +50,7 @@
   virtual void SetActiveURL(const GURL& url) = 0;
 
  protected:
-  virtual ~GpuChannelManagerDelegate() {}
+  virtual ~GpuChannelManagerDelegate() = default;
 };
 
 }  // namespace gpu
diff --git a/gpu/ipc/service/gpu_channel_manager_unittest.cc b/gpu/ipc/service/gpu_channel_manager_unittest.cc
index d7ef95c..c4443930 100644
--- a/gpu/ipc/service/gpu_channel_manager_unittest.cc
+++ b/gpu/ipc/service/gpu_channel_manager_unittest.cc
@@ -16,7 +16,7 @@
 class GpuChannelManagerTest : public GpuChannelTestCommon {
  public:
   GpuChannelManagerTest() : GpuChannelTestCommon() {}
-  ~GpuChannelManagerTest() override {}
+  ~GpuChannelManagerTest() override = default;
 
 #if defined(OS_ANDROID)
   void TestOnApplicationStateChange(gles2::ContextType type,
diff --git a/gpu/ipc/service/gpu_init.cc b/gpu/ipc/service/gpu_init.cc
index 0ca6403..507f852 100644
--- a/gpu/ipc/service/gpu_init.cc
+++ b/gpu/ipc/service/gpu_init.cc
@@ -92,7 +92,7 @@
 
 }  // namespace
 
-GpuInit::GpuInit() {}
+GpuInit::GpuInit() = default;
 
 GpuInit::~GpuInit() {
   gpu::StopForceDiscreteGPU();
diff --git a/gpu/ipc/service/gpu_init.h b/gpu/ipc/service/gpu_init.h
index 5799d46..173ca71 100644
--- a/gpu/ipc/service/gpu_init.h
+++ b/gpu/ipc/service/gpu_init.h
@@ -21,7 +21,7 @@
 
 class GPU_EXPORT GpuSandboxHelper {
  public:
-  virtual ~GpuSandboxHelper() {}
+  virtual ~GpuSandboxHelper() = default;
 
   virtual void PreSandboxStartup() = 0;
 
diff --git a/gpu/ipc/service/gpu_memory_buffer_factory.h b/gpu/ipc/service/gpu_memory_buffer_factory.h
index 55c83dc..31303529 100644
--- a/gpu/ipc/service/gpu_memory_buffer_factory.h
+++ b/gpu/ipc/service/gpu_memory_buffer_factory.h
@@ -21,7 +21,7 @@
 
 class GPU_EXPORT GpuMemoryBufferFactory {
  public:
-  virtual ~GpuMemoryBufferFactory() {}
+  virtual ~GpuMemoryBufferFactory() = default;
 
   // Creates a new factory instance for native GPU memory buffers. Returns null
   // if native buffers are not supported.
@@ -46,7 +46,7 @@
   virtual ImageFactory* AsImageFactory() = 0;
 
  protected:
-  GpuMemoryBufferFactory() {}
+  GpuMemoryBufferFactory() = default;
 
  private:
   DISALLOW_COPY_AND_ASSIGN(GpuMemoryBufferFactory);
diff --git a/gpu/ipc/service/gpu_memory_buffer_factory_android_hardware_buffer.cc b/gpu/ipc/service/gpu_memory_buffer_factory_android_hardware_buffer.cc
index d46185a5..5341ece 100644
--- a/gpu/ipc/service/gpu_memory_buffer_factory_android_hardware_buffer.cc
+++ b/gpu/ipc/service/gpu_memory_buffer_factory_android_hardware_buffer.cc
@@ -82,7 +82,8 @@
     const gfx::Size& size,
     gfx::BufferFormat format,
     gfx::BufferUsage usage,
-    unsigned internalformat) {
+    unsigned internalformat,
+    bool* is_cleared) {
   NOTIMPLEMENTED();
   return nullptr;
 }
diff --git a/gpu/ipc/service/gpu_memory_buffer_factory_android_hardware_buffer.h b/gpu/ipc/service/gpu_memory_buffer_factory_android_hardware_buffer.h
index 7cd7b614..84afa491f 100644
--- a/gpu/ipc/service/gpu_memory_buffer_factory_android_hardware_buffer.h
+++ b/gpu/ipc/service/gpu_memory_buffer_factory_android_hardware_buffer.h
@@ -42,11 +42,11 @@
       unsigned internalformat,
       int client_id,
       SurfaceHandle surface_handle) override;
-  scoped_refptr<gl::GLImage> CreateAnonymousImage(
-      const gfx::Size& size,
-      gfx::BufferFormat format,
-      gfx::BufferUsage usage,
-      unsigned internalformat) override;
+  scoped_refptr<gl::GLImage> CreateAnonymousImage(const gfx::Size& size,
+                                                  gfx::BufferFormat format,
+                                                  gfx::BufferUsage usage,
+                                                  unsigned internalformat,
+                                                  bool* is_cleared) override;
   unsigned RequiredTextureType() override;
 
  private:
diff --git a/gpu/ipc/service/gpu_memory_buffer_factory_dxgi.cc b/gpu/ipc/service/gpu_memory_buffer_factory_dxgi.cc
index 0526f6d..7a67cce 100644
--- a/gpu/ipc/service/gpu_memory_buffer_factory_dxgi.cc
+++ b/gpu/ipc/service/gpu_memory_buffer_factory_dxgi.cc
@@ -121,7 +121,8 @@
     const gfx::Size& size,
     gfx::BufferFormat format,
     gfx::BufferUsage usage,
-    unsigned internalformat) {
+    unsigned internalformat,
+    bool* is_cleared) {
   NOTIMPLEMENTED();
   return nullptr;
 }
@@ -133,4 +134,4 @@
 bool GpuMemoryBufferFactoryDXGI::SupportsFormatRGB() {
   return true;
 }
-}  // namespace gpu
\ No newline at end of file
+}  // namespace gpu
diff --git a/gpu/ipc/service/gpu_memory_buffer_factory_dxgi.h b/gpu/ipc/service/gpu_memory_buffer_factory_dxgi.h
index f9bac6f..73e160f 100644
--- a/gpu/ipc/service/gpu_memory_buffer_factory_dxgi.h
+++ b/gpu/ipc/service/gpu_memory_buffer_factory_dxgi.h
@@ -52,11 +52,11 @@
       unsigned internalformat,
       int client_id,
       SurfaceHandle surface_handle) override;
-  scoped_refptr<gl::GLImage> CreateAnonymousImage(
-      const gfx::Size& size,
-      gfx::BufferFormat format,
-      gfx::BufferUsage usage,
-      unsigned internalformat) override;
+  scoped_refptr<gl::GLImage> CreateAnonymousImage(const gfx::Size& size,
+                                                  gfx::BufferFormat format,
+                                                  gfx::BufferUsage usage,
+                                                  unsigned internalformat,
+                                                  bool* is_cleared) override;
   unsigned RequiredTextureType() override;
   bool SupportsFormatRGB() override;
 
diff --git a/gpu/ipc/service/gpu_memory_buffer_factory_io_surface.cc b/gpu/ipc/service/gpu_memory_buffer_factory_io_surface.cc
index 475e083..fd3bf0b 100644
--- a/gpu/ipc/service/gpu_memory_buffer_factory_io_surface.cc
+++ b/gpu/ipc/service/gpu_memory_buffer_factory_io_surface.cc
@@ -28,8 +28,10 @@
     gfx::BufferUsage usage,
     int client_id,
     SurfaceHandle surface_handle) {
+  // Don't clear anonymous io surfaces.
+  bool should_clear = id.is_valid();
   base::ScopedCFTypeRef<IOSurfaceRef> io_surface(
-      gfx::CreateIOSurface(size, format));
+      gfx::CreateIOSurface(size, format, should_clear));
   if (!io_surface)
     return gfx::GpuMemoryBufferHandle();
 
@@ -93,12 +95,13 @@
 GpuMemoryBufferFactoryIOSurface::CreateAnonymousImage(const gfx::Size& size,
                                                       gfx::BufferFormat format,
                                                       gfx::BufferUsage usage,
-                                                      unsigned internalformat) {
+                                                      unsigned internalformat,
+                                                      bool* is_cleared) {
   // Note that the child id doesn't matter since the texture will never be
   // directly exposed to other processes, only via a mailbox.
-  gfx::GpuMemoryBufferHandle handle = CreateGpuMemoryBuffer(
-      gfx::GpuMemoryBufferId(next_service_gmb_id_++), size, format, usage,
-      0 /* client_id */, gpu::kNullSurfaceHandle);
+  gfx::GpuMemoryBufferHandle handle =
+      CreateGpuMemoryBuffer(gfx::GpuMemoryBufferId(), size, format, usage,
+                            0 /* client_id */, gpu::kNullSurfaceHandle);
 
   base::ScopedCFTypeRef<IOSurfaceRef> io_surface;
   io_surface.reset(IOSurfaceLookupFromMachPort(handle.mach_port.get()));
@@ -109,6 +112,7 @@
   if (!image->Initialize(io_surface.get(), handle.id, format))
     return scoped_refptr<gl::GLImage>();
 
+  *is_cleared = false;
   return image;
 }
 
diff --git a/gpu/ipc/service/gpu_memory_buffer_factory_io_surface.h b/gpu/ipc/service/gpu_memory_buffer_factory_io_surface.h
index 9c9133c..66608ce4 100644
--- a/gpu/ipc/service/gpu_memory_buffer_factory_io_surface.h
+++ b/gpu/ipc/service/gpu_memory_buffer_factory_io_surface.h
@@ -54,11 +54,11 @@
       unsigned internalformat,
       int client_id,
       SurfaceHandle surface_handle) override;
-  scoped_refptr<gl::GLImage> CreateAnonymousImage(
-      const gfx::Size& size,
-      gfx::BufferFormat format,
-      gfx::BufferUsage usage,
-      unsigned internalformat) override;
+  scoped_refptr<gl::GLImage> CreateAnonymousImage(const gfx::Size& size,
+                                                  gfx::BufferFormat format,
+                                                  gfx::BufferUsage usage,
+                                                  unsigned internalformat,
+                                                  bool* is_cleared) override;
   unsigned RequiredTextureType() override;
   bool SupportsFormatRGB() override;
 
@@ -71,9 +71,6 @@
   IOSurfaceMap io_surfaces_;
   base::Lock io_surfaces_lock_;
 
-  // Assign unique ids to service side (anonymous) images for memory dumps.
-  int next_service_gmb_id_ = 1;
-
   DISALLOW_COPY_AND_ASSIGN(GpuMemoryBufferFactoryIOSurface);
 };
 
diff --git a/gpu/ipc/service/gpu_memory_buffer_factory_native_pixmap.cc b/gpu/ipc/service/gpu_memory_buffer_factory_native_pixmap.cc
index bddfa6d..81f0dd5 100644
--- a/gpu/ipc/service/gpu_memory_buffer_factory_native_pixmap.cc
+++ b/gpu/ipc/service/gpu_memory_buffer_factory_native_pixmap.cc
@@ -15,9 +15,11 @@
 
 namespace gpu {
 
-GpuMemoryBufferFactoryNativePixmap::GpuMemoryBufferFactoryNativePixmap() {}
+GpuMemoryBufferFactoryNativePixmap::GpuMemoryBufferFactoryNativePixmap() =
+    default;
 
-GpuMemoryBufferFactoryNativePixmap::~GpuMemoryBufferFactoryNativePixmap() {}
+GpuMemoryBufferFactoryNativePixmap::~GpuMemoryBufferFactoryNativePixmap() =
+    default;
 
 gfx::GpuMemoryBufferHandle
 GpuMemoryBufferFactoryNativePixmap::CreateGpuMemoryBuffer(
@@ -132,7 +134,8 @@
     const gfx::Size& size,
     gfx::BufferFormat format,
     gfx::BufferUsage usage,
-    unsigned internalformat) {
+    unsigned internalformat,
+    bool* is_cleared) {
   scoped_refptr<gfx::NativePixmap> pixmap;
 #if defined(USE_OZONE)
   pixmap =
@@ -154,6 +157,7 @@
                << static_cast<int>(format);
     return nullptr;
   }
+  *is_cleared = true;
   return image;
 }
 
diff --git a/gpu/ipc/service/gpu_memory_buffer_factory_native_pixmap.h b/gpu/ipc/service/gpu_memory_buffer_factory_native_pixmap.h
index 00c6bdc..44887d2 100644
--- a/gpu/ipc/service/gpu_memory_buffer_factory_native_pixmap.h
+++ b/gpu/ipc/service/gpu_memory_buffer_factory_native_pixmap.h
@@ -49,11 +49,11 @@
       unsigned internalformat,
       int client_id,
       SurfaceHandle surface_handle) override;
-  scoped_refptr<gl::GLImage> CreateAnonymousImage(
-      const gfx::Size& size,
-      gfx::BufferFormat format,
-      gfx::BufferUsage usage,
-      unsigned internalformat) override;
+  scoped_refptr<gl::GLImage> CreateAnonymousImage(const gfx::Size& size,
+                                                  gfx::BufferFormat format,
+                                                  gfx::BufferUsage usage,
+                                                  unsigned internalformat,
+                                                  bool* is_cleared) override;
   unsigned RequiredTextureType() override;
 
  private:
diff --git a/gpu/ipc/service/gpu_watchdog_thread.cc b/gpu/ipc/service/gpu_watchdog_thread.cc
index d88c2bd..de3e362e 100644
--- a/gpu/ipc/service/gpu_watchdog_thread.cc
+++ b/gpu/ipc/service/gpu_watchdog_thread.cc
@@ -133,7 +133,8 @@
     GpuWatchdogThread* watchdog)
     : watchdog_(watchdog) {}
 
-GpuWatchdogThread::GpuWatchdogTaskObserver::~GpuWatchdogTaskObserver() {}
+GpuWatchdogThread::GpuWatchdogTaskObserver::~GpuWatchdogTaskObserver() =
+    default;
 
 void GpuWatchdogThread::GpuWatchdogTaskObserver::WillProcessTask(
     const base::PendingTask& pending_task) {
diff --git a/gpu/ipc/service/image_transport_surface_delegate.h b/gpu/ipc/service/image_transport_surface_delegate.h
index 2af56568..73718ad 100644
--- a/gpu/ipc/service/image_transport_surface_delegate.h
+++ b/gpu/ipc/service/image_transport_surface_delegate.h
@@ -59,7 +59,7 @@
   virtual int32_t GetRouteID() const = 0;
 
  protected:
-  virtual ~ImageTransportSurfaceDelegate() {}
+  virtual ~ImageTransportSurfaceDelegate() = default;
 };
 
 }  // namespace gpu
diff --git a/gpu/perftests/measurements.cc b/gpu/perftests/measurements.cc
index 1b0d46d..01cae4d 100644
--- a/gpu/perftests/measurements.cc
+++ b/gpu/perftests/measurements.cc
@@ -12,14 +12,8 @@
 
 namespace gpu {
 
-Measurement::Measurement() : name(), wall_time(), cpu_time(), gpu_time() {
-}
-Measurement::Measurement(const Measurement& m)
-    : name(m.name),
-      wall_time(m.wall_time),
-      cpu_time(m.cpu_time),
-      gpu_time(m.gpu_time) {
-}
+Measurement::Measurement() = default;
+Measurement::Measurement(const Measurement& m) = default;
 Measurement::Measurement(const std::string& name,
                          const base::TimeDelta wall_time,
                          const base::TimeDelta cpu_time,
@@ -51,8 +45,7 @@
   return Measurement(name, wall_time / a, cpu_time / a, gpu_time / a);
 }
 
-Measurement::~Measurement() {
-}
+Measurement::~Measurement() = default;
 
 MeasurementTimers::MeasurementTimers(gl::GPUTimingClient* gpu_timing_client)
     : wall_time_start_(), cpu_time_start_(), gpu_timer_() {
diff --git a/headless/app/headless_shell.cc b/headless/app/headless_shell.cc
index 1c6537d15..332713d5 100644
--- a/headless/app/headless_shell.cc
+++ b/headless/app/headless_shell.cc
@@ -17,7 +17,6 @@
 #include "base/files/file_util.h"
 #include "base/json/json_writer.h"
 #include "base/location.h"
-#include "base/memory/ptr_util.h"
 #include "base/memory/weak_ptr.h"
 #include "base/numerics/safe_conversions.h"
 #include "base/path_service.h"
@@ -160,12 +159,12 @@
 
     ProtocolHandlerMap protocol_handlers;
     protocol_handlers[url::kHttpScheme] =
-        base::MakeUnique<DeterministicHttpProtocolHandler>(
+        std::make_unique<DeterministicHttpProtocolHandler>(
             deterministic_dispatcher_.get(), browser->BrowserIOThread());
     http_handler = static_cast<DeterministicHttpProtocolHandler*>(
         protocol_handlers[url::kHttpScheme].get());
     protocol_handlers[url::kHttpsScheme] =
-        base::MakeUnique<DeterministicHttpProtocolHandler>(
+        std::make_unique<DeterministicHttpProtocolHandler>(
             deterministic_dispatcher_.get(), browser->BrowserIOThread());
     https_handler = static_cast<DeterministicHttpProtocolHandler*>(
         protocol_handlers[url::kHttpsScheme].get());
@@ -378,7 +377,7 @@
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
   if (params.GetIsNavigationRequest()) {
     deterministic_dispatcher_->NavigationRequested(
-        base::MakeUnique<ShellNavigationRequest>(weak_factory_.GetWeakPtr(),
+        std::make_unique<ShellNavigationRequest>(weak_factory_.GetWeakPtr(),
                                                  params.GetInterceptionId()));
     return;
   }
@@ -519,7 +518,7 @@
     return;
   }
 
-  file_proxy_ = base::MakeUnique<base::FileProxy>(file_task_runner_.get());
+  file_proxy_ = std::make_unique<base::FileProxy>(file_task_runner_.get());
   if (!file_proxy_->CreateOrOpen(
           file_name, base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE,
           base::Bind(&HeadlessShell::OnFileOpened, weak_factory_.GetWeakPtr(),
diff --git a/headless/app/shell_navigation_request.cc b/headless/app/shell_navigation_request.cc
index 3f5344d..e1af96b 100644
--- a/headless/app/shell_navigation_request.cc
+++ b/headless/app/shell_navigation_request.cc
@@ -4,6 +4,8 @@
 
 #include "headless/app/shell_navigation_request.h"
 
+#include <memory>
+
 #include "content/public/browser/browser_thread.h"
 #include "headless/app/headless_shell.h"
 
@@ -13,7 +15,7 @@
     base::WeakPtr<HeadlessShell> headless_shell,
     const std::string& interception_id)
     : headless_shell_(
-          base::MakeUnique<base::WeakPtr<HeadlessShell>>(headless_shell)),
+          std::make_unique<base::WeakPtr<HeadlessShell>>(headless_shell)),
       interception_id_(interception_id) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
 }
diff --git a/headless/lib/browser/headless_browser_context_impl.cc b/headless/lib/browser/headless_browser_context_impl.cc
index 17849e2..137467e 100644
--- a/headless/lib/browser/headless_browser_context_impl.cc
+++ b/headless/lib/browser/headless_browser_context_impl.cc
@@ -10,7 +10,6 @@
 #include <vector>
 
 #include "base/guid.h"
-#include "base/memory/ptr_util.h"
 #include "base/path_service.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/resource_context.h"
@@ -510,9 +509,9 @@
     // context with mojo bindings.
     if (!enable_http_and_https_if_mojo_used_) {
       options_->protocol_handlers_[url::kHttpScheme] =
-          base::MakeUnique<BlackHoleProtocolHandler>();
+          std::make_unique<BlackHoleProtocolHandler>();
       options_->protocol_handlers_[url::kHttpsScheme] =
-          base::MakeUnique<BlackHoleProtocolHandler>();
+          std::make_unique<BlackHoleProtocolHandler>();
     }
   }
 
diff --git a/headless/lib/browser/headless_browser_impl_aura.cc b/headless/lib/browser/headless_browser_impl_aura.cc
index ccebd34..fc2392c 100644
--- a/headless/lib/browser/headless_browser_impl_aura.cc
+++ b/headless/lib/browser/headless_browser_impl_aura.cc
@@ -4,6 +4,8 @@
 
 #include "headless/lib/browser/headless_browser_impl.h"
 
+#include <memory>
+
 #include "content/public/browser/render_widget_host_view.h"
 #include "content/public/browser/web_contents.h"
 #include "headless/lib/browser/headless_clipboard.h"
@@ -24,7 +26,7 @@
   // TODO(eseckler): We shouldn't share clipboard contents across WebContents
   // (or at least BrowserContexts).
   ui::Clipboard::SetClipboardForCurrentThread(
-      base::MakeUnique<HeadlessClipboard>());
+      std::make_unique<HeadlessClipboard>());
 }
 
 void HeadlessBrowserImpl::PlatformStart() {
@@ -34,7 +36,7 @@
 
 void HeadlessBrowserImpl::PlatformInitializeWebContents(
     HeadlessWebContentsImpl* web_contents) {
-  auto window_tree_host = base::MakeUnique<HeadlessWindowTreeHost>(
+  auto window_tree_host = std::make_unique<HeadlessWindowTreeHost>(
       gfx::Rect(), web_contents->begin_frame_control_enabled());
   window_tree_host->InitHost();
   gfx::NativeWindow parent_window = window_tree_host->window();
diff --git a/headless/lib/browser/headless_content_browser_client.cc b/headless/lib/browser/headless_content_browser_client.cc
index 9843462..36b6a3b 100644
--- a/headless/lib/browser/headless_content_browser_client.cc
+++ b/headless/lib/browser/headless_content_browser_client.cc
@@ -11,7 +11,6 @@
 #include "base/callback.h"
 #include "base/command_line.h"
 #include "base/json/json_reader.h"
-#include "base/memory/ptr_util.h"
 #include "base/path_service.h"
 #include "content/public/browser/browser_context.h"
 #include "content/public/browser/browser_thread.h"
@@ -124,7 +123,7 @@
 content::BrowserMainParts* HeadlessContentBrowserClient::CreateBrowserMainParts(
     const content::MainFunctionParams&) {
   std::unique_ptr<HeadlessBrowserMainParts> browser_main_parts =
-      base::MakeUnique<HeadlessBrowserMainParts>(browser_);
+      std::make_unique<HeadlessBrowserMainParts>(browser_);
   browser_->set_browser_main_parts(browser_main_parts.get());
   return browser_main_parts.release();
 }
diff --git a/headless/lib/browser/headless_devtools_client_impl.cc b/headless/lib/browser/headless_devtools_client_impl.cc
index 9763565c59..d8b59c0a 100644
--- a/headless/lib/browser/headless_devtools_client_impl.cc
+++ b/headless/lib/browser/headless_devtools_client_impl.cc
@@ -177,7 +177,7 @@
     if (message_dict.GetDictionary("result", &result_dict)) {
       callback.callback_with_result.Run(*result_dict);
     } else if (message_dict.GetDictionary("error", &result_dict)) {
-      auto null_value = base::MakeUnique<base::Value>();
+      auto null_value = std::make_unique<base::Value>();
       DLOG(ERROR) << "Error in method call result: " << *result_dict;
       callback.callback_with_result.Run(*null_value);
     } else {
diff --git a/headless/lib/browser/headless_devtools_manager_delegate.cc b/headless/lib/browser/headless_devtools_manager_delegate.cc
index 553d715..b93acb3 100644
--- a/headless/lib/browser/headless_devtools_manager_delegate.cc
+++ b/headless/lib/browser/headless_devtools_manager_delegate.cc
@@ -50,9 +50,9 @@
     int command_id,
     std::unique_ptr<base::Value> result) {
   if (!result)
-    result = base::MakeUnique<base::DictionaryValue>();
+    result = std::make_unique<base::DictionaryValue>();
 
-  auto response = base::MakeUnique<base::DictionaryValue>();
+  auto response = std::make_unique<base::DictionaryValue>();
   response->SetInteger(kIdParam, command_id);
   response->Set(kResultParam, std::move(result));
   return response;
@@ -62,11 +62,11 @@
     int command_id,
     int error_code,
     const std::string& error_message) {
-  auto error_object = base::MakeUnique<base::DictionaryValue>();
+  auto error_object = std::make_unique<base::DictionaryValue>();
   error_object->SetInteger(kErrorCodeParam, error_code);
   error_object->SetString(kErrorMessageParam, error_message);
 
-  auto response = base::MakeUnique<base::DictionaryValue>();
+  auto response = std::make_unique<base::DictionaryValue>();
   response->SetInteger(kIdParam, command_id);
   response->Set(kErrorParam, std::move(error_object));
   return response;
@@ -82,7 +82,7 @@
 
 std::unique_ptr<base::DictionaryValue> CreateBoundsDict(
     const HeadlessWebContentsImpl* web_contents) {
-  auto bounds_object = base::MakeUnique<base::DictionaryValue>();
+  auto bounds_object = std::make_unique<base::DictionaryValue>();
   gfx::Rect bounds = web_contents->web_contents()->GetContainerBounds();
   bounds_object->SetInteger("left", bounds.x());
   bounds_object->SetInteger("top", bounds.y());
@@ -157,7 +157,7 @@
     bool has_damage,
     bool main_frame_content_updated,
     std::unique_ptr<SkBitmap> bitmap) {
-  auto result = base::MakeUnique<base::DictionaryValue>();
+  auto result = std::make_unique<base::DictionaryValue>();
   result->SetBoolean("hasDamage", has_damage);
   result->SetBoolean("mainFrameContentUpdated", main_frame_content_updated);
 
@@ -621,7 +621,7 @@
                                "No web contents for the given target id");
   }
 
-  auto result = base::MakeUnique<base::DictionaryValue>();
+  auto result = std::make_unique<base::DictionaryValue>();
   result->SetInteger("windowId", web_contents->window_id());
   result->Set("bounds", CreateBoundsDict(web_contents));
   return CreateSuccessResponse(command_id, std::move(result));
@@ -655,7 +655,7 @@
                                "Browser window not found");
   }
 
-  auto result = base::MakeUnique<base::DictionaryValue>();
+  auto result = std::make_unique<base::DictionaryValue>();
   result->Set("bounds", CreateBoundsDict(web_contents));
   return CreateSuccessResponse(command_id, std::move(result));
 }
diff --git a/headless/lib/browser/headless_net_log.cc b/headless/lib/browser/headless_net_log.cc
index 08a26f68..57f5580 100644
--- a/headless/lib/browser/headless_net_log.cc
+++ b/headless/lib/browser/headless_net_log.cc
@@ -4,12 +4,12 @@
 
 #include "headless/lib/browser/headless_net_log.h"
 
+#include <memory>
 #include <utility>
 
 #include "base/bind.h"
 #include "base/command_line.h"
 #include "base/files/file_path.h"
-#include "base/memory/ptr_util.h"
 #include "base/values.h"
 #include "build/build_config.h"
 #include "content/public/common/content_switches.h"
@@ -24,7 +24,7 @@
       net::GetNetConstants();
 
   // Add a dictionary with client information
-  auto dict = base::MakeUnique<base::DictionaryValue>();
+  auto dict = std::make_unique<base::DictionaryValue>();
 
   dict->SetString("name", "headless");
   dict->SetString(
diff --git a/headless/lib/browser/headless_print_manager.cc b/headless/lib/browser/headless_print_manager.cc
index e7a816d..df3b27c 100644
--- a/headless/lib/browser/headless_print_manager.cc
+++ b/headless/lib/browser/headless_print_manager.cc
@@ -4,11 +4,11 @@
 
 #include "headless/lib/browser/headless_print_manager.h"
 
+#include <memory>
 #include <utility>
 #include <vector>
 
 #include "base/base64.h"
-#include "base/memory/ptr_util.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_piece.h"
 #include "base/strings/string_split.h"
@@ -89,7 +89,7 @@
 HeadlessPrintManager::PDFContentsToDictionaryValue(const std::string& data) {
   std::string base_64_data;
   base::Base64Encode(data, &base_64_data);
-  auto result = base::MakeUnique<base::DictionaryValue>();
+  auto result = std::make_unique<base::DictionaryValue>();
   result->SetString("data", base_64_data);
   return result;
 }
@@ -198,7 +198,7 @@
   print_settings.SetPrinterPrintableArea(settings.paper_size_in_points,
                                          printable_area_device_units, true);
 
-  auto print_params = base::MakeUnique<PrintMsg_PrintPages_Params>();
+  auto print_params = std::make_unique<PrintMsg_PrintPages_Params>();
   printing::RenderParamsFromPrintSettings(print_settings,
                                           &print_params->params);
   print_params->params.document_cookie = printing::PrintSettings::NewCookie();
@@ -306,7 +306,7 @@
       return;
     }
     auto shared_buf =
-        base::MakeUnique<base::SharedMemory>(params.metafile_data_handle, true);
+        std::make_unique<base::SharedMemory>(params.metafile_data_handle, true);
     if (!shared_buf->Map(params.data_size)) {
       ReleaseJob(METAFILE_MAP_ERROR);
       return;
diff --git a/headless/lib/browser/headless_printing_unittest.cc b/headless/lib/browser/headless_printing_unittest.cc
index 5cdf858..ad7caa7 100644
--- a/headless/lib/browser/headless_printing_unittest.cc
+++ b/headless/lib/browser/headless_printing_unittest.cc
@@ -2,7 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "base/memory/ptr_util.h"
+#include <memory>
+
 #include "base/values.h"
 #include "headless/lib/browser/headless_devtools_manager_delegate.h"
 #include "headless/lib/browser/headless_print_manager.h"
@@ -16,7 +17,7 @@
   HeadlessPrintSettings settings;
   EXPECT_FALSE(settings.landscape);
 
-  auto params = base::MakeUnique<base::DictionaryValue>();
+  auto params = std::make_unique<base::DictionaryValue>();
   params->SetBoolean("landscape", true);
   std::unique_ptr<base::DictionaryValue> response =
       ParsePrintSettings(0, params.get(), &settings);
@@ -28,7 +29,7 @@
   HeadlessPrintSettings settings;
   EXPECT_FALSE(settings.display_header_footer);
 
-  auto params = base::MakeUnique<base::DictionaryValue>();
+  auto params = std::make_unique<base::DictionaryValue>();
   params->SetBoolean("displayHeaderFooter", true);
   std::unique_ptr<base::DictionaryValue> response =
       ParsePrintSettings(0, params.get(), &settings);
@@ -40,7 +41,7 @@
   HeadlessPrintSettings settings;
   EXPECT_FALSE(settings.should_print_backgrounds);
 
-  auto params = base::MakeUnique<base::DictionaryValue>();
+  auto params = std::make_unique<base::DictionaryValue>();
   params->SetBoolean("printBackground", true);
   std::unique_ptr<base::DictionaryValue> response =
       ParsePrintSettings(0, params.get(), &settings);
@@ -52,7 +53,7 @@
   HeadlessPrintSettings settings;
   EXPECT_DOUBLE_EQ(1, settings.scale);
 
-  auto params = base::MakeUnique<base::DictionaryValue>();
+  auto params = std::make_unique<base::DictionaryValue>();
   params->SetDouble("scale", 0.5);
   std::unique_ptr<base::DictionaryValue> response =
       ParsePrintSettings(0, params.get(), &settings);
@@ -72,7 +73,7 @@
   HeadlessPrintSettings settings;
   EXPECT_EQ("", settings.page_ranges);
 
-  auto params = base::MakeUnique<base::DictionaryValue>();
+  auto params = std::make_unique<base::DictionaryValue>();
   params->SetString("pageRanges", "abcd");
   params->SetBoolean("ignoreInvalidPageRanges", true);
   std::unique_ptr<base::DictionaryValue> response =
@@ -88,7 +89,7 @@
 TEST(ParsePrintSettingsTest, Paper) {
   HeadlessPrintSettings settings;
 
-  auto params = base::MakeUnique<base::DictionaryValue>();
+  auto params = std::make_unique<base::DictionaryValue>();
   std::unique_ptr<base::DictionaryValue> response =
       ParsePrintSettings(0, params.get(), &settings);
   EXPECT_EQ(printing::kLetterWidthInch * printing::kPointsPerInch,
@@ -120,7 +121,7 @@
 TEST(ParsePrintSettingsTest, Margin) {
   HeadlessPrintSettings settings;
 
-  auto params = base::MakeUnique<base::DictionaryValue>();
+  auto params = std::make_unique<base::DictionaryValue>();
   std::unique_ptr<base::DictionaryValue> response =
       ParsePrintSettings(0, params.get(), &settings);
   int default_margin =
diff --git a/headless/lib/browser/headless_url_request_context_getter.cc b/headless/lib/browser/headless_url_request_context_getter.cc
index 9df0218..b5489a8d7 100644
--- a/headless/lib/browser/headless_url_request_context_getter.cc
+++ b/headless/lib/browser/headless_url_request_context_getter.cc
@@ -8,7 +8,6 @@
 #include <utility>
 #include <vector>
 
-#include "base/memory/ptr_util.h"
 #include "base/task_scheduler/post_task.h"
 #include "build/build_config.h"
 #include "components/cookie_config/cookie_store_util.h"
@@ -123,7 +122,7 @@
         std::unique_ptr<net::CookieStore> cookie_store =
             CreateCookieStore(cookie_config);
         std::unique_ptr<net::ChannelIDService> channel_id_service =
-            base::MakeUnique<net::ChannelIDService>(
+            std::make_unique<net::ChannelIDService>(
                 new net::DefaultChannelIDStore(nullptr));
 
         cookie_store->SetChannelIDServiceID(channel_id_service->GetUniqueID());
@@ -147,7 +146,7 @@
     {
       base::AutoLock lock(lock_);
       builder.set_network_delegate(
-          base::MakeUnique<HeadlessNetworkDelegate>(headless_browser_context_));
+          std::make_unique<HeadlessNetworkDelegate>(headless_browser_context_));
     }
 
     if (!host_resolver_rules_.empty()) {
diff --git a/headless/lib/browser/headless_web_contents_impl.cc b/headless/lib/browser/headless_web_contents_impl.cc
index cc0c750..4e98eaf5 100644
--- a/headless/lib/browser/headless_web_contents_impl.cc
+++ b/headless/lib/browser/headless_web_contents_impl.cc
@@ -4,13 +4,13 @@
 
 #include "headless/lib/browser/headless_web_contents_impl.h"
 
+#include <memory>
 #include <string>
 #include <utility>
 #include <vector>
 
 #include "base/bind.h"
 #include "base/json/json_writer.h"
-#include "base/memory/ptr_util.h"
 #include "base/memory/weak_ptr.h"
 #include "base/stl_util.h"
 #include "base/strings/utf_string_conversions.h"
@@ -243,7 +243,7 @@
 
   if (builder->tab_sockets_allowed_) {
     headless_web_contents->headless_tab_socket_ =
-        base::MakeUnique<HeadlessTabSocketImpl>(
+        std::make_unique<HeadlessTabSocketImpl>(
             headless_web_contents->web_contents_.get());
     headless_web_contents->inject_mojo_services_into_isolated_world_ = true;
 
@@ -277,7 +277,7 @@
   child->mojo_services_ = parent->mojo_services_;
   if (parent->headless_tab_socket_) {
     child->headless_tab_socket_ =
-        base::MakeUnique<HeadlessTabSocketImpl>(child_contents);
+        std::make_unique<HeadlessTabSocketImpl>(child_contents);
     child->inject_mojo_services_into_isolated_world_ =
         parent->inject_mojo_services_into_isolated_world_;
   }
@@ -566,7 +566,7 @@
                "session_id", session_id, "needs_begin_frames",
                needs_external_begin_frames_);
   DCHECK(agent_host_);
-  auto params = base::MakeUnique<base::DictionaryValue>();
+  auto params = std::make_unique<base::DictionaryValue>();
   params->SetBoolean("needsBeginFrames", needs_external_begin_frames_);
 
   base::DictionaryValue event;
@@ -590,7 +590,7 @@
     base::DictionaryValue event;
     event.SetString("method",
                     "HeadlessExperimental.mainFrameReadyForScreenshots");
-    event.Set("params", base::MakeUnique<base::DictionaryValue>());
+    event.Set("params", std::make_unique<base::DictionaryValue>());
 
     std::string json_result;
     CHECK(base::JSONWriter::Write(event, &json_result));
@@ -615,7 +615,7 @@
       "headless", "HeadlessWebContentsImpl::PendingFrameReadbackComplete",
       "sequence_number", pending_frame->sequence_number, "response", response);
   if (response == content::READBACK_SUCCESS) {
-    pending_frame->bitmap = base::MakeUnique<SkBitmap>(bitmap);
+    pending_frame->bitmap = std::make_unique<SkBitmap>(bitmap);
   } else {
     LOG(WARNING) << "Readback from surface failed with response " << response;
   }
@@ -643,7 +643,7 @@
 
   uint64_t sequence_number = begin_frame_sequence_number_++;
 
-  auto pending_frame = base::MakeUnique<PendingFrame>();
+  auto pending_frame = std::make_unique<PendingFrame>();
   pending_frame->sequence_number = sequence_number;
   pending_frame->callback = frame_finished_callback;
 
diff --git a/headless/lib/frame_id_browsertest.cc b/headless/lib/frame_id_browsertest.cc
index 11253124..4a491f0 100644
--- a/headless/lib/frame_id_browsertest.cc
+++ b/headless/lib/frame_id_browsertest.cc
@@ -2,6 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include <memory>
+
 #include "base/bind.h"
 #include "base/run_loop.h"
 #include "base/single_thread_task_runner.h"
@@ -83,7 +85,7 @@
     devtools_client_->GetRuntime()->Enable();
 
     // Enabling the runtime domain will send us the current context.
-    run_loop_ = base::MakeUnique<base::RunLoop>(
+    run_loop_ = std::make_unique<base::RunLoop>(
         base::RunLoop::Type::kNestableTasksAllowed);
     run_loop_->Run();
     run_loop_ = nullptr;
@@ -106,7 +108,7 @@
 
     devtools_client_->GetPage()->AddObserver(this);
 
-    run_loop_ = base::MakeUnique<base::RunLoop>(
+    run_loop_ = std::make_unique<base::RunLoop>(
         base::RunLoop::Type::kNestableTasksAllowed);
     devtools_client_->GetPage()->Enable(run_loop_->QuitClosure());
     run_loop_->Run();
diff --git a/headless/lib/headless_browser_browsertest.cc b/headless/lib/headless_browser_browsertest.cc
index 0ed54b6..565b06e 100644
--- a/headless/lib/headless_browser_browsertest.cc
+++ b/headless/lib/headless_browser_browsertest.cc
@@ -7,7 +7,6 @@
 #include "base/command_line.h"
 #include "base/files/file_enumerator.h"
 #include "base/files/file_util.h"
-#include "base/memory/ptr_util.h"
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/threading/thread_restrictions.h"
@@ -262,7 +261,7 @@
   const std::string kResponseBody = "<p>HTTP response body</p>";
   ProtocolHandlerMap protocol_handlers;
   protocol_handlers[url::kHttpScheme] =
-      base::MakeUnique<TestProtocolHandler>(kResponseBody);
+      std::make_unique<TestProtocolHandler>(kResponseBody);
 
   HeadlessBrowserContext* browser_context =
       browser()
@@ -290,7 +289,7 @@
   const std::string kResponseBody = "<p>HTTPS response body</p>";
   ProtocolHandlerMap protocol_handlers;
   protocol_handlers[url::kHttpsScheme] =
-      base::MakeUnique<TestProtocolHandler>(kResponseBody);
+      std::make_unique<TestProtocolHandler>(kResponseBody);
 
   HeadlessBrowserContext* browser_context =
       browser()
@@ -483,7 +482,7 @@
   net::CookieList sent_cookies;
   ProtocolHandlerMap protocol_handlers;
   protocol_handlers[url::kHttpsScheme] =
-      base::MakeUnique<ProtocolHandlerWithCookies>(&sent_cookies);
+      std::make_unique<ProtocolHandlerWithCookies>(&sent_cookies);
 
   HeadlessBrowserContext* browser_context =
       browser()
@@ -830,7 +829,7 @@
       : browser_test_(browser_test),
         target_(target),
         client_(HeadlessDevToolsClient::Create()),
-        tracing_data_(base::MakeUnique<base::ListValue>()) {
+        tracing_data_(std::make_unique<base::ListValue>()) {
     EXPECT_FALSE(target_->IsAttached());
     target_->AttachClient(client_.get());
     EXPECT_TRUE(target_->IsAttached());
diff --git a/headless/lib/headless_browser_context_browsertest.cc b/headless/lib/headless_browser_context_browsertest.cc
index a40b10a..34e235d 100644
--- a/headless/lib/headless_browser_context_browsertest.cc
+++ b/headless/lib/headless_browser_context_browsertest.cc
@@ -5,7 +5,6 @@
 #include <memory>
 
 #include "base/files/scoped_temp_dir.h"
-#include "base/memory/ptr_util.h"
 #include "base/strings/stringprintf.h"
 #include "base/threading/thread_restrictions.h"
 #include "content/public/browser/render_view_host.h"
@@ -157,7 +156,7 @@
   const std::string kResponseBody = "<p>HTTP response body</p>";
   ProtocolHandlerMap protocol_handlers;
   protocol_handlers[url::kHttpScheme] =
-      base::MakeUnique<TestProtocolHandler>(kResponseBody);
+      std::make_unique<TestProtocolHandler>(kResponseBody);
 
   // Load a page which doesn't actually exist, but which is fetched by our
   // custom protocol handler.
diff --git a/headless/lib/headless_content_main_delegate.cc b/headless/lib/headless_content_main_delegate.cc
index 30e19fa..b6398e0d 100644
--- a/headless/lib/headless_content_main_delegate.cc
+++ b/headless/lib/headless_content_main_delegate.cc
@@ -4,6 +4,7 @@
 
 #include "headless/lib/headless_content_main_delegate.h"
 
+#include <memory>
 #include <utility>
 
 #include "base/base_switches.h"
@@ -340,7 +341,7 @@
 content::ContentBrowserClient*
 HeadlessContentMainDelegate::CreateContentBrowserClient() {
   browser_client_ =
-      base::MakeUnique<HeadlessContentBrowserClient>(browser_.get());
+      std::make_unique<HeadlessContentBrowserClient>(browser_.get());
   return browser_client_.get();
 }
 #endif  // !defined(CHROME_MULTIPLE_DLL_CHILD)
@@ -348,13 +349,13 @@
 #if !defined(CHROME_MULTIPLE_DLL_BROWSER)
 content::ContentRendererClient*
 HeadlessContentMainDelegate::CreateContentRendererClient() {
-  renderer_client_ = base::MakeUnique<HeadlessContentRendererClient>();
+  renderer_client_ = std::make_unique<HeadlessContentRendererClient>();
   return renderer_client_.get();
 }
 
 content::ContentUtilityClient*
 HeadlessContentMainDelegate::CreateContentUtilityClient() {
-  utility_client_ = base::MakeUnique<HeadlessContentUtilityClient>(
+  utility_client_ = std::make_unique<HeadlessContentUtilityClient>(
       browser_->options()->user_agent);
   return utility_client_.get();
 }
diff --git a/headless/lib/headless_devtools_client_browsertest.cc b/headless/lib/headless_devtools_client_browsertest.cc
index 44d8061..e3993ee9 100644
--- a/headless/lib/headless_devtools_client_browsertest.cc
+++ b/headless/lib/headless_devtools_client_browsertest.cc
@@ -1128,7 +1128,7 @@
     const std::string kResponseBody = "<p>HTTP response body</p>";
     ProtocolHandlerMap protocol_handlers;
     protocol_handlers[url::kHttpScheme] =
-        base::MakeUnique<TestProtocolHandler>(kResponseBody);
+        std::make_unique<TestProtocolHandler>(kResponseBody);
     test_handler_ = static_cast<TestProtocolHandler*>(
         protocol_handlers[url::kHttpScheme].get());
     return protocol_handlers;
diff --git a/headless/lib/renderer/headless_content_renderer_client.cc b/headless/lib/renderer/headless_content_renderer_client.cc
index edde2666..8fabc7a6 100644
--- a/headless/lib/renderer/headless_content_renderer_client.cc
+++ b/headless/lib/renderer/headless_content_renderer_client.cc
@@ -4,7 +4,8 @@
 
 #include "headless/lib/renderer/headless_content_renderer_client.h"
 
-#include "base/memory/ptr_util.h"
+#include <memory>
+
 #include "headless/lib/renderer/headless_render_frame_controller_impl.h"
 #include "printing/features/features.h"
 
@@ -23,7 +24,7 @@
     content::RenderFrame* render_frame) {
 #if BUILDFLAG(ENABLE_BASIC_PRINTING)
   new printing::PrintRenderFrameHelper(
-      render_frame, base::MakeUnique<HeadlessPrintRenderFrameHelperDelegate>());
+      render_frame, std::make_unique<HeadlessPrintRenderFrameHelperDelegate>());
 #endif
   new HeadlessRenderFrameControllerImpl(render_frame);
 }
diff --git a/headless/public/internal/value_conversions.h b/headless/public/internal/value_conversions.h
index 7f218b4..c9685d0 100644
--- a/headless/public/internal/value_conversions.h
+++ b/headless/public/internal/value_conversions.h
@@ -7,7 +7,6 @@
 
 #include <memory>
 
-#include "base/memory/ptr_util.h"
 #include "headless/public/util/error_reporter.h"
 
 namespace headless {
@@ -32,22 +31,22 @@
 // partially specialize vector types.
 template <typename T>
 std::unique_ptr<base::Value> ToValueImpl(int value, T*) {
-  return base::MakeUnique<base::Value>(value);
+  return std::make_unique<base::Value>(value);
 }
 
 template <typename T>
 std::unique_ptr<base::Value> ToValueImpl(double value, T*) {
-  return base::MakeUnique<base::Value>(value);
+  return std::make_unique<base::Value>(value);
 }
 
 template <typename T>
 std::unique_ptr<base::Value> ToValueImpl(bool value, T*) {
-  return base::MakeUnique<base::Value>(value);
+  return std::make_unique<base::Value>(value);
 }
 
 template <typename T>
 std::unique_ptr<base::Value> ToValueImpl(const std::string& value, T*) {
-  return base::MakeUnique<base::Value>(value);
+  return std::make_unique<base::Value>(value);
 }
 
 template <typename T>
diff --git a/headless/public/util/compositor_controller.cc b/headless/public/util/compositor_controller.cc
index 2bc803c8..d7b3664 100644
--- a/headless/public/util/compositor_controller.cc
+++ b/headless/public/util/compositor_controller.cc
@@ -4,11 +4,12 @@
 
 #include "headless/public/util/compositor_controller.h"
 
+#include <memory>
+
 #include "base/base64.h"
 #include "base/bind.h"
 #include "base/cancelable_callback.h"
 #include "base/logging.h"
-#include "base/memory/ptr_util.h"
 #include "base/single_thread_task_runner.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "base/trace_event/trace_event.h"
@@ -116,7 +117,7 @@
     : task_runner_(std::move(task_runner)),
       devtools_client_(devtools_client),
       virtual_time_controller_(virtual_time_controller),
-      animation_task_(base::MakeUnique<AnimationBeginFrameTask>(this)),
+      animation_task_(std::make_unique<AnimationBeginFrameTask>(this)),
       animation_begin_frame_interval_(animation_begin_frame_interval),
       wait_for_compositor_ready_begin_frame_delay_(
           wait_for_compositor_ready_begin_frame_delay),
diff --git a/headless/public/util/compositor_controller_browsertest.cc b/headless/public/util/compositor_controller_browsertest.cc
index 5169490..a3a4740 100644
--- a/headless/public/util/compositor_controller_browsertest.cc
+++ b/headless/public/util/compositor_controller_browsertest.cc
@@ -4,6 +4,8 @@
 
 #include "headless/public/util/compositor_controller.h"
 
+#include <memory>
+
 #include "base/bind.h"
 #include "base/command_line.h"
 #include "build/build_config.h"
@@ -42,8 +44,8 @@
 
   void RunDevTooledTest() override {
     virtual_time_controller_ =
-        base::MakeUnique<VirtualTimeController>(devtools_client_.get());
-    compositor_controller_ = base::MakeUnique<CompositorController>(
+        std::make_unique<VirtualTimeController>(devtools_client_.get());
+    compositor_controller_ = std::make_unique<CompositorController>(
         browser()->BrowserMainThread(), devtools_client_.get(),
         virtual_time_controller_.get(), kAnimationFrameInterval,
         kWaitForCompositorReadyFrameDelay);
diff --git a/headless/public/util/compositor_controller_unittest.cc b/headless/public/util/compositor_controller_unittest.cc
index 33aa032d..68c88d6 100644
--- a/headless/public/util/compositor_controller_unittest.cc
+++ b/headless/public/util/compositor_controller_unittest.cc
@@ -4,10 +4,11 @@
 
 #include "headless/public/util/compositor_controller.h"
 
+#include <memory>
+
 #include "base/base64.h"
 #include "base/bind.h"
 #include "base/json/json_writer.h"
-#include "base/memory/ptr_util.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/stringprintf.h"
 #include "base/test/test_simple_task_runner.h"
@@ -59,12 +60,12 @@
     EXPECT_CALL(*mock_host_, AttachClient(&client_));
     client_.AttachToHost(mock_host_.get());
     virtual_time_controller_ =
-        base::MakeUnique<TestVirtualTimeController>(&client_);
+        std::make_unique<TestVirtualTimeController>(&client_);
     EXPECT_CALL(*virtual_time_controller_,
                 ScheduleRepeatingTask(_, kAnimationFrameInterval))
         .WillOnce(testing::SaveArg<0>(&task_));
     ExpectHeadlessExperimentalEnable();
-    controller_ = base::MakeUnique<CompositorController>(
+    controller_ = std::make_unique<CompositorController>(
         task_runner_, &client_, virtual_time_controller_.get(),
         kAnimationFrameInterval, kWaitForCompositorReadyFrameDelay);
     EXPECT_NE(nullptr, task_);
diff --git a/headless/public/util/deterministic_dispatcher_test.cc b/headless/public/util/deterministic_dispatcher_test.cc
index 5b769800..17fdbf00 100644
--- a/headless/public/util/deterministic_dispatcher_test.cc
+++ b/headless/public/util/deterministic_dispatcher_test.cc
@@ -8,7 +8,6 @@
 #include <string>
 #include <vector>
 
-#include "base/memory/ptr_util.h"
 #include "base/message_loop/message_loop.h"
 #include "base/run_loop.h"
 #include "base/single_thread_task_runner.h"
@@ -154,7 +153,7 @@
                                            &notifications));
   base::Closure navigation_done_closure;
   deterministic_dispatcher_->NavigationRequested(
-      base::MakeUnique<NavigationRequestForTest>(&navigation_done_closure));
+      std::make_unique<NavigationRequestForTest>(&navigation_done_closure));
   std::unique_ptr<FakeManagedDispatchURLRequestJob> job2(
       new FakeManagedDispatchURLRequestJob(deterministic_dispatcher_.get(), 2,
                                            &notifications));
diff --git a/headless/public/util/deterministic_http_protocol_handler.cc b/headless/public/util/deterministic_http_protocol_handler.cc
index 84cc848..0ed79e9 100644
--- a/headless/public/util/deterministic_http_protocol_handler.cc
+++ b/headless/public/util/deterministic_http_protocol_handler.cc
@@ -4,8 +4,9 @@
 
 #include "headless/public/util/deterministic_http_protocol_handler.h"
 
+#include <memory>
+
 #include "base/macros.h"
-#include "base/memory/ptr_util.h"
 #include "headless/public/headless_browser_context.h"
 #include "headless/public/util/deterministic_dispatcher.h"
 #include "headless/public/util/generic_url_request_job.h"
@@ -65,7 +66,7 @@
   }
   return new GenericURLRequestJob(
       request, network_delegate, deterministic_dispatcher_,
-      base::MakeUnique<HttpURLFetcher>(url_request_context_.get()),
+      std::make_unique<HttpURLFetcher>(url_request_context_.get()),
       nop_delegate_.get(), headless_browser_context_);
 }
 
diff --git a/headless/public/util/expedited_dispatcher_test.cc b/headless/public/util/expedited_dispatcher_test.cc
index 05571f6..96c3ccf4 100644
--- a/headless/public/util/expedited_dispatcher_test.cc
+++ b/headless/public/util/expedited_dispatcher_test.cc
@@ -8,7 +8,6 @@
 #include <string>
 #include <vector>
 
-#include "base/memory/ptr_util.h"
 #include "base/message_loop/message_loop.h"
 #include "base/run_loop.h"
 #include "base/single_thread_task_runner.h"
@@ -111,7 +110,7 @@
                                            &notifications));
   base::Closure navigation_done_closure;
   expedited_dispatcher_->NavigationRequested(
-      base::MakeUnique<NavigationRequestForTest>(&navigation_done_closure));
+      std::make_unique<NavigationRequestForTest>(&navigation_done_closure));
   std::unique_ptr<FakeManagedDispatchURLRequestJob> job2(
       new FakeManagedDispatchURLRequestJob(expedited_dispatcher_.get(), 2,
                                            &notifications));
diff --git a/headless/public/util/generic_url_request_job_test.cc b/headless/public/util/generic_url_request_job_test.cc
index 777837d4..f59c63b 100644
--- a/headless/public/util/generic_url_request_job_test.cc
+++ b/headless/public/util/generic_url_request_job_test.cc
@@ -10,7 +10,6 @@
 
 #include "base/json/json_reader.h"
 #include "base/json/json_writer.h"
-#include "base/memory/ptr_util.h"
 #include "base/message_loop/message_loop.h"
 #include "base/run_loop.h"
 #include "base/single_thread_task_runner.h"
@@ -157,7 +156,7 @@
       net::NetworkDelegate* network_delegate) const override {
     return new GenericURLRequestJob(
         request, network_delegate, dispatcher_,
-        base::MakeUnique<MockFetcher>(fetch_request_, received_post_data_,
+        std::make_unique<MockFetcher>(fetch_request_, received_post_data_,
                                       json_fetch_reply_map_,
                                       on_request_callback_),
         job_delegate_, nullptr);
@@ -210,7 +209,7 @@
         TRAFFIC_ANNOTATION_FOR_TESTS));
     request->set_method("POST");
     request->set_upload(net::ElementsUploadDataStream::CreateWithReader(
-        base::MakeUnique<net::UploadBytesElementReader>(post_data.data(),
+        std::make_unique<net::UploadBytesElementReader>(post_data.data(),
                                                         post_data.size()),
         0));
     request->Start();
@@ -292,7 +291,7 @@
 
   std::string post_data = "lorem ipsom";
   request->set_upload(net::ElementsUploadDataStream::CreateWithReader(
-      base::MakeUnique<net::UploadBytesElementReader>(post_data.data(),
+      std::make_unique<net::UploadBytesElementReader>(post_data.data(),
                                                       post_data.size()),
       0));
   request->Start();
@@ -338,7 +337,7 @@
     post_data[i] = i & 127;
 
   request->set_upload(net::ElementsUploadDataStream::CreateWithReader(
-      base::MakeUnique<net::UploadBytesElementReader>(&post_data[0],
+      std::make_unique<net::UploadBytesElementReader>(&post_data[0],
                                                       post_data.size()),
       0));
   request->Start();
@@ -662,7 +661,7 @@
   json_fetch_reply_map_[url.spec()] = json_reply;
 
   request->set_upload(net::ElementsUploadDataStream::CreateWithReader(
-      base::MakeUnique<ByteAtATimeUploadElementReader>("payload"), 0));
+      std::make_unique<ByteAtATimeUploadElementReader>("payload"), 0));
   request->Start();
   base::RunLoop().RunUntilIdle();
 
@@ -695,7 +694,7 @@
     post_data.at(i) = i & 127;
 
   request->set_upload(net::ElementsUploadDataStream::CreateWithReader(
-      base::MakeUnique<ByteAtATimeUploadElementReader>(post_data), 0));
+      std::make_unique<ByteAtATimeUploadElementReader>(post_data), 0));
   request->Start();
   base::RunLoop().RunUntilIdle();
 
@@ -728,13 +727,13 @@
 
   std::vector<std::unique_ptr<net::UploadElementReader>> element_readers;
   element_readers.push_back(
-      base::MakeUnique<ByteAtATimeUploadElementReader>("Does "));
+      std::make_unique<ByteAtATimeUploadElementReader>("Does "));
   element_readers.push_back(
-      base::MakeUnique<ByteAtATimeUploadElementReader>("this "));
+      std::make_unique<ByteAtATimeUploadElementReader>("this "));
   element_readers.push_back(
-      base::MakeUnique<ByteAtATimeUploadElementReader>("work?"));
+      std::make_unique<ByteAtATimeUploadElementReader>("work?"));
 
-  request->set_upload(base::MakeUnique<net::ElementsUploadDataStream>(
+  request->set_upload(std::make_unique<net::ElementsUploadDataStream>(
       std::move(element_readers), 0));
   request->Start();
   base::RunLoop().RunUntilIdle();
diff --git a/headless/public/util/http_url_fetcher.cc b/headless/public/util/http_url_fetcher.cc
index 0e83ebb..7354aa7 100644
--- a/headless/public/util/http_url_fetcher.cc
+++ b/headless/public/util/http_url_fetcher.cc
@@ -4,6 +4,8 @@
 
 #include "headless/public/util/http_url_fetcher.h"
 
+#include <memory>
+
 #include "headless/public/util/generic_url_request_job.h"
 #include "net/base/elements_upload_data_stream.h"
 #include "net/base/io_buffer.h"
@@ -107,7 +109,7 @@
 
   if (!post_data.empty()) {
     request_->set_upload(net::ElementsUploadDataStream::CreateWithReader(
-        base::MakeUnique<net::UploadBytesElementReader>(post_data.data(),
+        std::make_unique<net::UploadBytesElementReader>(post_data.data(),
                                                         post_data.size()),
         0));
   }
diff --git a/headless/public/util/testing/test_in_memory_protocol_handler.cc b/headless/public/util/testing/test_in_memory_protocol_handler.cc
index 476dae15..00f7b10 100644
--- a/headless/public/util/testing/test_in_memory_protocol_handler.cc
+++ b/headless/public/util/testing/test_in_memory_protocol_handler.cc
@@ -4,7 +4,8 @@
 
 #include "headless/public/util/testing/test_in_memory_protocol_handler.h"
 
-#include "base/memory/ptr_util.h"
+#include <memory>
+
 #include "headless/public/util/expedited_dispatcher.h"
 #include "headless/public/util/generic_url_request_job.h"
 #include "headless/public/util/url_fetcher.h"
@@ -121,7 +122,7 @@
     net::NetworkDelegate* network_delegate) const {
   return new GenericURLRequestJob(
       request, network_delegate, dispatcher_.get(),
-      base::MakeUnique<MockURLFetcher>(
+      std::make_unique<MockURLFetcher>(
           const_cast<TestInMemoryProtocolHandler*>(this)),
       test_delegate_.get(), headless_browser_context_);
 }
diff --git a/headless/public/util/virtual_time_controller_test.cc b/headless/public/util/virtual_time_controller_test.cc
index 483a99b..33fcccc4 100644
--- a/headless/public/util/virtual_time_controller_test.cc
+++ b/headless/public/util/virtual_time_controller_test.cc
@@ -4,8 +4,9 @@
 
 #include "headless/public/util/virtual_time_controller.h"
 
+#include <memory>
+
 #include "base/bind.h"
-#include "base/memory/ptr_util.h"
 #include "base/memory/ref_counted.h"
 #include "base/strings/stringprintf.h"
 #include "base/test/test_simple_task_runner.h"
@@ -31,7 +32,7 @@
     EXPECT_CALL(*mock_host_, IsAttached()).WillOnce(Return(false));
     EXPECT_CALL(*mock_host_, AttachClient(&client_));
     client_.AttachToHost(mock_host_.get());
-    controller_ = base::MakeUnique<VirtualTimeController>(&client_, 0);
+    controller_ = std::make_unique<VirtualTimeController>(&client_, 0);
   }
 
   ~VirtualTimeControllerTest() override = default;
@@ -78,7 +79,7 @@
 };
 
 TEST_F(VirtualTimeControllerTest, AdvancesTimeWithoutTasks) {
-  controller_ = base::MakeUnique<VirtualTimeController>(&client_, 1000);
+  controller_ = std::make_unique<VirtualTimeController>(&client_, 1000);
 
   EXPECT_CALL(*mock_host_,
               DispatchProtocolMessage(
diff --git a/headless/test/headless_browser_test.cc b/headless/test/headless_browser_test.cc
index 8695223..9c7cc1a 100644
--- a/headless/test/headless_browser_test.cc
+++ b/headless/test/headless_browser_test.cc
@@ -4,10 +4,11 @@
 
 #include "headless/test/headless_browser_test.h"
 
+#include <memory>
+
 #include "base/command_line.h"
 #include "base/files/file_path.h"
 #include "base/macros.h"
-#include "base/memory/ptr_util.h"
 #include "base/message_loop/message_loop.h"
 #include "base/path_service.h"
 #include "base/run_loop.h"
@@ -197,7 +198,7 @@
   base::MessageLoop::ScopedNestableTaskAllower nestable_allower(
       base::MessageLoop::current());
   EXPECT_FALSE(run_loop_);
-  run_loop_ = base::MakeUnique<base::RunLoop>();
+  run_loop_ = std::make_unique<base::RunLoop>();
   PreRunAsynchronousTest();
   run_loop_->Run();
   PostRunAsynchronousTest();
diff --git a/ios/chrome/browser/feature_engagement/feature_engagement_egtest.mm b/ios/chrome/browser/feature_engagement/feature_engagement_egtest.mm
index f0e0bbc..e8e344a 100644
--- a/ios/chrome/browser/feature_engagement/feature_engagement_egtest.mm
+++ b/ios/chrome/browser/feature_engagement/feature_engagement_egtest.mm
@@ -29,6 +29,9 @@
 // Help feature to be shown.
 const int kMinChromeOpensRequired = 5;
 
+// The timeout for the load of the feature engagement tracker.
+const NSTimeInterval kWaitForTrackerLoadTimeout = 5.0;
+
 // Matcher for the Reading List Text Badge.
 id<GREYMatcher> ReadingListTextBadge() {
   return grey_accessibilityID(@"kReadingListTextBadgeAccessibilityIdentifier");
@@ -51,12 +54,12 @@
 
   feature_engagement::Tracker* tracker =
       feature_engagement::TrackerFactory::GetForBrowserState(browserState);
-  GREYAssert(testing::WaitUntilConditionOrTimeout(
-                 testing::kWaitForFileOperationTimeout,
-                 ^{
-                   return tracker->IsInitialized();
-                 }),
-             @"Engagement Tracker did not load before timeout.");
+  GREYAssert(
+      testing::WaitUntilConditionOrTimeout(kWaitForTrackerLoadTimeout,
+                                           ^{
+                                             return tracker->IsInitialized();
+                                           }),
+      @"Engagement Tracker did not load before timeout.");
 }
 
 // Enables the Badged Reading List help to be triggered for |feature_list|.
@@ -89,9 +92,7 @@
 
 // Verifies that the Badged Reading List feature shows when triggering
 // conditions are met.
-// TODO(crbug.com/789943): This test is flaky on devices. Reenable it once it is
-// fixed.
-- (void)FLAKY_testBadgedReadingListFeatureShouldShow {
+- (void)testBadgedReadingListFeatureShouldShow {
   base::test::ScopedFeatureList scoped_feature_list;
 
   EnableBadgedReadingListTriggering(scoped_feature_list);
diff --git a/ios/chrome/browser/metrics/ios_chrome_metrics_services_manager_client.mm b/ios/chrome/browser/metrics/ios_chrome_metrics_services_manager_client.mm
index a16552a..e0f12102 100644
--- a/ios/chrome/browser/metrics/ios_chrome_metrics_services_manager_client.mm
+++ b/ios/chrome/browser/metrics/ios_chrome_metrics_services_manager_client.mm
@@ -41,7 +41,7 @@
   IOSChromeEnabledStateProvider() {}
   ~IOSChromeEnabledStateProvider() override {}
 
-  bool IsConsentGiven() override {
+  bool IsConsentGiven() const override {
     return IOSChromeMetricsServiceAccessor::IsMetricsAndCrashReportingEnabled();
   }
 
diff --git a/ios/chrome/browser/payments/ios_payment_instrument_launcher.mm b/ios/chrome/browser/payments/ios_payment_instrument_launcher.mm
index 4ac1254..d949cdb 100644
--- a/ios/chrome/browser/payments/ios_payment_instrument_launcher.mm
+++ b/ios/chrome/browser/payments/ios_payment_instrument_launcher.mm
@@ -224,11 +224,13 @@
   scoped_refptr<net::X509Certificate> cert = item->GetSSL().certificate;
   std::vector<base::StringPiece> cert_chain;
 
-  cert_chain.reserve(1 + cert->GetIntermediateCertificates().size());
+  cert_chain.reserve(1 + cert->intermediate_buffers().size());
   cert_chain.push_back(
-      net::x509_util::CryptoBufferAsStringPiece(cert->os_cert_handle()));
-  for (auto* handle : cert->GetIntermediateCertificates())
-    cert_chain.push_back(net::x509_util::CryptoBufferAsStringPiece(handle));
+      net::x509_util::CryptoBufferAsStringPiece(cert->cert_buffer()));
+  for (const auto& handle : cert->intermediate_buffers()) {
+    cert_chain.push_back(
+        net::x509_util::CryptoBufferAsStringPiece(handle.get()));
+  }
 
   std::unique_ptr<base::ListValue> byte_array;
   for (const auto& cert_string : cert_chain) {
diff --git a/ios/chrome/browser/payments/payment_request_unittest.mm b/ios/chrome/browser/payments/payment_request_unittest.mm
index 4701cb7..8c7a040 100644
--- a/ios/chrome/browser/payments/payment_request_unittest.mm
+++ b/ios/chrome/browser/payments/payment_request_unittest.mm
@@ -330,7 +330,7 @@
   autofill::TestPersonalDataManager personal_data_manager;
 
   autofill::CreditCard credit_card_1 = autofill::test::GetCreditCard();
-  personal_data_manager.AddTestingCreditCard(&credit_card_1);
+  personal_data_manager.AddCreditCard(credit_card_1);
 
   TestPaymentRequest payment_request(web_payment_request,
                                      chrome_browser_state_.get(), &web_state_,
@@ -355,7 +355,7 @@
   autofill::TestPersonalDataManager personal_data_manager;
 
   autofill::AutofillProfile profile_1 = autofill::test::GetFullProfile();
-  personal_data_manager.AddTestingProfile(&profile_1);
+  personal_data_manager.AddProfile(profile_1);
 
   TestPaymentRequest payment_request(web_payment_request,
                                      chrome_browser_state_.get(), &web_state_,
@@ -478,10 +478,10 @@
   autofill::TestPersonalDataManager personal_data_manager;
   autofill::AutofillProfile address = autofill::test::GetFullProfile();
   address.set_use_count(5U);
-  personal_data_manager.AddTestingProfile(&address);
+  personal_data_manager.AddProfile(address);
   autofill::AutofillProfile address2 = autofill::test::GetFullProfile2();
   address2.set_use_count(15U);
-  personal_data_manager.AddTestingProfile(&address2);
+  personal_data_manager.AddProfile(address2);
 
   WebPaymentRequest web_payment_request;
   web_payment_request.details = CreateDetailsWithShippingOption();
@@ -505,7 +505,7 @@
   autofill::TestPersonalDataManager personal_data_manager;
   autofill::AutofillProfile address = autofill::test::GetFullProfile();
   address.set_use_count(5U);
-  personal_data_manager.AddTestingProfile(&address);
+  personal_data_manager.AddProfile(address);
 
   WebPaymentRequest web_payment_request;
   // No shipping options.
@@ -531,11 +531,11 @@
   address1.SetInfo(autofill::AutofillType(autofill::PHONE_HOME_WHOLE_NUMBER),
                    base::string16(), "en-US");
   address1.set_use_count(5U);
-  personal_data_manager.AddTestingProfile(&address1);
+  personal_data_manager.AddProfile(address1);
   // Add a complete profile, with fewer use counts.
   autofill::AutofillProfile address2 = autofill::test::GetFullProfile2();
   address2.set_use_count(3U);
-  personal_data_manager.AddTestingProfile(&address2);
+  personal_data_manager.AddProfile(address2);
 
   WebPaymentRequest web_payment_request;
   web_payment_request.details = CreateDetailsWithShippingOption();
@@ -565,11 +565,11 @@
   address1.SetInfo(autofill::AutofillType(autofill::PHONE_HOME_WHOLE_NUMBER),
                    base::string16(), "en-US");
   address1.set_use_count(5U);
-  personal_data_manager.AddTestingProfile(&address1);
+  personal_data_manager.AddProfile(address1);
   // Add a complete profile, with fewer use counts.
   autofill::AutofillProfile address2 = autofill::test::GetFullProfile();
   address2.set_use_count(3U);
-  personal_data_manager.AddTestingProfile(&address2);
+  personal_data_manager.AddProfile(address2);
 
   WebPaymentRequest web_payment_request;
   web_payment_request.details = CreateDetailsWithShippingOption();
@@ -608,11 +608,11 @@
 TEST_F(PaymentRequestTest, SelectedPaymentMethod_ExpiredCard) {
   autofill::TestPersonalDataManager personal_data_manager;
   autofill::AutofillProfile billing_address = autofill::test::GetFullProfile();
-  personal_data_manager.AddTestingProfile(&billing_address);
+  personal_data_manager.AddProfile(billing_address);
   autofill::CreditCard credit_card = autofill::test::GetCreditCard();
-  personal_data_manager.AddTestingCreditCard(&credit_card);
   credit_card.SetExpirationYear(2016);  // Expired.
   credit_card.set_billing_address_id(billing_address.guid());
+  personal_data_manager.AddCreditCard(credit_card);
 
   WebPaymentRequest web_payment_request =
       payment_request_test_util::CreateTestWebPaymentRequest();
@@ -633,15 +633,15 @@
 TEST_F(PaymentRequestTest, SelectedPaymentMethod_Complete) {
   autofill::TestPersonalDataManager personal_data_manager;
   autofill::AutofillProfile billing_address = autofill::test::GetFullProfile();
-  personal_data_manager.AddTestingProfile(&billing_address);
+  personal_data_manager.AddProfile(billing_address);
   autofill::CreditCard credit_card = autofill::test::GetCreditCard();
   credit_card.set_use_count(5U);
-  personal_data_manager.AddTestingCreditCard(&credit_card);
   credit_card.set_billing_address_id(billing_address.guid());
+  personal_data_manager.AddCreditCard(credit_card);
   autofill::CreditCard credit_card2 = autofill::test::GetCreditCard2();
   credit_card2.set_use_count(15U);
-  personal_data_manager.AddTestingCreditCard(&credit_card2);
   credit_card2.set_billing_address_id(billing_address.guid());
+  personal_data_manager.AddCreditCard(credit_card2);
 
   WebPaymentRequest web_payment_request =
       payment_request_test_util::CreateTestWebPaymentRequest();
@@ -661,14 +661,14 @@
 TEST_F(PaymentRequestTest, SelectedPaymentMethod_Incomplete) {
   autofill::TestPersonalDataManager personal_data_manager;
   autofill::AutofillProfile billing_address = autofill::test::GetFullProfile();
-  personal_data_manager.AddTestingProfile(&billing_address);
+  personal_data_manager.AddProfile(billing_address);
   autofill::CreditCard credit_card = autofill::test::GetCreditCard();
   credit_card.set_use_count(5U);
-  personal_data_manager.AddTestingCreditCard(&credit_card);
   credit_card.set_billing_address_id(billing_address.guid());
+  personal_data_manager.AddCreditCard(credit_card);
   autofill::CreditCard credit_card2 = autofill::test::GetCreditCard2();
   credit_card2.set_use_count(15U);
-  personal_data_manager.AddTestingCreditCard(&credit_card2);
+  personal_data_manager.AddCreditCard(credit_card2);
 
   WebPaymentRequest web_payment_request =
       payment_request_test_util::CreateTestWebPaymentRequest();
@@ -695,13 +695,13 @@
   address.SetInfo(autofill::AutofillType(autofill::EMAIL_ADDRESS),
                   base::string16(), "en-US");
   address.set_use_count(10U);
-  personal_data_manager.AddTestingProfile(&address);
+  personal_data_manager.AddProfile(address);
   autofill::AutofillProfile contact_info = autofill::test::GetFullProfile2();
   contact_info.set_use_count(5U);
-  personal_data_manager.AddTestingProfile(&contact_info);
+  personal_data_manager.AddProfile(contact_info);
   autofill::CreditCard credit_card = autofill::test::GetCreditCard();
-  personal_data_manager.AddTestingCreditCard(&credit_card);
   credit_card.set_billing_address_id(address.guid());
+  personal_data_manager.AddCreditCard(credit_card);
 
   WebPaymentRequest web_payment_request =
       payment_request_test_util::CreateTestWebPaymentRequest();
@@ -735,10 +735,10 @@
 TEST_F(PaymentRequestTest, RecordUseStats_SameShippingAndContactInfoProfile) {
   MockTestPersonalDataManager personal_data_manager;
   autofill::AutofillProfile address = autofill::test::GetFullProfile();
-  personal_data_manager.AddTestingProfile(&address);
+  personal_data_manager.AddProfile(address);
   autofill::CreditCard credit_card = autofill::test::GetCreditCard();
-  personal_data_manager.AddTestingCreditCard(&credit_card);
   credit_card.set_billing_address_id(address.guid());
+  personal_data_manager.AddCreditCard(credit_card);
 
   WebPaymentRequest web_payment_request =
       payment_request_test_util::CreateTestWebPaymentRequest();
@@ -770,10 +770,10 @@
 TEST_F(PaymentRequestTest, RecordUseStats_RequestShippingOnly) {
   MockTestPersonalDataManager personal_data_manager;
   autofill::AutofillProfile address = autofill::test::GetFullProfile();
-  personal_data_manager.AddTestingProfile(&address);
+  personal_data_manager.AddProfile(address);
   autofill::CreditCard credit_card = autofill::test::GetCreditCard();
-  personal_data_manager.AddTestingCreditCard(&credit_card);
   credit_card.set_billing_address_id(address.guid());
+  personal_data_manager.AddCreditCard(credit_card);
 
   WebPaymentRequest web_payment_request =
       payment_request_test_util::CreateTestWebPaymentRequest();
@@ -806,10 +806,10 @@
 TEST_F(PaymentRequestTest, RecordUseStats_RequestContactInfoOnly) {
   MockTestPersonalDataManager personal_data_manager;
   autofill::AutofillProfile address = autofill::test::GetFullProfile();
-  personal_data_manager.AddTestingProfile(&address);
+  personal_data_manager.AddProfile(address);
   autofill::CreditCard credit_card = autofill::test::GetCreditCard();
-  personal_data_manager.AddTestingCreditCard(&credit_card);
   credit_card.set_billing_address_id(address.guid());
+  personal_data_manager.AddCreditCard(credit_card);
 
   WebPaymentRequest web_payment_request =
       payment_request_test_util::CreateTestWebPaymentRequest();
@@ -839,10 +839,10 @@
 TEST_F(PaymentRequestTest, RecordUseStats_NoShippingOrContactInfoRequested) {
   MockTestPersonalDataManager personal_data_manager;
   autofill::AutofillProfile address = autofill::test::GetFullProfile();
-  personal_data_manager.AddTestingProfile(&address);
+  personal_data_manager.AddProfile(address);
   autofill::CreditCard credit_card = autofill::test::GetCreditCard();
-  personal_data_manager.AddTestingCreditCard(&credit_card);
   credit_card.set_billing_address_id(address.guid());
+  personal_data_manager.AddCreditCard(credit_card);
 
   WebPaymentRequest web_payment_request =
       payment_request_test_util::CreateTestWebPaymentRequest();
@@ -875,9 +875,9 @@
 TEST_F(PaymentRequestTest, PaymentDetailsModifier_BasicCard_NetworkMismatch) {
   autofill::TestPersonalDataManager personal_data_manager;
   autofill::AutofillProfile address = autofill::test::GetFullProfile();
-  personal_data_manager.AddTestingProfile(&address);
+  personal_data_manager.AddProfile(address);
   autofill::CreditCard credit_card = autofill::test::GetCreditCard();  // Visa.
-  personal_data_manager.AddTestingCreditCard(&credit_card);
+  personal_data_manager.AddCreditCard(credit_card);
   credit_card.set_billing_address_id(address.guid());
 
   WebPaymentRequest web_payment_request =
@@ -913,10 +913,10 @@
 TEST_F(PaymentRequestTest, PaymentDetailsModifier_BasicCard_NetworkMatch) {
   autofill::TestPersonalDataManager personal_data_manager;
   autofill::AutofillProfile address = autofill::test::GetFullProfile();
-  personal_data_manager.AddTestingProfile(&address);
+  personal_data_manager.AddProfile(address);
   autofill::CreditCard credit_card = autofill::test::GetCreditCard2();  // Amex.
-  personal_data_manager.AddTestingCreditCard(&credit_card);
   credit_card.set_billing_address_id(address.guid());
+  personal_data_manager.AddCreditCard(credit_card);
 
   WebPaymentRequest web_payment_request =
       payment_request_test_util::CreateTestWebPaymentRequest();
@@ -963,9 +963,9 @@
 TEST_F(PaymentRequestTest, PaymentDetailsModifier_BasicCard_TypeMismatch) {
   autofill::TestPersonalDataManager personal_data_manager;
   autofill::AutofillProfile address = autofill::test::GetFullProfile();
-  personal_data_manager.AddTestingProfile(&address);
+  personal_data_manager.AddProfile(address);
   autofill::CreditCard credit_card = autofill::test::GetCreditCard2();  // Amex.
-  personal_data_manager.AddTestingCreditCard(&credit_card);
+  personal_data_manager.AddCreditCard(credit_card);
   credit_card.set_billing_address_id(address.guid());
 
   WebPaymentRequest web_payment_request =
@@ -1005,11 +1005,11 @@
        PaymentDetailsModifier_BasicCard_NetworkAndTypeMatch) {
   autofill::TestPersonalDataManager personal_data_manager;
   autofill::AutofillProfile address = autofill::test::GetFullProfile();
-  personal_data_manager.AddTestingProfile(&address);
+  personal_data_manager.AddProfile(address);
   autofill::CreditCard credit_card = autofill::test::GetMaskedServerCardAmex();
   credit_card.set_card_type(autofill::CreditCard::CardType::CARD_TYPE_CREDIT);
-  personal_data_manager.AddTestingCreditCard(&credit_card);
   credit_card.set_billing_address_id(address.guid());
+  personal_data_manager.AddCreditCard(credit_card);
 
   WebPaymentRequest web_payment_request =
       payment_request_test_util::CreateTestWebPaymentRequest();
@@ -1110,10 +1110,10 @@
                   "en-US");
   profile.SetInfo(autofill::AutofillType(autofill::PHONE_HOME_WHOLE_NUMBER),
                   base::string16(), "en-US");
+  personal_data_manager.AddProfile(profile);
   autofill::CreditCard card = autofill::test::GetCreditCard();  // Visa.
   card.set_billing_address_id(profile.guid());
-  personal_data_manager.AddTestingProfile(&profile);
-  personal_data_manager.AddTestingCreditCard(&card);
+  personal_data_manager.AddCreditCard(card);
 
   // Has a selected payment method.
   payments::TestPaymentRequest payment_request2(
@@ -1128,8 +1128,9 @@
       &personal_data_manager);
   EXPECT_FALSE(payment_request3.IsAbleToPay());
 
-  profile.SetInfo(autofill::AutofillType(autofill::PHONE_HOME_WHOLE_NUMBER),
-                  base::ASCIIToUTF16("16502111111"), "en-US");
+  personal_data_manager.GetProfiles()[0]->SetInfo(
+      autofill::AutofillType(autofill::PHONE_HOME_WHOLE_NUMBER),
+      base::ASCIIToUTF16("16502111111"), "en-US");
 
   // Has a selected contact info.
   payments::TestPaymentRequest payment_request4(
diff --git a/ios/chrome/browser/payments/payment_request_unittest_base.h b/ios/chrome/browser/payments/payment_request_unittest_base.h
index 8e6b932e..e6ada3f 100644
--- a/ios/chrome/browser/payments/payment_request_unittest_base.h
+++ b/ios/chrome/browser/payments/payment_request_unittest_base.h
@@ -42,8 +42,8 @@
   // and/or AddCreditCard.
   void CreateTestPaymentRequest();
 
-  void AddAutofillProfile(autofill::AutofillProfile profile);
-  void AddCreditCard(autofill::CreditCard card);
+  void AddAutofillProfile(const autofill::AutofillProfile& profile);
+  void AddCreditCard(const autofill::CreditCard& card);
 
   SigninManager* GetSigninManager();
 
@@ -58,19 +58,14 @@
   TestChromeBrowserState* browser_state() {
     return chrome_browser_state_.get();
   }
-  const std::vector<std::unique_ptr<autofill::AutofillProfile>>& profiles()
-      const {
-    return profiles_;
+  std::vector<autofill::AutofillProfile*> profiles() const {
+    return personal_data_manager_.GetProfiles();
   }
-  const std::vector<std::unique_ptr<autofill::CreditCard>>& credit_cards()
-      const {
-    return cards_;
+  std::vector<autofill::CreditCard*> credit_cards() const {
+    return personal_data_manager_.GetCreditCards();
   }
 
  private:
-  std::vector<std::unique_ptr<autofill::AutofillProfile>> profiles_;
-  std::vector<std::unique_ptr<autofill::CreditCard>> cards_;
-
   web::TestWebThreadBundle web_thread_bundle_;
   web::TestWebState web_state_;
   std::unique_ptr<PrefService> pref_service_;
diff --git a/ios/chrome/browser/payments/payment_request_unittest_base.mm b/ios/chrome/browser/payments/payment_request_unittest_base.mm
index 751fd999..eb42c9f 100644
--- a/ios/chrome/browser/payments/payment_request_unittest_base.mm
+++ b/ios/chrome/browser/payments/payment_request_unittest_base.mm
@@ -27,11 +27,11 @@
                                      &ios::BuildFakeSigninManager);
   chrome_browser_state_ = test_cbs_builder.Build();
   web_state_.SetBrowserState(chrome_browser_state_.get());
-  personal_data_manager_.SetTestingPrefService(pref_service_.get());
+  personal_data_manager_.SetPrefService(pref_service_.get());
 }
 
 void PaymentRequestUnitTestBase::TearDown() {
-  personal_data_manager_.SetTestingPrefService(nullptr);
+  personal_data_manager_.SetPrefService(nullptr);
 }
 
 void PaymentRequestUnitTestBase::CreateTestPaymentRequest() {
@@ -42,15 +42,13 @@
 }
 
 void PaymentRequestUnitTestBase::AddAutofillProfile(
-    autofill::AutofillProfile profile) {
-  profiles_.push_back(
-      base::MakeUnique<autofill::AutofillProfile>(std::move(profile)));
-  personal_data_manager_.AddTestingProfile(profiles_.back().get());
+    const autofill::AutofillProfile& profile) {
+  personal_data_manager_.AddProfile(profile);
 }
 
-void PaymentRequestUnitTestBase::AddCreditCard(autofill::CreditCard card) {
-  cards_.push_back(base::MakeUnique<autofill::CreditCard>(std::move(card)));
-  personal_data_manager_.AddTestingCreditCard(cards_.back().get());
+void PaymentRequestUnitTestBase::AddCreditCard(
+    const autofill::CreditCard& card) {
+  personal_data_manager_.AddCreditCard(card);
 }
 
 SigninManager* PaymentRequestUnitTestBase::GetSigninManager() {
diff --git a/ios/chrome/browser/payments/payment_response_helper_unittest.mm b/ios/chrome/browser/payments/payment_response_helper_unittest.mm
index 483222e..2f543776 100644
--- a/ios/chrome/browser/payments/payment_response_helper_unittest.mm
+++ b/ios/chrome/browser/payments/payment_response_helper_unittest.mm
@@ -66,7 +66,7 @@
       : profile_(autofill::test::GetFullProfile()),
         credit_card_(autofill::test::GetCreditCard()),
         chrome_browser_state_(TestChromeBrowserState::Builder().Build()) {
-    personal_data_manager_.AddTestingProfile(&profile_);
+    personal_data_manager_.AddProfile(profile_);
     payment_request_ = base::MakeUnique<TestPaymentRequest>(
         payment_request_test_util::CreateTestWebPaymentRequest(),
         chrome_browser_state_.get(), &web_state_, &personal_data_manager_);
diff --git a/ios/chrome/browser/ui/bubble/bubble_view.mm b/ios/chrome/browser/ui/bubble/bubble_view.mm
index b2b8b3c2..2a78d49 100644
--- a/ios/chrome/browser/ui/bubble/bubble_view.mm
+++ b/ios/chrome/browser/ui/bubble/bubble_view.mm
@@ -33,7 +33,7 @@
 
 // Margin between the bubble view's bounds and its content. This margin is on
 // all sides of the bubble.
-const CGFloat kBubbleMargin = 8.0f;
+const CGFloat kBubbleMargin = 4.0f;
 // Padding between the top and bottom the bubble's background and the top and
 // bottom of the label.
 const CGFloat kLabelVerticalPadding = 8.0f;
diff --git a/ios/chrome/browser/ui/bubble/bubble_view_unittest.mm b/ios/chrome/browser/ui/bubble/bubble_view_unittest.mm
index 6842465..ae88d60 100644
--- a/ios/chrome/browser/ui/bubble/bubble_view_unittest.mm
+++ b/ios/chrome/browser/ui/bubble/bubble_view_unittest.mm
@@ -46,8 +46,8 @@
   CGSize bubbleSize = [bubble sizeThatFits:maxSize_];
   // Since the label is shorter than the minimum line width, expect the bubble
   // to be the minimum width and accommodate one line of text.
-  EXPECT_NEAR(56.0f, bubbleSize.width, 1.0f);
-  EXPECT_NEAR(61.5f, bubbleSize.height, 1.0f);
+  EXPECT_NEAR(50.0f, bubbleSize.width, 1.0f);
+  EXPECT_NEAR(53.5f, bubbleSize.height, 1.0f);
 }
 
 // Test |sizeThatFits| given text that should wrap onto multiple lines.
@@ -57,8 +57,8 @@
                                               alignment:alignment_];
   CGSize bubbleSize = [bubble sizeThatFits:maxSize_];
   // The bubble should fit the label, which contains two lines of text.
-  EXPECT_NEAR(349.0f, bubbleSize.width, 1.0f);
-  EXPECT_NEAR(80.5f, bubbleSize.height, 1.0f);
+  EXPECT_NEAR(341.0f, bubbleSize.width, 1.0f);
+  EXPECT_NEAR(72.5f, bubbleSize.height, 1.0f);
 }
 
 // Test that the accessibility label matches the display text.
diff --git a/ios/chrome/browser/ui/payments/address_edit_coordinator_unittest.mm b/ios/chrome/browser/ui/payments/address_edit_coordinator_unittest.mm
index 9dc21e7..af77409 100644
--- a/ios/chrome/browser/ui/payments/address_edit_coordinator_unittest.mm
+++ b/ios/chrome/browser/ui/payments/address_edit_coordinator_unittest.mm
@@ -114,7 +114,7 @@
     PaymentRequestUnitTestBase::SetUp();
 
     autofill::CountryNames::SetLocaleString("en-US");
-    personal_data_manager_.SetTestingPrefService(pref_service());
+    personal_data_manager_.SetPrefService(pref_service());
 
     payment_request_ = base::MakeUnique<MockTestPaymentRequest>(
         payment_request_test_util::CreateTestWebPaymentRequest(),
@@ -129,7 +129,7 @@
   }
 
   void TearDown() override {
-    personal_data_manager_.SetTestingPrefService(nullptr);
+    personal_data_manager_.SetPrefService(nullptr);
 
     PaymentRequestUnitTestBase::TearDown();
   }
diff --git a/ios/chrome/browser/ui/payments/contact_info_edit_coordinator_unittest.mm b/ios/chrome/browser/ui/payments/contact_info_edit_coordinator_unittest.mm
index 3ad9d67..f395bf2 100644
--- a/ios/chrome/browser/ui/payments/contact_info_edit_coordinator_unittest.mm
+++ b/ios/chrome/browser/ui/payments/contact_info_edit_coordinator_unittest.mm
@@ -103,7 +103,7 @@
   void SetUp() override {
     PaymentRequestUnitTestBase::SetUp();
 
-    personal_data_manager_.SetTestingPrefService(pref_service());
+    personal_data_manager_.SetPrefService(pref_service());
 
     payment_request_ = base::MakeUnique<MockTestPaymentRequest>(
         payment_request_test_util::CreateTestWebPaymentRequest(),
@@ -118,7 +118,7 @@
   }
 
   void TearDown() override {
-    personal_data_manager_.SetTestingPrefService(nullptr);
+    personal_data_manager_.SetPrefService(nullptr);
 
     PaymentRequestUnitTestBase::TearDown();
   }
diff --git a/ios/chrome/browser/ui/payments/payment_request_coordinator_unittest.mm b/ios/chrome/browser/ui/payments/payment_request_coordinator_unittest.mm
index adf596c..5cc25ac 100644
--- a/ios/chrome/browser/ui/payments/payment_request_coordinator_unittest.mm
+++ b/ios/chrome/browser/ui/payments/payment_request_coordinator_unittest.mm
@@ -170,7 +170,7 @@
 
   // Call the ShippingAddressSelectionCoordinator delegate method.
   [coordinator shippingAddressSelectionCoordinator:nil
-                          didSelectShippingAddress:profiles().back().get()];
+                          didSelectShippingAddress:profiles().back()];
 }
 
 // Tests that calling the ShippingOptionSelectionCoordinator delegate method
diff --git a/ios/chrome/browser/ui/tabs/tab_strip_controller.mm b/ios/chrome/browser/ui/tabs/tab_strip_controller.mm
index 0a4c88be..173d133 100644
--- a/ios/chrome/browser/ui/tabs/tab_strip_controller.mm
+++ b/ios/chrome/browser/ui/tabs/tab_strip_controller.mm
@@ -675,9 +675,10 @@
 
 - (CGPoint)anchorPointForTabSwitcherButton:(BubbleArrowDirection)direction {
   CGPoint anchorPoint =
-      bubble_util::AnchorPoint(_tabSwitcherButton.frame, direction);
-  return [_tabSwitcherButton.superview convertPoint:anchorPoint
-                                             toView:_tabSwitcherButton.window];
+      bubble_util::AnchorPoint(_tabSwitcherButton.imageView.frame, direction);
+  return [_tabSwitcherButton.imageView.superview
+      convertPoint:anchorPoint
+            toView:_tabSwitcherButton.imageView.window];
 }
 
 #pragma mark -
diff --git a/ios/chrome/browser/ui/toolbar/toolbar_controller.mm b/ios/chrome/browser/ui/toolbar/toolbar_controller.mm
index e1abae8..14d0f9b 100644
--- a/ios/chrome/browser/ui/toolbar/toolbar_controller.mm
+++ b/ios/chrome/browser/ui/toolbar/toolbar_controller.mm
@@ -794,9 +794,11 @@
 #pragma mark - BubbleViewAnchorPointProvider methods.
 
 - (CGPoint)anchorPointForTabSwitcherButton:(BubbleArrowDirection)direction {
-  CGPoint anchorPoint = bubble_util::AnchorPoint(stackButton_.frame, direction);
-  return [stackButton_.superview convertPoint:anchorPoint
-                                       toView:stackButton_.window];
+  CGPoint anchorPoint =
+      bubble_util::AnchorPoint(stackButton_.imageView.frame, direction);
+  return [stackButton_.imageView.superview
+      convertPoint:anchorPoint
+            toView:stackButton_.imageView.window];
 }
 
 - (CGPoint)anchorPointForToolsMenuButton:(BubbleArrowDirection)direction {
diff --git a/ios/chrome/browser/web/chrome_web_client.h b/ios/chrome/browser/web/chrome_web_client.h
index a298d361..0f7a8cf 100644
--- a/ios/chrome/browser/web/chrome_web_client.h
+++ b/ios/chrome/browser/web/chrome_web_client.h
@@ -37,7 +37,8 @@
       std::vector<std::string>* additional_schemes) override;
   void PostBrowserURLRewriterCreation(
       web::BrowserURLRewriter* rewriter) override;
-  NSString* GetEarlyPageScript(web::BrowserState* browser_state) const override;
+  NSString* GetEarlyPageScriptForMainFrame(
+      web::BrowserState* browser_state) const override;
   void AllowCertificateError(
       web::WebState* web_state,
       int cert_error,
diff --git a/ios/chrome/browser/web/chrome_web_client.mm b/ios/chrome/browser/web/chrome_web_client.mm
index 6fcdbea..3e63a8d 100644
--- a/ios/chrome/browser/web/chrome_web_client.mm
+++ b/ios/chrome/browser/web/chrome_web_client.mm
@@ -163,7 +163,7 @@
   rewriter->AddURLRewriter(&WillHandleWebBrowserAboutURL);
 }
 
-NSString* ChromeWebClient::GetEarlyPageScript(
+NSString* ChromeWebClient::GetEarlyPageScriptForMainFrame(
     web::BrowserState* browser_state) const {
   NSMutableArray* scripts = [NSMutableArray array];
   [scripts addObject:GetPageScript(@"chrome_bundle")];
diff --git a/ios/chrome/browser/web/chrome_web_client_unittest.mm b/ios/chrome/browser/web/chrome_web_client_unittest.mm
index 04d7a4b..187726ce 100644
--- a/ios/chrome/browser/web/chrome_web_client_unittest.mm
+++ b/ios/chrome/browser/web/chrome_web_client_unittest.mm
@@ -96,7 +96,8 @@
   web::ExecuteJavaScript(web_view, @"__gCrWeb = {};");
 
   web::ScopedTestingWebClient web_client(base::MakeUnique<ChromeWebClient>());
-  NSString* script = web_client.Get()->GetEarlyPageScript(browser_state());
+  NSString* script =
+      web_client.Get()->GetEarlyPageScriptForMainFrame(browser_state());
   web::ExecuteJavaScript(web_view, script);
   EXPECT_NSEQ(@"object",
               web::ExecuteJavaScript(web_view, @"typeof __gCrWeb.print"));
@@ -110,14 +111,15 @@
   web::ExecuteJavaScript(web_view, @"__gCrWeb = {};");
 
   web::ScopedTestingWebClient web_client(base::MakeUnique<ChromeWebClient>());
-  NSString* script = web_client.Get()->GetEarlyPageScript(browser_state());
+  NSString* script =
+      web_client.Get()->GetEarlyPageScriptForMainFrame(browser_state());
   web::ExecuteJavaScript(web_view, script);
   EXPECT_NSEQ(@"undefined", web::ExecuteJavaScript(
                                 web_view, @"typeof navigator.credentials"));
 
   base::test::ScopedFeatureList feature_list;
   feature_list.InitAndEnableFeature(features::kCredentialManager);
-  script = web_client.Get()->GetEarlyPageScript(browser_state());
+  script = web_client.Get()->GetEarlyPageScriptForMainFrame(browser_state());
   web::ExecuteJavaScript(web_view, script);
   EXPECT_NSEQ(@"object", web::ExecuteJavaScript(
                              web_view, @"typeof navigator.credentials"));
@@ -133,7 +135,8 @@
   web::ScopedTestingWebClient web_client(base::MakeUnique<ChromeWebClient>());
   base::test::ScopedFeatureList feature_list;
   feature_list.InitAndEnableFeature(payments::features::kWebPayments);
-  NSString* script = web_client.Get()->GetEarlyPageScript(browser_state());
+  NSString* script =
+      web_client.Get()->GetEarlyPageScriptForMainFrame(browser_state());
   web::ExecuteJavaScript(web_view, script);
   EXPECT_NSEQ(@"function", web::ExecuteJavaScript(
                                web_view, @"typeof window.PaymentRequest"));
@@ -149,7 +152,8 @@
   web::ScopedTestingWebClient web_client(base::MakeUnique<ChromeWebClient>());
   base::test::ScopedFeatureList feature_list;
   feature_list.InitAndDisableFeature(payments::features::kWebPayments);
-  NSString* script = web_client.Get()->GetEarlyPageScript(browser_state());
+  NSString* script =
+      web_client.Get()->GetEarlyPageScriptForMainFrame(browser_state());
   web::ExecuteJavaScript(web_view, script);
   EXPECT_NSEQ(@"undefined", web::ExecuteJavaScript(
                                 web_view, @"typeof window.PaymentRequest"));
diff --git a/ios/third_party/motion_transitioning_objc/BUILD.gn b/ios/third_party/motion_transitioning_objc/BUILD.gn
new file mode 100644
index 0000000..a20aba6
--- /dev/null
+++ b/ios/third_party/motion_transitioning_objc/BUILD.gn
@@ -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.
+
+config("config") {
+  include_dirs = [ "src/src" ]
+  visibility = [ ":motion_transitioning_objc" ]
+}
+
+source_set("motion_transitioning_objc") {
+  sources = [
+    "src/src/MDMTransition.h",
+    "src/src/MDMTransitionContext.h",
+    "src/src/MDMTransitionNavigationControllerDelegate.h",
+    "src/src/MDMTransitionNavigationControllerDelegate.m",
+    "src/src/MDMTransitionPresentationController.h",
+    "src/src/MDMTransitionPresentationController.m",
+    "src/src/MDMTransitionViewSnapshotter.h",
+    "src/src/MDMTransitionViewSnapshotter.m",
+    "src/src/MotionTransitioning.h",
+    "src/src/UIViewController+TransitionController.h",
+    "src/src/UIViewController+TransitionController.m",
+    "src/src/private/MDMViewControllerTransitionController.h",
+    "src/src/private/MDMViewControllerTransitionController.m",
+    "src/src/private/MDMViewControllerTransitionCoordinator.h",
+    "src/src/private/MDMViewControllerTransitionCoordinator.m",
+  ]
+  public = [
+    "src/src/MDMTransition.h",
+    "src/src/MDMTransitionContext.h",
+    "src/src/MDMTransitionNavigationControllerDelegate.h",
+    "src/src/MDMTransitionPresentationController.h",
+    "src/src/MDMTransitionViewSnapshotter.h",
+    "src/src/MotionTransitioning.h",
+    "src/src/UIViewController+TransitionController.h",
+  ]
+
+  libs = [
+    "CoreGraphics.framework",
+    "Foundation.framework",
+  ]
+  configs -= [ "//build/config/compiler:chromium_code" ]
+  configs += [
+    ":config",
+    "//build/config/compiler:enable_arc",
+    "//build/config/compiler:no_chromium_code",
+  ]
+  public_configs = [ ":config" ]
+}
diff --git a/ios/third_party/motion_transitioning_objc/LICENSE b/ios/third_party/motion_transitioning_objc/LICENSE
new file mode 100644
index 0000000..d645695
--- /dev/null
+++ b/ios/third_party/motion_transitioning_objc/LICENSE
@@ -0,0 +1,202 @@
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
diff --git a/ios/third_party/motion_transitioning_objc/OWNERS b/ios/third_party/motion_transitioning_objc/OWNERS
new file mode 100644
index 0000000..e9a3f8b3
--- /dev/null
+++ b/ios/third_party/motion_transitioning_objc/OWNERS
@@ -0,0 +1,9 @@
+sdefresne@chromium.org
+rohitrao@chromium.org
+
+# These are for the common case of adding or renaming files. If you're doing
+# structural changes, please get a review from an OWNER.
+per-file BUILD.gn=*
+
+# TEAM: ios-directory-owners@chromium.org
+# OS: iOS
diff --git a/ios/third_party/motion_transitioning_objc/README.chromium b/ios/third_party/motion_transitioning_objc/README.chromium
new file mode 100644
index 0000000..fb06e7ee
--- /dev/null
+++ b/ios/third_party/motion_transitioning_objc/README.chromium
@@ -0,0 +1,13 @@
+Name: Motion Transitioning for Objective-C
+URL: https://github.com/material-motion/motion-transitioning-objc
+Version: 0
+Revision: 994fd02d1de3d80ed284f0c1a4b5f459b8b051a6
+License: Apache 2.0
+License File: LICENSE
+Security Critical: yes
+
+Description:
+Light-weight API for building UIViewController transitions.
+
+Local Modifications:
+None
diff --git a/ios/web/BUILD.gn b/ios/web/BUILD.gn
index 16e48ca..6756f68 100644
--- a/ios/web/BUILD.gn
+++ b/ios/web/BUILD.gn
@@ -578,9 +578,9 @@
   ]
 }
 
-js_compile_bundle("web_bundle") {
+js_compile_bundle("main_frame_web_bundle") {
   visibility = [ ":js_resources" ]
-  closure_entry_point = "__crWeb.webBundle"
+  closure_entry_point = "__crWeb.mainFrameWebBundle"
 
   sources = [
     "web_state/js/resources/base.js",
@@ -590,10 +590,21 @@
     "web_state/js/resources/error.js",
     "web_state/js/resources/form.js",
     "web_state/js/resources/legacy.js",
+    "web_state/js/resources/main_frame_web_bundle.js",
     "web_state/js/resources/message.js",
     "web_state/js/resources/navigation.js",
     "web_state/js/resources/scroll_workaround.js",
-    "web_state/js/resources/web_bundle.js",
+  ]
+}
+
+js_compile_bundle("all_frames_web_bundle") {
+  visibility = [ ":js_resources" ]
+  closure_entry_point = "__crWeb.allFramesWebBundle"
+
+  sources = [
+    "web_state/js/resources/all_frames_web_bundle.js",
+    "web_state/js/resources/base.js",
+    "web_state/js/resources/form.js",
   ]
 }
 
@@ -608,8 +619,9 @@
 
 js_compile_checked("js_resources") {
   public_deps = [
+    ":all_frames_web_bundle",
+    ":main_frame_web_bundle",
     ":nav_bundle",
-    ":web_bundle",
     ":web_ui_bundle",
   ]
 
diff --git a/ios/web/net/crw_cert_verification_controller.mm b/ios/web/net/crw_cert_verification_controller.mm
index bb7717e..86bc9b9 100644
--- a/ios/web/net/crw_cert_verification_controller.mm
+++ b/ios/web/net/crw_cert_verification_controller.mm
@@ -17,6 +17,7 @@
 #include "ios/web/public/web_thread.h"
 #import "ios/web/web_state/wk_web_view_security_util.h"
 #include "net/cert/cert_verify_proc_ios.h"
+#include "net/cert/x509_util.h"
 #include "net/cert/x509_util_ios.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
@@ -125,12 +126,12 @@
   // |webView:didReceiveAuthenticationChallenge:completionHandler:|,
   // but the server-supplied chain in
   // |webView:didFailProvisionalNavigation:withError:|.
-  if (!cert->GetIntermediateCertificates().empty()) {
-    cert = net::X509Certificate::CreateFromHandle(
-        cert->os_cert_handle(), net::X509Certificate::OSCertHandles());
+  if (!cert->intermediate_buffers().empty()) {
+    cert = net::X509Certificate::CreateFromBuffer(
+        net::x509_util::DupCryptoBuffer(cert->cert_buffer()), {});
     DCHECK(cert);
   }
-  DCHECK(cert->GetIntermediateCertificates().empty());
+  DCHECK(cert->intermediate_buffers().empty());
   web::WebThread::PostTask(web::WebThread::IO, FROM_HERE, base::BindBlockArc(^{
                              _certPolicyCache->AllowCertForHost(
                                  cert.get(), base::SysNSStringToUTF8(host),
diff --git a/ios/web/net/crw_cert_verification_controller_unittest.mm b/ios/web/net/crw_cert_verification_controller_unittest.mm
index f092383..62f288d 100644
--- a/ios/web/net/crw_cert_verification_controller_unittest.mm
+++ b/ios/web/net/crw_cert_verification_controller_unittest.mm
@@ -12,6 +12,7 @@
 #include "ios/web/public/web_thread.h"
 #import "ios/web/web_state/wk_web_view_security_util.h"
 #include "net/cert/x509_certificate.h"
+#include "net/cert/x509_util.h"
 #include "net/cert/x509_util_ios_and_mac.h"
 #include "net/test/cert_test_util.h"
 #include "net/test/test_data_directory.h"
@@ -137,9 +138,13 @@
 
 // Tests that allowCert:forHost:status: strips all intermediate certs.
 TEST_F(CRWCertVerificationControllerTest, AllowCertIgnoresIntermediateCerts) {
+  std::vector<bssl::UniquePtr<CRYPTO_BUFFER>> intermediates;
+  intermediates.push_back(
+      net::x509_util::DupCryptoBuffer(cert_->cert_buffer()));
   scoped_refptr<net::X509Certificate> cert(
-      net::X509Certificate::CreateFromHandle(cert_->os_cert_handle(),
-                                             {cert_->os_cert_handle()}));
+      net::X509Certificate::CreateFromBuffer(
+          net::x509_util::DupCryptoBuffer(cert_->cert_buffer()),
+          std::move(intermediates)));
   ASSERT_TRUE(cert);
   [controller_ allowCert:cert.get()
                  forHost:kHostName
diff --git a/ios/web/public/crw_session_certificate_policy_cache_storage.mm b/ios/web/public/crw_session_certificate_policy_cache_storage.mm
index 970334d..3755559 100644
--- a/ios/web/public/crw_session_certificate_policy_cache_storage.mm
+++ b/ios/web/public/crw_session_certificate_policy_cache_storage.mm
@@ -7,6 +7,7 @@
 #import "base/strings/sys_string_conversions.h"
 #include "net/base/hash_value.h"
 #include "net/cert/x509_certificate.h"
+#include "net/cert/x509_util.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
@@ -37,11 +38,9 @@
 
 // Converts |certificate| to NSData for serialization.
 NSData* CertificateToNSData(net::X509Certificate* certificate) {
-  std::string cert_string;
-  bool success = net::X509Certificate::GetDEREncoded(
-      certificate->os_cert_handle(), &cert_string);
-  DCHECK(success);
-  return [NSData dataWithBytes:cert_string.c_str() length:cert_string.length()];
+  base::StringPiece cert_string =
+      net::x509_util::CryptoBufferAsStringPiece(certificate->cert_buffer());
+  return [NSData dataWithBytes:cert_string.data() length:cert_string.length()];
 }
 
 // Converts serialized NSData to a certificate.
diff --git a/ios/web/public/crw_session_certificate_policy_cache_storage_unittest.mm b/ios/web/public/crw_session_certificate_policy_cache_storage_unittest.mm
index d9739566..1848624 100644
--- a/ios/web/public/crw_session_certificate_policy_cache_storage_unittest.mm
+++ b/ios/web/public/crw_session_certificate_policy_cache_storage_unittest.mm
@@ -6,6 +6,7 @@
 
 #import "base/mac/scoped_nsobject.h"
 #include "net/cert/x509_certificate.h"
+#include "net/cert/x509_util.h"
 #include "net/test/cert_test_util.h"
 #include "net/test/test_data_directory.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -20,13 +21,9 @@
 // Checks for equality between |cert_storage1| and |cert_storage2|.
 bool CertStoragesAreEqual(CRWSessionCertificateStorage* cert_storage1,
                           CRWSessionCertificateStorage* cert_storage2) {
-  std::string cert_string1;
-  bool success1 = net::X509Certificate::GetDEREncoded(
-      cert_storage1.certificate->os_cert_handle(), &cert_string1);
-  std::string cert_string2;
-  bool success2 = net::X509Certificate::GetDEREncoded(
-      cert_storage2.certificate->os_cert_handle(), &cert_string2);
-  return success1 && success2 && cert_string1 == cert_string2 &&
+  return net::x509_util::CryptoBufferEqual(
+             cert_storage1.certificate->cert_buffer(),
+             cert_storage2.certificate->cert_buffer()) &&
          cert_storage1.host == cert_storage2.host &&
          cert_storage1.status == cert_storage2.status;
 }
diff --git a/ios/web/public/test/fakes/test_web_client.h b/ios/web/public/test/fakes/test_web_client.h
index 0e79b5c1..9e16ef6 100644
--- a/ios/web/public/test/fakes/test_web_client.h
+++ b/ios/web/public/test/fakes/test_web_client.h
@@ -28,7 +28,8 @@
   // Returns true for kTestWebUIScheme and kTestNativeContentScheme URL schemes.
   bool IsAppSpecificURL(const GURL& url) const override;
   base::RefCountedMemory* GetDataResourceBytes(int id) const override;
-  NSString* GetEarlyPageScript(BrowserState* browser_state) const override;
+  NSString* GetEarlyPageScriptForMainFrame(
+      BrowserState* browser_state) const override;
   void AllowCertificateError(WebState*,
                              int cert_error,
                              const net::SSLInfo&,
diff --git a/ios/web/public/test/fakes/test_web_client.mm b/ios/web/public/test/fakes/test_web_client.mm
index 2524605..d20001a 100644
--- a/ios/web/public/test/fakes/test_web_client.mm
+++ b/ios/web/public/test/fakes/test_web_client.mm
@@ -39,7 +39,8 @@
       resource_id);
 }
 
-NSString* TestWebClient::GetEarlyPageScript(BrowserState* browser_state) const {
+NSString* TestWebClient::GetEarlyPageScriptForMainFrame(
+    BrowserState* browser_state) const {
   return early_page_script_ ? early_page_script_ : @"";
 }
 
diff --git a/ios/web/public/web_client.h b/ios/web/public/web_client.h
index 2e9e8b6..5ecc7083 100644
--- a/ios/web/public/web_client.h
+++ b/ios/web/public/web_client.h
@@ -127,7 +127,8 @@
   //
   // TODO(crbug.com/703964): Change the return value to NSArray<NSString*> to
   // improve performance.
-  virtual NSString* GetEarlyPageScript(BrowserState* browser_state) const;
+  virtual NSString* GetEarlyPageScriptForMainFrame(
+      BrowserState* browser_state) const;
 
   using StaticServiceMap =
       std::map<std::string, service_manager::EmbeddedServiceInfo>;
diff --git a/ios/web/web_client.mm b/ios/web/web_client.mm
index aac6ef9..f48e18a 100644
--- a/ios/web/web_client.mm
+++ b/ios/web/web_client.mm
@@ -74,7 +74,8 @@
   return nullptr;
 }
 
-NSString* WebClient::GetEarlyPageScript(BrowserState* browser_state) const {
+NSString* WebClient::GetEarlyPageScriptForMainFrame(
+    BrowserState* browser_state) const {
   return @"";
 }
 
diff --git a/ios/web/web_state/js/crw_js_window_id_manager_unittest.mm b/ios/web/web_state/js/crw_js_window_id_manager_unittest.mm
index 9e3847e..be38ebed 100644
--- a/ios/web/web_state/js/crw_js_window_id_manager_unittest.mm
+++ b/ios/web/web_state/js/crw_js_window_id_manager_unittest.mm
@@ -29,7 +29,7 @@
 TEST_F(JSWindowIDManagerTest, WindowIDDifferentManager) {
   // Inject the first manager.
   WKWebView* web_view = [[WKWebView alloc] init];
-  ExecuteJavaScript(web_view, GetEarlyPageScript(&browser_state_));
+  ExecuteJavaScript(web_view, GetEarlyPageScriptForMainFrame(&browser_state_));
 
   CRWJSWindowIDManager* manager =
       [[CRWJSWindowIDManager alloc] initWithWebView:web_view];
@@ -39,7 +39,7 @@
 
   // Inject the second manager.
   WKWebView* web_view2 = [[WKWebView alloc] init];
-  ExecuteJavaScript(web_view2, GetEarlyPageScript(&browser_state_));
+  ExecuteJavaScript(web_view2, GetEarlyPageScriptForMainFrame(&browser_state_));
 
   CRWJSWindowIDManager* manager2 =
       [[CRWJSWindowIDManager alloc] initWithWebView:web_view2];
@@ -54,7 +54,7 @@
 // Tests that injecting multiple times creates a new window ID.
 TEST_F(JSWindowIDManagerTest, MultipleInjections) {
   WKWebView* web_view = [[WKWebView alloc] init];
-  ExecuteJavaScript(web_view, GetEarlyPageScript(&browser_state_));
+  ExecuteJavaScript(web_view, GetEarlyPageScriptForMainFrame(&browser_state_));
 
   // First injection.
   CRWJSWindowIDManager* manager =
@@ -83,7 +83,7 @@
   EXPECT_FALSE(ExecuteJavaScript(web_view, @"window.__gCrWeb"));
 
   // Now inject window.__gCrWeb and check if window ID injection retried.
-  ExecuteJavaScript(web_view, GetEarlyPageScript(&browser_state_));
+  ExecuteJavaScript(web_view, GetEarlyPageScriptForMainFrame(&browser_state_));
   EXPECT_NSEQ([manager windowID],
               ExecuteJavaScript(web_view, @"window.__gCrWeb.windowId"));
 }
diff --git a/ios/web/web_state/js/page_script_util.h b/ios/web/web_state/js/page_script_util.h
index 53d67cb..3a93222 100644
--- a/ios/web/web_state/js/page_script_util.h
+++ b/ios/web/web_state/js/page_script_util.h
@@ -17,8 +17,12 @@
 NSString* GetPageScript(NSString* script_file_name);
 
 // Returns an autoreleased string containing the JavaScript to be injected into
-// the web view as early as possible.
-NSString* GetEarlyPageScript(BrowserState* browser_state);
+// the main frame of the web view as early as possible.
+NSString* GetEarlyPageScriptForMainFrame(BrowserState* browser_state);
+
+// Returns an autoreleased string containing the JavaScript to be injected into
+// all frames of the web view as early as possible.
+NSString* GetEarlyPageScriptForAllFrames(BrowserState* browser_state);
 
 }  // namespace web
 
diff --git a/ios/web/web_state/js/page_script_util.mm b/ios/web/web_state/js/page_script_util.mm
index 4a7599d..3d92b8b 100644
--- a/ios/web/web_state/js/page_script_util.mm
+++ b/ios/web/web_state/js/page_script_util.mm
@@ -15,6 +15,22 @@
 #error "This file requires ARC support."
 #endif
 
+namespace {
+
+// Make sure that script is injected only once. For example, content of
+// WKUserScript can be injected into the same page multiple times
+// without notifying WKNavigationDelegate (e.g. after window.document.write
+// JavaScript call). Injecting the script multiple times invalidates the
+// __gCrWeb.windowId variable and will break the ability to send messages from
+// JS to the native code. Wrapping injected script into "if (!injected)" check
+// prevents multiple injections into the same page.
+NSString* MakeScriptInjectableOnce(NSString* script) {
+  NSString* kScriptTemplate = @"if (typeof __gCrWeb !== 'object') { %@; }";
+  return [NSString stringWithFormat:kScriptTemplate, script];
+}
+
+}  // namespace
+
 namespace web {
 
 NSString* GetPageScript(NSString* script_file_name) {
@@ -34,30 +50,28 @@
   return content;
 }
 
-NSString* GetEarlyPageScript(BrowserState* browser_state) {
+NSString* GetEarlyPageScriptForMainFrame(BrowserState* browser_state) {
   DCHECK(GetWebClient());
   NSString* embedder_page_script =
-      GetWebClient()->GetEarlyPageScript(browser_state);
+      GetWebClient()->GetEarlyPageScriptForMainFrame(browser_state);
   DCHECK(embedder_page_script);
 
-  // Make sure that script is injected only once. For example, content of
-  // WKUserScript can be injected into the same page multiple times
-  // without notifying WKNavigationDelegate (e.g. after window.document.write
-  // JavaScript call). Injecting the script multiple times invalidates the
-  // __gCrWeb.windowId variable and will break the ability to send messages from
-  // JS to the native code. Wrapping injected script into "if (!injected)" check
-  // prevents multiple injections into the same page.
-  NSString* kScriptTemplate = @"if (typeof __gCrWeb !== 'object') { %@; %@ }";
+  NSString* web_bundle = GetPageScript(@"main_frame_web_bundle");
 
-  NSString* web_bundle = GetPageScript(@"web_bundle");
   // The WKBackForwardList based navigation manager doesn't need to inject
   // JavaScript to intercept navigation calls.
   if (!GetWebClient()->IsSlimNavigationManagerEnabled()) {
     web_bundle = [NSString
         stringWithFormat:@"%@; %@", web_bundle, GetPageScript(@"nav_bundle")];
   }
-  return [NSString
-      stringWithFormat:kScriptTemplate, web_bundle, embedder_page_script];
+
+  NSString* script =
+      [NSString stringWithFormat:@"%@; %@", web_bundle, embedder_page_script];
+  return MakeScriptInjectableOnce(script);
+}
+
+NSString* GetEarlyPageScriptForAllFrames(BrowserState* browser_state) {
+  return MakeScriptInjectableOnce(GetPageScript(@"all_frames_web_bundle"));
 }
 
 }  // namespace web
diff --git a/ios/web/web_state/js/page_script_util_unittest.mm b/ios/web/web_state/js/page_script_util_unittest.mm
index df16aad..93bfc44d 100644
--- a/ios/web/web_state/js/page_script_util_unittest.mm
+++ b/ios/web/web_state/js/page_script_util_unittest.mm
@@ -30,7 +30,8 @@
 // __gCrWeb object.
 TEST_F(PageScriptUtilTest, WKWebViewEarlyPageScript) {
   WKWebView* web_view = BuildWKWebView(CGRectZero, GetBrowserState());
-  ExecuteJavaScript(web_view, GetEarlyPageScript(GetBrowserState()));
+  ExecuteJavaScript(web_view,
+                    GetEarlyPageScriptForMainFrame(GetBrowserState()));
   EXPECT_NSEQ(@"object", ExecuteJavaScript(web_view, @"typeof __gCrWeb"));
 }
 
@@ -38,7 +39,8 @@
 TEST_F(PageScriptUtilTest, WKEmbedderScript) {
   GetWebClient()->SetEarlyPageScript(@"__gCrEmbedder = {};");
   WKWebView* web_view = BuildWKWebView(CGRectZero, GetBrowserState());
-  ExecuteJavaScript(web_view, GetEarlyPageScript(GetBrowserState()));
+  ExecuteJavaScript(web_view,
+                    GetEarlyPageScriptForMainFrame(GetBrowserState()));
   EXPECT_NSEQ(@"object", ExecuteJavaScript(web_view, @"typeof __gCrEmbedder"));
 }
 
diff --git a/ios/web/web_state/js/resources/all_frames_web_bundle.js b/ios/web/web_state/js/resources/all_frames_web_bundle.js
new file mode 100644
index 0000000..f526b48
--- /dev/null
+++ b/ios/web/web_state/js/resources/all_frames_web_bundle.js
@@ -0,0 +1,8 @@
+// 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.
+
+// Set of scripts required by web layer backed up by WKWebView.
+goog.provide('__crWeb.allFramesWebBundle');
+
+goog.require('__crWeb.form');
\ No newline at end of file
diff --git a/ios/web/web_state/js/resources/form.js b/ios/web/web_state/js/resources/form.js
index 38e0cb4..cf9ca9f 100644
--- a/ios/web/web_state/js/resources/form.js
+++ b/ios/web/web_state/js/resources/form.js
@@ -10,10 +10,22 @@
 
 goog.provide('__crWeb.form');
 
-goog.require('__crWeb.message');
-
 /** Beginning of anonymous object */
 (function() {
+  // Skip iframes that have the same origin as the main frame. For such frames
+  // no form related actions (eg. filling, saving) are supported.
+  try {
+    // The following line generates exception for iframes that have different
+    // origin that.
+    // TODO(crbug.com/792642): implement sending messages instead of using
+    // window.top, when messaging framework is ready.
+    if (!window.top.document)
+      return;
+  }
+  catch(error) {
+    return;
+  }
+
 
   /**
    * Focus and input events for form elements are messaged to the main
@@ -30,13 +42,15 @@
 
     var msg = {
       'command': 'form.activity',
-      'formName': __gCrWeb.common.getFormIdentifier(evt.srcElement.form),
-      'fieldName': __gCrWeb.common.getFieldIdentifier(srcElement),
+      'formName': window.top.__gCrWeb.common.
+                      getFormIdentifier(evt.srcElement.form),
+      'fieldName': window.top.__gCrWeb.common.
+                      getFieldIdentifier(srcElement),
       'fieldType': fieldType,
       'type': evt.type,
       'value': value
     };
-    __gCrWeb.message.invokeOnHost(msg);
+    window.top.__gCrWeb.message.invokeOnHost(msg);
   };
 
   /**
@@ -66,9 +80,10 @@
     if (!action) {
       action = document.location.href;
     }
-    __gCrWeb.message.invokeOnHost({
+    window.top.__gCrWeb.message.invokeOnHost({
              'command': 'document.submit',
-            'formName': __gCrWeb.common.getFormIdentifier(evt.srcElement),
+            'formName': window.top.__gCrWeb.common.
+                            getFormIdentifier(evt.srcElement),
                 'href': getFullyQualifiedUrl_(action)
     });
   }, false);
@@ -83,8 +98,8 @@
   };
 
   /** Flush the message queue. */
-  if (__gCrWeb.message) {
-    __gCrWeb.message.invokeQueues();
+  if (window.top.__gCrWeb.message) {
+    window.top.__gCrWeb.message.invokeQueues();
   }
 
 }());  // End of anonymous object
diff --git a/ios/web/web_state/js/resources/web_bundle.js b/ios/web/web_state/js/resources/main_frame_web_bundle.js
similarity index 91%
rename from ios/web/web_state/js/resources/web_bundle.js
rename to ios/web/web_state/js/resources/main_frame_web_bundle.js
index a826451..7ad2f706 100644
--- a/ios/web/web_state/js/resources/web_bundle.js
+++ b/ios/web/web_state/js/resources/main_frame_web_bundle.js
@@ -3,7 +3,7 @@
 // found in the LICENSE file.
 
 // Set of scripts required by web layer backed up by WKWebView.
-goog.provide('__crWeb.webBundle');
+goog.provide('__crWeb.mainFrameWebBundle');
 
 goog.require('__crWeb.console');
 goog.require('__crWeb.contextMenu');
diff --git a/ios/web/web_state/navigation_context_impl.h b/ios/web/web_state/navigation_context_impl.h
index 1432e7cc..3faeeff 100644
--- a/ios/web/web_state/navigation_context_impl.h
+++ b/ios/web/web_state/navigation_context_impl.h
@@ -5,6 +5,8 @@
 #ifndef IOS_WEB_WEB_STATE_NAVIGATION_CONTEXT_IMPL_H_
 #define IOS_WEB_WEB_STATE_NAVIGATION_CONTEXT_IMPL_H_
 
+#import <WebKit/WebKit.h>
+
 #include <memory>
 
 #import "base/mac/scoped_nsobject.h"
@@ -54,6 +56,10 @@
   int GetNavigationItemUniqueID() const;
   void SetNavigationItemUniqueID(int unique_id);
 
+  // Optional WKNavigationType of the associated navigation in WKWebView.
+  void SetWKNavigationType(WKNavigationType wk_navigation_type);
+  WKNavigationType GetWKNavigationType() const;
+
  private:
   NavigationContextImpl(WebState* web_state,
                         const GURL& url,
@@ -62,13 +68,14 @@
 
   WebState* web_state_ = nullptr;
   GURL url_;
-  ui::PageTransition page_transition_;
+  const ui::PageTransition page_transition_;
   bool is_same_document_ = false;
   bool is_post_ = false;
   base::scoped_nsobject<NSError> error_;
   scoped_refptr<net::HttpResponseHeaders> response_headers_;
   bool is_renderer_initiated_ = false;
   int navigation_item_unique_id_ = -1;
+  WKNavigationType wk_navigation_type_ = WKNavigationTypeOther;
 
   DISALLOW_COPY_AND_ASSIGN(NavigationContextImpl);
 };
diff --git a/ios/web/web_state/navigation_context_impl.mm b/ios/web/web_state/navigation_context_impl.mm
index 5cd26f7..361e20e 100644
--- a/ios/web/web_state/navigation_context_impl.mm
+++ b/ios/web/web_state/navigation_context_impl.mm
@@ -98,6 +98,15 @@
   navigation_item_unique_id_ = unique_id;
 }
 
+void NavigationContextImpl::SetWKNavigationType(
+    WKNavigationType wk_navigation_type) {
+  wk_navigation_type_ = wk_navigation_type;
+}
+
+WKNavigationType NavigationContextImpl::GetWKNavigationType() const {
+  return wk_navigation_type_;
+}
+
 NavigationContextImpl::NavigationContextImpl(WebState* web_state,
                                              const GURL& url,
                                              ui::PageTransition page_transition,
diff --git a/ios/web/web_state/navigation_context_impl_unittest.mm b/ios/web/web_state/navigation_context_impl_unittest.mm
index 4688e4c..c06008a6 100644
--- a/ios/web/web_state/navigation_context_impl_unittest.mm
+++ b/ios/web/web_state/navigation_context_impl_unittest.mm
@@ -66,6 +66,7 @@
   ASSERT_FALSE(context->GetError());
   ASSERT_FALSE(context->IsRendererInitiated());
   ASSERT_NE(response_headers_.get(), context->GetResponseHeaders());
+  EXPECT_EQ(WKNavigationTypeOther, context->GetWKNavigationType());
 
   // SetSameDocument
   context->SetIsSameDocument(true);
@@ -74,6 +75,8 @@
   EXPECT_FALSE(context->GetError());
   EXPECT_FALSE(context->IsRendererInitiated());
   EXPECT_NE(response_headers_.get(), context->GetResponseHeaders());
+  EXPECT_EQ(WKNavigationTypeOther, context->GetWKNavigationType());
+  EXPECT_EQ(WKNavigationTypeOther, context->GetWKNavigationType());
 
   // SetPost
   context->SetIsPost(true);
@@ -82,6 +85,7 @@
   EXPECT_FALSE(context->GetError());
   EXPECT_FALSE(context->IsRendererInitiated());
   EXPECT_NE(response_headers_.get(), context->GetResponseHeaders());
+  EXPECT_EQ(WKNavigationTypeOther, context->GetWKNavigationType());
 
   // SetErrorPage
   NSError* error = [[NSError alloc] init];
@@ -91,6 +95,7 @@
   EXPECT_EQ(error, context->GetError());
   EXPECT_FALSE(context->IsRendererInitiated());
   EXPECT_NE(response_headers_.get(), context->GetResponseHeaders());
+  EXPECT_EQ(WKNavigationTypeOther, context->GetWKNavigationType());
 
   // SetResponseHeaders
   context->SetResponseHeaders(response_headers_);
@@ -99,6 +104,7 @@
   EXPECT_EQ(error, context->GetError());
   EXPECT_FALSE(context->IsRendererInitiated());
   EXPECT_EQ(response_headers_.get(), context->GetResponseHeaders());
+  EXPECT_EQ(WKNavigationTypeOther, context->GetWKNavigationType());
 
   // SetIsRendererInitiated
   context->SetIsRendererInitiated(true);
@@ -107,6 +113,16 @@
   EXPECT_EQ(error, context->GetError());
   EXPECT_TRUE(context->IsRendererInitiated());
   EXPECT_EQ(response_headers_.get(), context->GetResponseHeaders());
+  EXPECT_EQ(WKNavigationTypeOther, context->GetWKNavigationType());
+
+  // SetWKNavigationType
+  context->SetWKNavigationType(WKNavigationTypeBackForward);
+  EXPECT_TRUE(context->IsSameDocument());
+  ASSERT_TRUE(context->IsPost());
+  EXPECT_EQ(error, context->GetError());
+  EXPECT_TRUE(context->IsRendererInitiated());
+  EXPECT_EQ(response_headers_.get(), context->GetResponseHeaders());
+  EXPECT_EQ(WKNavigationTypeBackForward, context->GetWKNavigationType());
 }
 
 }  // namespace web
diff --git a/ios/web/web_state/ui/crw_web_controller.mm b/ios/web/web_state/ui/crw_web_controller.mm
index 5761af0..1777878 100644
--- a/ios/web/web_state/ui/crw_web_controller.mm
+++ b/ios/web/web_state/ui/crw_web_controller.mm
@@ -1365,10 +1365,13 @@
       [self pageTransitionFromNavigationType:navigationType];
   // The referrer is not known yet, and will be updated later.
   const web::Referrer emptyReferrer;
-  return [self registerLoadRequestForURL:URL
-                                referrer:emptyReferrer
-                              transition:transition
-                  sameDocumentNavigation:sameDocumentNavigation];
+  std::unique_ptr<web::NavigationContextImpl> context =
+      [self registerLoadRequestForURL:URL
+                             referrer:emptyReferrer
+                           transition:transition
+               sameDocumentNavigation:sameDocumentNavigation];
+  context->SetWKNavigationType(navigationType);
+  return context;
 }
 
 - (std::unique_ptr<web::NavigationContextImpl>)
@@ -4548,13 +4551,6 @@
   // pending navigation information should be applied to state information.
   [self setDocumentURL:webViewURL];
 
-  if (!_lastRegisteredRequestURL.is_valid() &&
-      _documentURL != _lastRegisteredRequestURL) {
-    // if |_lastRegisteredRequestURL| is an invalid URL, then |_documentURL|
-    // will be "about:blank".
-    self.navigationManagerImpl->UpdatePendingItemUrl(_documentURL);
-  }
-
   // If |navigation| is nil (which happens for windows open by DOM), then it
   // should be the first and the only pending navigation.
   BOOL isLastNavigation =
@@ -5222,6 +5218,7 @@
     } else {
       // |didCommitNavigation:| may not be called for fast navigation, so update
       // the navigation type now as it is already known.
+      navigationContext->SetWKNavigationType(WKNavigationTypeBackForward);
       holder->set_navigation_type(WKNavigationTypeBackForward);
       navigation =
           [_webView goToBackForwardListItem:holder->back_forward_list_item()];
diff --git a/ios/web/web_state/ui/wk_web_view_configuration_provider.mm b/ios/web/web_state/ui/wk_web_view_configuration_provider.mm
index 2a4b988..147a0be8 100644
--- a/ios/web/web_state/ui/wk_web_view_configuration_provider.mm
+++ b/ios/web/web_state/ui/wk_web_view_configuration_provider.mm
@@ -25,13 +25,24 @@
 
 // Returns an autoreleased instance of WKUserScript to be added to
 // configuration's userContentController.
-WKUserScript* InternalGetEarlyPageScript(BrowserState* browser_state) {
+WKUserScript* InternalGetEarlyPageScriptForMainFrame(
+    BrowserState* browser_state) {
   return [[WKUserScript alloc]
-        initWithSource:GetEarlyPageScript(browser_state)
+        initWithSource:GetEarlyPageScriptForMainFrame(browser_state)
          injectionTime:WKUserScriptInjectionTimeAtDocumentStart
       forMainFrameOnly:YES];
 }
 
+// Returns an autoreleased instance of WKUserScript to be added to
+// configuration's userContentController.
+WKUserScript* InternalGetEarlyPageScriptForAllFrames(
+    BrowserState* browser_state) {
+  return [[WKUserScript alloc]
+        initWithSource:GetEarlyPageScriptForAllFrames(browser_state)
+         injectionTime:WKUserScriptInjectionTimeAtDocumentStart
+      forMainFrameOnly:NO];
+}
+
 }  // namespace
 
 // static
@@ -70,7 +81,9 @@
     // setJavaScriptCanOpenWindowsAutomatically is required to support popups.
     [[configuration_ preferences] setJavaScriptCanOpenWindowsAutomatically:YES];
     [[configuration_ userContentController]
-        addUserScript:InternalGetEarlyPageScript(browser_state_)];
+        addUserScript:InternalGetEarlyPageScriptForMainFrame(browser_state_)];
+    [[configuration_ userContentController]
+        addUserScript:InternalGetEarlyPageScriptForAllFrames(browser_state_)];
   }
   // Prevent callers from changing the internals of configuration.
   return [configuration_ copy];
diff --git a/ios/web/web_state/ui/wk_web_view_configuration_provider_unittest.mm b/ios/web/web_state/ui/wk_web_view_configuration_provider_unittest.mm
index 20d402f..2e2813c 100644
--- a/ios/web/web_state/ui/wk_web_view_configuration_provider_unittest.mm
+++ b/ios/web/web_state/ui/wk_web_view_configuration_provider_unittest.mm
@@ -136,15 +136,20 @@
 }
 
 // Tests that configuration's userContentController has only one script with the
-// same content as web::GetEarlyPageScript() returns.
+// same content as web::GetEarlyPageScriptForMainFrame() returns.
 TEST_F(WKWebViewConfigurationProviderTest, UserScript) {
   WKWebViewConfiguration* config = GetProvider().GetWebViewConfiguration();
   NSArray* scripts = config.userContentController.userScripts;
-  EXPECT_EQ(1U, scripts.count);
-  NSString* early_script = GetEarlyPageScript(&browser_state_);
-  // |earlyScript| is a substring of |userScripts|. The latter wraps the
-  // former with "if (!injected)" check to avoid double injections.
-  EXPECT_LT(0U, [[scripts[0] source] rangeOfString:early_script].length);
+  ASSERT_EQ(2U, scripts.count);
+  EXPECT_TRUE(((WKUserScript*)[scripts objectAtIndex:0]).isForMainFrameOnly);
+  EXPECT_FALSE(((WKUserScript*)[scripts objectAtIndex:1]).isForMainFrameOnly);
+  NSString* main_frame_script = GetEarlyPageScriptForMainFrame(&browser_state_);
+  NSString* all_frames_script = GetEarlyPageScriptForAllFrames(&browser_state_);
+  // |early_main_frame_script| and |all_frames_script| are substrings of
+  // corresponding scripts from |userScripts|. The latter wraps the former with
+  // "if (!injected)" check to avoid double injections.
+  EXPECT_LT(0U, [[scripts[0] source] rangeOfString:main_frame_script].length);
+  EXPECT_LT(0U, [[scripts[1] source] rangeOfString:all_frames_script].length);
 }
 
 }  // namespace
diff --git a/ios/web_view/internal/web_view_web_client.h b/ios/web_view/internal/web_view_web_client.h
index 7e144b4..28e6ae6 100644
--- a/ios/web_view/internal/web_view_web_client.h
+++ b/ios/web_view/internal/web_view_web_client.h
@@ -26,7 +26,8 @@
       int resource_id,
       ui::ScaleFactor scale_factor) const override;
   base::RefCountedMemory* GetDataResourceBytes(int resource_id) const override;
-  NSString* GetEarlyPageScript(web::BrowserState* browser_state) const override;
+  NSString* GetEarlyPageScriptForMainFrame(
+      web::BrowserState* browser_state) const override;
 
  private:
   DISALLOW_COPY_AND_ASSIGN(WebViewWebClient);
diff --git a/ios/web_view/internal/web_view_web_client.mm b/ios/web_view/internal/web_view_web_client.mm
index 96de743..e5a1c0cc 100644
--- a/ios/web_view/internal/web_view_web_client.mm
+++ b/ios/web_view/internal/web_view_web_client.mm
@@ -48,7 +48,7 @@
       resource_id);
 }
 
-NSString* WebViewWebClient::GetEarlyPageScript(
+NSString* WebViewWebClient::GetEarlyPageScriptForMainFrame(
     web::BrowserState* browser_state) const {
   return WebViewEarlyPageScriptProvider::FromBrowserState(browser_state)
       .GetScript();
diff --git a/ipc/README.md b/ipc/README.md
index c30689a..2e0cbe40 100644
--- a/ipc/README.md
+++ b/ipc/README.md
@@ -237,12 +237,18 @@
 can be acquired by a renderer as follows:
 
 ``` cpp
-mojom::FooPtr foo;
+mojom::LoggerPtr logger;
 content::RenderThread::Get()->GetConnector()->BindInterface(
-    content::mojom::kBrowserServiceName, &foo);
-foo->DoSomePrettyCoolIPC();
+    content::mojom::kBrowserServiceName, &logger);
+logger->Log("Message to log here");
 ```
 
+Usually `logger` will be saved in a field at construction time, so the
+connection is only created once. There may be situations where you want to
+create one connection per request, e.g. a new instance of the Mojo
+implementation is created with some information about the request, and any
+responses for this request go straight to that instance.
+
 ### On Other Threads
 
 `Connector` instances can be created and asynchronously associated with each
@@ -255,20 +261,21 @@
 associate it with the main-thread `Connector` like so:
 
 ``` cpp
-class Thinger {
+class Logger {
  public:
-  explicit Thinger(scoped_refptr<base::TaskRunner> main_thread_task_runner) {
+  explicit Logger(scoped_refptr<base::TaskRunner> main_thread_task_runner) {
     service_manager::mojom::ConnectorRequest request;
 
     // Of course we could also retain |connector| if we intend to use it again.
     auto connector = service_manager::Connector::Create(&request);
-    connector->BindInterface("best_service_ever", &thinger_);
-    thinger_->DoTheThing();
+    // Replace service_name with the name of the service to bind on, e.g.
+    // content::mojom::kBrowserServiceName.
+    connector->BindInterface("service_name", &logger_);
+    logger_->Log("Test Message.");
 
-    // Doesn't really matter when this happens, as long as it eventually
-    // happens.
+    // Doesn't matter when this happens, as long as it happens eventually.
     main_thread_task_runner->PostTask(
-        FROM_HERE, base::BindOnce(&Thinger::BindConnectorOnMainThread,
+        FROM_HERE, base::BindOnce(&Logger::BindConnectorOnMainThread,
                                   std::move(request)));
   }
 
@@ -280,9 +287,9 @@
         std::move(request));
   }
 
-  mojom::ThingerPtr thinger_;
+  mojom::LoggerPtr logger_;
 
-  DISALLOW_COPY_AND_ASSIGN(Thinger);
+  DISALLOW_COPY_AND_ASSIGN(Logger);
 };
 ```
 
@@ -339,6 +346,170 @@
 
 As noted above, use of these registries is generally discouraged.
 
+### Deciding Which Interface Registry to Use
+
+Once you have an implementation of a Mojo interface, the next thing to decide is
+which registry and service to register it on.
+
+For browser/renderer communication, you can register your Mojo interface
+implementation in either the Browser or Renderer process (whichever side the
+interface was implemented on). Usually, this involves calling `AddInterface()`
+on the correct registry, passing a method that takes the Mojo Request object
+(e.g. `sample::mojom::LoggerRequest`) and binding it (e.g.
+`mojo::MakeStrongBinding()`, `bindings_.AddBinding()`, etc). Then the class that
+needs this API can call `BindInterface()` on the connector for that process,
+e.g.
+`RenderThread::Get()->GetConnector()->BindInterface(mojom::kBrowserServiceName, std::move(&mojo_interface_))`.
+
+**NOTE:** `content::ServiceManagerConnection::GetForProcess()` must be called in
+the browser process on the main thread, and its connector can only be used on
+the main thread; but you can clone connectors and move the clones around to
+other threads. A `Connector` is only bound to the thread which first calls into
+it.
+
+Depending on what resources you need access to, the main classes are:
+
+| Renderer Class  | Corresponding Browser Class |  Explanation                                                                                                      |
+|-----------------|-----------------------------|-------------------------------------------------------------------------------------------------------------------|
+| `RenderFrame`   | `RenderFrameHost`           |  A single frame. Use this for frame-to-frame messages.                                                            |
+| `RenderView`    | `RenderViewHost`            | A view (conceptually a 'tab'). You cannot send Mojo messages to a `RenderView` directly, since frames in a tab can
+                                                  be in multiple processes (and the classes are deprecated). Migrate these to `RenderFrame` instead, or see section
+                                                  [Migrating IPC calls to `RenderView` or `RenderViewHost`](#UMigrating-IPC-calls-to-RenderView-or-RenderViewHost). |
+| `RenderProcess` | `RenderProcessHost`         | A process, containing multiple frames (probably from the same origin, but not always).                            |
+
+**NOTE:** Previously, classes that ended with `Host` were implemented on the
+browser side; the equivalent classes on the renderer side had the same name
+without the `Host` suffix. We have since deviated from this convention since
+Mojo interfaces are not intended to prescribe where their endpoints live, so
+future classes should omit such suffixes and just describe the interface they
+are providing.
+
+Of course, any combination of the above is possible, e.g. `RenderProcessHost`
+can register a Mojo interface that can be called by a `RenderFrame` (this would
+be a way of the browser communicating with multiple frames at once).
+
+Once you know which class you want the implementation to be registered in, find
+the corresponding `Impl` class (e.g. `RenderProcessImpl`). There should be a
+`RegisterMojoInterfaces()` method where you can add calls to `AddInterface`,
+e.g. For a strong binding:
+
+```cpp
+  registry->AddInterface(base::Bind(&Logger::Create, GetID()));
+```
+
+Then in `Logger` we add a static `Create()` method that takes the
+`LoggerRequest` object:
+
+```cpp
+// static
+void Logger::Create(int render_process_id,
+                        mojom::LoggerRequest request) {
+  mojo::MakeStrongBinding(std::make_unique<Logger>(render_process_id),
+                          std::move(request));
+}
+```
+
+For a `BindingSet`, we can store a `std::unique_ptr<Logger>` on the
+`RenderProcessHost` instead, e.g.:
+
+```cpp
+// render_process_host_impl.h:
+std::unique_ptr<Logger> logger_;
+
+// render_process_host_impl.cc:
+logger_ = std::make_unique<Logger>(GetID());
+registry->AddInterface(base::Bind(&Logger::BindRequest,
+                       base::Unretained(logger_.get())));
+```
+
+Then in `Logger` we define the `BindRequest` method:
+
+```h
+class Logger : public sample::mojom::Logger {
+ public:
+  explicit Logger(int render_process_id);
+  ~Logger() override;
+
+  void BindRequest(mojom::LoggerRequest request);
+
+  // sample::mojom::Logger:
+  void Log(const std::string& message) override;
+  void GetTail(GetTailCallback callback) override;
+
+ private:
+  mojo::BindingSet<sample::mojom::Logger> bindings_;
+
+  DISALLOW_COPY_AND_ASSIGN(Logger);
+};
+```
+
+```cpp
+void Logger::BindRequest(mojom::LoggerRequest request) {
+  bindings_.AddBinding(this, std::move(request));
+}
+```
+
+#### Setting up Capabilities
+
+Once you've registered your interface, you need to add capabilities (resolved at
+runtime) to the corresponding capabilities manifest json file.
+
+The service manifest files (which contain the capability spec) are located in
+[/content/public/app/mojo/](/content/public/app/mojo/). As a general rule, the
+file you want to edit is the service which *provides* the interface (the side
+which instantiates the implementation), and the part of the file you want to add
+the name of the interface to is the service which *calls* the interface (i.e.
+the side containing `LoggerPtr`).
+
+You can usually just run your Mojo code and look at the error messages. The
+errors look like:
+
+```sh
+[ERROR:service_manager.cc(158)] Connection InterfaceProviderSpec prevented
+service: content_renderer from binding interface: content::mojom::Logger
+exposed by: content_browser
+```
+
+This means something in the renderer process (called "content_renderer") was
+trying to bind to `content::mojom::Logger` in the browser process (called
+"content_browser"). To add a capability for this, we need to find the json file
+with the capabilities for "content_browser", and add our new interface with name
+`content::mojom::Logger` to the "renderer" section.
+
+In this example, the capabilities for "content_browser" are implemented in
+[content_browser_manifest.json](/content/public/app/mojo/content_browser_manifest.json).
+It should look like:
+
+```json
+{
+  "name": "content_browser",
+  "display_name": "Content (browser process)",
+  "interface_provider_specs": {
+    "service_manager:connector": {
+      "provides": {
+        // ...
+        "renderer": [
+          //...
+```
+
+To add permission for `content::mojom::Logger`, add the string
+`"content::mojom::Logger"` to the "renderer" list.
+
+Similarly, if the error was:
+
+```sh
+[ERROR:service_manager.cc(158)] Connection InterfaceProviderSpec prevented
+service: content_browser from binding interface: content::mojom::Logger exposed
+by: content_renderer
+```
+
+We would want the
+`interface_provider_specs.service_manager:connector.provides.browser` section in
+[content_renderer_manifest.json](/content/public/app/mojo/content_renderer_manifest.json)
+(which defines the capabilities for `content_renderer`).
+
+TODO: Add more details on permission manifests here
+
 ## Using Channel-associated Interfaces
 
 **NOTE**: Channel-associated interfaces are an interim solution to make the
diff --git a/media/audio/BUILD.gn b/media/audio/BUILD.gn
index b56339f..8824839 100644
--- a/media/audio/BUILD.gn
+++ b/media/audio/BUILD.gn
@@ -376,6 +376,7 @@
     "audio_output_controller_unittest.cc",
     "audio_output_device_unittest.cc",
     "audio_output_proxy_unittest.cc",
+    "audio_output_unittest.cc",
     "audio_power_monitor_unittest.cc",
     "audio_system_impl_unittest.cc",
     "power_observer_helper_unittest.cc",
diff --git a/media/audio/alsa/alsa_output.cc b/media/audio/alsa/alsa_output.cc
index 2edd276d..830d25b 100644
--- a/media/audio/alsa/alsa_output.cc
+++ b/media/audio/alsa/alsa_output.cc
@@ -168,7 +168,7 @@
       volume_(1.0f),
       source_callback_(NULL),
       audio_bus_(AudioBus::Create(params)),
-      tick_clock_(new base::DefaultTickClock()),
+      tick_clock_(base::DefaultTickClock::GetInstance()),
       weak_factory_(this) {
   DCHECK(manager_->GetTaskRunner()->BelongsToCurrentThread());
   DCHECK_EQ(audio_bus_->frames() * bytes_per_frame_, packet_size_);
@@ -351,10 +351,9 @@
   *volume = volume_;
 }
 
-void AlsaPcmOutputStream::SetTickClockForTesting(
-    std::unique_ptr<base::TickClock> tick_clock) {
+void AlsaPcmOutputStream::SetTickClockForTesting(base::TickClock* tick_clock) {
   DCHECK(tick_clock);
-  tick_clock_ = std::move(tick_clock);
+  tick_clock_ = tick_clock;
 }
 
 void AlsaPcmOutputStream::BufferPacket(bool* source_exhausted) {
diff --git a/media/audio/alsa/alsa_output.h b/media/audio/alsa/alsa_output.h
index f6f046a..7c2cd1b 100644
--- a/media/audio/alsa/alsa_output.h
+++ b/media/audio/alsa/alsa_output.h
@@ -84,7 +84,7 @@
   void SetVolume(double volume) override;
   void GetVolume(double* volume) override;
 
-  void SetTickClockForTesting(std::unique_ptr<base::TickClock> tick_clock);
+  void SetTickClockForTesting(base::TickClock* tick_clock);
 
  private:
   friend class AlsaPcmOutputStreamTest;
@@ -211,7 +211,7 @@
   std::unique_ptr<ChannelMixer> channel_mixer_;
   std::unique_ptr<AudioBus> mixed_audio_bus_;
 
-  std::unique_ptr<base::TickClock> tick_clock_;
+  base::TickClock* tick_clock_;
 
   SEQUENCE_CHECKER(sequence_checker_);
 
diff --git a/media/audio/alsa/alsa_output_unittest.cc b/media/audio/alsa/alsa_output_unittest.cc
index 70ebd8a..10c9e03 100644
--- a/media/audio/alsa/alsa_output_unittest.cc
+++ b/media/audio/alsa/alsa_output_unittest.cc
@@ -413,9 +413,9 @@
   // Open the stream.
   AlsaPcmOutputStream* test_stream = CreateStream(kTestChannelLayout);
   ASSERT_TRUE(test_stream->Open());
-  base::SimpleTestTickClock* const tick_clock = new base::SimpleTestTickClock();
-  tick_clock->SetNowTicks(base::TimeTicks::Now());
-  test_stream->SetTickClockForTesting(base::WrapUnique(tick_clock));
+  base::SimpleTestTickClock tick_clock;
+  tick_clock.SetNowTicks(base::TimeTicks::Now());
+  test_stream->SetTickClockForTesting(&tick_clock);
 
   // Expect Device setup.
   EXPECT_CALL(mock_alsa_wrapper_, PcmDrop(kFakeHandle))
@@ -430,7 +430,7 @@
   EXPECT_CALL(mock_alsa_wrapper_, PcmDelay(kFakeHandle, _))
       .WillRepeatedly(DoAll(SetArgPointee<1>(0), Return(0)));
   EXPECT_CALL(mock_callback,
-              OnMoreData(base::TimeDelta(), tick_clock->NowTicks(), 0, _))
+              OnMoreData(base::TimeDelta(), tick_clock.NowTicks(), 0, _))
       .WillRepeatedly(DoAll(ClearBuffer(), Return(kTestFramesPerPacket)));
   EXPECT_CALL(mock_alsa_wrapper_, PcmWritei(kFakeHandle, _, _))
       .WillRepeatedly(Return(kTestFramesPerPacket));
@@ -577,9 +577,9 @@
 
 TEST_F(AlsaPcmOutputStreamTest, BufferPacket) {
   AlsaPcmOutputStream* test_stream = CreateStream(kTestChannelLayout);
-  base::SimpleTestTickClock* const tick_clock = new base::SimpleTestTickClock();
-  tick_clock->SetNowTicks(base::TimeTicks::Now());
-  test_stream->SetTickClockForTesting(base::WrapUnique(tick_clock));
+  base::SimpleTestTickClock tick_clock;
+  tick_clock.SetNowTicks(base::TimeTicks::Now());
+  test_stream->SetTickClockForTesting(&tick_clock);
   InitBuffer(test_stream);
   test_stream->buffer_->Clear();
 
@@ -593,7 +593,7 @@
 
   // Return a partially filled packet.
   EXPECT_CALL(mock_callback,
-              OnMoreData(base::TimeDelta(), tick_clock->NowTicks(), 0, _))
+              OnMoreData(base::TimeDelta(), tick_clock.NowTicks(), 0, _))
       .WillOnce(DoAll(ClearBuffer(), Return(kTestFramesPerPacket / 2)));
 
   bool source_exhausted;
@@ -608,9 +608,9 @@
 
 TEST_F(AlsaPcmOutputStreamTest, BufferPacket_Negative) {
   AlsaPcmOutputStream* test_stream = CreateStream(kTestChannelLayout);
-  base::SimpleTestTickClock* const tick_clock = new base::SimpleTestTickClock();
-  tick_clock->SetNowTicks(base::TimeTicks::Now());
-  test_stream->SetTickClockForTesting(base::WrapUnique(tick_clock));
+  base::SimpleTestTickClock tick_clock;
+  tick_clock.SetNowTicks(base::TimeTicks::Now());
+  test_stream->SetTickClockForTesting(&tick_clock);
   InitBuffer(test_stream);
   test_stream->buffer_->Clear();
 
@@ -623,7 +623,7 @@
   EXPECT_CALL(mock_alsa_wrapper_, PcmAvailUpdate(_))
       .WillRepeatedly(Return(0));  // Buffer is full.
   EXPECT_CALL(mock_callback,
-              OnMoreData(base::TimeDelta(), tick_clock->NowTicks(), 0, _))
+              OnMoreData(base::TimeDelta(), tick_clock.NowTicks(), 0, _))
       .WillOnce(DoAll(ClearBuffer(), Return(kTestFramesPerPacket / 2)));
 
   bool source_exhausted;
@@ -638,9 +638,9 @@
 
 TEST_F(AlsaPcmOutputStreamTest, BufferPacket_Underrun) {
   AlsaPcmOutputStream* test_stream = CreateStream(kTestChannelLayout);
-  base::SimpleTestTickClock* const tick_clock = new base::SimpleTestTickClock();
-  tick_clock->SetNowTicks(base::TimeTicks::Now());
-  test_stream->SetTickClockForTesting(base::WrapUnique(tick_clock));
+  base::SimpleTestTickClock tick_clock;
+  tick_clock.SetNowTicks(base::TimeTicks::Now());
+  test_stream->SetTickClockForTesting(&tick_clock);
   InitBuffer(test_stream);
   test_stream->buffer_->Clear();
 
@@ -651,7 +651,7 @@
   EXPECT_CALL(mock_alsa_wrapper_, PcmAvailUpdate(_))
       .WillRepeatedly(Return(0));  // Buffer is full.
   EXPECT_CALL(mock_callback,
-              OnMoreData(base::TimeDelta(), tick_clock->NowTicks(), 0, _))
+              OnMoreData(base::TimeDelta(), tick_clock.NowTicks(), 0, _))
       .WillOnce(DoAll(ClearBuffer(), Return(kTestFramesPerPacket / 2)));
 
   bool source_exhausted;
diff --git a/media/audio/audio_output_unittest.cc b/media/audio/audio_output_unittest.cc
new file mode 100644
index 0000000..11c38a9
--- /dev/null
+++ b/media/audio/audio_output_unittest.cc
@@ -0,0 +1,122 @@
+// 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 <stdint.h>
+
+#include <memory>
+
+#include "base/memory/aligned_memory.h"
+#include "base/message_loop/message_loop.h"
+#include "base/run_loop.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "base/time/time.h"
+#include "media/audio/audio_device_info_accessor_for_tests.h"
+#include "media/audio/audio_io.h"
+#include "media/audio/audio_manager.h"
+#include "media/audio/audio_unittest_util.h"
+#include "media/audio/simple_sources.h"
+#include "media/audio/test_audio_thread.h"
+#include "media/base/limits.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace media {
+
+class AudioOutputTest : public ::testing::Test {
+ public:
+  AudioOutputTest() {
+    audio_manager_ =
+        AudioManager::CreateForTesting(base::MakeUnique<TestAudioThread>());
+    audio_manager_device_info_ =
+        base::MakeUnique<AudioDeviceInfoAccessorForTests>(audio_manager_.get());
+    base::RunLoop().RunUntilIdle();
+  }
+  ~AudioOutputTest() override {
+    if (stream_)
+      stream_->Close();
+    audio_manager_->Shutdown();
+  }
+
+  void CreateWithDefaultParameters() {
+    stream_params_ =
+        audio_manager_device_info_->GetDefaultOutputStreamParameters();
+    stream_ = audio_manager_->MakeAudioOutputStream(
+        stream_params_, std::string(), AudioManager::LogCallback());
+  }
+
+  // Runs message loop for the specified amount of time.
+  void RunMessageLoop(base::TimeDelta delay) {
+    base::RunLoop run_loop;
+    base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+        FROM_HERE, run_loop.QuitClosure(), delay);
+    run_loop.Run();
+  }
+
+ protected:
+  base::MessageLoop message_loop_;
+  std::unique_ptr<AudioManager> audio_manager_;
+  std::unique_ptr<AudioDeviceInfoAccessorForTests> audio_manager_device_info_;
+  AudioParameters stream_params_;
+  AudioOutputStream* stream_ = nullptr;
+};
+
+// Test that can it be created and closed.
+TEST_F(AudioOutputTest, GetAndClose) {
+  ABORT_AUDIO_TEST_IF_NOT(audio_manager_device_info_->HasAudioOutputDevices());
+  CreateWithDefaultParameters();
+  ASSERT_TRUE(stream_);
+}
+
+// Test that it can be opened and closed.
+TEST_F(AudioOutputTest, OpenAndClose) {
+  ABORT_AUDIO_TEST_IF_NOT(audio_manager_device_info_->HasAudioOutputDevices());
+
+  CreateWithDefaultParameters();
+  ASSERT_TRUE(stream_);
+  EXPECT_TRUE(stream_->Open());
+}
+
+// This test produces actual audio for .25 seconds on the default device.
+TEST_F(AudioOutputTest, Play200HzTone) {
+  ABORT_AUDIO_TEST_IF_NOT(audio_manager_device_info_->HasAudioOutputDevices());
+
+  stream_params_ =
+      audio_manager_device_info_->GetDefaultOutputStreamParameters();
+  stream_ = audio_manager_->MakeAudioOutputStream(stream_params_, std::string(),
+                                                  AudioManager::LogCallback());
+  ASSERT_TRUE(stream_);
+
+  SineWaveAudioSource source(1, 200.0, stream_params_.sample_rate());
+
+  EXPECT_TRUE(stream_->Open());
+  stream_->SetVolume(1.0);
+  stream_->Start(&source);
+  RunMessageLoop(base::TimeDelta::FromMilliseconds(250));
+  stream_->Stop();
+
+  EXPECT_FALSE(source.errors());
+  EXPECT_GE(source.callbacks(), 1);
+}
+
+// Test that SetVolume() and GetVolume() work as expected.
+TEST_F(AudioOutputTest, VolumeControl) {
+  ABORT_AUDIO_TEST_IF_NOT(audio_manager_device_info_->HasAudioOutputDevices());
+
+  CreateWithDefaultParameters();
+  ASSERT_TRUE(stream_);
+  EXPECT_TRUE(stream_->Open());
+
+  double volume = 0.0;
+
+  stream_->GetVolume(&volume);
+  EXPECT_EQ(volume, 1.0);
+
+  stream_->SetVolume(0.5);
+
+  stream_->GetVolume(&volume);
+  EXPECT_LT(volume, 0.51);
+  EXPECT_GT(volume, 0.49);
+  stream_->Stop();
+}
+
+}  // namespace media
diff --git a/media/audio/mac/audio_auhal_mac.cc b/media/audio/mac/audio_auhal_mac.cc
index a26c49b..4cff091 100644
--- a/media/audio/mac/audio_auhal_mac.cc
+++ b/media/audio/mac/audio_auhal_mac.cc
@@ -175,7 +175,6 @@
   DCHECK(manager_);
   DCHECK(params_.IsValid());
   DCHECK_NE(device, kAudioObjectUnknown);
-  CHECK(!log_callback_.Equals(AudioManager::LogCallback()));
 }
 
 AUHALStream::~AUHALStream() {
@@ -409,10 +408,13 @@
                               1, 999999, 100);
 
   auto lost_frames_ms = (total_lost_frames_ * 1000) / params_.sample_rate();
+
   std::string log_message = base::StringPrintf(
       "AU out: Total glitches=%d. Total frames lost=%d (%d ms).",
       glitches_detected_, total_lost_frames_, lost_frames_ms);
-  log_callback_.Run(log_message);
+
+  if (!log_callback_.is_null())
+    log_callback_.Run(log_message);
 
   if (glitches_detected_ != 0) {
     UMA_HISTOGRAM_COUNTS("Media.Audio.Render.LostFramesInMs", lost_frames_ms);
diff --git a/media/audio/pulse/pulse_output.cc b/media/audio/pulse/pulse_output.cc
index baa19ad..a6ff39c 100644
--- a/media/audio/pulse/pulse_output.cc
+++ b/media/audio/pulse/pulse_output.cc
@@ -130,58 +130,66 @@
 void PulseAudioOutputStream::FulfillWriteRequest(size_t requested_bytes) {
   int bytes_remaining = requested_bytes;
   while (bytes_remaining > 0) {
-    void* buffer = NULL;
-    size_t bytes_to_fill = params_.GetBytesPerBuffer();
-    CHECK_GE(pa_stream_begin_write(pa_stream_, &buffer, &bytes_to_fill), 0);
-    CHECK_EQ(bytes_to_fill, static_cast<size_t>(params_.GetBytesPerBuffer()));
+    void* pa_buffer = nullptr;
+    size_t pa_buffer_size = params_.GetBytesPerBuffer();
+    CHECK_GE(pa_stream_begin_write(pa_stream_, &pa_buffer, &pa_buffer_size), 0);
 
-    // NOTE: |bytes_to_fill| may be larger than |requested_bytes| now, this is
-    // okay since pa_stream_begin_write() is the authoritative source on how
-    // much can be written.
-
-    int frames_filled = 0;
-    if (source_callback_) {
-      const base::TimeDelta delay = pulse::GetHardwareLatency(pa_stream_);
-      frames_filled = source_callback_->OnMoreData(
-          delay, base::TimeTicks::Now(), 0, audio_bus_.get());
-
-      // Zero any unfilled data so it plays back as silence.
-      if (frames_filled < audio_bus_->frames()) {
-        audio_bus_->ZeroFramesPartial(
-            frames_filled, audio_bus_->frames() - frames_filled);
-      }
-
-      audio_bus_->Scale(volume_);
-      audio_bus_->ToInterleaved<Float32SampleTypeTraits>(
-          audio_bus_->frames(), reinterpret_cast<float*>(buffer));
-    } else {
-      memset(buffer, 0, bytes_to_fill);
+    if (!source_callback_) {
+      memset(pa_buffer, 0, pa_buffer_size);
+      pa_stream_write(pa_stream_, pa_buffer, pa_buffer_size, NULL, 0LL,
+                      PA_SEEK_RELATIVE);
+      bytes_remaining -= pa_buffer_size;
+      continue;
     }
 
-    if (pa_stream_write(pa_stream_, buffer, bytes_to_fill, NULL, 0LL,
-                        PA_SEEK_RELATIVE) < 0) {
-      if (source_callback_) {
+    size_t unwritten_frames_in_bus = audio_bus_->frames();
+    size_t frames_filled = source_callback_->OnMoreData(
+        pulse::GetHardwareLatency(pa_stream_), base::TimeTicks::Now(), 0,
+        audio_bus_.get());
+
+    // Zero any unfilled data so it plays back as silence.
+    if (frames_filled < unwritten_frames_in_bus) {
+      audio_bus_->ZeroFramesPartial(frames_filled,
+                                    unwritten_frames_in_bus - frames_filled);
+    }
+
+    audio_bus_->Scale(volume_);
+
+    size_t frame_size = params_.GetBytesPerBuffer() / unwritten_frames_in_bus;
+    size_t frames_to_copy = pa_buffer_size / frame_size;
+    size_t frame_offset_in_bus = 0;
+    do {
+      // Grab frames and get the count.
+      frames_to_copy =
+          std::min(audio_bus_->frames() - frame_offset_in_bus, frames_to_copy);
+
+      audio_bus_->ToInterleavedPartial<Float32SampleTypeTraits>(
+          frame_offset_in_bus, frames_to_copy,
+          reinterpret_cast<float*>(pa_buffer));
+      frame_offset_in_bus += frames_to_copy;
+      unwritten_frames_in_bus -= frames_to_copy;
+
+      if (pa_stream_write(pa_stream_, pa_buffer, pa_buffer_size, NULL, 0LL,
+                          PA_SEEK_RELATIVE) < 0) {
         source_callback_->OnError();
+        return;
       }
-    }
-
-    // NOTE: As mentioned above, |bytes_remaining| may be negative after this.
-    bytes_remaining -= bytes_to_fill;
-
-    // Despite telling Pulse to only request certain buffer sizes, it will not
-    // always obey.  In these cases we need to avoid back to back reads from
-    // the renderer as it won't have time to complete the request.
-    //
-    // We can't defer the callback as Pulse will never call us again until we've
-    // satisfied writing the requested number of bytes.
-    //
-    // TODO(dalecurtis): It might be worth choosing the sleep duration based on
-    // the hardware latency return above.  Watch http://crbug.com/366433 to see
-    // if a more complicated wait process is necessary.  We may also need to see
-    // if a PostDelayedTask should be used here to avoid blocking the PulseAudio
-    // command thread.
-    if (source_callback_ && bytes_remaining > 0)
-      base::PlatformThread::Sleep(params_.GetBufferDuration() / 4);
+      bytes_remaining -= pa_buffer_size;
+      if (unwritten_frames_in_bus) {
+        // Reset the buffer and the size:
+        //   - If pa_buffer isn't nulled out, then it will get re-used, and
+        //     there will be a race between PA reading and us writing.
+        //   - If we don't shrink the pa_buffer_size to a small value, we get
+        //     stuttering as the memory allocation can take far too long. This
+        //     also means that we will never get more than we want, and we
+        //     dont need to memset.
+        pa_buffer = nullptr;
+        pa_buffer_size = unwritten_frames_in_bus * frame_size;
+        CHECK_GE(pa_stream_begin_write(pa_stream_, &pa_buffer, &pa_buffer_size),
+                 0);
+        frames_to_copy = pa_buffer_size / frame_size;
+      }
+    } while (unwritten_frames_in_bus);
   }
 }
 
diff --git a/media/base/audio_parameters.h b/media/base/audio_parameters.h
index e7f908e..6d7fb6e9 100644
--- a/media/base/audio_parameters.h
+++ b/media/base/audio_parameters.h
@@ -34,19 +34,22 @@
 #define PARAMETERS_ALIGNMENT 16
 static_assert(AudioBus::kChannelAlignment == PARAMETERS_ALIGNMENT,
               "Audio buffer parameters struct alignment not same as AudioBus");
+// ****WARNING****: Do not change the field types or ordering of these fields
+// without checking that alignment is correct. The structs may be concurrently
+// accessed by both 32bit and 64bit process in shmem. http://crbug.com/781095.
 struct MEDIA_SHMEM_EXPORT ALIGNAS(PARAMETERS_ALIGNMENT)
     AudioInputBufferParameters {
   double volume;
-  uint32_t size;
   int64_t capture_time;  // base::TimeTicks in microseconds.
+  uint32_t size;
   uint32_t id;
   bool key_pressed;
 };
 struct MEDIA_SHMEM_EXPORT ALIGNAS(PARAMETERS_ALIGNMENT)
     AudioOutputBufferParameters {
-  uint32_t frames_skipped;
   int64_t delay;            // base::TimeDelta in microseconds.
   int64_t delay_timestamp;  // base::TimeTicks in microseconds.
+  uint32_t frames_skipped;
   uint32_t bitstream_data_size;
   uint32_t bitstream_frames;
 };
diff --git a/media/base/null_video_sink.cc b/media/base/null_video_sink.cc
index 7a5c54d..f5ae913 100644
--- a/media/base/null_video_sink.cc
+++ b/media/base/null_video_sink.cc
@@ -22,9 +22,8 @@
       task_runner_(task_runner),
       started_(false),
       callback_(nullptr),
-      tick_clock_(&default_tick_clock_),
-      background_render_(false) {
-}
+      tick_clock_(base::DefaultTickClock::GetInstance()),
+      background_render_(false) {}
 
 NullVideoSink::~NullVideoSink() {
   DCHECK(!started_);
diff --git a/media/base/null_video_sink.h b/media/base/null_video_sink.h
index d5b8abe..763602b 100644
--- a/media/base/null_video_sink.h
+++ b/media/base/null_video_sink.h
@@ -78,10 +78,9 @@
   base::TimeTicks current_render_time_;
 
   // Allow for an injectable tick clock for testing.
-  base::DefaultTickClock default_tick_clock_;
   base::TimeTicks last_now_;
 
-  // If specified, used instead of |default_tick_clock_|.
+  // If specified, used instead of a DefaultTickClock.
   base::TickClock* tick_clock_;
 
   // If set, called when Stop() is called.
diff --git a/media/base/video_frame_pool.cc b/media/base/video_frame_pool.cc
index b9ca34d8..ccc63cf 100644
--- a/media/base/video_frame_pool.cc
+++ b/media/base/video_frame_pool.cc
@@ -58,14 +58,14 @@
 
   base::circular_deque<FrameEntry> frames_;
 
-  // |tick_clock_| is always &|default_tick_clock_| outside of testing.
-  base::DefaultTickClock default_tick_clock_;
+  // |tick_clock_| is always a DefaultTickClock outside of testing.
   base::TickClock* tick_clock_;
 
   DISALLOW_COPY_AND_ASSIGN(PoolImpl);
 };
 
-VideoFramePool::PoolImpl::PoolImpl() : tick_clock_(&default_tick_clock_) {}
+VideoFramePool::PoolImpl::PoolImpl()
+    : tick_clock_(base::DefaultTickClock::GetInstance()) {}
 
 VideoFramePool::PoolImpl::~PoolImpl() {
   DCHECK(is_shutdown_);
diff --git a/media/base/wall_clock_time_source.cc b/media/base/wall_clock_time_source.cc
index 40d1fb8..9ce5b4d 100644
--- a/media/base/wall_clock_time_source.cc
+++ b/media/base/wall_clock_time_source.cc
@@ -9,8 +9,9 @@
 namespace media {
 
 WallClockTimeSource::WallClockTimeSource()
-    : tick_clock_(&default_tick_clock_), ticking_(false), playback_rate_(1.0) {
-}
+    : tick_clock_(base::DefaultTickClock::GetInstance()),
+      ticking_(false),
+      playback_rate_(1.0) {}
 
 WallClockTimeSource::~WallClockTimeSource() = default;
 
diff --git a/media/base/wall_clock_time_source.h b/media/base/wall_clock_time_source.h
index 1f79ab76..b32da4f 100644
--- a/media/base/wall_clock_time_source.h
+++ b/media/base/wall_clock_time_source.h
@@ -37,9 +37,6 @@
   base::TimeDelta CurrentMediaTime_Locked();
 
   // Allow for an injectable tick clock for testing.
-  base::DefaultTickClock default_tick_clock_;
-
-  // If specified, used instead of |default_tick_clock_|.
   base::TickClock* tick_clock_;
 
   bool ticking_;
diff --git a/media/base/watch_time_keys.cc b/media/base/watch_time_keys.cc
index 3df9f86e..38b3d49 100644
--- a/media/base/watch_time_keys.cc
+++ b/media/base/watch_time_keys.cc
@@ -6,56 +6,108 @@
 
 namespace media {
 
+// TODO(dalecurtis): Key strings aren't really necessary anymore, so instead
+// of hard coding these, switch to generating them.
+
 // Audio+video watch time metrics.
-const char kWatchTimeAudioVideoAll[] = "Media.WatchTime.AudioVideo.All";
-const char kWatchTimeAudioVideoMse[] = "Media.WatchTime.AudioVideo.MSE";
-const char kWatchTimeAudioVideoEme[] = "Media.WatchTime.AudioVideo.EME";
-const char kWatchTimeAudioVideoSrc[] = "Media.WatchTime.AudioVideo.SRC";
-const char kWatchTimeAudioVideoBattery[] = "Media.WatchTime.AudioVideo.Battery";
-const char kWatchTimeAudioVideoAc[] = "Media.WatchTime.AudioVideo.AC";
-const char kWatchTimeAudioVideoDisplayFullscreen[] =
+static const char kWatchTimeAudioVideoAll[] = "Media.WatchTime.AudioVideo.All";
+static const char kWatchTimeAudioVideoMse[] = "Media.WatchTime.AudioVideo.MSE";
+static const char kWatchTimeAudioVideoEme[] = "Media.WatchTime.AudioVideo.EME";
+static const char kWatchTimeAudioVideoSrc[] = "Media.WatchTime.AudioVideo.SRC";
+static const char kWatchTimeAudioVideoBattery[] =
+    "Media.WatchTime.AudioVideo.Battery";
+static const char kWatchTimeAudioVideoAc[] = "Media.WatchTime.AudioVideo.AC";
+static const char kWatchTimeAudioVideoDisplayFullscreen[] =
     "Media.WatchTime.AudioVideo.DisplayFullscreen";
-const char kWatchTimeAudioVideoDisplayInline[] =
+static const char kWatchTimeAudioVideoDisplayInline[] =
     "Media.WatchTime.AudioVideo.DisplayInline";
-const char kWatchTimeAudioVideoDisplayPictureInPicture[] =
+static const char kWatchTimeAudioVideoDisplayPictureInPicture[] =
     "Media.WatchTime.AudioVideo.DisplayPictureInPicture";
-const char kWatchTimeAudioVideoEmbeddedExperience[] =
+static const char kWatchTimeAudioVideoEmbeddedExperience[] =
     "Media.WatchTime.AudioVideo.EmbeddedExperience";
-const char kWatchTimeAudioVideoNativeControlsOn[] =
+static const char kWatchTimeAudioVideoNativeControlsOn[] =
     "Media.WatchTime.AudioVideo.NativeControlsOn";
-const char kWatchTimeAudioVideoNativeControlsOff[] =
+static const char kWatchTimeAudioVideoNativeControlsOff[] =
     "Media.WatchTime.AudioVideo.NativeControlsOff";
 
 // Audio only "watch time" metrics.
-const char kWatchTimeAudioAll[] = "Media.WatchTime.Audio.All";
-const char kWatchTimeAudioMse[] = "Media.WatchTime.Audio.MSE";
-const char kWatchTimeAudioEme[] = "Media.WatchTime.Audio.EME";
-const char kWatchTimeAudioSrc[] = "Media.WatchTime.Audio.SRC";
-const char kWatchTimeAudioBattery[] = "Media.WatchTime.Audio.Battery";
-const char kWatchTimeAudioAc[] = "Media.WatchTime.Audio.AC";
-const char kWatchTimeAudioEmbeddedExperience[] =
+static const char kWatchTimeAudioAll[] = "Media.WatchTime.Audio.All";
+static const char kWatchTimeAudioMse[] = "Media.WatchTime.Audio.MSE";
+static const char kWatchTimeAudioEme[] = "Media.WatchTime.Audio.EME";
+static const char kWatchTimeAudioSrc[] = "Media.WatchTime.Audio.SRC";
+static const char kWatchTimeAudioBattery[] = "Media.WatchTime.Audio.Battery";
+static const char kWatchTimeAudioAc[] = "Media.WatchTime.Audio.AC";
+static const char kWatchTimeAudioEmbeddedExperience[] =
     "Media.WatchTime.Audio.EmbeddedExperience";
-const char kWatchTimeAudioNativeControlsOn[] =
+static const char kWatchTimeAudioNativeControlsOn[] =
     "Media.WatchTime.Audio.NativeControlsOn";
-const char kWatchTimeAudioNativeControlsOff[] =
+static const char kWatchTimeAudioNativeControlsOff[] =
     "Media.WatchTime.Audio.NativeControlsOff";
 
+static const char kWatchTimeAudioBackgroundAll[] =
+    "Media.WatchTime.Audio.Background.All";
+static const char kWatchTimeAudioBackgroundMse[] =
+    "Media.WatchTime.Audio.Background.MSE";
+static const char kWatchTimeAudioBackgroundEme[] =
+    "Media.WatchTime.Audio.Background.EME";
+static const char kWatchTimeAudioBackgroundSrc[] =
+    "Media.WatchTime.Audio.Background.SRC";
+static const char kWatchTimeAudioBackgroundBattery[] =
+    "Media.WatchTime.Audio.Background.Battery";
+static const char kWatchTimeAudioBackgroundAc[] =
+    "Media.WatchTime.Audio.Background.AC";
+static const char kWatchTimeAudioBackgroundEmbeddedExperience[] =
+    "Media.WatchTime.Audio.Background.EmbeddedExperience";
+
 // Audio+video background watch time metrics.
-const char kWatchTimeAudioVideoBackgroundAll[] =
+static const char kWatchTimeAudioVideoBackgroundAll[] =
     "Media.WatchTime.AudioVideo.Background.All";
-const char kWatchTimeAudioVideoBackgroundMse[] =
+static const char kWatchTimeAudioVideoBackgroundMse[] =
     "Media.WatchTime.AudioVideo.Background.MSE";
-const char kWatchTimeAudioVideoBackgroundEme[] =
+static const char kWatchTimeAudioVideoBackgroundEme[] =
     "Media.WatchTime.AudioVideo.Background.EME";
-const char kWatchTimeAudioVideoBackgroundSrc[] =
+static const char kWatchTimeAudioVideoBackgroundSrc[] =
     "Media.WatchTime.AudioVideo.Background.SRC";
-const char kWatchTimeAudioVideoBackgroundBattery[] =
+static const char kWatchTimeAudioVideoBackgroundBattery[] =
     "Media.WatchTime.AudioVideo.Background.Battery";
-const char kWatchTimeAudioVideoBackgroundAc[] =
+static const char kWatchTimeAudioVideoBackgroundAc[] =
     "Media.WatchTime.AudioVideo.Background.AC";
-const char kWatchTimeAudioVideoBackgroundEmbeddedExperience[] =
+static const char kWatchTimeAudioVideoBackgroundEmbeddedExperience[] =
     "Media.WatchTime.AudioVideo.Background.EmbeddedExperience";
 
+static const char kWatchTimeVideoAll[] = "Media.WatchTime.Video.All";
+static const char kWatchTimeVideoMse[] = "Media.WatchTime.Video.MSE";
+static const char kWatchTimeVideoEme[] = "Media.WatchTime.Video.EME";
+static const char kWatchTimeVideoSrc[] = "Media.WatchTime.Video.SRC";
+static const char kWatchTimeVideoBattery[] = "Media.WatchTime.Video.Battery";
+static const char kWatchTimeVideoAc[] = "Media.WatchTime.Video.AC";
+static const char kWatchTimeVideoDisplayFullscreen[] =
+    "Media.WatchTime.Video.DisplayFullscreen";
+static const char kWatchTimeVideoDisplayInline[] =
+    "Media.WatchTime.Video.DisplayInline";
+static const char kWatchTimeVideoDisplayPictureInPicture[] =
+    "Media.WatchTime.Video.DisplayPictureInPicture";
+static const char kWatchTimeVideoEmbeddedExperience[] =
+    "Media.WatchTime.Video.EmbeddedExperience";
+static const char kWatchTimeVideoNativeControlsOn[] =
+    "Media.WatchTime.Video.NativeControlsOn";
+static const char kWatchTimeVideoNativeControlsOff[] =
+    "Media.WatchTime.Video.NativeControlsOff";
+static const char kWatchTimeVideoBackgroundAll[] =
+    "Media.WatchTime.Video.Background.All";
+static const char kWatchTimeVideoBackgroundMse[] =
+    "Media.WatchTime.Video.Background.MSE";
+static const char kWatchTimeVideoBackgroundEme[] =
+    "Media.WatchTime.Video.Background.EME";
+static const char kWatchTimeVideoBackgroundSrc[] =
+    "Media.WatchTime.Video.Background.SRC";
+static const char kWatchTimeVideoBackgroundBattery[] =
+    "Media.WatchTime.Video.Background.Battery";
+static const char kWatchTimeVideoBackgroundAc[] =
+    "Media.WatchTime.Video.Background.AC";
+static const char kWatchTimeVideoBackgroundEmbeddedExperience[] =
+    "Media.WatchTime.Video.Background.EmbeddedExperience";
+
 const char kWatchTimeUnderflowCount[] = "UnderflowCount";
 
 const char kMeanTimeBetweenRebuffersAudioSrc[] =
@@ -101,6 +153,20 @@
       return kWatchTimeAudioNativeControlsOn;
     case WatchTimeKey::kAudioNativeControlsOff:
       return kWatchTimeAudioNativeControlsOff;
+    case WatchTimeKey::kAudioBackgroundAll:
+      return kWatchTimeAudioBackgroundAll;
+    case WatchTimeKey::kAudioBackgroundMse:
+      return kWatchTimeAudioBackgroundMse;
+    case WatchTimeKey::kAudioBackgroundEme:
+      return kWatchTimeAudioBackgroundEme;
+    case WatchTimeKey::kAudioBackgroundSrc:
+      return kWatchTimeAudioBackgroundSrc;
+    case WatchTimeKey::kAudioBackgroundBattery:
+      return kWatchTimeAudioBackgroundBattery;
+    case WatchTimeKey::kAudioBackgroundAc:
+      return kWatchTimeAudioBackgroundAc;
+    case WatchTimeKey::kAudioBackgroundEmbeddedExperience:
+      return kWatchTimeAudioBackgroundEmbeddedExperience;
     case WatchTimeKey::kAudioVideoAll:
       return kWatchTimeAudioVideoAll;
     case WatchTimeKey::kAudioVideoMse:
@@ -139,6 +205,44 @@
       return kWatchTimeAudioVideoBackgroundAc;
     case WatchTimeKey::kAudioVideoBackgroundEmbeddedExperience:
       return kWatchTimeAudioVideoBackgroundEmbeddedExperience;
+    case WatchTimeKey::kVideoAll:
+      return kWatchTimeVideoAll;
+    case WatchTimeKey::kVideoMse:
+      return kWatchTimeVideoMse;
+    case WatchTimeKey::kVideoEme:
+      return kWatchTimeVideoEme;
+    case WatchTimeKey::kVideoSrc:
+      return kWatchTimeVideoSrc;
+    case WatchTimeKey::kVideoBattery:
+      return kWatchTimeVideoBattery;
+    case WatchTimeKey::kVideoAc:
+      return kWatchTimeVideoAc;
+    case WatchTimeKey::kVideoDisplayFullscreen:
+      return kWatchTimeVideoDisplayFullscreen;
+    case WatchTimeKey::kVideoDisplayInline:
+      return kWatchTimeVideoDisplayInline;
+    case WatchTimeKey::kVideoDisplayPictureInPicture:
+      return kWatchTimeVideoDisplayPictureInPicture;
+    case WatchTimeKey::kVideoEmbeddedExperience:
+      return kWatchTimeVideoEmbeddedExperience;
+    case WatchTimeKey::kVideoNativeControlsOn:
+      return kWatchTimeVideoNativeControlsOn;
+    case WatchTimeKey::kVideoNativeControlsOff:
+      return kWatchTimeVideoNativeControlsOff;
+    case WatchTimeKey::kVideoBackgroundAll:
+      return kWatchTimeVideoBackgroundAll;
+    case WatchTimeKey::kVideoBackgroundMse:
+      return kWatchTimeVideoBackgroundMse;
+    case WatchTimeKey::kVideoBackgroundEme:
+      return kWatchTimeVideoBackgroundEme;
+    case WatchTimeKey::kVideoBackgroundSrc:
+      return kWatchTimeVideoBackgroundSrc;
+    case WatchTimeKey::kVideoBackgroundBattery:
+      return kWatchTimeVideoBackgroundBattery;
+    case WatchTimeKey::kVideoBackgroundAc:
+      return kWatchTimeVideoBackgroundAc;
+    case WatchTimeKey::kVideoBackgroundEmbeddedExperience:
+      return kWatchTimeVideoBackgroundEmbeddedExperience;
   };
 
   NOTREACHED();
diff --git a/media/base/watch_time_keys.h b/media/base/watch_time_keys.h
index dff973c..ba37dda 100644
--- a/media/base/watch_time_keys.h
+++ b/media/base/watch_time_keys.h
@@ -21,6 +21,13 @@
   kAudioEmbeddedExperience,
   kAudioNativeControlsOn,
   kAudioNativeControlsOff,
+  kAudioBackgroundAll,
+  kAudioBackgroundMse,
+  kAudioBackgroundEme,
+  kAudioBackgroundSrc,
+  kAudioBackgroundBattery,
+  kAudioBackgroundAc,
+  kAudioBackgroundEmbeddedExperience,
   kAudioVideoAll,
   kAudioVideoMse,
   kAudioVideoEme,
@@ -40,43 +47,28 @@
   kAudioVideoBackgroundBattery,
   kAudioVideoBackgroundAc,
   kAudioVideoBackgroundEmbeddedExperience,
-  kWatchTimeKeyMax = kAudioVideoBackgroundEmbeddedExperience
+  kVideoAll,
+  kVideoMse,
+  kVideoEme,
+  kVideoSrc,
+  kVideoBattery,
+  kVideoAc,
+  kVideoDisplayFullscreen,
+  kVideoDisplayInline,
+  kVideoDisplayPictureInPicture,
+  kVideoEmbeddedExperience,
+  kVideoNativeControlsOn,
+  kVideoNativeControlsOff,
+  kVideoBackgroundAll,
+  kVideoBackgroundMse,
+  kVideoBackgroundEme,
+  kVideoBackgroundSrc,
+  kVideoBackgroundBattery,
+  kVideoBackgroundAc,
+  kVideoBackgroundEmbeddedExperience,
+  kWatchTimeKeyMax = kVideoBackgroundEmbeddedExperience
 };
 
-// Histogram names used for reporting; also double as MediaLog key names.
-// NOTE: If you add to this list you must update GetWatchTimeKeys() and if
-// necessary, GetWatchTimePowerKeys().
-MEDIA_EXPORT extern const char kWatchTimeAudioAll[];
-MEDIA_EXPORT extern const char kWatchTimeAudioMse[];
-MEDIA_EXPORT extern const char kWatchTimeAudioEme[];
-MEDIA_EXPORT extern const char kWatchTimeAudioSrc[];
-MEDIA_EXPORT extern const char kWatchTimeAudioBattery[];
-MEDIA_EXPORT extern const char kWatchTimeAudioAc[];
-MEDIA_EXPORT extern const char kWatchTimeAudioEmbeddedExperience[];
-MEDIA_EXPORT extern const char kWatchTimeAudioNativeControlsOn[];
-MEDIA_EXPORT extern const char kWatchTimeAudioNativeControlsOff[];
-MEDIA_EXPORT extern const char kWatchTimeAudioVideoAll[];
-MEDIA_EXPORT extern const char kWatchTimeAudioVideoMse[];
-MEDIA_EXPORT extern const char kWatchTimeAudioVideoEme[];
-MEDIA_EXPORT extern const char kWatchTimeAudioVideoSrc[];
-MEDIA_EXPORT extern const char kWatchTimeAudioVideoBattery[];
-MEDIA_EXPORT extern const char kWatchTimeAudioVideoAc[];
-MEDIA_EXPORT extern const char kWatchTimeAudioVideoDisplayFullscreen[];
-MEDIA_EXPORT extern const char kWatchTimeAudioVideoDisplayInline[];
-MEDIA_EXPORT extern const char kWatchTimeAudioVideoDisplayPictureInPicture[];
-MEDIA_EXPORT extern const char kWatchTimeAudioVideoEmbeddedExperience[];
-MEDIA_EXPORT extern const char kWatchTimeAudioVideoNativeControlsOn[];
-MEDIA_EXPORT extern const char kWatchTimeAudioVideoNativeControlsOff[];
-MEDIA_EXPORT extern const char kWatchTimeAudioVideoBackgroundAll[];
-MEDIA_EXPORT extern const char kWatchTimeAudioVideoBackgroundMse[];
-MEDIA_EXPORT extern const char kWatchTimeAudioVideoBackgroundEme[];
-MEDIA_EXPORT extern const char kWatchTimeAudioVideoBackgroundSrc[];
-MEDIA_EXPORT extern const char kWatchTimeAudioVideoBackgroundBattery[];
-MEDIA_EXPORT extern const char kWatchTimeAudioVideoBackgroundAc[];
-MEDIA_EXPORT extern const char
-    kWatchTimeAudioVideoBackgroundEmbeddedExperience[];
-// **** If adding any line above this see the toplevel comment! ****
-
 // Count of the number of underflow events during a media session.
 MEDIA_EXPORT extern const char kWatchTimeUnderflowCount[];
 
diff --git a/media/blink/BUILD.gn b/media/blink/BUILD.gn
index 041d988e..fb93f24 100644
--- a/media/blink/BUILD.gn
+++ b/media/blink/BUILD.gn
@@ -120,6 +120,7 @@
     "//testing/gtest",
     "//third_party/WebKit/public:blink",
     "//third_party/WebKit/public:test_support",
+    "//tools/v8_context_snapshot",
     "//ui/gfx:test_support",
     "//ui/gfx/geometry",
     "//url",
@@ -127,6 +128,7 @@
 
   configs += [
     "//build/config/compiler:no_size_t_to_int_warning",
+    "//tools/v8_context_snapshot:use_v8_context_snapshot",
     "//v8:external_startup_data",
   ]
 
diff --git a/media/blink/run_all_unittests.cc b/media/blink/run_all_unittests.cc
index b9838df3..c6342066 100644
--- a/media/blink/run_all_unittests.cc
+++ b/media/blink/run_all_unittests.cc
@@ -87,6 +87,9 @@
   gin::V8Initializer::LoadV8Snapshot();
   gin::V8Initializer::LoadV8Natives();
 #endif
+#ifdef USE_V8_CONTEXT_SNAPSHOT
+  gin::V8Initializer::LoadV8ContextSnapshot();
+#endif
 
 // Initialize mojo firstly to enable Blink initialization to use it.
 #if !defined(OS_IOS)
diff --git a/media/blink/video_decode_stats_reporter.cc b/media/blink/video_decode_stats_reporter.cc
index d99409b5..8c8f2f8 100644
--- a/media/blink/video_decode_stats_reporter.cc
+++ b/media/blink/video_decode_stats_reporter.cc
@@ -17,7 +17,7 @@
     mojom::VideoDecodeStatsRecorderPtr recorder_ptr,
     GetPipelineStatsCB get_pipeline_stats_cb,
     const VideoDecoderConfig& video_config,
-    std::unique_ptr<base::TickClock> tick_clock)
+    base::TickClock* tick_clock)
     : kRecordingInterval(
           base::TimeDelta::FromMilliseconds(kRecordingIntervalMs)),
       kTinyFpsWindowDuration(
@@ -26,8 +26,8 @@
       get_pipeline_stats_cb_(std::move(get_pipeline_stats_cb)),
       video_config_(video_config),
       natural_size_(GetSizeBucket(video_config.natural_size())),
-      tick_clock_(std::move(tick_clock)),
-      stats_cb_timer_(tick_clock_.get()) {
+      tick_clock_(tick_clock),
+      stats_cb_timer_(tick_clock_) {
   DCHECK(recorder_ptr_.is_bound());
   DCHECK(!get_pipeline_stats_cb_.is_null());
   DCHECK(video_config_.IsValidConfig());
diff --git a/media/blink/video_decode_stats_reporter.h b/media/blink/video_decode_stats_reporter.h
index 0184aa97..6f100fcb 100644
--- a/media/blink/video_decode_stats_reporter.h
+++ b/media/blink/video_decode_stats_reporter.h
@@ -28,11 +28,11 @@
  public:
   using GetPipelineStatsCB = base::Callback<PipelineStatistics(void)>;
 
-  VideoDecodeStatsReporter(mojom::VideoDecodeStatsRecorderPtr recorder_ptr,
-                           GetPipelineStatsCB get_pipeline_stats_cb,
-                           const VideoDecoderConfig& video_config,
-                           std::unique_ptr<base::TickClock> tick_clock =
-                               base::MakeUnique<base::DefaultTickClock>());
+  VideoDecodeStatsReporter(
+      mojom::VideoDecodeStatsRecorderPtr recorder_ptr,
+      GetPipelineStatsCB get_pipeline_stats_cb,
+      const VideoDecoderConfig& video_config,
+      base::TickClock* tick_clock = base::DefaultTickClock::GetInstance());
   ~VideoDecodeStatsReporter();
 
   void OnPlaying();
@@ -151,7 +151,7 @@
 
   // Clock for |stats_cb_timer_| and getting current tick count (NowTicks()).
   // Tests may supply a mock clock via the constructor.
-  std::unique_ptr<base::TickClock> tick_clock_;
+  base::TickClock* tick_clock_;
 
   // Timer for all stats callbacks. Timer interval will be dynamically set based
   // on state of reporter. See calls to RunStatsTimerAtIntervalMs().
diff --git a/media/blink/video_decode_stats_reporter_unittest.cc b/media/blink/video_decode_stats_reporter_unittest.cc
index 1527b79..321f7e7 100644
--- a/media/blink/video_decode_stats_reporter_unittest.cc
+++ b/media/blink/video_decode_stats_reporter_unittest.cc
@@ -91,6 +91,7 @@
   void SetUp() override {
     // Do this first. Lots of pieces depend on the task runner.
     task_runner_ = new base::TestMockTimeTaskRunner();
+    clock_ = task_runner_->GetMockTickClock();
     message_loop_.SetTaskRunner(task_runner_);
 
     // Make reporter with default configuration. Connects RecordInterceptor as
@@ -172,7 +173,7 @@
         std::move(recorder_ptr),
         base::Bind(&VideoDecodeStatsReporterTest::GetPipelineStatsCB,
                    base::Unretained(this)),
-        MakeDefaultVideoConfig(), task_runner_->GetMockTickClock());
+        MakeDefaultVideoConfig(), clock_.get());
   }
 
   // Fast forward the task runner (and associated tick clock) by |milliseconds|.
@@ -338,6 +339,10 @@
   // used by message_loop_ in Setup().
   scoped_refptr<base::TestMockTimeTaskRunner> task_runner_;
 
+  // TODO(tzik): Remove |clock_| after updating GetMockTickClock to own the
+  // instance.
+  std::unique_ptr<base::TickClock> clock_;
+
   // Points to the interceptor that acts as a VideoDecodeStatsRecorder. The
   // object is owned by VideoDecodeStatsRecorderPtr, which is itself owned by
   // |reporter_|.
diff --git a/media/blink/video_frame_compositor.cc b/media/blink/video_frame_compositor.cc
index 39afe6ad..00312c0 100644
--- a/media/blink/video_frame_compositor.cc
+++ b/media/blink/video_frame_compositor.cc
@@ -25,7 +25,7 @@
     const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
     std::unique_ptr<blink::WebVideoFrameSubmitter> submitter)
     : task_runner_(task_runner),
-      tick_clock_(new base::DefaultTickClock()),
+      tick_clock_(base::DefaultTickClock::GetInstance()),
       background_rendering_enabled_(true),
       background_rendering_timer_(
           FROM_HERE,
diff --git a/media/blink/video_frame_compositor.h b/media/blink/video_frame_compositor.h
index 58513d94..5774f71 100644
--- a/media/blink/video_frame_compositor.h
+++ b/media/blink/video_frame_compositor.h
@@ -123,8 +123,8 @@
   // Must be called on the compositor thread.
   virtual void SetOnNewProcessedFrameCallback(const OnNewProcessedFrameCB& cb);
 
-  void set_tick_clock_for_testing(std::unique_ptr<base::TickClock> tick_clock) {
-    tick_clock_ = std::move(tick_clock);
+  void set_tick_clock_for_testing(base::TickClock* tick_clock) {
+    tick_clock_ = tick_clock;
   }
 
   void clear_current_frame_for_testing() { current_frame_ = nullptr; }
@@ -178,7 +178,7 @@
   // media thread.
   scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
 
-  std::unique_ptr<base::TickClock> tick_clock_;
+  base::TickClock* tick_clock_;
 
   // Allows tests to disable the background rendering task.
   bool background_rendering_enabled_;
diff --git a/media/blink/video_frame_compositor_unittest.cc b/media/blink/video_frame_compositor_unittest.cc
index 7b083285..cfcf9db 100644
--- a/media/blink/video_frame_compositor_unittest.cc
+++ b/media/blink/video_frame_compositor_unittest.cc
@@ -43,8 +43,7 @@
                                  public ::testing::TestWithParam<bool> {
  public:
   VideoFrameCompositorTest()
-      : tick_clock_(new base::SimpleTestTickClock()),
-        client_(new StrictMock<MockWebVideoFrameSubmitter>()) {}
+      : client_(new StrictMock<MockWebVideoFrameSubmitter>()) {}
 
   void SetUp() {
     if (IsSurfaceLayerForVideoEnabled()) {
@@ -70,8 +69,7 @@
       compositor_->EnableSubmission(viz::FrameSinkId(1, 1));
     }
 
-    compositor_->set_tick_clock_for_testing(
-        std::unique_ptr<base::TickClock>(tick_clock_));
+    compositor_->set_tick_clock_for_testing(&tick_clock_);
     // Disable background rendering by default.
     compositor_->set_background_rendering_for_testing(false);
   }
@@ -123,7 +121,7 @@
   }
 
   base::MessageLoop message_loop;
-  base::SimpleTestTickClock* tick_clock_;  // Owned by |compositor_|
+  base::SimpleTestTickClock tick_clock_;
   StrictMock<MockWebVideoFrameSubmitter>* submitter_;
   std::unique_ptr<StrictMock<MockWebVideoFrameSubmitter>> client_;
   std::unique_ptr<VideoFrameCompositor> compositor_;
@@ -260,7 +258,7 @@
 
   // Since we have a client, this call should not call background render, even
   // if a lot of time has elapsed between calls.
-  tick_clock_->Advance(base::TimeDelta::FromSeconds(1));
+  tick_clock_.Advance(base::TimeDelta::FromSeconds(1));
   EXPECT_CALL(*this, Render(_, _, _)).Times(0);
   compositor()->UpdateCurrentFrameIfStale();
 
@@ -285,7 +283,7 @@
   EXPECT_EQ(opaque_frame_2, compositor()->GetCurrentFrame());
 
   // Advancing the tick clock should allow a new frame to be requested.
-  tick_clock_->Advance(base::TimeDelta::FromMilliseconds(10));
+  tick_clock_.Advance(base::TimeDelta::FromMilliseconds(10));
   EXPECT_CALL(*this, Render(_, _, true)).WillOnce(Return(opaque_frame_1));
   compositor()->UpdateCurrentFrameIfStale();
   EXPECT_EQ(opaque_frame_1, compositor()->GetCurrentFrame());
diff --git a/media/blink/watch_time_reporter.cc b/media/blink/watch_time_reporter.cc
index 66b764c..cbef99dd 100644
--- a/media/blink/watch_time_reporter.cc
+++ b/media/blink/watch_time_reporter.cc
@@ -41,6 +41,7 @@
       get_media_time_cb_(std::move(get_media_time_cb)) {
   DCHECK(!get_media_time_cb_.is_null());
   DCHECK(properties_->has_audio || properties_->has_video);
+  DCHECK_EQ(is_background, properties_->is_background);
 
   if (base::PowerMonitor* pm = base::PowerMonitor::Get())
     pm->AddObserver(this);
@@ -48,21 +49,17 @@
   provider->AcquireWatchTimeRecorder(properties_->Clone(),
                                      mojo::MakeRequest(&recorder_));
 
-  if (is_background_) {
-    DCHECK(properties_->has_audio);
-    DCHECK(properties_->has_video);
+  if (is_background_ || !ShouldReportWatchTime())
     return;
-  }
 
   // Background watch time is reported by creating an background only watch time
   // reporter which receives play when hidden and pause when shown. This avoids
   // unnecessary complexity inside the UpdateWatchTime() for handling this case.
-  if (properties_->has_video && properties_->has_audio &&
-      ShouldReportWatchTime()) {
-    background_reporter_.reset(
-        new WatchTimeReporter(properties_->Clone(), true /* is_background */,
-                              get_media_time_cb_, provider));
-  }
+  auto prop_copy = properties_.Clone();
+  prop_copy->is_background = true;
+  background_reporter_.reset(
+      new WatchTimeReporter(std::move(prop_copy), true /* is_background */,
+                            get_media_time_cb_, provider));
 }
 
 WatchTimeReporter::~WatchTimeReporter() {
@@ -127,9 +124,6 @@
   if (background_reporter_)
     background_reporter_->OnPaused();
 
-  if (!properties_->has_video)
-    return;
-
   is_visible_ = true;
   MaybeStartReportingTimer(get_media_time_cb_.Run());
 }
@@ -138,9 +132,6 @@
   if (background_reporter_ && is_playing_)
     background_reporter_->OnPlaying();
 
-  if (!properties_->has_video)
-    return;
-
   is_visible_ = false;
   MaybeFinalizeWatchTime(FinalizeTime::ON_NEXT_UPDATE);
 }
@@ -155,8 +146,8 @@
 }
 
 void WatchTimeReporter::OnUnderflow() {
-  // We don't report underflow for background players since we don't want to
-  // pollute our foreground stats. TODO(dalecurtis): Create a background metric.
+  if (background_reporter_)
+    background_reporter_->OnUnderflow();
 
   if (!reporting_timer_.IsRunning())
     return;
@@ -230,12 +221,12 @@
 }
 
 bool WatchTimeReporter::ShouldReportWatchTime() {
-  // Report listen time or watch time only for tracks that are audio-only or
-  // have both an audio and video track of sufficient size.
-  return (!properties_->has_video && properties_->has_audio) ||
-         (properties_->has_video && properties_->has_audio &&
-          properties_->natural_size.height() >= kMinimumVideoSize.height() &&
-          properties_->natural_size.width() >= kMinimumVideoSize.width());
+  // Report listen time or watch time for videos of sufficient size.
+  return properties_->has_video
+             ? (properties_->natural_size.height() >=
+                    kMinimumVideoSize.height() &&
+                properties_->natural_size.width() >= kMinimumVideoSize.width())
+             : properties_->has_audio;
 }
 
 void WatchTimeReporter::MaybeStartReportingTimer(
@@ -322,14 +313,18 @@
 
   const base::TimeDelta elapsed = current_timestamp - start_timestamp_;
 
-#define RECORD_WATCH_TIME(key, value)                                    \
-  do {                                                                   \
-    recorder_->RecordWatchTime(                                          \
-        properties_->has_video                                           \
-            ? (is_background_ ? WatchTimeKey::kAudioVideoBackground##key \
-                              : WatchTimeKey::kAudioVideo##key)          \
-            : WatchTimeKey::kAudio##key,                                 \
-        value);                                                          \
+#define RECORD_WATCH_TIME(key, value)                                     \
+  do {                                                                    \
+    recorder_->RecordWatchTime(                                           \
+        (properties_->has_video && properties_->has_audio)                \
+            ? (is_background_ ? WatchTimeKey::kAudioVideoBackground##key  \
+                              : WatchTimeKey::kAudioVideo##key)           \
+            : properties_->has_video                                      \
+                  ? (is_background_ ? WatchTimeKey::kVideoBackground##key \
+                                    : WatchTimeKey::kVideo##key)          \
+                  : (is_background_ ? WatchTimeKey::kAudioBackground##key \
+                                    : WatchTimeKey::kAudio##key),         \
+        value);                                                           \
   } while (0)
 
   // Only report watch time after some minimum amount has elapsed. Don't update
@@ -378,13 +373,15 @@
   }
 
 // Similar to RECORD_WATCH_TIME but ignores background watch time.
-#define RECORD_FOREGROUND_WATCH_TIME(key, value)                    \
-  do {                                                              \
-    DCHECK(!is_background_);                                        \
-    recorder_->RecordWatchTime(properties_->has_video               \
-                                   ? WatchTimeKey::kAudioVideo##key \
-                                   : WatchTimeKey::kAudio##key,     \
-                               value);                              \
+#define RECORD_FOREGROUND_WATCH_TIME(key, value)                  \
+  do {                                                            \
+    DCHECK(!is_background_);                                      \
+    recorder_->RecordWatchTime(                                   \
+        (properties_->has_video && properties_->has_audio)        \
+            ? WatchTimeKey::kAudioVideo##key                      \
+            : properties_->has_audio ? WatchTimeKey::kAudio##key  \
+                                     : WatchTimeKey::kVideo##key, \
+        value);                                                   \
   } while (0)
 
   // Similar to the block above for controls.
@@ -406,11 +403,14 @@
   }
 
 // Similar to RECORD_WATCH_TIME but ignores background and audio watch time.
-#define RECORD_DISPLAY_WATCH_TIME(key, value)                          \
-  do {                                                                 \
-    DCHECK(properties_->has_video);                                    \
-    DCHECK(!is_background_);                                           \
-    recorder_->RecordWatchTime(WatchTimeKey::kAudioVideo##key, value); \
+#define RECORD_DISPLAY_WATCH_TIME(key, value)                       \
+  do {                                                              \
+    DCHECK(properties_->has_video);                                 \
+    DCHECK(!is_background_);                                        \
+    recorder_->RecordWatchTime(properties_->has_audio               \
+                                   ? WatchTimeKey::kAudioVideo##key \
+                                   : WatchTimeKey::kVideo##key,     \
+                               value);                              \
   } while (0)
 
   // Similar to the block above for display type.
@@ -472,9 +472,13 @@
       keys_to_finalize.insert(
           keys_to_finalize.end(),
           {WatchTimeKey::kAudioBattery, WatchTimeKey::kAudioAc,
-           WatchTimeKey::kAudioVideoBattery, WatchTimeKey::kAudioVideoAc,
+           WatchTimeKey::kAudioBackgroundBattery,
+           WatchTimeKey::kAudioBackgroundAc, WatchTimeKey::kAudioVideoBattery,
+           WatchTimeKey::kAudioVideoAc,
            WatchTimeKey::kAudioVideoBackgroundBattery,
-           WatchTimeKey::kAudioVideoBackgroundAc});
+           WatchTimeKey::kAudioVideoBackgroundAc, WatchTimeKey::kVideoBattery,
+           WatchTimeKey::kVideoAc, WatchTimeKey::kVideoBackgroundAc,
+           WatchTimeKey::kVideoBackgroundBattery});
     }
 
     if (is_controls_change_pending) {
@@ -482,15 +486,19 @@
                               {WatchTimeKey::kAudioNativeControlsOn,
                                WatchTimeKey::kAudioNativeControlsOff,
                                WatchTimeKey::kAudioVideoNativeControlsOn,
-                               WatchTimeKey::kAudioVideoNativeControlsOff});
+                               WatchTimeKey::kAudioVideoNativeControlsOff,
+                               WatchTimeKey::kVideoNativeControlsOn,
+                               WatchTimeKey::kVideoNativeControlsOff});
     }
 
     if (is_display_type_change_pending) {
-      keys_to_finalize.insert(
-          keys_to_finalize.end(),
-          {WatchTimeKey::kAudioVideoDisplayFullscreen,
-           WatchTimeKey::kAudioVideoDisplayInline,
-           WatchTimeKey::kAudioVideoDisplayPictureInPicture});
+      keys_to_finalize.insert(keys_to_finalize.end(),
+                              {WatchTimeKey::kAudioVideoDisplayFullscreen,
+                               WatchTimeKey::kAudioVideoDisplayInline,
+                               WatchTimeKey::kAudioVideoDisplayPictureInPicture,
+                               WatchTimeKey::kVideoDisplayFullscreen,
+                               WatchTimeKey::kVideoDisplayInline,
+                               WatchTimeKey::kVideoDisplayPictureInPicture});
     }
 
     if (!keys_to_finalize.empty())
diff --git a/media/blink/watch_time_reporter.h b/media/blink/watch_time_reporter.h
index e889876..6fea815 100644
--- a/media/blink/watch_time_reporter.h
+++ b/media/blink/watch_time_reporter.h
@@ -25,26 +25,25 @@
 
 // Class for monitoring and reporting watch time in response to various state
 // changes during the playback of media. We record metrics for audio only
-// playbacks as well as audio+video playbacks of sufficient size.
+// playbacks as well as video only or audio+video playbacks of sufficient size.
 //
-// Watch time for our purposes is defined as the amount of elapsed media time
-// for audio only or audio+video media. A minimum of 7 seconds of unmuted media
-// must be watched to start watch time monitoring. Watch time is checked every 5
-// seconds from then on and reported to multiple buckets: All, MSE, SRC, EME,
-// AC, and battery.
+// Watch time for our purposes is defined as the amount of elapsed media time. A
+// minimum of 7 seconds of unmuted media must be watched to start watch time
+// monitoring. Watch time is checked every 5 seconds from then on and reported
+// to multiple buckets: All, MSE, SRC, EME, AC, and battery.
 //
-// Any one of paused, hidden (where this is video), or muted is sufficient to
-// stop watch time metric reports. Each of these has a hysteresis where if the
-// state change is undone within 5 seconds, the watch time will be counted as
-// uninterrupted.
+// Either of paused or muted is sufficient to stop watch time metric reports.
+// Each of these has a hysteresis where if the state change is undone within 5
+// seconds, the watch time will be counted as uninterrupted.
 //
-// If the media is audio+video, foreground watch time is logged to the normal
-// AudioVideo bucket, while background watch time goes to the specific
-// AudioVideo.Background bucket. As with other events, there is hysteresis on
-// change between the foreground and background.
+// There are both foreground and background buckets for watch time. E.g., when
+// media goes into the background foreground collection stops and background
+// collection starts. As with other events, there is hysteresis on change
+// between the foreground and background.
 //
-// Power events (on/off battery power) have a similar hysteresis, but unlike
-// the aforementioned properties, will not stop metric collection.
+// Power events (on/off battery power), native controls changes, or display type
+// changes have a similar hysteresis, but unlike the aforementioned properties,
+// will not stop metric collection.
 //
 // Each seek event will result in a new watch time metric being started and the
 // old metric finalized as accurately as possible.
@@ -76,10 +75,10 @@
                     mojom::WatchTimeRecorderProvider* provider);
   ~WatchTimeReporter() override;
 
-  // These methods are used to ensure that watch time is only reported for
-  // media that is actually playing. They should be called whenever the media
-  // starts or stops playing for any reason. If the media is audio+video and
-  // currently hidden, OnPlaying() will start background watch time reporting.
+  // These methods are used to ensure that watch time is only reported for media
+  // that is actually playing. They should be called whenever the media starts
+  // or stops playing for any reason. If the media is currently hidden,
+  // OnPlaying() will start background watch time reporting.
   void OnPlaying();
   void OnPaused();
 
@@ -92,19 +91,14 @@
   // that is actually audible to the user. It should be called whenever the
   // volume changes.
   //
-  // Note: This does not catch all cases. E.g., headphones that are being
+  // Note: This does not catch all cases. E.g., headphones that are not being
   // listened too, or even OS level volume state.
   void OnVolumeChange(double volume);
 
-  // These methods are used to ensure that watch time is only reported for
-  // videos that are actually visible to the user. They should be called when
-  // the video is shown or hidden respectively. OnHidden() will start background
-  // watch time reporting if the media is audio+video.
-  //
-  // TODO(dalecurtis): At present, this is only called when the entire content
-  // window goes into the foreground or background respectively; i.e. it does
-  // not catch cases where the video is in the foreground but out of the view
-  // port. We need a method for rejecting out of view port videos.
+  // These methods are used to ensure that watch time is only reported for media
+  // that is actually visible to the user. They should be called when the media
+  // is shown or hidden respectively. OnHidden() will start background watch
+  // time reporting.
   void OnShown();
   void OnHidden();
 
diff --git a/media/blink/watch_time_reporter_unittest.cc b/media/blink/watch_time_reporter_unittest.cc
index 558bd74..9184b23 100644
--- a/media/blink/watch_time_reporter_unittest.cc
+++ b/media/blink/watch_time_reporter_unittest.cc
@@ -6,6 +6,7 @@
 
 #include "base/bind.h"
 #include "base/bind_helpers.h"
+#include "base/debug/stack_trace.h"
 #include "base/run_loop.h"
 #include "base/test/test_message_loop.h"
 #include "media/base/mock_media_log.h"
@@ -22,57 +23,68 @@
 
 using blink::WebMediaPlayer;
 
-#define EXPECT_WATCH_TIME(key, value)                                         \
+#define EXPECT_WATCH_TIME(key, value)                                          \
+  do {                                                                         \
+    EXPECT_CALL(                                                               \
+        *this, OnWatchTimeUpdate((has_video_ && has_audio_)                    \
+                                     ? WatchTimeKey::kAudioVideo##key          \
+                                     : has_audio_ ? WatchTimeKey::kAudio##key  \
+                                                  : WatchTimeKey::kVideo##key, \
+                                 value))                                       \
+        .RetiresOnSaturation();                                                \
+  } while (0)
+
+#define EXPECT_WATCH_TIME_IF_VIDEO(key, value)                                \
   do {                                                                        \
+    if (!has_video_)                                                          \
+      break;                                                                  \
     EXPECT_CALL(*this,                                                        \
-                OnWatchTimeUpdate(has_video_ ? WatchTimeKey::kAudioVideo##key \
-                                             : WatchTimeKey::kAudio##key,     \
+                OnWatchTimeUpdate(has_audio_ ? WatchTimeKey::kAudioVideo##key \
+                                             : WatchTimeKey::kVideo##key,     \
                                   value))                                     \
         .RetiresOnSaturation();                                               \
   } while (0)
 
-#define EXPECT_WATCH_TIME_IF_VIDEO(key, value)                            \
-  do {                                                                    \
-    if (!has_video_)                                                      \
-      break;                                                              \
-    EXPECT_CALL(*this,                                                    \
-                OnWatchTimeUpdate(WatchTimeKey::kAudioVideo##key, value)) \
-        .RetiresOnSaturation();                                           \
-  } while (0)
-
-#define EXPECT_BACKGROUND_WATCH_TIME(key, value)                             \
-  do {                                                                       \
-    DCHECK(has_video_);                                                      \
-    EXPECT_CALL(*this, OnWatchTimeUpdate(                                    \
-                           WatchTimeKey::kAudioVideoBackground##key, value)) \
-        .RetiresOnSaturation();                                              \
+#define EXPECT_BACKGROUND_WATCH_TIME(key, value)                            \
+  do {                                                                      \
+    EXPECT_CALL(*this,                                                      \
+                OnWatchTimeUpdate(                                          \
+                    (has_video_ && has_audio_)                              \
+                        ? WatchTimeKey::kAudioVideoBackground##key          \
+                        : has_audio_ ? WatchTimeKey::kAudioBackground##key  \
+                                     : WatchTimeKey::kVideoBackground##key, \
+                    value))                                                 \
+        .RetiresOnSaturation();                                             \
   } while (0)
 
 #define EXPECT_WATCH_TIME_FINALIZED() \
   EXPECT_CALL(*this, OnWatchTimeFinalized()).RetiresOnSaturation();
 
 // The following macros have .Times() values equal to the number of keys that a
-// finalize event is expected to generate.
-
+// finalize event is expected to finalize.
 #define EXPECT_POWER_WATCH_TIME_FINALIZED()       \
   EXPECT_CALL(*this, OnPowerWatchTimeFinalized()) \
-      .Times(6)                                   \
+      .Times(12)                                  \
       .RetiresOnSaturation();
 
 #define EXPECT_CONTROLS_WATCH_TIME_FINALIZED()       \
   EXPECT_CALL(*this, OnControlsWatchTimeFinalized()) \
-      .Times(4)                                      \
+      .Times(6)                                      \
       .RetiresOnSaturation();
 
 #define EXPECT_DISPLAY_WATCH_TIME_FINALIZED()       \
   EXPECT_CALL(*this, OnDisplayWatchTimeFinalized()) \
-      .Times(3)                                     \
+      .Times(6)                                     \
       .RetiresOnSaturation();
 
-class WatchTimeReporterTest : public testing::TestWithParam<bool>,
-                              public mojom::WatchTimeRecorderProvider {
+using WatchTimeReporterTestData = std::tuple<bool, bool>;
+class WatchTimeReporterTest
+    : public testing::TestWithParam<WatchTimeReporterTestData>,
+      public mojom::WatchTimeRecorderProvider {
  public:
-  WatchTimeReporterTest() : has_video_(GetParam()) {}
+  WatchTimeReporterTest()
+      : has_video_(std::get<0>(GetParam())),
+        has_audio_(std::get<1>(GetParam())) {}
   ~WatchTimeReporterTest() override = default;
 
  protected:
@@ -96,10 +108,16 @@
           switch (key) {
             case WatchTimeKey::kAudioBattery:
             case WatchTimeKey::kAudioAc:
+            case WatchTimeKey::kAudioBackgroundBattery:
+            case WatchTimeKey::kAudioBackgroundAc:
             case WatchTimeKey::kAudioVideoBattery:
             case WatchTimeKey::kAudioVideoAc:
             case WatchTimeKey::kAudioVideoBackgroundBattery:
             case WatchTimeKey::kAudioVideoBackgroundAc:
+            case WatchTimeKey::kVideoBattery:
+            case WatchTimeKey::kVideoAc:
+            case WatchTimeKey::kVideoBackgroundBattery:
+            case WatchTimeKey::kVideoBackgroundAc:
               parent_->OnPowerWatchTimeFinalized();
               break;
 
@@ -107,12 +125,17 @@
             case WatchTimeKey::kAudioNativeControlsOff:
             case WatchTimeKey::kAudioVideoNativeControlsOn:
             case WatchTimeKey::kAudioVideoNativeControlsOff:
+            case WatchTimeKey::kVideoNativeControlsOn:
+            case WatchTimeKey::kVideoNativeControlsOff:
               parent_->OnControlsWatchTimeFinalized();
               break;
 
             case WatchTimeKey::kAudioVideoDisplayFullscreen:
             case WatchTimeKey::kAudioVideoDisplayInline:
             case WatchTimeKey::kAudioVideoDisplayPictureInPicture:
+            case WatchTimeKey::kVideoDisplayFullscreen:
+            case WatchTimeKey::kVideoDisplayInline:
+            case WatchTimeKey::kVideoDisplayPictureInPicture:
               parent_->OnDisplayWatchTimeFinalized();
               break;
 
@@ -121,6 +144,11 @@
             case WatchTimeKey::kAudioEme:
             case WatchTimeKey::kAudioSrc:
             case WatchTimeKey::kAudioEmbeddedExperience:
+            case WatchTimeKey::kAudioBackgroundAll:
+            case WatchTimeKey::kAudioBackgroundMse:
+            case WatchTimeKey::kAudioBackgroundEme:
+            case WatchTimeKey::kAudioBackgroundSrc:
+            case WatchTimeKey::kAudioBackgroundEmbeddedExperience:
             case WatchTimeKey::kAudioVideoAll:
             case WatchTimeKey::kAudioVideoMse:
             case WatchTimeKey::kAudioVideoEme:
@@ -131,6 +159,16 @@
             case WatchTimeKey::kAudioVideoBackgroundEme:
             case WatchTimeKey::kAudioVideoBackgroundSrc:
             case WatchTimeKey::kAudioVideoBackgroundEmbeddedExperience:
+            case WatchTimeKey::kVideoAll:
+            case WatchTimeKey::kVideoMse:
+            case WatchTimeKey::kVideoEme:
+            case WatchTimeKey::kVideoSrc:
+            case WatchTimeKey::kVideoEmbeddedExperience:
+            case WatchTimeKey::kVideoBackgroundAll:
+            case WatchTimeKey::kVideoBackgroundMse:
+            case WatchTimeKey::kVideoBackgroundEme:
+            case WatchTimeKey::kVideoBackgroundSrc:
+            case WatchTimeKey::kVideoBackgroundEmbeddedExperience:
               // These keys do not support partial finalization.
               FAIL();
               break;
@@ -159,8 +197,7 @@
                             std::move(request));
   }
 
-  void Initialize(bool has_audio,
-                  bool is_mse,
+  void Initialize(bool is_mse,
                   bool is_encrypted,
                   const gfx::Size& initial_video_size) {
     if (wtr_ && IsMonitoring())
@@ -168,7 +205,7 @@
 
     wtr_.reset(new WatchTimeReporter(
         mojom::PlaybackProperties::New(kUnknownAudioCodec, kUnknownVideoCodec,
-                                       has_audio, has_video_, is_mse,
+                                       has_audio_, has_video_, false, is_mse,
                                        is_encrypted, false, initial_video_size,
                                        url::Origin(), true /* is_top_frame */),
         base::Bind(&WatchTimeReporterTest::GetCurrentMediaTime,
@@ -274,7 +311,7 @@
 
   template <int TestFlags = 0, typename HysteresisTestCallback>
   void RunHysteresisTest(HysteresisTestCallback test_callback_func) {
-    Initialize(true, false, false, kSizeJustRight);
+    Initialize(false, false, kSizeJustRight);
 
     // Disable background reporting for the hysteresis tests.
     wtr_->background_reporter_.reset();
@@ -468,6 +505,7 @@
   MOCK_METHOD1(OnError, void(PipelineStatus));
 
   const bool has_video_;
+  const bool has_audio_;
   base::TestMessageLoop message_loop_;
   std::unique_ptr<WatchTimeReporter> wtr_;
 
@@ -480,46 +518,46 @@
   EXPECT_CALL(*this, GetCurrentMediaTime())
       .WillRepeatedly(testing::Return(base::TimeDelta()));
 
-  Initialize(!has_video_, true, true, gfx::Size());
+  Initialize(true, true, gfx::Size());
   wtr_->OnPlaying();
   EXPECT_EQ(!has_video_, IsMonitoring());
 
-  Initialize(true, true, true, gfx::Size());
+  Initialize(true, true, gfx::Size());
   wtr_->OnPlaying();
   EXPECT_EQ(!has_video_, IsMonitoring());
 
   constexpr gfx::Size kSizeTooSmall = gfx::Size(100, 100);
-  Initialize(!has_video_, true, true, kSizeTooSmall);
+  Initialize(true, true, kSizeTooSmall);
   wtr_->OnPlaying();
   EXPECT_EQ(!has_video_, IsMonitoring());
 
-  Initialize(true, true, true, kSizeJustRight);
+  Initialize(true, true, kSizeJustRight);
   wtr_->OnPlaying();
   EXPECT_TRUE(IsMonitoring());
 
-  Initialize(true, false, false, kSizeJustRight);
+  Initialize(false, false, kSizeJustRight);
   wtr_->OnPlaying();
   EXPECT_TRUE(IsMonitoring());
 
-  Initialize(true, true, false, kSizeJustRight);
+  Initialize(true, false, kSizeJustRight);
   wtr_->OnPlaying();
   EXPECT_TRUE(IsMonitoring());
 
-  Initialize(true, true, true, gfx::Size());
-  wtr_->OnPlaying();
-  EXPECT_EQ(!has_video_, IsMonitoring());
-
-  Initialize(true, false, false, gfx::Size());
-  wtr_->OnPlaying();
-  EXPECT_EQ(!has_video_, IsMonitoring());
-
-  Initialize(true, true, false, gfx::Size());
-  wtr_->OnPlaying();
-  EXPECT_EQ(!has_video_, IsMonitoring());
-
-  EXPECT_CALL(*this, OnError(PIPELINE_ERROR_DECODE));
+  EXPECT_CALL(*this, OnError(PIPELINE_ERROR_DECODE)).Times(2);
   wtr_->OnError(PIPELINE_ERROR_DECODE);
 
+  Initialize(true, true, gfx::Size());
+  wtr_->OnPlaying();
+  EXPECT_EQ(!has_video_, IsMonitoring());
+
+  Initialize(false, false, gfx::Size());
+  wtr_->OnPlaying();
+  EXPECT_EQ(!has_video_, IsMonitoring());
+
+  Initialize(true, false, gfx::Size());
+  wtr_->OnPlaying();
+  EXPECT_EQ(!has_video_, IsMonitoring());
+
   if (!has_video_)
     EXPECT_WATCH_TIME_FINALIZED();
   wtr_.reset();
@@ -532,7 +570,7 @@
       .WillOnce(testing::Return(base::TimeDelta()))
       .WillOnce(testing::Return(kWatchTimeEarly))
       .WillRepeatedly(testing::Return(kWatchTimeLate));
-  Initialize(true, true, true, kSizeJustRight);
+  Initialize(true, true, kSizeJustRight);
   wtr_->OnPlaying();
   EXPECT_TRUE(IsMonitoring());
 
@@ -564,7 +602,7 @@
       .WillOnce(testing::Return(kWatchTimeEarly))
       .WillOnce(testing::Return(kWatchTimeEarly))
       .WillRepeatedly(testing::Return(kWatchTimeLate));
-  Initialize(true, true, true, kSizeJustRight);
+  Initialize(true, true, kSizeJustRight);
   wtr_->OnPlaying();
   EXPECT_TRUE(IsMonitoring());
 
@@ -601,46 +639,34 @@
       .WillOnce(testing::Return(kWatchTimeEarly))
       .WillOnce(testing::Return(kWatchTimeEarly))
       .WillRepeatedly(testing::Return(kWatchTimeLate));
-  Initialize(true, true, true, kSizeJustRight);
+  Initialize(true, true, kSizeJustRight);
   wtr_->OnPlaying();
   EXPECT_TRUE(IsMonitoring());
 
-  // If we have video, this will halt watch time collection, if only audio it
-  // will do nothing. Consume the expectations if audio only.
   wtr_->OnHidden();
-  if (!has_video_) {
-    GetCurrentMediaTime();
-    GetCurrentMediaTime();
-  } else {
-    const base::TimeDelta kExpectedWatchTime = kWatchTimeLate - kWatchTimeEarly;
-    EXPECT_BACKGROUND_WATCH_TIME(Ac, kExpectedWatchTime);
-    EXPECT_BACKGROUND_WATCH_TIME(All, kExpectedWatchTime);
-    EXPECT_BACKGROUND_WATCH_TIME(Eme, kExpectedWatchTime);
-    EXPECT_BACKGROUND_WATCH_TIME(Mse, kExpectedWatchTime);
-    EXPECT_WATCH_TIME_FINALIZED();
+  const base::TimeDelta kExpectedWatchTime = kWatchTimeLate - kWatchTimeEarly;
+  EXPECT_BACKGROUND_WATCH_TIME(Ac, kExpectedWatchTime);
+  EXPECT_BACKGROUND_WATCH_TIME(All, kExpectedWatchTime);
+  EXPECT_BACKGROUND_WATCH_TIME(Eme, kExpectedWatchTime);
+  EXPECT_BACKGROUND_WATCH_TIME(Mse, kExpectedWatchTime);
+  EXPECT_WATCH_TIME_FINALIZED();
 
-    // One call for the background reporter and one for the foreground.
-    EXPECT_CALL(*this, OnError(PIPELINE_ERROR_DECODE)).Times(2);
-    wtr_->OnError(PIPELINE_ERROR_DECODE);
-  }
+  // One call for the background reporter and one for the foreground.
+  EXPECT_CALL(*this, OnError(PIPELINE_ERROR_DECODE)).Times(2);
+  wtr_->OnError(PIPELINE_ERROR_DECODE);
 
-  const base::TimeDelta kExpectedWatchTime =
-      has_video_ ? kWatchTimeEarly : kWatchTimeLate;
-  EXPECT_WATCH_TIME(Ac, kExpectedWatchTime);
-  EXPECT_WATCH_TIME(All, kExpectedWatchTime);
-  EXPECT_WATCH_TIME(Eme, kExpectedWatchTime);
-  EXPECT_WATCH_TIME(Mse, kExpectedWatchTime);
-  EXPECT_WATCH_TIME(NativeControlsOff, kExpectedWatchTime);
-  EXPECT_WATCH_TIME_IF_VIDEO(DisplayInline, kExpectedWatchTime);
+  const base::TimeDelta kExpectedForegroundWatchTime = kWatchTimeEarly;
+  EXPECT_WATCH_TIME(Ac, kExpectedForegroundWatchTime);
+  EXPECT_WATCH_TIME(All, kExpectedForegroundWatchTime);
+  EXPECT_WATCH_TIME(Eme, kExpectedForegroundWatchTime);
+  EXPECT_WATCH_TIME(Mse, kExpectedForegroundWatchTime);
+  EXPECT_WATCH_TIME(NativeControlsOff, kExpectedForegroundWatchTime);
+  EXPECT_WATCH_TIME_IF_VIDEO(DisplayInline, kExpectedForegroundWatchTime);
   EXPECT_WATCH_TIME_FINALIZED();
   wtr_.reset();
 }
 
 TEST_P(WatchTimeReporterTest, WatchTimeReporterBackgroundHysteresis) {
-  // Only run these background tests when video is present.
-  if (!has_video_)
-    return;
-
   constexpr base::TimeDelta kWatchTimeEarly = base::TimeDelta::FromSeconds(8);
   constexpr base::TimeDelta kWatchTimeLate = base::TimeDelta::FromSeconds(10);
   EXPECT_CALL(*this, GetCurrentMediaTime())
@@ -652,7 +678,7 @@
       .WillOnce(testing::Return(kWatchTimeEarly))
       .WillOnce(testing::Return(kWatchTimeEarly))  // 1x for timer cycle.
       .WillRepeatedly(testing::Return(kWatchTimeLate));
-  Initialize(true, true, true, kSizeJustRight);
+  Initialize(true, true, kSizeJustRight);
   wtr_->OnHidden();
   wtr_->OnPlaying();
   EXPECT_TRUE(IsBackgroundMonitoring());
@@ -681,10 +707,6 @@
 }
 
 TEST_P(WatchTimeReporterTest, WatchTimeReporterShownHiddenBackground) {
-  // Only run these background tests when video is present.
-  if (!has_video_)
-    return;
-
   constexpr base::TimeDelta kWatchTimeEarly = base::TimeDelta::FromSeconds(8);
   constexpr base::TimeDelta kWatchTimeLate = base::TimeDelta::FromSeconds(10);
   EXPECT_CALL(*this, GetCurrentMediaTime())
@@ -694,7 +716,7 @@
       .WillOnce(testing::Return(kWatchTimeEarly))
       .WillRepeatedly(testing::Return(kWatchTimeLate));
 
-  Initialize(true, true, true, kSizeJustRight);
+  Initialize(true, true, kSizeJustRight);
   wtr_->OnHidden();
   wtr_->OnPlaying();
   EXPECT_TRUE(IsBackgroundMonitoring());
@@ -716,16 +738,12 @@
 }
 
 TEST_P(WatchTimeReporterTest, WatchTimeReporterHiddenPausedBackground) {
-  // Only run these background tests when video is present.
-  if (!has_video_)
-    return;
-
   constexpr base::TimeDelta kWatchTime = base::TimeDelta::FromSeconds(8);
   EXPECT_CALL(*this, GetCurrentMediaTime())
       .WillOnce(testing::Return(base::TimeDelta()))
       .WillOnce(testing::Return(base::TimeDelta()))
       .WillRepeatedly(testing::Return(kWatchTime));
-  Initialize(true, true, true, kSizeJustRight);
+  Initialize(true, true, kSizeJustRight);
   wtr_->OnHidden();
   wtr_->OnPlaying();
   EXPECT_TRUE(IsBackgroundMonitoring());
@@ -745,16 +763,12 @@
 }
 
 TEST_P(WatchTimeReporterTest, WatchTimeReporterHiddenSeekedBackground) {
-  // Only run these background tests when video is present.
-  if (!has_video_)
-    return;
-
   constexpr base::TimeDelta kWatchTime = base::TimeDelta::FromSeconds(8);
   EXPECT_CALL(*this, GetCurrentMediaTime())
       .WillOnce(testing::Return(base::TimeDelta()))
       .WillOnce(testing::Return(base::TimeDelta()))
       .WillRepeatedly(testing::Return(kWatchTime));
-  Initialize(true, false, true, kSizeJustRight);
+  Initialize(false, true, kSizeJustRight);
   wtr_->OnHidden();
   wtr_->OnPlaying();
   EXPECT_TRUE(IsBackgroundMonitoring());
@@ -773,10 +787,6 @@
 }
 
 TEST_P(WatchTimeReporterTest, WatchTimeReporterHiddenPowerBackground) {
-  // Only run these background tests when video is present.
-  if (!has_video_)
-    return;
-
   constexpr base::TimeDelta kWatchTime1 = base::TimeDelta::FromSeconds(8);
   constexpr base::TimeDelta kWatchTime2 = base::TimeDelta::FromSeconds(16);
   EXPECT_CALL(*this, GetCurrentMediaTime())
@@ -785,7 +795,7 @@
       .WillOnce(testing::Return(kWatchTime1))
       .WillOnce(testing::Return(kWatchTime1))
       .WillRepeatedly(testing::Return(kWatchTime2));
-  Initialize(true, true, true, kSizeJustRight);
+  Initialize(true, true, kSizeJustRight);
   wtr_->OnHidden();
   wtr_->OnPlaying();
   EXPECT_TRUE(IsBackgroundMonitoring());
@@ -813,10 +823,6 @@
 }
 
 TEST_P(WatchTimeReporterTest, WatchTimeReporterHiddenControlsBackground) {
-  // Only run these background tests when video is present.
-  if (!has_video_)
-    return;
-
   constexpr base::TimeDelta kWatchTime1 = base::TimeDelta::FromSeconds(8);
   constexpr base::TimeDelta kWatchTime2 = base::TimeDelta::FromSeconds(16);
   EXPECT_CALL(*this, GetCurrentMediaTime())
@@ -824,7 +830,7 @@
       .WillOnce(testing::Return(base::TimeDelta()))
       .WillOnce(testing::Return(kWatchTime1))
       .WillOnce(testing::Return(kWatchTime2));
-  Initialize(true, true, true, kSizeJustRight);
+  Initialize(true, true, kSizeJustRight);
   wtr_->OnHidden();
   wtr_->OnPlaying();
   EXPECT_TRUE(IsBackgroundMonitoring());
@@ -852,10 +858,6 @@
 }
 
 TEST_P(WatchTimeReporterTest, WatchTimeReporterHiddenDisplayTypeBackground) {
-  // Only run these background tests when video is present.
-  if (!has_video_)
-    return;
-
   constexpr base::TimeDelta kWatchTime1 = base::TimeDelta::FromSeconds(8);
   constexpr base::TimeDelta kWatchTime2 = base::TimeDelta::FromSeconds(16);
   EXPECT_CALL(*this, GetCurrentMediaTime())
@@ -863,7 +865,7 @@
       .WillOnce(testing::Return(base::TimeDelta()))
       .WillOnce(testing::Return(kWatchTime1))
       .WillOnce(testing::Return(kWatchTime2));
-  Initialize(true, true, true, kSizeJustRight);
+  Initialize(true, true, kSizeJustRight);
   wtr_->OnHidden();
   wtr_->OnPlaying();
   EXPECT_TRUE(IsBackgroundMonitoring());
@@ -891,10 +893,6 @@
 }
 
 TEST_P(WatchTimeReporterTest, WatchTimeReporterMultiplePartialFinalize) {
-  // Only run these background tests when video is present.
-  if (!has_video_)
-    return;
-
   constexpr base::TimeDelta kWatchTime1 = base::TimeDelta::FromSeconds(8);
   constexpr base::TimeDelta kWatchTime2 = base::TimeDelta::FromSeconds(16);
 
@@ -906,7 +904,7 @@
         .WillOnce(testing::Return(kWatchTime1))
         .WillOnce(testing::Return(kWatchTime1))
         .WillOnce(testing::Return(kWatchTime2));
-    Initialize(true, true, true, kSizeJustRight);
+    Initialize(true, true, kSizeJustRight);
     wtr_->OnPlaying();
     EXPECT_TRUE(IsMonitoring());
 
@@ -945,7 +943,7 @@
         .WillOnce(testing::Return(kWatchTime1))
         .WillOnce(testing::Return(kWatchTime1))
         .WillOnce(testing::Return(kWatchTime2));
-    Initialize(true, true, true, kSizeJustRight);
+    Initialize(true, true, kSizeJustRight);
     wtr_->OnPlaying();
     EXPECT_TRUE(IsMonitoring());
 
@@ -985,7 +983,7 @@
         .WillOnce(testing::Return(kWatchTime1))
         .WillOnce(testing::Return(kWatchTime1))
         .WillOnce(testing::Return(kWatchTime2));
-    Initialize(true, true, true, kSizeJustRight);
+    Initialize(true, true, kSizeJustRight);
     wtr_->OnPlaying();
     EXPECT_TRUE(IsMonitoring());
 
@@ -1027,7 +1025,7 @@
   EXPECT_CALL(*this, GetCurrentMediaTime())
       .WillOnce(testing::Return(kWatchTime1))
       .WillRepeatedly(testing::Return(kWatchTime2));
-  Initialize(true, true, true, kSizeJustRight);
+  Initialize(true, true, kSizeJustRight);
   wtr_->OnPlaying();
   EXPECT_TRUE(IsMonitoring());
 
@@ -1050,7 +1048,7 @@
   EXPECT_CALL(*this, GetCurrentMediaTime())
       .WillOnce(testing::Return(base::TimeDelta()))
       .WillOnce(testing::Return(kWatchTime));
-  Initialize(true, true, true, kSizeJustRight);
+  Initialize(true, true, kSizeJustRight);
   wtr_->OnPlaying();
   EXPECT_TRUE(IsMonitoring());
 
@@ -1071,7 +1069,7 @@
   EXPECT_CALL(*this, GetCurrentMediaTime())
       .WillOnce(testing::Return(base::TimeDelta()))
       .WillOnce(testing::Return(kWatchTime));
-  Initialize(true, true, true, kSizeJustRight);
+  Initialize(true, true, kSizeJustRight);
   wtr_->OnPlaying();
   EXPECT_TRUE(IsMonitoring());
 
@@ -1092,7 +1090,7 @@
   EXPECT_CALL(*this, GetCurrentMediaTime())
       .WillOnce(testing::Return(base::TimeDelta()))
       .WillOnce(testing::Return(kWatchTime));
-  Initialize(true, true, true, kSizeJustRight);
+  Initialize(true, true, kSizeJustRight);
   wtr_->OnPlaying();
   EXPECT_TRUE(IsMonitoring());
 
@@ -1115,7 +1113,7 @@
   EXPECT_CALL(*this, GetCurrentMediaTime())
       .WillOnce(testing::Return(base::TimeDelta()))
       .WillOnce(testing::Return(kWatchTime));
-  Initialize(true, false, false, kSizeJustRight);
+  Initialize(false, false, kSizeJustRight);
   wtr_->OnPlaying();
   EXPECT_TRUE(IsMonitoring());
   EXPECT_WATCH_TIME(Ac, kWatchTime);
@@ -1130,7 +1128,7 @@
   EXPECT_CALL(*this, GetCurrentMediaTime())
       .WillOnce(testing::Return(base::TimeDelta()))
       .WillOnce(testing::Return(kWatchTime));
-  Initialize(true, true, false, kSizeJustRight);
+  Initialize(true, false, kSizeJustRight);
   wtr_->OnPlaying();
   EXPECT_TRUE(IsMonitoring());
   EXPECT_WATCH_TIME(Ac, kWatchTime);
@@ -1145,7 +1143,7 @@
   EXPECT_CALL(*this, GetCurrentMediaTime())
       .WillOnce(testing::Return(base::TimeDelta()))
       .WillOnce(testing::Return(kWatchTime));
-  Initialize(true, false, true, kSizeJustRight);
+  Initialize(false, true, kSizeJustRight);
   wtr_->OnPlaying();
   EXPECT_TRUE(IsMonitoring());
   EXPECT_WATCH_TIME(Ac, kWatchTime);
@@ -1161,7 +1159,7 @@
   EXPECT_CALL(*this, GetCurrentMediaTime())
       .WillOnce(testing::Return(base::TimeDelta()))
       .WillOnce(testing::Return(kWatchTime));
-  Initialize(true, false, false, kSizeJustRight);
+  Initialize(false, false, kSizeJustRight);
   wtr_->OnPlaying();
   SetOnBatteryPower(true);
   EXPECT_TRUE(IsMonitoring());
@@ -1177,7 +1175,7 @@
   EXPECT_CALL(*this, GetCurrentMediaTime())
       .WillOnce(testing::Return(base::TimeDelta()))
       .WillOnce(testing::Return(kWatchTime));
-  Initialize(true, false, false, kSizeJustRight);
+  Initialize(false, false, kSizeJustRight);
   OnNativeControlsEnabled(true);
   wtr_->OnPlaying();
   EXPECT_TRUE(IsMonitoring());
@@ -1193,7 +1191,7 @@
   EXPECT_CALL(*this, GetCurrentMediaTime())
       .WillOnce(testing::Return(base::TimeDelta()))
       .WillOnce(testing::Return(kWatchTime));
-  Initialize(true, false, false, kSizeJustRight);
+  Initialize(false, false, kSizeJustRight);
   OnDisplayTypeChanged(WebMediaPlayer::DisplayType::kFullscreen);
   wtr_->OnPlaying();
   SetOnBatteryPower(true);
@@ -1210,7 +1208,7 @@
   EXPECT_CALL(*this, GetCurrentMediaTime())
       .WillOnce(testing::Return(base::TimeDelta()))
       .WillOnce(testing::Return(kWatchTime));
-  Initialize(true, false, false, kSizeJustRight);
+  Initialize(false, false, kSizeJustRight);
   OnNativeControlsEnabled(true);
   OnDisplayTypeChanged(WebMediaPlayer::DisplayType::kPictureInPicture);
   wtr_->OnPlaying();
@@ -1247,8 +1245,6 @@
 }
 
 TEST_P(WatchTimeReporterTest, OnShownHiddenHysteresisContinuation) {
-  if (!has_video_)
-    return;
   RunHysteresisTest<kAccumulationContinuesAfterTest>([this]() {
     wtr_->OnHidden();
     wtr_->OnShown();
@@ -1256,8 +1252,6 @@
 }
 
 TEST_P(WatchTimeReporterTest, OnShownHiddenHysteresisFinalized) {
-  if (!has_video_)
-    return;
   RunHysteresisTest([this]() { wtr_->OnHidden(); });
 }
 
@@ -1443,6 +1437,11 @@
 
 INSTANTIATE_TEST_CASE_P(WatchTimeReporterTest,
                         WatchTimeReporterTest,
-                        testing::Values(true, false));
+                        testing::ValuesIn({// has_video, has_audio
+                                           std::make_tuple(true, true),
+                                           // has_audio
+                                           std::make_tuple(true, false),
+                                           // has_video
+                                           std::make_tuple(false, true)}));
 
 }  // namespace media
diff --git a/media/blink/webmediaplayer_impl.cc b/media/blink/webmediaplayer_impl.cc
index 642bf19..65e3b42 100644
--- a/media/blink/webmediaplayer_impl.cc
+++ b/media/blink/webmediaplayer_impl.cc
@@ -211,10 +211,10 @@
       last_reported_memory_usage_(0),
       supports_save_(true),
       chunk_demuxer_(NULL),
-      tick_clock_(new base::DefaultTickClock()),
+      tick_clock_(base::DefaultTickClock::GetInstance()),
       buffered_data_source_host_(
           base::Bind(&WebMediaPlayerImpl::OnProgress, AsWeakPtr()),
-          tick_clock_.get()),
+          tick_clock_),
       url_index_(url_index),
       context_provider_(params->context_provider()),
       vfc_task_runner_(params->video_frame_compositor_task_runner()),
@@ -2572,7 +2572,7 @@
       mojom::PlaybackProperties::New(
           pipeline_metadata_.audio_decoder_config.codec(),
           pipeline_metadata_.video_decoder_config.codec(),
-          pipeline_metadata_.has_audio, pipeline_metadata_.has_video,
+          pipeline_metadata_.has_audio, pipeline_metadata_.has_video, false,
           !!chunk_demuxer_, is_encrypted_, embedded_media_experience_enabled_,
           pipeline_metadata_.natural_size, top_origin, is_top_frame),
       base::BindRepeating(&WebMediaPlayerImpl::GetCurrentTimeInternal,
@@ -2872,7 +2872,7 @@
 #undef UMA_HISTOGRAM_VIDEO_HEIGHT
 
 void WebMediaPlayerImpl::SetTickClockForTest(base::TickClock* tick_clock) {
-  tick_clock_.reset(tick_clock);
+  tick_clock_ = tick_clock;
   buffered_data_source_host_.SetTickClockForTest(tick_clock);
 }
 
diff --git a/media/blink/webmediaplayer_impl.h b/media/blink/webmediaplayer_impl.h
index 7d03385..af7f7de 100644
--- a/media/blink/webmediaplayer_impl.h
+++ b/media/blink/webmediaplayer_impl.h
@@ -517,7 +517,6 @@
   // Records |natural_size| to MediaLog and video height to UMA.
   void RecordVideoNaturalSize(const gfx::Size& natural_size);
 
-  // Takes ownership of |tick_clock|
   void SetTickClockForTest(base::TickClock* tick_clock);
 
   // Returns the current time without clamping to Duration() as required by
@@ -655,7 +654,7 @@
 
   std::unique_ptr<base::MemoryPressureListener> memory_pressure_listener_;
 
-  std::unique_ptr<base::TickClock> tick_clock_;
+  base::TickClock* tick_clock_;
 
   BufferedDataSourceHostImpl buffered_data_source_host_;
   UrlIndex* url_index_;
diff --git a/media/blink/webmediaplayer_impl_unittest.cc b/media/blink/webmediaplayer_impl_unittest.cc
index 2f4257d..707489a 100644
--- a/media/blink/webmediaplayer_impl_unittest.cc
+++ b/media/blink/webmediaplayer_impl_unittest.cc
@@ -545,13 +545,13 @@
 TEST_F(WebMediaPlayerImplTest,
        IdleSuspendIsDisabledIfLoadingProgressedRecently) {
   InitializeWebMediaPlayerImpl();
-  base::SimpleTestTickClock* clock = new base::SimpleTestTickClock();
-  clock->Advance(base::TimeDelta::FromSeconds(1));
-  SetTickClock(clock);
+  base::SimpleTestTickClock clock;
+  clock.Advance(base::TimeDelta::FromSeconds(1));
+  SetTickClock(&clock);
   AddBufferedRanges();
   wmpi_->DidLoadingProgress();
   // Advance less than the loading timeout.
-  clock->Advance(base::TimeDelta::FromSeconds(1));
+  clock.Advance(base::TimeDelta::FromSeconds(1));
   EXPECT_FALSE(delegate_.ExpireForTesting());
   base::RunLoop().RunUntilIdle();
   EXPECT_FALSE(IsSuspended());
@@ -560,13 +560,13 @@
 TEST_F(WebMediaPlayerImplTest, IdleSuspendIsEnabledIfLoadingHasStalled) {
   InitializeWebMediaPlayerImpl();
   SetNetworkState(blink::WebMediaPlayer::kNetworkStateLoading);
-  base::SimpleTestTickClock* clock = new base::SimpleTestTickClock();
-  clock->Advance(base::TimeDelta::FromSeconds(1));
-  SetTickClock(clock);
+  base::SimpleTestTickClock clock;
+  clock.Advance(base::TimeDelta::FromSeconds(1));
+  SetTickClock(&clock);
   AddBufferedRanges();
   wmpi_->DidLoadingProgress();
   // Advance more than the loading timeout.
-  clock->Advance(base::TimeDelta::FromSeconds(4));
+  clock.Advance(base::TimeDelta::FromSeconds(4));
   EXPECT_TRUE(delegate_.ExpireForTesting());
   base::RunLoop().RunUntilIdle();
   EXPECT_TRUE(IsSuspended());
diff --git a/media/cast/cast_environment.cc b/media/cast/cast_environment.cc
index 6f28a6bc..680c97b 100644
--- a/media/cast/cast_environment.cc
+++ b/media/cast/cast_environment.cc
@@ -16,14 +16,14 @@
 namespace cast {
 
 CastEnvironment::CastEnvironment(
-    std::unique_ptr<base::TickClock> clock,
+    base::TickClock* clock,
     scoped_refptr<SingleThreadTaskRunner> main_thread_proxy,
     scoped_refptr<SingleThreadTaskRunner> audio_thread_proxy,
     scoped_refptr<SingleThreadTaskRunner> video_thread_proxy)
     : main_thread_proxy_(main_thread_proxy),
       audio_thread_proxy_(audio_thread_proxy),
       video_thread_proxy_(video_thread_proxy),
-      clock_(std::move(clock)),
+      clock_(clock),
       logger_(this) {}
 
 CastEnvironment::~CastEnvironment() = default;
diff --git a/media/cast/cast_environment.h b/media/cast/cast_environment.h
index 604d1fd..731f9c3 100644
--- a/media/cast/cast_environment.h
+++ b/media/cast/cast_environment.h
@@ -32,7 +32,7 @@
   };
 
   CastEnvironment(
-      std::unique_ptr<base::TickClock> clock,
+      base::TickClock* clock,
       scoped_refptr<base::SingleThreadTaskRunner> main_thread_proxy,
       scoped_refptr<base::SingleThreadTaskRunner> audio_thread_proxy,
       scoped_refptr<base::SingleThreadTaskRunner> video_thread_proxy);
@@ -54,7 +54,7 @@
   bool CurrentlyOn(ThreadId identifier);
 
   // All of the media::cast implementation must use this TickClock.
-  base::TickClock* Clock() const { return clock_.get(); }
+  base::TickClock* Clock() const { return clock_; }
 
   // Thread-safe log event dispatcher.
   LogEventDispatcher* logger() { return &logger_; }
@@ -73,7 +73,7 @@
   scoped_refptr<base::SingleThreadTaskRunner> main_thread_proxy_;
   scoped_refptr<base::SingleThreadTaskRunner> audio_thread_proxy_;
   scoped_refptr<base::SingleThreadTaskRunner> video_thread_proxy_;
-  std::unique_ptr<base::TickClock> clock_;
+  base::TickClock* clock_;
   LogEventDispatcher logger_;
 
  private:
diff --git a/media/cast/logging/encoding_event_subscriber_unittest.cc b/media/cast/logging/encoding_event_subscriber_unittest.cc
index 9d0cbc4..8ee5188f 100644
--- a/media/cast/logging/encoding_event_subscriber_unittest.cc
+++ b/media/cast/logging/encoding_event_subscriber_unittest.cc
@@ -36,13 +36,11 @@
 class EncodingEventSubscriberTest : public ::testing::Test {
  protected:
   EncodingEventSubscriberTest()
-      : testing_clock_(new base::SimpleTestTickClock()),
-        task_runner_(new FakeSingleThreadTaskRunner(testing_clock_)),
-        cast_environment_(new CastEnvironment(
-            std::unique_ptr<base::TickClock>(testing_clock_),
-            task_runner_,
-            task_runner_,
-            task_runner_)) {}
+      : task_runner_(new FakeSingleThreadTaskRunner(&testing_clock_)),
+        cast_environment_(new CastEnvironment(&testing_clock_,
+                                              task_runner_,
+                                              task_runner_,
+                                              task_runner_)) {}
 
   void Init(EventMediaType event_media_type) {
     DCHECK(!event_subscriber_);
@@ -62,7 +60,7 @@
         RtpTimeTicks().Expand(metadata_.first_rtp_timestamp());
   }
 
-  base::SimpleTestTickClock* testing_clock_;  // Owned by CastEnvironment.
+  base::SimpleTestTickClock testing_clock_;
   scoped_refptr<FakeSingleThreadTaskRunner> task_runner_;
   scoped_refptr<CastEnvironment> cast_environment_;
   std::unique_ptr<EncodingEventSubscriber> event_subscriber_;
@@ -75,7 +73,7 @@
 TEST_F(EncodingEventSubscriberTest, FrameEventTruncating) {
   Init(VIDEO_EVENT);
 
-  base::TimeTicks now(testing_clock_->NowTicks());
+  base::TimeTicks now(testing_clock_.NowTicks());
 
   // Entry with RTP timestamp 0 should get dropped.
   int width = 320;
@@ -130,7 +128,7 @@
 TEST_F(EncodingEventSubscriberTest, PacketEventTruncating) {
   Init(AUDIO_EVENT);
 
-  base::TimeTicks now(testing_clock_->NowTicks());
+  base::TimeTicks now(testing_clock_.NowTicks());
 
   // Entry with RTP timestamp 0 should get dropped.
   for (int i = 0; i < 11; i++) {
@@ -157,7 +155,7 @@
   Init(VIDEO_EVENT);
   size_t num_frame_event_protos = 3;
   size_t num_packet_event_protos = kMaxProtosPerFrame - num_frame_event_protos;
-  base::TimeTicks now(testing_clock_->NowTicks());
+  base::TimeTicks now(testing_clock_.NowTicks());
 
   for (size_t i = 0; i < num_frame_event_protos; i++) {
     for (int j = 0; j < kMaxEventsPerProto; j++) {
@@ -203,7 +201,7 @@
 TEST_F(EncodingEventSubscriberTest, EventFiltering) {
   Init(VIDEO_EVENT);
 
-  base::TimeTicks now(testing_clock_->NowTicks());
+  base::TimeTicks now(testing_clock_.NowTicks());
   RtpTimeTicks rtp_timestamp = RtpTimeTicks().Expand(UINT32_C(100));
   std::unique_ptr<FrameEvent> video_event(new FrameEvent());
   video_event->timestamp = now;
@@ -240,7 +238,7 @@
 
 TEST_F(EncodingEventSubscriberTest, FrameEvent) {
   Init(VIDEO_EVENT);
-  base::TimeTicks now(testing_clock_->NowTicks());
+  base::TimeTicks now(testing_clock_.NowTicks());
   RtpTimeTicks rtp_timestamp = RtpTimeTicks().Expand(UINT32_C(100));
   std::unique_ptr<FrameEvent> decode_event(new FrameEvent());
   decode_event->timestamp = now;
@@ -275,7 +273,7 @@
 
 TEST_F(EncodingEventSubscriberTest, FrameEventDelay) {
   Init(AUDIO_EVENT);
-  base::TimeTicks now(testing_clock_->NowTicks());
+  base::TimeTicks now(testing_clock_.NowTicks());
   RtpTimeTicks rtp_timestamp = RtpTimeTicks().Expand(UINT32_C(100));
   int delay_ms = 100;
   std::unique_ptr<FrameEvent> playout_event(new FrameEvent());
@@ -310,7 +308,7 @@
 
 TEST_F(EncodingEventSubscriberTest, FrameEventSize) {
   Init(VIDEO_EVENT);
-  base::TimeTicks now(testing_clock_->NowTicks());
+  base::TimeTicks now(testing_clock_.NowTicks());
   RtpTimeTicks rtp_timestamp = RtpTimeTicks().Expand(UINT32_C(100));
   int size = 123;
   bool key_frame = true;
@@ -359,7 +357,7 @@
   Init(AUDIO_EVENT);
   RtpTimeTicks rtp_timestamp1 = RtpTimeTicks().Expand(UINT32_C(100));
   RtpTimeTicks rtp_timestamp2 = rtp_timestamp1.Expand(UINT32_C(200));
-  base::TimeTicks now1(testing_clock_->NowTicks());
+  base::TimeTicks now1(testing_clock_.NowTicks());
   std::unique_ptr<FrameEvent> playout_event(new FrameEvent());
   playout_event->timestamp = now1;
   playout_event->type = FRAME_PLAYOUT;
@@ -370,7 +368,7 @@
   cast_environment_->logger()->DispatchFrameEvent(std::move(playout_event));
 
   task_runner_->Sleep(base::TimeDelta::FromMilliseconds(20));
-  base::TimeTicks now2(testing_clock_->NowTicks());
+  base::TimeTicks now2(testing_clock_.NowTicks());
   std::unique_ptr<FrameEvent> encode_event(new FrameEvent());
   encode_event->timestamp = now2;
   encode_event->type = FRAME_ENCODED;
@@ -383,7 +381,7 @@
   cast_environment_->logger()->DispatchFrameEvent(std::move(encode_event));
 
   task_runner_->Sleep(base::TimeDelta::FromMilliseconds(20));
-  base::TimeTicks now3(testing_clock_->NowTicks());
+  base::TimeTicks now3(testing_clock_.NowTicks());
   std::unique_ptr<FrameEvent> decode_event(new FrameEvent());
   decode_event->timestamp = now3;
   decode_event->type = FRAME_DECODED;
@@ -433,7 +431,7 @@
 
 TEST_F(EncodingEventSubscriberTest, PacketEvent) {
   Init(AUDIO_EVENT);
-  base::TimeTicks now(testing_clock_->NowTicks());
+  base::TimeTicks now(testing_clock_.NowTicks());
   RtpTimeTicks rtp_timestamp = RtpTimeTicks().Expand(UINT32_C(100));
   int packet_id = 2;
   int size = 100;
@@ -475,7 +473,7 @@
 
 TEST_F(EncodingEventSubscriberTest, MultiplePacketEventsForPacket) {
   Init(VIDEO_EVENT);
-  base::TimeTicks now1(testing_clock_->NowTicks());
+  base::TimeTicks now1(testing_clock_.NowTicks());
   RtpTimeTicks rtp_timestamp = RtpTimeTicks().Expand(UINT32_C(100));
   int packet_id = 2;
   int size = 100;
@@ -491,7 +489,7 @@
   cast_environment_->logger()->DispatchPacketEvent(std::move(send_event));
 
   task_runner_->Sleep(base::TimeDelta::FromMilliseconds(20));
-  base::TimeTicks now2(testing_clock_->NowTicks());
+  base::TimeTicks now2(testing_clock_.NowTicks());
   std::unique_ptr<PacketEvent> retransmit_event(new PacketEvent());
   retransmit_event->timestamp = now2;
   retransmit_event->type = PACKET_RETRANSMITTED;
@@ -529,7 +527,7 @@
 
 TEST_F(EncodingEventSubscriberTest, MultiplePacketEventsForFrame) {
   Init(VIDEO_EVENT);
-  base::TimeTicks now1(testing_clock_->NowTicks());
+  base::TimeTicks now1(testing_clock_.NowTicks());
   RtpTimeTicks rtp_timestamp = RtpTimeTicks().Expand(UINT32_C(100));
   int packet_id_1 = 2;
   int packet_id_2 = 3;
@@ -546,7 +544,7 @@
   cast_environment_->logger()->DispatchPacketEvent(std::move(send_event));
 
   task_runner_->Sleep(base::TimeDelta::FromMilliseconds(20));
-  base::TimeTicks now2(testing_clock_->NowTicks());
+  base::TimeTicks now2(testing_clock_.NowTicks());
   std::unique_ptr<PacketEvent> retransmit_event(new PacketEvent());
   retransmit_event->timestamp = now2;
   retransmit_event->type = PACKET_RETRANSMITTED;
@@ -589,7 +587,7 @@
 
 TEST_F(EncodingEventSubscriberTest, MultiplePacketEvents) {
   Init(VIDEO_EVENT);
-  base::TimeTicks now1(testing_clock_->NowTicks());
+  base::TimeTicks now1(testing_clock_.NowTicks());
   RtpTimeTicks rtp_timestamp_1 = RtpTimeTicks().Expand(UINT32_C(100));
   RtpTimeTicks rtp_timestamp_2 = rtp_timestamp_1.Expand(UINT32_C(200));
   int packet_id_1 = 2;
@@ -607,7 +605,7 @@
   cast_environment_->logger()->DispatchPacketEvent(std::move(send_event));
 
   task_runner_->Sleep(base::TimeDelta::FromMilliseconds(20));
-  base::TimeTicks now2(testing_clock_->NowTicks());
+  base::TimeTicks now2(testing_clock_.NowTicks());
   std::unique_ptr<PacketEvent> retransmit_event(new PacketEvent());
   retransmit_event->timestamp = now2;
   retransmit_event->type = PACKET_RETRANSMITTED;
@@ -659,7 +657,7 @@
 TEST_F(EncodingEventSubscriberTest, FirstRtpTimeTicks) {
   Init(VIDEO_EVENT);
   RtpTimeTicks rtp_timestamp = RtpTimeTicks().Expand(UINT32_C(12345));
-  base::TimeTicks now(testing_clock_->NowTicks());
+  base::TimeTicks now(testing_clock_.NowTicks());
 
   std::unique_ptr<FrameEvent> capture_begin_event(new FrameEvent());
   capture_begin_event->timestamp = now;
@@ -710,7 +708,7 @@
 TEST_F(EncodingEventSubscriberTest, RelativeRtpTimeTicksWrapAround) {
   Init(VIDEO_EVENT);
   RtpTimeTicks rtp_timestamp = RtpTimeTicks() - RtpTimeDelta::FromTicks(20);
-  base::TimeTicks now(testing_clock_->NowTicks());
+  base::TimeTicks now(testing_clock_.NowTicks());
 
   std::unique_ptr<FrameEvent> capture_begin_event(new FrameEvent());
   capture_begin_event->timestamp = now;
@@ -749,7 +747,7 @@
   RtpTimeTicks rtp_timestamp = RtpTimeTicks().Expand(UINT32_C(100));
   for (int i = 0; i < kMaxEventsPerProto + 1; i++) {
     std::unique_ptr<FrameEvent> ack_event(new FrameEvent());
-    ack_event->timestamp = testing_clock_->NowTicks();
+    ack_event->timestamp = testing_clock_.NowTicks();
     ack_event->type = FRAME_ACK_RECEIVED;
     ack_event->media_type = VIDEO_EVENT;
     ack_event->rtp_timestamp = rtp_timestamp;
@@ -771,7 +769,7 @@
 
   for (int i = 0; i < kMaxPacketsPerFrame + 1; i++) {
     std::unique_ptr<PacketEvent> send_event(new PacketEvent());
-    send_event->timestamp = testing_clock_->NowTicks();
+    send_event->timestamp = testing_clock_.NowTicks();
     send_event->type = PACKET_SENT_TO_NETWORK;
     send_event->media_type = VIDEO_EVENT;
     send_event->rtp_timestamp = rtp_timestamp;
@@ -802,7 +800,7 @@
 
   for (int j = 0; j < kMaxEventsPerProto + 1; j++) {
     std::unique_ptr<PacketEvent> send_event(new PacketEvent());
-    send_event->timestamp = testing_clock_->NowTicks();
+    send_event->timestamp = testing_clock_.NowTicks();
     send_event->type = PACKET_SENT_TO_NETWORK;
     send_event->media_type = VIDEO_EVENT;
     send_event->rtp_timestamp = rtp_timestamp;
diff --git a/media/cast/logging/receiver_time_offset_estimator_impl_unittest.cc b/media/cast/logging/receiver_time_offset_estimator_impl_unittest.cc
index 13f32c3f..2a3788b 100644
--- a/media/cast/logging/receiver_time_offset_estimator_impl_unittest.cc
+++ b/media/cast/logging/receiver_time_offset_estimator_impl_unittest.cc
@@ -23,13 +23,11 @@
 class ReceiverTimeOffsetEstimatorImplTest : public ::testing::Test {
  protected:
   ReceiverTimeOffsetEstimatorImplTest()
-      : sender_clock_(new base::SimpleTestTickClock()),
-        task_runner_(new FakeSingleThreadTaskRunner(sender_clock_)),
-        cast_environment_(
-            new CastEnvironment(std::unique_ptr<base::TickClock>(sender_clock_),
-                                task_runner_,
-                                task_runner_,
-                                task_runner_)) {
+      : task_runner_(new FakeSingleThreadTaskRunner(&sender_clock_)),
+        cast_environment_(new CastEnvironment(&sender_clock_,
+                                              task_runner_,
+                                              task_runner_,
+                                              task_runner_)) {
     cast_environment_->logger()->Subscribe(&estimator_);
   }
 
@@ -42,7 +40,7 @@
     receiver_clock_.Advance(time);
   }
 
-  base::SimpleTestTickClock* sender_clock_;  // Owned by CastEnvironment.
+  base::SimpleTestTickClock sender_clock_;
   scoped_refptr<FakeSingleThreadTaskRunner> task_runner_;
   scoped_refptr<CastEnvironment> cast_environment_;
   base::SimpleTestTickClock receiver_clock_;
@@ -69,7 +67,7 @@
   AdvanceClocks(base::TimeDelta::FromMilliseconds(20));
 
   std::unique_ptr<FrameEvent> encode_event(new FrameEvent());
-  encode_event->timestamp = sender_clock_->NowTicks();
+  encode_event->timestamp = sender_clock_.NowTicks();
   encode_event->type = FRAME_ENCODED;
   encode_event->media_type = VIDEO_EVENT;
   encode_event->rtp_timestamp = rtp_timestamp;
@@ -82,7 +80,7 @@
   cast_environment_->logger()->DispatchFrameEvent(std::move(encode_event));
 
   std::unique_ptr<PacketEvent> send_event(new PacketEvent());
-  send_event->timestamp = sender_clock_->NowTicks();
+  send_event->timestamp = sender_clock_.NowTicks();
   send_event->type = PACKET_SENT_TO_NETWORK;
   send_event->media_type = VIDEO_EVENT;
   send_event->rtp_timestamp = rtp_timestamp;
@@ -118,7 +116,7 @@
 
   AdvanceClocks(base::TimeDelta::FromMilliseconds(30));
   std::unique_ptr<FrameEvent> ack_event(new FrameEvent());
-  ack_event->timestamp = sender_clock_->NowTicks();
+  ack_event->timestamp = sender_clock_.NowTicks();
   ack_event->type = FRAME_ACK_RECEIVED;
   ack_event->media_type = VIDEO_EVENT;
   ack_event->rtp_timestamp = rtp_timestamp;
@@ -152,7 +150,7 @@
   AdvanceClocks(base::TimeDelta::FromMilliseconds(20));
 
   std::unique_ptr<FrameEvent> encode_event(new FrameEvent());
-  encode_event->timestamp = sender_clock_->NowTicks();
+  encode_event->timestamp = sender_clock_.NowTicks();
   encode_event->type = FRAME_ENCODED;
   encode_event->media_type = VIDEO_EVENT;
   encode_event->rtp_timestamp = rtp_timestamp;
@@ -165,7 +163,7 @@
   cast_environment_->logger()->DispatchFrameEvent(std::move(encode_event));
 
   std::unique_ptr<PacketEvent> send_event(new PacketEvent());
-  send_event->timestamp = sender_clock_->NowTicks();
+  send_event->timestamp = sender_clock_.NowTicks();
   send_event->type = PACKET_SENT_TO_NETWORK;
   send_event->media_type = VIDEO_EVENT;
   send_event->rtp_timestamp = rtp_timestamp;
@@ -180,7 +178,7 @@
   AdvanceClocks(base::TimeDelta::FromMilliseconds(10));
   base::TimeTicks event_b_time = receiver_clock_.NowTicks();
   AdvanceClocks(base::TimeDelta::FromMilliseconds(30));
-  base::TimeTicks event_c_time = sender_clock_->NowTicks();
+  base::TimeTicks event_c_time = sender_clock_.NowTicks();
 
   std::unique_ptr<FrameEvent> ack_event(new FrameEvent());
   ack_event->timestamp = event_c_time;
@@ -244,7 +242,7 @@
   // Events times in chronological order: 20, 30 x2, 50, 55, 60, 77, 80, 110
   AdvanceClocks(base::TimeDelta::FromMilliseconds(20));
   std::unique_ptr<FrameEvent> encode_event(new FrameEvent());
-  encode_event->timestamp = sender_clock_->NowTicks();
+  encode_event->timestamp = sender_clock_.NowTicks();
   encode_event->type = FRAME_ENCODED;
   encode_event->media_type = VIDEO_EVENT;
   encode_event->rtp_timestamp = rtp_timestamp_a;
@@ -257,7 +255,7 @@
   cast_environment_->logger()->DispatchFrameEvent(std::move(encode_event));
 
   std::unique_ptr<PacketEvent> send_event(new PacketEvent());
-  send_event->timestamp = sender_clock_->NowTicks();
+  send_event->timestamp = sender_clock_.NowTicks();
   send_event->type = PACKET_SENT_TO_NETWORK;
   send_event->media_type = VIDEO_EVENT;
   send_event->rtp_timestamp = rtp_timestamp_a;
@@ -269,7 +267,7 @@
 
   AdvanceClocks(base::TimeDelta::FromMilliseconds(10));
   encode_event.reset(new FrameEvent());
-  encode_event->timestamp = sender_clock_->NowTicks();
+  encode_event->timestamp = sender_clock_.NowTicks();
   encode_event->type = FRAME_ENCODED;
   encode_event->media_type = VIDEO_EVENT;
   encode_event->rtp_timestamp = rtp_timestamp_b;
@@ -282,7 +280,7 @@
   cast_environment_->logger()->DispatchFrameEvent(std::move(encode_event));
 
   send_event.reset(new PacketEvent());
-  send_event->timestamp = sender_clock_->NowTicks();
+  send_event->timestamp = sender_clock_.NowTicks();
   send_event->type = PACKET_SENT_TO_NETWORK;
   send_event->media_type = VIDEO_EVENT;
   send_event->rtp_timestamp = rtp_timestamp_b;
@@ -323,7 +321,7 @@
 
   AdvanceClocks(base::TimeDelta::FromMilliseconds(5));
   std::unique_ptr<FrameEvent> ack_event(new FrameEvent());
-  ack_event->timestamp = sender_clock_->NowTicks();
+  ack_event->timestamp = sender_clock_.NowTicks();
   ack_event->type = FRAME_ACK_RECEIVED;
   ack_event->media_type = VIDEO_EVENT;
   ack_event->rtp_timestamp = rtp_timestamp_b;
@@ -332,7 +330,7 @@
 
   AdvanceClocks(base::TimeDelta::FromMilliseconds(5));
   ack_event.reset(new FrameEvent());
-  ack_event->timestamp = sender_clock_->NowTicks();
+  ack_event->timestamp = sender_clock_.NowTicks();
   ack_event->type = FRAME_ACK_RECEIVED;
   ack_event->media_type = VIDEO_EVENT;
   ack_event->rtp_timestamp = rtp_timestamp_a;
@@ -341,7 +339,7 @@
 
   AdvanceClocks(base::TimeDelta::FromMilliseconds(17));
   encode_event.reset(new FrameEvent());
-  encode_event->timestamp = sender_clock_->NowTicks();
+  encode_event->timestamp = sender_clock_.NowTicks();
   encode_event->type = FRAME_ENCODED;
   encode_event->media_type = VIDEO_EVENT;
   encode_event->rtp_timestamp = rtp_timestamp_c;
@@ -354,7 +352,7 @@
   cast_environment_->logger()->DispatchFrameEvent(std::move(encode_event));
 
   send_event.reset(new PacketEvent());
-  send_event->timestamp = sender_clock_->NowTicks();
+  send_event->timestamp = sender_clock_.NowTicks();
   send_event->type = PACKET_SENT_TO_NETWORK;
   send_event->media_type = VIDEO_EVENT;
   send_event->rtp_timestamp = rtp_timestamp_c;
@@ -386,7 +384,7 @@
 
   AdvanceClocks(base::TimeDelta::FromMilliseconds(30));
   ack_event.reset(new FrameEvent());
-  ack_event->timestamp = sender_clock_->NowTicks();
+  ack_event->timestamp = sender_clock_.NowTicks();
   ack_event->type = FRAME_ACK_RECEIVED;
   ack_event->media_type = VIDEO_EVENT;
   ack_event->rtp_timestamp = rtp_timestamp_c;
diff --git a/media/cast/logging/simple_event_subscriber_unittest.cc b/media/cast/logging/simple_event_subscriber_unittest.cc
index b4edec61..48f1d371 100644
--- a/media/cast/logging/simple_event_subscriber_unittest.cc
+++ b/media/cast/logging/simple_event_subscriber_unittest.cc
@@ -21,13 +21,11 @@
 class SimpleEventSubscriberTest : public ::testing::Test {
  protected:
   SimpleEventSubscriberTest()
-      : testing_clock_(new base::SimpleTestTickClock()),
-        task_runner_(new FakeSingleThreadTaskRunner(testing_clock_)),
-        cast_environment_(new CastEnvironment(
-            std::unique_ptr<base::TickClock>(testing_clock_),
-            task_runner_,
-            task_runner_,
-            task_runner_)) {
+      : task_runner_(new FakeSingleThreadTaskRunner(&testing_clock_)),
+        cast_environment_(new CastEnvironment(&testing_clock_,
+                                              task_runner_,
+                                              task_runner_,
+                                              task_runner_)) {
     cast_environment_->logger()->Subscribe(&event_subscriber_);
   }
 
@@ -35,7 +33,7 @@
     cast_environment_->logger()->Unsubscribe(&event_subscriber_);
   }
 
-  base::SimpleTestTickClock* testing_clock_;  // Owned by CastEnvironment.
+  base::SimpleTestTickClock testing_clock_;
   scoped_refptr<FakeSingleThreadTaskRunner> task_runner_;
   scoped_refptr<CastEnvironment> cast_environment_;
   SimpleEventSubscriber event_subscriber_;
@@ -44,7 +42,7 @@
 TEST_F(SimpleEventSubscriberTest, GetAndResetEvents) {
   // Log some frame events.
   std::unique_ptr<FrameEvent> encode_event(new FrameEvent());
-  encode_event->timestamp = testing_clock_->NowTicks();
+  encode_event->timestamp = testing_clock_.NowTicks();
   encode_event->type = FRAME_ENCODED;
   encode_event->media_type = AUDIO_EVENT;
   encode_event->rtp_timestamp = RtpTimeTicks().Expand(UINT32_C(100));
@@ -57,7 +55,7 @@
   cast_environment_->logger()->DispatchFrameEvent(std::move(encode_event));
 
   std::unique_ptr<FrameEvent> playout_event(new FrameEvent());
-  playout_event->timestamp = testing_clock_->NowTicks();
+  playout_event->timestamp = testing_clock_.NowTicks();
   playout_event->type = FRAME_PLAYOUT;
   playout_event->media_type = AUDIO_EVENT;
   playout_event->rtp_timestamp = RtpTimeTicks().Expand(UINT32_C(100));
@@ -66,7 +64,7 @@
   cast_environment_->logger()->DispatchFrameEvent(std::move(playout_event));
 
   std::unique_ptr<FrameEvent> decode_event(new FrameEvent());
-  decode_event->timestamp = testing_clock_->NowTicks();
+  decode_event->timestamp = testing_clock_.NowTicks();
   decode_event->type = FRAME_DECODED;
   decode_event->media_type = AUDIO_EVENT;
   decode_event->rtp_timestamp = RtpTimeTicks().Expand(UINT32_C(200));
@@ -75,7 +73,7 @@
 
   // Log some packet events.
   std::unique_ptr<PacketEvent> receive_event(new PacketEvent());
-  receive_event->timestamp = testing_clock_->NowTicks();
+  receive_event->timestamp = testing_clock_.NowTicks();
   receive_event->type = PACKET_RECEIVED;
   receive_event->media_type = AUDIO_EVENT;
   receive_event->rtp_timestamp = RtpTimeTicks().Expand(UINT32_C(200));
@@ -86,7 +84,7 @@
   cast_environment_->logger()->DispatchPacketEvent(std::move(receive_event));
 
   receive_event.reset(new PacketEvent());
-  receive_event->timestamp = testing_clock_->NowTicks();
+  receive_event->timestamp = testing_clock_.NowTicks();
   receive_event->type = PACKET_RECEIVED;
   receive_event->media_type = VIDEO_EVENT;
   receive_event->rtp_timestamp = RtpTimeTicks().Expand(UINT32_C(200));
diff --git a/media/cast/logging/stats_event_subscriber_unittest.cc b/media/cast/logging/stats_event_subscriber_unittest.cc
index ca8ca35..bd5881f 100644
--- a/media/cast/logging/stats_event_subscriber_unittest.cc
+++ b/media/cast/logging/stats_event_subscriber_unittest.cc
@@ -31,13 +31,11 @@
 class StatsEventSubscriberTest : public ::testing::Test {
  protected:
   StatsEventSubscriberTest()
-      : sender_clock_(new base::SimpleTestTickClock()),
-        task_runner_(new FakeSingleThreadTaskRunner(sender_clock_)),
-        cast_environment_(
-            new CastEnvironment(std::unique_ptr<base::TickClock>(sender_clock_),
-                                task_runner_,
-                                task_runner_,
-                                task_runner_)),
+      : task_runner_(new FakeSingleThreadTaskRunner(&sender_clock_)),
+        cast_environment_(new CastEnvironment(&sender_clock_,
+                                              task_runner_,
+                                              task_runner_,
+                                              task_runner_)),
         fake_offset_estimator_(
             base::TimeDelta::FromSeconds(kReceiverOffsetSecs)) {
     receiver_clock_.Advance(base::TimeDelta::FromSeconds(kReceiverOffsetSecs));
@@ -62,7 +60,7 @@
     cast_environment_->logger()->Subscribe(subscriber_.get());
   }
 
-  base::SimpleTestTickClock* sender_clock_;  // Owned by CastEnvironment.
+  base::SimpleTestTickClock sender_clock_;
   base::SimpleTestTickClock receiver_clock_;
   scoped_refptr<FakeSingleThreadTaskRunner> task_runner_;
   scoped_refptr<CastEnvironment> cast_environment_;
@@ -80,11 +78,11 @@
   // when computing dropped frames.
   int num_frames = StatsEventSubscriber::kMaxFrameInfoMapSize + 50;
   int dropped_frames = 0;
-  base::TimeTicks start_time = sender_clock_->NowTicks();
+  base::TimeTicks start_time = sender_clock_.NowTicks();
   // Drop half the frames during the encode step.
   for (int i = 0; i < num_frames; i++) {
     std::unique_ptr<FrameEvent> capture_begin_event(new FrameEvent());
-    capture_begin_event->timestamp = sender_clock_->NowTicks();
+    capture_begin_event->timestamp = sender_clock_.NowTicks();
     capture_begin_event->type = FRAME_CAPTURE_BEGIN;
     capture_begin_event->media_type = VIDEO_EVENT;
     capture_begin_event->rtp_timestamp = rtp_timestamp;
@@ -93,7 +91,7 @@
 
     AdvanceClocks(base::TimeDelta::FromMicroseconds(10));
     std::unique_ptr<FrameEvent> capture_end_event(new FrameEvent());
-    capture_end_event->timestamp = sender_clock_->NowTicks();
+    capture_end_event->timestamp = sender_clock_.NowTicks();
     capture_end_event->type = FRAME_CAPTURE_END;
     capture_end_event->media_type = VIDEO_EVENT;
     capture_end_event->rtp_timestamp = rtp_timestamp;
@@ -103,7 +101,7 @@
     if (i % 2 == 0) {
       AdvanceClocks(base::TimeDelta::FromMicroseconds(10));
       std::unique_ptr<FrameEvent> encode_event(new FrameEvent());
-      encode_event->timestamp = sender_clock_->NowTicks();
+      encode_event->timestamp = sender_clock_.NowTicks();
       encode_event->type = FRAME_ENCODED;
       encode_event->media_type = VIDEO_EVENT;
       encode_event->rtp_timestamp = rtp_timestamp;
@@ -122,7 +120,7 @@
     frame_id++;
   }
 
-  base::TimeTicks end_time = sender_clock_->NowTicks();
+  base::TimeTicks end_time = sender_clock_.NowTicks();
 
   StatsEventSubscriber::StatsMap stats_map;
   subscriber_->GetStatsInternal(&stats_map);
@@ -158,16 +156,16 @@
   RtpTimeTicks rtp_timestamp;
   FrameId frame_id = FrameId::first();
   int num_frames = 10;
-  base::TimeTicks start_time = sender_clock_->NowTicks();
+  base::TimeTicks start_time = sender_clock_.NowTicks();
   AdvanceClocks(base::TimeDelta::FromMicroseconds(35678));
-  base::TimeTicks first_event_time = sender_clock_->NowTicks();
+  base::TimeTicks first_event_time = sender_clock_.NowTicks();
   base::TimeTicks last_event_time;
   int total_size = 0;
   for (int i = 0; i < num_frames; i++) {
     int size = 1000 + base::RandInt(-100, 100);
     total_size += size;
     std::unique_ptr<FrameEvent> encode_event(new FrameEvent());
-    encode_event->timestamp = sender_clock_->NowTicks();
+    encode_event->timestamp = sender_clock_.NowTicks();
     encode_event->type = FRAME_ENCODED;
     encode_event->media_type = VIDEO_EVENT;
     encode_event->rtp_timestamp = rtp_timestamp;
@@ -178,14 +176,14 @@
     encode_event->encoder_cpu_utilization = 9.10;
     encode_event->idealized_bitrate_utilization = 11.12;
     cast_environment_->logger()->DispatchFrameEvent(std::move(encode_event));
-    last_event_time = sender_clock_->NowTicks();
+    last_event_time = sender_clock_.NowTicks();
 
     AdvanceClocks(base::TimeDelta::FromMicroseconds(35678));
     rtp_timestamp += RtpTimeDelta::FromTicks(90);
     frame_id++;
   }
 
-  base::TimeTicks end_time = sender_clock_->NowTicks();
+  base::TimeTicks end_time = sender_clock_.NowTicks();
 
   StatsEventSubscriber::StatsMap stats_map;
   subscriber_->GetStatsInternal(&stats_map);
@@ -226,7 +224,7 @@
   RtpTimeTicks rtp_timestamp;
   FrameId frame_id = FrameId::first();
   int num_frames = 10;
-  base::TimeTicks start_time = sender_clock_->NowTicks();
+  base::TimeTicks start_time = sender_clock_.NowTicks();
   for (int i = 0; i < num_frames; i++) {
     std::unique_ptr<FrameEvent> decode_event(new FrameEvent());
     decode_event->timestamp = receiver_clock_.NowTicks();
@@ -241,7 +239,7 @@
     frame_id++;
   }
 
-  base::TimeTicks end_time = sender_clock_->NowTicks();
+  base::TimeTicks end_time = sender_clock_.NowTicks();
 
   StatsEventSubscriber::StatsMap stats_map;
   subscriber_->GetStatsInternal(&stats_map);
@@ -300,7 +298,7 @@
   base::TimeDelta total_latency;
   for (int i = 0; i < num_frames; i++) {
     std::unique_ptr<FrameEvent> capture_begin_event(new FrameEvent());
-    capture_begin_event->timestamp = sender_clock_->NowTicks();
+    capture_begin_event->timestamp = sender_clock_.NowTicks();
     capture_begin_event->type = FRAME_CAPTURE_BEGIN;
     capture_begin_event->media_type = VIDEO_EVENT;
     capture_begin_event->rtp_timestamp = rtp_timestamp;
@@ -345,7 +343,7 @@
   RtpTimeTicks rtp_timestamp;
   int num_packets = 10;
   int num_latency_recorded_packets = 0;
-  base::TimeTicks start_time = sender_clock_->NowTicks();
+  base::TimeTicks start_time = sender_clock_.NowTicks();
   int total_size = 0;
   int retransmit_total_size = 0;
   base::TimeDelta total_network_latency;
@@ -356,7 +354,7 @@
   int num_packets_retransmitted = 0;
   int num_packets_rtx_rejected = 0;
 
-  base::TimeTicks sender_encoded_time = sender_clock_->NowTicks();
+  base::TimeTicks sender_encoded_time = sender_clock_.NowTicks();
   base::TimeTicks receiver_encoded_time = receiver_clock_.NowTicks();
   std::unique_ptr<FrameEvent> encode_event(new FrameEvent());
   encode_event->timestamp = sender_encoded_time;
@@ -374,7 +372,7 @@
     total_size += size;
 
     std::unique_ptr<PacketEvent> send_event(new PacketEvent());
-    send_event->timestamp = sender_clock_->NowTicks();
+    send_event->timestamp = sender_clock_.NowTicks();
     send_event->type = PACKET_SENT_TO_NETWORK;
     send_event->media_type = VIDEO_EVENT;
     send_event->rtp_timestamp = rtp_timestamp;
@@ -385,7 +383,7 @@
     cast_environment_->logger()->DispatchPacketEvent(std::move(send_event));
 
     num_packets_transmitted++;
-    total_queueing_latency += sender_clock_->NowTicks() - sender_encoded_time;
+    total_queueing_latency += sender_clock_.NowTicks() - sender_encoded_time;
 
     int latency_micros = 20000 + base::RandInt(-10000, 10000);
     base::TimeDelta latency = base::TimeDelta::FromMicroseconds(latency_micros);
@@ -487,7 +485,7 @@
     num_packets_received++;
   }
 
-  base::TimeTicks end_time = sender_clock_->NowTicks();
+  base::TimeTicks end_time = sender_clock_.NowTicks();
   base::TimeDelta duration = end_time - start_time;
 
   StatsEventSubscriber::StatsMap stats_map;
@@ -579,7 +577,7 @@
     rtp_timestamp += RtpTimeDelta::FromTicks(1);
 
     std::unique_ptr<FrameEvent> capture_begin_event(new FrameEvent());
-    capture_begin_event->timestamp = sender_clock_->NowTicks();
+    capture_begin_event->timestamp = sender_clock_.NowTicks();
     capture_begin_event->type = FRAME_CAPTURE_BEGIN;
     capture_begin_event->media_type = VIDEO_EVENT;
     capture_begin_event->rtp_timestamp = rtp_timestamp;
@@ -588,7 +586,7 @@
 
     AdvanceClocks(base::TimeDelta::FromMilliseconds(10));
     std::unique_ptr<FrameEvent> capture_end_event(new FrameEvent());
-    capture_end_event->timestamp = sender_clock_->NowTicks();
+    capture_end_event->timestamp = sender_clock_.NowTicks();
     capture_end_event->type = FRAME_CAPTURE_END;
     capture_end_event->media_type = VIDEO_EVENT;
     capture_end_event->rtp_timestamp = rtp_timestamp;
@@ -597,7 +595,7 @@
 
     AdvanceClocks(base::TimeDelta::FromMilliseconds(15));
     std::unique_ptr<FrameEvent> encode_event(new FrameEvent());
-    encode_event->timestamp = sender_clock_->NowTicks();
+    encode_event->timestamp = sender_clock_.NowTicks();
     encode_event->type = FRAME_ENCODED;
     encode_event->media_type = VIDEO_EVENT;
     encode_event->rtp_timestamp = rtp_timestamp;
@@ -615,7 +613,7 @@
   for (int i = 0; i < 3; ++i) {
     AdvanceClocks(base::TimeDelta::FromMilliseconds(100));
     std::unique_ptr<PacketEvent> send_event(new PacketEvent());
-    send_event->timestamp = sender_clock_->NowTicks();
+    send_event->timestamp = sender_clock_.NowTicks();
     send_event->type = PACKET_SENT_TO_NETWORK;
     send_event->media_type = VIDEO_EVENT;
     send_event->rtp_timestamp = rtp_timestamp;
diff --git a/media/cast/net/rtcp/receiver_rtcp_event_subscriber_unittest.cc b/media/cast/net/rtcp/receiver_rtcp_event_subscriber_unittest.cc
index b600035..20686da 100644
--- a/media/cast/net/rtcp/receiver_rtcp_event_subscriber_unittest.cc
+++ b/media/cast/net/rtcp/receiver_rtcp_event_subscriber_unittest.cc
@@ -31,13 +31,11 @@
 class ReceiverRtcpEventSubscriberTest : public ::testing::Test {
  protected:
   ReceiverRtcpEventSubscriberTest()
-      : testing_clock_(new base::SimpleTestTickClock()),
-        task_runner_(new FakeSingleThreadTaskRunner(testing_clock_)),
-        cast_environment_(new CastEnvironment(
-            std::unique_ptr<base::TickClock>(testing_clock_),
-            task_runner_,
-            task_runner_,
-            task_runner_)) {}
+      : task_runner_(new FakeSingleThreadTaskRunner(&testing_clock_)),
+        cast_environment_(new CastEnvironment(&testing_clock_,
+                                              task_runner_,
+                                              task_runner_,
+                                              task_runner_)) {}
 
   ~ReceiverRtcpEventSubscriberTest() override = default;
 
@@ -57,7 +55,7 @@
   void InsertEvents() {
     // Video events
     std::unique_ptr<FrameEvent> playout_event(new FrameEvent());
-    playout_event->timestamp = testing_clock_->NowTicks();
+    playout_event->timestamp = testing_clock_.NowTicks();
     playout_event->type = FRAME_PLAYOUT;
     playout_event->media_type = VIDEO_EVENT;
     playout_event->rtp_timestamp = RtpTimeTicks().Expand(UINT32_C(100));
@@ -66,7 +64,7 @@
     cast_environment_->logger()->DispatchFrameEvent(std::move(playout_event));
 
     std::unique_ptr<FrameEvent> decode_event(new FrameEvent());
-    decode_event->timestamp = testing_clock_->NowTicks();
+    decode_event->timestamp = testing_clock_.NowTicks();
     decode_event->type = FRAME_DECODED;
     decode_event->media_type = VIDEO_EVENT;
     decode_event->rtp_timestamp = RtpTimeTicks().Expand(UINT32_C(200));
@@ -74,7 +72,7 @@
     cast_environment_->logger()->DispatchFrameEvent(std::move(decode_event));
 
     std::unique_ptr<PacketEvent> receive_event(new PacketEvent());
-    receive_event->timestamp = testing_clock_->NowTicks();
+    receive_event->timestamp = testing_clock_.NowTicks();
     receive_event->type = PACKET_RECEIVED;
     receive_event->media_type = VIDEO_EVENT;
     receive_event->rtp_timestamp = RtpTimeTicks().Expand(UINT32_C(200));
@@ -86,7 +84,7 @@
 
     // Audio events
     playout_event.reset(new FrameEvent());
-    playout_event->timestamp = testing_clock_->NowTicks();
+    playout_event->timestamp = testing_clock_.NowTicks();
     playout_event->type = FRAME_PLAYOUT;
     playout_event->media_type = AUDIO_EVENT;
     playout_event->rtp_timestamp = RtpTimeTicks().Expand(UINT32_C(300));
@@ -95,7 +93,7 @@
     cast_environment_->logger()->DispatchFrameEvent(std::move(playout_event));
 
     decode_event.reset(new FrameEvent());
-    decode_event->timestamp = testing_clock_->NowTicks();
+    decode_event->timestamp = testing_clock_.NowTicks();
     decode_event->type = FRAME_DECODED;
     decode_event->media_type = AUDIO_EVENT;
     decode_event->rtp_timestamp = RtpTimeTicks().Expand(UINT32_C(400));
@@ -103,7 +101,7 @@
     cast_environment_->logger()->DispatchFrameEvent(std::move(decode_event));
 
     receive_event.reset(new PacketEvent());
-    receive_event->timestamp = testing_clock_->NowTicks();
+    receive_event->timestamp = testing_clock_.NowTicks();
     receive_event->type = PACKET_RECEIVED;
     receive_event->media_type = AUDIO_EVENT;
     receive_event->rtp_timestamp = RtpTimeTicks().Expand(UINT32_C(400));
@@ -115,7 +113,7 @@
 
     // Unrelated events
     std::unique_ptr<FrameEvent> encode_event(new FrameEvent());
-    encode_event->timestamp = testing_clock_->NowTicks();
+    encode_event->timestamp = testing_clock_.NowTicks();
     encode_event->type = FRAME_ENCODED;
     encode_event->media_type = VIDEO_EVENT;
     encode_event->rtp_timestamp = RtpTimeTicks().Expand(UINT32_C(100));
@@ -123,7 +121,7 @@
     cast_environment_->logger()->DispatchFrameEvent(std::move(encode_event));
 
     encode_event.reset(new FrameEvent());
-    encode_event->timestamp = testing_clock_->NowTicks();
+    encode_event->timestamp = testing_clock_.NowTicks();
     encode_event->type = FRAME_ENCODED;
     encode_event->media_type = AUDIO_EVENT;
     encode_event->rtp_timestamp = RtpTimeTicks().Expand(UINT32_C(100));
@@ -131,7 +129,7 @@
     cast_environment_->logger()->DispatchFrameEvent(std::move(encode_event));
   }
 
-  base::SimpleTestTickClock* testing_clock_;  // Owned by CastEnvironment.
+  base::SimpleTestTickClock testing_clock_;
   scoped_refptr<FakeSingleThreadTaskRunner> task_runner_;
   scoped_refptr<CastEnvironment> cast_environment_;
   std::unique_ptr<ReceiverRtcpEventSubscriber> event_subscriber_;
@@ -160,7 +158,7 @@
 
   for (int i = 1; i <= 10; ++i) {
     std::unique_ptr<FrameEvent> decode_event(new FrameEvent());
-    decode_event->timestamp = testing_clock_->NowTicks();
+    decode_event->timestamp = testing_clock_.NowTicks();
     decode_event->type = FRAME_DECODED;
     decode_event->media_type = VIDEO_EVENT;
     decode_event->rtp_timestamp =
diff --git a/media/cast/receiver/frame_receiver_unittest.cc b/media/cast/receiver/frame_receiver_unittest.cc
index 70ddd84c..1aa9d5b 100644
--- a/media/cast/receiver/frame_receiver_unittest.cc
+++ b/media/cast/receiver/frame_receiver_unittest.cc
@@ -74,14 +74,12 @@
 class FrameReceiverTest : public ::testing::Test {
  protected:
   FrameReceiverTest() {
-    testing_clock_ = new base::SimpleTestTickClock();
-    testing_clock_->Advance(base::TimeTicks::Now() - base::TimeTicks());
-    start_time_ = testing_clock_->NowTicks();
-    task_runner_ = new FakeSingleThreadTaskRunner(testing_clock_);
+    testing_clock_.Advance(base::TimeTicks::Now() - base::TimeTicks());
+    start_time_ = testing_clock_.NowTicks();
+    task_runner_ = new FakeSingleThreadTaskRunner(&testing_clock_);
 
-    cast_environment_ =
-        new CastEnvironment(std::unique_ptr<base::TickClock>(testing_clock_),
-                            task_runner_, task_runner_, task_runner_);
+    cast_environment_ = new CastEnvironment(&testing_clock_, task_runner_,
+                                            task_runner_, task_runner_);
   }
 
   ~FrameReceiverTest() override = default;
@@ -124,7 +122,7 @@
   }
 
   void FeedLipSyncInfoIntoReceiver() {
-    const base::TimeTicks now = testing_clock_->NowTicks();
+    const base::TimeTicks now = testing_clock_.NowTicks();
     const RtpTimeTicks rtp_timestamp =
         RtpTimeTicks::FromTimeDelta(now - start_time_, config_.rtp_timebase);
     CHECK_LE(RtpTimeTicks(), rtp_timestamp);
@@ -140,7 +138,7 @@
   FrameReceiverConfig config_;
   std::vector<uint8_t> payload_;
   RtpCastHeader rtp_header_;
-  base::SimpleTestTickClock* testing_clock_;  // Owned by CastEnvironment.
+  base::SimpleTestTickClock testing_clock_;
   base::TimeTicks start_time_;
   MockCastTransport mock_transport_;
   scoped_refptr<FakeSingleThreadTaskRunner> task_runner_;
@@ -210,7 +208,7 @@
   const base::TimeDelta target_playout_delay =
       base::TimeDelta::FromMilliseconds(kPlayoutDelayMillis);
   frame_client_.AddExpectedResult(
-      GetFirstTestFrameId(), testing_clock_->NowTicks() + target_playout_delay);
+      GetFirstTestFrameId(), testing_clock_.NowTicks() + target_playout_delay);
   FeedOneFrameIntoReceiver();
   task_runner_->RunTasks();
   EXPECT_EQ(1, frame_client_.number_times_called());
@@ -253,7 +251,7 @@
   // Feed and process lip sync in receiver.
   FeedLipSyncInfoIntoReceiver();
   task_runner_->RunTasks();
-  const base::TimeTicks first_frame_capture_time = testing_clock_->NowTicks();
+  const base::TimeTicks first_frame_capture_time = testing_clock_.NowTicks();
 
   // Enqueue a request for a frame.
   const ReceiveEncodedFrameCallback frame_encoded_callback =
@@ -301,7 +299,7 @@
   // Now, advance time forward such that the receiver is convinced it should
   // skip Frame 2.  Frame 3 is emitted (to satisfy the second request) because a
   // decision was made to skip over the no-show Frame 2.
-  testing_clock_->Advance(2 * time_advance_per_frame + target_playout_delay);
+  testing_clock_.Advance(2 * time_advance_per_frame + target_playout_delay);
   task_runner_->RunTasks();
   EXPECT_EQ(2, frame_client_.number_times_called());
 
@@ -319,7 +317,7 @@
 
   // Move forward to the playout time of an unreceived Frame 5.  Expect no
   // additional frames were emitted.
-  testing_clock_->Advance(3 * time_advance_per_frame);
+  testing_clock_.Advance(3 * time_advance_per_frame);
   task_runner_->RunTasks();
   EXPECT_EQ(3, frame_client_.number_times_called());
 
@@ -367,7 +365,7 @@
   // Feed and process lip sync in receiver.
   FeedLipSyncInfoIntoReceiver();
   task_runner_->RunTasks();
-  const base::TimeTicks first_frame_capture_time = testing_clock_->NowTicks();
+  const base::TimeTicks first_frame_capture_time = testing_clock_.NowTicks();
 
   // Enqueue a request for a frame.
   const ReceiveEncodedFrameCallback frame_encoded_callback =
@@ -413,7 +411,7 @@
   // Regardless, the receiver must NOT emit Frame 3 yet because it is not
   // allowed to skip frames when dependencies are not satisfied.  In other
   // words, Frame 3 is not decodable without Frame 2.
-  testing_clock_->Advance(2 * time_advance_per_frame + target_playout_delay);
+  testing_clock_.Advance(2 * time_advance_per_frame + target_playout_delay);
   task_runner_->RunTasks();
   EXPECT_EQ(1, frame_client_.number_times_called());
 
@@ -436,7 +434,7 @@
 
   // Move forward to the playout time of an unreceived Frame 5.  Expect no
   // additional frames were emitted.
-  testing_clock_->Advance(3 * time_advance_per_frame);
+  testing_clock_.Advance(3 * time_advance_per_frame);
   task_runner_->RunTasks();
   EXPECT_EQ(3, frame_client_.number_times_called());
 
diff --git a/media/cast/sender/audio_encoder_unittest.cc b/media/cast/sender/audio_encoder_unittest.cc
index 15329740..6a46f39 100644
--- a/media/cast/sender/audio_encoder_unittest.cc
+++ b/media/cast/sender/audio_encoder_unittest.cc
@@ -105,15 +105,13 @@
  public:
   AudioEncoderTest() {
     InitializeMediaLibrary();
-    testing_clock_ = new base::SimpleTestTickClock();
-    testing_clock_->Advance(base::TimeTicks::Now() - base::TimeTicks());
+    testing_clock_.Advance(base::TimeTicks::Now() - base::TimeTicks());
   }
 
   void SetUp() final {
-    task_runner_ = new FakeSingleThreadTaskRunner(testing_clock_);
-    cast_environment_ =
-        new CastEnvironment(std::unique_ptr<base::TickClock>(testing_clock_),
-                            task_runner_, task_runner_, task_runner_);
+    task_runner_ = new FakeSingleThreadTaskRunner(&testing_clock_);
+    cast_environment_ = new CastEnvironment(&testing_clock_, task_runner_,
+                                            task_runner_, task_runner_);
   }
 
   virtual ~AudioEncoderTest() = default;
@@ -131,16 +129,16 @@
       const base::TimeDelta duration = base::TimeDelta::FromMilliseconds(
           std::abs(scenario.durations_in_ms[i]));
       receiver_->SetCaptureTimeBounds(
-          testing_clock_->NowTicks() - frame_duration,
-          testing_clock_->NowTicks() + duration);
+          testing_clock_.NowTicks() - frame_duration,
+          testing_clock_.NowTicks() + duration);
       if (simulate_missing_data) {
         task_runner_->RunTasks();
-        testing_clock_->Advance(duration);
+        testing_clock_.Advance(duration);
       } else {
         audio_encoder_->InsertAudio(audio_bus_factory_->NextAudioBus(duration),
-                                    testing_clock_->NowTicks());
+                                    testing_clock_.NowTicks());
         task_runner_->RunTasks();
-        testing_clock_->Advance(duration);
+        testing_clock_.Advance(duration);
       }
     }
 
@@ -170,7 +168,7 @@
     receiver_->SetSamplesPerFrame(audio_encoder_->GetSamplesPerFrame());
   }
 
-  base::SimpleTestTickClock* testing_clock_;  // Owned by CastEnvironment.
+  base::SimpleTestTickClock testing_clock_;
   scoped_refptr<FakeSingleThreadTaskRunner> task_runner_;
   std::unique_ptr<TestAudioBusFactory> audio_bus_factory_;
   std::unique_ptr<TestEncodedAudioFrameReceiver> receiver_;
diff --git a/media/cast/sender/audio_sender_unittest.cc b/media/cast/sender/audio_sender_unittest.cc
index fa3224e0..f176afa 100644
--- a/media/cast/sender/audio_sender_unittest.cc
+++ b/media/cast/sender/audio_sender_unittest.cc
@@ -95,12 +95,10 @@
  protected:
   AudioSenderTest() {
     InitializeMediaLibrary();
-    testing_clock_ = new base::SimpleTestTickClock();
-    testing_clock_->Advance(base::TimeTicks::Now() - base::TimeTicks());
-    task_runner_ = new FakeSingleThreadTaskRunner(testing_clock_);
-    cast_environment_ =
-        new CastEnvironment(std::unique_ptr<base::TickClock>(testing_clock_),
-                            task_runner_, task_runner_, task_runner_);
+    testing_clock_.Advance(base::TimeTicks::Now() - base::TimeTicks());
+    task_runner_ = new FakeSingleThreadTaskRunner(&testing_clock_);
+    cast_environment_ = new CastEnvironment(&testing_clock_, task_runner_,
+                                            task_runner_, task_runner_);
     audio_config_.codec = CODEC_AUDIO_OPUS;
     audio_config_.use_external_encoder = false;
     audio_config_.rtp_timebase = kDefaultAudioSamplingRate;
@@ -110,7 +108,7 @@
 
     transport_ = new TestPacketSender();
     transport_sender_.reset(new CastTransportImpl(
-        testing_clock_, base::TimeDelta(), base::MakeUnique<TransportClient>(),
+        &testing_clock_, base::TimeDelta(), base::MakeUnique<TransportClient>(),
         base::WrapUnique(transport_), task_runner_));
     OperationalStatus operational_status = STATUS_UNINITIALIZED;
     audio_sender_.reset(new AudioSender(
@@ -124,7 +122,7 @@
 
   ~AudioSenderTest() override = default;
 
-  base::SimpleTestTickClock* testing_clock_;  // Owned by CastEnvironment.
+  base::SimpleTestTickClock testing_clock_;
   TestPacketSender* transport_;               // Owned by CastTransport.
   std::unique_ptr<CastTransportImpl> transport_sender_;
   scoped_refptr<FakeSingleThreadTaskRunner> task_runner_;
@@ -140,7 +138,7 @@
                           TestAudioBusFactory::kMiddleANoteFreq, 0.5f)
           .NextAudioBus(kDuration));
 
-  audio_sender_->InsertAudio(std::move(bus), testing_clock_->NowTicks());
+  audio_sender_->InsertAudio(std::move(bus), testing_clock_.NowTicks());
   task_runner_->RunTasks();
   EXPECT_LE(1, transport_->number_of_rtp_packets());
   EXPECT_LE(1, transport_->number_of_rtcp_packets());
@@ -153,13 +151,13 @@
                           TestAudioBusFactory::kMiddleANoteFreq, 0.5f)
           .NextAudioBus(kDuration));
 
-  audio_sender_->InsertAudio(std::move(bus), testing_clock_->NowTicks());
+  audio_sender_->InsertAudio(std::move(bus), testing_clock_.NowTicks());
   task_runner_->RunTasks();
 
   // Make sure that we send at least one RTCP packet.
   base::TimeDelta max_rtcp_timeout =
       base::TimeDelta::FromMilliseconds(1 + kRtcpReportIntervalMs * 3 / 2);
-  testing_clock_->Advance(max_rtcp_timeout);
+  testing_clock_.Advance(max_rtcp_timeout);
   task_runner_->RunTasks();
   EXPECT_LE(1, transport_->number_of_rtp_packets());
   EXPECT_LE(1, transport_->number_of_rtcp_packets());
diff --git a/media/cast/sender/h264_vt_encoder_unittest.cc b/media/cast/sender/h264_vt_encoder_unittest.cc
index 98b8aba..7c1e990 100644
--- a/media/cast/sender/h264_vt_encoder_unittest.cc
+++ b/media/cast/sender/h264_vt_encoder_unittest.cc
@@ -213,16 +213,15 @@
   H264VideoToolboxEncoderTest() = default;
 
   void SetUp() final {
-    clock_ = new base::SimpleTestTickClock();
-    clock_->Advance(base::TimeTicks::Now() - base::TimeTicks());
+    clock_.Advance(base::TimeTicks::Now() - base::TimeTicks());
 
     power_source_ = new TestPowerSource();
     power_monitor_.reset(new base::PowerMonitor(
         std::unique_ptr<TestPowerSource>(power_source_)));
 
     cast_environment_ = new CastEnvironment(
-        std::unique_ptr<base::TickClock>(clock_), message_loop_.task_runner(),
-        message_loop_.task_runner(), message_loop_.task_runner());
+        &clock_, message_loop_.task_runner(), message_loop_.task_runner(),
+        message_loop_.task_runner());
     encoder_.reset(new H264VideoToolboxEncoder(
         cast_environment_, video_sender_config_,
         base::Bind(&SaveOperationalStatus, &operational_status_)));
@@ -237,7 +236,7 @@
   }
 
   void AdvanceClockAndVideoFrameTimestamp() {
-    clock_->Advance(base::TimeDelta::FromMilliseconds(33));
+    clock_.Advance(base::TimeDelta::FromMilliseconds(33));
     frame_->set_timestamp(frame_->timestamp() +
                           base::TimeDelta::FromMilliseconds(33));
   }
@@ -257,7 +256,7 @@
   static scoped_refptr<media::VideoFrame> frame_;
   static FrameSenderConfig video_sender_config_;
 
-  base::SimpleTestTickClock* clock_;  // Owned by CastEnvironment.
+  base::SimpleTestTickClock clock_;
   base::MessageLoop message_loop_;
   scoped_refptr<CastEnvironment> cast_environment_;
   std::unique_ptr<VideoEncoder> encoder_;
@@ -282,8 +281,8 @@
   metadata_recorder->PushExpectation(
       FrameId::first(), FrameId::first(),
       RtpTimeTicks::FromTimeDelta(frame_->timestamp(), kVideoFrequency),
-      clock_->NowTicks());
-  EXPECT_TRUE(encoder_->EncodeVideoFrame(frame_, clock_->NowTicks(), cb));
+      clock_.NowTicks());
+  EXPECT_TRUE(encoder_->EncodeVideoFrame(frame_, clock_.NowTicks(), cb));
   base::RunLoop().RunUntilIdle();
 
   for (FrameId frame_id = FrameId::first() + 1;
@@ -292,8 +291,8 @@
     metadata_recorder->PushExpectation(
         frame_id, frame_id - 1,
         RtpTimeTicks::FromTimeDelta(frame_->timestamp(), kVideoFrequency),
-        clock_->NowTicks());
-    EXPECT_TRUE(encoder_->EncodeVideoFrame(frame_, clock_->NowTicks(), cb));
+        clock_.NowTicks());
+    EXPECT_TRUE(encoder_->EncodeVideoFrame(frame_, clock_.NowTicks(), cb));
   }
 
   encoder_.reset();
@@ -316,7 +315,7 @@
   for (FrameId frame_id = FrameId::first(); frame_id < FrameId::first() + 6;
        ++frame_id) {
     checker->PushExpectation(frame_);
-    EXPECT_TRUE(encoder_->EncodeVideoFrame(frame_, clock_->NowTicks(), cb));
+    EXPECT_TRUE(encoder_->EncodeVideoFrame(frame_, clock_.NowTicks(), cb));
     AdvanceClockAndVideoFrameTimestamp();
   }
 
@@ -344,11 +343,11 @@
   // Encode a frame, suspend, encode a frame, resume, encode a frame.
 
   VideoEncoder::FrameEncodedCallback cb = base::Bind(&NoopFrameEncodedCallback);
-  EXPECT_TRUE(encoder_->EncodeVideoFrame(frame_, clock_->NowTicks(), cb));
+  EXPECT_TRUE(encoder_->EncodeVideoFrame(frame_, clock_.NowTicks(), cb));
   power_source_->GenerateSuspendEvent();
-  EXPECT_FALSE(encoder_->EncodeVideoFrame(frame_, clock_->NowTicks(), cb));
+  EXPECT_FALSE(encoder_->EncodeVideoFrame(frame_, clock_.NowTicks(), cb));
   power_source_->GenerateResumeEvent();
-  EXPECT_TRUE(encoder_->EncodeVideoFrame(frame_, clock_->NowTicks(), cb));
+  EXPECT_TRUE(encoder_->EncodeVideoFrame(frame_, clock_.NowTicks(), cb));
 }
 
 TEST_F(H264VideoToolboxEncoderTest, CheckPowerMonitoringNoInitialFrame) {
@@ -356,9 +355,9 @@
 
   VideoEncoder::FrameEncodedCallback cb = base::Bind(&NoopFrameEncodedCallback);
   power_source_->GenerateSuspendEvent();
-  EXPECT_FALSE(encoder_->EncodeVideoFrame(frame_, clock_->NowTicks(), cb));
+  EXPECT_FALSE(encoder_->EncodeVideoFrame(frame_, clock_.NowTicks(), cb));
   power_source_->GenerateResumeEvent();
-  EXPECT_TRUE(encoder_->EncodeVideoFrame(frame_, clock_->NowTicks(), cb));
+  EXPECT_TRUE(encoder_->EncodeVideoFrame(frame_, clock_.NowTicks(), cb));
 }
 
 TEST_F(H264VideoToolboxEncoderTest, CheckPowerMonitoringVideoFrameFactory) {
diff --git a/media/cast/sender/video_encoder_unittest.cc b/media/cast/sender/video_encoder_unittest.cc
index 8ebd7135..4e7dcb43 100644
--- a/media/cast/sender/video_encoder_unittest.cc
+++ b/media/cast/sender/video_encoder_unittest.cc
@@ -35,18 +35,16 @@
     : public ::testing::TestWithParam<std::pair<Codec, bool>> {
  protected:
   VideoEncoderTest()
-      : testing_clock_(new base::SimpleTestTickClock()),
-        task_runner_(new FakeSingleThreadTaskRunner(testing_clock_)),
-        cast_environment_(new CastEnvironment(
-            std::unique_ptr<base::TickClock>(testing_clock_),
-            task_runner_,
-            task_runner_,
-            task_runner_)),
+      : task_runner_(new FakeSingleThreadTaskRunner(&testing_clock_)),
+        cast_environment_(new CastEnvironment(&testing_clock_,
+                                              task_runner_,
+                                              task_runner_,
+                                              task_runner_)),
         video_config_(GetDefaultVideoSenderConfig()),
         operational_status_(STATUS_UNINITIALIZED),
         count_frames_delivered_(0) {
-    testing_clock_->Advance(base::TimeTicks::Now() - base::TimeTicks());
-    first_frame_time_ = testing_clock_->NowTicks();
+    testing_clock_.Advance(base::TimeTicks::Now() - base::TimeTicks());
+    first_frame_time_ = testing_clock_.NowTicks();
   }
 
   ~VideoEncoderTest() override = default;
@@ -116,11 +114,9 @@
     video_encoder_.reset();
   }
 
-  base::TimeTicks Now() const {
-    return testing_clock_->NowTicks();
-  }
+  base::TimeTicks Now() { return testing_clock_.NowTicks(); }
 
-  void RunTasksAndAdvanceClock() const {
+  void RunTasksAndAdvanceClock() {
     DCHECK_GT(video_config_.max_frame_rate, 0);
     const base::TimeDelta frame_duration = base::TimeDelta::FromMicroseconds(
         1000000.0 / video_config_.max_frame_rate);
@@ -135,14 +131,14 @@
     }
 #endif
     task_runner_->RunTasks();
-    testing_clock_->Advance(frame_duration);
+    testing_clock_.Advance(frame_duration);
   }
 
   int count_frames_delivered() const {
     return count_frames_delivered_;
   }
 
-  void WaitForAllFramesToBeDelivered(int total_expected) const {
+  void WaitForAllFramesToBeDelivered(int total_expected) {
     video_encoder_->EmitFrames();
     while (count_frames_delivered_ < total_expected)
       RunTasksAndAdvanceClock();
@@ -153,7 +149,7 @@
   // encoder.
   scoped_refptr<media::VideoFrame> CreateTestVideoFrame(const gfx::Size& size) {
     const base::TimeDelta timestamp =
-        testing_clock_->NowTicks() - first_frame_time_;
+        testing_clock_.NowTicks() - first_frame_time_;
     scoped_refptr<media::VideoFrame> frame;
     if (video_frame_factory_)
       frame = video_frame_factory_->MaybeCreateFrame(size, timestamp);
@@ -264,7 +260,7 @@
     ++count_frames_delivered_;
   }
 
-  base::SimpleTestTickClock* const testing_clock_;  // Owned by CastEnvironment.
+  base::SimpleTestTickClock testing_clock_;
   const scoped_refptr<FakeSingleThreadTaskRunner> task_runner_;
   const scoped_refptr<CastEnvironment> cast_environment_;
   FrameSenderConfig video_config_;
diff --git a/media/cast/sender/video_sender_unittest.cc b/media/cast/sender/video_sender_unittest.cc
index 27cf37a..0077531 100644
--- a/media/cast/sender/video_sender_unittest.cc
+++ b/media/cast/sender/video_sender_unittest.cc
@@ -149,21 +149,19 @@
 class VideoSenderTest : public ::testing::Test {
  protected:
   VideoSenderTest()
-      : testing_clock_(new base::SimpleTestTickClock()),
-        task_runner_(new FakeSingleThreadTaskRunner(testing_clock_)),
-        cast_environment_(new CastEnvironment(
-            std::unique_ptr<base::TickClock>(testing_clock_),
-            task_runner_,
-            task_runner_,
-            task_runner_)),
+      : task_runner_(new FakeSingleThreadTaskRunner(&testing_clock_)),
+        cast_environment_(new CastEnvironment(&testing_clock_,
+                                              task_runner_,
+                                              task_runner_,
+                                              task_runner_)),
         operational_status_(STATUS_UNINITIALIZED),
         vea_factory_(task_runner_) {
-    testing_clock_->Advance(base::TimeTicks::Now() - base::TimeTicks());
+    testing_clock_.Advance(base::TimeTicks::Now() - base::TimeTicks());
     vea_factory_.SetAutoRespond(true);
     last_pixel_value_ = kPixelValue;
     transport_ = new TestPacketSender();
     transport_sender_.reset(new CastTransportImpl(
-        testing_clock_, base::TimeDelta(), base::MakeUnique<TransportClient>(),
+        &testing_clock_, base::TimeDelta(), base::MakeUnique<TransportClient>(),
         base::WrapUnique(transport_), task_runner_));
   }
 
@@ -205,24 +203,24 @@
 
   scoped_refptr<media::VideoFrame> GetNewVideoFrame() {
     if (first_frame_timestamp_.is_null())
-      first_frame_timestamp_ = testing_clock_->NowTicks();
+      first_frame_timestamp_ = testing_clock_.NowTicks();
     gfx::Size size(kWidth, kHeight);
     scoped_refptr<media::VideoFrame> video_frame =
         media::VideoFrame::CreateFrame(
             PIXEL_FORMAT_I420, size, gfx::Rect(size), size,
-            testing_clock_->NowTicks() - first_frame_timestamp_);
+            testing_clock_.NowTicks() - first_frame_timestamp_);
     PopulateVideoFrame(video_frame.get(), last_pixel_value_++);
     return video_frame;
   }
 
   scoped_refptr<media::VideoFrame> GetLargeNewVideoFrame() {
     if (first_frame_timestamp_.is_null())
-      first_frame_timestamp_ = testing_clock_->NowTicks();
+      first_frame_timestamp_ = testing_clock_.NowTicks();
     gfx::Size size(kWidth, kHeight);
     scoped_refptr<media::VideoFrame> video_frame =
         media::VideoFrame::CreateFrame(
             PIXEL_FORMAT_I420, size, gfx::Rect(size), size,
-            testing_clock_->NowTicks() - first_frame_timestamp_);
+            testing_clock_.NowTicks() - first_frame_timestamp_);
     PopulateVideoFrameWithNoise(video_frame.get());
     return video_frame;
   }
@@ -231,7 +229,7 @@
     task_runner_->Sleep(base::TimeDelta::FromMilliseconds(during_ms));
   }
 
-  base::SimpleTestTickClock* const testing_clock_;  // Owned by CastEnvironment.
+  base::SimpleTestTickClock testing_clock_;
   const scoped_refptr<FakeSingleThreadTaskRunner> task_runner_;
   const scoped_refptr<CastEnvironment> cast_environment_;
   OperationalStatus operational_status_;
@@ -252,7 +250,7 @@
 
   scoped_refptr<media::VideoFrame> video_frame = GetNewVideoFrame();
 
-  const base::TimeTicks reference_time = testing_clock_->NowTicks();
+  const base::TimeTicks reference_time = testing_clock_.NowTicks();
   video_sender_->InsertRawVideoFrame(video_frame, reference_time);
 
   task_runner_->RunTasks();
@@ -270,7 +268,7 @@
   // underlying ExternalVideoEncoder instance.
   if (vea_factory_.vea_response_count() == 0) {
     video_sender_->InsertRawVideoFrame(GetNewVideoFrame(),
-                                       testing_clock_->NowTicks());
+                                       testing_clock_.NowTicks());
     task_runner_->RunTasks();
   }
   ASSERT_EQ(STATUS_INITIALIZED, operational_status_);
@@ -284,7 +282,7 @@
   scoped_refptr<media::VideoFrame> video_frame = GetNewVideoFrame();
 
   for (int i = 0; i < 3; ++i) {
-    const base::TimeTicks reference_time = testing_clock_->NowTicks();
+    const base::TimeTicks reference_time = testing_clock_.NowTicks();
     video_sender_->InsertRawVideoFrame(video_frame, reference_time);
     RunTasks(33);
     // VideoSender re-created the encoder for the 320x240 frames we're
@@ -308,7 +306,7 @@
   if (operational_status_ == STATUS_INITIALIZED ||
       operational_status_ == STATUS_CODEC_REINIT_PENDING) {
     video_sender_->InsertRawVideoFrame(GetNewVideoFrame(),
-                                       testing_clock_->NowTicks());
+                                       testing_clock_.NowTicks());
     task_runner_->RunTasks();
   }
   EXPECT_EQ(STATUS_CODEC_INIT_FAILED, operational_status_);
@@ -323,7 +321,7 @@
 
   scoped_refptr<media::VideoFrame> video_frame = GetNewVideoFrame();
 
-  const base::TimeTicks reference_time = testing_clock_->NowTicks();
+  const base::TimeTicks reference_time = testing_clock_.NowTicks();
   video_sender_->InsertRawVideoFrame(video_frame, reference_time);
 
   // Make sure that we send at least one RTCP packet.
@@ -348,7 +346,7 @@
 
   scoped_refptr<media::VideoFrame> video_frame = GetNewVideoFrame();
 
-  const base::TimeTicks reference_time = testing_clock_->NowTicks();
+  const base::TimeTicks reference_time = testing_clock_.NowTicks();
   video_sender_->InsertRawVideoFrame(video_frame, reference_time);
 
   // ACK the key frame.
@@ -381,7 +379,7 @@
   for (int i = 0; i < num_frames; i++) {
     scoped_refptr<media::VideoFrame> video_frame = GetNewVideoFrame();
 
-    const base::TimeTicks reference_time = testing_clock_->NowTicks();
+    const base::TimeTicks reference_time = testing_clock_.NowTicks();
     video_sender_->InsertRawVideoFrame(video_frame, reference_time);
     RunTasks(33);
   }
@@ -411,13 +409,13 @@
   // Send a stream of frames and don't ACK; by default we shouldn't have more
   // than 4 frames in flight.
   scoped_refptr<media::VideoFrame> video_frame = GetNewVideoFrame();
-  video_sender_->InsertRawVideoFrame(video_frame, testing_clock_->NowTicks());
+  video_sender_->InsertRawVideoFrame(video_frame, testing_clock_.NowTicks());
   RunTasks(33);
 
   // Send 3 more frames and record the number of packets sent.
   for (int i = 0; i < 3; ++i) {
     scoped_refptr<media::VideoFrame> video_frame = GetNewVideoFrame();
-    video_sender_->InsertRawVideoFrame(video_frame, testing_clock_->NowTicks());
+    video_sender_->InsertRawVideoFrame(video_frame, testing_clock_.NowTicks());
     RunTasks(33);
   }
   const int number_of_packets_sent = transport_->number_of_rtp_packets();
@@ -426,7 +424,7 @@
   // any acks.
   for (int i = 0; i < 3; ++i) {
     scoped_refptr<media::VideoFrame> video_frame = GetNewVideoFrame();
-    video_sender_->InsertRawVideoFrame(video_frame, testing_clock_->NowTicks());
+    video_sender_->InsertRawVideoFrame(video_frame, testing_clock_.NowTicks());
     RunTasks(33);
   }
 
@@ -454,7 +452,7 @@
   ASSERT_EQ(STATUS_INITIALIZED, operational_status_);
 
   scoped_refptr<media::VideoFrame> video_frame = GetNewVideoFrame();
-  video_sender_->InsertRawVideoFrame(video_frame, testing_clock_->NowTicks());
+  video_sender_->InsertRawVideoFrame(video_frame, testing_clock_.NowTicks());
   RunTasks(33);
   RtcpCastMessage cast_feedback(1);
   cast_feedback.remote_ssrc = 2;
@@ -463,7 +461,7 @@
   // Send 3 more frames but don't ACK.
   for (int i = 0; i < 3; ++i) {
     scoped_refptr<media::VideoFrame> video_frame = GetNewVideoFrame();
-    video_sender_->InsertRawVideoFrame(video_frame, testing_clock_->NowTicks());
+    video_sender_->InsertRawVideoFrame(video_frame, testing_clock_.NowTicks());
     RunTasks(33);
   }
   const int number_of_packets_sent = transport_->number_of_rtp_packets();
@@ -497,7 +495,7 @@
   ASSERT_EQ(STATUS_INITIALIZED, operational_status_);
 
   scoped_refptr<media::VideoFrame> video_frame = GetNewVideoFrame();
-  video_sender_->InsertRawVideoFrame(video_frame, testing_clock_->NowTicks());
+  video_sender_->InsertRawVideoFrame(video_frame, testing_clock_.NowTicks());
   RunTasks(33);
   RtcpCastMessage cast_feedback(1);
   cast_feedback.remote_ssrc = 2;
@@ -506,7 +504,7 @@
   // Send 2 more frames but don't ACK.
   for (int i = 0; i < 2; ++i) {
     scoped_refptr<media::VideoFrame> video_frame = GetNewVideoFrame();
-    video_sender_->InsertRawVideoFrame(video_frame, testing_clock_->NowTicks());
+    video_sender_->InsertRawVideoFrame(video_frame, testing_clock_.NowTicks());
     RunTasks(33);
   }
   // Pause the transport
@@ -514,7 +512,7 @@
 
   // Insert one more video frame.
   video_frame = GetLargeNewVideoFrame();
-  video_sender_->InsertRawVideoFrame(video_frame, testing_clock_->NowTicks());
+  video_sender_->InsertRawVideoFrame(video_frame, testing_clock_.NowTicks());
   RunTasks(33);
 
   const int number_of_packets_sent = transport_->number_of_rtp_packets();
@@ -552,7 +550,7 @@
 
   transport_->SetPause(true);
   scoped_refptr<media::VideoFrame> video_frame = GetLargeNewVideoFrame();
-  video_sender_->InsertRawVideoFrame(video_frame, testing_clock_->NowTicks());
+  video_sender_->InsertRawVideoFrame(video_frame, testing_clock_.NowTicks());
   RunTasks(33);
 
   // Frame should be in buffer, waiting. Now let's ack it.
@@ -582,7 +580,7 @@
     ASSERT_FALSE(video_frame->metadata()->HasKey(
         media::VideoFrameMetadata::RESOURCE_UTILIZATION));
 
-    const base::TimeTicks reference_time = testing_clock_->NowTicks();
+    const base::TimeTicks reference_time = testing_clock_.NowTicks();
     video_sender_->InsertRawVideoFrame(video_frame, reference_time);
 
     // Run encode tasks.  VideoSender::OnEncodedVideoFrame() will be called once
@@ -609,7 +607,7 @@
 
   // Send a frame and ACK it.
   scoped_refptr<media::VideoFrame> video_frame = GetNewVideoFrame();
-  video_sender_->InsertRawVideoFrame(video_frame, testing_clock_->NowTicks());
+  video_sender_->InsertRawVideoFrame(video_frame, testing_clock_.NowTicks());
   RunTasks(33);
 
   RtcpCastMessage cast_feedback(1);
@@ -621,7 +619,7 @@
   // Send three more frames.
   for (int i = 0; i < 3; i++) {
     video_frame = GetNewVideoFrame();
-    video_sender_->InsertRawVideoFrame(video_frame, testing_clock_->NowTicks());
+    video_sender_->InsertRawVideoFrame(video_frame, testing_clock_.NowTicks());
     RunTasks(33);
   }
   EXPECT_EQ(1, transport_->number_of_rtp_packets());
@@ -632,7 +630,7 @@
   video_frame = GetNewVideoFrame();
   video_sender_->InsertRawVideoFrame(
       video_frame,
-      testing_clock_->NowTicks() + base::TimeDelta::FromMilliseconds(1000));
+      testing_clock_.NowTicks() + base::TimeDelta::FromMilliseconds(1000));
   RunTasks(33);
   transport_->SetPause(false);
   RunTasks(33);
diff --git a/media/cast/test/cast_benchmarks.cc b/media/cast/test/cast_benchmarks.cc
index 580358c..bd8a18f 100644
--- a/media/cast/test/cast_benchmarks.cc
+++ b/media/cast/test/cast_benchmarks.cc
@@ -206,22 +206,20 @@
   RunOneBenchmark()
       : start_time_(),
         task_runner_(new FakeSingleThreadTaskRunner(&testing_clock_)),
-        testing_clock_sender_(new test::SkewedTickClock(&testing_clock_)),
+        testing_clock_sender_(&testing_clock_),
         task_runner_sender_(
             new test::SkewedSingleThreadTaskRunner(task_runner_)),
-        testing_clock_receiver_(new test::SkewedTickClock(&testing_clock_)),
+        testing_clock_receiver_(&testing_clock_),
         task_runner_receiver_(
             new test::SkewedSingleThreadTaskRunner(task_runner_)),
-        cast_environment_sender_(new CastEnvironment(
-            std::unique_ptr<base::TickClock>(testing_clock_sender_),
-            task_runner_sender_,
-            task_runner_sender_,
-            task_runner_sender_)),
-        cast_environment_receiver_(new CastEnvironment(
-            std::unique_ptr<base::TickClock>(testing_clock_receiver_),
-            task_runner_receiver_,
-            task_runner_receiver_,
-            task_runner_receiver_)),
+        cast_environment_sender_(new CastEnvironment(&testing_clock_sender_,
+                                                     task_runner_sender_,
+                                                     task_runner_sender_,
+                                                     task_runner_sender_)),
+        cast_environment_receiver_(new CastEnvironment(&testing_clock_receiver_,
+                                                       task_runner_receiver_,
+                                                       task_runner_receiver_,
+                                                       task_runner_receiver_)),
         video_bytes_encoded_(0),
         audio_bytes_encoded_(0),
         frames_sent_(0) {
@@ -261,12 +259,12 @@
   }
 
   void SetSenderClockSkew(double skew, base::TimeDelta offset) {
-    testing_clock_sender_->SetSkew(skew, offset);
+    testing_clock_sender_.SetSkew(skew, offset);
     task_runner_sender_->SetSkew(1.0 / skew);
   }
 
   void SetReceiverClockSkew(double skew, base::TimeDelta offset) {
-    testing_clock_receiver_->SetSkew(skew, offset);
+    testing_clock_receiver_.SetSkew(skew, offset);
     task_runner_receiver_->SetSkew(1.0 / skew);
   }
 
@@ -290,9 +288,9 @@
   void SendFakeVideoFrame() {
     // NB: Blackframe with timestamp
     cast_sender_->video_frame_input()->InsertRawVideoFrame(
-        media::VideoFrame::CreateColorFrame(gfx::Size(2, 2),
-        0x00, 0x80, 0x80, VideoTimestamp(frames_sent_)),
-        testing_clock_sender_->NowTicks());
+        media::VideoFrame::CreateColorFrame(gfx::Size(2, 2), 0x00, 0x80, 0x80,
+                                            VideoTimestamp(frames_sent_)),
+        testing_clock_sender_.NowTicks());
     frames_sent_++;
   }
 
@@ -305,7 +303,7 @@
       const base::TimeTicks& render_time,
       bool continuous) {
     video_ticks_.push_back(
-        std::make_pair(testing_clock_receiver_->NowTicks(), render_time));
+        std::make_pair(testing_clock_receiver_.NowTicks(), render_time));
     cast_receiver_->RequestDecodedVideoFrame(base::Bind(
         &RunOneBenchmark::BasicPlayerGotVideoFrame, base::Unretained(this)));
   }
@@ -314,7 +312,7 @@
                                 const base::TimeTicks& playout_time,
                                 bool is_continuous) {
     audio_ticks_.push_back(
-        std::make_pair(testing_clock_receiver_->NowTicks(), playout_time));
+        std::make_pair(testing_clock_receiver_.NowTicks(), playout_time));
     cast_receiver_->RequestDecodedAudioFrame(base::Bind(
         &RunOneBenchmark::BasicPlayerGotAudioFrame, base::Unretained(this)));
   }
@@ -418,11 +416,11 @@
   scoped_refptr<FakeSingleThreadTaskRunner> task_runner_;
 
   // These run on the sender timeline.
-  test::SkewedTickClock* testing_clock_sender_;
+  test::SkewedTickClock testing_clock_sender_;
   scoped_refptr<test::SkewedSingleThreadTaskRunner> task_runner_sender_;
 
   // These run on the receiver timeline.
-  test::SkewedTickClock* testing_clock_receiver_;
+  test::SkewedTickClock testing_clock_receiver_;
   scoped_refptr<test::SkewedSingleThreadTaskRunner> task_runner_receiver_;
 
   scoped_refptr<CastEnvironment> cast_environment_sender_;
@@ -475,14 +473,14 @@
   sender_to_receiver_ = new LoopBackTransport(cast_environment_sender_);
   transport_sender_.Init(
       new CastTransportImpl(
-          testing_clock_sender_, base::TimeDelta::FromSeconds(1),
+          &testing_clock_sender_, base::TimeDelta::FromSeconds(1),
           base::MakeUnique<TransportClient>(nullptr),
           base::WrapUnique(sender_to_receiver_), task_runner_sender_),
       &video_bytes_encoded_, &audio_bytes_encoded_);
 
   receiver_to_sender_ = new LoopBackTransport(cast_environment_receiver_);
   transport_receiver_.reset(new CastTransportImpl(
-      testing_clock_receiver_, base::TimeDelta::FromSeconds(1),
+      &testing_clock_receiver_, base::TimeDelta::FromSeconds(1),
       base::MakeUnique<TransportClient>(this),
       base::WrapUnique(receiver_to_sender_), task_runner_receiver_));
 
diff --git a/media/cast/test/end2end_unittest.cc b/media/cast/test/end2end_unittest.cc
index 9b80af7c..780f2b9 100644
--- a/media/cast/test/end2end_unittest.cc
+++ b/media/cast/test/end2end_unittest.cc
@@ -405,22 +405,20 @@
   End2EndTest()
       : start_time_(),
         task_runner_(new FakeSingleThreadTaskRunner(&testing_clock_)),
-        testing_clock_sender_(new test::SkewedTickClock(&testing_clock_)),
+        testing_clock_sender_(&testing_clock_),
         task_runner_sender_(
             new test::SkewedSingleThreadTaskRunner(task_runner_)),
-        testing_clock_receiver_(new test::SkewedTickClock(&testing_clock_)),
+        testing_clock_receiver_(&testing_clock_),
         task_runner_receiver_(
             new test::SkewedSingleThreadTaskRunner(task_runner_)),
-        cast_environment_sender_(new CastEnvironment(
-            std::unique_ptr<base::TickClock>(testing_clock_sender_),
-            task_runner_sender_,
-            task_runner_sender_,
-            task_runner_sender_)),
-        cast_environment_receiver_(new CastEnvironment(
-            std::unique_ptr<base::TickClock>(testing_clock_receiver_),
-            task_runner_receiver_,
-            task_runner_receiver_,
-            task_runner_receiver_)),
+        cast_environment_sender_(new CastEnvironment(&testing_clock_sender_,
+                                                     task_runner_sender_,
+                                                     task_runner_sender_,
+                                                     task_runner_sender_)),
+        cast_environment_receiver_(new CastEnvironment(&testing_clock_receiver_,
+                                                       task_runner_receiver_,
+                                                       task_runner_receiver_,
+                                                       task_runner_receiver_)),
         receiver_to_sender_(new LoopBackTransport(cast_environment_receiver_)),
         sender_to_receiver_(new LoopBackTransport(cast_environment_sender_)),
         test_receiver_audio_callback_(new TestReceiverAudioCallback()),
@@ -497,7 +495,7 @@
   }
 
   void SetReceiverSkew(double skew, base::TimeDelta offset) {
-    testing_clock_receiver_->SetSkew(skew, offset);
+    testing_clock_receiver_.SetSkew(skew, offset);
     task_runner_receiver_->SetSkew(1.0 / skew);
   }
 
@@ -517,8 +515,8 @@
       std::unique_ptr<AudioBus> audio_bus(audio_bus_factory_->NextAudioBus(
           base::TimeDelta::FromMilliseconds(kAudioFrameDurationMs)));
       const base::TimeTicks reference_time =
-          testing_clock_sender_->NowTicks() +
-              i * base::TimeDelta::FromMilliseconds(kAudioFrameDurationMs);
+          testing_clock_sender_.NowTicks() +
+          i * base::TimeDelta::FromMilliseconds(kAudioFrameDurationMs);
       if (will_be_checked) {
         test_receiver_audio_callback_->AddExpectedResult(
             *audio_bus,
@@ -535,8 +533,8 @@
       std::unique_ptr<AudioBus> audio_bus(audio_bus_factory_->NextAudioBus(
           base::TimeDelta::FromMilliseconds(kAudioFrameDurationMs)));
       const base::TimeTicks reference_time =
-          testing_clock_sender_->NowTicks() +
-              i * base::TimeDelta::FromMilliseconds(kAudioFrameDurationMs);
+          testing_clock_sender_.NowTicks() +
+          i * base::TimeDelta::FromMilliseconds(kAudioFrameDurationMs);
       test_receiver_audio_callback_->AddExpectedResult(
           *audio_bus,
           reference_time + delay +
@@ -798,9 +796,8 @@
     }
     last_video_playout_time_ = playout_time;
 
-    video_ticks_.push_back(std::make_pair(
-        testing_clock_receiver_->NowTicks(),
-        playout_time));
+    video_ticks_.push_back(
+        std::make_pair(testing_clock_receiver_.NowTicks(), playout_time));
     cast_receiver_->RequestDecodedVideoFrame(
         base::Bind(&End2EndTest::BasicPlayerGotVideoFrame,
                    base::Unretained(this)));
@@ -815,9 +812,8 @@
         << " usec.";
     last_audio_playout_time_ = playout_time;
 
-    audio_ticks_.push_back(std::make_pair(
-        testing_clock_receiver_->NowTicks(),
-        playout_time));
+    audio_ticks_.push_back(
+        std::make_pair(testing_clock_receiver_.NowTicks(), playout_time));
     cast_receiver_->RequestDecodedAudioFrame(
         base::Bind(&End2EndTest::BasicPlayerGotAudioFrame,
                    base::Unretained(this)));
@@ -844,11 +840,11 @@
   scoped_refptr<FakeSingleThreadTaskRunner> task_runner_;
 
   // These run on the sender timeline.
-  test::SkewedTickClock* testing_clock_sender_;
+  test::SkewedTickClock testing_clock_sender_;
   scoped_refptr<test::SkewedSingleThreadTaskRunner> task_runner_sender_;
 
   // These run on the receiver timeline.
-  test::SkewedTickClock* testing_clock_receiver_;
+  test::SkewedTickClock testing_clock_receiver_;
   scoped_refptr<test::SkewedSingleThreadTaskRunner> task_runner_receiver_;
   base::TimeDelta min_video_playout_delta_;
   base::TimeDelta max_video_playout_delta_;
@@ -918,13 +914,13 @@
 
 void End2EndTest::Create() {
   transport_sender_.reset(new CastTransportImpl(
-      testing_clock_sender_, base::TimeDelta::FromMilliseconds(1),
+      &testing_clock_sender_, base::TimeDelta::FromMilliseconds(1),
       base::MakeUnique<TransportClient>(cast_environment_sender_->logger(),
                                         nullptr),
       base::WrapUnique(sender_to_receiver_), task_runner_sender_));
 
   transport_receiver_.reset(new CastTransportImpl(
-      testing_clock_sender_, base::TimeDelta::FromMilliseconds(1),
+      &testing_clock_sender_, base::TimeDelta::FromMilliseconds(1),
       base::MakeUnique<TransportClient>(cast_environment_receiver_->logger(),
                                         this),
       base::WrapUnique(receiver_to_sender_), task_runner_sender_));
@@ -1005,7 +1001,7 @@
   const int test_delay_ms = 100;
 
   const int kNumVideoFramesBeforeReceiverStarted = 2;
-  const base::TimeTicks initial_send_time = testing_clock_sender_->NowTicks();
+  const base::TimeTicks initial_send_time = testing_clock_sender_.NowTicks();
   const base::TimeDelta expected_delay =
       base::TimeDelta::FromMilliseconds(test_delay_ms + kFrameTimerMs);
   for (int i = 0; i < kNumVideoFramesBeforeReceiverStarted; ++i) {
@@ -1023,7 +1019,7 @@
         initial_send_time + expected_delay +
             base::TimeDelta::FromMilliseconds(kTargetPlayoutDelayMs),
         true);
-    SendVideoFrame(frame_number++, testing_clock_sender_->NowTicks());
+    SendVideoFrame(frame_number++, testing_clock_sender_.NowTicks());
 
     if (num_audio_frames > 0)
       RunTasks(kAudioFrameDurationMs);  // Advance clock forward.
@@ -1047,10 +1043,10 @@
 
     test_receiver_video_callback_->AddExpectedResult(
         frame_number, GetTestVideoFrameSize(),
-        testing_clock_sender_->NowTicks() +
+        testing_clock_sender_.NowTicks() +
             base::TimeDelta::FromMilliseconds(kTargetPlayoutDelayMs),
         true);
-    SendVideoFrame(frame_number++, testing_clock_sender_->NowTicks());
+    SendVideoFrame(frame_number++, testing_clock_sender_.NowTicks());
 
     if (num_audio_frames > 0)
       RunTasks(kAudioFrameDurationMs);  // Advance clock forward.
@@ -1088,7 +1084,7 @@
 
   int frames_counter = 0;
   for (; frames_counter < 30; ++frames_counter) {
-    SendVideoFrame(frames_counter, testing_clock_sender_->NowTicks());
+    SendVideoFrame(frames_counter, testing_clock_sender_.NowTicks());
     RunTasks(kFrameTimerMs);
   }
   RunTasks(2 * kFrameTimerMs + 1);  // Empty the pipeline.
@@ -1117,7 +1113,7 @@
 
   for (int frames_counter = 0; frames_counter < kLongTestIterations;
        ++frames_counter) {
-    SendVideoFrame(frames_counter, testing_clock_sender_->NowTicks());
+    SendVideoFrame(frames_counter, testing_clock_sender_.NowTicks());
     RunTasks(kFrameTimerMs);
   }
   RunTasks(2 * kFrameTimerMs + 1);  // Empty the pipeline.
@@ -1132,7 +1128,7 @@
 
   for (int frames_counter = 0; frames_counter < kLongTestIterations;
        ++frames_counter) {
-    SendVideoFrame(frames_counter, testing_clock_sender_->NowTicks());
+    SendVideoFrame(frames_counter, testing_clock_sender_.NowTicks());
     RunTasks(kFrameTimerMs);
   }
   RunTasks(2 * kFrameTimerMs + 1);  // Empty the pipeline.
@@ -1153,7 +1149,7 @@
 
   for (int frames_counter = 0; frames_counter < kLongTestIterations;
        ++frames_counter) {
-    SendVideoFrame(frames_counter, testing_clock_sender_->NowTicks());
+    SendVideoFrame(frames_counter, testing_clock_sender_.NowTicks());
     RunTasks(kFrameTimerMs);
   }
   RunTasks(2 * kFrameTimerMs + 1);  // Empty the pipeline.
@@ -1169,10 +1165,10 @@
 
   for (int frames_counter = 0; frames_counter < kLongTestIterations;
        ++frames_counter) {
-    SendVideoFrame(frames_counter, testing_clock_sender_->NowTicks());
+    SendVideoFrame(frames_counter, testing_clock_sender_.NowTicks());
     RunTasks(kFrameTimerMs);
   }
-  base::TimeTicks test_end = testing_clock_receiver_->NowTicks();
+  base::TimeTicks test_end = testing_clock_receiver_.NowTicks();
   RunTasks(100 * kFrameTimerMs + 1);  // Empty the pipeline.
   EXPECT_LT(static_cast<size_t>(kLongTestIterations / 100),
             video_ticks_.size());
@@ -1191,10 +1187,10 @@
 
   for (int frames_counter = 0; frames_counter < kLongTestIterations;
        ++frames_counter) {
-    SendVideoFrame(frames_counter, testing_clock_sender_->NowTicks());
+    SendVideoFrame(frames_counter, testing_clock_sender_.NowTicks());
     RunTasks(10 /* 10 ms, but 33.3 expected by system */);
   }
-  base::TimeTicks test_end = testing_clock_receiver_->NowTicks();
+  base::TimeTicks test_end = testing_clock_receiver_.NowTicks();
   RunTasks(100 * kFrameTimerMs + 1);  // Empty the pipeline.
   EXPECT_LT(static_cast<size_t>(kLongTestIterations / 100),
             video_ticks_.size());
@@ -1228,7 +1224,7 @@
 
   for (int frames_counter = 0; frames_counter < kLongTestIterations;
        ++frames_counter) {
-    SendVideoFrame(frames_counter, testing_clock_sender_->NowTicks());
+    SendVideoFrame(frames_counter, testing_clock_sender_.NowTicks());
     RunTasks(kFrameTimerMs);
   }
   RunTasks(100 * kFrameTimerMs + 1);  // Empty the pipeline.
@@ -1250,13 +1246,13 @@
 
   int frames_counter = 0;
   for (; frames_counter < 50; ++frames_counter) {
-    SendVideoFrame(frames_counter, testing_clock_sender_->NowTicks());
+    SendVideoFrame(frames_counter, testing_clock_sender_.NowTicks());
     RunTasks(kFrameTimerMs);
   }
   cast_sender_->SetTargetPlayoutDelay(
       base::TimeDelta::FromMilliseconds(kNewDelay));
   for (; frames_counter < 100; ++frames_counter) {
-    SendVideoFrame(frames_counter, testing_clock_sender_->NowTicks());
+    SendVideoFrame(frames_counter, testing_clock_sender_.NowTicks());
     RunTasks(kFrameTimerMs);
   }
   RunTasks(100 * kFrameTimerMs + 1);  // Empty the pipeline.
diff --git a/media/cast/test/sender.cc b/media/cast/test/sender.cc
index a0be8da..d876b1d 100644
--- a/media/cast/test/sender.cc
+++ b/media/cast/test/sender.cc
@@ -239,9 +239,8 @@
   // Running transport on the main thread.
   scoped_refptr<media::cast::CastEnvironment> cast_environment(
       new media::cast::CastEnvironment(
-          base::WrapUnique<base::TickClock>(new base::DefaultTickClock()),
-          io_message_loop.task_runner(), audio_thread.task_runner(),
-          video_thread.task_runner()));
+          base::DefaultTickClock::GetInstance(), io_message_loop.task_runner(),
+          audio_thread.task_runner(), video_thread.task_runner()));
 
   // SendProcess initialization.
   std::unique_ptr<media::cast::FakeMediaSource> fake_media_source(
diff --git a/media/cast/test/simulator.cc b/media/cast/test/simulator.cc
index f29ebb7..f6d3e71 100644
--- a/media/cast/test/simulator.cc
+++ b/media/cast/test/simulator.cc
@@ -339,14 +339,12 @@
   base::ThreadTaskRunnerHandle task_runner_handle(task_runner);
 
   // CastEnvironments.
+  test::SkewedTickClock sender_clock(&testing_clock);
   scoped_refptr<CastEnvironment> sender_env =
-      new CastEnvironment(std::unique_ptr<base::TickClock>(
-                              new test::SkewedTickClock(&testing_clock)),
-                          task_runner, task_runner, task_runner);
-  scoped_refptr<CastEnvironment> receiver_env =
-      new CastEnvironment(std::unique_ptr<base::TickClock>(
-                              new test::SkewedTickClock(&testing_clock)),
-                          task_runner, task_runner, task_runner);
+      new CastEnvironment(&sender_clock, task_runner, task_runner, task_runner);
+  test::SkewedTickClock receiver_clock(&testing_clock);
+  scoped_refptr<CastEnvironment> receiver_env = new CastEnvironment(
+      &receiver_clock, task_runner, task_runner, task_runner);
 
   // Event subscriber. Store at most 1 hour of events.
   EncodingEventSubscriber audio_event_subscriber(AUDIO_EVENT,
diff --git a/media/cast/test/utility/standalone_cast_environment.cc b/media/cast/test/utility/standalone_cast_environment.cc
index 9a2b4b2..0847935 100644
--- a/media/cast/test/utility/standalone_cast_environment.cc
+++ b/media/cast/test/utility/standalone_cast_environment.cc
@@ -13,11 +13,7 @@
 namespace cast {
 
 StandaloneCastEnvironment::StandaloneCastEnvironment()
-    : CastEnvironment(
-          base::WrapUnique<base::TickClock>(new base::DefaultTickClock()),
-          NULL,
-          NULL,
-          NULL),
+    : CastEnvironment(base::DefaultTickClock::GetInstance(), NULL, NULL, NULL),
       main_thread_("StandaloneCastEnvironment Main"),
       audio_thread_("StandaloneCastEnvironment Audio"),
       video_thread_("StandaloneCastEnvironment Video") {
diff --git a/media/cast/test/utility/tap_proxy.cc b/media/cast/test/utility/tap_proxy.cc
index f75c3bc..e446011 100644
--- a/media/cast/test/utility/tap_proxy.cc
+++ b/media/cast/test/utility/tap_proxy.cc
@@ -88,7 +88,7 @@
       packet_pipe_ = std::move(tmp);
     }
     packet_pipe_->InitOnIOThread(base::ThreadTaskRunnerHandle::Get(),
-                                 &tick_clock_);
+                                 base::DefaultTickClock::GetInstance());
   }
 
  private:
@@ -111,7 +111,6 @@
   std::unique_ptr<PacketPipe> packet_pipe_;
   std::unique_ptr<base::FileDescriptorWatcher::Controller>
       read_socket_watch_controller_;
-  base::DefaultTickClock tick_clock_;
 };
 
 }  // namespace test
diff --git a/media/cast/test/utility/udp_proxy.cc b/media/cast/test/utility/udp_proxy.cc
index d4ecd5ef..1cd8fbd 100644
--- a/media/cast/test/utility/udp_proxy.cc
+++ b/media/cast/test/utility/udp_proxy.cc
@@ -761,9 +761,9 @@
     BuildPipe(&to_dest_pipe_, new PacketSender(this, &destination_));
     BuildPipe(&from_dest_pipe_, new PacketSender(this, &return_address_));
     to_dest_pipe_->InitOnIOThread(base::ThreadTaskRunnerHandle::Get(),
-                                  &tick_clock_);
+                                  base::DefaultTickClock::GetInstance());
     from_dest_pipe_->InitOnIOThread(base::ThreadTaskRunnerHandle::Get(),
-                                    &tick_clock_);
+                                    base::DefaultTickClock::GetInstance());
 
     VLOG(0) << "From:" << local_port_.ToString();
     if (!destination_is_mutable_)
@@ -844,7 +844,6 @@
   net::IPEndPoint return_address_;
   bool set_destination_next_;
 
-  base::DefaultTickClock tick_clock_;
   base::Thread proxy_thread_;
   std::unique_ptr<net::UDPServerSocket> socket_;
   std::unique_ptr<PacketPipe> to_dest_pipe_;
diff --git a/media/filters/frame_buffer_pool.cc b/media/filters/frame_buffer_pool.cc
index 96be0739..84c0997 100644
--- a/media/filters/frame_buffer_pool.cc
+++ b/media/filters/frame_buffer_pool.cc
@@ -27,7 +27,8 @@
   base::TimeTicks last_use_time;
 };
 
-FrameBufferPool::FrameBufferPool() : tick_clock_(&default_tick_clock_) {
+FrameBufferPool::FrameBufferPool()
+    : tick_clock_(base::DefaultTickClock::GetInstance()) {
   DETACH_FROM_SEQUENCE(sequence_checker_);
 }
 
diff --git a/media/filters/frame_buffer_pool.h b/media/filters/frame_buffer_pool.h
index 1b55ee8..444691f0 100644
--- a/media/filters/frame_buffer_pool.h
+++ b/media/filters/frame_buffer_pool.h
@@ -92,8 +92,7 @@
 
   bool registered_dump_provider_ = false;
 
-  // |tick_clock_| is always &|default_tick_clock_| outside of testing.
-  base::DefaultTickClock default_tick_clock_;
+  // |tick_clock_| is always a DefaultTickClock outside of testing.
   base::TickClock* tick_clock_;
 
   SEQUENCE_CHECKER(sequence_checker_);
diff --git a/media/filters/vpx_video_decoder.cc b/media/filters/vpx_video_decoder.cc
index 33e86f02..567a581 100644
--- a/media/filters/vpx_video_decoder.cc
+++ b/media/filters/vpx_video_decoder.cc
@@ -320,7 +320,8 @@
   int64_t timestamp = buffer->timestamp().InMicroseconds();
   void* user_priv = reinterpret_cast<void*>(&timestamp);
   {
-    TRACE_EVENT1("media", "vpx_codec_decode", "timestamp", timestamp);
+    TRACE_EVENT2("media", "vpx_codec_decode", "timestamp", timestamp,
+                 "buffer size (B)", buffer->data_size());
     vpx_codec_err_t status =
         vpx_codec_decode(vpx_codec_.get(), buffer->data(), buffer->data_size(),
                          user_priv, 0 /* deadline */);
diff --git a/media/mojo/clients/mojo_renderer.cc b/media/mojo/clients/mojo_renderer.cc
index 9061f31..8498e14 100644
--- a/media/mojo/clients/mojo_renderer.cc
+++ b/media/mojo/clients/mojo_renderer.cc
@@ -30,7 +30,7 @@
       video_renderer_sink_(video_renderer_sink),
       remote_renderer_info_(remote_renderer.PassInterface()),
       client_binding_(this),
-      media_time_interpolator_(&media_clock_) {
+      media_time_interpolator_(base::DefaultTickClock::GetInstance()) {
   DVLOG(1) << __func__;
 }
 
@@ -185,7 +185,7 @@
 
   {
     base::AutoLock auto_lock(lock_);
-    media_time_interpolator_.SetBounds(time, time, media_clock_.NowTicks());
+    media_time_interpolator_.SetBounds(time, time, base::TimeTicks::Now());
     media_time_interpolator_.StartInterpolating();
   }
 
diff --git a/media/mojo/clients/mojo_renderer.h b/media/mojo/clients/mojo_renderer.h
index bf5c525..91954c4 100644
--- a/media/mojo/clients/mojo_renderer.h
+++ b/media/mojo/clients/mojo_renderer.h
@@ -158,7 +158,6 @@
 
   // Lock used to serialize access for |time_interpolator_|.
   mutable base::Lock lock_;
-  base::DefaultTickClock media_clock_;
   media::TimeDeltaInterpolator media_time_interpolator_;
 
   DISALLOW_COPY_AND_ASSIGN(MojoRenderer);
diff --git a/media/mojo/clients/mojo_renderer_factory.cc b/media/mojo/clients/mojo_renderer_factory.cc
index bd4b0972..2cce793 100644
--- a/media/mojo/clients/mojo_renderer_factory.cc
+++ b/media/mojo/clients/mojo_renderer_factory.cc
@@ -11,7 +11,7 @@
 #include "media/renderers/video_overlay_factory.h"
 #include "mojo/public/cpp/bindings/interface_request.h"
 #include "services/service_manager/public/cpp/connect.h"
-#include "services/service_manager/public/interfaces/interface_provider.mojom.h"
+#include "services/service_manager/public/cpp/interface_provider.h"
 
 namespace media {
 
@@ -26,7 +26,7 @@
 
 MojoRendererFactory::MojoRendererFactory(
     const GetGpuFactoriesCB& get_gpu_factories_cb,
-    service_manager::mojom::InterfaceProvider* interface_provider)
+    service_manager::InterfaceProvider* interface_provider)
     : get_gpu_factories_cb_(get_gpu_factories_cb),
       interface_provider_(interface_provider) {
   DCHECK(interface_provider_);
@@ -63,8 +63,7 @@
     interface_factory_->CreateRenderer(std::string(),
                                        mojo::MakeRequest(&renderer_ptr));
   } else if (interface_provider_) {
-    service_manager::GetInterface<mojom::Renderer>(interface_provider_,
-                                                   &renderer_ptr);
+    interface_provider_->GetInterface(&renderer_ptr);
   } else {
     NOTREACHED();
   }
diff --git a/media/mojo/clients/mojo_renderer_factory.h b/media/mojo/clients/mojo_renderer_factory.h
index bf06a614..db6b2fe 100644
--- a/media/mojo/clients/mojo_renderer_factory.h
+++ b/media/mojo/clients/mojo_renderer_factory.h
@@ -12,10 +12,8 @@
 #include "media/mojo/interfaces/renderer.mojom.h"
 
 namespace service_manager {
-namespace mojom {
 class InterfaceProvider;
 }
-}
 
 namespace media {
 
@@ -32,9 +30,8 @@
 
   MojoRendererFactory(const GetGpuFactoriesCB& get_gpu_factories_cb,
                       media::mojom::InterfaceFactory* interface_factory);
-  MojoRendererFactory(
-      const GetGpuFactoriesCB& get_gpu_factories_cb,
-      service_manager::mojom::InterfaceProvider* interface_provider);
+  MojoRendererFactory(const GetGpuFactoriesCB& get_gpu_factories_cb,
+                      service_manager::InterfaceProvider* interface_provider);
 
   ~MojoRendererFactory() final;
 
@@ -54,7 +51,7 @@
   // InterfaceFactory or InterfaceProvider used to create or connect to remote
   // renderer.
   media::mojom::InterfaceFactory* interface_factory_ = nullptr;
-  service_manager::mojom::InterfaceProvider* interface_provider_ = nullptr;
+  service_manager::InterfaceProvider* interface_provider_ = nullptr;
 
   DISALLOW_COPY_AND_ASSIGN(MojoRendererFactory);
 };
diff --git a/media/mojo/interfaces/watch_time_recorder.mojom b/media/mojo/interfaces/watch_time_recorder.mojom
index 1e3492e..b69cbe85 100644
--- a/media/mojo/interfaces/watch_time_recorder.mojom
+++ b/media/mojo/interfaces/watch_time_recorder.mojom
@@ -16,6 +16,7 @@
   VideoCodec video_codec;  // playbacks (HLS, remoting, etc).
   bool has_audio;          // Note: Due to the above, we also need these bools
   bool has_video;          // for audio and video presence.
+  bool is_background;      // Is report for playback in the background?
   bool is_mse;
   bool is_eme;
   bool is_embedded_media_experience;  // Playback from 'Downloads' on Android.
@@ -36,6 +37,9 @@
 // Values will be recorded to UMA and UKM upon requesting finalization or the
 // destruction of the WatchTimeRecorder binding.
 //
+// Note: Not all values recorded by UKM are recorded by UMA. See implementations
+// for more details; specifically WatchTimeRecorder::ShouldReportToUma().
+//
 // Note: There are some UMA values that the WatchTimeRecorder will generate
 // based on the recorded keys and values. Such metrics will only be generated
 // when finalizing everything via FinalizeWatchTime({}) or destruction.
diff --git a/media/mojo/services/watch_time_recorder.cc b/media/mojo/services/watch_time_recorder.cc
index b3d7a91c..5c9a03b 100644
--- a/media/mojo/services/watch_time_recorder.cc
+++ b/media/mojo/services/watch_time_recorder.cc
@@ -15,6 +15,74 @@
 
 namespace media {
 
+static bool ShouldReportToUma(WatchTimeKey key) {
+  switch (key) {
+    // These keys are not currently reported to UMA, but are used for UKM metric
+    // calculations. To report them in the future just add the keys to report to
+    // the lower list and add histograms.xml entries for them.
+    case WatchTimeKey::kVideoAll:
+    case WatchTimeKey::kVideoMse:
+    case WatchTimeKey::kVideoEme:
+    case WatchTimeKey::kVideoSrc:
+    case WatchTimeKey::kVideoBattery:
+    case WatchTimeKey::kVideoAc:
+    case WatchTimeKey::kVideoDisplayFullscreen:
+    case WatchTimeKey::kVideoDisplayInline:
+    case WatchTimeKey::kVideoDisplayPictureInPicture:
+    case WatchTimeKey::kVideoEmbeddedExperience:
+    case WatchTimeKey::kVideoNativeControlsOn:
+    case WatchTimeKey::kVideoNativeControlsOff:
+    case WatchTimeKey::kVideoBackgroundAll:
+    case WatchTimeKey::kVideoBackgroundMse:
+    case WatchTimeKey::kVideoBackgroundEme:
+    case WatchTimeKey::kVideoBackgroundSrc:
+    case WatchTimeKey::kVideoBackgroundBattery:
+    case WatchTimeKey::kVideoBackgroundAc:
+    case WatchTimeKey::kVideoBackgroundEmbeddedExperience:
+      return false;
+
+    case WatchTimeKey::kAudioAll:
+    case WatchTimeKey::kAudioMse:
+    case WatchTimeKey::kAudioEme:
+    case WatchTimeKey::kAudioSrc:
+    case WatchTimeKey::kAudioBattery:
+    case WatchTimeKey::kAudioAc:
+    case WatchTimeKey::kAudioEmbeddedExperience:
+    case WatchTimeKey::kAudioNativeControlsOn:
+    case WatchTimeKey::kAudioNativeControlsOff:
+    case WatchTimeKey::kAudioBackgroundAll:
+    case WatchTimeKey::kAudioBackgroundMse:
+    case WatchTimeKey::kAudioBackgroundEme:
+    case WatchTimeKey::kAudioBackgroundSrc:
+    case WatchTimeKey::kAudioBackgroundBattery:
+    case WatchTimeKey::kAudioBackgroundAc:
+    case WatchTimeKey::kAudioBackgroundEmbeddedExperience:
+    case WatchTimeKey::kAudioVideoAll:
+    case WatchTimeKey::kAudioVideoMse:
+    case WatchTimeKey::kAudioVideoEme:
+    case WatchTimeKey::kAudioVideoSrc:
+    case WatchTimeKey::kAudioVideoBattery:
+    case WatchTimeKey::kAudioVideoAc:
+    case WatchTimeKey::kAudioVideoDisplayFullscreen:
+    case WatchTimeKey::kAudioVideoDisplayInline:
+    case WatchTimeKey::kAudioVideoDisplayPictureInPicture:
+    case WatchTimeKey::kAudioVideoEmbeddedExperience:
+    case WatchTimeKey::kAudioVideoNativeControlsOn:
+    case WatchTimeKey::kAudioVideoNativeControlsOff:
+    case WatchTimeKey::kAudioVideoBackgroundAll:
+    case WatchTimeKey::kAudioVideoBackgroundMse:
+    case WatchTimeKey::kAudioVideoBackgroundEme:
+    case WatchTimeKey::kAudioVideoBackgroundSrc:
+    case WatchTimeKey::kAudioVideoBackgroundBattery:
+    case WatchTimeKey::kAudioVideoBackgroundAc:
+    case WatchTimeKey::kAudioVideoBackgroundEmbeddedExperience:
+      return true;
+  }
+
+  NOTREACHED();
+  return false;
+}
+
 static void RecordWatchTimeInternal(base::StringPiece key,
                                     base::TimeDelta value,
                                     bool is_mtbr = false) {
@@ -104,14 +172,14 @@
       continue;
     }
 
-    const base::StringPiece metric_name = WatchTimeKeyToString(kv.first);
-    RecordWatchTimeInternal(metric_name, kv.second);
+    if (ShouldReportToUma(kv.first))
+      RecordWatchTimeInternal(WatchTimeKeyToString(kv.first), kv.second);
 
     // At finalize, update the aggregate entry.
     aggregate_watch_time_info_[kv.first] += kv.second;
   }
 
-  // If we're not finalizing everyting, we're done after removing keys.
+  // If we're not finalizing everything, we're done after removing keys.
   if (!should_finalize_everything) {
     for (auto key : keys_to_finalize)
       watch_time_info_.erase(key);
@@ -123,18 +191,21 @@
   RecordUkmPlaybackData();
 
   // Check for watch times entries that have corresponding MTBR entries and
-  // report the MTBR value using watch_time / |underflow_count|.
-  for (auto& mapping : rebuffer_keys_) {
-    auto it = watch_time_info_.find(mapping.watch_time_key);
-    if (it == watch_time_info_.end())
-      continue;
+  // report the MTBR value using watch_time / |underflow_count|. Do this only
+  // for foreground reporters since we only have UMA keys for foreground.
+  if (!properties_->is_background) {
+    for (auto& mapping : rebuffer_keys_) {
+      auto it = watch_time_info_.find(mapping.watch_time_key);
+      if (it == watch_time_info_.end())
+        continue;
 
-    if (underflow_count_) {
-      RecordMeanTimeBetweenRebuffers(mapping.mtbr_key,
-                                     it->second / underflow_count_);
+      if (underflow_count_) {
+        RecordMeanTimeBetweenRebuffers(mapping.mtbr_key,
+                                       it->second / underflow_count_);
+      }
+
+      RecordRebuffersCount(mapping.smooth_rate_key, underflow_count_);
     }
-
-    RecordRebuffersCount(mapping.smooth_rate_key, underflow_count_);
   }
 
   underflow_count_ = 0;
@@ -149,6 +220,11 @@
   underflow_count_ = count;
 }
 
+// static
+bool WatchTimeRecorder::ShouldReportUmaForTesting(WatchTimeKey key) {
+  return ShouldReportToUma(key);
+}
+
 void WatchTimeRecorder::RecordUkmPlaybackData() {
   // UKM may be unavailable in content_shell or other non-chrome/ builds; it
   // may also be unavailable if browser shutdown has started; so this may be a
@@ -158,13 +234,16 @@
     return;
 
   // Ensure we have an "All" watch time entry or skip reporting.
-  if (!std::any_of(aggregate_watch_time_info_.begin(),
-                   aggregate_watch_time_info_.end(),
-                   [](const std::pair<WatchTimeKey, base::TimeDelta>& kv) {
-                     return kv.first == WatchTimeKey::kAudioAll ||
-                            kv.first == WatchTimeKey::kAudioVideoAll ||
-                            kv.first == WatchTimeKey::kAudioVideoBackgroundAll;
-                   })) {
+  if (!std::any_of(
+          aggregate_watch_time_info_.begin(), aggregate_watch_time_info_.end(),
+          [](const std::pair<WatchTimeKey, base::TimeDelta>& kv) {
+            return kv.first == WatchTimeKey::kAudioAll ||
+                   kv.first == WatchTimeKey::kAudioBackgroundAll ||
+                   kv.first == WatchTimeKey::kAudioVideoAll ||
+                   kv.first == WatchTimeKey::kAudioVideoBackgroundAll ||
+                   kv.first == WatchTimeKey::kVideoAll ||
+                   kv.first == WatchTimeKey::kVideoBackgroundAll;
+          })) {
     return;
   }
 
@@ -176,12 +255,16 @@
   ukm::builders::Media_BasicPlayback builder(source_id);
 
   builder.SetIsTopFrame(properties_->is_top_frame);
+  builder.SetIsBackground(properties_->is_background);
 
   bool recorded_all_metric = false;
   for (auto& kv : aggregate_watch_time_info_) {
     if (kv.first == WatchTimeKey::kAudioAll ||
+        kv.first == WatchTimeKey::kAudioBackgroundAll ||
         kv.first == WatchTimeKey::kAudioVideoAll ||
-        kv.first == WatchTimeKey::kAudioVideoBackgroundAll) {
+        kv.first == WatchTimeKey::kAudioVideoBackgroundAll ||
+        kv.first == WatchTimeKey::kVideoAll ||
+        kv.first == WatchTimeKey::kVideoBackgroundAll) {
       // Only one of these keys should be present in a given finalize.
       DCHECK(!recorded_all_metric);
       recorded_all_metric = true;
@@ -191,27 +274,36 @@
         builder.SetMeanTimeBetweenRebuffers(
             (kv.second / underflow_count_).InMilliseconds());
       }
-      builder.SetIsBackground(kv.first ==
-                              WatchTimeKey::kAudioVideoBackgroundAll);
     } else if (kv.first == WatchTimeKey::kAudioAc ||
+               kv.first == WatchTimeKey::kAudioBackgroundAc ||
                kv.first == WatchTimeKey::kAudioVideoAc ||
-               kv.first == WatchTimeKey::kAudioVideoBackgroundAc) {
+               kv.first == WatchTimeKey::kAudioVideoBackgroundAc ||
+               kv.first == WatchTimeKey::kVideoAc ||
+               kv.first == WatchTimeKey::kVideoBackgroundAc) {
       builder.SetWatchTime_AC(kv.second.InMilliseconds());
     } else if (kv.first == WatchTimeKey::kAudioBattery ||
+               kv.first == WatchTimeKey::kAudioBackgroundBattery ||
                kv.first == WatchTimeKey::kAudioVideoBattery ||
-               kv.first == WatchTimeKey::kAudioVideoBackgroundBattery) {
+               kv.first == WatchTimeKey::kAudioVideoBackgroundBattery ||
+               kv.first == WatchTimeKey::kVideoBattery ||
+               kv.first == WatchTimeKey::kVideoBackgroundBattery) {
       builder.SetWatchTime_Battery(kv.second.InMilliseconds());
     } else if (kv.first == WatchTimeKey::kAudioNativeControlsOn ||
-               kv.first == WatchTimeKey::kAudioVideoNativeControlsOn) {
+               kv.first == WatchTimeKey::kAudioVideoNativeControlsOn ||
+               kv.first == WatchTimeKey::kVideoNativeControlsOn) {
       builder.SetWatchTime_NativeControlsOn(kv.second.InMilliseconds());
     } else if (kv.first == WatchTimeKey::kAudioNativeControlsOff ||
-               kv.first == WatchTimeKey::kAudioVideoNativeControlsOff) {
+               kv.first == WatchTimeKey::kAudioVideoNativeControlsOff ||
+               kv.first == WatchTimeKey::kAudioNativeControlsOff) {
       builder.SetWatchTime_NativeControlsOff(kv.second.InMilliseconds());
-    } else if (kv.first == WatchTimeKey::kAudioVideoDisplayFullscreen) {
+    } else if (kv.first == WatchTimeKey::kAudioVideoDisplayFullscreen ||
+               kv.first == WatchTimeKey::kVideoDisplayFullscreen) {
       builder.SetWatchTime_DisplayFullscreen(kv.second.InMilliseconds());
-    } else if (kv.first == WatchTimeKey::kAudioVideoDisplayInline) {
+    } else if (kv.first == WatchTimeKey::kAudioVideoDisplayInline ||
+               kv.first == WatchTimeKey::kVideoDisplayInline) {
       builder.SetWatchTime_DisplayInline(kv.second.InMilliseconds());
-    } else if (kv.first == WatchTimeKey::kAudioVideoDisplayPictureInPicture) {
+    } else if (kv.first == WatchTimeKey::kAudioVideoDisplayPictureInPicture ||
+               kv.first == WatchTimeKey::kVideoDisplayPictureInPicture) {
       builder.SetWatchTime_DisplayPictureInPicture(kv.second.InMilliseconds());
     }
   }
diff --git a/media/mojo/services/watch_time_recorder.h b/media/mojo/services/watch_time_recorder.h
index d9d6aa5..cf122512 100644
--- a/media/mojo/services/watch_time_recorder.h
+++ b/media/mojo/services/watch_time_recorder.h
@@ -36,6 +36,9 @@
   void OnError(PipelineStatus status) override;
   void UpdateUnderflowCount(int32_t count) override;
 
+  // Test helper method for determining if keys are not reported to UMA.
+  static bool ShouldReportUmaForTesting(WatchTimeKey key);
+
  private:
   // Records a UKM event based on |aggregate_watch_time_info_|; only recorded
   // with a complete finalize (destruction or empty FinalizeWatchTime call).
diff --git a/media/mojo/services/watch_time_recorder_unittest.cc b/media/mojo/services/watch_time_recorder_unittest.cc
index 666b224..6ecd839e 100644
--- a/media/mojo/services/watch_time_recorder_unittest.cc
+++ b/media/mojo/services/watch_time_recorder_unittest.cc
@@ -56,7 +56,7 @@
                   bool is_encrypted) {
     provider_->AcquireWatchTimeRecorder(
         mojom::PlaybackProperties::New(
-            kUnknownAudioCodec, kUnknownVideoCodec, has_audio, has_video,
+            kUnknownAudioCodec, kUnknownVideoCodec, has_audio, has_video, false,
             is_mse, is_encrypted, false, gfx::Size(800, 600),
             url::Origin::Create(GURL(kTestOrigin)), true /* is_top_frame */),
         mojo::MakeRequest(&wtr_));
@@ -149,11 +149,7 @@
   constexpr base::TimeDelta kWatchTime1 = base::TimeDelta::FromSeconds(25);
   constexpr base::TimeDelta kWatchTime2 = base::TimeDelta::FromSeconds(50);
 
-  // Don't include kWatchTimeKeyMax, since we'll use that as a placeholder to
-  // ensure only the keys requested for finalize are finalized.
-  const base::StringPiece kLastKey =
-      WatchTimeKeyToString(WatchTimeKey::kWatchTimeKeyMax);
-  for (int i = 0; i < static_cast<int>(WatchTimeKey::kWatchTimeKeyMax); ++i) {
+  for (int i = 0; i <= static_cast<int>(WatchTimeKey::kWatchTimeKeyMax); ++i) {
     const WatchTimeKey key = static_cast<WatchTimeKey>(i);
     SCOPED_TRACE(WatchTimeKeyToString(key));
 
@@ -170,25 +166,29 @@
     wtr_->FinalizeWatchTime({key});
     base::RunLoop().RunUntilIdle();
 
-    const base::StringPiece key_str = WatchTimeKeyToString(key);
-    ExpectWatchTime({key_str}, kWatchTime2);
+    if (WatchTimeRecorder::ShouldReportUmaForTesting(key)) {
+      const base::StringPiece key_str = WatchTimeKeyToString(key);
+      ExpectWatchTime({key_str}, kWatchTime2);
+    }
 
     // These keys are only reported for a full finalize.
     ExpectMtbrTime({}, base::TimeDelta());
     ExpectZeroRebuffers({});
     ExpectUkmWatchTime({}, base::TimeDelta());
 
-    // Verify our sentinel key is recorded properly at player destruction.
+    // Verify nothing else is recorded except for what we finalized above.
     ResetMetricRecorders();
     wtr_.reset();
     base::RunLoop().RunUntilIdle();
-
-    ExpectWatchTime({kLastKey}, kWatchTime1);
+    ExpectWatchTime({}, base::TimeDelta());
     ExpectMtbrTime({}, base::TimeDelta());
     ExpectZeroRebuffers({});
 
     if (key == WatchTimeKey::kAudioAll || key == WatchTimeKey::kAudioVideoAll ||
-        key == WatchTimeKey::kAudioVideoBackgroundAll) {
+        key == WatchTimeKey::kAudioBackgroundAll ||
+        key == WatchTimeKey::kAudioVideoBackgroundAll ||
+        key == WatchTimeKey::kVideoAll ||
+        key == WatchTimeKey::kVideoBackgroundAll) {
       ExpectUkmWatchTime({UkmEntry::kWatchTimeName}, kWatchTime2);
     } else {
       ExpectUkmWatchTime({}, base::TimeDelta());
@@ -246,7 +246,7 @@
 
 TEST_F(WatchTimeRecorderTest, BasicUkmAudioVideo) {
   mojom::PlaybackPropertiesPtr properties = mojom::PlaybackProperties::New(
-      kCodecAAC, kCodecH264, true, true, false, false, false,
+      kCodecAAC, kCodecH264, true, true, false, false, false, false,
       gfx::Size(800, 600), url::Origin::Create(GURL(kTestOrigin)), true);
   provider_->AcquireWatchTimeRecorder(properties.Clone(),
                                       mojo::MakeRequest(&wtr_));
@@ -262,7 +262,7 @@
     test_recorder_->ExpectEntrySourceHasUrl(entry, GURL(kTestOrigin));
 
     EXPECT_UKM(UkmEntry::kWatchTimeName, kWatchTime.InMilliseconds());
-    EXPECT_UKM(UkmEntry::kIsBackgroundName, false);
+    EXPECT_UKM(UkmEntry::kIsBackgroundName, properties->is_background);
     EXPECT_UKM(UkmEntry::kAudioCodecName, properties->audio_codec);
     EXPECT_UKM(UkmEntry::kVideoCodecName, properties->video_codec);
     EXPECT_UKM(UkmEntry::kHasAudioName, properties->has_audio);
@@ -289,8 +289,8 @@
 
 TEST_F(WatchTimeRecorderTest, BasicUkmAudioVideoWithExtras) {
   mojom::PlaybackPropertiesPtr properties = mojom::PlaybackProperties::New(
-      kCodecOpus, kCodecVP9, true, true, true, true, false, gfx::Size(800, 600),
-      url::Origin::Create(GURL(kTestOrigin)), true);
+      kCodecOpus, kCodecVP9, true, true, false, true, true, false,
+      gfx::Size(800, 600), url::Origin::Create(GURL(kTestOrigin)), true);
   provider_->AcquireWatchTimeRecorder(properties.Clone(),
                                       mojo::MakeRequest(&wtr_));
 
@@ -339,7 +339,7 @@
     EXPECT_UKM(UkmEntry::kMeanTimeBetweenRebuffersName,
                kWatchTime2.InMilliseconds() / 3);
 
-    EXPECT_UKM(UkmEntry::kIsBackgroundName, false);
+    EXPECT_UKM(UkmEntry::kIsBackgroundName, properties->is_background);
     EXPECT_UKM(UkmEntry::kAudioCodecName, properties->audio_codec);
     EXPECT_UKM(UkmEntry::kVideoCodecName, properties->video_codec);
     EXPECT_UKM(UkmEntry::kHasAudioName, properties->has_audio);
@@ -357,7 +357,7 @@
 
 TEST_F(WatchTimeRecorderTest, BasicUkmAudioVideoBackground) {
   mojom::PlaybackPropertiesPtr properties = mojom::PlaybackProperties::New(
-      kCodecAAC, kCodecH264, true, true, false, false, false,
+      kCodecAAC, kCodecH264, true, true, true, false, false, false,
       gfx::Size(800, 600), url::Origin::Create(GURL(kTestOrigin)), true);
   provider_->AcquireWatchTimeRecorder(properties.Clone(),
                                       mojo::MakeRequest(&wtr_));
@@ -373,7 +373,7 @@
     test_recorder_->ExpectEntrySourceHasUrl(entry, GURL(kTestOrigin));
 
     EXPECT_UKM(UkmEntry::kWatchTimeName, kWatchTime.InMilliseconds());
-    EXPECT_UKM(UkmEntry::kIsBackgroundName, true);
+    EXPECT_UKM(UkmEntry::kIsBackgroundName, properties->is_background);
     EXPECT_UKM(UkmEntry::kAudioCodecName, properties->audio_codec);
     EXPECT_UKM(UkmEntry::kVideoCodecName, properties->video_codec);
     EXPECT_UKM(UkmEntry::kHasAudioName, properties->has_audio);
diff --git a/media/remoting/courier_renderer.cc b/media/remoting/courier_renderer.cc
index fe6bd433..9a6650cf 100644
--- a/media/remoting/courier_renderer.cc
+++ b/media/remoting/courier_renderer.cc
@@ -73,7 +73,7 @@
       rpc_handle_(rpc_broker_->GetUniqueHandle()),
       remote_renderer_handle_(RpcBroker::kInvalidHandle),
       video_renderer_sink_(video_renderer_sink),
-      clock_(new base::DefaultTickClock()),
+      clock_(base::DefaultTickClock::GetInstance()),
       weak_factory_(this) {
   VLOG(2) << __func__;
   // Note: The constructor is running on the main thread, but will be destroyed
diff --git a/media/remoting/courier_renderer.h b/media/remoting/courier_renderer.h
index a5eb71149..51197e9 100644
--- a/media/remoting/courier_renderer.h
+++ b/media/remoting/courier_renderer.h
@@ -211,7 +211,7 @@
   // Records events and measurements of interest.
   RendererMetricsRecorder metrics_recorder_;
 
-  std::unique_ptr<base::TickClock> clock_;
+  base::TickClock* clock_;
 
   // A timer that polls the DemuxerStreamAdapters periodically to measure
   // the data flow rates for metrics.
diff --git a/media/remoting/courier_renderer_unittest.cc b/media/remoting/courier_renderer_unittest.cc
index 74374b2..e9ba2cd 100644
--- a/media/remoting/courier_renderer_unittest.cc
+++ b/media/remoting/courier_renderer_unittest.cc
@@ -288,9 +288,8 @@
 
     renderer_.reset(new CourierRenderer(base::ThreadTaskRunnerHandle::Get(),
                                         controller_->GetWeakPtr(), nullptr));
-    clock_ = new base::SimpleTestTickClock();
-    renderer_->clock_.reset(clock_);
-    clock_->Advance(base::TimeDelta::FromSeconds(1));
+    renderer_->clock_ = &clock_;
+    clock_.Advance(base::TimeDelta::FromSeconds(1));
 
     RunPendingTasks();
   }
@@ -338,7 +337,7 @@
       ASSERT_FALSE(DidEncounterFatalError());
       IssueTimeUpdateRpc(base::TimeDelta::FromMilliseconds(100 + i * 800),
                          base::TimeDelta::FromSeconds(100));
-      clock_->Advance(base::TimeDelta::FromSeconds(1));
+      clock_.Advance(base::TimeDelta::FromSeconds(1));
       RunPendingTasks();
     }
   }
@@ -384,7 +383,7 @@
   std::unique_ptr<RendererClientImpl> render_client_;
   std::unique_ptr<FakeMediaResource> media_resource_;
   std::unique_ptr<CourierRenderer> renderer_;
-  base::SimpleTestTickClock* clock_;  // Owned by |renderer_|;
+  base::SimpleTestTickClock clock_;
 
   // RPC handles.
   const int receiver_renderer_handle_;
@@ -693,7 +692,7 @@
   EXPECT_CALL(*render_client_, OnBufferingStateChange(BUFFERING_HAVE_ENOUGH))
       .Times(1);
   IssuesBufferingStateRpc(BufferingState::BUFFERING_HAVE_ENOUGH);
-  clock_->Advance(base::TimeDelta::FromSeconds(3));
+  clock_.Advance(base::TimeDelta::FromSeconds(3));
   VerifyAndReportTimeUpdates(0, 15);
   ASSERT_FALSE(DidEncounterFatalError());
 
@@ -701,7 +700,7 @@
   // playback was continuously delayed for 10 times.
   renderer_->SetPlaybackRate(1);
   RunPendingTasks();
-  clock_->Advance(base::TimeDelta::FromSeconds(3));
+  clock_.Advance(base::TimeDelta::FromSeconds(3));
   VerifyAndReportTimeUpdates(15, 30);
   ASSERT_TRUE(DidEncounterFatalError());
 }
@@ -712,7 +711,7 @@
   for (int i = 0; i < 7; ++i) {
     ASSERT_FALSE(DidEncounterFatalError());  // Not enough measurements.
     IssueStatisticsUpdateRpc();
-    clock_->Advance(base::TimeDelta::FromSeconds(1));
+    clock_.Advance(base::TimeDelta::FromSeconds(1));
     RunPendingTasks();
   }
   ASSERT_TRUE(DidEncounterFatalError());
diff --git a/media/remoting/renderer_controller.cc b/media/remoting/renderer_controller.cc
index 0bf8ee9..e4a1dfc 100644
--- a/media/remoting/renderer_controller.cc
+++ b/media/remoting/renderer_controller.cc
@@ -41,7 +41,7 @@
 
 RendererController::RendererController(scoped_refptr<SharedSession> session)
     : session_(std::move(session)),
-      clock_(new base::DefaultTickClock()),
+      clock_(base::DefaultTickClock::GetInstance()),
       weak_factory_(this) {
   session_->AddClient(this);
 }
diff --git a/media/remoting/renderer_controller.h b/media/remoting/renderer_controller.h
index 6ae0965..db2ca77 100644
--- a/media/remoting/renderer_controller.h
+++ b/media/remoting/renderer_controller.h
@@ -198,7 +198,7 @@
   // remote the content while this timer is running.
   base::OneShotTimer delayed_start_stability_timer_;
 
-  std::unique_ptr<base::TickClock> clock_;
+  base::TickClock* clock_;
 
   base::WeakPtrFactory<RendererController> weak_factory_;
 
diff --git a/media/remoting/renderer_controller_unittest.cc b/media/remoting/renderer_controller_unittest.cc
index c1a83914..10465d7d 100644
--- a/media/remoting/renderer_controller_unittest.cc
+++ b/media/remoting/renderer_controller_unittest.cc
@@ -110,9 +110,8 @@
     EXPECT_FALSE(is_rendering_remotely_);
     EXPECT_TRUE(sink_name_.empty());
     controller_ = base::MakeUnique<RendererController>(shared_session);
-    clock_ = new base::SimpleTestTickClock();
-    controller_->clock_.reset(clock_);
-    clock_->Advance(base::TimeDelta::FromSeconds(1));
+    controller_->clock_ = &clock_;
+    clock_.Advance(base::TimeDelta::FromSeconds(1));
     controller_->SetClient(this);
     RunUntilIdle();
     EXPECT_FALSE(is_rendering_remotely_);
@@ -145,7 +144,7 @@
   void DelayedStartEnds(double frame_rate = 30) {
     EXPECT_TRUE(IsInDelayedStart());
     decoded_frames_ = frame_rate * kDelayedStartDuration.InSeconds();
-    clock_->Advance(kDelayedStartDuration);
+    clock_.Advance(kDelayedStartDuration);
     RunUntilIdle();
     const base::Closure callback =
         controller_->delayed_start_stability_timer_.user_task();
@@ -185,7 +184,7 @@
   bool disable_pipeline_suspend_ = false;
   size_t decoded_bytes_ = 0;
   unsigned decoded_frames_ = 0;
-  base::SimpleTestTickClock* clock_;  // Own by |controller_|;
+  base::SimpleTestTickClock clock_;
   std::string sink_name_;
   std::unique_ptr<RendererController> controller_;
   double duration_in_sec_ = 120;  // 2m duration.
diff --git a/media/renderers/audio_renderer_impl.cc b/media/renderers/audio_renderer_impl.cc
index 45ead5e..55aa8a26 100644
--- a/media/renderers/audio_renderer_impl.cc
+++ b/media/renderers/audio_renderer_impl.cc
@@ -49,7 +49,7 @@
       sink_(sink),
       media_log_(media_log),
       client_(nullptr),
-      tick_clock_(new base::DefaultTickClock()),
+      tick_clock_(base::DefaultTickClock::GetInstance()),
       last_audio_memory_usage_(0),
       last_decoded_sample_rate_(0),
       last_decoded_channel_layout_(CHANNEL_LAYOUT_NONE),
diff --git a/media/renderers/audio_renderer_impl.h b/media/renderers/audio_renderer_impl.h
index 6afdca6..ca04dc3 100644
--- a/media/renderers/audio_renderer_impl.h
+++ b/media/renderers/audio_renderer_impl.h
@@ -242,7 +242,7 @@
   base::Closure flush_cb_;
 
   // Overridable tick clock for testing.
-  std::unique_ptr<base::TickClock> tick_clock_;
+  base::TickClock* tick_clock_;
 
   // Memory usage of |algorithm_| recorded during the last
   // HandleDecodedBuffer_Locked() call.
diff --git a/media/renderers/audio_renderer_impl_unittest.cc b/media/renderers/audio_renderer_impl_unittest.cc
index 944c2aa..5cd430f 100644
--- a/media/renderers/audio_renderer_impl_unittest.cc
+++ b/media/renderers/audio_renderer_impl_unittest.cc
@@ -117,7 +117,6 @@
                          SampleFormatToBytesPerChannel(kSampleFormat) * 8,
                          512),
         sink_(new FakeAudioRendererSink(hardware_params_)),
-        tick_clock_(new base::SimpleTestTickClock()),
         demuxer_stream_(DemuxerStream::AUDIO),
         expected_init_result_(true),
         enter_pending_decoder_init_(false),
@@ -139,8 +138,8 @@
         base::Bind(&AudioRendererImplTest::CreateAudioDecoderForTest,
                    base::Unretained(this)),
         &media_log_));
-    renderer_->tick_clock_.reset(tick_clock_);
-    tick_clock_->Advance(base::TimeDelta::FromSeconds(1));
+    renderer_->tick_clock_ = &tick_clock_;
+    tick_clock_.Advance(base::TimeDelta::FromSeconds(1));
   }
 
   virtual ~AudioRendererImplTest() {
@@ -519,7 +518,7 @@
   MediaLog media_log_;
   std::unique_ptr<AudioRendererImpl> renderer_;
   scoped_refptr<FakeAudioRendererSink> sink_;
-  base::SimpleTestTickClock* tick_clock_;
+  base::SimpleTestTickClock tick_clock_;
   PipelineStatistics last_statistics_;
 
   MockDemuxerStream demuxer_stream_;
@@ -904,7 +903,7 @@
 
   // Render() has not be called yet, thus no data has been consumed, so
   // advancing tick clock must not change the media time.
-  tick_clock_->Advance(kConsumptionDuration);
+  tick_clock_.Advance(kConsumptionDuration);
   EXPECT_EQ(timestamp_helper.GetTimestamp(), CurrentMediaTime());
 
   // Consume some audio data.
@@ -916,7 +915,7 @@
   EXPECT_EQ(timestamp_helper.GetTimestamp(), CurrentMediaTime());
 
   // Advancing the tick clock now should result in an estimated media time.
-  tick_clock_->Advance(kConsumptionDuration);
+  tick_clock_.Advance(kConsumptionDuration);
   EXPECT_EQ(timestamp_helper.GetTimestamp() + kConsumptionDuration,
             CurrentMediaTime());
 
@@ -930,7 +929,7 @@
   // Advance current time well past all played audio to simulate an irregular or
   // delayed OS callback. The value should be clamped to whats been rendered.
   timestamp_helper.AddFrames(frames_to_consume.value);
-  tick_clock_->Advance(kConsumptionDuration * 2);
+  tick_clock_.Advance(kConsumptionDuration * 2);
   EXPECT_EQ(timestamp_helper.GetTimestamp(), CurrentMediaTime());
 
   // Consume some more audio data.
@@ -939,7 +938,7 @@
   // Stop ticking, the media time should be clamped to what's been rendered.
   StopTicking();
   EXPECT_EQ(timestamp_helper.GetTimestamp(), CurrentMediaTime());
-  tick_clock_->Advance(kConsumptionDuration * 2);
+  tick_clock_.Advance(kConsumptionDuration * 2);
   timestamp_helper.AddFrames(frames_to_consume.value);
   EXPECT_EQ(timestamp_helper.GetTimestamp(), CurrentMediaTime());
 }
@@ -1115,29 +1114,29 @@
 
   // Time shouldn't change just yet because we've only sent the initial audio
   // data to the hardware.
-  EXPECT_EQ(tick_clock_->NowTicks(),
+  EXPECT_EQ(tick_clock_.NowTicks(),
             ConvertMediaTime(base::TimeDelta(), &is_time_moving));
   EXPECT_TRUE(is_time_moving);
 
   // A system suspend should freeze the time state and resume restart it.
   renderer_->OnSuspend();
-  EXPECT_EQ(tick_clock_->NowTicks(),
+  EXPECT_EQ(tick_clock_.NowTicks(),
             ConvertMediaTime(base::TimeDelta(), &is_time_moving));
   EXPECT_FALSE(is_time_moving);
   renderer_->OnResume();
-  EXPECT_EQ(tick_clock_->NowTicks(),
+  EXPECT_EQ(tick_clock_.NowTicks(),
             ConvertMediaTime(base::TimeDelta(), &is_time_moving));
   EXPECT_TRUE(is_time_moving);
 
   // Consume some more audio data.
   frames_to_consume = frames_buffered();
-  tick_clock_->Advance(
+  tick_clock_.Advance(
       base::TimeDelta::FromSecondsD(1.0 / kOutputSamplesPerSecond));
   EXPECT_TRUE(ConsumeBufferedData(frames_to_consume));
 
   // Time should change now that the audio hardware has called back.
   const base::TimeTicks wall_clock_time_zero =
-      tick_clock_->NowTicks() -
+      tick_clock_.NowTicks() -
       timestamp_helper.GetFrameDuration(frames_to_consume.value);
   EXPECT_EQ(wall_clock_time_zero,
             ConvertMediaTime(base::TimeDelta(), &is_time_moving));
@@ -1154,8 +1153,8 @@
       timestamp_helper.GetFrameDuration(frames_to_consume.value) / kSteps;
 
   for (int i = 0; i < kSteps; ++i) {
-    tick_clock_->Advance(kAdvanceDelta);
-    EXPECT_EQ(tick_clock_->NowTicks(),
+    tick_clock_.Advance(kAdvanceDelta);
+    EXPECT_EQ(tick_clock_.NowTicks(),
               CurrentMediaWallClockTime(&is_time_moving));
     EXPECT_TRUE(is_time_moving);
   }
@@ -1168,8 +1167,8 @@
   // Advancing once more will exceed the amount of played out frames finally.
   const base::TimeDelta kOneSample =
       base::TimeDelta::FromSecondsD(1.0 / kOutputSamplesPerSecond);
-  base::TimeTicks current_time = tick_clock_->NowTicks();
-  tick_clock_->Advance(kOneSample);
+  base::TimeTicks current_time = tick_clock_.NowTicks();
+  tick_clock_.Advance(kOneSample);
   EXPECT_EQ(current_time, CurrentMediaWallClockTime(&is_time_moving));
   EXPECT_TRUE(is_time_moving);
 
@@ -1178,7 +1177,7 @@
 
   // Elapse a lot of time between StopTicking() and the next Render() call.
   const base::TimeDelta kOneSecond = base::TimeDelta::FromSeconds(1);
-  tick_clock_->Advance(kOneSecond);
+  tick_clock_.Advance(kOneSecond);
   StartTicking();
 
   // Time should be stopped until the next render call.
@@ -1194,14 +1193,14 @@
   EXPECT_TRUE(ConsumeBufferedData(frames_to_consume, delay_time));
 
   // Verify time is adjusted for the current delay.
-  current_time = tick_clock_->NowTicks() + delay_time;
+  current_time = tick_clock_.NowTicks() + delay_time;
   EXPECT_EQ(current_time, CurrentMediaWallClockTime(&is_time_moving));
   EXPECT_TRUE(is_time_moving);
   EXPECT_EQ(current_time,
             ConvertMediaTime(renderer_->CurrentMediaTime(), &is_time_moving));
   EXPECT_TRUE(is_time_moving);
 
-  tick_clock_->Advance(kOneSample);
+  tick_clock_.Advance(kOneSample);
   renderer_->SetPlaybackRate(2);
   EXPECT_EQ(current_time, CurrentMediaWallClockTime(&is_time_moving));
   EXPECT_TRUE(is_time_moving);
@@ -1211,7 +1210,7 @@
 
   // Advance far enough that we shouldn't be clamped to current time (tested
   // already above).
-  tick_clock_->Advance(kOneSecond);
+  tick_clock_.Advance(kOneSecond);
   EXPECT_EQ(
       current_time + timestamp_helper.GetFrameDuration(frames_to_consume.value),
       CurrentMediaWallClockTime(&is_time_moving));
diff --git a/media/renderers/video_renderer_impl.cc b/media/renderers/video_renderer_impl.cc
index ce19950a..634f467 100644
--- a/media/renderers/video_renderer_impl.cc
+++ b/media/renderers/video_renderer_impl.cc
@@ -133,7 +133,7 @@
       frames_decoded_(0),
       frames_dropped_(0),
       frames_decoded_power_efficient_(0),
-      tick_clock_(new base::DefaultTickClock()),
+      tick_clock_(base::DefaultTickClock::GetInstance()),
       was_background_rendering_(false),
       time_progressing_(false),
       last_video_memory_usage_(0),
@@ -398,9 +398,8 @@
   }
 }
 
-void VideoRendererImpl::SetTickClockForTesting(
-    std::unique_ptr<base::TickClock> tick_clock) {
-  tick_clock_.swap(tick_clock);
+void VideoRendererImpl::SetTickClockForTesting(base::TickClock* tick_clock) {
+  tick_clock_ = tick_clock;
 }
 
 void VideoRendererImpl::SetGpuMemoryBufferVideoForTesting(
diff --git a/media/renderers/video_renderer_impl.h b/media/renderers/video_renderer_impl.h
index acbf658..db708730 100644
--- a/media/renderers/video_renderer_impl.h
+++ b/media/renderers/video_renderer_impl.h
@@ -73,7 +73,7 @@
   void OnTimeProgressing() override;
   void OnTimeStopped() override;
 
-  void SetTickClockForTesting(std::unique_ptr<base::TickClock> tick_clock);
+  void SetTickClockForTesting(base::TickClock* tick_clock);
   void SetGpuMemoryBufferVideoForTesting(
       std::unique_ptr<GpuMemoryBufferVideoFramePool> gpu_memory_buffer_pool);
   size_t frames_queued_for_testing() const {
@@ -299,7 +299,7 @@
   // Keeps track of the number of power efficient decoded frames.
   int frames_decoded_power_efficient_;
 
-  std::unique_ptr<base::TickClock> tick_clock_;
+  base::TickClock* tick_clock_;
 
   // Algorithm for selecting which frame to render; manages frames and all
   // timing related information. Ensure this is destructed before
diff --git a/media/renderers/video_renderer_impl_unittest.cc b/media/renderers/video_renderer_impl_unittest.cc
index a2dd42c..582f2b6 100644
--- a/media/renderers/video_renderer_impl_unittest.cc
+++ b/media/renderers/video_renderer_impl_unittest.cc
@@ -74,8 +74,7 @@
   }
 
   VideoRendererImplTest()
-      : tick_clock_(new base::SimpleTestTickClock()),
-        decoder_(nullptr),
+      : decoder_(nullptr),
         demuxer_stream_(DemuxerStream::VIDEO),
         simulate_decode_delay_(false),
         expect_init_success_(true) {
@@ -95,10 +94,9 @@
         true,
         nullptr,  // gpu_factories
         &media_log_));
-    renderer_->SetTickClockForTesting(
-        std::unique_ptr<base::TickClock>(tick_clock_));
-    null_video_sink_->set_tick_clock_for_testing(tick_clock_);
-    time_source_.set_tick_clock_for_testing(tick_clock_);
+    renderer_->SetTickClockForTesting(&tick_clock_);
+    null_video_sink_->set_tick_clock_for_testing(&tick_clock_);
+    time_source_.set_tick_clock_for_testing(&tick_clock_);
 
     // Start wallclock time at a non-zero value.
     AdvanceWallclockTimeInMs(12345);
@@ -290,7 +288,7 @@
   void AdvanceWallclockTimeInMs(int time_ms) {
     DCHECK_EQ(&message_loop_, base::MessageLoop::current());
     base::AutoLock l(lock_);
-    tick_clock_->Advance(base::TimeDelta::FromMilliseconds(time_ms));
+    tick_clock_.Advance(base::TimeDelta::FromMilliseconds(time_ms));
   }
 
   void AdvanceTimeInMs(int time_ms) {
@@ -458,7 +456,7 @@
   // Fixture members.
   base::test::ScopedFeatureList scoped_feature_list_;
   std::unique_ptr<VideoRendererImpl> renderer_;
-  base::SimpleTestTickClock* tick_clock_;  // Owned by |renderer_|.
+  base::SimpleTestTickClock tick_clock_;
   NiceMock<MockVideoDecoder>* decoder_;    // Owned by |renderer_|.
   NiceMock<MockDemuxerStream> demuxer_stream_;
   bool simulate_decode_delay_;
@@ -492,7 +490,7 @@
       return;
 
     if (simulate_decode_delay_)
-      tick_clock_->Advance(OnSimulateDecodeDelay());
+      tick_clock_.Advance(OnSimulateDecodeDelay());
 
     SatisfyPendingDecode();
   }
diff --git a/media/video/gpu_memory_buffer_video_frame_pool.cc b/media/video/gpu_memory_buffer_video_frame_pool.cc
index 1a7c93b..0d1d2d37 100644
--- a/media/video/gpu_memory_buffer_video_frame_pool.cc
+++ b/media/video/gpu_memory_buffer_video_frame_pool.cc
@@ -53,7 +53,7 @@
         worker_task_runner_(worker_task_runner),
         gpu_factories_(gpu_factories),
         output_format_(GpuVideoAcceleratorFactories::OutputFormat::UNDEFINED),
-        tick_clock_(&default_tick_clock_),
+        tick_clock_(base::DefaultTickClock::GetInstance()),
         in_shutdown_(false) {
     DCHECK(media_task_runner_);
     DCHECK(worker_task_runner_);
@@ -176,8 +176,7 @@
 
   GpuVideoAcceleratorFactories::OutputFormat output_format_;
 
-  // |tick_clock_| is always &|default_tick_clock_| outside of testing.
-  base::DefaultTickClock default_tick_clock_;
+  // |tick_clock_| is always a DefaultTickClock outside of testing.
   base::TickClock* tick_clock_;
 
   bool in_shutdown_;
diff --git a/mojo/BUILD.gn b/mojo/BUILD.gn
index 1c0914c..cfb2273 100644
--- a/mojo/BUILD.gn
+++ b/mojo/BUILD.gn
@@ -28,7 +28,6 @@
   deps = [
     "//ipc:ipc_tests",
     "//mojo/common:mojo_common_unittests",
-    "//mojo/edk/js/tests",
     "//mojo/edk/system:mojo_message_pipe_perftests",
     "//mojo/edk/system:mojo_system_unittests",
     "//mojo/edk/test:mojo_public_bindings_perftests",
diff --git a/mojo/edk/DEPS b/mojo/edk/DEPS
index 77abb21..4cc26fb 100644
--- a/mojo/edk/DEPS
+++ b/mojo/edk/DEPS
@@ -3,11 +3,9 @@
   "+base",
   "+crypto",
   "+build",
-  "+gin",
   "+native_client/src/public",
   "+testing",
   "+third_party/ashmem",
-  "+v8",
 
   # internal includes.
   "+mojo",
diff --git a/mojo/edk/js/BUILD.gn b/mojo/edk/js/BUILD.gn
deleted file mode 100644
index fc1e03c..0000000
--- a/mojo/edk/js/BUILD.gn
+++ /dev/null
@@ -1,35 +0,0 @@
-# Copyright 2014 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-component("js") {
-  sources = [
-    "core.cc",
-    "core.h",
-    "drain_data.cc",
-    "drain_data.h",
-    "handle.cc",
-    "handle.h",
-    "handle_close_observer.h",
-    "js_export.h",
-    "mojo_runner_delegate.cc",
-    "mojo_runner_delegate.h",
-    "support.cc",
-    "support.h",
-    "threading.cc",
-    "threading.h",
-    "waiting_callback.cc",
-    "waiting_callback.h",
-  ]
-
-  public_deps = [
-    "//base",
-    "//gin",
-    "//v8",
-  ]
-
-  deps = [
-    "//mojo/public/cpp/system",
-  ]
-  defines = [ "MOJO_JS_IMPLEMENTATION" ]
-}
diff --git a/mojo/edk/js/core.cc b/mojo/edk/js/core.cc
deleted file mode 100644
index 4cc25a3..0000000
--- a/mojo/edk/js/core.cc
+++ /dev/null
@@ -1,473 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "mojo/edk/js/core.h"
-
-#include <stddef.h>
-#include <stdint.h>
-
-#include "base/bind.h"
-#include "base/logging.h"
-#include "gin/arguments.h"
-#include "gin/array_buffer.h"
-#include "gin/converter.h"
-#include "gin/dictionary.h"
-#include "gin/function_template.h"
-#include "gin/handle.h"
-#include "gin/object_template_builder.h"
-#include "gin/per_isolate_data.h"
-#include "gin/public/wrapper_info.h"
-#include "gin/wrappable.h"
-#include "mojo/edk/js/drain_data.h"
-#include "mojo/edk/js/handle.h"
-#include "mojo/public/cpp/system/wait.h"
-
-namespace mojo {
-namespace edk {
-namespace js {
-
-namespace {
-
-MojoResult CloseHandle(gin::Handle<HandleWrapper> handle) {
-  if (!handle->get().is_valid())
-    return MOJO_RESULT_INVALID_ARGUMENT;
-  handle->Close();
-  return MOJO_RESULT_OK;
-}
-
-gin::Dictionary QueryHandleSignalsState(const gin::Arguments& args,
-                                        mojo::Handle handle) {
-  gin::Dictionary dictionary = gin::Dictionary::CreateEmpty(args.isolate());
-  if (!handle.is_valid()) {
-    dictionary.Set("result", MOJO_RESULT_INVALID_ARGUMENT);
-  } else {
-    HandleSignalsState state = handle.QuerySignalsState();
-    dictionary.Set("result", MOJO_RESULT_OK);
-    dictionary.Set("satisfiedSignals", state.satisfied_signals);
-    dictionary.Set("satisfiableSignals", state.satisfiable_signals);
-  }
-  return dictionary;
-}
-
-gin::Dictionary WaitHandle(const gin::Arguments& args,
-                           mojo::Handle handle,
-                           MojoHandleSignals signals) {
-  v8::Isolate* isolate = args.isolate();
-  gin::Dictionary dictionary = gin::Dictionary::CreateEmpty(isolate);
-
-  MojoHandleSignalsState signals_state;
-  MojoResult result = Wait(handle, signals, &signals_state);
-  dictionary.Set("result", result);
-
-  if (result != MOJO_RESULT_OK && result != MOJO_RESULT_FAILED_PRECONDITION) {
-    dictionary.Set("signalsState", v8::Null(isolate).As<v8::Value>());
-  } else {
-    gin::Dictionary signalsStateDict = gin::Dictionary::CreateEmpty(isolate);
-    signalsStateDict.Set("satisfiedSignals", signals_state.satisfied_signals);
-    signalsStateDict.Set("satisfiableSignals",
-                         signals_state.satisfiable_signals);
-    dictionary.Set("signalsState", signalsStateDict);
-  }
-
-  return dictionary;
-}
-
-gin::Dictionary CreateMessagePipe(const gin::Arguments& args) {
-  gin::Dictionary dictionary = gin::Dictionary::CreateEmpty(args.isolate());
-  dictionary.Set("result", MOJO_RESULT_INVALID_ARGUMENT);
-
-  MojoHandle handle0 = MOJO_HANDLE_INVALID;
-  MojoHandle handle1 = MOJO_HANDLE_INVALID;
-  MojoResult result = MOJO_RESULT_OK;
-
-  v8::Local<v8::Value> options_value = args.PeekNext();
-  if (options_value.IsEmpty() || options_value->IsNull() ||
-      options_value->IsUndefined()) {
-    result = MojoCreateMessagePipe(NULL, &handle0, &handle1);
-  } else if (options_value->IsObject()) {
-    gin::Dictionary options_dict(args.isolate(), options_value->ToObject());
-    MojoCreateMessagePipeOptions options;
-    // For future struct_size, we can probably infer that from the presence of
-    // properties in options_dict. For now, it's always 8.
-    options.struct_size = 8;
-    // Ideally these would be optional. But the interface makes it hard to
-    // typecheck them then.
-    if (!options_dict.Get("flags", &options.flags)) {
-      return dictionary;
-    }
-
-    result = MojoCreateMessagePipe(&options, &handle0, &handle1);
-  } else {
-    return dictionary;
-  }
-
-  CHECK_EQ(MOJO_RESULT_OK, result);
-
-  dictionary.Set("result", result);
-  dictionary.Set("handle0", mojo::Handle(handle0));
-  dictionary.Set("handle1", mojo::Handle(handle1));
-  return dictionary;
-}
-
-MojoResult WriteMessage(mojo::Handle handle,
-                        const gin::ArrayBufferView& buffer,
-                        const std::vector<gin::Handle<HandleWrapper>>& handles,
-                        MojoWriteMessageFlags flags) {
-  std::vector<MojoHandle> raw_handles(handles.size());
-  for (size_t i = 0; i < handles.size(); ++i)
-    raw_handles[i] = handles[i]->get().value();
-  MojoResult rv =
-      WriteMessageRaw(MessagePipeHandle(handle.value()), buffer.bytes(),
-                      static_cast<uint32_t>(buffer.num_bytes()),
-                      raw_handles.empty() ? NULL : &raw_handles[0],
-                      static_cast<uint32_t>(raw_handles.size()), flags);
-  // WriteMessageRaw takes ownership of the handles, so release them here.
-  for (size_t i = 0; i < handles.size(); ++i)
-    ignore_result(handles[i]->release());
-
-  return rv;
-}
-
-gin::Dictionary ReadMessage(const gin::Arguments& args,
-                            mojo::Handle handle,
-                            MojoReadMessageFlags flags) {
-  MojoMessageHandle message;
-  MojoResult result =
-      MojoReadMessage(handle.value(), &message, MOJO_READ_MESSAGE_FLAG_NONE);
-  if (result != MOJO_RESULT_OK) {
-    gin::Dictionary dictionary = gin::Dictionary::CreateEmpty(args.isolate());
-    dictionary.Set("result", result);
-    return dictionary;
-  }
-
-  result = MojoSerializeMessage(message);
-  if (result != MOJO_RESULT_OK && result != MOJO_RESULT_FAILED_PRECONDITION) {
-    MojoDestroyMessage(message);
-    gin::Dictionary dictionary = gin::Dictionary::CreateEmpty(args.isolate());
-    dictionary.Set("result", MOJO_RESULT_ABORTED);
-    return dictionary;
-  }
-
-  uint32_t num_bytes = 0;
-  void* bytes;
-  uint32_t num_handles = 0;
-  std::vector<mojo::Handle> handles;
-  result = MojoGetSerializedMessageContents(
-      message, &bytes, &num_bytes, nullptr, &num_handles,
-      MOJO_GET_SERIALIZED_MESSAGE_CONTENTS_FLAG_NONE);
-  if (result == MOJO_RESULT_RESOURCE_EXHAUSTED) {
-    handles.resize(num_handles);
-    result = MojoGetSerializedMessageContents(
-        message, &bytes, &num_bytes,
-        reinterpret_cast<MojoHandle*>(handles.data()), &num_handles,
-        MOJO_GET_SERIALIZED_MESSAGE_CONTENTS_FLAG_NONE);
-  }
-
-  if (result != MOJO_RESULT_OK) {
-    MojoDestroyMessage(message);
-    gin::Dictionary dictionary = gin::Dictionary::CreateEmpty(args.isolate());
-    dictionary.Set("result", MOJO_RESULT_ABORTED);
-    return dictionary;
-  }
-
-  v8::Local<v8::ArrayBuffer> array_buffer =
-      v8::ArrayBuffer::New(args.isolate(), num_bytes);
-  if (num_bytes) {
-    gin::ArrayBuffer buffer;
-    ConvertFromV8(args.isolate(), array_buffer, &buffer);
-    DCHECK_EQ(buffer.num_bytes(), num_bytes);
-    memcpy(buffer.bytes(), bytes, num_bytes);
-  }
-
-  MojoDestroyMessage(message);
-
-  gin::Dictionary dictionary = gin::Dictionary::CreateEmpty(args.isolate());
-  dictionary.Set("result", result);
-  dictionary.Set("buffer", array_buffer);
-  dictionary.Set("handles", handles);
-  return dictionary;
-}
-
-gin::Dictionary CreateDataPipe(const gin::Arguments& args) {
-  gin::Dictionary dictionary = gin::Dictionary::CreateEmpty(args.isolate());
-  dictionary.Set("result", MOJO_RESULT_INVALID_ARGUMENT);
-
-  MojoHandle producer_handle = MOJO_HANDLE_INVALID;
-  MojoHandle consumer_handle = MOJO_HANDLE_INVALID;
-  MojoResult result = MOJO_RESULT_OK;
-
-  v8::Local<v8::Value> options_value = args.PeekNext();
-  if (options_value.IsEmpty() || options_value->IsNull() ||
-      options_value->IsUndefined()) {
-    result = MojoCreateDataPipe(NULL, &producer_handle, &consumer_handle);
-  } else if (options_value->IsObject()) {
-    gin::Dictionary options_dict(args.isolate(), options_value->ToObject());
-    MojoCreateDataPipeOptions options;
-    // For future struct_size, we can probably infer that from the presence of
-    // properties in options_dict. For now, it's always 16.
-    options.struct_size = 16;
-    // Ideally these would be optional. But the interface makes it hard to
-    // typecheck them then.
-    if (!options_dict.Get("flags", &options.flags) ||
-        !options_dict.Get("elementNumBytes", &options.element_num_bytes) ||
-        !options_dict.Get("capacityNumBytes", &options.capacity_num_bytes)) {
-      return dictionary;
-    }
-
-    result = MojoCreateDataPipe(&options, &producer_handle, &consumer_handle);
-  } else {
-    return dictionary;
-  }
-
-  CHECK_EQ(MOJO_RESULT_OK, result);
-
-  dictionary.Set("result", result);
-  dictionary.Set("producerHandle", mojo::Handle(producer_handle));
-  dictionary.Set("consumerHandle", mojo::Handle(consumer_handle));
-  return dictionary;
-}
-
-gin::Dictionary WriteData(const gin::Arguments& args,
-                          mojo::Handle handle,
-                          const gin::ArrayBufferView& buffer,
-                          MojoWriteDataFlags flags) {
-  uint32_t num_bytes = static_cast<uint32_t>(buffer.num_bytes());
-  MojoResult result =
-      MojoWriteData(handle.value(), buffer.bytes(), &num_bytes, flags);
-  gin::Dictionary dictionary = gin::Dictionary::CreateEmpty(args.isolate());
-  dictionary.Set("result", result);
-  dictionary.Set("numBytes", num_bytes);
-  return dictionary;
-}
-
-gin::Dictionary ReadData(const gin::Arguments& args,
-                         mojo::Handle handle,
-                         MojoReadDataFlags flags) {
-  uint32_t num_bytes = 0;
-  MojoResult result =
-      MojoReadData(handle.value(), NULL, &num_bytes, MOJO_READ_DATA_FLAG_QUERY);
-  if (result != MOJO_RESULT_OK) {
-    gin::Dictionary dictionary = gin::Dictionary::CreateEmpty(args.isolate());
-    dictionary.Set("result", result);
-    return dictionary;
-  }
-
-  v8::Local<v8::ArrayBuffer> array_buffer =
-      v8::ArrayBuffer::New(args.isolate(), num_bytes);
-  gin::ArrayBuffer buffer;
-  ConvertFromV8(args.isolate(), array_buffer, &buffer);
-  CHECK_EQ(num_bytes, buffer.num_bytes());
-
-  result = MojoReadData(handle.value(), buffer.bytes(), &num_bytes, flags);
-  CHECK_EQ(num_bytes, buffer.num_bytes());
-
-  gin::Dictionary dictionary = gin::Dictionary::CreateEmpty(args.isolate());
-  dictionary.Set("result", result);
-  dictionary.Set("buffer", array_buffer);
-  return dictionary;
-}
-
-// Asynchronously read all of the data available for the specified data pipe
-// consumer handle until the remote handle is closed or an error occurs. A
-// Promise is returned whose settled value is an object like this:
-// {result: core.RESULT_OK, buffer: dataArrayBuffer}. If the read failed,
-// then the Promise is rejected, the result will be the actual error code,
-// and the buffer will contain whatever was read before the error occurred.
-// The drainData data pipe handle argument is closed automatically.
-
-v8::Local<v8::Value> DoDrainData(gin::Arguments* args,
-                                 gin::Handle<HandleWrapper> handle) {
-  return (new DrainData(args->isolate(), handle->release()))->GetPromise();
-}
-
-bool IsHandle(gin::Arguments* args, v8::Local<v8::Value> val) {
-  gin::Handle<mojo::edk::js::HandleWrapper> ignore_handle;
-  return gin::Converter<gin::Handle<mojo::edk::js::HandleWrapper>>::FromV8(
-      args->isolate(), val, &ignore_handle);
-}
-
-gin::Dictionary CreateSharedBuffer(const gin::Arguments& args,
-                                   uint64_t num_bytes,
-                                   MojoCreateSharedBufferOptionsFlags flags) {
-  gin::Dictionary dictionary = gin::Dictionary::CreateEmpty(args.isolate());
-  MojoHandle handle = MOJO_HANDLE_INVALID;
-  MojoCreateSharedBufferOptions options;
-  // The |flags| is mandatory parameter for CreateSharedBuffer, and it will
-  // be always initialized in MojoCreateSharedBufferOptions struct. For
-  // forward compatibility, set struct_size to be 8 bytes (struct_size + flags),
-  // so that validator will only check the field that is set.
-  options.struct_size = 8;
-  options.flags = flags;
-  MojoResult result = MojoCreateSharedBuffer(&options, num_bytes, &handle);
-  if (result != MOJO_RESULT_OK) {
-    dictionary.Set("result", result);
-    return dictionary;
-  }
-
-  dictionary.Set("result", result);
-  dictionary.Set("handle", mojo::Handle(handle));
-
-  return dictionary;
-}
-
-gin::Dictionary DuplicateBufferHandle(
-    const gin::Arguments& args,
-    mojo::Handle handle,
-    MojoDuplicateBufferHandleOptionsFlags flags) {
-  gin::Dictionary dictionary = gin::Dictionary::CreateEmpty(args.isolate());
-  MojoHandle duped = MOJO_HANDLE_INVALID;
-  MojoDuplicateBufferHandleOptions options;
-  // The |flags| is mandatory parameter for DuplicateBufferHandle, and it will
-  // be always initialized in MojoDuplicateBufferHandleOptions struct. For
-  // forward compatibility, set struct_size to be 8 bytes (struct_size + flags),
-  // so that validator will only check the field that is set.
-  options.struct_size = 8;
-  options.flags = flags;
-  MojoResult result =
-      MojoDuplicateBufferHandle(handle.value(), &options, &duped);
-  if (result != MOJO_RESULT_OK) {
-    dictionary.Set("result", result);
-    return dictionary;
-  }
-
-  dictionary.Set("result", result);
-  dictionary.Set("handle", mojo::Handle(duped));
-
-  return dictionary;
-}
-
-gin::Dictionary MapBuffer(const gin::Arguments& args,
-                          mojo::Handle handle,
-                          uint64_t offset,
-                          uint64_t num_bytes,
-                          MojoMapBufferFlags flags) {
-  gin::Dictionary dictionary = gin::Dictionary::CreateEmpty(args.isolate());
-  void* data = nullptr;
-  MojoResult result =
-      MojoMapBuffer(handle.value(), offset, num_bytes, &data, flags);
-  if (result != MOJO_RESULT_OK) {
-    dictionary.Set("result", result);
-    return dictionary;
-  }
-
-  v8::Local<v8::ArrayBuffer> array_buffer =
-      v8::ArrayBuffer::New(args.isolate(), data, num_bytes);
-
-  dictionary.Set("result", result);
-  dictionary.Set("buffer", array_buffer);
-
-  return dictionary;
-}
-
-MojoResult UnmapBuffer(const gin::Arguments& args,
-                       const v8::Local<v8::ArrayBuffer>& buffer) {
-  // Buffer must be external, created by MapBuffer
-  if (!buffer->IsExternal())
-    return MOJO_RESULT_INVALID_ARGUMENT;
-
-  return MojoUnmapBuffer(buffer->GetContents().Data());
-}
-
-gin::WrapperInfo g_wrapper_info = {gin::kEmbedderNativeGin};
-
-}  // namespace
-
-const char Core::kModuleName[] = "mojo/public/js/core";
-
-v8::Local<v8::Value> Core::GetModule(v8::Isolate* isolate) {
-  gin::PerIsolateData* data = gin::PerIsolateData::From(isolate);
-  v8::Local<v8::ObjectTemplate> templ =
-      data->GetObjectTemplate(&g_wrapper_info);
-
-  if (templ.IsEmpty()) {
-    templ =
-        gin::ObjectTemplateBuilder(isolate)
-            // TODO(mpcomplete): Should these just be methods on the JS Handle
-            // object?
-            .SetMethod("close", CloseHandle)
-            .SetMethod("queryHandleSignalsState", QueryHandleSignalsState)
-            .SetMethod("wait", WaitHandle)
-            .SetMethod("createMessagePipe", CreateMessagePipe)
-            .SetMethod("writeMessage", WriteMessage)
-            .SetMethod("readMessage", ReadMessage)
-            .SetMethod("createDataPipe", CreateDataPipe)
-            .SetMethod("writeData", WriteData)
-            .SetMethod("readData", ReadData)
-            .SetMethod("drainData", DoDrainData)
-            .SetMethod("isHandle", IsHandle)
-            .SetMethod("createSharedBuffer", CreateSharedBuffer)
-            .SetMethod("duplicateBufferHandle", DuplicateBufferHandle)
-            .SetMethod("mapBuffer", MapBuffer)
-            .SetMethod("unmapBuffer", UnmapBuffer)
-
-            .SetValue("RESULT_OK", MOJO_RESULT_OK)
-            .SetValue("RESULT_CANCELLED", MOJO_RESULT_CANCELLED)
-            .SetValue("RESULT_UNKNOWN", MOJO_RESULT_UNKNOWN)
-            .SetValue("RESULT_INVALID_ARGUMENT", MOJO_RESULT_INVALID_ARGUMENT)
-            .SetValue("RESULT_DEADLINE_EXCEEDED", MOJO_RESULT_DEADLINE_EXCEEDED)
-            .SetValue("RESULT_NOT_FOUND", MOJO_RESULT_NOT_FOUND)
-            .SetValue("RESULT_ALREADY_EXISTS", MOJO_RESULT_ALREADY_EXISTS)
-            .SetValue("RESULT_PERMISSION_DENIED", MOJO_RESULT_PERMISSION_DENIED)
-            .SetValue("RESULT_RESOURCE_EXHAUSTED",
-                      MOJO_RESULT_RESOURCE_EXHAUSTED)
-            .SetValue("RESULT_FAILED_PRECONDITION",
-                      MOJO_RESULT_FAILED_PRECONDITION)
-            .SetValue("RESULT_ABORTED", MOJO_RESULT_ABORTED)
-            .SetValue("RESULT_OUT_OF_RANGE", MOJO_RESULT_OUT_OF_RANGE)
-            .SetValue("RESULT_UNIMPLEMENTED", MOJO_RESULT_UNIMPLEMENTED)
-            .SetValue("RESULT_INTERNAL", MOJO_RESULT_INTERNAL)
-            .SetValue("RESULT_UNAVAILABLE", MOJO_RESULT_UNAVAILABLE)
-            .SetValue("RESULT_DATA_LOSS", MOJO_RESULT_DATA_LOSS)
-            .SetValue("RESULT_BUSY", MOJO_RESULT_BUSY)
-            .SetValue("RESULT_SHOULD_WAIT", MOJO_RESULT_SHOULD_WAIT)
-
-            .SetValue("HANDLE_SIGNAL_NONE", MOJO_HANDLE_SIGNAL_NONE)
-            .SetValue("HANDLE_SIGNAL_READABLE", MOJO_HANDLE_SIGNAL_READABLE)
-            .SetValue("HANDLE_SIGNAL_WRITABLE", MOJO_HANDLE_SIGNAL_WRITABLE)
-            .SetValue("HANDLE_SIGNAL_PEER_CLOSED",
-                      MOJO_HANDLE_SIGNAL_PEER_CLOSED)
-            .SetValue("HANDLE_SIGNAL_PEER_REMOTE",
-                      MOJO_HANDLE_SIGNAL_PEER_REMOTE)
-
-            .SetValue("CREATE_MESSAGE_PIPE_OPTIONS_FLAG_NONE",
-                      MOJO_CREATE_MESSAGE_PIPE_OPTIONS_FLAG_NONE)
-
-            .SetValue("WRITE_MESSAGE_FLAG_NONE", MOJO_WRITE_MESSAGE_FLAG_NONE)
-
-            .SetValue("READ_MESSAGE_FLAG_NONE", MOJO_READ_MESSAGE_FLAG_NONE)
-
-            .SetValue("CREATE_DATA_PIPE_OPTIONS_FLAG_NONE",
-                      MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_NONE)
-
-            .SetValue("WRITE_DATA_FLAG_NONE", MOJO_WRITE_DATA_FLAG_NONE)
-            .SetValue("WRITE_DATA_FLAG_ALL_OR_NONE",
-                      MOJO_WRITE_DATA_FLAG_ALL_OR_NONE)
-
-            .SetValue("READ_DATA_FLAG_NONE", MOJO_READ_DATA_FLAG_NONE)
-            .SetValue("READ_DATA_FLAG_ALL_OR_NONE",
-                      MOJO_READ_DATA_FLAG_ALL_OR_NONE)
-            .SetValue("READ_DATA_FLAG_DISCARD", MOJO_READ_DATA_FLAG_DISCARD)
-            .SetValue("READ_DATA_FLAG_QUERY", MOJO_READ_DATA_FLAG_QUERY)
-            .SetValue("READ_DATA_FLAG_PEEK", MOJO_READ_DATA_FLAG_PEEK)
-            .SetValue("CREATE_SHARED_BUFFER_OPTIONS_FLAG_NONE",
-                      MOJO_CREATE_SHARED_BUFFER_OPTIONS_FLAG_NONE)
-
-            .SetValue("DUPLICATE_BUFFER_HANDLE_OPTIONS_FLAG_NONE",
-                      MOJO_DUPLICATE_BUFFER_HANDLE_OPTIONS_FLAG_NONE)
-
-            .SetValue("DUPLICATE_BUFFER_HANDLE_OPTIONS_FLAG_READ_ONLY",
-                      MOJO_DUPLICATE_BUFFER_HANDLE_OPTIONS_FLAG_READ_ONLY)
-
-            .SetValue("MAP_BUFFER_FLAG_NONE", MOJO_MAP_BUFFER_FLAG_NONE)
-            .Build();
-
-    data->SetObjectTemplate(&g_wrapper_info, templ);
-  }
-
-  return templ->NewInstance();
-}
-
-}  // namespace js
-}  // namespace edk
-}  // namespace mojo
diff --git a/mojo/edk/js/core.h b/mojo/edk/js/core.h
deleted file mode 100644
index 97ef5dfd..0000000
--- a/mojo/edk/js/core.h
+++ /dev/null
@@ -1,25 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef MOJO_EDK_JS_CORE_H_
-#define MOJO_EDK_JS_CORE_H_
-
-#include "mojo/edk/js/js_export.h"
-#include "v8/include/v8.h"
-
-namespace mojo {
-namespace edk {
-namespace js {
-
-class MOJO_JS_EXPORT Core {
- public:
-  static const char kModuleName[];
-  static v8::Local<v8::Value> GetModule(v8::Isolate* isolate);
-};
-
-}  // namespace js
-}  // namespace edk
-}  // namespace mojo
-
-#endif  // MOJO_EDK_JS_CORE_H_
diff --git a/mojo/edk/js/drain_data.cc b/mojo/edk/js/drain_data.cc
deleted file mode 100644
index 7787b67f..0000000
--- a/mojo/edk/js/drain_data.cc
+++ /dev/null
@@ -1,129 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "mojo/edk/js/drain_data.h"
-
-#include <stddef.h>
-#include <stdint.h>
-
-#include "base/bind.h"
-#include "base/memory/ptr_util.h"
-#include "gin/array_buffer.h"
-#include "gin/converter.h"
-#include "gin/dictionary.h"
-#include "gin/per_context_data.h"
-#include "gin/per_isolate_data.h"
-#include "mojo/public/cpp/system/core.h"
-
-namespace mojo {
-namespace edk {
-namespace js {
-
-DrainData::DrainData(v8::Isolate* isolate, mojo::Handle handle)
-    : isolate_(isolate),
-      handle_(DataPipeConsumerHandle(handle.value())),
-      handle_watcher_(FROM_HERE, SimpleWatcher::ArmingPolicy::AUTOMATIC) {
-  v8::Local<v8::Context> context(isolate_->GetCurrentContext());
-  runner_ = gin::PerContextData::From(context)->runner()->GetWeakPtr();
-
-  WaitForData();
-}
-
-v8::Local<v8::Value> DrainData::GetPromise() {
-  CHECK(resolver_.IsEmpty());
-  v8::Local<v8::Promise::Resolver> resolver(
-      v8::Promise::Resolver::New(isolate_));
-  resolver_.Reset(isolate_, resolver);
-  return resolver->GetPromise();
-}
-
-DrainData::~DrainData() {
-  resolver_.Reset();
-}
-
-void DrainData::WaitForData() {
-  handle_watcher_.Watch(
-      handle_.get(), MOJO_HANDLE_SIGNAL_READABLE,
-      base::Bind(&DrainData::DataReady, base::Unretained(this)));
-}
-
-void DrainData::DataReady(MojoResult result) {
-  if (result != MOJO_RESULT_OK) {
-    DeliverData(result);
-    return;
-  }
-  while (result == MOJO_RESULT_OK) {
-    result = ReadData();
-    if (result == MOJO_RESULT_SHOULD_WAIT)
-      WaitForData();
-    else if (result != MOJO_RESULT_OK)
-      DeliverData(result);
-  }
-}
-
-MojoResult DrainData::ReadData() {
-  const void* buffer;
-  uint32_t num_bytes = 0;
-  MojoResult result =
-      handle_->BeginReadData(&buffer, &num_bytes, MOJO_READ_DATA_FLAG_NONE);
-  if (result != MOJO_RESULT_OK)
-    return result;
-  const char* p = static_cast<const char*>(buffer);
-  data_buffers_.push_back(std::make_unique<DataBuffer>(p, p + num_bytes));
-  return handle_->EndReadData(num_bytes);
-}
-
-void DrainData::DeliverData(MojoResult result) {
-  if (!runner_) {
-    delete this;
-    return;
-  }
-
-  size_t total_bytes = 0;
-  for (unsigned i = 0; i < data_buffers_.size(); i++)
-    total_bytes += data_buffers_[i]->size();
-
-  // Create a total_bytes length ArrayBuffer return value.
-  gin::Runner::Scope scope(runner_.get());
-  v8::Local<v8::ArrayBuffer> array_buffer =
-      v8::ArrayBuffer::New(isolate_, total_bytes);
-  gin::ArrayBuffer buffer;
-  ConvertFromV8(isolate_, array_buffer, &buffer);
-  CHECK_EQ(total_bytes, buffer.num_bytes());
-
-  // Copy the data_buffers into the ArrayBuffer.
-  char* array_buffer_ptr = static_cast<char*>(buffer.bytes());
-  size_t offset = 0;
-  for (size_t i = 0; i < data_buffers_.size(); i++) {
-    size_t num_bytes = data_buffers_[i]->size();
-    if (num_bytes == 0)
-      continue;
-    const char* data_buffer_ptr = &((*data_buffers_[i])[0]);
-    memcpy(array_buffer_ptr + offset, data_buffer_ptr, num_bytes);
-    offset += num_bytes;
-  }
-
-  // The "settled" value of the promise always includes all of the data
-  // that was read before either an error occurred or the remote pipe handle
-  // was closed. The latter is indicated by MOJO_RESULT_FAILED_PRECONDITION.
-
-  v8::Local<v8::Promise::Resolver> resolver(
-      v8::Local<v8::Promise::Resolver>::New(isolate_, resolver_));
-
-  gin::Dictionary dictionary = gin::Dictionary::CreateEmpty(isolate_);
-  dictionary.Set("result", result);
-  dictionary.Set("buffer", array_buffer);
-  v8::Local<v8::Value> settled_value(ConvertToV8(isolate_, dictionary));
-
-  if (result == MOJO_RESULT_FAILED_PRECONDITION)
-    resolver->Resolve(settled_value);
-  else
-    resolver->Reject(settled_value);
-
-  delete this;
-}
-
-}  // namespace js
-}  // namespace edk
-}  // namespace mojo
diff --git a/mojo/edk/js/drain_data.h b/mojo/edk/js/drain_data.h
deleted file mode 100644
index 42734893d..0000000
--- a/mojo/edk/js/drain_data.h
+++ /dev/null
@@ -1,65 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef MOJO_EDK_JS_DRAIN_DATA_H_
-#define MOJO_EDK_JS_DRAIN_DATA_H_
-
-#include <memory>
-#include <vector>
-
-#include "gin/runner.h"
-#include "mojo/public/cpp/system/core.h"
-#include "mojo/public/cpp/system/simple_watcher.h"
-#include "v8/include/v8.h"
-
-namespace mojo {
-namespace edk {
-namespace js {
-
-// This class is the implementation of the Mojo JavaScript core module's
-// drainData() method. It is not intended to be used directly. The caller
-// allocates a DrainData on the heap and returns GetPromise() to JS. The
-// implementation deletes itself after reading as much data as possible
-// and rejecting or resolving the Promise.
-
-class DrainData {
- public:
-  // Starts waiting for data on the specified data pipe consumer handle.
-  // See WaitForData(). The constructor does not block.
-  DrainData(v8::Isolate* isolate, mojo::Handle handle);
-
-  // Returns a Promise that will be settled when no more data can be read.
-  // Should be called just once on a newly allocated DrainData object.
-  v8::Local<v8::Value> GetPromise();
-
- private:
-  ~DrainData();
-
-  // Waits for data to be available. DataReady() will be notified.
-  void WaitForData();
-
-  // Use ReadData() to read whatever is availble now on handle_ and save
-  // it in data_buffers_.
-  void DataReady(MojoResult result);
-  MojoResult ReadData();
-
-  // When the remote data pipe handle is closed, or an error occurs, deliver
-  // all of the buffered data to the JS Promise and then delete this.
-  void DeliverData(MojoResult result);
-
-  using DataBuffer = std::vector<char>;
-
-  v8::Isolate* isolate_;
-  ScopedDataPipeConsumerHandle handle_;
-  SimpleWatcher handle_watcher_;
-  base::WeakPtr<gin::Runner> runner_;
-  v8::UniquePersistent<v8::Promise::Resolver> resolver_;
-  std::vector<std::unique_ptr<DataBuffer>> data_buffers_;
-};
-
-}  // namespace js
-}  // namespace edk
-}  // namespace mojo
-
-#endif  // MOJO_EDK_JS_DRAIN_DATA_H_
diff --git a/mojo/edk/js/handle.cc b/mojo/edk/js/handle.cc
deleted file mode 100644
index b120f96..0000000
--- a/mojo/edk/js/handle.cc
+++ /dev/null
@@ -1,86 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "mojo/edk/js/handle.h"
-
-#include "mojo/edk/js/handle_close_observer.h"
-
-namespace mojo {
-namespace edk {
-namespace js {
-
-gin::WrapperInfo HandleWrapper::kWrapperInfo = { gin::kEmbedderNativeGin };
-
-HandleWrapper::HandleWrapper(MojoHandle handle)
-    : handle_(mojo::Handle(handle)) {
-}
-
-HandleWrapper::~HandleWrapper() {
-  NotifyCloseObservers();
-}
-
-void HandleWrapper::Close() {
-  NotifyCloseObservers();
-  handle_.reset();
-}
-
-void HandleWrapper::AddCloseObserver(HandleCloseObserver* observer) {
-  close_observers_.AddObserver(observer);
-}
-
-void HandleWrapper::RemoveCloseObserver(HandleCloseObserver* observer) {
-  close_observers_.RemoveObserver(observer);
-}
-
-void HandleWrapper::NotifyCloseObservers() {
-  if (!handle_.is_valid())
-    return;
-
-  for (auto& observer : close_observers_)
-    observer.OnWillCloseHandle();
-}
-
-}  // namespace js
-}  // namespace edk
-}  // namespace mojo
-
-namespace gin {
-
-v8::Local<v8::Value> Converter<mojo::Handle>::ToV8(v8::Isolate* isolate,
-                                                   const mojo::Handle& val) {
-  if (!val.is_valid())
-    return v8::Null(isolate);
-  return mojo::edk::js::HandleWrapper::Create(isolate, val.value()).ToV8();
-}
-
-bool Converter<mojo::Handle>::FromV8(v8::Isolate* isolate,
-                                     v8::Local<v8::Value> val,
-                                     mojo::Handle* out) {
-  if (val->IsNull()) {
-    *out = mojo::Handle();
-    return true;
-  }
-
-  gin::Handle<mojo::edk::js::HandleWrapper> handle;
-  if (!Converter<gin::Handle<mojo::edk::js::HandleWrapper>>::FromV8(
-          isolate, val, &handle))
-    return false;
-
-  *out = handle->get();
-  return true;
-}
-
-v8::Local<v8::Value> Converter<mojo::MessagePipeHandle>::ToV8(
-    v8::Isolate* isolate,
-    mojo::MessagePipeHandle val) {
-  return Converter<mojo::Handle>::ToV8(isolate, val);
-}
-
-bool Converter<mojo::MessagePipeHandle>::FromV8(v8::Isolate* isolate,
-                                                v8::Local<v8::Value> val,
-                                                mojo::MessagePipeHandle* out) {
-  return Converter<mojo::Handle>::FromV8(isolate, val, out);
-}
-
-}  // namespace gin
diff --git a/mojo/edk/js/handle.h b/mojo/edk/js/handle.h
deleted file mode 100644
index af5cc1a..0000000
--- a/mojo/edk/js/handle.h
+++ /dev/null
@@ -1,108 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef MOJO_EDK_JS_HANDLE_H_
-#define MOJO_EDK_JS_HANDLE_H_
-
-#include <stdint.h>
-
-#include "base/observer_list.h"
-#include "gin/converter.h"
-#include "gin/handle.h"
-#include "gin/wrappable.h"
-#include "mojo/edk/js/js_export.h"
-#include "mojo/public/cpp/system/core.h"
-
-namespace mojo {
-namespace edk {
-namespace js {
-
-class HandleCloseObserver;
-
-// Wrapper for mojo Handles exposed to JavaScript. This ensures the Handle
-// is Closed when its JS object is garbage collected.
-class MOJO_JS_EXPORT HandleWrapper : public gin::Wrappable<HandleWrapper> {
- public:
-  static gin::WrapperInfo kWrapperInfo;
-
-  static gin::Handle<HandleWrapper> Create(v8::Isolate* isolate,
-                                           MojoHandle handle) {
-    return gin::CreateHandle(isolate, new HandleWrapper(handle));
-  }
-
-  mojo::Handle get() const { return handle_.get(); }
-  mojo::Handle release() { return handle_.release(); }
-  void Close();
-
-  void AddCloseObserver(HandleCloseObserver* observer);
-  void RemoveCloseObserver(HandleCloseObserver* observer);
-
- protected:
-  HandleWrapper(MojoHandle handle);
-  ~HandleWrapper() override;
-  void NotifyCloseObservers();
-
-  mojo::ScopedHandle handle_;
-  base::ObserverList<HandleCloseObserver> close_observers_;
-};
-
-}  // namespace js
-}  // namespace edk
-}  // namespace mojo
-
-namespace gin {
-
-// Note: It's important to use this converter rather than the one for
-// MojoHandle, since that will do a simple int32_t conversion. It's unfortunate
-// there's no way to prevent against accidental use.
-// TODO(mpcomplete): define converters for all Handle subtypes.
-template <>
-struct MOJO_JS_EXPORT Converter<mojo::Handle> {
-  static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
-                                   const mojo::Handle& val);
-  static bool FromV8(v8::Isolate* isolate,
-                     v8::Local<v8::Value> val,
-                     mojo::Handle* out);
-};
-
-template <>
-struct MOJO_JS_EXPORT Converter<mojo::MessagePipeHandle> {
-  static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
-                                   mojo::MessagePipeHandle val);
-  static bool FromV8(v8::Isolate* isolate,
-                     v8::Local<v8::Value> val,
-                     mojo::MessagePipeHandle* out);
-};
-
-// We need to specialize the normal gin::Handle converter in order to handle
-// converting |null| to a wrapper for an empty mojo::Handle.
-template <>
-struct MOJO_JS_EXPORT Converter<gin::Handle<mojo::edk::js::HandleWrapper>> {
-  static v8::Local<v8::Value> ToV8(
-      v8::Isolate* isolate,
-      const gin::Handle<mojo::edk::js::HandleWrapper>& val) {
-    return val.ToV8();
-  }
-
-  static bool FromV8(v8::Isolate* isolate,
-                     v8::Local<v8::Value> val,
-                     gin::Handle<mojo::edk::js::HandleWrapper>* out) {
-    if (val->IsNull()) {
-      *out = mojo::edk::js::HandleWrapper::Create(isolate, MOJO_HANDLE_INVALID);
-      return true;
-    }
-
-    mojo::edk::js::HandleWrapper* object = NULL;
-    if (!Converter<mojo::edk::js::HandleWrapper*>::FromV8(isolate, val,
-                                                          &object)) {
-      return false;
-    }
-    *out = gin::Handle<mojo::edk::js::HandleWrapper>(val, object);
-    return true;
-  }
-};
-
-}  // namespace gin
-
-#endif  // MOJO_EDK_JS_HANDLE_H_
diff --git a/mojo/edk/js/handle_close_observer.h b/mojo/edk/js/handle_close_observer.h
deleted file mode 100644
index c7b935ec..0000000
--- a/mojo/edk/js/handle_close_observer.h
+++ /dev/null
@@ -1,24 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef MOJO_EDK_JS_HANDLE_CLOSE_OBSERVER_H_
-#define MOJO_EDK_JS_HANDLE_CLOSE_OBSERVER_H_
-
-namespace mojo {
-namespace edk {
-namespace js {
-
-class HandleCloseObserver {
- public:
-  virtual void OnWillCloseHandle() = 0;
-
- protected:
-  virtual ~HandleCloseObserver() {}
-};
-
-}  // namespace js
-}  // namespace edk
-}  // namespace mojo
-
-#endif  // MOJO_EDK_JS_HANDLE_CLOSE_OBSERVER_H_
diff --git a/mojo/edk/js/handle_unittest.cc b/mojo/edk/js/handle_unittest.cc
deleted file mode 100644
index dd2562f..0000000
--- a/mojo/edk/js/handle_unittest.cc
+++ /dev/null
@@ -1,92 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "base/macros.h"
-#include "mojo/edk/js/handle.h"
-#include "mojo/edk/js/handle_close_observer.h"
-#include "mojo/public/cpp/system/core.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace mojo {
-namespace edk {
-namespace js {
-
-class HandleWrapperTest : public testing::Test,
-                          public HandleCloseObserver {
- public:
-  HandleWrapperTest() : closes_observed_(0) {}
-
-  void OnWillCloseHandle() override { closes_observed_++; }
-
- protected:
-  int closes_observed_;
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(HandleWrapperTest);
-};
-
-class TestHandleWrapper : public HandleWrapper {
- public:
-  explicit TestHandleWrapper(MojoHandle handle) : HandleWrapper(handle) {}
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(TestHandleWrapper);
-};
-
-// Test that calling Close() on a HandleWrapper for an invalid handle does not
-// notify observers.
-TEST_F(HandleWrapperTest, CloseWithInvalidHandle) {
-  {
-    TestHandleWrapper wrapper(MOJO_HANDLE_INVALID);
-    wrapper.AddCloseObserver(this);
-    ASSERT_EQ(0, closes_observed_);
-    wrapper.Close();
-    EXPECT_EQ(0, closes_observed_);
-  }
-  EXPECT_EQ(0, closes_observed_);
-}
-
-// Test that destroying a HandleWrapper for an invalid handle does not notify
-// observers.
-TEST_F(HandleWrapperTest, DestroyWithInvalidHandle) {
-  {
-    TestHandleWrapper wrapper(MOJO_HANDLE_INVALID);
-    wrapper.AddCloseObserver(this);
-    ASSERT_EQ(0, closes_observed_);
-  }
-  EXPECT_EQ(0, closes_observed_);
-}
-
-// Test that calling Close on a HandleWrapper for a valid handle notifies
-// observers once.
-TEST_F(HandleWrapperTest, CloseWithValidHandle) {
-  {
-    mojo::MessagePipe pipe;
-    TestHandleWrapper wrapper(pipe.handle0.release().value());
-    wrapper.AddCloseObserver(this);
-    ASSERT_EQ(0, closes_observed_);
-    wrapper.Close();
-    EXPECT_EQ(1, closes_observed_);
-    // Check that calling close again doesn't notify observers.
-    wrapper.Close();
-    EXPECT_EQ(1, closes_observed_);
-  }
-  // Check that destroying a closed HandleWrapper doesn't notify observers.
-  EXPECT_EQ(1, closes_observed_);
-}
-
-// Test that destroying a HandleWrapper for a valid handle notifies observers.
-TEST_F(HandleWrapperTest, DestroyWithValidHandle) {
-  {
-    mojo::MessagePipe pipe;
-    TestHandleWrapper wrapper(pipe.handle0.release().value());
-    wrapper.AddCloseObserver(this);
-    ASSERT_EQ(0, closes_observed_);
-  }
-  EXPECT_EQ(1, closes_observed_);
-}
-
-}  // namespace js
-}  // namespace edk
-}  // namespace mojo
diff --git a/mojo/edk/js/js_export.h b/mojo/edk/js/js_export.h
deleted file mode 100644
index 179113c..0000000
--- a/mojo/edk/js/js_export.h
+++ /dev/null
@@ -1,32 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef MOJO_EDK_JS_JS_EXPORT_H_
-#define MOJO_EDK_JS_JS_EXPORT_H_
-
-// Defines MOJO_JS_EXPORT so that functionality implemented by //mojo/edk/js can
-// be exported to consumers.
-
-#if defined(COMPONENT_BUILD)
-#if defined(WIN32)
-
-#if defined(MOJO_JS_IMPLEMENTATION)
-#define MOJO_JS_EXPORT __declspec(dllexport)
-#else
-#define MOJO_JS_EXPORT __declspec(dllimport)
-#endif  // defined(MOJO_JS_IMPLEMENTATION)
-
-#else  // defined(WIN32)
-#if defined(MOJO_JS_IMPLEMENTATION)
-#define MOJO_JS_EXPORT __attribute__((visibility("default")))
-#else
-#define MOJO_JS_EXPORT
-#endif
-#endif
-
-#else  // defined(COMPONENT_BUILD)
-#define MOJO_JS_EXPORT
-#endif
-
-#endif  // MOJO_EDK_JS_JS_EXPORT_H_
diff --git a/mojo/edk/js/mojo_runner_delegate.cc b/mojo/edk/js/mojo_runner_delegate.cc
deleted file mode 100644
index 5d001f9..0000000
--- a/mojo/edk/js/mojo_runner_delegate.cc
+++ /dev/null
@@ -1,79 +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.
-
-#include "mojo/edk/js/mojo_runner_delegate.h"
-
-#include "base/bind.h"
-#include "base/path_service.h"
-#include "gin/converter.h"
-#include "gin/modules/console.h"
-#include "gin/modules/module_registry.h"
-#include "gin/modules/timer.h"
-#include "gin/try_catch.h"
-#include "mojo/edk/js/core.h"
-#include "mojo/edk/js/handle.h"
-#include "mojo/edk/js/support.h"
-#include "mojo/edk/js/threading.h"
-
-namespace mojo {
-namespace edk {
-namespace js {
-
-namespace {
-
-// TODO(abarth): Rather than loading these modules from the file system, we
-// should load them from the network via Mojo IPC.
-std::vector<base::FilePath> GetModuleSearchPaths() {
-  std::vector<base::FilePath> search_paths(2);
-  PathService::Get(base::DIR_SOURCE_ROOT, &search_paths[0]);
-  PathService::Get(base::DIR_EXE, &search_paths[1]);
-  search_paths[1] = search_paths[1].AppendASCII("gen");
-  return search_paths;
-}
-
-void StartCallback(base::WeakPtr<gin::Runner> runner,
-                   MojoHandle pipe,
-                   v8::Local<v8::Value> module) {
-  v8::Isolate* isolate = runner->GetContextHolder()->isolate();
-  v8::Local<v8::Function> start;
-  CHECK(gin::ConvertFromV8(isolate, module, &start));
-
-  v8::Local<v8::Value> args[] = {gin::ConvertToV8(isolate, Handle(pipe))};
-  runner->Call(start, runner->global(), 1, args);
-}
-
-}  // namespace
-
-MojoRunnerDelegate::MojoRunnerDelegate()
-    : ModuleRunnerDelegate(GetModuleSearchPaths()) {
-  AddBuiltinModule(gin::Console::kModuleName, gin::Console::GetModule);
-  AddBuiltinModule(gin::TimerModule::kName, gin::TimerModule::GetModule);
-  AddBuiltinModule(Core::kModuleName, Core::GetModule);
-  AddBuiltinModule(Support::kModuleName, Support::GetModule);
-  AddBuiltinModule(Threading::kModuleName, Threading::GetModule);
-}
-
-MojoRunnerDelegate::~MojoRunnerDelegate() {
-}
-
-void MojoRunnerDelegate::Start(gin::Runner* runner,
-                               MojoHandle pipe,
-                               const std::string& module) {
-  gin::Runner::Scope scope(runner);
-  gin::ModuleRegistry* registry =
-      gin::ModuleRegistry::From(runner->GetContextHolder()->context());
-  registry->LoadModule(runner->GetContextHolder()->isolate(), module,
-                       base::Bind(StartCallback, runner->GetWeakPtr(), pipe));
-  AttemptToLoadMoreModules(runner);
-}
-
-void MojoRunnerDelegate::UnhandledException(gin::ShellRunner* runner,
-                                            gin::TryCatch& try_catch) {
-  gin::ModuleRunnerDelegate::UnhandledException(runner, try_catch);
-  LOG(ERROR) << try_catch.GetStackTrace();
-}
-
-}  // namespace js
-}  // namespace edk
-}  // namespace mojo
diff --git a/mojo/edk/js/mojo_runner_delegate.h b/mojo/edk/js/mojo_runner_delegate.h
deleted file mode 100644
index 9ab325c..0000000
--- a/mojo/edk/js/mojo_runner_delegate.h
+++ /dev/null
@@ -1,36 +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.
-
-#ifndef MOJO_EDK_JS_MOJO_RUNNER_DELEGATE_H_
-#define MOJO_EDK_JS_MOJO_RUNNER_DELEGATE_H_
-
-#include "base/macros.h"
-#include "gin/modules/module_runner_delegate.h"
-#include "mojo/edk/js/js_export.h"
-#include "mojo/public/c/system/core.h"
-
-namespace mojo {
-namespace edk {
-namespace js {
-
-class MOJO_JS_EXPORT MojoRunnerDelegate : public gin::ModuleRunnerDelegate {
- public:
-  MojoRunnerDelegate();
-  ~MojoRunnerDelegate() override;
-
-  void Start(gin::Runner* runner, MojoHandle pipe, const std::string& module);
-
- private:
-  // From ModuleRunnerDelegate:
-  void UnhandledException(gin::ShellRunner* runner,
-                          gin::TryCatch& try_catch) override;
-
-  DISALLOW_COPY_AND_ASSIGN(MojoRunnerDelegate);
-};
-
-}  // namespace js
-}  // namespace edk
-}  // namespace mojo
-
-#endif  // MOJO_EDK_JS_MOJO_RUNNER_DELEGATE_H_
diff --git a/mojo/edk/js/support.cc b/mojo/edk/js/support.cc
deleted file mode 100644
index 21ce0d0d..0000000
--- a/mojo/edk/js/support.cc
+++ /dev/null
@@ -1,77 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "mojo/edk/js/support.h"
-
-#include "base/bind.h"
-#include "gin/arguments.h"
-#include "gin/converter.h"
-#include "gin/function_template.h"
-#include "gin/object_template_builder.h"
-#include "gin/per_isolate_data.h"
-#include "gin/public/wrapper_info.h"
-#include "gin/wrappable.h"
-#include "mojo/edk/js/handle.h"
-#include "mojo/edk/js/waiting_callback.h"
-#include "mojo/public/cpp/system/core.h"
-
-namespace mojo {
-namespace edk {
-namespace js {
-
-namespace {
-
-WaitingCallback* AsyncWait(const gin::Arguments& args,
-                           gin::Handle<HandleWrapper> handle,
-                           MojoHandleSignals signals,
-                           v8::Local<v8::Function> callback) {
-  return WaitingCallback::Create(
-      args.isolate(), callback, handle, signals, true /* one_shot */).get();
-}
-
-void CancelWait(WaitingCallback* waiting_callback) {
-  waiting_callback->Cancel();
-}
-
-WaitingCallback* Watch(const gin::Arguments& args,
-                       gin::Handle<HandleWrapper> handle,
-                       MojoHandleSignals signals,
-                       v8::Local<v8::Function> callback) {
-  return WaitingCallback::Create(
-      args.isolate(), callback, handle, signals, false /* one_shot */).get();
-}
-
-void CancelWatch(WaitingCallback* waiting_callback) {
-  waiting_callback->Cancel();
-}
-
-gin::WrapperInfo g_wrapper_info = { gin::kEmbedderNativeGin };
-
-}  // namespace
-
-const char Support::kModuleName[] = "mojo/public/js/support";
-
-v8::Local<v8::Value> Support::GetModule(v8::Isolate* isolate) {
-  gin::PerIsolateData* data = gin::PerIsolateData::From(isolate);
-  v8::Local<v8::ObjectTemplate> templ = data->GetObjectTemplate(
-      &g_wrapper_info);
-
-  if (templ.IsEmpty()) {
-    templ = gin::ObjectTemplateBuilder(isolate)
-                // TODO(rockot): Remove asyncWait and cancelWait.
-                .SetMethod("asyncWait", AsyncWait)
-                .SetMethod("cancelWait", CancelWait)
-                .SetMethod("watch", Watch)
-                .SetMethod("cancelWatch", CancelWatch)
-                .Build();
-
-    data->SetObjectTemplate(&g_wrapper_info, templ);
-  }
-
-  return templ->NewInstance();
-}
-
-}  // namespace js
-}  // namespace edk
-}  // namespace mojo
diff --git a/mojo/edk/js/support.h b/mojo/edk/js/support.h
deleted file mode 100644
index 551f5ac0..0000000
--- a/mojo/edk/js/support.h
+++ /dev/null
@@ -1,25 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef MOJO_EDK_JS_SUPPORT_H_
-#define MOJO_EDK_JS_SUPPORT_H_
-
-#include "mojo/edk/js/js_export.h"
-#include "v8/include/v8.h"
-
-namespace mojo {
-namespace edk {
-namespace js {
-
-class MOJO_JS_EXPORT Support {
- public:
-  static const char kModuleName[];
-  static v8::Local<v8::Value> GetModule(v8::Isolate* isolate);
-};
-
-}  // namespace js
-}  // namespace edk
-}  // namespace mojo
-
-#endif  // MOJO_EDK_JS_SUPPORT_H_
diff --git a/mojo/edk/js/tests/BUILD.gn b/mojo/edk/js/tests/BUILD.gn
deleted file mode 100644
index 53e79d2..0000000
--- a/mojo/edk/js/tests/BUILD.gn
+++ /dev/null
@@ -1,37 +0,0 @@
-# Copyright 2014 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-import("//mojo/public/tools/bindings/mojom.gni")
-import("//testing/test.gni")
-
-# TODO(hansmuller): The organization of tests in this directory is weird:
-#   * Really, js_unittests tests public stuff, so that should live in public
-#     and be reworked as some sort of apptest.
-#   * Both js_unittests and js_integration_tests should auto-generate their
-#     tests somehow. The .cc files are just test runner stubs, including
-#     explicit lists of .js files.
-
-group("tests") {
-  testonly = true
-  deps = [
-    ":mojo_js_unittests",
-  ]
-}
-
-test("mojo_js_unittests") {
-  deps = [
-    "//base",
-    "//gin:gin_test",
-    "//mojo/edk/js",
-    "//mojo/edk/test:run_all_unittests",
-    "//mojo/edk/test:test_support",
-    "//mojo/public/cpp/system",
-    "//mojo/public/js:tests",
-  ]
-
-  sources = [
-    "//mojo/edk/js/handle_unittest.cc",
-    "run_js_unittests.cc",
-  ]
-}
diff --git a/mojo/edk/js/tests/OWNERS b/mojo/edk/js/tests/OWNERS
deleted file mode 100644
index 6c1f2fb..0000000
--- a/mojo/edk/js/tests/OWNERS
+++ /dev/null
@@ -1,6 +0,0 @@
-per-file *.mojom=file://mojo/OWNERS
-
-# These mojom test files don't really require security review, but we need to
-# add these to please PRESUBMIT.
-per-file *.mojom=set noparent
-per-file *.mojom=file://ipc/SECURITY_OWNERS
diff --git a/mojo/edk/js/tests/run_js_unittests.cc b/mojo/edk/js/tests/run_js_unittests.cc
deleted file mode 100644
index 26d3b67..0000000
--- a/mojo/edk/js/tests/run_js_unittests.cc
+++ /dev/null
@@ -1,57 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "base/files/file_path.h"
-#include "base/macros.h"
-#include "base/path_service.h"
-#include "gin/modules/console.h"
-#include "gin/modules/module_registry.h"
-#include "gin/modules/timer.h"
-#include "gin/test/file_runner.h"
-#include "gin/test/gtest.h"
-#include "mojo/edk/js/core.h"
-#include "mojo/edk/js/support.h"
-#include "mojo/edk/js/threading.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace mojo {
-namespace edk {
-namespace js {
-namespace {
-
-class TestRunnerDelegate : public gin::FileRunnerDelegate {
- public:
-  TestRunnerDelegate() {
-    AddBuiltinModule(gin::Console::kModuleName, gin::Console::GetModule);
-    AddBuiltinModule(gin::TimerModule::kName, gin::TimerModule::GetModule);
-    AddBuiltinModule(Core::kModuleName, Core::GetModule);
-    AddBuiltinModule(Threading::kModuleName, Threading::GetModule);
-    AddBuiltinModule(Support::kModuleName, Support::GetModule);
-  }
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(TestRunnerDelegate);
-};
-
-void RunTest(std::string test, bool run_until_idle) {
-  base::FilePath path;
-  PathService::Get(base::DIR_SOURCE_ROOT, &path);
-  path = path.AppendASCII("mojo")
-             .AppendASCII("public")
-             .AppendASCII("js")
-             .AppendASCII("tests")
-             .AppendASCII(test);
-  TestRunnerDelegate delegate;
-  gin::RunTestFromFile(path, &delegate, run_until_idle);
-}
-
-// TODO(abarth): Should we autogenerate these stubs from GYP?
-TEST(JSTest, Core) {
-  RunTest("core_unittest.js", true);
-}
-
-}  // namespace
-}  // namespace js
-}  // namespace edk
-}  // namespace mojo
diff --git a/mojo/edk/js/threading.cc b/mojo/edk/js/threading.cc
deleted file mode 100644
index 47cb3c5..0000000
--- a/mojo/edk/js/threading.cc
+++ /dev/null
@@ -1,49 +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.
-
-#include "mojo/edk/js/threading.h"
-
-#include "base/run_loop.h"
-#include "gin/object_template_builder.h"
-#include "gin/per_isolate_data.h"
-#include "mojo/edk/js/handle.h"
-
-namespace mojo {
-namespace edk {
-namespace js {
-
-namespace {
-
-void Quit() {
-  base::RunLoop::QuitCurrentDeprecated();
-}
-
-gin::WrapperInfo g_wrapper_info = { gin::kEmbedderNativeGin };
-
-}  // namespace
-
-const char Threading::kModuleName[] = "mojo/public/js/threading";
-
-v8::Local<v8::Value> Threading::GetModule(v8::Isolate* isolate) {
-  gin::PerIsolateData* data = gin::PerIsolateData::From(isolate);
-  v8::Local<v8::ObjectTemplate> templ = data->GetObjectTemplate(
-      &g_wrapper_info);
-
-  if (templ.IsEmpty()) {
-    templ = gin::ObjectTemplateBuilder(isolate)
-        .SetMethod("quit", Quit)
-        .Build();
-
-    data->SetObjectTemplate(&g_wrapper_info, templ);
-  }
-
-  return templ->NewInstance();
-}
-
-Threading::Threading() {
-}
-
-}  // namespace js
-}  // namespace edk
-}  // namespace mojo
diff --git a/mojo/edk/js/threading.h b/mojo/edk/js/threading.h
deleted file mode 100644
index 653d076..0000000
--- a/mojo/edk/js/threading.h
+++ /dev/null
@@ -1,28 +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.
-
-#ifndef MOJO_EDK_JS_THREADING_H_
-#define MOJO_EDK_JS_THREADING_H_
-
-#include "gin/public/wrapper_info.h"
-#include "mojo/edk/js/js_export.h"
-#include "v8/include/v8.h"
-
-namespace mojo {
-namespace edk {
-namespace js {
-
-class MOJO_JS_EXPORT Threading {
- public:
-  static const char kModuleName[];
-  static v8::Local<v8::Value> GetModule(v8::Isolate* isolate);
- private:
-  Threading();
-};
-
-}  // namespace js
-}  // namespace edk
-}  // namespace mojo
-
-#endif  // MOJO_EDK_JS_THREADING_H_
diff --git a/mojo/edk/js/waiting_callback.cc b/mojo/edk/js/waiting_callback.cc
deleted file mode 100644
index d9c920a..0000000
--- a/mojo/edk/js/waiting_callback.cc
+++ /dev/null
@@ -1,102 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "mojo/edk/js/waiting_callback.h"
-
-#include "base/bind.h"
-#include "base/message_loop/message_loop.h"
-#include "gin/per_context_data.h"
-
-namespace mojo {
-namespace edk {
-namespace js {
-
-namespace {
-
-v8::Local<v8::Private> GetHiddenPropertyName(v8::Isolate* isolate) {
-  return v8::Private::ForApi(
-      isolate, gin::StringToV8(isolate, "::mojo::js::WaitingCallback"));
-}
-
-}  // namespace
-
-gin::WrapperInfo WaitingCallback::kWrapperInfo = { gin::kEmbedderNativeGin };
-
-// static
-gin::Handle<WaitingCallback> WaitingCallback::Create(
-    v8::Isolate* isolate,
-    v8::Local<v8::Function> callback,
-    gin::Handle<HandleWrapper> handle_wrapper,
-    MojoHandleSignals signals,
-    bool one_shot) {
-  gin::Handle<WaitingCallback> waiting_callback = gin::CreateHandle(
-      isolate, new WaitingCallback(isolate, callback, one_shot));
-  MojoResult result = waiting_callback->watcher_.Watch(
-      handle_wrapper->get(), signals,
-      base::Bind(&WaitingCallback::OnHandleReady,
-                 base::Unretained(waiting_callback.get())));
-
-  // The signals may already be unsatisfiable.
-  if (result == MOJO_RESULT_FAILED_PRECONDITION)
-    waiting_callback->OnHandleReady(MOJO_RESULT_FAILED_PRECONDITION);
-
-  return waiting_callback;
-}
-
-void WaitingCallback::Cancel() {
-  if (watcher_.IsWatching())
-    watcher_.Cancel();
-}
-
-WaitingCallback::WaitingCallback(v8::Isolate* isolate,
-                                 v8::Local<v8::Function> callback,
-                                 bool one_shot)
-    : one_shot_(one_shot),
-      watcher_(FROM_HERE, SimpleWatcher::ArmingPolicy::AUTOMATIC),
-      weak_factory_(this) {
-  v8::Local<v8::Context> context = isolate->GetCurrentContext();
-  runner_ = gin::PerContextData::From(context)->runner()->GetWeakPtr();
-  v8::Maybe<bool> result = GetWrapper(isolate).ToLocalChecked()->SetPrivate(
-      context, GetHiddenPropertyName(isolate), callback);
-  DCHECK(result.IsJust() && result.FromJust());
-}
-
-WaitingCallback::~WaitingCallback() {
-  Cancel();
-}
-
-void WaitingCallback::OnHandleReady(MojoResult result) {
-  if (!runner_)
-    return;
-
-  gin::Runner::Scope scope(runner_.get());
-  v8::Isolate* isolate = runner_->GetContextHolder()->isolate();
-
-  v8::Local<v8::Object> wrapper;
-  if (!GetWrapper(isolate).ToLocal(&wrapper)) {
-    Cancel();
-    return;
-  }
-
-  v8::Local<v8::Value> hidden_value =
-      wrapper
-          ->GetPrivate(runner_->GetContextHolder()->context(),
-                       GetHiddenPropertyName(isolate))
-          .ToLocalChecked();
-  v8::Local<v8::Function> callback;
-  bool convert_result = gin::ConvertFromV8(isolate, hidden_value, &callback);
-  DCHECK(convert_result);
-
-  v8::Local<v8::Value> args[] = {gin::ConvertToV8(isolate, result)};
-  runner_->Call(callback, runner_->global(), 1, args);
-
-  if (one_shot_ || result == MOJO_RESULT_CANCELLED) {
-    runner_.reset();
-    Cancel();
-  }
-}
-
-}  // namespace js
-}  // namespace edk
-}  // namespace mojo
diff --git a/mojo/edk/js/waiting_callback.h b/mojo/edk/js/waiting_callback.h
deleted file mode 100644
index 03518fe..0000000
--- a/mojo/edk/js/waiting_callback.h
+++ /dev/null
@@ -1,67 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef MOJO_EDK_JS_WAITING_CALLBACK_H_
-#define MOJO_EDK_JS_WAITING_CALLBACK_H_
-
-#include "base/macros.h"
-#include "base/memory/weak_ptr.h"
-#include "gin/handle.h"
-#include "gin/runner.h"
-#include "gin/wrappable.h"
-#include "mojo/edk/js/handle.h"
-#include "mojo/public/cpp/system/core.h"
-#include "mojo/public/cpp/system/simple_watcher.h"
-
-namespace mojo {
-namespace edk {
-namespace js {
-
-class WaitingCallback : public gin::Wrappable<WaitingCallback> {
- public:
-  static gin::WrapperInfo kWrapperInfo;
-
-  // Creates a new WaitingCallback.
-  //
-  // If |one_shot| is true, the callback will only ever be called at most once.
-  // If false, the callback may be called any number of times until the
-  // WaitingCallback is explicitly cancelled.
-  static gin::Handle<WaitingCallback> Create(
-      v8::Isolate* isolate,
-      v8::Local<v8::Function> callback,
-      gin::Handle<HandleWrapper> handle_wrapper,
-      MojoHandleSignals signals,
-      bool one_shot);
-
-  // Cancels the callback. Does nothing if a callback is not pending. This is
-  // implicitly invoked from the destructor but can be explicitly invoked as
-  // necessary.
-  void Cancel();
-
- private:
-  WaitingCallback(v8::Isolate* isolate,
-                  v8::Local<v8::Function> callback,
-                  bool one_shot);
-  ~WaitingCallback() override;
-
-  // Callback from the Watcher.
-  void OnHandleReady(MojoResult result);
-
-  // Indicates whether this is a one-shot callback or not. If so, it uses the
-  // deprecated HandleWatcher to wait for signals; otherwise it uses the new
-  // system Watcher API.
-  const bool one_shot_;
-
-  base::WeakPtr<gin::Runner> runner_;
-  SimpleWatcher watcher_;
-  base::WeakPtrFactory<WaitingCallback> weak_factory_;
-
-  DISALLOW_COPY_AND_ASSIGN(WaitingCallback);
-};
-
-}  // namespace js
-}  // namespace edk
-}  // namespace mojo
-
-#endif  // MOJO_EDK_JS_WAITING_CALLBACK_H_
diff --git a/mojo/public/BUILD.gn b/mojo/public/BUILD.gn
index fdb8dee..bd094c8c 100644
--- a/mojo/public/BUILD.gn
+++ b/mojo/public/BUILD.gn
@@ -23,7 +23,6 @@
   deps = [
     "c/system",
     "cpp/bindings",
-    "js",
   ]
 }
 
diff --git a/mojo/public/cpp/bindings/README.md b/mojo/public/cpp/bindings/README.md
index d894732..fb46a93 100644
--- a/mojo/public/cpp/bindings/README.md
+++ b/mojo/public/cpp/bindings/README.md
@@ -471,6 +471,8 @@
 message. Thus the `impl` above will first log our message and *then* see a
 connection error and break out of the run loop.
 
+## Types
+
 ### Enums
 
 [Mojom enums](/mojo/public/tools/bindings#Enumeration-Types) translate directly
@@ -1448,6 +1450,10 @@
 inline bool IsKnownEnumValue(Department value);
 ```
 
+### Using Mojo Bindings in Chrome
+
+See [Converting Legacy Chrome IPC To Mojo](/ipc).
+
 ### Additional Documentation
 
 [Calling Mojo From Blink](https://www.chromium.org/developers/design-documents/mojo/calling-mojo-from-blink)
diff --git a/mojo/public/interfaces/bindings/BUILD.gn b/mojo/public/interfaces/bindings/BUILD.gn
index 4608db0..9821a5f7 100644
--- a/mojo/public/interfaces/bindings/BUILD.gn
+++ b/mojo/public/interfaces/bindings/BUILD.gn
@@ -22,16 +22,4 @@
   export_class_attribute_shared = "MOJO_CPP_BINDINGS_EXPORT"
   export_define_shared = "MOJO_CPP_BINDINGS_IMPLEMENTATION"
   export_header_shared = "mojo/public/cpp/bindings/bindings_export.h"
-
-  use_new_js_bindings = false
-}
-
-# TODO(yzshen): Remove this target and use the one above once
-# |use_new_js_bindings| becomes true by default.
-mojom("new_bindings") {
-  visibility = []
-  sources = [
-    "new_bindings/interface_control_messages.mojom",
-    "new_bindings/pipe_control_messages.mojom",
-  ]
 }
diff --git a/mojo/public/interfaces/bindings/new_bindings/OWNERS b/mojo/public/interfaces/bindings/new_bindings/OWNERS
deleted file mode 100644
index 08850f4..0000000
--- a/mojo/public/interfaces/bindings/new_bindings/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-per-file *.mojom=set noparent
-per-file *.mojom=file://ipc/SECURITY_OWNERS
diff --git a/mojo/public/interfaces/bindings/new_bindings/interface_control_messages.mojom b/mojo/public/interfaces/bindings/new_bindings/interface_control_messages.mojom
deleted file mode 100644
index e03ffd6..0000000
--- a/mojo/public/interfaces/bindings/new_bindings/interface_control_messages.mojom
+++ /dev/null
@@ -1,67 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-[JavaPackage="org.chromium.mojo.bindings.interfacecontrol"]
-module mojo.interface_control2;
-
-// For each user-defined interface, some control functions are provided by the
-// interface endpoints at both sides.
-
-////////////////////////////////////////////////////////////////////////////////
-// Run@0xFFFFFFFF(RunInput input) => (RunOutput? output);
-//
-// This control function runs the input command. If the command is not
-// supported, |output| is set to null; otherwise |output| stores the result,
-// whose type depends on the input.
-
-const uint32 kRunMessageId = 0xFFFFFFFF;
-
-struct RunMessageParams {
-  RunInput input;
-};
-union RunInput {
-  QueryVersion query_version;
-  FlushForTesting flush_for_testing;
-};
-
-struct RunResponseMessageParams {
-  RunOutput? output;
-};
-union RunOutput {
-  QueryVersionResult query_version_result;
-};
-
-// Queries the max supported version of the user-defined interface.
-// Sent by the interface client side.
-struct QueryVersion {
-};
-struct QueryVersionResult {
-  uint32 version;
-};
-
-// Sent by either side of the interface.
-struct FlushForTesting {
-};
-
-////////////////////////////////////////////////////////////////////////////////
-// RunOrClosePipe@0xFFFFFFFE(RunOrClosePipeInput input);
-//
-// This control function runs the input command. If the operation fails or the
-// command is not supported, the message pipe is closed.
-
-const uint32 kRunOrClosePipeMessageId = 0xFFFFFFFE;
-
-struct RunOrClosePipeMessageParams {
-  RunOrClosePipeInput input;
-};
-union RunOrClosePipeInput {
-  RequireVersion require_version;
-};
-
-// If the specified version of the user-defined interface is not supported, the
-// function fails and the pipe is closed.
-// Sent by the interface client side.
-struct RequireVersion {
-  uint32 version;
-};
diff --git a/mojo/public/interfaces/bindings/new_bindings/pipe_control_messages.mojom b/mojo/public/interfaces/bindings/new_bindings/pipe_control_messages.mojom
deleted file mode 100644
index 69975fc1..0000000
--- a/mojo/public/interfaces/bindings/new_bindings/pipe_control_messages.mojom
+++ /dev/null
@@ -1,46 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-[JavaPackage="org.chromium.mojo.bindings.pipecontrol"]
-module mojo.pipe_control2;
-
-// For each message pipe running user-defined interfaces, some control
-// functions are provided and used by the routers at both ends of the pipe, so
-// that they can coordinate to manage interface endpoints.
-// All these control messages will have the interface ID field in the message
-// header set to invalid.
-
-////////////////////////////////////////////////////////////////////////////////
-// RunOrClosePipe@0xFFFFFFFE(RunOrClosePipeInput input);
-//
-// This control function runs the input command. If the operation fails or the
-// command is not supported, the message pipe is closed.
-
-const uint32 kRunOrClosePipeMessageId = 0xFFFFFFFE;
-
-struct RunOrClosePipeMessageParams {
-  RunOrClosePipeInput input;
-};
-
-union RunOrClosePipeInput {
-  PeerAssociatedEndpointClosedEvent peer_associated_endpoint_closed_event;
-};
-
-// A user-defined reason about why the interface is disconnected.
-struct DisconnectReason {
-  uint32 custom_reason;
-  string description;
-};
-
-// An event to notify that an interface endpoint set up at the message sender
-// side has been closed.
-//
-// This event is omitted if the endpoint belongs to the master interface and
-// there is no disconnect reason specified.
-struct PeerAssociatedEndpointClosedEvent {
-  // The interface ID.
-  uint32 id;
-  DisconnectReason? disconnect_reason;
-};
-
diff --git a/mojo/public/js/BUILD.gn b/mojo/public/js/BUILD.gn
index 7b7f4990..7a1e0873 100644
--- a/mojo/public/js/BUILD.gn
+++ b/mojo/public/js/BUILD.gn
@@ -6,42 +6,7 @@
 
 interfaces_bindings_gen_dir = "$root_gen_dir/mojo/public/interfaces/bindings"
 
-source_set("js") {
-  sources = [
-    "constants.cc",
-    "constants.h",
-  ]
-}
-
-group("bindings") {
-  data = [
-    "$interfaces_bindings_gen_dir/interface_control_messages.mojom.js",
-    "$interfaces_bindings_gen_dir/pipe_control_messages.mojom.js",
-    "associated_bindings.js",
-    "bindings.js",
-    "buffer.js",
-    "codec.js",
-    "connector.js",
-    "core.js",
-    "interface_types.js",
-    "lib/control_message_handler.js",
-    "lib/control_message_proxy.js",
-    "lib/interface_endpoint_client.js",
-    "lib/interface_endpoint_handle.js",
-    "lib/pipe_control_message_handler.js",
-    "lib/pipe_control_message_proxy.js",
-    "router.js",
-    "support.js",
-    "threading.js",
-    "unicode.js",
-    "validator.js",
-  ]
-
-  public_deps = [
-    "//mojo/public/interfaces/bindings:bindings_js__generator",
-  ]
-}
-
+# TODO(yzshen): Rename to "bindings" and move the files accordingly.
 action("new_bindings") {
   new_bindings_js_files = [
     # This must be the first file in the list, because it initializes global
@@ -64,8 +29,8 @@
     "new_bindings/validator.js",
 
     # These two needs to refer to codec.js.
-    "$interfaces_bindings_gen_dir/new_bindings/interface_control_messages.mojom.js",
-    "$interfaces_bindings_gen_dir/new_bindings/pipe_control_messages.mojom.js",
+    "$interfaces_bindings_gen_dir/interface_control_messages.mojom.js",
+    "$interfaces_bindings_gen_dir/pipe_control_messages.mojom.js",
   ]
   compiled_file = "$target_gen_dir/mojo_bindings.js"
 
@@ -82,19 +47,7 @@
   args += [ rebase_path(compiled_file, root_build_dir) ]
 
   deps = [
-    "//mojo/public/interfaces/bindings:new_bindings_js__generator",
-  ]
-}
-
-group("tests") {
-  testonly = true
-
-  data = [
-    "tests/core_unittest.js",
-  ]
-
-  public_deps = [
-    ":bindings",
+    "//mojo/public/interfaces/bindings:bindings_js__generator",
   ]
 }
 
diff --git a/mojo/public/js/README.md b/mojo/public/js/README.md
index 6b5eed3..450186bbb 100644
--- a/mojo/public/js/README.md
+++ b/mojo/public/js/README.md
@@ -1,10 +1,6 @@
 # Mojo JavaScript Bindings API
 This document is a subset of the [Mojo documentation](/mojo).
 
-**NOTE:** This document only covers the *new mode* of JavaScript APIs. If a
-Mojom target sets `use_new_js_bindings = false`, it is using the deprecated
-*old mode* and should be converted.
-
 [TOC]
 
 ## Getting Started
diff --git a/mojo/public/js/associated_bindings.js b/mojo/public/js/associated_bindings.js
deleted file mode 100644
index 5fa9533..0000000
--- a/mojo/public/js/associated_bindings.js
+++ /dev/null
@@ -1,264 +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.
-
-define("mojo/public/js/associated_bindings", [
-  "mojo/public/js/bindings",
-  "mojo/public/js/core",
-  "mojo/public/js/interface_types",
-  "mojo/public/js/lib/interface_endpoint_client",
-  "mojo/public/js/lib/interface_endpoint_handle",
-], function(bindings,
-            core,
-            types,
-            interfaceEndpointClient,
-            interfaceEndpointHandle) {
-
-  var InterfaceEndpointClient = interfaceEndpointClient.InterfaceEndpointClient;
-
-  // ---------------------------------------------------------------------------
-
-  function makeRequest(associatedInterfacePtrInfo) {
-    var {handle0, handle1} =
-        interfaceEndpointHandle.createPairPendingAssociation();
-
-    associatedInterfacePtrInfo.interfaceEndpointHandle = handle0;
-    associatedInterfacePtrInfo.version = 0;
-
-    var request = new types.AssociatedInterfaceRequest(handle1);
-    return request;
-  }
-
-  // ---------------------------------------------------------------------------
-
-  // Operations used to setup/configure an associated interface pointer.
-  // Exposed as |ptr| field of generated associated interface pointer classes.
-  // |associatedPtrInfo| could be omitted and passed into bind() later.
-  //
-  // Example:
-  //    // IntegerSenderImpl implements mojom.IntegerSender
-  //    function IntegerSenderImpl() { ... }
-  //    IntegerSenderImpl.prototype.echo = function() { ... }
-  //
-  //    // IntegerSenderConnectionImpl implements mojom.IntegerSenderConnection
-  //    function IntegerSenderConnectionImpl() {
-  //      this.senderBinding_ = null;
-  //    }
-  //    IntegerSenderConnectionImpl.prototype.getSender = function(
-  //        associatedRequest) {
-  //      this.senderBinding_ = new AssociatedBinding(mojom.IntegerSender,
-  //          new IntegerSenderImpl(),
-  //          associatedRequest);
-  //    }
-  //
-  //    var integerSenderConnection = new mojom.IntegerSenderConnectionPtr();
-  //    var integerSenderConnectionBinding = new Binding(
-  //        mojom.IntegerSenderConnection,
-  //        new IntegerSenderConnectionImpl(),
-  //        bindings.makeRequest(integerSenderConnection));
-  //
-  //    // A locally-created associated interface pointer can only be used to
-  //    // make calls when the corresponding associated request is sent over
-  //    // another interface (either the master interface or another
-  //    // associated interface).
-  //    var associatedInterfacePtrInfo = new AssociatedInterfacePtrInfo();
-  //    var associatedRequest = makeRequest(interfacePtrInfo);
-  //
-  //    integerSenderConnection.getSender(associatedRequest);
-  //
-  //    // Create an associated interface and bind the associated handle.
-  //    var integerSender = new mojom.AssociatedIntegerSenderPtr();
-  //    integerSender.ptr.bind(associatedInterfacePtrInfo);
-  //    integerSender.echo();
-
-  function AssociatedInterfacePtrController(interfaceType, associatedPtrInfo) {
-    this.version = 0;
-
-    this.interfaceType_ = interfaceType;
-    this.interfaceEndpointClient_ = null;
-    this.proxy_ = null;
-
-    if (associatedPtrInfo) {
-      this.bind(associatedPtrInfo);
-    }
-  }
-
-  AssociatedInterfacePtrController.prototype.bind = function(
-      associatedPtrInfo) {
-    this.reset();
-    this.version = associatedPtrInfo.version;
-
-    this.interfaceEndpointClient_ = new InterfaceEndpointClient(
-        associatedPtrInfo.interfaceEndpointHandle);
-
-    this.interfaceEndpointClient_ .setPayloadValidators([
-        this.interfaceType_.validateResponse]);
-    this.proxy_ = new this.interfaceType_.proxyClass(
-        this.interfaceEndpointClient_);
-  };
-
-  AssociatedInterfacePtrController.prototype.isBound = function() {
-    return this.interfaceEndpointClient_ !== null;
-  };
-
-  AssociatedInterfacePtrController.prototype.reset = function() {
-    this.version = 0;
-    if (this.interfaceEndpointClient_) {
-      this.interfaceEndpointClient_.close();
-      this.interfaceEndpointClient_ = null;
-    }
-    if (this.proxy_) {
-      this.proxy_ = null;
-    }
-  };
-
-  AssociatedInterfacePtrController.prototype.resetWithReason = function(
-      reason) {
-    if (this.isBound()) {
-      this.interfaceEndpointClient_.close(reason);
-      this.interfaceEndpointClient_ = null;
-    }
-    this.reset();
-  };
-
-  // Indicates whether an error has been encountered. If true, method calls
-  // on this interface will be dropped (and may already have been dropped).
-  AssociatedInterfacePtrController.prototype.getEncounteredError = function() {
-    return this.interfaceEndpointClient_ ?
-        this.interfaceEndpointClient_.getEncounteredError() : false;
-  };
-
-  AssociatedInterfacePtrController.prototype.setConnectionErrorHandler =
-      function(callback) {
-    if (!this.isBound()) {
-      throw new Error("Cannot set connection error handler if not bound.");
-    }
-
-    this.interfaceEndpointClient_.setConnectionErrorHandler(callback);
-  };
-
-  AssociatedInterfacePtrController.prototype.passInterface = function() {
-    if (!this.isBound()) {
-      return new types.AssociatedInterfacePtrInfo(null);
-    }
-
-    var result = new types.AssociatedInterfacePtrInfo(
-        this.interfaceEndpointClient_.passHandle(), this.version);
-    this.reset();
-    return result;
-  };
-
-  AssociatedInterfacePtrController.prototype.getProxy = function() {
-    return this.proxy_;
-  };
-
-  AssociatedInterfacePtrController.prototype.queryVersion = function() {
-    function onQueryVersion(version) {
-      this.version = version;
-      return version;
-    }
-
-    return this.interfaceEndpointClient_.queryVersion().then(
-      onQueryVersion.bind(this));
-  };
-
-  AssociatedInterfacePtrController.prototype.requireVersion = function(
-      version) {
-    if (this.version >= version) {
-      return;
-    }
-    this.version = version;
-    this.interfaceEndpointClient_.requireVersion(version);
-  };
-
-  // ---------------------------------------------------------------------------
-
-  // |associatedInterfaceRequest| could be omitted and passed into bind()
-  // later.
-  function AssociatedBinding(interfaceType, impl, associatedInterfaceRequest) {
-    this.interfaceType_ = interfaceType;
-    this.impl_ = impl;
-    this.interfaceEndpointClient_ = null;
-    this.stub_ = null;
-
-    if (associatedInterfaceRequest) {
-      this.bind(associatedInterfaceRequest);
-    }
-  }
-
-  AssociatedBinding.prototype.isBound = function() {
-    return this.interfaceEndpointClient_ !== null;
-  };
-
-  AssociatedBinding.prototype.bind = function(associatedInterfaceRequest) {
-    this.close();
-
-    this.stub_ = new this.interfaceType_.stubClass(this.impl_);
-    this.interfaceEndpointClient_ = new InterfaceEndpointClient(
-        associatedInterfaceRequest.interfaceEndpointHandle, this.stub_,
-        this.interfaceType_.kVersion);
-
-    this.interfaceEndpointClient_ .setPayloadValidators([
-        this.interfaceType_.validateRequest]);
-  };
-
-
-  AssociatedBinding.prototype.close = function() {
-    if (!this.isBound()) {
-      return;
-    }
-
-    if (this.interfaceEndpointClient_) {
-      this.interfaceEndpointClient_.close();
-      this.interfaceEndpointClient_ = null;
-    }
-
-    this.stub_ = null;
-  };
-
-  AssociatedBinding.prototype.closeWithReason = function(reason) {
-    if (this.interfaceEndpointClient_) {
-      this.interfaceEndpointClient_.close(reason);
-      this.interfaceEndpointClient_ = null;
-    }
-    this.close();
-  };
-
-  AssociatedBinding.prototype.setConnectionErrorHandler = function(callback) {
-    if (!this.isBound()) {
-      throw new Error("Cannot set connection error handler if not bound.");
-    }
-    this.interfaceEndpointClient_.setConnectionErrorHandler(callback);
-  };
-
-  AssociatedBinding.prototype.unbind = function() {
-    if (!this.isBound()) {
-      return new types.AssociatedInterfaceRequest(null);
-    }
-
-    var result = new types.AssociatedInterfaceRequest(
-        this.interfaceEndpointClient_.passHandle());
-    this.close();
-    return result;
-  };
-
-  // ---------------------------------------------------------------------------
-
-  function AssociatedBindingSet(interfaceType) {
-    bindings.BindingSet.call(this, interfaceType);
-    this.bindingType_ = AssociatedBinding;
-  }
-
-  AssociatedBindingSet.prototype = Object.create(bindings.BindingSet.prototype);
-  AssociatedBindingSet.prototype.constructor = AssociatedBindingSet;
-
-  var exports = {};
-  exports.AssociatedInterfacePtrInfo = types.AssociatedInterfacePtrInfo;
-  exports.AssociatedInterfaceRequest = types.AssociatedInterfaceRequest;
-  exports.makeRequest = makeRequest;
-  exports.AssociatedInterfacePtrController = AssociatedInterfacePtrController;
-  exports.AssociatedBinding = AssociatedBinding;
-  exports.AssociatedBindingSet = AssociatedBindingSet;
-
-  return exports;
-});
diff --git a/mojo/public/js/bindings.js b/mojo/public/js/bindings.js
deleted file mode 100644
index 0c12c4e..0000000
--- a/mojo/public/js/bindings.js
+++ /dev/null
@@ -1,324 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-define("mojo/public/js/bindings", [
-  "mojo/public/js/core",
-  "mojo/public/js/interface_types",
-  "mojo/public/js/lib/interface_endpoint_client",
-  "mojo/public/js/router",
-], function(core, types, interfaceEndpointClient, router) {
-
-  var InterfaceEndpointClient = interfaceEndpointClient.InterfaceEndpointClient;
-
-  // ---------------------------------------------------------------------------
-
-  function makeRequest(interfacePtr) {
-    var pipe = core.createMessagePipe();
-    interfacePtr.ptr.bind(new types.InterfacePtrInfo(pipe.handle0, 0));
-    return new types.InterfaceRequest(pipe.handle1);
-  }
-
-  // ---------------------------------------------------------------------------
-
-  // Operations used to setup/configure an interface pointer. Exposed as the
-  // |ptr| field of generated interface pointer classes.
-  // |ptrInfoOrHandle| could be omitted and passed into bind() later.
-  function InterfacePtrController(interfaceType, ptrInfoOrHandle) {
-    this.version = 0;
-
-    this.interfaceType_ = interfaceType;
-    this.router_ = null;
-    this.interfaceEndpointClient_ = null;
-    this.proxy_ = null;
-
-    // |router_| and |interfaceEndpointClient_| are lazily initialized.
-    // |handle_| is valid between bind() and
-    // the initialization of |router_| and |interfaceEndpointClient_|.
-    this.handle_ = null;
-
-    if (ptrInfoOrHandle)
-      this.bind(ptrInfoOrHandle);
-  }
-
-  InterfacePtrController.prototype.bind = function(ptrInfoOrHandle) {
-    this.reset();
-
-    if (ptrInfoOrHandle instanceof types.InterfacePtrInfo) {
-      this.version = ptrInfoOrHandle.version;
-      this.handle_ = ptrInfoOrHandle.handle;
-    } else {
-      this.handle_ = ptrInfoOrHandle;
-    }
-  };
-
-  InterfacePtrController.prototype.isBound = function() {
-    return this.interfaceEndpointClient_ !== null || this.handle_ !== null;
-  };
-
-  // Although users could just discard the object, reset() closes the pipe
-  // immediately.
-  InterfacePtrController.prototype.reset = function() {
-    this.version = 0;
-    if (this.interfaceEndpointClient_) {
-      this.interfaceEndpointClient_.close();
-      this.interfaceEndpointClient_ = null;
-    }
-    if (this.router_) {
-      this.router_.close();
-      this.router_ = null;
-
-      this.proxy_ = null;
-    }
-    if (this.handle_) {
-      core.close(this.handle_);
-      this.handle_ = null;
-    }
-  };
-
-  InterfacePtrController.prototype.resetWithReason = function(reason) {
-    if (this.isBound()) {
-      this.configureProxyIfNecessary_();
-      this.interfaceEndpointClient_.close(reason);
-      this.interfaceEndpointClient_ = null;
-    }
-    this.reset();
-  };
-
-  InterfacePtrController.prototype.setConnectionErrorHandler = function(
-      callback) {
-    if (!this.isBound())
-      throw new Error("Cannot set connection error handler if not bound.");
-
-    this.configureProxyIfNecessary_();
-    this.interfaceEndpointClient_.setConnectionErrorHandler(callback);
-  };
-
-  InterfacePtrController.prototype.passInterface = function() {
-    var result;
-    if (this.router_) {
-      // TODO(yzshen): Fix Router interface to support extracting handle.
-      result = new types.InterfacePtrInfo(
-          this.router_.connector_.handle_, this.version);
-      this.router_.connector_.handle_ = null;
-    } else {
-      // This also handles the case when this object is not bound.
-      result = new types.InterfacePtrInfo(this.handle_, this.version);
-      this.handle_ = null;
-    }
-
-    this.reset();
-    return result;
-  };
-
-  InterfacePtrController.prototype.getProxy = function() {
-    this.configureProxyIfNecessary_();
-    return this.proxy_;
-  };
-
-  InterfacePtrController.prototype.waitForNextMessageForTesting = function() {
-    this.configureProxyIfNecessary_();
-    this.router_.waitForNextMessageForTesting();
-  };
-
-  InterfacePtrController.prototype.configureProxyIfNecessary_ = function() {
-    if (!this.handle_)
-      return;
-
-    this.router_ = new router.Router(this.handle_, true);
-    this.handle_ = null;
-
-    this.interfaceEndpointClient_ = new InterfaceEndpointClient(
-        this.router_.createLocalEndpointHandle(types.kMasterInterfaceId));
-
-    this.interfaceEndpointClient_ .setPayloadValidators([
-        this.interfaceType_.validateResponse]);
-    this.proxy_ = new this.interfaceType_.proxyClass(
-        this.interfaceEndpointClient_);
-  };
-
-  InterfacePtrController.prototype.queryVersion = function() {
-    function onQueryVersion(version) {
-      this.version = version;
-      return version;
-    }
-
-    this.configureProxyIfNecessary_();
-    return this.interfaceEndpointClient_.queryVersion().then(
-      onQueryVersion.bind(this));
-  };
-
-  InterfacePtrController.prototype.requireVersion = function(version) {
-    this.configureProxyIfNecessary_();
-
-    if (this.version >= version) {
-      return;
-    }
-    this.version = version;
-    this.interfaceEndpointClient_.requireVersion(version);
-  };
-
-  // ---------------------------------------------------------------------------
-
-  // |request| could be omitted and passed into bind() later.
-  //
-  // Example:
-  //
-  //    // FooImpl implements mojom.Foo.
-  //    function FooImpl() { ... }
-  //    FooImpl.prototype.fooMethod1 = function() { ... }
-  //    FooImpl.prototype.fooMethod2 = function() { ... }
-  //
-  //    var fooPtr = new mojom.FooPtr();
-  //    var request = makeRequest(fooPtr);
-  //    var binding = new Binding(mojom.Foo, new FooImpl(), request);
-  //    fooPtr.fooMethod1();
-  function Binding(interfaceType, impl, requestOrHandle) {
-    this.interfaceType_ = interfaceType;
-    this.impl_ = impl;
-    this.router_ = null;
-    this.interfaceEndpointClient_ = null;
-    this.stub_ = null;
-
-    if (requestOrHandle)
-      this.bind(requestOrHandle);
-  }
-
-  Binding.prototype.isBound = function() {
-    return this.router_ !== null;
-  };
-
-  Binding.prototype.createInterfacePtrAndBind = function() {
-    var ptr = new this.interfaceType_.ptrClass();
-    // TODO(yzshen): Set the version of the interface pointer.
-    this.bind(makeRequest(ptr));
-    return ptr;
-  };
-
-  Binding.prototype.bind = function(requestOrHandle) {
-    this.close();
-
-    var handle = requestOrHandle instanceof types.InterfaceRequest ?
-        requestOrHandle.handle : requestOrHandle;
-    if (!core.isHandle(handle))
-      return;
-
-    this.router_ = new router.Router(handle);
-
-    this.stub_ = new this.interfaceType_.stubClass(this.impl_);
-    this.interfaceEndpointClient_ = new InterfaceEndpointClient(
-        this.router_.createLocalEndpointHandle(types.kMasterInterfaceId),
-        this.stub_, this.interfaceType_.kVersion);
-
-    this.interfaceEndpointClient_ .setPayloadValidators([
-        this.interfaceType_.validateRequest]);
-  };
-
-  Binding.prototype.close = function() {
-    if (!this.isBound())
-      return;
-
-    if (this.interfaceEndpointClient_) {
-      this.interfaceEndpointClient_.close();
-      this.interfaceEndpointClient_ = null;
-    }
-
-    this.router_.close();
-    this.router_ = null;
-    this.stub_ = null;
-  };
-
-  Binding.prototype.closeWithReason = function(reason) {
-    if (this.interfaceEndpointClient_) {
-      this.interfaceEndpointClient_.close(reason);
-      this.interfaceEndpointClient_ = null;
-    }
-    this.close();
-  };
-
-  Binding.prototype.setConnectionErrorHandler = function(callback) {
-    if (!this.isBound()) {
-      throw new Error("Cannot set connection error handler if not bound.");
-    }
-    this.interfaceEndpointClient_.setConnectionErrorHandler(callback);
-  };
-
-  Binding.prototype.unbind = function() {
-    if (!this.isBound())
-      return new types.InterfaceRequest(null);
-
-    var result = new types.InterfaceRequest(this.router_.connector_.handle_);
-    this.router_.connector_.handle_ = null;
-    this.close();
-    return result;
-  };
-
-  Binding.prototype.waitForNextMessageForTesting = function() {
-    this.router_.waitForNextMessageForTesting();
-  };
-
-  // ---------------------------------------------------------------------------
-
-  function BindingSetEntry(bindingSet, interfaceType, bindingType, impl,
-      requestOrHandle, bindingId) {
-    this.bindingSet_ = bindingSet;
-    this.bindingId_ = bindingId;
-    this.binding_ = new bindingType(interfaceType, impl,
-        requestOrHandle);
-
-    this.binding_.setConnectionErrorHandler(function(reason) {
-      this.bindingSet_.onConnectionError(bindingId, reason);
-    }.bind(this));
-  }
-
-  BindingSetEntry.prototype.close = function() {
-    this.binding_.close();
-  };
-
-  function BindingSet(interfaceType) {
-    this.interfaceType_ = interfaceType;
-    this.nextBindingId_ = 0;
-    this.bindings_ = new Map();
-    this.errorHandler_ = null;
-    this.bindingType_ = Binding;
-  }
-
-  BindingSet.prototype.isEmpty = function() {
-    return this.bindings_.size == 0;
-  };
-
-  BindingSet.prototype.addBinding = function(impl, requestOrHandle) {
-    this.bindings_.set(
-        this.nextBindingId_,
-        new BindingSetEntry(this, this.interfaceType_, this.bindingType_, impl,
-            requestOrHandle, this.nextBindingId_));
-    ++this.nextBindingId_;
-  };
-
-  BindingSet.prototype.closeAllBindings = function() {
-    for (var entry of this.bindings_.values())
-      entry.close();
-    this.bindings_.clear();
-  };
-
-  BindingSet.prototype.setConnectionErrorHandler = function(callback) {
-    this.errorHandler_ = callback;
-  };
-
-  BindingSet.prototype.onConnectionError = function(bindingId, reason) {
-    this.bindings_.delete(bindingId);
-
-    if (this.errorHandler_)
-      this.errorHandler_(reason);
-  };
-
-  var exports = {};
-  exports.InterfacePtrInfo = types.InterfacePtrInfo;
-  exports.InterfaceRequest = types.InterfaceRequest;
-  exports.makeRequest = makeRequest;
-  exports.InterfacePtrController = InterfacePtrController;
-  exports.Binding = Binding;
-  exports.BindingSet = BindingSet;
-
-  return exports;
-});
diff --git a/mojo/public/js/buffer.js b/mojo/public/js/buffer.js
deleted file mode 100644
index e35f6951..0000000
--- a/mojo/public/js/buffer.js
+++ /dev/null
@@ -1,156 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-define("mojo/public/js/buffer", function() {
-
-  var kHostIsLittleEndian = (function () {
-    var endianArrayBuffer = new ArrayBuffer(2);
-    var endianUint8Array = new Uint8Array(endianArrayBuffer);
-    var endianUint16Array = new Uint16Array(endianArrayBuffer);
-    endianUint16Array[0] = 1;
-    return endianUint8Array[0] == 1;
-  })();
-
-  var kHighWordMultiplier = 0x100000000;
-
-  function Buffer(sizeOrArrayBuffer) {
-    if (sizeOrArrayBuffer instanceof ArrayBuffer)
-      this.arrayBuffer = sizeOrArrayBuffer;
-    else
-      this.arrayBuffer = new ArrayBuffer(sizeOrArrayBuffer);
-
-    this.dataView = new DataView(this.arrayBuffer);
-    this.next = 0;
-  }
-
-  Object.defineProperty(Buffer.prototype, "byteLength", {
-    get: function() { return this.arrayBuffer.byteLength; }
-  });
-
-  Buffer.prototype.alloc = function(size) {
-    var pointer = this.next;
-    this.next += size;
-    if (this.next > this.byteLength) {
-      var newSize = (1.5 * (this.byteLength + size)) | 0;
-      this.grow(newSize);
-    }
-    return pointer;
-  };
-
-  function copyArrayBuffer(dstArrayBuffer, srcArrayBuffer) {
-    (new Uint8Array(dstArrayBuffer)).set(new Uint8Array(srcArrayBuffer));
-  }
-
-  Buffer.prototype.grow = function(size) {
-    var newArrayBuffer = new ArrayBuffer(size);
-    copyArrayBuffer(newArrayBuffer, this.arrayBuffer);
-    this.arrayBuffer = newArrayBuffer;
-    this.dataView = new DataView(this.arrayBuffer);
-  };
-
-  Buffer.prototype.trim = function() {
-    this.arrayBuffer = this.arrayBuffer.slice(0, this.next);
-    this.dataView = new DataView(this.arrayBuffer);
-  };
-
-  Buffer.prototype.getUint8 = function(offset) {
-    return this.dataView.getUint8(offset);
-  }
-  Buffer.prototype.getUint16 = function(offset) {
-    return this.dataView.getUint16(offset, kHostIsLittleEndian);
-  }
-  Buffer.prototype.getUint32 = function(offset) {
-    return this.dataView.getUint32(offset, kHostIsLittleEndian);
-  }
-  Buffer.prototype.getUint64 = function(offset) {
-    var lo, hi;
-    if (kHostIsLittleEndian) {
-      lo = this.dataView.getUint32(offset, kHostIsLittleEndian);
-      hi = this.dataView.getUint32(offset + 4, kHostIsLittleEndian);
-    } else {
-      hi = this.dataView.getUint32(offset, kHostIsLittleEndian);
-      lo = this.dataView.getUint32(offset + 4, kHostIsLittleEndian);
-    }
-    return lo + hi * kHighWordMultiplier;
-  }
-
-  Buffer.prototype.getInt8 = function(offset) {
-    return this.dataView.getInt8(offset);
-  }
-  Buffer.prototype.getInt16 = function(offset) {
-    return this.dataView.getInt16(offset, kHostIsLittleEndian);
-  }
-  Buffer.prototype.getInt32 = function(offset) {
-    return this.dataView.getInt32(offset, kHostIsLittleEndian);
-  }
-  Buffer.prototype.getInt64 = function(offset) {
-    var lo, hi;
-    if (kHostIsLittleEndian) {
-      lo = this.dataView.getUint32(offset, kHostIsLittleEndian);
-      hi = this.dataView.getInt32(offset + 4, kHostIsLittleEndian);
-    } else {
-      hi = this.dataView.getInt32(offset, kHostIsLittleEndian);
-      lo = this.dataView.getUint32(offset + 4, kHostIsLittleEndian);
-    }
-    return lo + hi * kHighWordMultiplier;
-  }
-
-  Buffer.prototype.getFloat32 = function(offset) {
-    return this.dataView.getFloat32(offset, kHostIsLittleEndian);
-  }
-  Buffer.prototype.getFloat64 = function(offset) {
-    return this.dataView.getFloat64(offset, kHostIsLittleEndian);
-  }
-
-  Buffer.prototype.setUint8 = function(offset, value) {
-    this.dataView.setUint8(offset, value);
-  }
-  Buffer.prototype.setUint16 = function(offset, value) {
-    this.dataView.setUint16(offset, value, kHostIsLittleEndian);
-  }
-  Buffer.prototype.setUint32 = function(offset, value) {
-    this.dataView.setUint32(offset, value, kHostIsLittleEndian);
-  }
-  Buffer.prototype.setUint64 = function(offset, value) {
-    var hi = (value / kHighWordMultiplier) | 0;
-    if (kHostIsLittleEndian) {
-      this.dataView.setInt32(offset, value, kHostIsLittleEndian);
-      this.dataView.setInt32(offset + 4, hi, kHostIsLittleEndian);
-    } else {
-      this.dataView.setInt32(offset, hi, kHostIsLittleEndian);
-      this.dataView.setInt32(offset + 4, value, kHostIsLittleEndian);
-    }
-  }
-
-  Buffer.prototype.setInt8 = function(offset, value) {
-    this.dataView.setInt8(offset, value);
-  }
-  Buffer.prototype.setInt16 = function(offset, value) {
-    this.dataView.setInt16(offset, value, kHostIsLittleEndian);
-  }
-  Buffer.prototype.setInt32 = function(offset, value) {
-    this.dataView.setInt32(offset, value, kHostIsLittleEndian);
-  }
-  Buffer.prototype.setInt64 = function(offset, value) {
-    var hi = Math.floor(value / kHighWordMultiplier);
-    if (kHostIsLittleEndian) {
-      this.dataView.setInt32(offset, value, kHostIsLittleEndian);
-      this.dataView.setInt32(offset + 4, hi, kHostIsLittleEndian);
-    } else {
-      this.dataView.setInt32(offset, hi, kHostIsLittleEndian);
-      this.dataView.setInt32(offset + 4, value, kHostIsLittleEndian);
-    }
-  }
-
-  Buffer.prototype.setFloat32 = function(offset, value) {
-    this.dataView.setFloat32(offset, value, kHostIsLittleEndian);
-  }
-  Buffer.prototype.setFloat64 = function(offset, value) {
-    this.dataView.setFloat64(offset, value, kHostIsLittleEndian);
-  }
-
-  var exports = {};
-  exports.Buffer = Buffer;
-  return exports;
-});
diff --git a/mojo/public/js/codec.js b/mojo/public/js/codec.js
deleted file mode 100644
index a57e94f0..0000000
--- a/mojo/public/js/codec.js
+++ /dev/null
@@ -1,1146 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-define("mojo/public/js/codec", [
-  "mojo/public/js/buffer",
-  "mojo/public/js/interface_types",
-  "mojo/public/js/lib/interface_endpoint_handle",
-  "mojo/public/js/unicode",
-], function(buffer, types, interfaceEndpointHandle, unicode) {
-
-  var kErrorUnsigned = "Passing negative value to unsigned";
-  var kErrorArray = "Passing non Array for array type";
-  var kErrorString = "Passing non String for string type";
-  var kErrorMap = "Passing non Map for map type";
-  var InterfaceEndpointHandle = interfaceEndpointHandle.InterfaceEndpointHandle;
-
-  // Memory -------------------------------------------------------------------
-
-  var kAlignment = 8;
-
-  function align(size) {
-    return size + (kAlignment - (size % kAlignment)) % kAlignment;
-  }
-
-  function isAligned(offset) {
-    return offset >= 0 && (offset % kAlignment) === 0;
-  }
-
-  // Constants ----------------------------------------------------------------
-
-  var kArrayHeaderSize = 8;
-  var kStructHeaderSize = 8;
-  var kMessageV0HeaderSize = 24;
-  var kMessageV1HeaderSize = 32;
-  var kMessageV2HeaderSize = 48;
-  var kMapStructPayloadSize = 16;
-
-  var kStructHeaderNumBytesOffset = 0;
-  var kStructHeaderVersionOffset = 4;
-
-  var kEncodedInvalidHandleValue = 0xFFFFFFFF;
-
-  // Decoder ------------------------------------------------------------------
-
-  function Decoder(buffer, handles, associatedEndpointHandles, base) {
-    this.buffer = buffer;
-    this.handles = handles;
-    this.associatedEndpointHandles = associatedEndpointHandles;
-    this.base = base;
-    this.next = base;
-  }
-
-  Decoder.prototype.align = function() {
-    this.next = align(this.next);
-  };
-
-  Decoder.prototype.skip = function(offset) {
-    this.next += offset;
-  };
-
-  Decoder.prototype.readInt8 = function() {
-    var result = this.buffer.getInt8(this.next);
-    this.next += 1;
-    return result;
-  };
-
-  Decoder.prototype.readUint8 = function() {
-    var result = this.buffer.getUint8(this.next);
-    this.next += 1;
-    return result;
-  };
-
-  Decoder.prototype.readInt16 = function() {
-    var result = this.buffer.getInt16(this.next);
-    this.next += 2;
-    return result;
-  };
-
-  Decoder.prototype.readUint16 = function() {
-    var result = this.buffer.getUint16(this.next);
-    this.next += 2;
-    return result;
-  };
-
-  Decoder.prototype.readInt32 = function() {
-    var result = this.buffer.getInt32(this.next);
-    this.next += 4;
-    return result;
-  };
-
-  Decoder.prototype.readUint32 = function() {
-    var result = this.buffer.getUint32(this.next);
-    this.next += 4;
-    return result;
-  };
-
-  Decoder.prototype.readInt64 = function() {
-    var result = this.buffer.getInt64(this.next);
-    this.next += 8;
-    return result;
-  };
-
-  Decoder.prototype.readUint64 = function() {
-    var result = this.buffer.getUint64(this.next);
-    this.next += 8;
-    return result;
-  };
-
-  Decoder.prototype.readFloat = function() {
-    var result = this.buffer.getFloat32(this.next);
-    this.next += 4;
-    return result;
-  };
-
-  Decoder.prototype.readDouble = function() {
-    var result = this.buffer.getFloat64(this.next);
-    this.next += 8;
-    return result;
-  };
-
-  Decoder.prototype.decodePointer = function() {
-    // TODO(abarth): To correctly decode a pointer, we need to know the real
-    // base address of the array buffer.
-    var offsetPointer = this.next;
-    var offset = this.readUint64();
-    if (!offset)
-      return 0;
-    return offsetPointer + offset;
-  };
-
-  Decoder.prototype.decodeAndCreateDecoder = function(pointer) {
-    return new Decoder(this.buffer, this.handles,
-        this.associatedEndpointHandles, pointer);
-  };
-
-  Decoder.prototype.decodeHandle = function() {
-    return this.handles[this.readUint32()] || null;
-  };
-
-  Decoder.prototype.decodeAssociatedEndpointHandle = function() {
-    return this.associatedEndpointHandles[this.readUint32()] || null;
-  };
-
-  Decoder.prototype.decodeString = function() {
-    var numberOfBytes = this.readUint32();
-    var numberOfElements = this.readUint32();
-    var base = this.next;
-    this.next += numberOfElements;
-    return unicode.decodeUtf8String(
-        new Uint8Array(this.buffer.arrayBuffer, base, numberOfElements));
-  };
-
-  Decoder.prototype.decodeArray = function(cls) {
-    var numberOfBytes = this.readUint32();
-    var numberOfElements = this.readUint32();
-    var val = new Array(numberOfElements);
-    if (cls === PackedBool) {
-      var byte;
-      for (var i = 0; i < numberOfElements; ++i) {
-        if (i % 8 === 0)
-          byte = this.readUint8();
-        val[i] = (byte & (1 << i % 8)) ? true : false;
-      }
-    } else {
-      for (var i = 0; i < numberOfElements; ++i) {
-        val[i] = cls.decode(this);
-      }
-    }
-    return val;
-  };
-
-  Decoder.prototype.decodeStruct = function(cls) {
-    return cls.decode(this);
-  };
-
-  Decoder.prototype.decodeStructPointer = function(cls) {
-    var pointer = this.decodePointer();
-    if (!pointer) {
-      return null;
-    }
-    return cls.decode(this.decodeAndCreateDecoder(pointer));
-  };
-
-  Decoder.prototype.decodeArrayPointer = function(cls) {
-    var pointer = this.decodePointer();
-    if (!pointer) {
-      return null;
-    }
-    return this.decodeAndCreateDecoder(pointer).decodeArray(cls);
-  };
-
-  Decoder.prototype.decodeStringPointer = function() {
-    var pointer = this.decodePointer();
-    if (!pointer) {
-      return null;
-    }
-    return this.decodeAndCreateDecoder(pointer).decodeString();
-  };
-
-  Decoder.prototype.decodeMap = function(keyClass, valueClass) {
-    this.skip(4); // numberOfBytes
-    this.skip(4); // version
-    var keys = this.decodeArrayPointer(keyClass);
-    var values = this.decodeArrayPointer(valueClass);
-    var val = new Map();
-    for (var i = 0; i < keys.length; i++)
-      val.set(keys[i], values[i]);
-    return val;
-  };
-
-  Decoder.prototype.decodeMapPointer = function(keyClass, valueClass) {
-    var pointer = this.decodePointer();
-    if (!pointer) {
-      return null;
-    }
-    var decoder = this.decodeAndCreateDecoder(pointer);
-    return decoder.decodeMap(keyClass, valueClass);
-  };
-
-  // Encoder ------------------------------------------------------------------
-
-  function Encoder(buffer, handles, associatedEndpointHandles, base) {
-    this.buffer = buffer;
-    this.handles = handles;
-    this.associatedEndpointHandles = associatedEndpointHandles;
-    this.base = base;
-    this.next = base;
-  }
-
-  Encoder.prototype.align = function() {
-    this.next = align(this.next);
-  };
-
-  Encoder.prototype.skip = function(offset) {
-    this.next += offset;
-  };
-
-  Encoder.prototype.writeInt8 = function(val) {
-    this.buffer.setInt8(this.next, val);
-    this.next += 1;
-  };
-
-  Encoder.prototype.writeUint8 = function(val) {
-    if (val < 0) {
-      throw new Error(kErrorUnsigned);
-    }
-    this.buffer.setUint8(this.next, val);
-    this.next += 1;
-  };
-
-  Encoder.prototype.writeInt16 = function(val) {
-    this.buffer.setInt16(this.next, val);
-    this.next += 2;
-  };
-
-  Encoder.prototype.writeUint16 = function(val) {
-    if (val < 0) {
-      throw new Error(kErrorUnsigned);
-    }
-    this.buffer.setUint16(this.next, val);
-    this.next += 2;
-  };
-
-  Encoder.prototype.writeInt32 = function(val) {
-    this.buffer.setInt32(this.next, val);
-    this.next += 4;
-  };
-
-  Encoder.prototype.writeUint32 = function(val) {
-    if (val < 0) {
-      throw new Error(kErrorUnsigned);
-    }
-    this.buffer.setUint32(this.next, val);
-    this.next += 4;
-  };
-
-  Encoder.prototype.writeInt64 = function(val) {
-    this.buffer.setInt64(this.next, val);
-    this.next += 8;
-  };
-
-  Encoder.prototype.writeUint64 = function(val) {
-    if (val < 0) {
-      throw new Error(kErrorUnsigned);
-    }
-    this.buffer.setUint64(this.next, val);
-    this.next += 8;
-  };
-
-  Encoder.prototype.writeFloat = function(val) {
-    this.buffer.setFloat32(this.next, val);
-    this.next += 4;
-  };
-
-  Encoder.prototype.writeDouble = function(val) {
-    this.buffer.setFloat64(this.next, val);
-    this.next += 8;
-  };
-
-  Encoder.prototype.encodePointer = function(pointer) {
-    if (!pointer)
-      return this.writeUint64(0);
-    // TODO(abarth): To correctly encode a pointer, we need to know the real
-    // base address of the array buffer.
-    var offset = pointer - this.next;
-    this.writeUint64(offset);
-  };
-
-  Encoder.prototype.createAndEncodeEncoder = function(size) {
-    var pointer = this.buffer.alloc(align(size));
-    this.encodePointer(pointer);
-    return new Encoder(this.buffer, this.handles,
-        this.associatedEndpointHandles, pointer);
-  };
-
-  Encoder.prototype.encodeHandle = function(handle) {
-    if (handle) {
-      this.handles.push(handle);
-      this.writeUint32(this.handles.length - 1);
-    } else {
-      this.writeUint32(kEncodedInvalidHandleValue);
-    }
-  };
-
-  Encoder.prototype.encodeAssociatedEndpointHandle = function(endpointHandle) {
-    if (endpointHandle) {
-      this.associatedEndpointHandles.push(endpointHandle);
-      this.writeUint32(this.associatedEndpointHandles.length - 1);
-    } else {
-      this.writeUint32(kEncodedInvalidHandleValue);
-    }
-  };
-
-  Encoder.prototype.encodeString = function(val) {
-    var base = this.next + kArrayHeaderSize;
-    var numberOfElements = unicode.encodeUtf8String(
-        val, new Uint8Array(this.buffer.arrayBuffer, base));
-    var numberOfBytes = kArrayHeaderSize + numberOfElements;
-    this.writeUint32(numberOfBytes);
-    this.writeUint32(numberOfElements);
-    this.next += numberOfElements;
-  };
-
-  Encoder.prototype.encodeArray =
-      function(cls, val, numberOfElements, encodedSize) {
-    if (numberOfElements === undefined)
-      numberOfElements = val.length;
-    if (encodedSize === undefined)
-      encodedSize = kArrayHeaderSize + cls.encodedSize * numberOfElements;
-
-    this.writeUint32(encodedSize);
-    this.writeUint32(numberOfElements);
-
-    if (cls === PackedBool) {
-      var byte = 0;
-      for (i = 0; i < numberOfElements; ++i) {
-        if (val[i])
-          byte |= (1 << i % 8);
-        if (i % 8 === 7 || i == numberOfElements - 1) {
-          Uint8.encode(this, byte);
-          byte = 0;
-        }
-      }
-    } else {
-      for (var i = 0; i < numberOfElements; ++i)
-        cls.encode(this, val[i]);
-    }
-  };
-
-  Encoder.prototype.encodeStruct = function(cls, val) {
-    return cls.encode(this, val);
-  };
-
-  Encoder.prototype.encodeStructPointer = function(cls, val) {
-    if (val == null) {
-      // Also handles undefined, since undefined == null.
-      this.encodePointer(val);
-      return;
-    }
-    var encoder = this.createAndEncodeEncoder(cls.encodedSize);
-    cls.encode(encoder, val);
-  };
-
-  Encoder.prototype.encodeArrayPointer = function(cls, val) {
-    if (val == null) {
-      // Also handles undefined, since undefined == null.
-      this.encodePointer(val);
-      return;
-    }
-
-    var numberOfElements = val.length;
-    if (!Number.isSafeInteger(numberOfElements) || numberOfElements < 0)
-      throw new Error(kErrorArray);
-
-    var encodedSize = kArrayHeaderSize + ((cls === PackedBool) ?
-        Math.ceil(numberOfElements / 8) : cls.encodedSize * numberOfElements);
-    var encoder = this.createAndEncodeEncoder(encodedSize);
-    encoder.encodeArray(cls, val, numberOfElements, encodedSize);
-  };
-
-  Encoder.prototype.encodeStringPointer = function(val) {
-    if (val == null) {
-      // Also handles undefined, since undefined == null.
-      this.encodePointer(val);
-      return;
-    }
-    // Only accepts string primivites, not String Objects like new String("foo")
-    if (typeof(val) !== "string") {
-      throw new Error(kErrorString);
-    }
-    var encodedSize = kArrayHeaderSize + unicode.utf8Length(val);
-    var encoder = this.createAndEncodeEncoder(encodedSize);
-    encoder.encodeString(val);
-  };
-
-  Encoder.prototype.encodeMap = function(keyClass, valueClass, val) {
-    var keys = new Array(val.size);
-    var values = new Array(val.size);
-    var i = 0;
-    val.forEach(function(value, key) {
-      values[i] = value;
-      keys[i++] = key;
-    });
-    this.writeUint32(kStructHeaderSize + kMapStructPayloadSize);
-    this.writeUint32(0);  // version
-    this.encodeArrayPointer(keyClass, keys);
-    this.encodeArrayPointer(valueClass, values);
-  }
-
-  Encoder.prototype.encodeMapPointer = function(keyClass, valueClass, val) {
-    if (val == null) {
-      // Also handles undefined, since undefined == null.
-      this.encodePointer(val);
-      return;
-    }
-    if (!(val instanceof Map)) {
-      throw new Error(kErrorMap);
-    }
-    var encodedSize = kStructHeaderSize + kMapStructPayloadSize;
-    var encoder = this.createAndEncodeEncoder(encodedSize);
-    encoder.encodeMap(keyClass, valueClass, val);
-  };
-
-  // Message ------------------------------------------------------------------
-
-  var kMessageInterfaceIdOffset = kStructHeaderSize;
-  var kMessageNameOffset = kMessageInterfaceIdOffset + 4;
-  var kMessageFlagsOffset = kMessageNameOffset + 4;
-  var kMessageRequestIDOffset = kMessageFlagsOffset + 8;
-  var kMessagePayloadInterfaceIdsPointerOffset = kMessageV2HeaderSize - 8;
-
-  var kMessageExpectsResponse = 1 << 0;
-  var kMessageIsResponse      = 1 << 1;
-
-  function Message(buffer, handles, associatedEndpointHandles) {
-    if (associatedEndpointHandles === undefined) {
-      associatedEndpointHandles = [];
-    }
-
-    this.buffer = buffer;
-    this.handles = handles;
-    this.associatedEndpointHandles = associatedEndpointHandles;
-  }
-
-  Message.prototype.getHeaderNumBytes = function() {
-    return this.buffer.getUint32(kStructHeaderNumBytesOffset);
-  };
-
-  Message.prototype.getHeaderVersion = function() {
-    return this.buffer.getUint32(kStructHeaderVersionOffset);
-  };
-
-  Message.prototype.getName = function() {
-    return this.buffer.getUint32(kMessageNameOffset);
-  };
-
-  Message.prototype.getFlags = function() {
-    return this.buffer.getUint32(kMessageFlagsOffset);
-  };
-
-  Message.prototype.getInterfaceId = function() {
-    return this.buffer.getUint32(kMessageInterfaceIdOffset);
-  };
-
-  Message.prototype.getPayloadInterfaceIds = function() {
-    if (this.getHeaderVersion() < 2) {
-      return null;
-    }
-
-    var decoder = new Decoder(this.buffer, this.handles,
-        this.associatedEndpointHandles,
-        kMessagePayloadInterfaceIdsPointerOffset);
-    var payloadInterfaceIds = decoder.decodeArrayPointer(Uint32);
-    return payloadInterfaceIds;
-  };
-
-  Message.prototype.isResponse = function() {
-    return (this.getFlags() & kMessageIsResponse) != 0;
-  };
-
-  Message.prototype.expectsResponse = function() {
-    return (this.getFlags() & kMessageExpectsResponse) != 0;
-  };
-
-  Message.prototype.setRequestID = function(requestID) {
-    // TODO(darin): Verify that space was reserved for this field!
-    this.buffer.setUint64(kMessageRequestIDOffset, requestID);
-  };
-
-  Message.prototype.setInterfaceId = function(interfaceId) {
-    this.buffer.setUint32(kMessageInterfaceIdOffset, interfaceId);
-  };
-
-  Message.prototype.setPayloadInterfaceIds_ = function(payloadInterfaceIds) {
-    if (this.getHeaderVersion() < 2) {
-      throw new Error(
-          "Version of message does not support payload interface ids");
-    }
-
-    var decoder = new Decoder(this.buffer, this.handles,
-        this.associatedEndpointHandles,
-        kMessagePayloadInterfaceIdsPointerOffset);
-    var payloadInterfaceIdsOffset = decoder.decodePointer();
-    var encoder = new Encoder(this.buffer, this.handles,
-        this.associatedEndpointHandles,
-        payloadInterfaceIdsOffset);
-    encoder.encodeArray(Uint32, payloadInterfaceIds);
-  };
-
-  Message.prototype.serializeAssociatedEndpointHandles = function(
-      associatedGroupController) {
-    if (this.associatedEndpointHandles.length > 0) {
-      if (this.getHeaderVersion() < 2) {
-        throw new Error(
-            "Version of message does not support associated endpoint handles");
-      }
-
-      var data = [];
-      for (var i = 0; i < this.associatedEndpointHandles.length; i++) {
-        var handle = this.associatedEndpointHandles[i];
-        data.push(associatedGroupController.associateInterface(handle));
-      }
-      this.associatedEndpointHandles = [];
-      this.setPayloadInterfaceIds_(data);
-    }
-  };
-
-  Message.prototype.deserializeAssociatedEndpointHandles = function(
-      associatedGroupController) {
-    if (this.getHeaderVersion() < 2) {
-      return true;
-    }
-
-    this.associatedEndpointHandles = [];
-    var ids = this.getPayloadInterfaceIds();
-
-    var result = true;
-    for (var i = 0; i < ids.length; i++) {
-      var handle = associatedGroupController.createLocalEndpointHandle(ids[i]);
-      if (types.isValidInterfaceId(ids[i]) && !handle.isValid()) {
-        // |ids[i]| itself is valid but handle creation failed. In that case,
-        // mark deserialization as failed but continue to deserialize the
-        // rest of handles.
-        result = false;
-      }
-      this.associatedEndpointHandles.push(handle);
-      ids[i] = types.kInvalidInterfaceId;
-    }
-
-    this.setPayloadInterfaceIds_(ids);
-    return result;
-  };
-
-
-  // MessageV0Builder ---------------------------------------------------------
-
-  function MessageV0Builder(messageName, payloadSize) {
-    // Currently, we don't compute the payload size correctly ahead of time.
-    // Instead, we resize the buffer at the end.
-    var numberOfBytes = kMessageV0HeaderSize + payloadSize;
-    this.buffer = new buffer.Buffer(numberOfBytes);
-    this.handles = [];
-    var encoder = this.createEncoder(kMessageV0HeaderSize);
-    encoder.writeUint32(kMessageV0HeaderSize);
-    encoder.writeUint32(0);  // version.
-    encoder.writeUint32(0);  // interface ID.
-    encoder.writeUint32(messageName);
-    encoder.writeUint32(0);  // flags.
-    encoder.writeUint32(0);  // padding.
-  }
-
-  MessageV0Builder.prototype.createEncoder = function(size) {
-    var pointer = this.buffer.alloc(size);
-    return new Encoder(this.buffer, this.handles, [], pointer);
-  };
-
-  MessageV0Builder.prototype.encodeStruct = function(cls, val) {
-    cls.encode(this.createEncoder(cls.encodedSize), val);
-  };
-
-  MessageV0Builder.prototype.finish = function() {
-    // TODO(abarth): Rather than resizing the buffer at the end, we could
-    // compute the size we need ahead of time, like we do in C++.
-    this.buffer.trim();
-    var message = new Message(this.buffer, this.handles);
-    this.buffer = null;
-    this.handles = null;
-    this.encoder = null;
-    return message;
-  };
-
-  // MessageV1Builder -----------------------------------------------
-
-  function MessageV1Builder(messageName, payloadSize, flags,
-                                       requestID) {
-    // Currently, we don't compute the payload size correctly ahead of time.
-    // Instead, we resize the buffer at the end.
-    var numberOfBytes = kMessageV1HeaderSize + payloadSize;
-    this.buffer = new buffer.Buffer(numberOfBytes);
-    this.handles = [];
-    var encoder = this.createEncoder(kMessageV1HeaderSize);
-    encoder.writeUint32(kMessageV1HeaderSize);
-    encoder.writeUint32(1);  // version.
-    encoder.writeUint32(0);  // interface ID.
-    encoder.writeUint32(messageName);
-    encoder.writeUint32(flags);
-    encoder.writeUint32(0);  // padding.
-    encoder.writeUint64(requestID);
-  }
-
-  MessageV1Builder.prototype =
-      Object.create(MessageV0Builder.prototype);
-
-  MessageV1Builder.prototype.constructor =
-      MessageV1Builder;
-
-  // MessageV2 -----------------------------------------------
-
-  function MessageV2Builder(messageName, payloadSize, flags, requestID) {
-    // Currently, we don't compute the payload size correctly ahead of time.
-    // Instead, we resize the buffer at the end.
-    var numberOfBytes = kMessageV2HeaderSize + payloadSize;
-    this.buffer = new buffer.Buffer(numberOfBytes);
-    this.handles = [];
-
-    this.payload = null;
-    this.associatedEndpointHandles = [];
-
-    this.encoder = this.createEncoder(kMessageV2HeaderSize);
-    this.encoder.writeUint32(kMessageV2HeaderSize);
-    this.encoder.writeUint32(2);  // version.
-    // Gets set to an appropriate interfaceId for the endpoint by the Router.
-    this.encoder.writeUint32(0);  // interface ID.
-    this.encoder.writeUint32(messageName);
-    this.encoder.writeUint32(flags);
-    this.encoder.writeUint32(0);  // padding.
-    this.encoder.writeUint64(requestID);
-  }
-
-  MessageV2Builder.prototype.createEncoder = function(size) {
-    var pointer = this.buffer.alloc(size);
-    return new Encoder(this.buffer, this.handles,
-        this.associatedEndpointHandles, pointer);
-  };
-
-  MessageV2Builder.prototype.setPayload = function(cls, val) {
-    this.payload = {cls: cls, val: val};
-  };
-
-  MessageV2Builder.prototype.finish = function() {
-    if (!this.payload) {
-      throw new Error("Payload needs to be set before calling finish");
-    }
-
-    this.encoder.encodeStructPointer(this.payload.cls, this.payload.val);
-    this.encoder.encodeArrayPointer(Uint32,
-        new Array(this.associatedEndpointHandles.length));
-
-    this.buffer.trim();
-    var message = new Message(this.buffer, this.handles,
-        this.associatedEndpointHandles);
-    this.buffer = null;
-    this.handles = null;
-    this.encoder = null;
-    this.payload = null;
-    this.associatedEndpointHandles = null;
-
-    return message;
-  };
-
-  // MessageReader ------------------------------------------------------------
-
-  function MessageReader(message) {
-    this.decoder = new Decoder(message.buffer, message.handles,
-        message.associatedEndpointHandles, 0);
-    var messageHeaderSize = this.decoder.readUint32();
-    this.payloadSize = message.buffer.byteLength - messageHeaderSize;
-    var version = this.decoder.readUint32();
-    var interface_id = this.decoder.readUint32();
-    this.messageName = this.decoder.readUint32();
-    this.flags = this.decoder.readUint32();
-    // Skip the padding.
-    this.decoder.skip(4);
-    if (version >= 1)
-      this.requestID = this.decoder.readUint64();
-    this.decoder.skip(messageHeaderSize - this.decoder.next);
-  }
-
-  MessageReader.prototype.decodeStruct = function(cls) {
-    return cls.decode(this.decoder);
-  };
-
-  // Built-in types -----------------------------------------------------------
-
-  // This type is only used with ArrayOf(PackedBool).
-  function PackedBool() {
-  }
-
-  function Int8() {
-  }
-
-  Int8.encodedSize = 1;
-
-  Int8.decode = function(decoder) {
-    return decoder.readInt8();
-  };
-
-  Int8.encode = function(encoder, val) {
-    encoder.writeInt8(val);
-  };
-
-  Uint8.encode = function(encoder, val) {
-    encoder.writeUint8(val);
-  };
-
-  function Uint8() {
-  }
-
-  Uint8.encodedSize = 1;
-
-  Uint8.decode = function(decoder) {
-    return decoder.readUint8();
-  };
-
-  Uint8.encode = function(encoder, val) {
-    encoder.writeUint8(val);
-  };
-
-  function Int16() {
-  }
-
-  Int16.encodedSize = 2;
-
-  Int16.decode = function(decoder) {
-    return decoder.readInt16();
-  };
-
-  Int16.encode = function(encoder, val) {
-    encoder.writeInt16(val);
-  };
-
-  function Uint16() {
-  }
-
-  Uint16.encodedSize = 2;
-
-  Uint16.decode = function(decoder) {
-    return decoder.readUint16();
-  };
-
-  Uint16.encode = function(encoder, val) {
-    encoder.writeUint16(val);
-  };
-
-  function Int32() {
-  }
-
-  Int32.encodedSize = 4;
-
-  Int32.decode = function(decoder) {
-    return decoder.readInt32();
-  };
-
-  Int32.encode = function(encoder, val) {
-    encoder.writeInt32(val);
-  };
-
-  function Uint32() {
-  }
-
-  Uint32.encodedSize = 4;
-
-  Uint32.decode = function(decoder) {
-    return decoder.readUint32();
-  };
-
-  Uint32.encode = function(encoder, val) {
-    encoder.writeUint32(val);
-  };
-
-  function Int64() {
-  }
-
-  Int64.encodedSize = 8;
-
-  Int64.decode = function(decoder) {
-    return decoder.readInt64();
-  };
-
-  Int64.encode = function(encoder, val) {
-    encoder.writeInt64(val);
-  };
-
-  function Uint64() {
-  }
-
-  Uint64.encodedSize = 8;
-
-  Uint64.decode = function(decoder) {
-    return decoder.readUint64();
-  };
-
-  Uint64.encode = function(encoder, val) {
-    encoder.writeUint64(val);
-  };
-
-  function String() {
-  };
-
-  String.encodedSize = 8;
-
-  String.decode = function(decoder) {
-    return decoder.decodeStringPointer();
-  };
-
-  String.encode = function(encoder, val) {
-    encoder.encodeStringPointer(val);
-  };
-
-  function NullableString() {
-  }
-
-  NullableString.encodedSize = String.encodedSize;
-
-  NullableString.decode = String.decode;
-
-  NullableString.encode = String.encode;
-
-  function Float() {
-  }
-
-  Float.encodedSize = 4;
-
-  Float.decode = function(decoder) {
-    return decoder.readFloat();
-  };
-
-  Float.encode = function(encoder, val) {
-    encoder.writeFloat(val);
-  };
-
-  function Double() {
-  }
-
-  Double.encodedSize = 8;
-
-  Double.decode = function(decoder) {
-    return decoder.readDouble();
-  };
-
-  Double.encode = function(encoder, val) {
-    encoder.writeDouble(val);
-  };
-
-  function Enum(cls) {
-    this.cls = cls;
-  }
-
-  Enum.prototype.encodedSize = 4;
-
-  Enum.prototype.decode = function(decoder) {
-    return decoder.readInt32();
-  };
-
-  Enum.prototype.encode = function(encoder, val) {
-    encoder.writeInt32(val);
-  };
-
-  function PointerTo(cls) {
-    this.cls = cls;
-  }
-
-  PointerTo.prototype.encodedSize = 8;
-
-  PointerTo.prototype.decode = function(decoder) {
-    var pointer = decoder.decodePointer();
-    if (!pointer) {
-      return null;
-    }
-    return this.cls.decode(decoder.decodeAndCreateDecoder(pointer));
-  };
-
-  PointerTo.prototype.encode = function(encoder, val) {
-    if (!val) {
-      encoder.encodePointer(val);
-      return;
-    }
-    var objectEncoder = encoder.createAndEncodeEncoder(this.cls.encodedSize);
-    this.cls.encode(objectEncoder, val);
-  };
-
-  function NullablePointerTo(cls) {
-    PointerTo.call(this, cls);
-  }
-
-  NullablePointerTo.prototype = Object.create(PointerTo.prototype);
-
-  function ArrayOf(cls, length) {
-    this.cls = cls;
-    this.length = length || 0;
-  }
-
-  ArrayOf.prototype.encodedSize = 8;
-
-  ArrayOf.prototype.dimensions = function() {
-    return [this.length].concat(
-      (this.cls instanceof ArrayOf) ? this.cls.dimensions() : []);
-  }
-
-  ArrayOf.prototype.decode = function(decoder) {
-    return decoder.decodeArrayPointer(this.cls);
-  };
-
-  ArrayOf.prototype.encode = function(encoder, val) {
-    encoder.encodeArrayPointer(this.cls, val);
-  };
-
-  function NullableArrayOf(cls) {
-    ArrayOf.call(this, cls);
-  }
-
-  NullableArrayOf.prototype = Object.create(ArrayOf.prototype);
-
-  function Handle() {
-  }
-
-  Handle.encodedSize = 4;
-
-  Handle.decode = function(decoder) {
-    return decoder.decodeHandle();
-  };
-
-  Handle.encode = function(encoder, val) {
-    encoder.encodeHandle(val);
-  };
-
-  function NullableHandle() {
-  }
-
-  NullableHandle.encodedSize = Handle.encodedSize;
-
-  NullableHandle.decode = Handle.decode;
-
-  NullableHandle.encode = Handle.encode;
-
-  function Interface(cls) {
-    this.cls = cls;
-  }
-
-  Interface.prototype.encodedSize = 8;
-
-  Interface.prototype.decode = function(decoder) {
-    var interfacePtrInfo = new types.InterfacePtrInfo(
-        decoder.decodeHandle(), decoder.readUint32());
-    var interfacePtr = new this.cls();
-    interfacePtr.ptr.bind(interfacePtrInfo);
-    return interfacePtr;
-  };
-
-  Interface.prototype.encode = function(encoder, val) {
-    var interfacePtrInfo =
-        val ? val.ptr.passInterface() : new types.InterfacePtrInfo(null, 0);
-    encoder.encodeHandle(interfacePtrInfo.handle);
-    encoder.writeUint32(interfacePtrInfo.version);
-  };
-
-  function NullableInterface(cls) {
-    Interface.call(this, cls);
-  }
-
-  NullableInterface.prototype = Object.create(Interface.prototype);
-
-  function AssociatedInterfacePtrInfo() {
-  }
-
-  AssociatedInterfacePtrInfo.prototype.encodedSize = 8;
-
-  AssociatedInterfacePtrInfo.decode = function(decoder) {
-    return new types.AssociatedInterfacePtrInfo(
-      decoder.decodeAssociatedEndpointHandle(), decoder.readUint32());
-  };
-
-  AssociatedInterfacePtrInfo.encode = function(encoder, val) {
-    var associatedinterfacePtrInfo =
-        val ? val : new types.AssociatedInterfacePtrInfo(null, 0);
-    encoder.encodeAssociatedEndpointHandle(
-        associatedinterfacePtrInfo.interfaceEndpointHandle);
-    encoder.writeUint32(associatedinterfacePtrInfo.version);
-  };
-
-  function NullableAssociatedInterfacePtrInfo() {
-  }
-
-  NullableAssociatedInterfacePtrInfo.encodedSize =
-      AssociatedInterfacePtrInfo.encodedSize;
-
-  NullableAssociatedInterfacePtrInfo.decode =
-      AssociatedInterfacePtrInfo.decode;
-
-  NullableAssociatedInterfacePtrInfo.encode =
-      AssociatedInterfacePtrInfo.encode;
-
-  function InterfaceRequest() {
-  }
-
-  InterfaceRequest.encodedSize = 4;
-
-  InterfaceRequest.decode = function(decoder) {
-    return new types.InterfaceRequest(decoder.decodeHandle());
-  };
-
-  InterfaceRequest.encode = function(encoder, val) {
-    encoder.encodeHandle(val ? val.handle : null);
-  };
-
-  function NullableInterfaceRequest() {
-  }
-
-  NullableInterfaceRequest.encodedSize = InterfaceRequest.encodedSize;
-
-  NullableInterfaceRequest.decode = InterfaceRequest.decode;
-
-  NullableInterfaceRequest.encode = InterfaceRequest.encode;
-
-  function AssociatedInterfaceRequest() {
-  }
-
-  AssociatedInterfaceRequest.decode = function(decoder) {
-    var handle = decoder.decodeAssociatedEndpointHandle();
-    return new types.AssociatedInterfaceRequest(handle);
-  };
-
-  AssociatedInterfaceRequest.encode = function(encoder, val) {
-    encoder.encodeAssociatedEndpointHandle(
-        val ? val.interfaceEndpointHandle : null);
-  };
-
-  AssociatedInterfaceRequest.encodedSize = 4;
-
-  function NullableAssociatedInterfaceRequest() {
-  }
-
-  NullableAssociatedInterfaceRequest.encodedSize =
-      AssociatedInterfaceRequest.encodedSize;
-
-  NullableAssociatedInterfaceRequest.decode =
-      AssociatedInterfaceRequest.decode;
-
-  NullableAssociatedInterfaceRequest.encode =
-      AssociatedInterfaceRequest.encode;
-
-  function MapOf(keyClass, valueClass) {
-    this.keyClass = keyClass;
-    this.valueClass = valueClass;
-  }
-
-  MapOf.prototype.encodedSize = 8;
-
-  MapOf.prototype.decode = function(decoder) {
-    return decoder.decodeMapPointer(this.keyClass, this.valueClass);
-  };
-
-  MapOf.prototype.encode = function(encoder, val) {
-    encoder.encodeMapPointer(this.keyClass, this.valueClass, val);
-  };
-
-  function NullableMapOf(keyClass, valueClass) {
-    MapOf.call(this, keyClass, valueClass);
-  }
-
-  NullableMapOf.prototype = Object.create(MapOf.prototype);
-
-  var exports = {};
-  exports.align = align;
-  exports.isAligned = isAligned;
-  exports.Message = Message;
-  exports.MessageV0Builder = MessageV0Builder;
-  exports.MessageV1Builder = MessageV1Builder;
-  exports.MessageV2Builder = MessageV2Builder;
-  exports.MessageReader = MessageReader;
-  exports.kArrayHeaderSize = kArrayHeaderSize;
-  exports.kMapStructPayloadSize = kMapStructPayloadSize;
-  exports.kStructHeaderSize = kStructHeaderSize;
-  exports.kEncodedInvalidHandleValue = kEncodedInvalidHandleValue;
-  exports.kMessageV0HeaderSize = kMessageV0HeaderSize;
-  exports.kMessageV1HeaderSize = kMessageV1HeaderSize;
-  exports.kMessageV2HeaderSize = kMessageV2HeaderSize;
-  exports.kMessagePayloadInterfaceIdsPointerOffset =
-      kMessagePayloadInterfaceIdsPointerOffset;
-  exports.kMessageExpectsResponse = kMessageExpectsResponse;
-  exports.kMessageIsResponse = kMessageIsResponse;
-  exports.Int8 = Int8;
-  exports.Uint8 = Uint8;
-  exports.Int16 = Int16;
-  exports.Uint16 = Uint16;
-  exports.Int32 = Int32;
-  exports.Uint32 = Uint32;
-  exports.Int64 = Int64;
-  exports.Uint64 = Uint64;
-  exports.Float = Float;
-  exports.Double = Double;
-  exports.String = String;
-  exports.Enum = Enum;
-  exports.NullableString = NullableString;
-  exports.PointerTo = PointerTo;
-  exports.NullablePointerTo = NullablePointerTo;
-  exports.ArrayOf = ArrayOf;
-  exports.NullableArrayOf = NullableArrayOf;
-  exports.PackedBool = PackedBool;
-  exports.Handle = Handle;
-  exports.NullableHandle = NullableHandle;
-  exports.Interface = Interface;
-  exports.NullableInterface = NullableInterface;
-  exports.InterfaceRequest = InterfaceRequest;
-  exports.NullableInterfaceRequest = NullableInterfaceRequest;
-  exports.AssociatedInterfacePtrInfo = AssociatedInterfacePtrInfo;
-  exports.NullableAssociatedInterfacePtrInfo =
-      NullableAssociatedInterfacePtrInfo;
-  exports.AssociatedInterfaceRequest = AssociatedInterfaceRequest;
-  exports.NullableAssociatedInterfaceRequest =
-      NullableAssociatedInterfaceRequest;
-  exports.MapOf = MapOf;
-  exports.NullableMapOf = NullableMapOf;
-  return exports;
-});
diff --git a/mojo/public/js/connector.js b/mojo/public/js/connector.js
deleted file mode 100644
index 662c65da..0000000
--- a/mojo/public/js/connector.js
+++ /dev/null
@@ -1,181 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-define("mojo/public/js/connector", [
-  "mojo/public/js/buffer",
-  "mojo/public/js/codec",
-  "mojo/public/js/core",
-  "mojo/public/js/support",
-  "mojo/public/js/validator",
-], function(buffer, codec, core, support, validator) {
-
-  function Connector(handle) {
-    if (!core.isHandle(handle))
-      throw new Error("Connector: not a handle " + handle);
-    this.handle_ = handle;
-    this.dropWrites_ = false;
-    this.error_ = false;
-    this.incomingReceiver_ = null;
-    this.readWatcher_ = null;
-    this.errorHandler_ = null;
-    this.paused_ = false;
-
-    this.waitToReadMore();
-  }
-
-  Connector.prototype.close = function() {
-    this.cancelWait();
-    if (this.handle_ != null) {
-      core.close(this.handle_);
-      this.handle_ = null;
-    }
-  };
-
-  Connector.prototype.pauseIncomingMethodCallProcessing = function() {
-    if (this.paused_) {
-      return;
-    }
-    this.paused_= true;
-    this.cancelWait();
-  };
-
-  Connector.prototype.resumeIncomingMethodCallProcessing = function() {
-    if (!this.paused_) {
-      return;
-    }
-    this.paused_= false;
-    this.waitToReadMore();
-  };
-
-  Connector.prototype.accept = function(message) {
-    if (this.error_)
-      return false;
-
-    if (this.dropWrites_)
-      return true;
-
-    var result = core.writeMessage(this.handle_,
-                                   new Uint8Array(message.buffer.arrayBuffer),
-                                   message.handles,
-                                   core.WRITE_MESSAGE_FLAG_NONE);
-    switch (result) {
-      case core.RESULT_OK:
-        // The handles were successfully transferred, so we don't own them
-        // anymore.
-        message.handles = [];
-        break;
-      case core.RESULT_FAILED_PRECONDITION:
-        // There's no point in continuing to write to this pipe since the other
-        // end is gone. Avoid writing any future messages. Hide write failures
-        // from the caller since we'd like them to continue consuming any
-        // backlog of incoming messages before regarding the message pipe as
-        // closed.
-        this.dropWrites_ = true;
-        break;
-      default:
-        // This particular write was rejected, presumably because of bad input.
-        // The pipe is not necessarily in a bad state.
-        return false;
-    }
-    return true;
-  };
-
-  Connector.prototype.setIncomingReceiver = function(receiver) {
-    this.incomingReceiver_ = receiver;
-  };
-
-  Connector.prototype.setErrorHandler = function(handler) {
-    this.errorHandler_ = handler;
-  };
-
-  Connector.prototype.waitForNextMessageForTesting = function() {
-    var wait = core.wait(this.handle_, core.HANDLE_SIGNAL_READABLE);
-    this.readMore_(wait.result);
-  };
-
-  Connector.prototype.readMore_ = function(result) {
-    for (;;) {
-      if (this.paused_) {
-        return;
-      }
-
-      var read = core.readMessage(this.handle_,
-                                  core.READ_MESSAGE_FLAG_NONE);
-      if (this.handle_ == null) // The connector has been closed.
-        return;
-      if (read.result == core.RESULT_SHOULD_WAIT)
-        return;
-      if (read.result != core.RESULT_OK) {
-        this.handleError(read.result !== core.RESULT_FAILED_PRECONDITION,
-            false);
-        return;
-      }
-      var messageBuffer = new buffer.Buffer(read.buffer);
-      var message = new codec.Message(messageBuffer, read.handles);
-      var receiverResult = this.incomingReceiver_ &&
-          this.incomingReceiver_.accept(message);
-
-      // Handle invalid incoming message.
-      if (!validator.isTestingMode() && !receiverResult) {
-        // TODO(yzshen): Consider notifying the embedder.
-        this.handleError(true, false);
-      }
-    }
-  };
-
-  Connector.prototype.cancelWait = function() {
-    if (this.readWatcher_) {
-      support.cancelWatch(this.readWatcher_);
-      this.readWatcher_ = null;
-    }
-  };
-
-  Connector.prototype.waitToReadMore = function() {
-    if (this.handle_) {
-      this.readWatcher_ = support.watch(this.handle_,
-                                        core.HANDLE_SIGNAL_READABLE,
-                                        this.readMore_.bind(this));
-    }
-  };
-
-  Connector.prototype.handleError = function(forcePipeReset,
-                                             forceAsyncHandler) {
-    if (this.error_ || this.handle_ === null) {
-      return;
-    }
-
-    if (this.paused_) {
-      // Enforce calling the error handler asynchronously if the user has
-      // paused receiving messages. We need to wait until the user starts
-      // receiving messages again.
-      forceAsyncHandler = true;
-    }
-
-    if (!forcePipeReset && forceAsyncHandler) {
-      forcePipeReset = true;
-    }
-
-    this.cancelWait();
-    if (forcePipeReset) {
-      core.close(this.handle_);
-      var dummyPipe = core.createMessagePipe();
-      this.handle_ = dummyPipe.handle0;
-    }
-
-    if (forceAsyncHandler) {
-      if (!this.paused_) {
-        this.waitToReadMore();
-      }
-    } else {
-      this.error_ = true;
-      if (this.errorHandler_) {
-        this.errorHandler_.onError();
-      }
-    }
-  };
-
-  var exports = {};
-  exports.Connector = Connector;
-  return exports;
-});
diff --git a/mojo/public/js/constants.cc b/mojo/public/js/constants.cc
deleted file mode 100644
index 17cd0a9..0000000
--- a/mojo/public/js/constants.cc
+++ /dev/null
@@ -1,35 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "mojo/public/js/constants.h"
-
-namespace mojo {
-
-const char kAssociatedBindingsModuleName[] =
-    "mojo/public/js/associated_bindings";
-const char kBindingsModuleName[] = "mojo/public/js/bindings";
-const char kBufferModuleName[] = "mojo/public/js/buffer";
-const char kCodecModuleName[] = "mojo/public/js/codec";
-const char kConnectorModuleName[] = "mojo/public/js/connector";
-const char kControlMessageHandlerModuleName[] =
-    "mojo/public/js/lib/control_message_handler";
-const char kControlMessageProxyModuleName[] =
-    "mojo/public/js/lib/control_message_proxy";
-const char kInterfaceControlMessagesMojom[] =
-    "mojo/public/interfaces/bindings/interface_control_messages.mojom";
-const char kInterfaceEndpointClientModuleName[] =
-    "mojo/public/js/lib/interface_endpoint_client";
-const char kInterfaceEndpointHandleModuleName[] =
-    "mojo/public/js/lib/interface_endpoint_handle";
-const char kInterfaceTypesModuleName[] = "mojo/public/js/interface_types";
-const char kPipeControlMessageHandlerModuleName[] =
-    "mojo/public/js/lib/pipe_control_message_handler";
-const char kPipeControlMessageProxyModuleName[] =
-    "mojo/public/js/lib/pipe_control_message_proxy";
-const char kPipeControlMessagesMojom[] =
-    "mojo/public/interfaces/bindings/pipe_control_messages.mojom";
-const char kRouterModuleName[] = "mojo/public/js/router";
-const char kUnicodeModuleName[] = "mojo/public/js/unicode";
-const char kValidatorModuleName[] = "mojo/public/js/validator";
-}  // namespace mojo
diff --git a/mojo/public/js/constants.h b/mojo/public/js/constants.h
deleted file mode 100644
index c82fe1d..0000000
--- a/mojo/public/js/constants.h
+++ /dev/null
@@ -1,31 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef MOJO_PUBLIC_JS_BINDINGS_CONSTANTS_H_
-#define MOJO_PUBLIC_JS_BINDINGS_CONSTANTS_H_
-
-namespace mojo {
-
-// JavaScript module names:
-extern const char kAssociatedBindingsModuleName[];
-extern const char kBindingsModuleName[];
-extern const char kBufferModuleName[];
-extern const char kCodecModuleName[];
-extern const char kConnectorModuleName[];
-extern const char kControlMessageHandlerModuleName[];
-extern const char kControlMessageProxyModuleName[];
-extern const char kInterfaceControlMessagesMojom[];
-extern const char kInterfaceEndpointClientModuleName[];
-extern const char kInterfaceEndpointHandleModuleName[];
-extern const char kInterfaceTypesModuleName[];
-extern const char kPipeControlMessageHandlerModuleName[];
-extern const char kPipeControlMessageProxyModuleName[];
-extern const char kPipeControlMessagesMojom[];
-extern const char kRouterModuleName[];
-extern const char kUnicodeModuleName[];
-extern const char kValidatorModuleName[];
-
-}  // namespace mojo
-
-#endif  // MOJO_PUBLIC_JS_BINDINGS_CONSTANTS_H_
diff --git a/mojo/public/js/core.js b/mojo/public/js/core.js
deleted file mode 100644
index 706ed223..0000000
--- a/mojo/public/js/core.js
+++ /dev/null
@@ -1,304 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-// Module "mojo/public/js/core"
-//
-// Note: This file is for documentation purposes only. The code here is not
-// actually executed. The real module is implemented natively in Mojo.
-//
-// This module provides the JavaScript bindings for mojo/public/c/system/core.h.
-// Refer to that file for more detailed documentation for equivalent methods.
-
-while (1);
-
-/**
- * MojoHandle: An opaque handles to a Mojo object (e.g. a message pipe).
- */
-var kInvalidHandle;
-
-/**
- * MojoResult {number}: Result codes for Mojo operations.
- * See core.h for more information.
- */
-var RESULT_OK;
-var RESULT_CANCELLED;
-var RESULT_UNKNOWN;
-var RESULT_INVALID_ARGUMENT;
-var RESULT_DEADLINE_EXCEEDED;
-var RESULT_NOT_FOUND;
-var RESULT_ALREADY_EXISTS;
-var RESULT_PERMISSION_DENIED;
-var RESULT_RESOURCE_EXHAUSTED;
-var RESULT_FAILED_PRECONDITION;
-var RESULT_ABORTED;
-var RESULT_OUT_OF_RANGE;
-var RESULT_UNIMPLEMENTED;
-var RESULT_INTERNAL;
-var RESULT_UNAVAILABLE;
-var RESULT_DATA_LOSS;
-var RESULT_BUSY;
-var RESULT_SHOULD_WAIT;
-
-/**
- * MojoHandleSignals: Used to specify signals that can be waited on for a handle
- *(and which can be triggered), e.g., the ability to read or write to
- * the handle.
- * See core.h for more information.
- */
-var HANDLE_SIGNAL_NONE;
-var HANDLE_SIGNAL_READABLE;
-var HANDLE_SIGNAL_WRITABLE;
-var HANDLE_SIGNAL_PEER_CLOSED;
-var HANDLE_SIGNAL_PEER_REMOTE;
-
-/**
- * MojoCreateDataMessageOptions: Used to specify creation parameters for a data
- * pipe to |createDataMessage()|.
- * See core.h for more information.
- */
-dictionary MojoCreateDataMessageOptions {
-  MojoCreateDataMessageOptionsFlags flags;  // See below.
-};
-
-// MojoCreateDataMessageOptionsFlags
-var CREATE_MESSAGE_PIPE_OPTIONS_FLAG_NONE;
-
-/*
- * MojoWriteMessageFlags: Used to specify different modes to |writeMessage()|.
- * See core.h for more information.
- */
-var WRITE_MESSAGE_FLAG_NONE;
-
-/**
- * MojoReadMessageFlags: Used to specify different modes to |readMessage()|.
- * See core.h for more information.
- */
-var READ_MESSAGE_FLAG_NONE;
-
-/**
- * MojoCreateDataPipeOptions: Used to specify creation parameters for a data
- * pipe to |createDataPipe()|.
- * See core.h for more information.
- */
-dictionary MojoCreateDataPipeOptions {
-  MojoCreateDataPipeOptionsFlags flags;  // See below.
-  int32 elementNumBytes;  // The size of an element, in bytes.
-  int32 capacityNumBytes;  // The capacity of the data pipe, in bytes.
-};
-
-// MojoCreateDataPipeOptionsFlags
-var CREATE_DATA_PIPE_OPTIONS_FLAG_NONE;
-
-/*
- * MojoWriteDataFlags: Used to specify different modes to |writeData()|.
- * See core.h for more information.
- */
-var WRITE_DATA_FLAG_NONE;
-var WRITE_DATA_FLAG_ALL_OR_NONE;
-
-/**
- * MojoReadDataFlags: Used to specify different modes to |readData()|.
- * See core.h for more information.
- */
-var READ_DATA_FLAG_NONE;
-var READ_DATA_FLAG_ALL_OR_NONE;
-var READ_DATA_FLAG_DISCARD;
-var READ_DATA_FLAG_QUERY;
-var READ_DATA_FLAG_PEEK;
-
-/**
- * MojoCreateSharedBufferOptionsFlags: Used to specify options to
- *   |createSharedBuffer()|.
- * See core.h for more information.
- */
-var CREATE_SHARED_BUFFER_OPTIONS_FLAG_NONE;
-
-/**
- * MojoDuplicateBufferHandleOptionsFlags: Used to specify options to
- *   |duplicateBufferHandle()|.
- * See core.h for more information.
- */
-var DUPLICATE_BUFFER_HANDLE_OPTIONS_FLAG_NONE;
-var DUPLICATE_BUFFER_HANDLE_OPTIONS_FLAG_READ_ONLY;
-
-/**
- * MojoMapBufferFlags: Used to specify options to |mapBuffer()|.
- * See core.h for more information.
- */
-var MAP_BUFFER_FLAG_NONE;
-
-/**
- * Closes the given |handle|. See MojoClose for more info.
- * @param {MojoHandle} Handle to close.
- * @return {MojoResult} Result code.
- */
-function close(handle) { [native code] }
-
-/**
- * Queries the last known signaling state of |handle|.
- *
- * @param {MojoHandle} handle Handle to query.
- * @return {object} An object of the form {
- *     result,              // MOJO_RESULT_OK or MOJO_RESULT_INVALID_ARGUMENT
- *     satisfiedSignals,    // MojoHandleSignals (see above)
- *     satisfiableSignals,  // MojoHandleSignals
- * }
- */
-function queryHandleSignalsState(handle) { [native code] }
-
-/**
- * Waits on the given handle until a signal indicated by |signals| is
- * satisfied or an error occurs.
- *
- * @param {MojoHandle} handle Handle to wait on.
- * @param {MojoHandleSignals} signals Specifies the condition to wait for.
- * @return {MojoResult} Result code.
- */
-function wait(handle, signals) { [native code] }
-
-/**
- * Creates a message pipe. This function always succeeds.
- * See MojoCreateMessagePipe for more information on message pipes.
- *
- * @param {MojoCreateMessagePipeOptions} optionsDict Options to control the
- * message pipe parameters. May be null.
- * @return {MessagePipe} An object of the form {
- *     handle0,
- *     handle1,
- *   }
- *   where |handle0| and |handle1| are MojoHandles to each end of the channel.
- */
-function createMessagePipe(optionsDict) { [native code] }
-
-/**
- * Writes a message to the message pipe endpoint given by |handle|. See
- * MojoWriteMessage for more information, including return codes.
- *
- * @param {MojoHandle} handle The endpoint to write to.
- * @param {ArrayBufferView} buffer The message data. May be empty.
- * @param {Array.MojoHandle} handlesArray Any handles to attach. Handles are
- *   transferred on success and will no longer be valid. May be empty.
- * @param {MojoWriteMessageFlags} flags Flags.
- * @return {MojoResult} Result code.
- */
-function writeMessage(handle, buffer, handlesArray, flags) { [native code] }
-
-/**
- * Reads a message from the message pipe endpoint given by |handle|. See
- * MojoReadMessage for more information, including return codes.
- *
- * @param {MojoHandle} handle The endpoint to read from.
- * @param {MojoReadMessageFlags} flags Flags.
- * @return {object} An object of the form {
- *     result,  // |RESULT_OK| on success, error code otherwise.
- *     buffer,  // An ArrayBufferView of the message data (only on success).
- *     handles  // An array of MojoHandles transferred, if any.
- *   }
- */
-function readMessage(handle, flags) { [native code] }
-
-/**
- * Creates a data pipe, which is a unidirectional communication channel for
- * unframed data, with the given options. See MojoCreateDataPipe for more
- * more information, including return codes.
- *
- * @param {MojoCreateDataPipeOptions} optionsDict Options to control the data
- *   pipe parameters. May be null.
- * @return {object} An object of the form {
- *     result,  // |RESULT_OK| on success, error code otherwise.
- *     producerHandle,  // MojoHandle to use with writeData (only on success).
- *     consumerHandle,  // MojoHandle to use with readData (only on success).
- *   }
- */
-function createDataPipe(optionsDict) { [native code] }
-
-/**
- * Writes the given data to the data pipe producer given by |handle|. See
- * MojoWriteData for more information, including return codes.
- *
- * @param {MojoHandle} handle A producerHandle returned by createDataPipe.
- * @param {ArrayBufferView} buffer The data to write.
- * @param {MojoWriteDataFlags} flags Flags.
- * @return {object} An object of the form {
- *     result,  // |RESULT_OK| on success, error code otherwise.
- *     numBytes,  // The number of bytes written.
- *   }
- */
-function writeData(handle, buffer, flags) { [native code] }
-
-/**
- * Reads data from the data pipe consumer given by |handle|. May also
- * be used to discard data. See MojoReadData for more information, including
- * return codes.
- *
- * @param {MojoHandle} handle A consumerHandle returned by createDataPipe.
- * @param {MojoReadDataFlags} flags Flags.
- * @return {object} An object of the form {
- *     result,  // |RESULT_OK| on success, error code otherwise.
- *     buffer,  // An ArrayBufferView of the data read (only on success).
- *   }
- */
-function readData(handle, flags) { [native code] }
-
-/**
- * True if the argument is a message or data pipe handle.
- *
- * @param {value} an arbitrary JS value.
- * @return true or false
- */
-function isHandle(value) { [native code] }
-
-/**
- * Creates shared buffer of specified size |num_bytes|.
- * See MojoCreateSharedBuffer for more information including error codes.
- *
- * @param {number} num_bytes Size of the memory to be allocated for shared
- * @param {MojoCreateSharedBufferOptionsFlags} flags Flags.
- *   buffer.
- * @return {object} An object of the form {
- *     result,  // |RESULT_OK| on success, error code otherwise.
- *     handle,  // An MojoHandle for shared buffer (only on success).
- *   }
- */
-function createSharedBuffer(num_bytes, flags) { [native code] }
-
-/**
- * Duplicates the |buffer_handle| to a shared buffer. Duplicated handle can be
- * sent to another process over message pipe. See MojoDuplicateBufferHandle for
- * more information including error codes.
- *
- * @param {MojoHandle} buffer_handle MojoHandle.
- * @param {MojoCreateSharedBufferOptionsFlags} flags Flags.
- * @return {object} An object of the form {
- *     result,  // |RESULT_OK| on success, error code otherwise.
- *     handle,  // A duplicated MojoHandle for shared buffer (only on success).
- *   }
- */
-function duplicateBufferHandle(buffer_handle, flags) { [native code] }
-
-/**
- * Maps the part (at offset |offset| of length |num_bytes|) of the buffer given
- * by |buffer_handle| into ArrayBuffer memory |buffer|, with options specified
- * by |flags|. See MojoMapBuffer for more information including error codes.
- *
- * @param {MojoHandle} buffer_handle A sharedBufferHandle returned by
- *   createSharedBuffer.
- * @param {number} offset Offset.
- * @param {number} num_bytes Size of the memory to be mapped.
- * @param {MojoMapBufferFlags} flags Flags.
- * @return {object} An object of the form {
- *     result,  // |RESULT_OK| on success, error code otherwise.
- *     buffer,  // An ArrayBuffer (only on success).
- *   }
- */
-function mapBuffer(buffer_handle, offset, num_bytes, flags) { [native code] }
-
-/**
- * Unmaps buffer that was mapped using mapBuffer.
- * See MojoUnmapBuffer for more information including error codes.
- *
- * @param {ArrayBuffer} buffer ArrayBuffer.
- * @return {MojoResult} Result code.
- */
-function unmapBuffer(buffer) { [native code] }
diff --git a/mojo/public/js/interface_types.js b/mojo/public/js/interface_types.js
deleted file mode 100644
index 03ba2ba..0000000
--- a/mojo/public/js/interface_types.js
+++ /dev/null
@@ -1,93 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-define("mojo/public/js/interface_types", [
-  "mojo/public/js/core",
-], function(core) {
-
-  // Constants ----------------------------------------------------------------
-  var kInterfaceIdNamespaceMask = 0x80000000;
-  var kMasterInterfaceId = 0x00000000;
-  var kInvalidInterfaceId = 0xFFFFFFFF;
-
-  // ---------------------------------------------------------------------------
-
-  function InterfacePtrInfo(handle, version) {
-    this.handle = handle;
-    this.version = version;
-  }
-
-  InterfacePtrInfo.prototype.isValid = function() {
-    return core.isHandle(this.handle);
-  };
-
-  InterfacePtrInfo.prototype.close = function() {
-    if (!this.isValid())
-      return;
-
-    core.close(this.handle);
-    this.handle = null;
-    this.version = 0;
-  };
-
-  function AssociatedInterfacePtrInfo(interfaceEndpointHandle, version) {
-    this.interfaceEndpointHandle = interfaceEndpointHandle;
-    this.version = version;
-  }
-
-  AssociatedInterfacePtrInfo.prototype.isValid = function() {
-    return this.interfaceEndpointHandle.isValid();
-  };
-
-  // ---------------------------------------------------------------------------
-
-  function InterfaceRequest(handle) {
-    this.handle = handle;
-  }
-
-  InterfaceRequest.prototype.isValid = function() {
-    return core.isHandle(this.handle);
-  };
-
-  InterfaceRequest.prototype.close = function() {
-    if (!this.isValid())
-      return;
-
-    core.close(this.handle);
-    this.handle = null;
-  };
-
-  function AssociatedInterfaceRequest(interfaceEndpointHandle) {
-    this.interfaceEndpointHandle = interfaceEndpointHandle;
-  }
-
-  AssociatedInterfaceRequest.prototype.isValid = function() {
-    return this.interfaceEndpointHandle.isValid();
-  };
-
-  AssociatedInterfaceRequest.prototype.resetWithReason = function(reason) {
-    this.interfaceEndpointHandle.reset(reason);
-  };
-
-  function isMasterInterfaceId(interfaceId) {
-    return interfaceId === kMasterInterfaceId;
-  }
-
-  function isValidInterfaceId(interfaceId) {
-    return interfaceId !== kInvalidInterfaceId;
-  }
-
-  var exports = {};
-  exports.InterfacePtrInfo = InterfacePtrInfo;
-  exports.InterfaceRequest = InterfaceRequest;
-  exports.AssociatedInterfacePtrInfo = AssociatedInterfacePtrInfo;
-  exports.AssociatedInterfaceRequest = AssociatedInterfaceRequest;
-  exports.isMasterInterfaceId = isMasterInterfaceId;
-  exports.isValidInterfaceId = isValidInterfaceId;
-  exports.kInvalidInterfaceId = kInvalidInterfaceId;
-  exports.kMasterInterfaceId = kMasterInterfaceId;
-  exports.kInterfaceIdNamespaceMask = kInterfaceIdNamespaceMask;
-
-  return exports;
-});
diff --git a/mojo/public/js/lib/control_message_handler.js b/mojo/public/js/lib/control_message_handler.js
deleted file mode 100644
index 09c0b78c..0000000
--- a/mojo/public/js/lib/control_message_handler.js
+++ /dev/null
@@ -1,111 +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.
-
-define("mojo/public/js/lib/control_message_handler", [
-  "mojo/public/interfaces/bindings/interface_control_messages.mojom",
-  "mojo/public/js/codec",
-  "mojo/public/js/validator",
-], function(controlMessages, codec, validator) {
-
-  var Validator = validator.Validator;
-
-  function validateControlRequestWithResponse(message) {
-    var messageValidator = new Validator(message);
-    var error = messageValidator.validateMessageIsRequestExpectingResponse();
-    if (error !== validator.validationError.NONE) {
-      throw error;
-    }
-
-    if (message.getName() != controlMessages.kRunMessageId) {
-      throw new Error("Control message name is not kRunMessageId");
-    }
-
-    // Validate payload.
-    error = controlMessages.RunMessageParams.validate(messageValidator,
-        message.getHeaderNumBytes());
-    if (error != validator.validationError.NONE) {
-      throw error;
-    }
-  }
-
-  function validateControlRequestWithoutResponse(message) {
-    var messageValidator = new Validator(message);
-    var error = messageValidator.validateMessageIsRequestWithoutResponse();
-    if (error != validator.validationError.NONE) {
-      throw error;
-    }
-
-    if (message.getName() != controlMessages.kRunOrClosePipeMessageId) {
-      throw new Error("Control message name is not kRunOrClosePipeMessageId");
-    }
-
-    // Validate payload.
-    error = controlMessages.RunOrClosePipeMessageParams.validate(
-        messageValidator, message.getHeaderNumBytes());
-    if (error != validator.validationError.NONE) {
-      throw error;
-    }
-  }
-
-  function runOrClosePipe(message, interface_version) {
-    var reader = new codec.MessageReader(message);
-    var runOrClosePipeMessageParams = reader.decodeStruct(
-        controlMessages.RunOrClosePipeMessageParams);
-    return interface_version >=
-        runOrClosePipeMessageParams.input.require_version.version;
-  }
-
-  function run(message, responder, interface_version) {
-    var reader = new codec.MessageReader(message);
-    var runMessageParams =
-        reader.decodeStruct(controlMessages.RunMessageParams);
-    var runOutput = null;
-
-    if (runMessageParams.input.query_version) {
-      runOutput = new controlMessages.RunOutput();
-      runOutput.query_version_result = new
-          controlMessages.QueryVersionResult({'version': interface_version});
-    }
-
-    var runResponseMessageParams = new
-        controlMessages.RunResponseMessageParams();
-    runResponseMessageParams.output = runOutput;
-
-    var messageName = controlMessages.kRunMessageId;
-    var payloadSize = controlMessages.RunResponseMessageParams.encodedSize;
-    var requestID = reader.requestID;
-    var builder = new codec.MessageV1Builder(messageName,
-        payloadSize, codec.kMessageIsResponse, requestID);
-    builder.encodeStruct(controlMessages.RunResponseMessageParams,
-                         runResponseMessageParams);
-    responder.accept(builder.finish());
-    return true;
-  }
-
-  function isControlMessage(message) {
-    return message.getName() == controlMessages.kRunMessageId ||
-           message.getName() == controlMessages.kRunOrClosePipeMessageId;
-  }
-
-  function ControlMessageHandler(interface_version) {
-    this.interface_version_ = interface_version;
-  }
-
-  ControlMessageHandler.prototype.accept = function(message) {
-    validateControlRequestWithoutResponse(message);
-    return runOrClosePipe(message, this.interface_version_);
-  };
-
-  ControlMessageHandler.prototype.acceptWithResponder = function(message,
-      responder) {
-    validateControlRequestWithResponse(message);
-    return run(message, responder, this.interface_version_);
-  };
-
-  var exports = {};
-  exports.ControlMessageHandler = ControlMessageHandler;
-  exports.isControlMessage = isControlMessage;
-
-  return exports;
-});
diff --git a/mojo/public/js/lib/control_message_proxy.js b/mojo/public/js/lib/control_message_proxy.js
deleted file mode 100644
index 8cd84c5c3..0000000
--- a/mojo/public/js/lib/control_message_proxy.js
+++ /dev/null
@@ -1,104 +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.
-
-define("mojo/public/js/lib/control_message_proxy", [
-  "mojo/public/interfaces/bindings/interface_control_messages.mojom",
-  "mojo/public/js/codec",
-  "mojo/public/js/validator",
-], function(controlMessages, codec, validator) {
-
-  var Validator = validator.Validator;
-
-  function constructRunOrClosePipeMessage(runOrClosePipeInput) {
-    var runOrClosePipeMessageParams = new
-        controlMessages.RunOrClosePipeMessageParams();
-    runOrClosePipeMessageParams.input = runOrClosePipeInput;
-
-    var messageName = controlMessages.kRunOrClosePipeMessageId;
-    var payloadSize = controlMessages.RunOrClosePipeMessageParams.encodedSize;
-    var builder = new codec.MessageV0Builder(messageName, payloadSize);
-    builder.encodeStruct(controlMessages.RunOrClosePipeMessageParams,
-                         runOrClosePipeMessageParams);
-    var message = builder.finish();
-    return message;
-  }
-
-  function validateControlResponse(message) {
-    var messageValidator = new Validator(message);
-    var error = messageValidator.validateMessageIsResponse();
-    if (error != validator.validationError.NONE) {
-      throw error;
-    }
-
-    if (message.getName() != controlMessages.kRunMessageId) {
-      throw new Error("Control message name is not kRunMessageId");
-    }
-
-    // Validate payload.
-    error = controlMessages.RunResponseMessageParams.validate(
-        messageValidator, message.getHeaderNumBytes());
-    if (error != validator.validationError.NONE) {
-      throw error;
-    }
-  }
-
-  function acceptRunResponse(message) {
-    validateControlResponse(message);
-
-    var reader = new codec.MessageReader(message);
-    var runResponseMessageParams = reader.decodeStruct(
-        controlMessages.RunResponseMessageParams);
-
-    return Promise.resolve(runResponseMessageParams);
-  }
-
- /**
-  * Sends the given run message through the receiver.
-  * Accepts the response message from the receiver and decodes the message
-  * struct to RunResponseMessageParams.
-  *
-  * @param  {Router} receiver.
-  * @param  {RunMessageParams} runMessageParams to be sent via a message.
-  * @return {Promise} that resolves to a RunResponseMessageParams.
-  */
-  function sendRunMessage(receiver, runMessageParams) {
-    var messageName = controlMessages.kRunMessageId;
-    var payloadSize = controlMessages.RunMessageParams.encodedSize;
-    // |requestID| is set to 0, but is later properly set by Router.
-    var builder = new codec.MessageV1Builder(messageName,
-        payloadSize, codec.kMessageExpectsResponse, 0);
-    builder.encodeStruct(controlMessages.RunMessageParams, runMessageParams);
-    var message = builder.finish();
-
-    return receiver.acceptAndExpectResponse(message).then(acceptRunResponse);
-  }
-
-  function ControlMessageProxy(receiver) {
-    this.receiver_ = receiver;
-  }
-
-  ControlMessageProxy.prototype.queryVersion = function() {
-    var runMessageParams = new controlMessages.RunMessageParams();
-    runMessageParams.input = new controlMessages.RunInput();
-    runMessageParams.input.query_version = new controlMessages.QueryVersion();
-
-    return sendRunMessage(this.receiver_, runMessageParams).then(function(
-        runResponseMessageParams) {
-      return runResponseMessageParams.output.query_version_result.version;
-    });
-  };
-
-  ControlMessageProxy.prototype.requireVersion = function(version) {
-    var runOrClosePipeInput = new controlMessages.RunOrClosePipeInput();
-    runOrClosePipeInput.require_version = new controlMessages.RequireVersion({
-        'version': version});
-    var message = constructRunOrClosePipeMessage(runOrClosePipeInput);
-    this.receiver_.accept(message);
-  };
-
-  var exports = {};
-  exports.ControlMessageProxy = ControlMessageProxy;
-
-  return exports;
-});
diff --git a/mojo/public/js/lib/interface_endpoint_client.js b/mojo/public/js/lib/interface_endpoint_client.js
deleted file mode 100644
index 3235434d..0000000
--- a/mojo/public/js/lib/interface_endpoint_client.js
+++ /dev/null
@@ -1,243 +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.
-
-define("mojo/public/js/lib/interface_endpoint_client", [
-  "console",
-  "mojo/public/js/codec",
-  "mojo/public/js/lib/control_message_handler",
-  "mojo/public/js/lib/control_message_proxy",
-  "mojo/public/js/lib/interface_endpoint_handle",
-  "mojo/public/js/validator",
-  "timer",
-], function(console,
-            codec,
-            controlMessageHandler,
-            controlMessageProxy,
-            interfaceEndpointHandle,
-            validator,
-            timer) {
-
-  var ControlMessageHandler = controlMessageHandler.ControlMessageHandler;
-  var ControlMessageProxy = controlMessageProxy.ControlMessageProxy;
-  var MessageReader = codec.MessageReader;
-  var InterfaceEndpointHandle = interfaceEndpointHandle.InterfaceEndpointHandle;
-  var AssociationEvent = interfaceEndpointHandle.AssociationEvent;
-
-  function InterfaceEndpointClient(interfaceEndpointHandle, receiver,
-      interfaceVersion) {
-    this.controller_ = null;
-    this.encounteredError_ = false;
-    this.handle_ = interfaceEndpointHandle;
-    this.incomingReceiver_ = receiver;
-
-    if (interfaceVersion !== undefined) {
-      this.controlMessageHandler_ = new ControlMessageHandler(
-          interfaceVersion);
-    } else {
-      this.controlMessageProxy_ = new ControlMessageProxy(this);
-    }
-
-    this.nextRequestID_ = 0;
-    this.completers_ = new Map();
-    this.payloadValidators_ = [];
-    this.connectionErrorHandler_ = null;
-
-    if (interfaceEndpointHandle.pendingAssociation()) {
-      interfaceEndpointHandle.setAssociationEventHandler(
-          this.onAssociationEvent.bind(this));
-    } else {
-      this.initControllerIfNecessary_();
-    }
-  }
-
-  InterfaceEndpointClient.prototype.initControllerIfNecessary_ = function() {
-    if (this.controller_ || this.handle_.pendingAssociation()) {
-      return;
-    }
-
-    this.controller_ = this.handle_.groupController().attachEndpointClient(
-        this.handle_, this);
-  };
-
-  InterfaceEndpointClient.prototype.onAssociationEvent = function(
-      associationEvent) {
-    if (associationEvent === AssociationEvent.ASSOCIATED) {
-      this.initControllerIfNecessary_();
-    } else if (associationEvent ===
-          AssociationEvent.PEER_CLOSED_BEFORE_ASSOCIATION) {
-      timer.createOneShot(0, this.notifyError.bind(this,
-          this.handle_.disconnectReason()));
-    }
-  };
-
-  InterfaceEndpointClient.prototype.passHandle = function() {
-    if (!this.handle_.isValid()) {
-      return new InterfaceEndpointHandle();
-    }
-
-    // Used to clear the previously set callback.
-    this.handle_.setAssociationEventHandler(undefined);
-
-    if (this.controller_) {
-      this.controller_ = null;
-      this.handle_.groupController().detachEndpointClient(this.handle_);
-    }
-    var handle = this.handle_;
-    this.handle_ = null;
-    return handle;
-  };
-
-  InterfaceEndpointClient.prototype.close = function(reason) {
-    var handle = this.passHandle();
-    handle.reset(reason);
-  };
-
-  InterfaceEndpointClient.prototype.accept = function(message) {
-    if (message.associatedEndpointHandles.length > 0) {
-      message.serializeAssociatedEndpointHandles(
-          this.handle_.groupController());
-    }
-
-    if (this.encounteredError_) {
-      return false;
-    }
-
-    this.initControllerIfNecessary_();
-    return this.controller_.sendMessage(message);
-  };
-
-  InterfaceEndpointClient.prototype.acceptAndExpectResponse = function(
-      message) {
-    if (message.associatedEndpointHandles.length > 0) {
-      message.serializeAssociatedEndpointHandles(
-          this.handle_.groupController());
-    }
-
-    if (this.encounteredError_) {
-      return Promise.reject();
-    }
-
-    this.initControllerIfNecessary_();
-
-    // Reserve 0 in case we want it to convey special meaning in the future.
-    var requestID = this.nextRequestID_++;
-    if (requestID === 0)
-      requestID = this.nextRequestID_++;
-
-    message.setRequestID(requestID);
-    var result = this.controller_.sendMessage(message);
-    if (!result)
-      return Promise.reject(Error("Connection error"));
-
-    var completer = {};
-    this.completers_.set(requestID, completer);
-    return new Promise(function(resolve, reject) {
-      completer.resolve = resolve;
-      completer.reject = reject;
-    });
-  };
-
-  InterfaceEndpointClient.prototype.setPayloadValidators = function(
-      payloadValidators) {
-    this.payloadValidators_ = payloadValidators;
-  };
-
-  InterfaceEndpointClient.prototype.setIncomingReceiver = function(receiver) {
-    this.incomingReceiver_ = receiver;
-  };
-
-  InterfaceEndpointClient.prototype.setConnectionErrorHandler = function(
-      handler) {
-    this.connectionErrorHandler_ = handler;
-  };
-
-  InterfaceEndpointClient.prototype.handleIncomingMessage = function(message,
-      messageValidator) {
-    var noError = validator.validationError.NONE;
-    var err = noError;
-    for (var i = 0; err === noError && i < this.payloadValidators_.length; ++i)
-      err = this.payloadValidators_[i](messageValidator);
-
-    if (err == noError) {
-      return this.handleValidIncomingMessage_(message);
-    } else {
-      validator.reportValidationError(err);
-      return false;
-    }
-  };
-
-  InterfaceEndpointClient.prototype.handleValidIncomingMessage_ = function(
-      message) {
-    if (validator.isTestingMode()) {
-      return true;
-    }
-
-    if (this.encounteredError_) {
-      return false;
-    }
-
-    var ok = false;
-
-    if (message.expectsResponse()) {
-      if (controlMessageHandler.isControlMessage(message) &&
-          this.controlMessageHandler_) {
-        ok = this.controlMessageHandler_.acceptWithResponder(message, this);
-      } else if (this.incomingReceiver_) {
-        ok = this.incomingReceiver_.acceptWithResponder(message, this);
-      }
-    } else if (message.isResponse()) {
-      var reader = new MessageReader(message);
-      var requestID = reader.requestID;
-      var completer = this.completers_.get(requestID);
-      if (completer) {
-        this.completers_.delete(requestID);
-        completer.resolve(message);
-        ok = true;
-      } else {
-        console.log("Unexpected response with request ID: " + requestID);
-      }
-    } else {
-      if (controlMessageHandler.isControlMessage(message) &&
-          this.controlMessageHandler_) {
-        ok = this.controlMessageHandler_.accept(message);
-      } else if (this.incomingReceiver_) {
-        ok = this.incomingReceiver_.accept(message);
-      }
-    }
-    return ok;
-  };
-
-  InterfaceEndpointClient.prototype.notifyError = function(reason) {
-    if (this.encounteredError_) {
-      return;
-    }
-    this.encounteredError_ = true;
-
-    this.completers_.forEach(function(value) {
-      value.reject();
-    });
-    this.completers_.clear();  // Drop any responders.
-
-    if (this.connectionErrorHandler_) {
-      this.connectionErrorHandler_(reason);
-    }
-  };
-
-  InterfaceEndpointClient.prototype.queryVersion = function() {
-    return this.controlMessageProxy_.queryVersion();
-  };
-
-  InterfaceEndpointClient.prototype.requireVersion = function(version) {
-    this.controlMessageProxy_.requireVersion(version);
-  };
-
-  InterfaceEndpointClient.prototype.getEncounteredError = function() {
-    return this.encounteredError_;
-  };
-
-  var exports = {};
-  exports.InterfaceEndpointClient = InterfaceEndpointClient;
-
-  return exports;
-});
diff --git a/mojo/public/js/lib/interface_endpoint_handle.js b/mojo/public/js/lib/interface_endpoint_handle.js
deleted file mode 100644
index dda951a..0000000
--- a/mojo/public/js/lib/interface_endpoint_handle.js
+++ /dev/null
@@ -1,187 +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.
-
-define("mojo/public/js/lib/interface_endpoint_handle", [
-  "mojo/public/js/interface_types",
-  "timer",
-], function(types, timer) {
-
-  var AssociationEvent = {
-    // The interface has been associated with a message pipe.
-    ASSOCIATED: 'associated',
-    // The peer of this object has been closed before association.
-    PEER_CLOSED_BEFORE_ASSOCIATION: 'peer_closed_before_association'
-  };
-
-  function State(interfaceId, associatedGroupController) {
-    if (interfaceId === undefined) {
-      interfaceId = types.kInvalidInterfaceId;
-    }
-
-    this.interfaceId = interfaceId;
-    this.associatedGroupController = associatedGroupController;
-    this.pendingAssociation = false;
-    this.disconnectReason = null;
-    this.peerState_ = null;
-    this.associationEventHandler_ = null;
-  }
-
-  State.prototype.initPendingState = function(peer) {
-    this.pendingAssociation = true;
-    this.peerState_ = peer;
-  };
-
-  State.prototype.isValid = function() {
-    return this.pendingAssociation ||
-        types.isValidInterfaceId(this.interfaceId);
-  };
-
-  State.prototype.close = function(disconnectReason) {
-    var cachedGroupController;
-    var cachedPeerState;
-    var cachedId = types.kInvalidInterfaceId;
-
-    if (!this.pendingAssociation) {
-      if (types.isValidInterfaceId(this.interfaceId)) {
-        cachedGroupController = this.associatedGroupController;
-        this.associatedGroupController = null;
-        cachedId = this.interfaceId;
-        this.interfaceId = types.kInvalidInterfaceId;
-      }
-    } else {
-      this.pendingAssociation = false;
-      cachedPeerState = this.peerState_;
-      this.peerState_ = null;
-    }
-
-    if (cachedGroupController) {
-      cachedGroupController.closeEndpointHandle(cachedId,
-          disconnectReason);
-    } else if (cachedPeerState) {
-      cachedPeerState.onPeerClosedBeforeAssociation(disconnectReason);
-    }
-  };
-
-  State.prototype.runAssociationEventHandler = function(associationEvent) {
-    if (this.associationEventHandler_) {
-      var handler = this.associationEventHandler_;
-      this.associationEventHandler_ = null;
-      handler(associationEvent);
-    }
-  };
-
-  State.prototype.setAssociationEventHandler = function(handler) {
-    if (!this.pendingAssociation &&
-        !types.isValidInterfaceId(this.interfaceId)) {
-      return;
-    }
-
-    if (!handler) {
-      this.associationEventHandler_ = null;
-      return;
-    }
-
-    this.associationEventHandler_ = handler;
-    if (!this.pendingAssociation) {
-      timer.createOneShot(0, this.runAssociationEventHandler.bind(this,
-          AssociationEvent.ASSOCIATED));
-    } else if (!this.peerState_) {
-      timer.createOneShot(0, this.runAssociationEventHandler.bind(this,
-          AssociationEvent.PEER_CLOSED_BEFORE_ASSOCIATION));
-    }
-  };
-
-  State.prototype.notifyAssociation = function(interfaceId,
-                                               peerGroupController) {
-    var cachedPeerState = this.peerState_;
-    this.peerState_ = null;
-
-    this.pendingAssociation = false;
-
-    if (cachedPeerState) {
-      cachedPeerState.onAssociated(interfaceId, peerGroupController);
-      return true;
-    }
-    return false;
-  };
-
-  State.prototype.onAssociated = function(interfaceId,
-      associatedGroupController) {
-    if (!this.pendingAssociation) {
-      return;
-    }
-
-    this.pendingAssociation = false;
-    this.peerState_ = null;
-    this.interfaceId = interfaceId;
-    this.associatedGroupController = associatedGroupController;
-    this.runAssociationEventHandler(AssociationEvent.ASSOCIATED);
-  };
-
-  State.prototype.onPeerClosedBeforeAssociation = function(disconnectReason) {
-    if (!this.pendingAssociation) {
-      return;
-    }
-
-    this.peerState_ = null;
-    this.disconnectReason = disconnectReason;
-
-    this.runAssociationEventHandler(
-        AssociationEvent.PEER_CLOSED_BEFORE_ASSOCIATION);
-  };
-
-  function createPairPendingAssociation() {
-    var handle0 = new InterfaceEndpointHandle();
-    var handle1 = new InterfaceEndpointHandle();
-    handle0.state_.initPendingState(handle1.state_);
-    handle1.state_.initPendingState(handle0.state_);
-    return {handle0: handle0, handle1: handle1};
-  }
-
-  function InterfaceEndpointHandle(interfaceId, associatedGroupController) {
-    this.state_ = new State(interfaceId, associatedGroupController);
-  }
-
-  InterfaceEndpointHandle.prototype.isValid = function() {
-    return this.state_.isValid();
-  };
-
-  InterfaceEndpointHandle.prototype.pendingAssociation = function() {
-    return this.state_.pendingAssociation;
-  };
-
-  InterfaceEndpointHandle.prototype.id = function() {
-    return this.state_.interfaceId;
-  };
-
-  InterfaceEndpointHandle.prototype.groupController = function() {
-    return this.state_.associatedGroupController;
-  };
-
-  InterfaceEndpointHandle.prototype.disconnectReason = function() {
-    return this.state_.disconnectReason;
-  };
-
-  InterfaceEndpointHandle.prototype.setAssociationEventHandler = function(
-      handler) {
-    this.state_.setAssociationEventHandler(handler);
-  };
-
-  InterfaceEndpointHandle.prototype.notifyAssociation = function(interfaceId,
-      peerGroupController) {
-    return this.state_.notifyAssociation(interfaceId, peerGroupController);
-  };
-
-  InterfaceEndpointHandle.prototype.reset = function(reason) {
-    this.state_.close(reason);
-    this.state_ = new State();
-  };
-
-  var exports = {};
-  exports.AssociationEvent = AssociationEvent;
-  exports.InterfaceEndpointHandle = InterfaceEndpointHandle;
-  exports.createPairPendingAssociation = createPairPendingAssociation;
-
-  return exports;
-});
diff --git a/mojo/public/js/lib/pipe_control_message_handler.js b/mojo/public/js/lib/pipe_control_message_handler.js
deleted file mode 100644
index 2eb45d162..0000000
--- a/mojo/public/js/lib/pipe_control_message_handler.js
+++ /dev/null
@@ -1,61 +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.
-
-define("mojo/public/js/lib/pipe_control_message_handler", [
-  "mojo/public/interfaces/bindings/pipe_control_messages.mojom",
-  "mojo/public/js/codec",
-  "mojo/public/js/interface_types",
-  "mojo/public/js/validator",
-], function(pipeControlMessages, codec, types, validator) {
-
-  var Validator = validator.Validator;
-
-  function validateControlRequestWithoutResponse(message) {
-    var messageValidator = new Validator(message);
-    var error = messageValidator.validateMessageIsRequestWithoutResponse();
-    if (error != validator.validationError.NONE) {
-      throw error;
-    }
-
-    if (message.getName() != pipeControlMessages.kRunOrClosePipeMessageId) {
-      throw new Error("Control message name is not kRunOrClosePipeMessageId");
-    }
-
-    // Validate payload.
-    error = pipeControlMessages.RunOrClosePipeMessageParams.validate(
-        messageValidator, message.getHeaderNumBytes());
-    if (error != validator.validationError.NONE) {
-      throw error;
-    }
-  }
-
-  function runOrClosePipe(message, delegate) {
-    var reader = new codec.MessageReader(message);
-    var runOrClosePipeMessageParams = reader.decodeStruct(
-        pipeControlMessages.RunOrClosePipeMessageParams);
-    var event = runOrClosePipeMessageParams.input
-        .peer_associated_endpoint_closed_event;
-    return delegate.onPeerAssociatedEndpointClosed(event.id,
-        event.disconnect_reason);
-  }
-
-  function isPipeControlMessage(message) {
-    return !types.isValidInterfaceId(message.getInterfaceId());
-  }
-
-  function PipeControlMessageHandler(delegate) {
-    this.delegate_ = delegate;
-  }
-
-  PipeControlMessageHandler.prototype.accept = function(message) {
-    validateControlRequestWithoutResponse(message);
-    return runOrClosePipe(message, this.delegate_);
-  };
-
-  var exports = {};
-  exports.PipeControlMessageHandler = PipeControlMessageHandler;
-  exports.isPipeControlMessage = isPipeControlMessage;
-
-  return exports;
-});
diff --git a/mojo/public/js/lib/pipe_control_message_proxy.js b/mojo/public/js/lib/pipe_control_message_proxy.js
deleted file mode 100644
index 71091d0..0000000
--- a/mojo/public/js/lib/pipe_control_message_proxy.js
+++ /dev/null
@@ -1,56 +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.
-
-define("mojo/public/js/lib/pipe_control_message_proxy", [
-  "mojo/public/interfaces/bindings/pipe_control_messages.mojom",
-  "mojo/public/js/codec",
-  "mojo/public/js/interface_types",
-], function(pipeControlMessages, codec, types) {
-
-  function constructRunOrClosePipeMessage(runOrClosePipeInput) {
-    var runOrClosePipeMessageParams = new
-        pipeControlMessages.RunOrClosePipeMessageParams();
-    runOrClosePipeMessageParams.input = runOrClosePipeInput;
-
-    var messageName = pipeControlMessages.kRunOrClosePipeMessageId;
-    var payloadSize =
-        pipeControlMessages.RunOrClosePipeMessageParams.encodedSize;
-
-    var builder = new codec.MessageV0Builder(messageName, payloadSize);
-    builder.encodeStruct(pipeControlMessages.RunOrClosePipeMessageParams,
-                         runOrClosePipeMessageParams);
-    var message = builder.finish();
-    message.setInterfaceId(types.kInvalidInterfaceId);
-    return message;
-  }
-
-  function PipeControlMessageProxy(receiver) {
-    this.receiver_ = receiver;
-  }
-
-  PipeControlMessageProxy.prototype.notifyPeerEndpointClosed = function(
-      interfaceId, reason) {
-    var message = this.constructPeerEndpointClosedMessage(interfaceId, reason);
-    this.receiver_.accept(message);
-  };
-
-  PipeControlMessageProxy.prototype.constructPeerEndpointClosedMessage =
-      function(interfaceId, reason) {
-    var event = new pipeControlMessages.PeerAssociatedEndpointClosedEvent();
-    event.id = interfaceId;
-    if (reason) {
-      event.disconnect_reason = new pipeControlMessages.DisconnectReason({
-          custom_reason: reason.custom_reason,
-          description: reason.description});
-    }
-    var runOrClosePipeInput = new pipeControlMessages.RunOrClosePipeInput();
-    runOrClosePipeInput.peer_associated_endpoint_closed_event = event;
-    return constructRunOrClosePipeMessage(runOrClosePipeInput);
-  };
-
-  var exports = {};
-  exports.PipeControlMessageProxy = PipeControlMessageProxy;
-
-  return exports;
-});
diff --git a/mojo/public/js/new_bindings/lib/control_message_handler.js b/mojo/public/js/new_bindings/lib/control_message_handler.js
index 93e5e2c..ad816544 100644
--- a/mojo/public/js/new_bindings/lib/control_message_handler.js
+++ b/mojo/public/js/new_bindings/lib/control_message_handler.js
@@ -12,12 +12,12 @@
       throw error;
     }
 
-    if (message.getName() != mojo.interfaceControl2.kRunMessageId) {
+    if (message.getName() != mojo.interfaceControl.kRunMessageId) {
       throw new Error("Control message name is not kRunMessageId");
     }
 
     // Validate payload.
-    error = mojo.interfaceControl2.RunMessageParams.validate(messageValidator,
+    error = mojo.interfaceControl.RunMessageParams.validate(messageValidator,
         message.getHeaderNumBytes());
     if (error != internal.validationError.NONE) {
       throw error;
@@ -31,12 +31,12 @@
       throw error;
     }
 
-    if (message.getName() != mojo.interfaceControl2.kRunOrClosePipeMessageId) {
+    if (message.getName() != mojo.interfaceControl.kRunOrClosePipeMessageId) {
       throw new Error("Control message name is not kRunOrClosePipeMessageId");
     }
 
     // Validate payload.
-    error = mojo.interfaceControl2.RunOrClosePipeMessageParams.validate(
+    error = mojo.interfaceControl.RunOrClosePipeMessageParams.validate(
         messageValidator, message.getHeaderNumBytes());
     if (error != internal.validationError.NONE) {
       throw error;
@@ -46,7 +46,7 @@
   function runOrClosePipe(message, interfaceVersion) {
     var reader = new internal.MessageReader(message);
     var runOrClosePipeMessageParams = reader.decodeStruct(
-        mojo.interfaceControl2.RunOrClosePipeMessageParams);
+        mojo.interfaceControl.RunOrClosePipeMessageParams);
     return interfaceVersion >=
         runOrClosePipeMessageParams.input.requireVersion.version;
   }
@@ -54,35 +54,35 @@
   function run(message, responder, interfaceVersion) {
     var reader = new internal.MessageReader(message);
     var runMessageParams =
-        reader.decodeStruct(mojo.interfaceControl2.RunMessageParams);
+        reader.decodeStruct(mojo.interfaceControl.RunMessageParams);
     var runOutput = null;
 
     if (runMessageParams.input.queryVersion) {
-      runOutput = new mojo.interfaceControl2.RunOutput();
+      runOutput = new mojo.interfaceControl.RunOutput();
       runOutput.queryVersionResult = new
-          mojo.interfaceControl2.QueryVersionResult(
+          mojo.interfaceControl.QueryVersionResult(
               {'version': interfaceVersion});
     }
 
     var runResponseMessageParams = new
-        mojo.interfaceControl2.RunResponseMessageParams();
+        mojo.interfaceControl.RunResponseMessageParams();
     runResponseMessageParams.output = runOutput;
 
-    var messageName = mojo.interfaceControl2.kRunMessageId;
+    var messageName = mojo.interfaceControl.kRunMessageId;
     var payloadSize =
-        mojo.interfaceControl2.RunResponseMessageParams.encodedSize;
+        mojo.interfaceControl.RunResponseMessageParams.encodedSize;
     var requestID = reader.requestID;
     var builder = new internal.MessageV1Builder(messageName,
         payloadSize, internal.kMessageIsResponse, requestID);
-    builder.encodeStruct(mojo.interfaceControl2.RunResponseMessageParams,
+    builder.encodeStruct(mojo.interfaceControl.RunResponseMessageParams,
                          runResponseMessageParams);
     responder.accept(builder.finish());
     return true;
   }
 
   function isInterfaceControlMessage(message) {
-    return message.getName() == mojo.interfaceControl2.kRunMessageId ||
-           message.getName() == mojo.interfaceControl2.kRunOrClosePipeMessageId;
+    return message.getName() == mojo.interfaceControl.kRunMessageId ||
+           message.getName() == mojo.interfaceControl.kRunOrClosePipeMessageId;
   }
 
   function ControlMessageHandler(interfaceVersion) {
diff --git a/mojo/public/js/new_bindings/lib/control_message_proxy.js b/mojo/public/js/new_bindings/lib/control_message_proxy.js
index 6bce620..c8447cde 100644
--- a/mojo/public/js/new_bindings/lib/control_message_proxy.js
+++ b/mojo/public/js/new_bindings/lib/control_message_proxy.js
@@ -7,14 +7,14 @@
 
   function constructRunOrClosePipeMessage(runOrClosePipeInput) {
     var runOrClosePipeMessageParams = new
-        mojo.interfaceControl2.RunOrClosePipeMessageParams();
+        mojo.interfaceControl.RunOrClosePipeMessageParams();
     runOrClosePipeMessageParams.input = runOrClosePipeInput;
 
-    var messageName = mojo.interfaceControl2.kRunOrClosePipeMessageId;
+    var messageName = mojo.interfaceControl.kRunOrClosePipeMessageId;
     var payloadSize =
-        mojo.interfaceControl2.RunOrClosePipeMessageParams.encodedSize;
+        mojo.interfaceControl.RunOrClosePipeMessageParams.encodedSize;
     var builder = new internal.MessageV0Builder(messageName, payloadSize);
-    builder.encodeStruct(mojo.interfaceControl2.RunOrClosePipeMessageParams,
+    builder.encodeStruct(mojo.interfaceControl.RunOrClosePipeMessageParams,
                          runOrClosePipeMessageParams);
     var message = builder.finish();
     return message;
@@ -27,12 +27,12 @@
       throw error;
     }
 
-    if (message.getName() != mojo.interfaceControl2.kRunMessageId) {
+    if (message.getName() != mojo.interfaceControl.kRunMessageId) {
       throw new Error("Control message name is not kRunMessageId");
     }
 
     // Validate payload.
-    error = mojo.interfaceControl2.RunResponseMessageParams.validate(
+    error = mojo.interfaceControl.RunResponseMessageParams.validate(
         messageValidator, message.getHeaderNumBytes());
     if (error != internal.validationError.NONE) {
       throw error;
@@ -44,7 +44,7 @@
 
     var reader = new internal.MessageReader(message);
     var runResponseMessageParams = reader.decodeStruct(
-        mojo.interfaceControl2.RunResponseMessageParams);
+        mojo.interfaceControl.RunResponseMessageParams);
 
     return Promise.resolve(runResponseMessageParams);
   }
@@ -59,12 +59,12 @@
   * @return {Promise} that resolves to a RunResponseMessageParams.
   */
   function sendRunMessage(receiver, runMessageParams) {
-    var messageName = mojo.interfaceControl2.kRunMessageId;
-    var payloadSize = mojo.interfaceControl2.RunMessageParams.encodedSize;
+    var messageName = mojo.interfaceControl.kRunMessageId;
+    var payloadSize = mojo.interfaceControl.RunMessageParams.encodedSize;
     // |requestID| is set to 0, but is later properly set by Router.
     var builder = new internal.MessageV1Builder(messageName,
         payloadSize, internal.kMessageExpectsResponse, 0);
-    builder.encodeStruct(mojo.interfaceControl2.RunMessageParams,
+    builder.encodeStruct(mojo.interfaceControl.RunMessageParams,
                          runMessageParams);
     var message = builder.finish();
 
@@ -76,10 +76,10 @@
   }
 
   ControlMessageProxy.prototype.queryVersion = function() {
-    var runMessageParams = new mojo.interfaceControl2.RunMessageParams();
-    runMessageParams.input = new mojo.interfaceControl2.RunInput();
+    var runMessageParams = new mojo.interfaceControl.RunMessageParams();
+    runMessageParams.input = new mojo.interfaceControl.RunInput();
     runMessageParams.input.queryVersion =
-        new mojo.interfaceControl2.QueryVersion();
+        new mojo.interfaceControl.QueryVersion();
 
     return sendRunMessage(this.receiver_, runMessageParams).then(function(
         runResponseMessageParams) {
@@ -88,9 +88,9 @@
   };
 
   ControlMessageProxy.prototype.requireVersion = function(version) {
-    var runOrClosePipeInput = new mojo.interfaceControl2.RunOrClosePipeInput();
+    var runOrClosePipeInput = new mojo.interfaceControl.RunOrClosePipeInput();
     runOrClosePipeInput.requireVersion =
-        new mojo.interfaceControl2.RequireVersion({'version': version});
+        new mojo.interfaceControl.RequireVersion({'version': version});
     var message = constructRunOrClosePipeMessage(runOrClosePipeInput);
     this.receiver_.accept(message);
   };
diff --git a/mojo/public/js/new_bindings/lib/pipe_control_message_handler.js b/mojo/public/js/new_bindings/lib/pipe_control_message_handler.js
index 465bf85..f395f22b 100644
--- a/mojo/public/js/new_bindings/lib/pipe_control_message_handler.js
+++ b/mojo/public/js/new_bindings/lib/pipe_control_message_handler.js
@@ -12,12 +12,12 @@
       throw error;
     }
 
-    if (message.getName() != mojo.pipeControl2.kRunOrClosePipeMessageId) {
+    if (message.getName() != mojo.pipeControl.kRunOrClosePipeMessageId) {
       throw new Error("Control message name is not kRunOrClosePipeMessageId");
     }
 
     // Validate payload.
-    error = mojo.pipeControl2.RunOrClosePipeMessageParams.validate(
+    error = mojo.pipeControl.RunOrClosePipeMessageParams.validate(
         messageValidator, message.getHeaderNumBytes());
     if (error != internal.validationError.NONE) {
       throw error;
@@ -27,7 +27,7 @@
   function runOrClosePipe(message, delegate) {
     var reader = new internal.MessageReader(message);
     var runOrClosePipeMessageParams = reader.decodeStruct(
-        mojo.pipeControl2.RunOrClosePipeMessageParams);
+        mojo.pipeControl.RunOrClosePipeMessageParams);
     var event = runOrClosePipeMessageParams.input
         .peerAssociatedEndpointClosedEvent;
     return delegate.onPeerAssociatedEndpointClosed(event.id,
diff --git a/mojo/public/js/new_bindings/lib/pipe_control_message_proxy.js b/mojo/public/js/new_bindings/lib/pipe_control_message_proxy.js
index 55cf151d..6e3d5cac 100644
--- a/mojo/public/js/new_bindings/lib/pipe_control_message_proxy.js
+++ b/mojo/public/js/new_bindings/lib/pipe_control_message_proxy.js
@@ -7,15 +7,15 @@
 
   function constructRunOrClosePipeMessage(runOrClosePipeInput) {
     var runOrClosePipeMessageParams = new
-        mojo.pipeControl2.RunOrClosePipeMessageParams();
+        mojo.pipeControl.RunOrClosePipeMessageParams();
     runOrClosePipeMessageParams.input = runOrClosePipeInput;
 
-    var messageName = mojo.pipeControl2.kRunOrClosePipeMessageId;
+    var messageName = mojo.pipeControl.kRunOrClosePipeMessageId;
     var payloadSize =
-        mojo.pipeControl2.RunOrClosePipeMessageParams.encodedSize;
+        mojo.pipeControl.RunOrClosePipeMessageParams.encodedSize;
 
     var builder = new internal.MessageV0Builder(messageName, payloadSize);
-    builder.encodeStruct(mojo.pipeControl2.RunOrClosePipeMessageParams,
+    builder.encodeStruct(mojo.pipeControl.RunOrClosePipeMessageParams,
                          runOrClosePipeMessageParams);
     var message = builder.finish();
     message.setInterfaceId(internal.kInvalidInterfaceId);
@@ -34,14 +34,14 @@
 
   PipeControlMessageProxy.prototype.constructPeerEndpointClosedMessage =
       function(interfaceId, reason) {
-    var event = new mojo.pipeControl2.PeerAssociatedEndpointClosedEvent();
+    var event = new mojo.pipeControl.PeerAssociatedEndpointClosedEvent();
     event.id = interfaceId;
     if (reason) {
-      event.disconnectReason = new mojo.pipeControl2.DisconnectReason({
+      event.disconnectReason = new mojo.pipeControl.DisconnectReason({
           customReason: reason.customReason,
           description: reason.description});
     }
-    var runOrClosePipeInput = new mojo.pipeControl2.RunOrClosePipeInput();
+    var runOrClosePipeInput = new mojo.pipeControl.RunOrClosePipeInput();
     runOrClosePipeInput.peerAssociatedEndpointClosedEvent = event;
     return constructRunOrClosePipeMessage(runOrClosePipeInput);
   };
diff --git a/mojo/public/js/router.js b/mojo/public/js/router.js
deleted file mode 100644
index 805f663..0000000
--- a/mojo/public/js/router.js
+++ /dev/null
@@ -1,331 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-define("mojo/public/js/router", [
-  "mojo/public/js/connector",
-  "mojo/public/js/core",
-  "mojo/public/js/interface_types",
-  "mojo/public/js/lib/interface_endpoint_handle",
-  "mojo/public/js/lib/pipe_control_message_handler",
-  "mojo/public/js/lib/pipe_control_message_proxy",
-  "mojo/public/js/validator",
-  "timer",
-], function(connector, core, types, interfaceEndpointHandle,
-      controlMessageHandler, controlMessageProxy, validator, timer) {
-
-  var Connector = connector.Connector;
-  var PipeControlMessageHandler =
-      controlMessageHandler.PipeControlMessageHandler;
-  var PipeControlMessageProxy = controlMessageProxy.PipeControlMessageProxy;
-  var Validator = validator.Validator;
-  var InterfaceEndpointHandle = interfaceEndpointHandle.InterfaceEndpointHandle;
-
-  /**
-   * The state of |endpoint|. If both the endpoint and its peer have been
-   * closed, removes it from |endpoints_|.
-   * @enum {string}
-   */
-  var EndpointStateUpdateType = {
-    ENDPOINT_CLOSED: 'endpoint_closed',
-    PEER_ENDPOINT_CLOSED: 'peer_endpoint_closed'
-  };
-
-  function check(condition, output) {
-    if (!condition) {
-      // testharness.js does not rethrow errors so the error stack needs to be
-      // included as a string in the error we throw for debugging layout tests.
-      throw new Error((new Error()).stack);
-    }
-  }
-
-  function InterfaceEndpoint(router, interfaceId) {
-    this.router_ = router;
-    this.id = interfaceId;
-    this.closed = false;
-    this.peerClosed = false;
-    this.handleCreated = false;
-    this.disconnectReason = null;
-    this.client = null;
-  }
-
-  InterfaceEndpoint.prototype.sendMessage = function(message) {
-    message.setInterfaceId(this.id);
-    return this.router_.connector_.accept(message);
-  };
-
-  function Router(handle, setInterfaceIdNamespaceBit) {
-    if (!core.isHandle(handle)) {
-      throw new Error("Router constructor: Not a handle");
-    }
-    if (setInterfaceIdNamespaceBit === undefined) {
-      setInterfaceIdNamespaceBit = false;
-    }
-
-    this.connector_ = new Connector(handle);
-
-    this.connector_.setIncomingReceiver({
-        accept: this.accept.bind(this),
-    });
-    this.connector_.setErrorHandler({
-        onError: this.onPipeConnectionError.bind(this),
-    });
-
-    this.setInterfaceIdNamespaceBit_ = setInterfaceIdNamespaceBit;
-    // |cachedMessageData| caches infomation about a message, so it can be
-    // processed later if a client is not yet attached to the target endpoint.
-    this.cachedMessageData = null;
-    this.controlMessageHandler_ = new PipeControlMessageHandler(this);
-    this.controlMessageProxy_ = new PipeControlMessageProxy(this.connector_);
-    this.nextInterfaceIdValue_ = 1;
-    this.encounteredError_ = false;
-    this.endpoints_ = new Map();
-  }
-
-  Router.prototype.associateInterface = function(handleToSend) {
-    if (!handleToSend.pendingAssociation()) {
-      return types.kInvalidInterfaceId;
-    }
-
-    var id = 0;
-    do {
-      if (this.nextInterfaceIdValue_ >= types.kInterfaceIdNamespaceMask) {
-        this.nextInterfaceIdValue_ = 1;
-      }
-      id = this.nextInterfaceIdValue_++;
-      if (this.setInterfaceIdNamespaceBit_) {
-        id += types.kInterfaceIdNamespaceMask;
-      }
-    } while (this.endpoints_.has(id));
-
-    var endpoint = new InterfaceEndpoint(this, id);
-    this.endpoints_.set(id, endpoint);
-    if (this.encounteredError_) {
-      this.updateEndpointStateMayRemove(endpoint,
-          EndpointStateUpdateType.PEER_ENDPOINT_CLOSED);
-    }
-    endpoint.handleCreated = true;
-
-    if (!handleToSend.notifyAssociation(id, this)) {
-      // The peer handle of |handleToSend|, which is supposed to join this
-      // associated group, has been closed.
-      this.updateEndpointStateMayRemove(endpoint,
-          EndpointStateUpdateType.ENDPOINT_CLOSED);
-
-      pipeControlMessageproxy.notifyPeerEndpointClosed(id,
-          handleToSend.disconnectReason());
-    }
-
-    return id;
-  };
-
-  Router.prototype.attachEndpointClient = function(
-      interfaceEndpointHandle, interfaceEndpointClient) {
-    check(types.isValidInterfaceId(interfaceEndpointHandle.id()));
-    check(interfaceEndpointClient);
-
-    var endpoint = this.endpoints_.get(interfaceEndpointHandle.id());
-    check(endpoint);
-    check(!endpoint.client);
-    check(!endpoint.closed);
-    endpoint.client = interfaceEndpointClient;
-
-    if (endpoint.peerClosed) {
-      timer.createOneShot(0,
-          endpoint.client.notifyError.bind(endpoint.client));
-    }
-
-    if (this.cachedMessageData && interfaceEndpointHandle.id() ===
-        this.cachedMessageData.message.getInterfaceId()) {
-      timer.createOneShot(0, (function() {
-        if (!this.cachedMessageData) {
-          return;
-        }
-
-        var targetEndpoint = this.endpoints_.get(
-            this.cachedMessageData.message.getInterfaceId());
-        // Check that the target endpoint's client still exists.
-        if (targetEndpoint && targetEndpoint.client) {
-          var message = this.cachedMessageData.message;
-          var messageValidator = this.cachedMessageData.messageValidator;
-          this.cachedMessageData = null;
-          this.connector_.resumeIncomingMethodCallProcessing();
-          var ok = endpoint.client.handleIncomingMessage(message,
-              messageValidator);
-
-          // Handle invalid cached incoming message.
-          if (!validator.isTestingMode() && !ok) {
-            this.connector_.handleError(true, true);
-          }
-        }
-      }).bind(this));
-    }
-
-    return endpoint;
-  };
-
-  Router.prototype.detachEndpointClient = function(
-      interfaceEndpointHandle) {
-    check(types.isValidInterfaceId(interfaceEndpointHandle.id()));
-    var endpoint = this.endpoints_.get(interfaceEndpointHandle.id());
-    check(endpoint);
-    check(endpoint.client);
-    check(!endpoint.closed);
-
-    endpoint.client = null;
-  };
-
-  Router.prototype.createLocalEndpointHandle = function(
-      interfaceId) {
-    if (!types.isValidInterfaceId(interfaceId)) {
-      return new InterfaceEndpointHandle();
-    }
-
-    var endpoint = this.endpoints_.get(interfaceId);
-
-    if (!endpoint) {
-      endpoint = new InterfaceEndpoint(this, interfaceId);
-      this.endpoints_.set(interfaceId, endpoint);
-
-      check(!endpoint.handleCreated);
-
-      if (this.encounteredError_) {
-        this.updateEndpointStateMayRemove(endpoint,
-            EndpointStateUpdateType.PEER_ENDPOINT_CLOSED);
-      }
-    } else {
-      if (endpoint.handleCreated) {
-        return new InterfaceEndpointHandle();
-      }
-
-      // If the endpoint already exist, it is because we have received a
-      // notification that the peer endpoint has closed.
-      check(!endpoint.closed);
-      check(endpoint.peerClosed);
-    }
-
-    endpoint.handleCreated = true;
-    return new InterfaceEndpointHandle(interfaceId, this);
-  };
-
-  Router.prototype.accept = function(message) {
-    var messageValidator = new Validator(message);
-    var err = messageValidator.validateMessageHeader();
-
-    var ok = false;
-    if (err !== validator.validationError.NONE) {
-      validator.reportValidationError(err);
-    } else if (message.deserializeAssociatedEndpointHandles(this)) {
-      if (controlMessageHandler.isPipeControlMessage(message)) {
-        ok = this.controlMessageHandler_.accept(message);
-      } else {
-        var interfaceId = message.getInterfaceId();
-        var endpoint = this.endpoints_.get(interfaceId);
-        if (!endpoint || endpoint.closed) {
-          return true;
-        }
-
-        if (!endpoint.client) {
-          // We need to wait until a client is attached in order to dispatch
-          // further messages.
-          this.cachedMessageData = {message: message,
-              messageValidator: messageValidator};
-          this.connector_.pauseIncomingMethodCallProcessing();
-          return true;
-        }
-        ok = endpoint.client.handleIncomingMessage(message, messageValidator);
-      }
-    }
-    return ok;
-  };
-
-  Router.prototype.close = function() {
-    this.connector_.close();
-    // Closing the message pipe won't trigger connection error handler.
-    // Explicitly call onPipeConnectionError() so that associated endpoints
-    // will get notified.
-    this.onPipeConnectionError();
-  };
-
-  Router.prototype.waitForNextMessageForTesting = function() {
-    this.connector_.waitForNextMessageForTesting();
-  };
-
-  Router.prototype.onPeerAssociatedEndpointClosed = function(interfaceId,
-      reason) {
-    check(!types.isMasterInterfaceId(interfaceId) || reason);
-
-    var endpoint = this.endpoints_.get(interfaceId);
-    if (!endpoint) {
-      endpoint = new InterfaceEndpoint(this, interfaceId);
-      this.endpoints_.set(interfaceId, endpoint);
-    }
-
-    if (reason) {
-      endpoint.disconnectReason = reason;
-    }
-
-    if (!endpoint.peerClosed) {
-      if (endpoint.client) {
-        timer.createOneShot(0,
-            endpoint.client.notifyError.bind(endpoint.client, reason));
-      }
-      this.updateEndpointStateMayRemove(endpoint,
-          EndpointStateUpdateType.PEER_ENDPOINT_CLOSED);
-    }
-    return true;
-  };
-
-  Router.prototype.onPipeConnectionError = function() {
-    this.encounteredError_ = true;
-
-    for (var endpoint of this.endpoints_.values()) {
-      if (endpoint.client) {
-        timer.createOneShot(0,
-            endpoint.client.notifyError.bind(endpoint.client,
-              endpoint.disconnectReason));
-      }
-      this.updateEndpointStateMayRemove(endpoint,
-          EndpointStateUpdateType.PEER_ENDPOINT_CLOSED);
-    }
-  };
-
-  Router.prototype.closeEndpointHandle = function(interfaceId, reason) {
-    if (!types.isValidInterfaceId(interfaceId)) {
-      return;
-    }
-    var endpoint = this.endpoints_.get(interfaceId);
-    check(endpoint);
-    check(!endpoint.client);
-    check(!endpoint.closed);
-
-    this.updateEndpointStateMayRemove(endpoint,
-        EndpointStateUpdateType.ENDPOINT_CLOSED);
-
-    if (!types.isMasterInterfaceId(interfaceId) || reason) {
-      this.controlMessageProxy_.notifyPeerEndpointClosed(interfaceId, reason);
-    }
-
-    if (this.cachedMessageData && interfaceId ===
-        this.cachedMessageData.message.getInterfaceId()) {
-      this.cachedMessageData = null;
-      this.connector_.resumeIncomingMethodCallProcessing();
-    }
-  };
-
-  Router.prototype.updateEndpointStateMayRemove = function(endpoint,
-      endpointStateUpdateType) {
-    if (endpointStateUpdateType === EndpointStateUpdateType.ENDPOINT_CLOSED) {
-      endpoint.closed = true;
-    } else {
-      endpoint.peerClosed = true;
-    }
-    if (endpoint.closed && endpoint.peerClosed) {
-      this.endpoints_.delete(endpoint.id);
-    }
-  };
-
-  var exports = {};
-  exports.Router = Router;
-  return exports;
-});
diff --git a/mojo/public/js/support.js b/mojo/public/js/support.js
deleted file mode 100644
index 7e27504..0000000
--- a/mojo/public/js/support.js
+++ /dev/null
@@ -1,53 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-// Module "mojo/public/js/support"
-//
-// Note: This file is for documentation purposes only. The code here is not
-// actually executed. The real module is implemented natively in Mojo.
-
-while (1);
-
-/* @deprecated Please use watch()/cancelWatch() instead of
- *     asyncWait()/cancelWait().
- *
- * Waits on the given handle until the state indicated by |signals| is
- * satisfied.
- *
- * @param {MojoHandle} handle The handle to wait on.
- * @param {MojoHandleSignals} signals Specifies the condition to wait for.
- * @param {function (mojoResult)} callback Called with the result the wait is
- *     complete. See MojoWait for possible result codes.
- *
- * @return {MojoWaitId} A waitId that can be passed to cancelWait to cancel the
- *     wait.
- */
-function asyncWait(handle, signals, callback) { [native code] }
-
-/* @deprecated Please use watch()/cancelWatch() instead of
- *     asyncWait()/cancelWait().
- *
- * Cancels the asyncWait operation specified by the given |waitId|.
- *
- * @param {MojoWaitId} waitId The waitId returned by asyncWait.
- */
-function cancelWait(waitId) { [native code] }
-
-/* Begins watching a handle for |signals| to be satisfied or unsatisfiable.
- *
-  * @param {MojoHandle} handle The handle to watch.
-  * @param {MojoHandleSignals} signals The signals to watch.
-  * @param {function (mojoResult)} calback Called with a result any time
-  *     the watched signals become satisfied or unsatisfiable.
-  *
-  * @param {MojoWatchId} watchId An opaque identifier that identifies this
-  *     watch.
-  */
-function watch(handle, signals, callback) { [native code] }
-
-/* Cancels a handle watch initiated by watch().
- *
- * @param {MojoWatchId} watchId The watch identifier returned by watch().
- */
-function cancelWatch(watchId) { [native code] }
diff --git a/mojo/public/js/tests/core_unittest.js b/mojo/public/js/tests/core_unittest.js
deleted file mode 100644
index de473f24..0000000
--- a/mojo/public/js/tests/core_unittest.js
+++ /dev/null
@@ -1,224 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-define([
-    "gin/test/expect",
-    "mojo/public/js/core",
-    "gc",
-  ], function(expect, core, gc) {
-
-  var HANDLE_SIGNAL_READWRITABLE = core.HANDLE_SIGNAL_WRITABLE |
-                                   core.HANDLE_SIGNAL_READABLE;
-  var HANDLE_SIGNAL_ALL = core.HANDLE_SIGNAL_WRITABLE |
-                          core.HANDLE_SIGNAL_READABLE |
-                          core.HANDLE_SIGNAL_PEER_CLOSED |
-                          core.HANDLE_SIGNAL_PEER_REMOTE;
-
-  runWithMessagePipe(testNop);
-  runWithMessagePipe(testReadAndWriteMessage);
-  runWithMessagePipeWithOptions(testNop);
-  runWithMessagePipeWithOptions(testReadAndWriteMessage);
-  runWithDataPipe(testNop);
-  runWithDataPipe(testReadAndWriteDataPipe);
-  runWithDataPipeWithOptions(testNop);
-  runWithDataPipeWithOptions(testReadAndWriteDataPipe);
-  runWithMessagePipe(testIsHandleMessagePipe);
-  runWithDataPipe(testIsHandleDataPipe);
-  runWithSharedBuffer(testSharedBuffer);
-  gc.collectGarbage();  // should not crash
-  this.result = "PASS";
-
-  function runWithMessagePipe(test) {
-    var pipe = core.createMessagePipe();
-    expect(pipe.result).toBe(core.RESULT_OK);
-
-    test(pipe);
-
-    expect(core.close(pipe.handle0)).toBe(core.RESULT_OK);
-    expect(core.close(pipe.handle1)).toBe(core.RESULT_OK);
-  }
-
-  function runWithMessagePipeWithOptions(test) {
-    var pipe = core.createMessagePipe({
-        flags: core.CREATE_MESSAGE_PIPE_OPTIONS_FLAG_NONE
-    });
-    expect(pipe.result).toBe(core.RESULT_OK);
-
-    test(pipe);
-
-    expect(core.close(pipe.handle0)).toBe(core.RESULT_OK);
-    expect(core.close(pipe.handle1)).toBe(core.RESULT_OK);
-  }
-
-  function runWithDataPipe(test) {
-    var pipe = core.createDataPipe();
-    expect(pipe.result).toBe(core.RESULT_OK);
-
-    test(pipe);
-
-    expect(core.close(pipe.producerHandle)).toBe(core.RESULT_OK);
-    expect(core.close(pipe.consumerHandle)).toBe(core.RESULT_OK);
-  }
-
-  function runWithDataPipeWithOptions(test) {
-    var pipe = core.createDataPipe({
-        flags: core.CREATE_DATA_PIPE_OPTIONS_FLAG_NONE,
-        elementNumBytes: 1,
-        capacityNumBytes: 64
-        });
-    expect(pipe.result).toBe(core.RESULT_OK);
-
-    test(pipe);
-
-    expect(core.close(pipe.producerHandle)).toBe(core.RESULT_OK);
-    expect(core.close(pipe.consumerHandle)).toBe(core.RESULT_OK);
-  }
-
-  function runWithSharedBuffer(test) {
-    let buffer_size = 32;
-    let sharedBuffer = core.createSharedBuffer(buffer_size,
-        core.CREATE_SHARED_BUFFER_OPTIONS_FLAG_NONE);
-
-    expect(sharedBuffer.result).toBe(core.RESULT_OK);
-    expect(core.isHandle(sharedBuffer.handle)).toBeTruthy();
-
-    test(sharedBuffer, buffer_size);
-  }
-
-  function testNop(pipe) {
-  }
-
-  function testReadAndWriteMessage(pipe) {
-    var state0 = core.queryHandleSignalsState(pipe.handle0);
-    expect(state0.result).toBe(core.RESULT_OK);
-    expect(state0.satisfiedSignals).toBe(core.HANDLE_SIGNAL_WRITABLE);
-    expect(state0.satisfiableSignals).toBe(HANDLE_SIGNAL_ALL);
-
-    var state1 = core.queryHandleSignalsState(pipe.handle1);
-    expect(state1.result).toBe(core.RESULT_OK);
-    expect(state1.satisfiedSignals).toBe(core.HANDLE_SIGNAL_WRITABLE);
-    expect(state1.satisfiableSignals).toBe(HANDLE_SIGNAL_ALL);
-
-    var senderData = new Uint8Array(42);
-    for (var i = 0; i < senderData.length; ++i) {
-      senderData[i] = i * i;
-    }
-
-    var result = core.writeMessage(
-      pipe.handle0, senderData, [],
-      core.WRITE_MESSAGE_FLAG_NONE);
-
-    expect(result).toBe(core.RESULT_OK);
-
-    state0 = core.queryHandleSignalsState(pipe.handle0);
-    expect(state0.result).toBe(core.RESULT_OK);
-    expect(state0.satisfiedSignals).toBe(core.HANDLE_SIGNAL_WRITABLE);
-    expect(state0.satisfiableSignals).toBe(HANDLE_SIGNAL_ALL);
-
-    var wait = core.wait(pipe.handle1, core.HANDLE_SIGNAL_READABLE);
-    expect(wait.result).toBe(core.RESULT_OK);
-    expect(wait.signalsState.satisfiedSignals).toBe(HANDLE_SIGNAL_READWRITABLE);
-    expect(wait.signalsState.satisfiableSignals).toBe(HANDLE_SIGNAL_ALL);
-
-    var read = core.readMessage(pipe.handle1, core.READ_MESSAGE_FLAG_NONE);
-
-    expect(read.result).toBe(core.RESULT_OK);
-    expect(read.buffer.byteLength).toBe(42);
-    expect(read.handles.length).toBe(0);
-
-    var memory = new Uint8Array(read.buffer);
-    for (var i = 0; i < memory.length; ++i)
-      expect(memory[i]).toBe((i * i) & 0xFF);
-  }
-
-  function testReadAndWriteDataPipe(pipe) {
-    var senderData = new Uint8Array(42);
-    for (var i = 0; i < senderData.length; ++i) {
-      senderData[i] = i * i;
-    }
-
-    var write = core.writeData(
-      pipe.producerHandle, senderData,
-      core.WRITE_DATA_FLAG_ALL_OR_NONE);
-
-    expect(write.result).toBe(core.RESULT_OK);
-    expect(write.numBytes).toBe(42);
-
-    var wait = core.wait(pipe.consumerHandle, core.HANDLE_SIGNAL_READABLE);
-    expect(wait.result).toBe(core.RESULT_OK);
-    var peeked = core.readData(
-         pipe.consumerHandle,
-         core.READ_DATA_FLAG_PEEK | core.READ_DATA_FLAG_ALL_OR_NONE);
-    expect(peeked.result).toBe(core.RESULT_OK);
-    expect(peeked.buffer.byteLength).toBe(42);
-
-    var peeked_memory = new Uint8Array(peeked.buffer);
-    for (var i = 0; i < peeked_memory.length; ++i)
-      expect(peeked_memory[i]).toBe((i * i) & 0xFF);
-
-    var read = core.readData(
-      pipe.consumerHandle, core.READ_DATA_FLAG_ALL_OR_NONE);
-
-    expect(read.result).toBe(core.RESULT_OK);
-    expect(read.buffer.byteLength).toBe(42);
-
-    var memory = new Uint8Array(read.buffer);
-    for (var i = 0; i < memory.length; ++i)
-      expect(memory[i]).toBe((i * i) & 0xFF);
-  }
-
-  function testIsHandleMessagePipe(pipe) {
-    expect(core.isHandle(123).toBeFalsy);
-    expect(core.isHandle("123").toBeFalsy);
-    expect(core.isHandle({}).toBeFalsy);
-    expect(core.isHandle([]).toBeFalsy);
-    expect(core.isHandle(undefined).toBeFalsy);
-    expect(core.isHandle(pipe).toBeFalsy);
-    expect(core.isHandle(pipe.handle0)).toBeTruthy();
-    expect(core.isHandle(pipe.handle1)).toBeTruthy();
-    expect(core.isHandle(null)).toBeTruthy();
-  }
-
-  function testIsHandleDataPipe(pipe) {
-    expect(core.isHandle(pipe.consumerHandle)).toBeTruthy();
-    expect(core.isHandle(pipe.producerHandle)).toBeTruthy();
-  }
-
-  function testSharedBuffer(sharedBuffer, buffer_size) {
-    let offset = 0;
-    let mappedBuffer0 = core.mapBuffer(sharedBuffer.handle,
-                                       offset,
-                                       buffer_size,
-                                       core.MAP_BUFFER_FLAG_NONE);
-
-    expect(mappedBuffer0.result).toBe(core.RESULT_OK);
-
-    let dupedBufferHandle = core.duplicateBufferHandle(sharedBuffer.handle,
-        core.DUPLICATE_BUFFER_HANDLE_OPTIONS_FLAG_NONE);
-
-    expect(dupedBufferHandle.result).toBe(core.RESULT_OK);
-    expect(core.isHandle(dupedBufferHandle.handle)).toBeTruthy();
-
-    let mappedBuffer1 = core.mapBuffer(dupedBufferHandle.handle,
-                                       offset,
-                                       buffer_size,
-                                       core.MAP_BUFFER_FLAG_NONE);
-
-    expect(mappedBuffer1.result).toBe(core.RESULT_OK);
-
-    let buffer0 = new Uint8Array(mappedBuffer0.buffer);
-    let buffer1 = new Uint8Array(mappedBuffer1.buffer);
-    for(let i = 0; i < buffer0.length; ++i) {
-      buffer0[i] = i;
-      expect(buffer1[i]).toBe(i);
-    }
-
-    expect(core.unmapBuffer(mappedBuffer0.buffer)).toBe(core.RESULT_OK);
-    expect(core.unmapBuffer(mappedBuffer1.buffer)).toBe(core.RESULT_OK);
-
-    expect(core.close(dupedBufferHandle.handle)).toBe(core.RESULT_OK);
-    expect(core.close(sharedBuffer.handle)).toBe(core.RESULT_OK);
-  }
-
-});
diff --git a/mojo/public/js/threading.js b/mojo/public/js/threading.js
deleted file mode 100644
index 49ab5c9..0000000
--- a/mojo/public/js/threading.js
+++ /dev/null
@@ -1,21 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-// Module "mojo/public/js/threading"
-//
-// Note: This file is for documentation purposes only. The code here is not
-// actually executed. The real module is implemented natively in Mojo.
-//
-// This module provides a way for a Service implemented in JS
-// to exit by quitting the current message loop. This module is not
-// intended to be used by Mojo JS application started by the JS
-// content handler.
-
-while (1);
-
-/**
- * Quits the current message loop, esssentially:
- * base::MessageLoop::current()->QuitNow();
-*/
-function quit() { [native code] }
diff --git a/mojo/public/js/unicode.js b/mojo/public/js/unicode.js
deleted file mode 100644
index be2ba0e..0000000
--- a/mojo/public/js/unicode.js
+++ /dev/null
@@ -1,51 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-/**
- * Defines functions for translating between JavaScript strings and UTF8 strings
- * stored in ArrayBuffers. There is much room for optimization in this code if
- * it proves necessary.
- */
-define("mojo/public/js/unicode", function() {
-  /**
-   * Decodes the UTF8 string from the given buffer.
-   * @param {ArrayBufferView} buffer The buffer containing UTF8 string data.
-   * @return {string} The corresponding JavaScript string.
-   */
-  function decodeUtf8String(buffer) {
-    return decodeURIComponent(escape(String.fromCharCode.apply(null, buffer)));
-  }
-
-  /**
-   * Encodes the given JavaScript string into UTF8.
-   * @param {string} str The string to encode.
-   * @param {ArrayBufferView} outputBuffer The buffer to contain the result.
-   * Should be pre-allocated to hold enough space. Use |utf8Length| to determine
-   * how much space is required.
-   * @return {number} The number of bytes written to |outputBuffer|.
-   */
-  function encodeUtf8String(str, outputBuffer) {
-    var utf8String = unescape(encodeURIComponent(str));
-    if (outputBuffer.length < utf8String.length)
-      throw new Error("Buffer too small for encodeUtf8String");
-    for (var i = 0; i < outputBuffer.length && i < utf8String.length; i++)
-      outputBuffer[i] = utf8String.charCodeAt(i);
-    return i;
-  }
-
-  /**
-   * Returns the number of bytes that a UTF8 encoding of the JavaScript string
-   * |str| would occupy.
-   */
-  function utf8Length(str) {
-    var utf8String = unescape(encodeURIComponent(str));
-    return utf8String.length;
-  }
-
-  var exports = {};
-  exports.decodeUtf8String = decodeUtf8String;
-  exports.encodeUtf8String = encodeUtf8String;
-  exports.utf8Length = utf8Length;
-  return exports;
-});
diff --git a/mojo/public/js/validator.js b/mojo/public/js/validator.js
deleted file mode 100644
index 4abc359..0000000
--- a/mojo/public/js/validator.js
+++ /dev/null
@@ -1,686 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-define("mojo/public/js/validator", [
-  "mojo/public/js/codec",
-  "mojo/public/js/interface_types",
-], function(codec, types) {
-
-  var validationError = {
-    NONE: 'VALIDATION_ERROR_NONE',
-    MISALIGNED_OBJECT: 'VALIDATION_ERROR_MISALIGNED_OBJECT',
-    ILLEGAL_MEMORY_RANGE: 'VALIDATION_ERROR_ILLEGAL_MEMORY_RANGE',
-    UNEXPECTED_STRUCT_HEADER: 'VALIDATION_ERROR_UNEXPECTED_STRUCT_HEADER',
-    UNEXPECTED_ARRAY_HEADER: 'VALIDATION_ERROR_UNEXPECTED_ARRAY_HEADER',
-    ILLEGAL_HANDLE: 'VALIDATION_ERROR_ILLEGAL_HANDLE',
-    UNEXPECTED_INVALID_HANDLE: 'VALIDATION_ERROR_UNEXPECTED_INVALID_HANDLE',
-    ILLEGAL_POINTER: 'VALIDATION_ERROR_ILLEGAL_POINTER',
-    UNEXPECTED_NULL_POINTER: 'VALIDATION_ERROR_UNEXPECTED_NULL_POINTER',
-    ILLEGAL_INTERFACE_ID: 'VALIDATION_ERROR_ILLEGAL_INTERFACE_ID',
-    UNEXPECTED_INVALID_INTERFACE_ID:
-        'VALIDATION_ERROR_UNEXPECTED_INVALID_INTERFACE_ID',
-    MESSAGE_HEADER_INVALID_FLAGS:
-        'VALIDATION_ERROR_MESSAGE_HEADER_INVALID_FLAGS',
-    MESSAGE_HEADER_MISSING_REQUEST_ID:
-        'VALIDATION_ERROR_MESSAGE_HEADER_MISSING_REQUEST_ID',
-    DIFFERENT_SIZED_ARRAYS_IN_MAP:
-        'VALIDATION_ERROR_DIFFERENT_SIZED_ARRAYS_IN_MAP',
-    INVALID_UNION_SIZE: 'VALIDATION_ERROR_INVALID_UNION_SIZE',
-    UNEXPECTED_NULL_UNION: 'VALIDATION_ERROR_UNEXPECTED_NULL_UNION',
-    UNKNOWN_ENUM_VALUE: 'VALIDATION_ERROR_UNKNOWN_ENUM_VALUE',
-  };
-
-  var NULL_MOJO_POINTER = "NULL_MOJO_POINTER";
-  var gValidationErrorObserver = null;
-
-  function reportValidationError(error) {
-    if (gValidationErrorObserver) {
-      gValidationErrorObserver.setLastError(error);
-    }
-  }
-
-  var ValidationErrorObserverForTesting = (function() {
-    function Observer() {
-      this.lastError = validationError.NONE;
-      this.callback = null;
-    }
-
-    Observer.prototype.setLastError = function(error) {
-      this.lastError = error;
-      if (this.callback) {
-        this.callback(error);
-      }
-    };
-
-    Observer.prototype.reset = function(error) {
-      this.lastError = validationError.NONE;
-      this.callback = null;
-    };
-
-    return {
-      getInstance: function() {
-        if (!gValidationErrorObserver) {
-          gValidationErrorObserver = new Observer();
-        }
-        return gValidationErrorObserver;
-      }
-    };
-  })();
-
-  function isTestingMode() {
-    return Boolean(gValidationErrorObserver);
-  }
-
-  function clearTestingMode() {
-    gValidationErrorObserver = null;
-  }
-
-  function isEnumClass(cls) {
-    return cls instanceof codec.Enum;
-  }
-
-  function isStringClass(cls) {
-    return cls === codec.String || cls === codec.NullableString;
-  }
-
-  function isHandleClass(cls) {
-    return cls === codec.Handle || cls === codec.NullableHandle;
-  }
-
-  function isInterfaceClass(cls) {
-    return cls instanceof codec.Interface;
-  }
-
-  function isInterfaceRequestClass(cls) {
-    return cls === codec.InterfaceRequest ||
-        cls === codec.NullableInterfaceRequest;
-  }
-
-  function isAssociatedInterfaceClass(cls) {
-    return cls === codec.AssociatedInterfacePtrInfo ||
-        cls === codec.NullableAssociatedInterfacePtrInfo;
-  }
-
-  function isAssociatedInterfaceRequestClass(cls) {
-    return cls === codec.AssociatedInterfaceRequest ||
-        cls === codec.NullableAssociatedInterfaceRequest;
-  }
-
-  function isNullable(type) {
-    return type === codec.NullableString || type === codec.NullableHandle ||
-        type === codec.NullableAssociatedInterfacePtrInfo ||
-        type === codec.NullableAssociatedInterfaceRequest ||
-        type === codec.NullableInterface ||
-        type === codec.NullableInterfaceRequest ||
-        type instanceof codec.NullableArrayOf ||
-        type instanceof codec.NullablePointerTo;
-  }
-
-  function Validator(message) {
-    this.message = message;
-    this.offset = 0;
-    this.handleIndex = 0;
-    this.associatedEndpointHandleIndex = 0;
-    this.payloadInterfaceIds = null;
-    this.offsetLimit = this.message.buffer.byteLength;
-  }
-
-  Object.defineProperty(Validator.prototype, "handleIndexLimit", {
-    get: function() { return this.message.handles.length; }
-  });
-
-  Object.defineProperty(Validator.prototype, "associatedHandleIndexLimit", {
-    get: function() {
-      return this.payloadInterfaceIds ? this.payloadInterfaceIds.length : 0;
-    }
-  });
-
-  // True if we can safely allocate a block of bytes from start to
-  // to start + numBytes.
-  Validator.prototype.isValidRange = function(start, numBytes) {
-    // Only positive JavaScript integers that are less than 2^53
-    // (Number.MAX_SAFE_INTEGER) can be represented exactly.
-    if (start < this.offset || numBytes <= 0 ||
-        !Number.isSafeInteger(start) ||
-        !Number.isSafeInteger(numBytes))
-      return false;
-
-    var newOffset = start + numBytes;
-    if (!Number.isSafeInteger(newOffset) || newOffset > this.offsetLimit)
-      return false;
-
-    return true;
-  };
-
-  Validator.prototype.claimRange = function(start, numBytes) {
-    if (this.isValidRange(start, numBytes)) {
-      this.offset = start + numBytes;
-      return true;
-    }
-    return false;
-  };
-
-  Validator.prototype.claimHandle = function(index) {
-    if (index === codec.kEncodedInvalidHandleValue)
-      return true;
-
-    if (index < this.handleIndex || index >= this.handleIndexLimit)
-      return false;
-
-    // This is safe because handle indices are uint32.
-    this.handleIndex = index + 1;
-    return true;
-  };
-
-  Validator.prototype.claimAssociatedEndpointHandle = function(index) {
-    if (index === codec.kEncodedInvalidHandleValue) {
-      return true;
-    }
-
-    if (index < this.associatedEndpointHandleIndex ||
-        index >= this.associatedHandleIndexLimit) {
-      return false;
-    }
-
-    // This is safe because handle indices are uint32.
-    this.associatedEndpointHandleIndex = index + 1;
-    return true;
-  };
-
-  Validator.prototype.validateEnum = function(offset, enumClass) {
-    // Note: Assumes that enums are always 32 bits! But this matches
-    // mojom::generate::pack::PackedField::GetSizeForKind, so it should be okay.
-    var value = this.message.buffer.getInt32(offset);
-    return enumClass.validate(value);
-  }
-
-  Validator.prototype.validateHandle = function(offset, nullable) {
-    var index = this.message.buffer.getUint32(offset);
-
-    if (index === codec.kEncodedInvalidHandleValue)
-      return nullable ?
-          validationError.NONE : validationError.UNEXPECTED_INVALID_HANDLE;
-
-    if (!this.claimHandle(index))
-      return validationError.ILLEGAL_HANDLE;
-
-    return validationError.NONE;
-  };
-
-  Validator.prototype.validateAssociatedEndpointHandle = function(offset,
-      nullable) {
-    var index = this.message.buffer.getUint32(offset);
-
-    if (index === codec.kEncodedInvalidHandleValue) {
-      return nullable ? validationError.NONE :
-          validationError.UNEXPECTED_INVALID_INTERFACE_ID;
-    }
-
-    if (!this.claimAssociatedEndpointHandle(index)) {
-      return validationError.ILLEGAL_INTERFACE_ID;
-    }
-
-    return validationError.NONE;
-  };
-
-  Validator.prototype.validateInterface = function(offset, nullable) {
-    return this.validateHandle(offset, nullable);
-  };
-
-  Validator.prototype.validateInterfaceRequest = function(offset, nullable) {
-    return this.validateHandle(offset, nullable);
-  };
-
-  Validator.prototype.validateAssociatedInterface = function(offset,
-      nullable) {
-    return this.validateAssociatedEndpointHandle(offset, nullable);
-  };
-
-  Validator.prototype.validateAssociatedInterfaceRequest = function(
-      offset, nullable) {
-    return this.validateAssociatedEndpointHandle(offset, nullable);
-  };
-
-  Validator.prototype.validateStructHeader = function(offset, minNumBytes) {
-    if (!codec.isAligned(offset))
-      return validationError.MISALIGNED_OBJECT;
-
-    if (!this.isValidRange(offset, codec.kStructHeaderSize))
-      return validationError.ILLEGAL_MEMORY_RANGE;
-
-    var numBytes = this.message.buffer.getUint32(offset);
-
-    if (numBytes < minNumBytes)
-      return validationError.UNEXPECTED_STRUCT_HEADER;
-
-    if (!this.claimRange(offset, numBytes))
-      return validationError.ILLEGAL_MEMORY_RANGE;
-
-    return validationError.NONE;
-  };
-
-  Validator.prototype.validateStructVersion = function(offset, versionSizes) {
-    var numBytes = this.message.buffer.getUint32(offset);
-    var version = this.message.buffer.getUint32(offset + 4);
-
-    if (version <= versionSizes[versionSizes.length - 1].version) {
-      // Scan in reverse order to optimize for more recent versionSizes.
-      for (var i = versionSizes.length - 1; i >= 0; --i) {
-        if (version >= versionSizes[i].version) {
-          if (numBytes == versionSizes[i].numBytes)
-            break;
-          return validationError.UNEXPECTED_STRUCT_HEADER;
-        }
-      }
-    } else if (numBytes < versionSizes[versionSizes.length-1].numBytes) {
-      return validationError.UNEXPECTED_STRUCT_HEADER;
-    }
-
-    return validationError.NONE;
-  };
-
-  Validator.prototype.isFieldInStructVersion = function(offset, fieldVersion) {
-    var structVersion = this.message.buffer.getUint32(offset + 4);
-    return fieldVersion <= structVersion;
-  };
-
-  Validator.prototype.validateMessageHeader = function() {
-    var err = this.validateStructHeader(0, codec.kMessageV0HeaderSize);
-    if (err != validationError.NONE) {
-      return err;
-    }
-
-    var numBytes = this.message.getHeaderNumBytes();
-    var version = this.message.getHeaderVersion();
-
-    var validVersionAndNumBytes =
-        (version == 0 && numBytes == codec.kMessageV0HeaderSize) ||
-        (version == 1 && numBytes == codec.kMessageV1HeaderSize) ||
-        (version == 2 && numBytes == codec.kMessageV2HeaderSize) ||
-        (version > 2 && numBytes >= codec.kMessageV2HeaderSize);
-
-    if (!validVersionAndNumBytes) {
-      return validationError.UNEXPECTED_STRUCT_HEADER;
-    }
-
-    var expectsResponse = this.message.expectsResponse();
-    var isResponse = this.message.isResponse();
-
-    if (version == 0 && (expectsResponse || isResponse)) {
-      return validationError.MESSAGE_HEADER_MISSING_REQUEST_ID;
-    }
-
-    if (isResponse && expectsResponse) {
-      return validationError.MESSAGE_HEADER_INVALID_FLAGS;
-    }
-
-    if (version < 2) {
-      return validationError.NONE;
-    }
-
-    var err = this.validateArrayPointer(
-        codec.kMessagePayloadInterfaceIdsPointerOffset,
-        codec.Uint32.encodedSize, codec.Uint32, true, [0], 0);
-
-    if (err != validationError.NONE) {
-      return err;
-    }
-
-    this.payloadInterfaceIds = this.message.getPayloadInterfaceIds();
-    if (this.payloadInterfaceIds) {
-      for (var interfaceId of this.payloadInterfaceIds) {
-        if (!types.isValidInterfaceId(interfaceId) ||
-            types.isMasterInterfaceId(interfaceId)) {
-          return validationError.ILLEGAL_INTERFACE_ID;
-        }
-      }
-    }
-
-    // Set offset to the start of the payload and offsetLimit to the start of
-    // the payload interface Ids so that payload can be validated using the
-    // same messageValidator.
-    this.offset = this.message.getHeaderNumBytes();
-    this.offsetLimit = this.decodePointer(
-        codec.kMessagePayloadInterfaceIdsPointerOffset);
-
-    return validationError.NONE;
-  };
-
-  Validator.prototype.validateMessageIsRequestWithoutResponse = function() {
-    if (this.message.isResponse() || this.message.expectsResponse()) {
-      return validationError.MESSAGE_HEADER_INVALID_FLAGS;
-    }
-    return validationError.NONE;
-  };
-
-  Validator.prototype.validateMessageIsRequestExpectingResponse = function() {
-    if (this.message.isResponse() || !this.message.expectsResponse()) {
-      return validationError.MESSAGE_HEADER_INVALID_FLAGS;
-    }
-    return validationError.NONE;
-  };
-
-  Validator.prototype.validateMessageIsResponse = function() {
-    if (this.message.expectsResponse() || !this.message.isResponse()) {
-      return validationError.MESSAGE_HEADER_INVALID_FLAGS;
-    }
-    return validationError.NONE;
-  };
-
-  // Returns the message.buffer relative offset this pointer "points to",
-  // NULL_MOJO_POINTER if the pointer represents a null, or JS null if the
-  // pointer's value is not valid.
-  Validator.prototype.decodePointer = function(offset) {
-    var pointerValue = this.message.buffer.getUint64(offset);
-    if (pointerValue === 0)
-      return NULL_MOJO_POINTER;
-    var bufferOffset = offset + pointerValue;
-    return Number.isSafeInteger(bufferOffset) ? bufferOffset : null;
-  };
-
-  Validator.prototype.decodeUnionSize = function(offset) {
-    return this.message.buffer.getUint32(offset);
-  };
-
-  Validator.prototype.decodeUnionTag = function(offset) {
-    return this.message.buffer.getUint32(offset + 4);
-  };
-
-  Validator.prototype.validateArrayPointer = function(
-      offset, elementSize, elementType, nullable, expectedDimensionSizes,
-      currentDimension) {
-    var arrayOffset = this.decodePointer(offset);
-    if (arrayOffset === null)
-      return validationError.ILLEGAL_POINTER;
-
-    if (arrayOffset === NULL_MOJO_POINTER)
-      return nullable ?
-          validationError.NONE : validationError.UNEXPECTED_NULL_POINTER;
-
-    return this.validateArray(arrayOffset, elementSize, elementType,
-                              expectedDimensionSizes, currentDimension);
-  };
-
-  Validator.prototype.validateStructPointer = function(
-      offset, structClass, nullable) {
-    var structOffset = this.decodePointer(offset);
-    if (structOffset === null)
-      return validationError.ILLEGAL_POINTER;
-
-    if (structOffset === NULL_MOJO_POINTER)
-      return nullable ?
-          validationError.NONE : validationError.UNEXPECTED_NULL_POINTER;
-
-    return structClass.validate(this, structOffset);
-  };
-
-  Validator.prototype.validateUnion = function(
-      offset, unionClass, nullable) {
-    var size = this.message.buffer.getUint32(offset);
-    if (size == 0) {
-      return nullable ?
-          validationError.NONE : validationError.UNEXPECTED_NULL_UNION;
-    }
-
-    return unionClass.validate(this, offset);
-  };
-
-  Validator.prototype.validateNestedUnion = function(
-      offset, unionClass, nullable) {
-    var unionOffset = this.decodePointer(offset);
-    if (unionOffset === null)
-      return validationError.ILLEGAL_POINTER;
-
-    if (unionOffset === NULL_MOJO_POINTER)
-      return nullable ?
-          validationError.NONE : validationError.UNEXPECTED_NULL_UNION;
-
-    return this.validateUnion(unionOffset, unionClass, nullable);
-  };
-
-  // This method assumes that the array at arrayPointerOffset has
-  // been validated.
-
-  Validator.prototype.arrayLength = function(arrayPointerOffset) {
-    var arrayOffset = this.decodePointer(arrayPointerOffset);
-    return this.message.buffer.getUint32(arrayOffset + 4);
-  };
-
-  Validator.prototype.validateMapPointer = function(
-      offset, mapIsNullable, keyClass, valueClass, valueIsNullable) {
-    // Validate the implicit map struct:
-    // struct {array<keyClass> keys; array<valueClass> values};
-    var structOffset = this.decodePointer(offset);
-    if (structOffset === null)
-      return validationError.ILLEGAL_POINTER;
-
-    if (structOffset === NULL_MOJO_POINTER)
-      return mapIsNullable ?
-          validationError.NONE : validationError.UNEXPECTED_NULL_POINTER;
-
-    var mapEncodedSize = codec.kStructHeaderSize + codec.kMapStructPayloadSize;
-    var err = this.validateStructHeader(structOffset, mapEncodedSize);
-    if (err !== validationError.NONE)
-        return err;
-
-    // Validate the keys array.
-    var keysArrayPointerOffset = structOffset + codec.kStructHeaderSize;
-    err = this.validateArrayPointer(
-        keysArrayPointerOffset, keyClass.encodedSize, keyClass, false, [0], 0);
-    if (err !== validationError.NONE)
-        return err;
-
-    // Validate the values array.
-    var valuesArrayPointerOffset = keysArrayPointerOffset + 8;
-    var valuesArrayDimensions = [0]; // Validate the actual length below.
-    if (valueClass instanceof codec.ArrayOf)
-      valuesArrayDimensions =
-          valuesArrayDimensions.concat(valueClass.dimensions());
-    var err = this.validateArrayPointer(valuesArrayPointerOffset,
-                                        valueClass.encodedSize,
-                                        valueClass,
-                                        valueIsNullable,
-                                        valuesArrayDimensions,
-                                        0);
-    if (err !== validationError.NONE)
-        return err;
-
-    // Validate the lengths of the keys and values arrays.
-    var keysArrayLength = this.arrayLength(keysArrayPointerOffset);
-    var valuesArrayLength = this.arrayLength(valuesArrayPointerOffset);
-    if (keysArrayLength != valuesArrayLength)
-      return validationError.DIFFERENT_SIZED_ARRAYS_IN_MAP;
-
-    return validationError.NONE;
-  };
-
-  Validator.prototype.validateStringPointer = function(offset, nullable) {
-    return this.validateArrayPointer(
-        offset, codec.Uint8.encodedSize, codec.Uint8, nullable, [0], 0);
-  };
-
-  // Similar to Array_Data<T>::Validate()
-  // mojo/public/cpp/bindings/lib/array_internal.h
-
-  Validator.prototype.validateArray =
-      function (offset, elementSize, elementType, expectedDimensionSizes,
-                currentDimension) {
-    if (!codec.isAligned(offset))
-      return validationError.MISALIGNED_OBJECT;
-
-    if (!this.isValidRange(offset, codec.kArrayHeaderSize))
-      return validationError.ILLEGAL_MEMORY_RANGE;
-
-    var numBytes = this.message.buffer.getUint32(offset);
-    var numElements = this.message.buffer.getUint32(offset + 4);
-
-    // Note: this computation is "safe" because elementSize <= 8 and
-    // numElements is a uint32.
-    var elementsTotalSize = (elementType === codec.PackedBool) ?
-        Math.ceil(numElements / 8) : (elementSize * numElements);
-
-    if (numBytes < codec.kArrayHeaderSize + elementsTotalSize)
-      return validationError.UNEXPECTED_ARRAY_HEADER;
-
-    if (expectedDimensionSizes[currentDimension] != 0 &&
-        numElements != expectedDimensionSizes[currentDimension]) {
-      return validationError.UNEXPECTED_ARRAY_HEADER;
-    }
-
-    if (!this.claimRange(offset, numBytes))
-      return validationError.ILLEGAL_MEMORY_RANGE;
-
-    // Validate the array's elements if they are pointers or handles.
-
-    var elementsOffset = offset + codec.kArrayHeaderSize;
-    var nullable = isNullable(elementType);
-
-    if (isHandleClass(elementType))
-      return this.validateHandleElements(elementsOffset, numElements, nullable);
-    if (isInterfaceClass(elementType))
-      return this.validateInterfaceElements(
-          elementsOffset, numElements, nullable);
-    if (isInterfaceRequestClass(elementType))
-      return this.validateInterfaceRequestElements(
-          elementsOffset, numElements, nullable);
-    if (isAssociatedInterfaceClass(elementType))
-      return this.validateAssociatedInterfaceElements(
-          elementsOffset, numElements, nullable);
-    if (isAssociatedInterfaceRequestClass(elementType))
-      return this.validateAssociatedInterfaceRequestElements(
-          elementsOffset, numElements, nullable);
-    if (isStringClass(elementType))
-      return this.validateArrayElements(
-          elementsOffset, numElements, codec.Uint8, nullable, [0], 0);
-    if (elementType instanceof codec.PointerTo)
-      return this.validateStructElements(
-          elementsOffset, numElements, elementType.cls, nullable);
-    if (elementType instanceof codec.ArrayOf)
-      return this.validateArrayElements(
-          elementsOffset, numElements, elementType.cls, nullable,
-          expectedDimensionSizes, currentDimension + 1);
-    if (isEnumClass(elementType))
-      return this.validateEnumElements(elementsOffset, numElements,
-                                       elementType.cls);
-
-    return validationError.NONE;
-  };
-
-  // Note: the |offset + i * elementSize| computation in the validateFooElements
-  // methods below is "safe" because elementSize <= 8, offset and
-  // numElements are uint32, and 0 <= i < numElements.
-
-  Validator.prototype.validateHandleElements =
-      function(offset, numElements, nullable) {
-    var elementSize = codec.Handle.encodedSize;
-    for (var i = 0; i < numElements; i++) {
-      var elementOffset = offset + i * elementSize;
-      var err = this.validateHandle(elementOffset, nullable);
-      if (err != validationError.NONE)
-        return err;
-    }
-    return validationError.NONE;
-  };
-
-  Validator.prototype.validateInterfaceElements =
-      function(offset, numElements, nullable) {
-    var elementSize = codec.Interface.prototype.encodedSize;
-    for (var i = 0; i < numElements; i++) {
-      var elementOffset = offset + i * elementSize;
-      var err = this.validateInterface(elementOffset, nullable);
-      if (err != validationError.NONE)
-        return err;
-    }
-    return validationError.NONE;
-  };
-
-  Validator.prototype.validateInterfaceRequestElements =
-      function(offset, numElements, nullable) {
-    var elementSize = codec.InterfaceRequest.encodedSize;
-    for (var i = 0; i < numElements; i++) {
-      var elementOffset = offset + i * elementSize;
-      var err = this.validateInterfaceRequest(elementOffset, nullable);
-      if (err != validationError.NONE)
-        return err;
-    }
-    return validationError.NONE;
-  };
-
-  Validator.prototype.validateAssociatedInterfaceElements =
-      function(offset, numElements, nullable) {
-    var elementSize = codec.AssociatedInterfacePtrInfo.prototype.encodedSize;
-    for (var i = 0; i < numElements; i++) {
-      var elementOffset = offset + i * elementSize;
-      var err = this.validateAssociatedInterface(elementOffset, nullable);
-      if (err != validationError.NONE) {
-        return err;
-      }
-    }
-    return validationError.NONE;
-  };
-
-  Validator.prototype.validateAssociatedInterfaceRequestElements =
-      function(offset, numElements, nullable) {
-    var elementSize = codec.AssociatedInterfaceRequest.encodedSize;
-    for (var i = 0; i < numElements; i++) {
-      var elementOffset = offset + i * elementSize;
-      var err = this.validateAssociatedInterfaceRequest(elementOffset,
-          nullable);
-      if (err != validationError.NONE) {
-        return err;
-      }
-    }
-    return validationError.NONE;
-  };
-
-  // The elementClass parameter is the element type of the element arrays.
-  Validator.prototype.validateArrayElements =
-      function(offset, numElements, elementClass, nullable,
-               expectedDimensionSizes, currentDimension) {
-    var elementSize = codec.PointerTo.prototype.encodedSize;
-    for (var i = 0; i < numElements; i++) {
-      var elementOffset = offset + i * elementSize;
-      var err = this.validateArrayPointer(
-          elementOffset, elementClass.encodedSize, elementClass, nullable,
-          expectedDimensionSizes, currentDimension);
-      if (err != validationError.NONE)
-        return err;
-    }
-    return validationError.NONE;
-  };
-
-  Validator.prototype.validateStructElements =
-      function(offset, numElements, structClass, nullable) {
-    var elementSize = codec.PointerTo.prototype.encodedSize;
-    for (var i = 0; i < numElements; i++) {
-      var elementOffset = offset + i * elementSize;
-      var err =
-          this.validateStructPointer(elementOffset, structClass, nullable);
-      if (err != validationError.NONE)
-        return err;
-    }
-    return validationError.NONE;
-  };
-
-  Validator.prototype.validateEnumElements =
-      function(offset, numElements, enumClass) {
-    var elementSize = codec.Enum.prototype.encodedSize;
-    for (var i = 0; i < numElements; i++) {
-      var elementOffset = offset + i * elementSize;
-      var err = this.validateEnum(elementOffset, enumClass);
-      if (err != validationError.NONE)
-        return err;
-    }
-    return validationError.NONE;
-  };
-
-  var exports = {};
-  exports.validationError = validationError;
-  exports.Validator = Validator;
-  exports.ValidationErrorObserverForTesting = ValidationErrorObserverForTesting;
-  exports.reportValidationError = reportValidationError;
-  exports.isTestingMode = isTestingMode;
-  exports.clearTestingMode = clearTestingMode;
-  return exports;
-});
diff --git a/mojo/public/tools/bindings/generators/js_templates/module.amd.tmpl b/mojo/public/tools/bindings/generators/js_templates/module.amd.tmpl
index d280176..02a0488 100644
--- a/mojo/public/tools/bindings/generators/js_templates/module.amd.tmpl
+++ b/mojo/public/tools/bindings/generators/js_templates/module.amd.tmpl
@@ -2,15 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-{%- if js_bindings_mode == "both" or js_bindings_mode == "new" %}
-{{"new"|set_current_mode}}
-
 'use strict';
 
-{%-   if js_bindings_mode == "both" %}
-if ((typeof mojo !== 'undefined')  && mojo.internal && mojo.config) {
-{%-   endif %}
-
 (function() {
   var mojomId = '{{module.path}}';
   if (mojo.internal.isMojomLoaded(mojomId)) {
@@ -28,65 +21,14 @@
 
   var exports = mojo.internal.exposeNamespace('{{module.namespace}}');
 
-{%-   for import in imports %}
+{%- for import in imports %}
   var {{import.unique_name}} =
       mojo.internal.exposeNamespace('{{import.namespace}}');
   if (mojo.config.autoLoadMojomDeps) {
     mojo.internal.loadMojomIfNecessary(
         '{{import.path}}', '{{import|get_relative_url(module)}}.js');
   }
-{%-   endfor %}
+{%- endfor %}
 
 {% include "module_definition.tmpl" %}
 })();
-
-{%-   if js_bindings_mode == "both" %}
-}
-{%-   endif %}
-
-{%- endif %}
-
-{%- if js_bindings_mode == "both" or js_bindings_mode == "old" %}
-{{"old"|set_current_mode}}
-
-{%-   if js_bindings_mode == "both" %}
-if ((typeof mojo === 'undefined') || !mojo.internal || !mojo.config) {
-{%-   endif %}
-
-define("{{module.path}}", [
-{%- if module.path !=
-         "mojo/public/interfaces/bindings/interface_control_messages.mojom" and
-       module.path !=
-         "mojo/public/interfaces/bindings/pipe_control_messages.mojom" %}
-    "mojo/public/js/associated_bindings",
-    "mojo/public/js/bindings",
-{%-   endif %}
-    "mojo/public/js/codec",
-    "mojo/public/js/core",
-    "mojo/public/js/validator",
-{%-   for import in imports %}
-    "{{import.path}}",
-{%-   endfor %}
-], function(
-{%- if module.path !=
-         "mojo/public/interfaces/bindings/interface_control_messages.mojom" and
-       module.path !=
-         "mojo/public/interfaces/bindings/pipe_control_messages.mojom" -%}
-associatedBindings, bindings, {% endif -%}
-codec, core, validator
-{%-   for import in imports -%}
-    , {{import.unique_name}}
-{%-   endfor -%}
-) {
-  var exports = {};
-
-{%- include "module_definition.tmpl" %}
-
-  return exports;
-});
-
-{%-   if js_bindings_mode == "both" %}
-}
-{%-   endif %}
-
-{%- endif %}
diff --git a/mojo/public/tools/bindings/generators/mojom_js_generator.py b/mojo/public/tools/bindings/generators/mojom_js_generator.py
index 62b3cda..3230060c 100644
--- a/mojo/public/tools/bindings/generators/mojom_js_generator.py
+++ b/mojo/public/tools/bindings/generators/mojom_js_generator.py
@@ -95,65 +95,31 @@
 
 
 class JavaScriptStylizer(generator.Stylizer):
-  MODE_RESET = 0
-  MODE_OLD = 1
-  MODE_NEW = 2
-
-  def __init__(self, mode):
-    assert (mode == JavaScriptStylizer.MODE_RESET or
-            mode == JavaScriptStylizer.MODE_OLD or
-            mode == JavaScriptStylizer.MODE_NEW)
-    self.mode = mode
-
   def StylizeConstant(self, mojom_name):
-    if self.mode == JavaScriptStylizer.MODE_RESET:
-      return ""
     return mojom_name
 
   def StylizeField(self, mojom_name):
-    if self.mode == JavaScriptStylizer.MODE_RESET:
-      return ""
-    if self.mode == JavaScriptStylizer.MODE_OLD:
-      return mojom_name
     return generator.ToCamel(mojom_name, lower_initial=True)
 
   def StylizeStruct(self, mojom_name):
-    if self.mode == JavaScriptStylizer.MODE_RESET:
-      return ""
     return mojom_name
 
   def StylizeUnion(self, mojom_name):
-    if self.mode == JavaScriptStylizer.MODE_RESET:
-      return ""
     return mojom_name
 
   def StylizeParameter(self, mojom_name):
-    if self.mode == JavaScriptStylizer.MODE_RESET:
-      return ""
-    if self.mode == JavaScriptStylizer.MODE_OLD:
-      return mojom_name
     return generator.ToCamel(mojom_name, lower_initial=True)
 
   def StylizeMethod(self, mojom_name):
-    if self.mode == JavaScriptStylizer.MODE_RESET:
-      return ""
     return generator.ToCamel(mojom_name, lower_initial=True)
 
   def StylizeEnumField(self, mojom_name):
-    if self.mode == JavaScriptStylizer.MODE_RESET:
-      return ""
     return mojom_name
 
   def StylizeEnum(self, mojom_name):
-    if self.mode == JavaScriptStylizer.MODE_RESET:
-      return ""
     return mojom_name
 
   def StylizeModule(self, mojom_namespace):
-    if self.mode == JavaScriptStylizer.MODE_RESET:
-      return ""
-    if self.mode == JavaScriptStylizer.MODE_OLD:
-      return mojom_namespace
     return '.'.join(generator.ToCamel(word, lower_initial=True)
                         for word in mojom_namespace.split('.'))
 
@@ -168,7 +134,6 @@
       "module": self.module,
       "structs": self.module.structs + self._GetStructsFromMethods(),
       "unions": self.module.unions,
-      "js_bindings_mode": self.js_bindings_mode,
     }
 
   @staticmethod
@@ -202,7 +167,6 @@
       "js_type": self._JavaScriptType,
       "method_passes_associated_kinds": mojom.MethodPassesAssociatedKinds,
       "payload_size": JavaScriptPayloadSize,
-      "set_current_mode": self._SetCurrentMode,
       "to_camel": generator.ToCamel,
       "union_decode_snippet": self._JavaScriptUnionDecodeSnippet,
       "union_encode_snippet": self._JavaScriptUnionEncodeSnippet,
@@ -223,7 +187,7 @@
     if self.variant:
       raise Exception("Variants not supported in JavaScript bindings.")
 
-    self.module.Stylize(JavaScriptStylizer(JavaScriptStylizer.MODE_RESET))
+    self.module.Stylize(JavaScriptStylizer())
 
     # TODO(yzshen): Remove this method once the old JS bindings go away.
     self._SetUniqueNameForImports()
@@ -448,10 +412,3 @@
         if method.response_param_struct is not None:
           result.append(method.response_param_struct)
     return result
-
-  def _SetCurrentMode(self, mode):
-    self.module.Stylize(JavaScriptStylizer(
-        JavaScriptStylizer.MODE_OLD if mode == "old"
-            else JavaScriptStylizer.MODE_NEW))
-    return ""
-
diff --git a/mojo/public/tools/bindings/mojom.gni b/mojo/public/tools/bindings/mojom.gni
index 4bc9040..b7872fe 100644
--- a/mojo/public/tools/bindings/mojom.gni
+++ b/mojo/public/tools/bindings/mojom.gni
@@ -188,22 +188,6 @@
 #   cpp_only (optional)
 #       If set to true, only the C++ bindings targets will be generated.
 #
-#   use_new_js_bindings (optional)
-#       If set to true, the generated JS code will use the new module loading
-#       approach and the core API exposed by Web IDL.
-#       Default value is true.
-#       TODO(yzshen): Convert all users to use new JS bindings and remove the
-#       old mode.
-#
-#   js_bindings_mode (optional)
-#       |js_bindings_mode| and |use_new_js_bindings| are mutually exclusive. You
-#       can only specify at most one of them.
-#       - "new" (default): generate only the new-style JS bindings;
-#       - "both": generate both the old- and new-style JS bindings;
-#       - "old": generate only the old-style JS bindings.
-#       TODO(yzshen): Convert all users to use new JS bindings and remove the
-#       old mode.
-#
 #   support_lazy_serialization (optional)
 #       If set to |true|, generated C++ bindings will effectively prefer to
 #       transmit messages in an unserialized form when going between endpoints
@@ -280,11 +264,6 @@
           defined(invoker.public_deps),
       "\"sources\" or \"deps\" must be defined for the $target_name template.")
 
-  assert(!defined(invoker.use_new_js_bindings) ||
-             !defined(invoker.js_bindings_mode),
-         "You shouldn't specify both \"use_new_js_bindings\" and " +
-             "\"js_bindings_mode\".")
-
   if (defined(invoker.export_class_attribute) ||
       defined(invoker.export_define) || defined(invoker.export_header)) {
     assert(defined(invoker.export_class_attribute))
@@ -311,17 +290,6 @@
     assert(defined(invoker.component_deps_blink))
   }
 
-  js_bindings_mode = "new"
-  if (defined(invoker.js_bindings_mode)) {
-    js_bindings_mode = invoker.js_bindings_mode
-  }
-  if (defined(invoker.use_new_js_bindings) && !invoker.use_new_js_bindings) {
-    js_bindings_mode = "old"
-  }
-  assert(js_bindings_mode == "new" || js_bindings_mode == "both" ||
-             js_bindings_mode == "old",
-         "Invalid js_bindings_mode value.")
-
   all_deps = []
   if (defined(invoker.deps)) {
     all_deps += invoker.deps
@@ -995,11 +963,6 @@
           "-g",
           "javascript",
         ]
-
-        args += [
-          "--js_bindings_mode",
-          js_bindings_mode,
-        ]
       }
     }
 
diff --git a/net/base/network_throttle_manager_impl.cc b/net/base/network_throttle_manager_impl.cc
index 4c96573b0..52e1fcf 100644
--- a/net/base/network_throttle_manager_impl.cc
+++ b/net/base/network_throttle_manager_impl.cc
@@ -156,7 +156,7 @@
       outstanding_recomputation_timer_(
           std::make_unique<base::Timer>(false /* retain_user_task */,
                                         false /* is_repeating */)),
-      tick_clock_(new base::DefaultTickClock()),
+      tick_clock_(base::DefaultTickClock::GetInstance()),
       weak_ptr_factory_(this) {}
 
 NetworkThrottleManagerImpl::~NetworkThrottleManagerImpl() = default;
@@ -188,12 +188,11 @@
 }
 
 void NetworkThrottleManagerImpl::SetTickClockForTesting(
-    std::unique_ptr<base::TickClock> tick_clock) {
-  tick_clock_ = std::move(tick_clock);
+    base::TickClock* tick_clock) {
+  tick_clock_ = tick_clock;
   DCHECK(!outstanding_recomputation_timer_->IsRunning());
   outstanding_recomputation_timer_ = std::make_unique<base::Timer>(
-      false /* retain_user_task */, false /* is_repeating */,
-      tick_clock_.get());
+      false /* retain_user_task */, false /* is_repeating */, tick_clock_);
 }
 
 bool NetworkThrottleManagerImpl::ConditionallyTriggerTimerForTesting() {
diff --git a/net/base/network_throttle_manager_impl.h b/net/base/network_throttle_manager_impl.h
index a388032d..620da45 100644
--- a/net/base/network_throttle_manager_impl.h
+++ b/net/base/network_throttle_manager_impl.h
@@ -71,7 +71,7 @@
                                            RequestPriority priority,
                                            bool ignore_limits) override;
 
-  void SetTickClockForTesting(std::unique_ptr<base::TickClock> tick_clock);
+  void SetTickClockForTesting(base::TickClock* tick_clock);
 
   // If the |NowTicks()| value of |tick_clock_| is greater than the
   // time the outstanding_recomputation_timer_ has set to go off, Stop()
@@ -140,7 +140,7 @@
   ThrottleList blocked_throttles_;
 
   // For testing.
-  std::unique_ptr<base::TickClock> tick_clock_;
+  base::TickClock* tick_clock_;
 
   base::WeakPtrFactory<NetworkThrottleManagerImpl> weak_ptr_factory_;
 
diff --git a/net/base/network_throttle_manager_impl_unittest.cc b/net/base/network_throttle_manager_impl_unittest.cc
index 16ad54c..713b2680 100644
--- a/net/base/network_throttle_manager_impl_unittest.cc
+++ b/net/base/network_throttle_manager_impl_unittest.cc
@@ -47,14 +47,12 @@
                                    NetworkThrottleManager::ThrottleDelegate {
  public:
   NetworkThrottleManagerTest()
-      : clock_(new base::SimpleTestTickClock),
-        now_(base::TimeTicks::Now()),
+      : now_(base::TimeTicks::Now()),
         throttle_state_change_count_(0),
         last_throttle_to_change_state_(nullptr),
         throttle_manager_(new NetworkThrottleManagerImpl) {
-    clock_->SetNowTicks(now_);
-    throttle_manager_->SetTickClockForTesting(
-        std::unique_ptr<base::TickClock>(clock_));
+    clock_.SetNowTicks(now_);
+    throttle_manager_->SetTickClockForTesting(&clock_);
   }
 
  protected:
@@ -67,7 +65,7 @@
 
   // Set the offset of the test clock from now_.
   void SetClockDelta(base::TimeDelta time_delta) {
-    clock_->SetNowTicks(now_ + time_delta);
+    clock_.SetNowTicks(now_ + time_delta);
   }
 
   // Throttle creation
@@ -108,7 +106,7 @@
       base::ResetAndReturn(&throttle_state_changed_callback_).Run();
   }
 
-  base::SimpleTestTickClock* clock_;
+  base::SimpleTestTickClock clock_;
   base::TimeTicks now_;
   int throttle_state_change_count_;
   NetworkThrottleManager::Throttle* last_throttle_to_change_state_;
diff --git a/net/cert/caching_cert_verifier_unittest.cc b/net/cert/caching_cert_verifier_unittest.cc
index 354059f..11e0917 100644
--- a/net/cert/caching_cert_verifier_unittest.cc
+++ b/net/cert/caching_cert_verifier_unittest.cc
@@ -12,6 +12,7 @@
 #include "net/cert/cert_verify_result.h"
 #include "net/cert/mock_cert_verifier.h"
 #include "net/cert/x509_certificate.h"
+#include "net/cert/x509_util.h"
 #include "net/log/net_log_with_source.h"
 #include "net/test/cert_test_util.h"
 #include "net/test/gtest_util.h"
@@ -234,18 +235,22 @@
       ImportCertFromFile(certs_dir, "verisign_intermediate_ca_2016.pem");
   ASSERT_TRUE(intermediate_cert2);
 
-  X509Certificate::OSCertHandles intermediates;
-  intermediates.push_back(intermediate_cert1->os_cert_handle());
+  std::vector<bssl::UniquePtr<CRYPTO_BUFFER>> intermediates;
+  intermediates.push_back(
+      x509_util::DupCryptoBuffer(intermediate_cert1->cert_buffer()));
   scoped_refptr<X509Certificate> cert_chain1 =
-      X509Certificate::CreateFromHandle(server_cert->os_cert_handle(),
-                                        intermediates);
+      X509Certificate::CreateFromBuffer(
+          x509_util::DupCryptoBuffer(server_cert->cert_buffer()),
+          std::move(intermediates));
   ASSERT_TRUE(cert_chain1);
 
   intermediates.clear();
-  intermediates.push_back(intermediate_cert2->os_cert_handle());
+  intermediates.push_back(
+      x509_util::DupCryptoBuffer(intermediate_cert2->cert_buffer()));
   scoped_refptr<X509Certificate> cert_chain2 =
-      X509Certificate::CreateFromHandle(server_cert->os_cert_handle(),
-                                        intermediates);
+      X509Certificate::CreateFromBuffer(
+          x509_util::DupCryptoBuffer(server_cert->cert_buffer()),
+          std::move(intermediates));
   ASSERT_TRUE(cert_chain2);
 
   int error;
diff --git a/net/cert/cert_verifier.cc b/net/cert/cert_verifier.cc
index 5742ee1..f8e6a7f 100644
--- a/net/cert/cert_verifier.cc
+++ b/net/cert/cert_verifier.cc
@@ -9,6 +9,7 @@
 #include "base/strings/string_util.h"
 #include "build/build_config.h"
 #include "net/cert/cert_verify_proc.h"
+#include "third_party/boringssl/src/include/openssl/pool.h"
 #include "third_party/boringssl/src/include/openssl/sha.h"
 
 #if defined(OS_NACL)
@@ -37,19 +38,18 @@
   // sake.
   SHA256_CTX ctx;
   SHA256_Init(&ctx);
-  std::string cert_der;
-  X509Certificate::GetDEREncoded(certificate_->os_cert_handle(), &cert_der);
-  SHA256_Update(&ctx, cert_der.data(), cert_der.size());
-  for (auto* cert_handle : certificate_->GetIntermediateCertificates()) {
-    X509Certificate::GetDEREncoded(cert_handle, &cert_der);
-    SHA256_Update(&ctx, cert_der.data(), cert_der.size());
+  SHA256_Update(&ctx, CRYPTO_BUFFER_data(certificate_->cert_buffer()),
+                CRYPTO_BUFFER_len(certificate_->cert_buffer()));
+  for (const auto& cert_handle : certificate_->intermediate_buffers()) {
+    SHA256_Update(&ctx, CRYPTO_BUFFER_data(cert_handle.get()),
+                  CRYPTO_BUFFER_len(cert_handle.get()));
   }
   SHA256_Update(&ctx, hostname_.data(), hostname.size());
   SHA256_Update(&ctx, &flags, sizeof(flags));
   SHA256_Update(&ctx, ocsp_response.data(), ocsp_response.size());
   for (const auto& trust_anchor : additional_trust_anchors_) {
-    X509Certificate::GetDEREncoded(trust_anchor->os_cert_handle(), &cert_der);
-    SHA256_Update(&ctx, cert_der.data(), cert_der.size());
+    SHA256_Update(&ctx, CRYPTO_BUFFER_data(trust_anchor->cert_buffer()),
+                  CRYPTO_BUFFER_len(trust_anchor->cert_buffer()));
   }
   SHA256_Final(reinterpret_cast<uint8_t*>(
                    base::WriteInto(&key_, SHA256_DIGEST_LENGTH + 1)),
diff --git a/net/cert/cert_verifier_unittest.cc b/net/cert/cert_verifier_unittest.cc
index 73e7c9f8..b54f00fa 100644
--- a/net/cert/cert_verifier_unittest.cc
+++ b/net/cert/cert_verifier_unittest.cc
@@ -7,6 +7,7 @@
 #include "base/files/file_path.h"
 #include "base/memory/ref_counted.h"
 #include "net/cert/x509_certificate.h"
+#include "net/cert/x509_util.h"
 #include "net/test/cert_test_util.h"
 #include "net/test/test_data_directory.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -28,10 +29,11 @@
 
   // Create a certificate that contains both a leaf and an
   // intermediate/root.
-  X509Certificate::OSCertHandles chain;
-  chain.push_back(root_cert->os_cert_handle());
+  std::vector<bssl::UniquePtr<CRYPTO_BUFFER>> chain;
+  chain.push_back(x509_util::DupCryptoBuffer(root_cert->cert_buffer()));
   const scoped_refptr<X509Certificate> combined_cert =
-      X509Certificate::CreateFromHandle(ok_cert->os_cert_handle(), chain);
+      X509Certificate::CreateFromBuffer(
+          x509_util::DupCryptoBuffer(ok_cert->cert_buffer()), std::move(chain));
   ASSERT_TRUE(combined_cert.get());
 
   const CertificateList empty_list;
diff --git a/net/cert/cert_verify_proc.cc b/net/cert/cert_verify_proc.cc
index 47562afd..33862ce 100644
--- a/net/cert/cert_verify_proc.cc
+++ b/net/cert/cert_verify_proc.cc
@@ -30,6 +30,7 @@
 #include "net/cert/known_roots.h"
 #include "net/cert/ocsp_revocation_status.h"
 #include "net/cert/x509_certificate.h"
+#include "net/cert/x509_util.h"
 #include "net/der/encode_values.h"
 #include "url/url_canon.h"
 
@@ -152,7 +153,7 @@
       cert->valid_start() >= kBaselineEffectiveDate &&
       cert->valid_expiry() >= kBaselineKeysizeEffectiveDate;
 
-  X509Certificate::GetPublicKeyInfo(cert->os_cert_handle(), &size_bits, &type);
+  X509Certificate::GetPublicKeyInfo(cert->cert_buffer(), &size_bits, &type);
   if (should_histogram) {
     RecordPublicKeyHistogram(kLeafCert, baseline_keysize_applies, size_bits,
                              type);
@@ -160,10 +161,11 @@
   if (IsWeakKey(type, size_bits))
     weak_key = true;
 
-  const X509Certificate::OSCertHandles& intermediates =
-      cert->GetIntermediateCertificates();
+  const std::vector<bssl::UniquePtr<CRYPTO_BUFFER>>& intermediates =
+      cert->intermediate_buffers();
   for (size_t i = 0; i < intermediates.size(); ++i) {
-    X509Certificate::GetPublicKeyInfo(intermediates[i], &size_bits, &type);
+    X509Certificate::GetPublicKeyInfo(intermediates[i].get(), &size_bits,
+                                      &type);
     if (should_histogram) {
       RecordPublicKeyHistogram(
           (i < intermediates.size() - 1) ? kIntermediateCert : kRootCert,
@@ -199,31 +201,24 @@
     return;
   }
 
-  std::string cert_der;
-  if (!X509Certificate::GetDEREncoded(certificate.os_cert_handle(),
-                                      &cert_der)) {
-    *verify_result = OCSPVerifyResult();
-    return;
-  }
+  base::StringPiece cert_der =
+      x509_util::CryptoBufferAsStringPiece(certificate.cert_buffer());
 
   // Try to get the certificate that signed |certificate|. This will run into
   // problems if the CertVerifyProc implementation doesn't return the ordered
   // certificates. If that happens the OCSP verification may be incorrect.
-  std::string issuer_der;
-  const X509Certificate::OSCertHandles& intermediates =
-      certificate.GetIntermediateCertificates();
-  if (intermediates.empty()) {
-    if (X509Certificate::IsSelfSigned(certificate.os_cert_handle())) {
+  base::StringPiece issuer_der;
+  if (certificate.intermediate_buffers().empty()) {
+    if (X509Certificate::IsSelfSigned(certificate.cert_buffer())) {
       issuer_der = cert_der;
     } else {
       // A valid cert chain wasn't provided.
       *verify_result = OCSPVerifyResult();
       return;
     }
-  } else if (!X509Certificate::GetDEREncoded(intermediates.front(),
-                                             &issuer_der)) {
-    *verify_result = OCSPVerifyResult();
-    return;
+  } else {
+    issuer_der = x509_util::CryptoBufferAsStringPiece(
+        certificate.intermediate_buffers().front().get());
   }
 
   verify_result->revocation_status =
@@ -238,16 +233,13 @@
 void RecordTLSFeatureExtensionWithPrivateRoot(
     X509Certificate* cert,
     const OCSPVerifyResult& ocsp_result) {
-  std::string cert_der;
-  if (!X509Certificate::GetDEREncoded(cert->os_cert_handle(), &cert_der))
-    return;
-
   // This checks only for the presence of the TLS Feature Extension, but
   // does not check the feature list, and in particular does not verify that
   // its value is 'status_request' or 'status_request2'. In practice the
   // only use of the TLS feature extension is for OCSP stapling, so
   // don't bother to check the value.
-  bool has_extension = asn1::HasTLSFeatureExtension(cert_der);
+  bool has_extension = asn1::HasTLSFeatureExtension(
+      x509_util::CryptoBufferAsStringPiece(cert->cert_buffer()));
 
   UMA_HISTOGRAM_BOOLEAN("Net.Certificate.TLSFeatureExtensionWithPrivateRoot",
                         has_extension);
@@ -345,16 +337,15 @@
 //
 // Returns false if the signature algorithm was unknown or mismatched.
 WARN_UNUSED_RESULT bool InspectSignatureAlgorithmForCert(
-    X509Certificate::OSCertHandle cert,
+    const CRYPTO_BUFFER* cert,
     CertVerifyResult* verify_result) {
-  std::string cert_der;
   base::StringPiece cert_algorithm_sequence;
   base::StringPiece tbs_algorithm_sequence;
 
   // Extract the AlgorithmIdentifier SEQUENCEs
-  if (!X509Certificate::GetDEREncoded(cert, &cert_der) ||
-      !asn1::ExtractSignatureAlgorithmsFromDERCert(
-          cert_der, &cert_algorithm_sequence, &tbs_algorithm_sequence)) {
+  if (!asn1::ExtractSignatureAlgorithmsFromDERCert(
+          x509_util::CryptoBufferAsStringPiece(cert), &cert_algorithm_sequence,
+          &tbs_algorithm_sequence)) {
     return false;
   }
 
@@ -412,8 +403,8 @@
 // in order to prevent such confusion.
 WARN_UNUSED_RESULT bool InspectSignatureAlgorithmsInChain(
     CertVerifyResult* verify_result) {
-  const X509Certificate::OSCertHandles& intermediates =
-      verify_result->verified_cert->GetIntermediateCertificates();
+  const std::vector<bssl::UniquePtr<CRYPTO_BUFFER>>& intermediates =
+      verify_result->verified_cert->intermediate_buffers();
 
   // If there are no intermediates, then the leaf is trusted or verification
   // failed.
@@ -424,7 +415,7 @@
 
   // Fill in hash algorithms for the leaf certificate.
   if (!InspectSignatureAlgorithmForCert(
-          verify_result->verified_cert->os_cert_handle(), verify_result)) {
+          verify_result->verified_cert->cert_buffer(), verify_result)) {
     return false;
   }
 
@@ -434,7 +425,8 @@
   // final one (which is presumably the trust anchor; may be incorrect for
   // partial chains).
   for (size_t i = 0; i + 1 < intermediates.size(); ++i) {
-    if (!InspectSignatureAlgorithmForCert(intermediates[i], verify_result))
+    if (!InspectSignatureAlgorithmForCert(intermediates[i].get(),
+                                          verify_result))
       return false;
   }
 
diff --git a/net/cert/cert_verify_proc_android.cc b/net/cert/cert_verify_proc_android.cc
index cdf87d3..3526e84 100644
--- a/net/cert/cert_verify_proc_android.cc
+++ b/net/cert/cert_verify_proc_android.cc
@@ -317,12 +317,12 @@
 
 void GetChainDEREncodedBytes(X509Certificate* cert,
                              std::vector<std::string>* chain_bytes) {
-  chain_bytes->reserve(1 + cert->GetIntermediateCertificates().size());
+  chain_bytes->reserve(1 + cert->intermediate_buffers().size());
   chain_bytes->emplace_back(
-      net::x509_util::CryptoBufferAsStringPiece(cert->os_cert_handle()));
-  for (auto* handle : cert->GetIntermediateCertificates()) {
+      net::x509_util::CryptoBufferAsStringPiece(cert->cert_buffer()));
+  for (const auto& handle : cert->intermediate_buffers()) {
     chain_bytes->emplace_back(
-        net::x509_util::CryptoBufferAsStringPiece(handle));
+        net::x509_util::CryptoBufferAsStringPiece(handle.get()));
   }
 }
 
diff --git a/net/cert/cert_verify_proc_android_unittest.cc b/net/cert/cert_verify_proc_android_unittest.cc
index 4f8c424..cc5e0ec4 100644
--- a/net/cert/cert_verify_proc_android_unittest.cc
+++ b/net/cert/cert_verify_proc_android_unittest.cc
@@ -13,6 +13,7 @@
 #include "net/cert/internal/test_helpers.h"
 #include "net/cert/test_root_certs.h"
 #include "net/cert/x509_certificate.h"
+#include "net/cert/x509_util.h"
 #include "net/test/cert_test_util.h"
 #include "net/test/test_certificate_data.h"
 #include "net/test/test_data_directory.h"
@@ -64,8 +65,8 @@
 std::unique_ptr<CertNetFetcher::Request> CreateMockRequestFromX509Certificate(
     Error error,
     const scoped_refptr<X509Certificate>& cert) {
-  std::string der;
-  EXPECT_TRUE(X509Certificate::GetDEREncoded(cert->os_cert_handle(), &der));
+  base::StringPiece der =
+      x509_util::CryptoBufferAsStringPiece(cert->cert_buffer());
   return std::make_unique<TestCertNetFetcherRequest>(
       error, std::vector<uint8_t>(der.data(), der.data() + der.length()));
 }
@@ -121,18 +122,18 @@
   ::testing::AssertionResult r = ReadTestCert(files[0], &leaf);
   if (!r)
     return r;
-  CertificateList intermediates;
-  X509Certificate::OSCertHandles intermediate_os_cert_handles;
+  std::vector<bssl::UniquePtr<CRYPTO_BUFFER>> intermediate_buffers;
   for (size_t i = 1; i < files.size(); i++) {
     scoped_refptr<X509Certificate> intermediate;
     r = ReadTestCert(files[i], &intermediate);
     if (!r)
       return r;
-    intermediates.push_back(intermediate);
-    intermediate_os_cert_handles.push_back(intermediate->os_cert_handle());
+    intermediate_buffers.push_back(
+        x509_util::DupCryptoBuffer(intermediate->cert_buffer()));
   }
-  *result = X509Certificate::CreateFromHandle(leaf->os_cert_handle(),
-                                              intermediate_os_cert_handles);
+  *result = X509Certificate::CreateFromBuffer(
+      x509_util::DupCryptoBuffer(leaf->cert_buffer()),
+      std::move(intermediate_buffers));
   return ::testing::AssertionSuccess();
 }
 
diff --git a/net/cert/cert_verify_proc_builtin.cc b/net/cert/cert_verify_proc_builtin.cc
index a822027..dc565ea 100644
--- a/net/cert/cert_verify_proc_builtin.cc
+++ b/net/cert/cert_verify_proc_builtin.cc
@@ -293,25 +293,20 @@
   return true;
 }
 
-scoped_refptr<ParsedCertificate> ParseCertificateFromOSHandle(
-    X509Certificate::OSCertHandle cert_handle,
+scoped_refptr<ParsedCertificate> ParseCertificateFromBuffer(
+    CRYPTO_BUFFER* cert_handle,
     CertErrors* errors) {
-  std::string cert_bytes;
-  if (!X509Certificate::GetDEREncoded(cert_handle, &cert_bytes))
-    return nullptr;
-  return ParsedCertificate::Create(x509_util::CreateCryptoBuffer(cert_bytes),
+  return ParsedCertificate::Create(x509_util::DupCryptoBuffer(cert_handle),
                                    x509_util::DefaultParseCertificateOptions(),
                                    errors);
 }
 
 void AddIntermediatesToIssuerSource(X509Certificate* x509_cert,
                                     CertIssuerSourceStatic* intermediates) {
-  const X509Certificate::OSCertHandles& cert_handles =
-      x509_cert->GetIntermediateCertificates();
   CertErrors errors;
-  for (auto it = cert_handles.begin(); it != cert_handles.end(); ++it) {
+  for (const auto& intermediate : x509_cert->intermediate_buffers()) {
     scoped_refptr<ParsedCertificate> cert =
-        ParseCertificateFromOSHandle(*it, &errors);
+        ParseCertificateFromBuffer(intermediate.get(), &errors);
     if (cert)
       intermediates->AddCert(std::move(cert));
     // TODO(crbug.com/634443): Surface these parsing errors?
@@ -371,9 +366,9 @@
     *cert_status |= CERT_STATUS_INVALID;
 }
 
-X509Certificate::OSCertHandle CreateOSCertHandle(
+bssl::UniquePtr<CRYPTO_BUFFER> CreateCertBuffers(
     const scoped_refptr<ParsedCertificate>& certificate) {
-  return X509Certificate::CreateOSCertHandleFromBytes(
+  return X509Certificate::CreateCertBufferFromBytes(
       reinterpret_cast<const char*>(certificate->der_cert().UnsafeData()),
       certificate->der_cert().Length());
 }
@@ -386,20 +381,18 @@
 scoped_refptr<X509Certificate> CreateVerifiedCertChain(
     X509Certificate* target_cert,
     const CertPathBuilderResultPath& path) {
-  X509Certificate::OSCertHandles intermediates;
+  std::vector<bssl::UniquePtr<CRYPTO_BUFFER>> intermediates;
 
   // Skip the first certificate in the path as that is the target certificate
   for (size_t i = 1; i < path.certs.size(); ++i)
-    intermediates.push_back(CreateOSCertHandle(path.certs[i]));
+    intermediates.push_back(CreateCertBuffers(path.certs[i]));
 
-  scoped_refptr<X509Certificate> result = X509Certificate::CreateFromHandle(
-      target_cert->os_cert_handle(), intermediates);
+  scoped_refptr<X509Certificate> result = X509Certificate::CreateFromBuffer(
+      x509_util::DupCryptoBuffer(target_cert->cert_buffer()),
+      std::move(intermediates));
   // |target_cert| was already successfully parsed, so this should never fail.
   DCHECK(result);
 
-  for (const X509Certificate::OSCertHandle handle : intermediates)
-    X509Certificate::FreeOSCertHandle(handle);
-
   return result;
 }
 
@@ -534,8 +527,8 @@
   base::Time verification_time = base::Time::Now();
 
   // Parse the target certificate.
-  scoped_refptr<ParsedCertificate> target = ParseCertificateFromOSHandle(
-      input_cert->os_cert_handle(), &parsing_errors);
+  scoped_refptr<ParsedCertificate> target =
+      ParseCertificateFromBuffer(input_cert->cert_buffer(), &parsing_errors);
   if (!target) {
     // TODO(crbug.com/634443): Surface these parsing errors?
     verify_result->cert_status |= CERT_STATUS_INVALID;
@@ -551,8 +544,8 @@
       CreateSslSystemTrustStore();
 
   for (const auto& x509_cert : additional_trust_anchors) {
-    scoped_refptr<ParsedCertificate> cert = ParseCertificateFromOSHandle(
-        x509_cert->os_cert_handle(), &parsing_errors);
+    scoped_refptr<ParsedCertificate> cert =
+        ParseCertificateFromBuffer(x509_cert->cert_buffer(), &parsing_errors);
     if (cert)
       ssl_trust_store->AddTrustAnchor(cert);
     // TODO(eroman): Surface parsing errors of additional trust anchor.
diff --git a/net/cert/cert_verify_proc_mac.cc b/net/cert/cert_verify_proc_mac.cc
index 424c765..4dd8715c 100644
--- a/net/cert/cert_verify_proc_mac.cc
+++ b/net/cert/cert_verify_proc_mac.cc
@@ -309,14 +309,8 @@
                           std::string* ev_policy_oid) {
   ev_policy_oid->clear();
 
-  std::string der_cert;
-  if (!X509Certificate::GetDEREncoded(cert_input->os_cert_handle(),
-                                      &der_cert)) {
-    return;
-  }
-
   scoped_refptr<ParsedCertificate> cert(ParsedCertificate::Create(
-      x509_util::CreateCryptoBuffer(der_cert), {}, nullptr));
+      x509_util::DupCryptoBuffer(cert_input->cert_buffer()), {}, nullptr));
   if (!cert)
     return;
 
@@ -342,27 +336,24 @@
 bool CheckCertChainEV(const X509Certificate* cert,
                       const std::string& ev_policy_oid_string) {
   der::Input ev_policy_oid(&ev_policy_oid_string);
-  X509Certificate::OSCertHandles os_cert_chain =
-      cert->GetIntermediateCertificates();
+  const std::vector<bssl::UniquePtr<CRYPTO_BUFFER>>& cert_chain =
+      cert->intermediate_buffers();
 
   // Root should have matching policy in EVRootCAMetadata.
-  if (os_cert_chain.empty())
+  if (cert_chain.empty())
     return false;
   SHA256HashValue fingerprint =
-      X509Certificate::CalculateFingerprint256(os_cert_chain.back());
+      X509Certificate::CalculateFingerprint256(cert_chain.back().get());
   EVRootCAMetadata* metadata = EVRootCAMetadata::GetInstance();
   if (!metadata->HasEVPolicyOID(fingerprint, ev_policy_oid))
     return false;
 
   // Intermediates should have Certificate Policies extension with the EV policy
   // or AnyPolicy.
-  for (size_t i = 0; i < os_cert_chain.size() - 1; ++i) {
-    std::string der_cert;
-    if (!X509Certificate::GetDEREncoded(os_cert_chain[i], &der_cert))
-      return false;
+  for (size_t i = 0; i < cert_chain.size() - 1; ++i) {
     scoped_refptr<ParsedCertificate> intermediate_cert(
-        ParsedCertificate::Create(x509_util::CreateCryptoBuffer(der_cert), {},
-                                  nullptr));
+        ParsedCertificate::Create(
+            x509_util::DupCryptoBuffer(cert_chain[i].get()), {}, nullptr));
     if (!intermediate_cert)
       return false;
     if (!HasPolicyOrAnyPolicy(intermediate_cert.get(), ev_policy_oid))
diff --git a/net/cert/cert_verify_proc_mac_unittest.cc b/net/cert/cert_verify_proc_mac_unittest.cc
index 71200c0..24ced3f 100644
--- a/net/cert/cert_verify_proc_mac_unittest.cc
+++ b/net/cert/cert_verify_proc_mac_unittest.cc
@@ -19,6 +19,7 @@
 #include "net/cert/test_keychain_search_list_mac.h"
 #include "net/cert/test_root_certs.h"
 #include "net/cert/x509_certificate.h"
+#include "net/cert/x509_util.h"
 #include "net/test/cert_test_util.h"
 #include "net/test/gtest_util.h"
 #include "net/test/test_data_directory.h"
@@ -69,11 +70,14 @@
   // Add E as trust anchor.
   ScopedTestRoot test_root_E(path_3_certs[3].get());  // E-by-E
 
-  X509Certificate::OSCertHandles intermediates;
-  intermediates.push_back(path_2_certs[1]->os_cert_handle());  // B-by-C
-  intermediates.push_back(path_2_certs[2]->os_cert_handle());  // C-by-E
-  scoped_refptr<X509Certificate> cert = X509Certificate::CreateFromHandle(
-      path_3_certs[0]->os_cert_handle(), intermediates);
+  std::vector<bssl::UniquePtr<CRYPTO_BUFFER>> intermediates;
+  intermediates.push_back(
+      x509_util::DupCryptoBuffer(path_2_certs[1]->cert_buffer()));  // B-by-C
+  intermediates.push_back(
+      x509_util::DupCryptoBuffer(path_2_certs[2]->cert_buffer()));  // C-by-E
+  scoped_refptr<X509Certificate> cert = X509Certificate::CreateFromBuffer(
+      x509_util::DupCryptoBuffer(path_3_certs[0]->cert_buffer()),
+      std::move(intermediates));
   ASSERT_TRUE(cert);
 
   std::unique_ptr<TestKeychainSearchList> test_keychain_search_list(
@@ -113,13 +117,13 @@
   ASSERT_EQ(0U, verify_result.cert_status);
   ASSERT_TRUE(verify_result.verified_cert.get());
 
-  const X509Certificate::OSCertHandles& verified_intermediates =
-      verify_result.verified_cert->GetIntermediateCertificates();
+  const auto& verified_intermediates =
+      verify_result.verified_cert->intermediate_buffers();
   ASSERT_EQ(3U, verified_intermediates.size());
 
   scoped_refptr<X509Certificate> intermediate =
-      X509Certificate::CreateFromHandle(verified_intermediates[1],
-                                        X509Certificate::OSCertHandles());
+      X509Certificate::CreateFromBuffer(
+          x509_util::DupCryptoBuffer(verified_intermediates[1].get()), {});
   ASSERT_TRUE(intermediate);
 
   scoped_refptr<X509Certificate> expected_intermediate = path_3_certs[2];
@@ -171,8 +175,8 @@
   EXPECT_FALSE(verify_result.has_sha1);
   ASSERT_TRUE(verify_result.verified_cert.get());
 
-  const X509Certificate::OSCertHandles& verified_intermediates =
-      verify_result.verified_cert->GetIntermediateCertificates();
+  const auto& verified_intermediates =
+      verify_result.verified_cert->intermediate_buffers();
   ASSERT_EQ(2U, verified_intermediates.size());
 }
 
diff --git a/net/cert/cert_verify_proc_unittest.cc b/net/cert/cert_verify_proc_unittest.cc
index 1a7195a..050f951 100644
--- a/net/cert/cert_verify_proc_unittest.cc
+++ b/net/cert/cert_verify_proc_unittest.cc
@@ -333,12 +333,12 @@
   //
   // This way CRLSet coverage will be sufficient for EV revocation checking,
   // so this test does not depend on online revocation checking.
-  ASSERT_EQ(1u, chain->GetIntermediateCertificates().size());
-  std::string der_bytes;
-  ASSERT_TRUE(X509Certificate::GetDEREncoded(
-      chain->GetIntermediateCertificates()[0], &der_bytes));
+  ASSERT_EQ(1u, chain->intermediate_buffers().size());
   base::StringPiece spki;
-  ASSERT_TRUE(asn1::ExtractSPKIFromDERCert(der_bytes, &spki));
+  ASSERT_TRUE(
+      asn1::ExtractSPKIFromDERCert(x509_util::CryptoBufferAsStringPiece(
+                                       chain->intermediate_buffers()[0].get()),
+                                   &spki));
   SHA256HashValue spki_sha256;
   crypto::SHA256HashString(spki, spki_sha256.data, sizeof(spki_sha256.data));
   scoped_refptr<CRLSet> crl_set(
@@ -376,8 +376,7 @@
   } else if (ScopedTestRootCanTrustTargetCert(verify_proc_type())) {
     EXPECT_THAT(error, IsOk());
     ASSERT_TRUE(verify_result.verified_cert);
-    EXPECT_TRUE(
-        verify_result.verified_cert->GetIntermediateCertificates().empty());
+    EXPECT_TRUE(verify_result.verified_cert->intermediate_buffers().empty());
   } else {
     EXPECT_THAT(error, IsError(ERR_CERT_AUTHORITY_INVALID));
   }
@@ -417,8 +416,7 @@
   } else if (ScopedTestRootCanTrustTargetCert(verify_proc_type())) {
     EXPECT_THAT(error, IsOk());
     ASSERT_TRUE(verify_result.verified_cert);
-    EXPECT_TRUE(
-        verify_result.verified_cert->GetIntermediateCertificates().empty());
+    EXPECT_TRUE(verify_result.verified_cert->intermediate_buffers().empty());
   } else {
     EXPECT_THAT(error, IsError(ERR_CERT_AUTHORITY_INVALID));
   }
@@ -443,7 +441,7 @@
   ASSERT_NE(static_cast<X509Certificate*>(NULL), paypal_null_cert.get());
 
   EXPECT_EQ(paypal_null_fingerprint, X509Certificate::CalculateFingerprint256(
-                                         paypal_null_cert->os_cert_handle()));
+                                         paypal_null_cert->cert_buffer()));
 
   int flags = 0;
   CertVerifyResult verify_result;
@@ -489,11 +487,14 @@
       ImportCertFromFile(GetTestCertsDirectory(), "ok_cert.pem"));
   ASSERT_TRUE(ok_cert);
 
+  std::vector<bssl::UniquePtr<CRYPTO_BUFFER>> intermediates;
+  intermediates.push_back(x509_util::DupCryptoBuffer(ok_cert->cert_buffer()));
   scoped_refptr<X509Certificate> cert_with_bad_target(
-      X509Certificate::CreateFromHandle(bad_cert->os_cert_handle(),
-                                        {ok_cert->os_cert_handle()}));
+      X509Certificate::CreateFromBuffer(
+          x509_util::DupCryptoBuffer(bad_cert->cert_buffer()),
+          std::move(intermediates)));
   ASSERT_TRUE(cert_with_bad_target);
-  EXPECT_EQ(1U, cert_with_bad_target->GetIntermediateCertificates().size());
+  EXPECT_EQ(1U, cert_with_bad_target->intermediate_buffers().size());
 
   int flags = 0;
   CertVerifyResult verify_result;
@@ -522,12 +523,14 @@
       ImportCertFromFile(GetTestCertsDirectory(), "ok_cert.pem"));
   ASSERT_TRUE(ok_cert);
 
+  std::vector<bssl::UniquePtr<CRYPTO_BUFFER>> intermediates;
+  intermediates.push_back(std::move(bad_cert));
   scoped_refptr<X509Certificate> cert_with_bad_intermediate(
-      X509Certificate::CreateFromHandle(ok_cert->os_cert_handle(),
-                                        {bad_cert.get()}));
+      X509Certificate::CreateFromBuffer(
+          x509_util::DupCryptoBuffer(ok_cert->cert_buffer()),
+          std::move(intermediates)));
   ASSERT_TRUE(cert_with_bad_intermediate);
-  EXPECT_EQ(1U,
-            cert_with_bad_intermediate->GetIntermediateCertificates().size());
+  EXPECT_EQ(1U, cert_with_bad_intermediate->intermediate_buffers().size());
 
   int flags = 0;
   CertVerifyResult verify_result;
@@ -553,11 +556,12 @@
       certs_dir, "explicit-policy-chain.pem", X509Certificate::FORMAT_AUTO);
   ASSERT_EQ(3U, certs.size());
 
-  X509Certificate::OSCertHandles intermediates;
-  intermediates.push_back(certs[1]->os_cert_handle());
+  std::vector<bssl::UniquePtr<CRYPTO_BUFFER>> intermediates;
+  intermediates.push_back(x509_util::DupCryptoBuffer(certs[1]->cert_buffer()));
 
-  scoped_refptr<X509Certificate> cert = X509Certificate::CreateFromHandle(
-      certs[0]->os_cert_handle(), intermediates);
+  scoped_refptr<X509Certificate> cert = X509Certificate::CreateFromBuffer(
+      x509_util::DupCryptoBuffer(certs[0]->cert_buffer()),
+      std::move(intermediates));
   ASSERT_TRUE(cert.get());
 
   ScopedTestRoot scoped_root(certs[2].get());
@@ -580,7 +584,7 @@
   scoped_refptr<X509Certificate> cert = CreateCertificateChainFromFile(
       certs_dir, "expired_cert.pem", X509Certificate::FORMAT_AUTO);
   ASSERT_TRUE(cert);
-  ASSERT_EQ(0U, cert->GetIntermediateCertificates().size());
+  ASSERT_EQ(0U, cert->intermediate_buffers().size());
 
   int flags = 0;
   CertVerifyResult verify_result;
@@ -643,11 +647,13 @@
           ImportCertFromFile(certs_dir, basename);
       ASSERT_NE(static_cast<X509Certificate*>(NULL), intermediate.get());
 
-      X509Certificate::OSCertHandles intermediates;
-      intermediates.push_back(intermediate->os_cert_handle());
+      std::vector<bssl::UniquePtr<CRYPTO_BUFFER>> intermediates;
+      intermediates.push_back(
+          x509_util::DupCryptoBuffer(intermediate->cert_buffer()));
       scoped_refptr<X509Certificate> cert_chain =
-          X509Certificate::CreateFromHandle(ee_cert->os_cert_handle(),
-                                            intermediates);
+          X509Certificate::CreateFromBuffer(
+              x509_util::DupCryptoBuffer(ee_cert->cert_buffer()),
+              std::move(intermediates));
       ASSERT_TRUE(cert_chain);
 
       CertVerifyResult verify_result;
@@ -700,10 +706,12 @@
 
   ScopedTestRoot scoped_root(root_cert.get());
 
-  X509Certificate::OSCertHandles intermediates;
-  intermediates.push_back(extra_cert->os_cert_handle());
-  scoped_refptr<X509Certificate> cert_chain = X509Certificate::CreateFromHandle(
-      server_cert->os_cert_handle(), intermediates);
+  std::vector<bssl::UniquePtr<CRYPTO_BUFFER>> intermediates;
+  intermediates.push_back(
+      x509_util::DupCryptoBuffer(extra_cert->cert_buffer()));
+  scoped_refptr<X509Certificate> cert_chain = X509Certificate::CreateFromBuffer(
+      x509_util::DupCryptoBuffer(server_cert->cert_buffer()),
+      std::move(intermediates));
   ASSERT_TRUE(cert_chain);
 
   CertVerifyResult verify_result;
@@ -714,11 +722,10 @@
 
   // The extra MD5 root should be discarded
   ASSERT_TRUE(verify_result.verified_cert.get());
-  ASSERT_EQ(1u,
-            verify_result.verified_cert->GetIntermediateCertificates().size());
-  EXPECT_TRUE(X509Certificate::IsSameOSCert(
-      verify_result.verified_cert->GetIntermediateCertificates().front(),
-      root_cert->os_cert_handle()));
+  ASSERT_EQ(1u, verify_result.verified_cert->intermediate_buffers().size());
+  EXPECT_TRUE(x509_util::CryptoBufferEqual(
+      verify_result.verified_cert->intermediate_buffers().front().get(),
+      root_cert->cert_buffer()));
 
   EXPECT_FALSE(verify_result.has_md5);
 }
@@ -735,10 +742,12 @@
       ImportCertFromFile(certs_dir, "diginotar_public_ca_2025.pem");
   ASSERT_NE(static_cast<X509Certificate*>(NULL), intermediate_cert.get());
 
-  X509Certificate::OSCertHandles intermediates;
-  intermediates.push_back(intermediate_cert->os_cert_handle());
-  scoped_refptr<X509Certificate> cert_chain = X509Certificate::CreateFromHandle(
-      server_cert->os_cert_handle(), intermediates);
+  std::vector<bssl::UniquePtr<CRYPTO_BUFFER>> intermediates;
+  intermediates.push_back(
+      x509_util ::DupCryptoBuffer(intermediate_cert->cert_buffer()));
+  scoped_refptr<X509Certificate> cert_chain = X509Certificate::CreateFromBuffer(
+      x509_util::DupCryptoBuffer(server_cert->cert_buffer()),
+      std::move(intermediates));
   ASSERT_TRUE(cert_chain);
 
   CertVerifyResult verify_result;
@@ -779,12 +788,10 @@
   for (size_t i = 0; kDigiNotarFilenames[i]; i++) {
     scoped_refptr<X509Certificate> diginotar_cert =
         ImportCertFromFile(certs_dir, kDigiNotarFilenames[i]);
-    std::string der_bytes;
-    ASSERT_TRUE(X509Certificate::GetDEREncoded(diginotar_cert->os_cert_handle(),
-                                               &der_bytes));
-
     base::StringPiece spki;
-    ASSERT_TRUE(asn1::ExtractSPKIFromDERCert(der_bytes, &spki));
+    ASSERT_TRUE(asn1::ExtractSPKIFromDERCert(
+        x509_util::CryptoBufferAsStringPiece(diginotar_cert->cert_buffer()),
+        &spki));
 
     std::string spki_sha256 = crypto::SHA256HashString(spki);
 
@@ -810,7 +817,7 @@
       GetTestCertsDirectory(), "name_constraint_good.pem",
       X509Certificate::FORMAT_AUTO);
   ASSERT_TRUE(leaf);
-  ASSERT_EQ(0U, leaf->GetIntermediateCertificates().size());
+  ASSERT_EQ(0U, leaf->intermediate_buffers().size());
 
   int flags = 0;
   CertVerifyResult verify_result;
@@ -1005,13 +1012,10 @@
       return nullptr;
     }
 
-    // Start with the DER bytes of a valid certificate. This will be the basis
-    // for building a modified certificate.
-    std::string cert_der;
-    if (!X509Certificate::GetDEREncoded(cert->os_cert_handle(), &cert_der)) {
-      ADD_FAILURE() << "Failed getting DER bytes";
-      return nullptr;
-    }
+    // Start with the DER bytes of a valid certificate. The der data is copied
+    // to a new std::string as it will modified to create a new certificate.
+    std::string cert_der(
+        x509_util::CryptoBufferAsStringPiece(cert->cert_buffer()));
 
     // Parse the certificate and identify the locations of interest within
     // |cert_der|.
@@ -1062,12 +1066,14 @@
         return nullptr;
     }
 
-    X509Certificate::OSCertHandles intermediates;
+    std::vector<bssl::UniquePtr<CRYPTO_BUFFER>> intermediates;
     for (size_t i = 1; i < certs.size(); ++i)
-      intermediates.push_back(certs[i]->os_cert_handle());
+      intermediates.push_back(
+          x509_util::DupCryptoBuffer(certs[i]->cert_buffer()));
 
-    return X509Certificate::CreateFromHandle(certs[0]->os_cert_handle(),
-                                             intermediates);
+    return X509Certificate::CreateFromBuffer(
+        x509_util::DupCryptoBuffer(certs[0]->cert_buffer()),
+        std::move(intermediates));
   }
 };
 
@@ -1206,9 +1212,8 @@
       X509Certificate::FORMAT_AUTO);
   ASSERT_EQ(1U, cert_list.size());
 
-  X509Certificate::OSCertHandles intermediates;
-  scoped_refptr<X509Certificate> leaf = X509Certificate::CreateFromHandle(
-      cert_list[0]->os_cert_handle(), intermediates);
+  scoped_refptr<X509Certificate> leaf = X509Certificate::CreateFromBuffer(
+      x509_util::DupCryptoBuffer(cert_list[0]->cert_buffer()), {});
   ASSERT_TRUE(leaf);
 
   int flags = 0;
@@ -1262,11 +1267,12 @@
       certs_dir, "twitter-chain.pem", X509Certificate::FORMAT_AUTO);
   ASSERT_EQ(3U, certs.size());
 
-  X509Certificate::OSCertHandles intermediates;
-  intermediates.push_back(certs[1]->os_cert_handle());
+  std::vector<bssl::UniquePtr<CRYPTO_BUFFER>> intermediates;
+  intermediates.push_back(x509_util::DupCryptoBuffer(certs[1]->cert_buffer()));
 
-  scoped_refptr<X509Certificate> cert_chain = X509Certificate::CreateFromHandle(
-      certs[0]->os_cert_handle(), intermediates);
+  scoped_refptr<X509Certificate> cert_chain = X509Certificate::CreateFromBuffer(
+      x509_util::DupCryptoBuffer(certs[0]->cert_buffer()),
+      std::move(intermediates));
   ASSERT_TRUE(cert_chain);
 
   int flags = 0;
@@ -1293,15 +1299,16 @@
       certs_dir, "x509_verify_results.chain.pem", X509Certificate::FORMAT_AUTO);
   ASSERT_EQ(3U, certs.size());
 
-  X509Certificate::OSCertHandles intermediates;
-  intermediates.push_back(certs[1]->os_cert_handle());
-  intermediates.push_back(certs[2]->os_cert_handle());
+  std::vector<bssl::UniquePtr<CRYPTO_BUFFER>> intermediates;
+  intermediates.push_back(x509_util::DupCryptoBuffer(certs[1]->cert_buffer()));
+  intermediates.push_back(x509_util::DupCryptoBuffer(certs[2]->cert_buffer()));
 
   ScopedTestRoot scoped_root(certs[2].get());
-  scoped_refptr<X509Certificate> cert_chain = X509Certificate::CreateFromHandle(
-      certs[0]->os_cert_handle(), intermediates);
+  scoped_refptr<X509Certificate> cert_chain = X509Certificate::CreateFromBuffer(
+      x509_util::DupCryptoBuffer(certs[0]->cert_buffer()),
+      std::move(intermediates));
   ASSERT_TRUE(cert_chain);
-  ASSERT_EQ(2U, cert_chain->GetIntermediateCertificates().size());
+  ASSERT_EQ(2U, cert_chain->intermediate_buffers().size());
 
   int flags = 0;
   CertVerifyResult verify_result;
@@ -1385,17 +1392,18 @@
       certs_dir, "x509_verify_results.chain.pem", X509Certificate::FORMAT_AUTO);
   ASSERT_EQ(3U, certs.size());
 
-  X509Certificate::OSCertHandles intermediates;
-  intermediates.push_back(certs[1]->os_cert_handle());
-  intermediates.push_back(certs[2]->os_cert_handle());
+  std::vector<bssl::UniquePtr<CRYPTO_BUFFER>> intermediates;
+  intermediates.push_back(x509_util::DupCryptoBuffer(certs[1]->cert_buffer()));
+  intermediates.push_back(x509_util::DupCryptoBuffer(certs[2]->cert_buffer()));
 
   ScopedTestRoot scoped_root(certs[2].get());
 
   scoped_refptr<X509Certificate> google_full_chain =
-      X509Certificate::CreateFromHandle(certs[0]->os_cert_handle(),
-                                        intermediates);
+      X509Certificate::CreateFromBuffer(
+          x509_util::DupCryptoBuffer(certs[0]->cert_buffer()),
+          std::move(intermediates));
   ASSERT_NE(static_cast<X509Certificate*>(NULL), google_full_chain.get());
-  ASSERT_EQ(2U, google_full_chain->GetIntermediateCertificates().size());
+  ASSERT_EQ(2U, google_full_chain->intermediate_buffers().size());
 
   CertVerifyResult verify_result;
   EXPECT_EQ(static_cast<X509Certificate*>(NULL),
@@ -1407,16 +1415,16 @@
             verify_result.verified_cert.get());
 
   EXPECT_NE(google_full_chain, verify_result.verified_cert);
-  EXPECT_TRUE(X509Certificate::IsSameOSCert(
-      google_full_chain->os_cert_handle(),
-      verify_result.verified_cert->os_cert_handle()));
-  const X509Certificate::OSCertHandles& return_intermediates =
-      verify_result.verified_cert->GetIntermediateCertificates();
+  EXPECT_TRUE(
+      x509_util::CryptoBufferEqual(google_full_chain->cert_buffer(),
+                                   verify_result.verified_cert->cert_buffer()));
+  const auto& return_intermediates =
+      verify_result.verified_cert->intermediate_buffers();
   ASSERT_EQ(2U, return_intermediates.size());
-  EXPECT_TRUE(X509Certificate::IsSameOSCert(return_intermediates[0],
-                                            certs[1]->os_cert_handle()));
-  EXPECT_TRUE(X509Certificate::IsSameOSCert(return_intermediates[1],
-                                            certs[2]->os_cert_handle()));
+  EXPECT_TRUE(x509_util::CryptoBufferEqual(return_intermediates[0].get(),
+                                           certs[1]->cert_buffer()));
+  EXPECT_TRUE(x509_util::CryptoBufferEqual(return_intermediates[1].get(),
+                                           certs[2]->cert_buffer()));
 }
 
 // Test that certificates issued for 'intranet' names (that is, containing no
@@ -1555,38 +1563,37 @@
   ASSERT_EQ(3U, certs.size());
 
   // Construct the chain out of order.
-  X509Certificate::OSCertHandles intermediates;
-  intermediates.push_back(certs[2]->os_cert_handle());
-  intermediates.push_back(certs[1]->os_cert_handle());
+  std::vector<bssl::UniquePtr<CRYPTO_BUFFER>> intermediates;
+  intermediates.push_back(x509_util::DupCryptoBuffer(certs[2]->cert_buffer()));
+  intermediates.push_back(x509_util::DupCryptoBuffer(certs[1]->cert_buffer()));
 
   ScopedTestRoot scoped_root(certs[2].get());
 
   scoped_refptr<X509Certificate> google_full_chain =
-      X509Certificate::CreateFromHandle(certs[0]->os_cert_handle(),
-                                        intermediates);
-  ASSERT_NE(static_cast<X509Certificate*>(NULL), google_full_chain.get());
-  ASSERT_EQ(2U, google_full_chain->GetIntermediateCertificates().size());
+      X509Certificate::CreateFromBuffer(
+          x509_util::DupCryptoBuffer(certs[0]->cert_buffer()),
+          std::move(intermediates));
+  ASSERT_TRUE(google_full_chain);
+  ASSERT_EQ(2U, google_full_chain->intermediate_buffers().size());
 
   CertVerifyResult verify_result;
-  EXPECT_EQ(static_cast<X509Certificate*>(NULL),
-            verify_result.verified_cert.get());
+  EXPECT_FALSE(verify_result.verified_cert);
   int error = Verify(google_full_chain.get(), "127.0.0.1", 0, NULL,
                      CertificateList(), &verify_result);
   EXPECT_THAT(error, IsOk());
-  ASSERT_NE(static_cast<X509Certificate*>(NULL),
-            verify_result.verified_cert.get());
+  ASSERT_TRUE(verify_result.verified_cert);
 
   EXPECT_NE(google_full_chain, verify_result.verified_cert);
-  EXPECT_TRUE(X509Certificate::IsSameOSCert(
-      google_full_chain->os_cert_handle(),
-      verify_result.verified_cert->os_cert_handle()));
-  const X509Certificate::OSCertHandles& return_intermediates =
-      verify_result.verified_cert->GetIntermediateCertificates();
+  EXPECT_TRUE(
+      x509_util::CryptoBufferEqual(google_full_chain->cert_buffer(),
+                                   verify_result.verified_cert->cert_buffer()));
+  const auto& return_intermediates =
+      verify_result.verified_cert->intermediate_buffers();
   ASSERT_EQ(2U, return_intermediates.size());
-  EXPECT_TRUE(X509Certificate::IsSameOSCert(return_intermediates[0],
-                                            certs[1]->os_cert_handle()));
-  EXPECT_TRUE(X509Certificate::IsSameOSCert(return_intermediates[1],
-                                            certs[2]->os_cert_handle()));
+  EXPECT_TRUE(x509_util::CryptoBufferEqual(return_intermediates[0].get(),
+                                           certs[1]->cert_buffer()));
+  EXPECT_TRUE(x509_util::CryptoBufferEqual(return_intermediates[1].get(),
+                                           certs[2]->cert_buffer()));
 }
 
 // Test that Verify() filters out certificates which are not related to
@@ -1611,38 +1618,39 @@
   ASSERT_NE(static_cast<X509Certificate*>(NULL), unrelated_certificate2.get());
 
   // Interject unrelated certificates into the list of intermediates.
-  X509Certificate::OSCertHandles intermediates;
-  intermediates.push_back(unrelated_certificate->os_cert_handle());
-  intermediates.push_back(certs[1]->os_cert_handle());
-  intermediates.push_back(unrelated_certificate2->os_cert_handle());
-  intermediates.push_back(certs[2]->os_cert_handle());
+  std::vector<bssl::UniquePtr<CRYPTO_BUFFER>> intermediates;
+  intermediates.push_back(
+      x509_util::DupCryptoBuffer(unrelated_certificate->cert_buffer()));
+  intermediates.push_back(x509_util::DupCryptoBuffer(certs[1]->cert_buffer()));
+  intermediates.push_back(
+      x509_util::DupCryptoBuffer(unrelated_certificate2->cert_buffer()));
+  intermediates.push_back(x509_util::DupCryptoBuffer(certs[2]->cert_buffer()));
 
   scoped_refptr<X509Certificate> google_full_chain =
-      X509Certificate::CreateFromHandle(certs[0]->os_cert_handle(),
-                                        intermediates);
-  ASSERT_NE(static_cast<X509Certificate*>(NULL), google_full_chain.get());
-  ASSERT_EQ(4U, google_full_chain->GetIntermediateCertificates().size());
+      X509Certificate::CreateFromBuffer(
+          x509_util::DupCryptoBuffer(certs[0]->cert_buffer()),
+          std::move(intermediates));
+  ASSERT_TRUE(google_full_chain);
+  ASSERT_EQ(4U, google_full_chain->intermediate_buffers().size());
 
   CertVerifyResult verify_result;
-  EXPECT_EQ(static_cast<X509Certificate*>(NULL),
-            verify_result.verified_cert.get());
+  EXPECT_FALSE(verify_result.verified_cert);
   int error = Verify(google_full_chain.get(), "127.0.0.1", 0, NULL,
                      CertificateList(), &verify_result);
   EXPECT_THAT(error, IsOk());
-  ASSERT_NE(static_cast<X509Certificate*>(NULL),
-            verify_result.verified_cert.get());
+  ASSERT_TRUE(verify_result.verified_cert);
 
   EXPECT_NE(google_full_chain, verify_result.verified_cert);
-  EXPECT_TRUE(X509Certificate::IsSameOSCert(
-      google_full_chain->os_cert_handle(),
-      verify_result.verified_cert->os_cert_handle()));
-  const X509Certificate::OSCertHandles& return_intermediates =
-      verify_result.verified_cert->GetIntermediateCertificates();
+  EXPECT_TRUE(
+      x509_util::CryptoBufferEqual(google_full_chain->cert_buffer(),
+                                   verify_result.verified_cert->cert_buffer()));
+  const auto& return_intermediates =
+      verify_result.verified_cert->intermediate_buffers();
   ASSERT_EQ(2U, return_intermediates.size());
-  EXPECT_TRUE(X509Certificate::IsSameOSCert(return_intermediates[0],
-                                            certs[1]->os_cert_handle()));
-  EXPECT_TRUE(X509Certificate::IsSameOSCert(return_intermediates[1],
-                                            certs[2]->os_cert_handle()));
+  EXPECT_TRUE(x509_util::CryptoBufferEqual(return_intermediates[0].get(),
+                                           certs[1]->cert_buffer()));
+  EXPECT_TRUE(x509_util::CryptoBufferEqual(return_intermediates[1].get(),
+                                           certs[2]->cert_buffer()));
 }
 
 TEST_P(CertVerifyProcInternalTest, AdditionalTrustAnchors) {
@@ -1781,16 +1789,18 @@
       GetTestCertsDirectory(), "intermediate_ca_cert.pem",
       X509Certificate::FORMAT_AUTO);
   ASSERT_EQ(1U, intermediate_cert_list.size());
-  X509Certificate::OSCertHandles intermediates;
-  intermediates.push_back(intermediate_cert_list[0]->os_cert_handle());
+  std::vector<bssl::UniquePtr<CRYPTO_BUFFER>> intermediates;
+  intermediates.push_back(
+      x509_util::DupCryptoBuffer(intermediate_cert_list[0]->cert_buffer()));
 
   CertificateList cert_list = CreateCertificateListFromFile(
       GetTestCertsDirectory(), "ok_cert_by_intermediate.pem",
       X509Certificate::FORMAT_AUTO);
   ASSERT_EQ(1U, cert_list.size());
 
-  scoped_refptr<X509Certificate> leaf = X509Certificate::CreateFromHandle(
-      cert_list[0]->os_cert_handle(), intermediates);
+  scoped_refptr<X509Certificate> leaf = X509Certificate::CreateFromBuffer(
+      x509_util::DupCryptoBuffer(cert_list[0]->cert_buffer()),
+      std::move(intermediates));
   ASSERT_TRUE(leaf);
 
   int flags = 0;
@@ -1860,14 +1870,20 @@
   // that they're ignored if not necessary.
   // This is to avoid relying on AIA or internal object caches when
   // interacting with the underlying library.
-  X509Certificate::OSCertHandles intermediates;
-  intermediates.push_back(path_1_certs[1]->os_cert_handle());  // B-by-C
-  intermediates.push_back(path_1_certs[2]->os_cert_handle());  // C-by-D
-  intermediates.push_back(path_2_certs[2]->os_cert_handle());  // C-by-E
-  intermediates.push_back(path_3_certs[1]->os_cert_handle());  // B-by-F
-  intermediates.push_back(path_3_certs[2]->os_cert_handle());  // F-by-E
-  scoped_refptr<X509Certificate> cert = X509Certificate::CreateFromHandle(
-      path_1_certs[0]->os_cert_handle(), intermediates);
+  std::vector<bssl::UniquePtr<CRYPTO_BUFFER>> intermediates;
+  intermediates.push_back(
+      x509_util::DupCryptoBuffer(path_1_certs[1]->cert_buffer()));  // B-by-C
+  intermediates.push_back(
+      x509_util::DupCryptoBuffer(path_1_certs[2]->cert_buffer()));  // C-by-D
+  intermediates.push_back(
+      x509_util::DupCryptoBuffer(path_2_certs[2]->cert_buffer()));  // C-by-E
+  intermediates.push_back(
+      x509_util::DupCryptoBuffer(path_3_certs[1]->cert_buffer()));  // B-by-F
+  intermediates.push_back(
+      x509_util::DupCryptoBuffer(path_3_certs[2]->cert_buffer()));  // F-by-E
+  scoped_refptr<X509Certificate> cert = X509Certificate::CreateFromBuffer(
+      x509_util::DupCryptoBuffer(path_1_certs[0]->cert_buffer()),
+      std::move(intermediates));
   ASSERT_TRUE(cert);
 
   struct TestPermutations {
@@ -1907,13 +1923,13 @@
     if (!testcase.expected_intermediate)
       continue;
 
-    const X509Certificate::OSCertHandles& verified_intermediates =
-        verify_result.verified_cert->GetIntermediateCertificates();
+    const auto& verified_intermediates =
+        verify_result.verified_cert->intermediate_buffers();
     ASSERT_EQ(3U, verified_intermediates.size());
 
     scoped_refptr<X509Certificate> intermediate =
-        X509Certificate::CreateFromHandle(verified_intermediates[1],
-                                          X509Certificate::OSCertHandles());
+        X509Certificate::CreateFromBuffer(
+            x509_util::DupCryptoBuffer(verified_intermediates[1].get()), {});
     ASSERT_TRUE(intermediate);
 
     EXPECT_TRUE(testcase.expected_intermediate->Equals(intermediate.get()))
@@ -2113,31 +2129,32 @@
   WeakDigestTestData data = GetParam();
   base::FilePath certs_dir = GetTestCertsDirectory();
 
-  scoped_refptr<X509Certificate> intermediate_cert;
-  scoped_refptr<X509Certificate> root_cert;
-
   // Build |intermediates| as the full chain (including trust anchor).
-  X509Certificate::OSCertHandles intermediates;
+  std::vector<bssl::UniquePtr<CRYPTO_BUFFER>> intermediates;
 
   if (data.intermediate_cert_filename) {
-    intermediate_cert =
+    scoped_refptr<X509Certificate> intermediate_cert =
         ImportCertFromFile(certs_dir, data.intermediate_cert_filename);
     ASSERT_TRUE(intermediate_cert);
-    intermediates.push_back(intermediate_cert->os_cert_handle());
+    intermediates.push_back(
+        x509_util::DupCryptoBuffer(intermediate_cert->cert_buffer()));
   }
 
   if (data.root_cert_filename) {
-    root_cert = ImportCertFromFile(certs_dir, data.root_cert_filename);
+    scoped_refptr<X509Certificate> root_cert =
+        ImportCertFromFile(certs_dir, data.root_cert_filename);
     ASSERT_TRUE(root_cert);
-    intermediates.push_back(root_cert->os_cert_handle());
+    intermediates.push_back(
+        x509_util::DupCryptoBuffer(root_cert->cert_buffer()));
   }
 
   scoped_refptr<X509Certificate> ee_cert =
       ImportCertFromFile(certs_dir, data.ee_cert_filename);
   ASSERT_TRUE(ee_cert);
 
-  scoped_refptr<X509Certificate> ee_chain = X509Certificate::CreateFromHandle(
-      ee_cert->os_cert_handle(), intermediates);
+  scoped_refptr<X509Certificate> ee_chain = X509Certificate::CreateFromBuffer(
+      x509_util::DupCryptoBuffer(ee_cert->cert_buffer()),
+      std::move(intermediates));
   ASSERT_TRUE(ee_chain);
 
   int flags = 0;
diff --git a/net/cert/cert_verify_result.h b/net/cert/cert_verify_result.h
index 5077e2f..43c88b9 100644
--- a/net/cert/cert_verify_result.h
+++ b/net/cert/cert_verify_result.h
@@ -31,7 +31,7 @@
   // The certificate chain that was constructed during verification.
   //
   // Note: Although |verified_cert| will match the originally supplied
-  // certificate to be validated, the results of GetIntermediateCertificates()
+  // certificate to be validated, the results of intermediate_buffers()
   // may be substantially different, both in order and in content, then the
   // originally supplied intermediates.
   //
@@ -40,9 +40,9 @@
   // the implementation.
   //
   // In the event of validation success, the trust anchor will be
-  // |verified_cert->GetIntermediateCertificates().back()| if
+  // |verified_cert->intermediate_buffers().back()| if
   // there was a certificate chain to the trust anchor, and will
-  // be |verified_cert->os_cert_handle()| if the certificate was
+  // be |verified_cert->cert_buffer()| if the certificate was
   // the trust anchor.
   scoped_refptr<X509Certificate> verified_cert;
 
diff --git a/net/cert/crl_set_unittest.cc b/net/cert/crl_set_unittest.cc
index 49e1ae3..756a06eb 100644
--- a/net/cert/crl_set_unittest.cc
+++ b/net/cert/crl_set_unittest.cc
@@ -2,12 +2,14 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "net/cert/crl_set.h"
+
 #include "base/files/file_util.h"
 #include "crypto/sha2.h"
 #include "net/cert/asn1_util.h"
-#include "net/cert/crl_set.h"
 #include "net/cert/crl_set_storage.h"
 #include "net/cert/x509_certificate.h"
+#include "net/cert/x509_util.h"
 #include "net/test/cert_test_util.h"
 #include "net/test/test_data_directory.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -335,9 +337,8 @@
   scoped_refptr<X509Certificate> root = CreateCertificateChainFromFile(
       GetTestCertsDirectory(), "root_ca_cert.pem",
       X509Certificate::FORMAT_AUTO);
-  std::string root_der;
-  ASSERT_TRUE(
-      X509Certificate::GetDEREncoded(root->os_cert_handle(), &root_der));
+  base::StringPiece root_der =
+      net::x509_util::CryptoBufferAsStringPiece(root->cert_buffer());
 
   base::StringPiece spki;
   ASSERT_TRUE(asn1::ExtractSPKIFromDERCert(root_der, &spki));
diff --git a/net/cert/ct_objects_extractor.cc b/net/cert/ct_objects_extractor.cc
index 25c8219..055fbdb 100644
--- a/net/cert/ct_objects_extractor.cc
+++ b/net/cert/ct_objects_extractor.cc
@@ -12,6 +12,7 @@
 #include "crypto/sha2.h"
 #include "net/cert/asn1_util.h"
 #include "net/cert/signed_certificate_timestamp.h"
+#include "net/cert/x509_util.h"
 #include "third_party/boringssl/src/include/openssl/bytestring.h"
 #include "third_party/boringssl/src/include/openssl/mem.h"
 
@@ -174,15 +175,12 @@
 // |*out_single_response| to the body of the SingleResponse starting at the
 // |certStatus| field.
 bool FindMatchingSingleResponse(CBS* responses,
-                                X509Certificate::OSCertHandle issuer,
+                                const CRYPTO_BUFFER* issuer,
                                 const std::string& cert_serial_number,
                                 CBS* out_single_response) {
-  std::string issuer_der;
-  if (!X509Certificate::GetDEREncoded(issuer, &issuer_der))
-    return false;
-
   base::StringPiece issuer_spki;
-  if (!asn1::ExtractSPKIFromDERCert(issuer_der, &issuer_spki))
+  if (!asn1::ExtractSPKIFromDERCert(
+          x509_util::CryptoBufferAsStringPiece(issuer), &issuer_spki))
     return false;
 
   // In OCSP, only the key itself is under hash.
@@ -245,13 +243,9 @@
 
 }  // namespace
 
-bool ExtractEmbeddedSCTList(X509Certificate::OSCertHandle cert,
-                            std::string* sct_list) {
-  std::string der;
-  if (!X509Certificate::GetDEREncoded(cert, &der))
-    return false;
+bool ExtractEmbeddedSCTList(const CRYPTO_BUFFER* cert, std::string* sct_list) {
   CBS cert_cbs;
-  CBS_init(&cert_cbs, reinterpret_cast<const uint8_t*>(der.data()), der.size());
+  CBS_init(&cert_cbs, CRYPTO_BUFFER_data(cert), CRYPTO_BUFFER_len(cert));
   CBS cert_body, tbs_cert, extensions_wrap, extensions;
   if (!CBS_get_asn1(&cert_cbs, &cert_body, CBS_ASN1_SEQUENCE) ||
       CBS_len(&cert_cbs) != 0 ||
@@ -269,19 +263,14 @@
                                     sizeof(kEmbeddedSCTOid), sct_list);
 }
 
-bool GetPrecertSignedEntry(X509Certificate::OSCertHandle leaf,
-                           X509Certificate::OSCertHandle issuer,
+bool GetPrecertSignedEntry(const CRYPTO_BUFFER* leaf,
+                           const CRYPTO_BUFFER* issuer,
                            SignedEntryData* result) {
   result->Reset();
 
-  std::string leaf_der;
-  if (!X509Certificate::GetDEREncoded(leaf, &leaf_der))
-    return false;
-
   // Parse the TBSCertificate.
   CBS cert_cbs;
-  CBS_init(&cert_cbs, reinterpret_cast<const uint8_t*>(leaf_der.data()),
-           leaf_der.size());
+  CBS_init(&cert_cbs, CRYPTO_BUFFER_data(leaf), CRYPTO_BUFFER_len(leaf));
   CBS cert_body, tbs_cert;
   if (!CBS_get_asn1(&cert_cbs, &cert_body, CBS_ASN1_SEQUENCE) ||
       CBS_len(&cert_cbs) != 0 ||
@@ -336,10 +325,9 @@
   bssl::UniquePtr<uint8_t> scoped_new_tbs_cert_der(new_tbs_cert_der);
 
   // Extract the issuer's public key.
-  std::string issuer_der;
   base::StringPiece issuer_key;
-  if (!X509Certificate::GetDEREncoded(issuer, &issuer_der) ||
-      !asn1::ExtractSPKIFromDERCert(issuer_der, &issuer_key)) {
+  if (!asn1::ExtractSPKIFromDERCert(
+          x509_util::CryptoBufferAsStringPiece(issuer), &issuer_key)) {
     return false;
   }
 
@@ -353,21 +341,17 @@
   return true;
 }
 
-bool GetX509SignedEntry(X509Certificate::OSCertHandle leaf,
-                        SignedEntryData* result) {
+bool GetX509SignedEntry(const CRYPTO_BUFFER* leaf, SignedEntryData* result) {
   DCHECK(leaf);
 
-  std::string encoded;
-  if (!X509Certificate::GetDEREncoded(leaf, &encoded))
-    return false;
-
   result->Reset();
   result->type = ct::SignedEntryData::LOG_ENTRY_TYPE_X509;
-  result->leaf_certificate.swap(encoded);
+  result->leaf_certificate =
+      std::string(x509_util::CryptoBufferAsStringPiece(leaf));
   return true;
 }
 
-bool ExtractSCTListFromOCSPResponse(X509Certificate::OSCertHandle issuer,
+bool ExtractSCTListFromOCSPResponse(const CRYPTO_BUFFER* issuer,
                                     const std::string& cert_serial_number,
                                     base::StringPiece ocsp_response,
                                     std::string* sct_list) {
diff --git a/net/cert/ct_objects_extractor.h b/net/cert/ct_objects_extractor.h
index 469e315..e18a84a 100644
--- a/net/cert/ct_objects_extractor.h
+++ b/net/cert/ct_objects_extractor.h
@@ -22,9 +22,8 @@
 // If the extension is present, returns true, updating |*sct_list| to contain
 // the encoded list, minus the DER encoding necessary for the extension.
 // |*sct_list| can then be further decoded with ct::DecodeSCTList
-NET_EXPORT_PRIVATE bool ExtractEmbeddedSCTList(
-    X509Certificate::OSCertHandle cert,
-    std::string* sct_list);
+NET_EXPORT_PRIVATE bool ExtractEmbeddedSCTList(const CRYPTO_BUFFER* cert,
+                                               std::string* sct_list);
 
 // Obtains a PrecertChain log entry for |leaf|, an X.509v3 certificate that
 // contains an X.509v3 extension with the OID 1.3.6.1.4.1.11129.2.4.2. On
@@ -33,10 +32,9 @@
 // The filled |*result| should be verified using ct::CTLogVerifier::Verify
 // Note: If |leaf| does not contain the required extension, it is treated as
 // a failure.
-NET_EXPORT_PRIVATE bool GetPrecertSignedEntry(
-    X509Certificate::OSCertHandle leaf,
-    X509Certificate::OSCertHandle issuer,
-    SignedEntryData* result);
+NET_EXPORT_PRIVATE bool GetPrecertSignedEntry(const CRYPTO_BUFFER* leaf,
+                                              const CRYPTO_BUFFER* issuer,
+                                              SignedEntryData* result);
 
 // Obtains an X509Chain log entry for |leaf|, an X.509v3 certificate that
 // is not expected to contain an X.509v3 extension with the OID
@@ -44,7 +42,7 @@
 // On success, fills |result| with the data for an X509Chain log entry and
 // returns true.
 // The filled |*result| should be verified using ct::CTLogVerifier::Verify
-NET_EXPORT_PRIVATE bool GetX509SignedEntry(X509Certificate::OSCertHandle leaf,
+NET_EXPORT_PRIVATE bool GetX509SignedEntry(const CRYPTO_BUFFER* leaf,
                                            SignedEntryData* result);
 
 // Extracts a SignedCertificateTimestampList that has been embedded within
@@ -54,7 +52,7 @@
 // the encoded list, minus the DER encoding necessary for the extension.
 // |*sct_list| can then be further decoded with ct::DecodeSCTList.
 NET_EXPORT_PRIVATE bool ExtractSCTListFromOCSPResponse(
-    X509Certificate::OSCertHandle issuer,
+    const CRYPTO_BUFFER* issuer,
     const std::string& cert_serial_number,
     base::StringPiece ocsp_response,
     std::string* sct_list);
diff --git a/net/cert/ct_objects_extractor_unittest.cc b/net/cert/ct_objects_extractor_unittest.cc
index 846dd62..8152d023 100644
--- a/net/cert/ct_objects_extractor_unittest.cc
+++ b/net/cert/ct_objects_extractor_unittest.cc
@@ -40,7 +40,7 @@
   void ExtractEmbeddedSCT(scoped_refptr<X509Certificate> cert,
                           scoped_refptr<SignedCertificateTimestamp>* sct) {
     std::string sct_list;
-    ASSERT_TRUE(ExtractEmbeddedSCTList(cert->os_cert_handle(), &sct_list));
+    ASSERT_TRUE(ExtractEmbeddedSCTList(cert->cert_buffer(), &sct_list));
 
     std::vector<base::StringPiece> parsed_scts;
     // Make sure the SCT list can be decoded properly
@@ -73,9 +73,8 @@
 
 TEST_F(CTObjectsExtractorTest, ExtractPrecert) {
   SignedEntryData entry;
-  ASSERT_TRUE(GetPrecertSignedEntry(precert_chain_[0]->os_cert_handle(),
-                                    precert_chain_[1]->os_cert_handle(),
-                                    &entry));
+  ASSERT_TRUE(GetPrecertSignedEntry(precert_chain_[0]->cert_buffer(),
+                                    precert_chain_[1]->cert_buffer(), &entry));
 
   ASSERT_EQ(ct::SignedEntryData::LOG_ENTRY_TYPE_PRECERT, entry.type);
   // Should have empty leaf cert for this log entry type.
@@ -88,7 +87,7 @@
 
 TEST_F(CTObjectsExtractorTest, ExtractOrdinaryX509Cert) {
   SignedEntryData entry;
-  ASSERT_TRUE(GetX509SignedEntry(test_cert_->os_cert_handle(), &entry));
+  ASSERT_TRUE(GetX509SignedEntry(test_cert_->cert_buffer(), &entry));
 
   ASSERT_EQ(ct::SignedEntryData::LOG_ENTRY_TYPE_X509, entry.type);
   // Should have empty tbs_certificate for this log entry type.
@@ -104,9 +103,8 @@
   ExtractEmbeddedSCT(precert_chain_[0], &sct);
 
   SignedEntryData entry;
-  ASSERT_TRUE(GetPrecertSignedEntry(precert_chain_[0]->os_cert_handle(),
-                                    precert_chain_[1]->os_cert_handle(),
-                                    &entry));
+  ASSERT_TRUE(GetPrecertSignedEntry(precert_chain_[0]->cert_buffer(),
+                                    precert_chain_[1]->cert_buffer(), &entry));
 
   EXPECT_TRUE(log_->Verify(entry, *sct.get()));
 }
@@ -119,7 +117,7 @@
   GetX509CertSCT(&sct);
 
   SignedEntryData entry;
-  ASSERT_TRUE(GetX509SignedEntry(test_cert_->os_cert_handle(), &entry));
+  ASSERT_TRUE(GetX509SignedEntry(test_cert_->cert_buffer(), &entry));
 
   EXPECT_TRUE(log_->Verify(entry, *sct.get()));
 }
@@ -143,8 +141,8 @@
 
   std::string extracted_sct_list;
   EXPECT_TRUE(ct::ExtractSCTListFromOCSPResponse(
-      issuer_cert->os_cert_handle(), subject_cert->serial_number(),
-      ocsp_response, &extracted_sct_list));
+      issuer_cert->cert_buffer(), subject_cert->serial_number(), ocsp_response,
+      &extracted_sct_list));
   EXPECT_EQ(extracted_sct_list, fake_sct_list);
 }
 
@@ -160,8 +158,8 @@
 
   std::string extracted_sct_list;
   EXPECT_FALSE(ct::ExtractSCTListFromOCSPResponse(
-      issuer_cert->os_cert_handle(), test_cert_->serial_number(),
-      ocsp_response, &extracted_sct_list));
+      issuer_cert->cert_buffer(), test_cert_->serial_number(), ocsp_response,
+      &extracted_sct_list));
 }
 
 // Test that the extractor honours issuer ID.
@@ -177,8 +175,8 @@
   std::string extracted_sct_list;
   // Use test_cert_ for issuer - it is not the correct issuer of |subject_cert|.
   EXPECT_FALSE(ct::ExtractSCTListFromOCSPResponse(
-      test_cert_->os_cert_handle(), subject_cert->serial_number(),
-      ocsp_response, &extracted_sct_list));
+      test_cert_->cert_buffer(), subject_cert->serial_number(), ocsp_response,
+      &extracted_sct_list));
 }
 
 }  // namespace ct
diff --git a/net/cert/internal/system_trust_store.cc b/net/cert/internal/system_trust_store.cc
index 5f0c724..f5c2b5f 100644
--- a/net/cert/internal/system_trust_store.cc
+++ b/net/cert/internal/system_trust_store.cc
@@ -175,8 +175,7 @@
     for (const auto& cert : certs) {
       CertErrors errors;
       auto parsed = ParsedCertificate::Create(
-          bssl::UniquePtr<CRYPTO_BUFFER>(
-              X509Certificate::DupOSCertHandle(cert->os_cert_handle())),
+          x509_util::DupCryptoBuffer(cert->cert_buffer()),
           x509_util::DefaultParseCertificateOptions(), &errors);
       CHECK(parsed) << errors.ToDebugString();
       system_trust_store_.AddTrustAnchor(parsed);
diff --git a/net/cert/internal/trust_store_mac.cc b/net/cert/internal/trust_store_mac.cc
index 0d78dd0..01b505d 100644
--- a/net/cert/internal/trust_store_mac.cc
+++ b/net/cert/internal/trust_store_mac.cc
@@ -347,7 +347,7 @@
       x509_util::CreateSecCertificateFromBytes(cert->der_cert().UnsafeData(),
                                                cert->der_cert().Length()));
   if (!cert_handle) {
-    LOG(ERROR) << "CreateOSCertHandleFromBytes";
+    LOG(ERROR) << "CreateCertBufferFromBytes";
     return name_data;
   }
   {
diff --git a/net/cert/internal/trust_store_mac_unittest.cc b/net/cert/internal/trust_store_mac_unittest.cc
index 70a3775a..04b3fbb 100644
--- a/net/cert/internal/trust_store_mac_unittest.cc
+++ b/net/cert/internal/trust_store_mac_unittest.cc
@@ -273,7 +273,7 @@
         x509_util::CreateSecCertificateFromBytes(cert->der_cert().UnsafeData(),
                                                  cert->der_cert().Length()));
     if (!cert_handle) {
-      ADD_FAILURE() << "CreateOSCertHandleFromBytes " << hash_text;
+      ADD_FAILURE() << "CreateCertBufferFromBytes " << hash_text;
       continue;
     }
     base::ScopedCFTypeRef<SecTrustRef> trust;
diff --git a/net/cert/merkle_tree_leaf.cc b/net/cert/merkle_tree_leaf.cc
index 07cd469..1030213 100644
--- a/net/cert/merkle_tree_leaf.cc
+++ b/net/cert/merkle_tree_leaf.cc
@@ -35,14 +35,14 @@
                        const SignedCertificateTimestamp* sct,
                        MerkleTreeLeaf* merkle_tree_leaf) {
   if (sct->origin == SignedCertificateTimestamp::SCT_EMBEDDED) {
-    if (cert->GetIntermediateCertificates().empty() ||
-        !GetPrecertSignedEntry(cert->os_cert_handle(),
-                               cert->GetIntermediateCertificates().front(),
+    if (cert->intermediate_buffers().empty() ||
+        !GetPrecertSignedEntry(cert->cert_buffer(),
+                               cert->intermediate_buffers().front().get(),
                                &merkle_tree_leaf->signed_entry)) {
       return false;
     }
   } else {
-    if (!GetX509SignedEntry(cert->os_cert_handle(),
+    if (!GetX509SignedEntry(cert->cert_buffer(),
                             &merkle_tree_leaf->signed_entry)) {
       return false;
     }
diff --git a/net/cert/merkle_tree_leaf_unittest.cc b/net/cert/merkle_tree_leaf_unittest.cc
index 59ac7dce..691c110 100644
--- a/net/cert/merkle_tree_leaf_unittest.cc
+++ b/net/cert/merkle_tree_leaf_unittest.cc
@@ -59,7 +59,7 @@
         GetTestCertsDirectory(), "ct-test-embedded-cert.pem",
         X509Certificate::FORMAT_AUTO);
     ASSERT_TRUE(test_precert_);
-    ASSERT_EQ(1u, test_precert_->GetIntermediateCertificates().size());
+    ASSERT_EQ(1u, test_precert_->intermediate_buffers().size());
     GetPrecertSCT(&precert_sct_);
     precert_sct_->origin = SignedCertificateTimestamp::SCT_EMBEDDED;
   }
diff --git a/net/cert/multi_log_ct_verifier.cc b/net/cert/multi_log_ct_verifier.cc
index 784924a..4a50beb 100644
--- a/net/cert/multi_log_ct_verifier.cc
+++ b/net/cert/multi_log_ct_verifier.cc
@@ -93,14 +93,12 @@
   output_scts->clear();
 
   std::string embedded_scts;
-  if (!cert->GetIntermediateCertificates().empty() &&
-      ct::ExtractEmbeddedSCTList(
-          cert->os_cert_handle(),
-          &embedded_scts)) {
+  if (!cert->intermediate_buffers().empty() &&
+      ct::ExtractEmbeddedSCTList(cert->cert_buffer(), &embedded_scts)) {
     ct::SignedEntryData precert_entry;
 
-    if (ct::GetPrecertSignedEntry(cert->os_cert_handle(),
-                                  cert->GetIntermediateCertificates().front(),
+    if (ct::GetPrecertSignedEntry(cert->cert_buffer(),
+                                  cert->intermediate_buffers().front().get(),
                                   &precert_entry)) {
       VerifySCTs(embedded_scts, precert_entry,
                  ct::SignedCertificateTimestamp::SCT_EMBEDDED, cert,
@@ -109,10 +107,9 @@
   }
 
   std::string sct_list_from_ocsp;
-  if (!stapled_ocsp_response.empty() &&
-      !cert->GetIntermediateCertificates().empty()) {
+  if (!stapled_ocsp_response.empty() && !cert->intermediate_buffers().empty()) {
     ct::ExtractSCTListFromOCSPResponse(
-        cert->GetIntermediateCertificates().front(), cert->serial_number(),
+        cert->intermediate_buffers().front().get(), cert->serial_number(),
         stapled_ocsp_response, &sct_list_from_ocsp);
   }
 
@@ -126,7 +123,7 @@
                    net_log_callback);
 
   ct::SignedEntryData x509_entry;
-  if (ct::GetX509SignedEntry(cert->os_cert_handle(), &x509_entry)) {
+  if (ct::GetX509SignedEntry(cert->cert_buffer(), &x509_entry)) {
     VerifySCTs(sct_list_from_ocsp, x509_entry,
                ct::SignedCertificateTimestamp::SCT_FROM_OCSP_RESPONSE, cert,
                output_scts);
diff --git a/net/cert/nss_cert_database_unittest.cc b/net/cert/nss_cert_database_unittest.cc
index d1753aef..46f34ce 100644
--- a/net/cert/nss_cert_database_unittest.cc
+++ b/net/cert/nss_cert_database_unittest.cc
@@ -383,7 +383,7 @@
   ASSERT_EQ(1U, failed.size());
   // Note: this compares pointers directly.  It's okay in this case because
   // ImportCACerts returns the same pointers that were passed in.  In the
-  // general case IsSameOSCert should be used.
+  // general case x509_util::CryptoBufferEqual should be used.
   EXPECT_EQ(certs[0], failed[0].certificate);
   EXPECT_THAT(failed[0].net_error, IsError(ERR_IMPORT_CA_CERT_NOT_CA));
 
diff --git a/net/cert/test_root_certs_android.cc b/net/cert/test_root_certs_android.cc
index 44cd1f9d..6160fa3 100644
--- a/net/cert/test_root_certs_android.cc
+++ b/net/cert/test_root_certs_android.cc
@@ -8,16 +8,14 @@
 #include "base/logging.h"
 #include "net/android/network_library.h"
 #include "net/cert/x509_certificate.h"
+#include "third_party/boringssl/src/include/openssl/pool.h"
 
 namespace net {
 
 bool TestRootCerts::Add(X509Certificate* certificate) {
-  std::string cert_bytes;
-  if (!X509Certificate::GetDEREncoded(certificate->os_cert_handle(),
-                                      &cert_bytes))
-      return false;
   android::AddTestRootCertificate(
-      reinterpret_cast<const uint8_t*>(cert_bytes.data()), cert_bytes.size());
+      CRYPTO_BUFFER_data(certificate->cert_buffer()),
+      CRYPTO_BUFFER_len(certificate->cert_buffer()));
   empty_ = false;
   return true;
 }
diff --git a/net/cert/test_root_certs_fuchsia.cc b/net/cert/test_root_certs_fuchsia.cc
index b0bd830..cd909be 100644
--- a/net/cert/test_root_certs_fuchsia.cc
+++ b/net/cert/test_root_certs_fuchsia.cc
@@ -9,6 +9,7 @@
 #include "net/cert/internal/cert_errors.h"
 #include "net/cert/internal/parsed_certificate.h"
 #include "net/cert/x509_certificate.h"
+#include "net/cert/x509_util.h"
 #include "third_party/boringssl/src/include/openssl/pool.h"
 
 namespace net {
@@ -16,8 +17,7 @@
 bool TestRootCerts::Add(X509Certificate* certificate) {
   CertErrors errors;
   auto parsed = ParsedCertificate::Create(
-      bssl::UniquePtr<CRYPTO_BUFFER>(
-          X509Certificate::DupOSCertHandle(certificate->os_cert_handle())),
+      x509_util::DupCryptoBuffer(certificate->cert_buffer()),
       ParseCertificateOptions(), &errors);
   if (!parsed) {
     LOG(ERROR) << "Failed to parse DER certificate: " << errors.ToDebugString();
diff --git a/net/cert/test_root_certs_mac.cc b/net/cert/test_root_certs_mac.cc
index 876395f..9e0206a 100644
--- a/net/cert/test_root_certs_mac.cc
+++ b/net/cert/test_root_certs_mac.cc
@@ -33,12 +33,8 @@
 
   // Add the certificate to the parallel |test_trust_store_|.
   CertErrors errors;
-  std::string cert_bytes;
-  if (!X509Certificate::GetDEREncoded(certificate->os_cert_handle(),
-                                      &cert_bytes))
-    return false;
   scoped_refptr<ParsedCertificate> parsed = ParsedCertificate::Create(
-      x509_util::CreateCryptoBuffer(cert_bytes),
+      x509_util::DupCryptoBuffer(certificate->cert_buffer()),
       x509_util::DefaultParseCertificateOptions(), &errors);
   if (!parsed)
     return false;
diff --git a/net/cert/test_root_certs_win.cc b/net/cert/test_root_certs_win.cc
index 3c900ca..8bf74cdab 100644
--- a/net/cert/test_root_certs_win.cc
+++ b/net/cert/test_root_certs_win.cc
@@ -11,6 +11,7 @@
 #include "base/numerics/safe_conversions.h"
 #include "base/win/win_util.h"
 #include "net/cert/x509_certificate.h"
+#include "third_party/boringssl/src/include/openssl/pool.h"
 
 namespace net {
 
@@ -143,12 +144,12 @@
   // happen.
   g_capi_injector.Get();
 
-  std::string der_cert;
-  X509Certificate::GetDEREncoded(certificate->os_cert_handle(), &der_cert);
   BOOL ok = CertAddEncodedCertificateToStore(
       temporary_roots_, X509_ASN_ENCODING,
-      reinterpret_cast<const BYTE*>(der_cert.data()),
-      base::checked_cast<DWORD>(der_cert.size()), CERT_STORE_ADD_NEW, NULL);
+      reinterpret_cast<const BYTE*>(
+          CRYPTO_BUFFER_data(certificate->cert_buffer())),
+      base::checked_cast<DWORD>(CRYPTO_BUFFER_len(certificate->cert_buffer())),
+      CERT_STORE_ADD_NEW, NULL);
   if (!ok) {
     // If the certificate is already added, return successfully.
     return GetLastError() == static_cast<DWORD>(CRYPT_E_EXISTS);
diff --git a/net/cert/x509_certificate.cc b/net/cert/x509_certificate.cc
index 370d4abb..454110f 100644
--- a/net/cert/x509_certificate.cc
+++ b/net/cert/x509_certificate.cc
@@ -145,10 +145,10 @@
 
 // Parses certificates from a PKCS#7 SignedData structure, appending them to
 // |handles|.
-void CreateOSCertHandlesFromPKCS7Bytes(
+void CreateCertBuffersFromPKCS7Bytes(
     const char* data,
     size_t length,
-    X509Certificate::OSCertHandles* handles) {
+    std::vector<bssl::UniquePtr<CRYPTO_BUFFER>>* handles) {
   crypto::EnsureOpenSSLInit();
   crypto::OpenSSLErrStackTracer err_cleaner(FROM_HERE);
 
@@ -159,7 +159,8 @@
   if (PKCS7_get_raw_certificates(certs, &der_data,
                                  x509_util::GetBufferPool())) {
     for (size_t i = 0; i < sk_CRYPTO_BUFFER_num(certs); ++i) {
-      handles->push_back(sk_CRYPTO_BUFFER_value(certs, i));
+      handles->push_back(
+          bssl::UniquePtr<CRYPTO_BUFFER>(sk_CRYPTO_BUFFER_value(certs, i)));
     }
   }
   // |handles| took ownership of the individual buffers, so only free the list
@@ -170,26 +171,26 @@
 }  // namespace
 
 // static
-scoped_refptr<X509Certificate> X509Certificate::CreateFromHandle(
-    OSCertHandle cert_handle,
-    const OSCertHandles& intermediates) {
-  DCHECK(cert_handle);
+scoped_refptr<X509Certificate> X509Certificate::CreateFromBuffer(
+    bssl::UniquePtr<CRYPTO_BUFFER> cert_buffer,
+    std::vector<bssl::UniquePtr<CRYPTO_BUFFER>> intermediates) {
+  DCHECK(cert_buffer);
   scoped_refptr<X509Certificate> cert(
-      new X509Certificate(cert_handle, intermediates));
-  if (!cert->os_cert_handle())
+      new X509Certificate(std::move(cert_buffer), std::move(intermediates)));
+  if (!cert->cert_buffer())
     return nullptr;  // Initialize() failed.
   return cert;
 }
 
 // static
-scoped_refptr<X509Certificate> X509Certificate::CreateFromHandleUnsafeOptions(
-    OSCertHandle cert_handle,
-    const OSCertHandles& intermediates,
+scoped_refptr<X509Certificate> X509Certificate::CreateFromBufferUnsafeOptions(
+    bssl::UniquePtr<CRYPTO_BUFFER> cert_buffer,
+    std::vector<bssl::UniquePtr<CRYPTO_BUFFER>> intermediates,
     UnsafeCreateOptions options) {
-  DCHECK(cert_handle);
-  scoped_refptr<X509Certificate> cert(
-      new X509Certificate(cert_handle, intermediates, options));
-  if (!cert->os_cert_handle())
+  DCHECK(cert_buffer);
+  scoped_refptr<X509Certificate> cert(new X509Certificate(
+      std::move(cert_buffer), std::move(intermediates), options));
+  if (!cert->cert_buffer())
     return nullptr;  // Initialize() failed.
   return cert;
 }
@@ -199,34 +200,28 @@
     const std::vector<base::StringPiece>& der_certs) {
   TRACE_EVENT0("io", "X509Certificate::CreateFromDERCertChain");
   if (der_certs.empty())
-    return NULL;
+    return nullptr;
 
-  X509Certificate::OSCertHandles intermediate_ca_certs;
+  std::vector<bssl::UniquePtr<CRYPTO_BUFFER>> intermediate_ca_certs;
+  intermediate_ca_certs.reserve(der_certs.size() - 1);
   for (size_t i = 1; i < der_certs.size(); i++) {
-    OSCertHandle handle = CreateOSCertHandleFromBytes(
+    bssl::UniquePtr<CRYPTO_BUFFER> handle = CreateCertBufferFromBytes(
         const_cast<char*>(der_certs[i].data()), der_certs[i].size());
     if (!handle)
       break;
-    intermediate_ca_certs.push_back(handle);
+    intermediate_ca_certs.push_back(std::move(handle));
   }
 
-  OSCertHandle handle = NULL;
   // Return NULL if we failed to parse any of the certs.
-  if (der_certs.size() - 1 == intermediate_ca_certs.size()) {
-    handle = CreateOSCertHandleFromBytes(
-        const_cast<char*>(der_certs[0].data()), der_certs[0].size());
-  }
+  if (der_certs.size() - 1 != intermediate_ca_certs.size())
+    return nullptr;
 
-  scoped_refptr<X509Certificate> cert = nullptr;
-  if (handle) {
-    cert = CreateFromHandle(handle, intermediate_ca_certs);
-    FreeOSCertHandle(handle);
-  }
+  bssl::UniquePtr<CRYPTO_BUFFER> handle = CreateCertBufferFromBytes(
+      const_cast<char*>(der_certs[0].data()), der_certs[0].size());
+  if (!handle)
+    return nullptr;
 
-  for (size_t i = 0; i < intermediate_ca_certs.size(); i++)
-    FreeOSCertHandle(intermediate_ca_certs[i]);
-
-  return cert;
+  return CreateFromBuffer(std::move(handle), std::move(intermediate_ca_certs));
 }
 
 // static
@@ -241,13 +236,13 @@
     const char* data,
     size_t length,
     UnsafeCreateOptions options) {
-  OSCertHandle cert_handle = CreateOSCertHandleFromBytes(data, length);
-  if (!cert_handle)
+  bssl::UniquePtr<CRYPTO_BUFFER> cert_buffer =
+      CreateCertBufferFromBytes(data, length);
+  if (!cert_buffer)
     return NULL;
 
   scoped_refptr<X509Certificate> cert =
-      CreateFromHandleUnsafeOptions(cert_handle, {}, options);
-  FreeOSCertHandle(cert_handle);
+      CreateFromBufferUnsafeOptions(std::move(cert_buffer), {}, options);
   return cert;
 }
 
@@ -274,7 +269,7 @@
     const char* data,
     size_t length,
     int format) {
-  OSCertHandles certificates;
+  std::vector<bssl::UniquePtr<CRYPTO_BUFFER>> certificates;
 
   // Check to see if it is in a PEM-encoded form. This check is performed
   // first, as both OS X and NSS will both try to convert if they detect
@@ -292,14 +287,14 @@
   while (pem_tokenizer.GetNext()) {
     std::string decoded(pem_tokenizer.data());
 
-    OSCertHandle handle = NULL;
+    bssl::UniquePtr<CRYPTO_BUFFER> handle;
     if (format & FORMAT_PEM_CERT_SEQUENCE)
-      handle = CreateOSCertHandleFromBytes(decoded.c_str(), decoded.size());
-    if (handle != NULL) {
+      handle = CreateCertBufferFromBytes(decoded.c_str(), decoded.size());
+    if (handle) {
       // Parsed a DER encoded certificate. All PEM blocks that follow must
       // also be DER encoded certificates wrapped inside of PEM blocks.
       format = FORMAT_PEM_CERT_SEQUENCE;
-      certificates.push_back(handle);
+      certificates.push_back(std::move(handle));
       continue;
     }
 
@@ -310,8 +305,8 @@
       for (size_t i = 0; certificates.empty() &&
            i < arraysize(kFormatDecodePriority); ++i) {
         if (format & kFormatDecodePriority[i]) {
-          certificates = CreateOSCertHandlesFromBytes(decoded.c_str(),
-              decoded.size(), kFormatDecodePriority[i]);
+          certificates = CreateCertBuffersFromBytes(
+              decoded.c_str(), decoded.size(), kFormatDecodePriority[i]);
         }
       }
     }
@@ -329,8 +324,8 @@
   for (size_t i = 0; certificates.empty() &&
        i < arraysize(kFormatDecodePriority); ++i) {
     if (format & kFormatDecodePriority[i])
-      certificates = CreateOSCertHandlesFromBytes(data, length,
-                                                  kFormatDecodePriority[i]);
+      certificates =
+          CreateCertBuffersFromBytes(data, length, kFormatDecodePriority[i]);
   }
 
   CertificateList results;
@@ -338,29 +333,28 @@
   if (certificates.empty())
     return results;
 
-  for (OSCertHandles::iterator it = certificates.begin();
-       it != certificates.end(); ++it) {
-    scoped_refptr<X509Certificate> cert =
-        CreateFromHandle(*it, OSCertHandles());
+  for (auto& it : certificates) {
+    scoped_refptr<X509Certificate> cert = CreateFromBuffer(std::move(it), {});
     if (cert)
       results.push_back(std::move(cert));
-    FreeOSCertHandle(*it);
   }
 
   return results;
 }
 
 void X509Certificate::Persist(base::Pickle* pickle) {
-  DCHECK(cert_handle_);
+  DCHECK(cert_buffer_);
   // This would be an absolutely insane number of intermediates.
   if (intermediate_ca_certs_.size() > static_cast<size_t>(INT_MAX) - 1) {
     NOTREACHED();
     return;
   }
   pickle->WriteInt(static_cast<int>(intermediate_ca_certs_.size() + 1));
-  pickle->WriteString(x509_util::CryptoBufferAsStringPiece(cert_handle_));
-  for (auto* intermediate : intermediate_ca_certs_)
-    pickle->WriteString(x509_util::CryptoBufferAsStringPiece(intermediate));
+  pickle->WriteString(x509_util::CryptoBufferAsStringPiece(cert_buffer_.get()));
+  for (const auto& intermediate : intermediate_ca_certs_) {
+    pickle->WriteString(
+        x509_util::CryptoBufferAsStringPiece(intermediate.get()));
+  }
 }
 
 void X509Certificate::GetDNSNames(std::vector<std::string>* dns_names) const {
@@ -380,8 +374,8 @@
   der::Input tbs_certificate_tlv;
   der::Input signature_algorithm_tlv;
   der::BitString signature_value;
-  if (!ParseCertificate(der::Input(CRYPTO_BUFFER_data(cert_handle_),
-                                   CRYPTO_BUFFER_len(cert_handle_)),
+  if (!ParseCertificate(der::Input(CRYPTO_BUFFER_data(cert_buffer_.get()),
+                                   CRYPTO_BUFFER_len(cert_buffer_.get())),
                         &tbs_certificate_tlv, &signature_algorithm_tlv,
                         &signature_value, nullptr)) {
     return false;
@@ -432,7 +426,8 @@
 }
 
 bool X509Certificate::Equals(const X509Certificate* other) const {
-  return IsSameOSCert(cert_handle_, other->cert_handle_);
+  return x509_util::CryptoBufferEqual(cert_buffer_.get(),
+                                      other->cert_buffer_.get());
 }
 
 bool X509Certificate::IsIssuedByEncoded(
@@ -450,13 +445,13 @@
   }
 
   std::string normalized_cert_issuer;
-  if (!GetNormalizedCertIssuer(cert_handle_, &normalized_cert_issuer))
+  if (!GetNormalizedCertIssuer(cert_buffer_.get(), &normalized_cert_issuer))
     return false;
   if (base::ContainsValue(normalized_issuers, normalized_cert_issuer))
     return true;
 
-  for (CRYPTO_BUFFER* intermediate : intermediate_ca_certs_) {
-    if (!GetNormalizedCertIssuer(intermediate, &normalized_cert_issuer))
+  for (const auto& intermediate : intermediate_ca_certs_) {
+    if (!GetNormalizedCertIssuer(intermediate.get(), &normalized_cert_issuer))
       return false;
     if (base::ContainsValue(normalized_issuers, normalized_cert_issuer))
       return true;
@@ -616,18 +611,7 @@
 }
 
 // static
-bool X509Certificate::GetDEREncoded(X509Certificate::OSCertHandle cert_handle,
-                                    std::string* encoded) {
-  if (!cert_handle)
-    return false;
-  encoded->assign(
-      reinterpret_cast<const char*>(CRYPTO_BUFFER_data(cert_handle)),
-      CRYPTO_BUFFER_len(cert_handle));
-  return true;
-}
-
-// static
-bool X509Certificate::GetPEMEncodedFromDER(const std::string& der_encoded,
+bool X509Certificate::GetPEMEncodedFromDER(base::StringPiece der_encoded,
                                            std::string* pem_encoded) {
   if (der_encoded.empty())
     return false;
@@ -649,23 +633,21 @@
 }
 
 // static
-bool X509Certificate::GetPEMEncoded(OSCertHandle cert_handle,
+bool X509Certificate::GetPEMEncoded(const CRYPTO_BUFFER* cert_buffer,
                                     std::string* pem_encoded) {
-  std::string der_encoded;
-  if (!GetDEREncoded(cert_handle, &der_encoded))
-    return false;
-  return GetPEMEncodedFromDER(der_encoded, pem_encoded);
+  return GetPEMEncodedFromDER(x509_util::CryptoBufferAsStringPiece(cert_buffer),
+                              pem_encoded);
 }
 
 bool X509Certificate::GetPEMEncodedChain(
     std::vector<std::string>* pem_encoded) const {
   std::vector<std::string> encoded_chain;
   std::string pem_data;
-  if (!GetPEMEncoded(os_cert_handle(), &pem_data))
+  if (!GetPEMEncoded(cert_buffer(), &pem_data))
     return false;
   encoded_chain.push_back(pem_data);
   for (size_t i = 0; i < intermediate_ca_certs_.size(); ++i) {
-    if (!GetPEMEncoded(intermediate_ca_certs_[i], &pem_data))
+    if (!GetPEMEncoded(intermediate_ca_certs_[i].get(), &pem_data))
       return false;
     encoded_chain.push_back(pem_data);
   }
@@ -674,7 +656,7 @@
 }
 
 // static
-void X509Certificate::GetPublicKeyInfo(OSCertHandle cert_handle,
+void X509Certificate::GetPublicKeyInfo(const CRYPTO_BUFFER* cert_buffer,
                                        size_t* size_bits,
                                        PublicKeyType* type) {
   *type = kPublicKeyTypeUnknown;
@@ -683,8 +665,8 @@
   base::StringPiece spki;
   if (!asn1::ExtractSPKIFromDERCert(
           base::StringPiece(
-              reinterpret_cast<const char*>(CRYPTO_BUFFER_data(cert_handle)),
-              CRYPTO_BUFFER_len(cert_handle)),
+              reinterpret_cast<const char*>(CRYPTO_BUFFER_data(cert_buffer)),
+              CRYPTO_BUFFER_len(cert_buffer)),
           &spki)) {
     return;
   }
@@ -715,18 +697,7 @@
 }
 
 // static
-bool X509Certificate::IsSameOSCert(X509Certificate::OSCertHandle a,
-                                   X509Certificate::OSCertHandle b) {
-  DCHECK(a && b);
-  if (a == b)
-    return true;
-  return CRYPTO_BUFFER_len(a) == CRYPTO_BUFFER_len(b) &&
-         memcmp(CRYPTO_BUFFER_data(a), CRYPTO_BUFFER_data(b),
-                CRYPTO_BUFFER_len(a)) == 0;
-}
-
-// static
-X509Certificate::OSCertHandle X509Certificate::CreateOSCertHandleFromBytes(
+bssl::UniquePtr<CRYPTO_BUFFER> X509Certificate::CreateCertBufferFromBytes(
     const char* data,
     size_t length) {
   der::Input tbs_certificate_tlv;
@@ -742,26 +713,27 @@
     return nullptr;
   }
 
-  return CRYPTO_BUFFER_new(reinterpret_cast<const uint8_t*>(data), length,
-                           x509_util::GetBufferPool());
+  return x509_util::CreateCryptoBuffer(reinterpret_cast<const uint8_t*>(data),
+                                       length);
 }
 
 // static
-X509Certificate::OSCertHandles X509Certificate::CreateOSCertHandlesFromBytes(
-    const char* data,
-    size_t length,
-    Format format) {
-  OSCertHandles results;
+std::vector<bssl::UniquePtr<CRYPTO_BUFFER>>
+X509Certificate::CreateCertBuffersFromBytes(const char* data,
+                                            size_t length,
+                                            Format format) {
+  std::vector<bssl::UniquePtr<CRYPTO_BUFFER>> results;
 
   switch (format) {
     case FORMAT_SINGLE_CERTIFICATE: {
-      OSCertHandle handle = CreateOSCertHandleFromBytes(data, length);
+      bssl::UniquePtr<CRYPTO_BUFFER> handle =
+          CreateCertBufferFromBytes(data, length);
       if (handle)
-        results.push_back(handle);
+        results.push_back(std::move(handle));
       break;
     }
     case FORMAT_PKCS7: {
-      CreateOSCertHandlesFromPKCS7Bytes(data, length, &results);
+      CreateCertBuffersFromPKCS7Bytes(data, length, &results);
       break;
     }
     default: {
@@ -774,19 +746,8 @@
 }
 
 // static
-X509Certificate::OSCertHandle X509Certificate::DupOSCertHandle(
-    OSCertHandle cert_handle) {
-  CRYPTO_BUFFER_up_ref(cert_handle);
-  return cert_handle;
-}
-
-// static
-void X509Certificate::FreeOSCertHandle(OSCertHandle cert_handle) {
-  CRYPTO_BUFFER_free(cert_handle);
-}
-
-// static
-SHA256HashValue X509Certificate::CalculateFingerprint256(OSCertHandle cert) {
+SHA256HashValue X509Certificate::CalculateFingerprint256(
+    const CRYPTO_BUFFER* cert) {
   SHA256HashValue sha256;
 
   SHA256(CRYPTO_BUFFER_data(cert), CRYPTO_BUFFER_len(cert), sha256.data);
@@ -799,11 +760,11 @@
 
   SHA256_CTX sha256_ctx;
   SHA256_Init(&sha256_ctx);
-  SHA256_Update(&sha256_ctx, CRYPTO_BUFFER_data(cert_handle_),
-                CRYPTO_BUFFER_len(cert_handle_));
-  for (CRYPTO_BUFFER* cert : intermediate_ca_certs_) {
-    SHA256_Update(&sha256_ctx, CRYPTO_BUFFER_data(cert),
-                  CRYPTO_BUFFER_len(cert));
+  SHA256_Update(&sha256_ctx, CRYPTO_BUFFER_data(cert_buffer_.get()),
+                CRYPTO_BUFFER_len(cert_buffer_.get()));
+  for (const auto& cert : intermediate_ca_certs_) {
+    SHA256_Update(&sha256_ctx, CRYPTO_BUFFER_data(cert.get()),
+                  CRYPTO_BUFFER_len(cert.get()));
   }
   SHA256_Final(sha256.data, &sha256_ctx);
 
@@ -811,12 +772,12 @@
 }
 
 // static
-bool X509Certificate::IsSelfSigned(OSCertHandle cert_handle) {
+bool X509Certificate::IsSelfSigned(const CRYPTO_BUFFER* cert_buffer) {
   der::Input tbs_certificate_tlv;
   der::Input signature_algorithm_tlv;
   der::BitString signature_value;
-  if (!ParseCertificate(der::Input(CRYPTO_BUFFER_data(cert_handle),
-                                   CRYPTO_BUFFER_len(cert_handle)),
+  if (!ParseCertificate(der::Input(CRYPTO_BUFFER_data(cert_buffer),
+                                   CRYPTO_BUFFER_len(cert_buffer)),
                         &tbs_certificate_tlv, &signature_algorithm_tlv,
                         &signature_value, nullptr)) {
     return false;
@@ -856,41 +817,33 @@
                           signature_value, tbs.spki_tlv);
 }
 
-X509Certificate::X509Certificate(OSCertHandle cert_handle,
-                                 const OSCertHandles& intermediates)
-    : X509Certificate(cert_handle, intermediates, {}) {}
+X509Certificate::X509Certificate(
+    bssl::UniquePtr<CRYPTO_BUFFER> cert_buffer,
+    std::vector<bssl::UniquePtr<CRYPTO_BUFFER>> intermediates)
+    : X509Certificate(std::move(cert_buffer), std::move(intermediates), {}) {}
 
-X509Certificate::X509Certificate(OSCertHandle cert_handle,
-                                 const OSCertHandles& intermediates,
-                                 UnsafeCreateOptions options)
-    : cert_handle_(DupOSCertHandle(cert_handle)) {
-  for (size_t i = 0; i < intermediates.size(); ++i) {
-    // Duplicate the incoming certificate, as the caller retains ownership
-    // of |intermediates|.
-    intermediate_ca_certs_.push_back(DupOSCertHandle(intermediates[i]));
-  }
+X509Certificate::X509Certificate(
+    bssl::UniquePtr<CRYPTO_BUFFER> cert_buffer,
+    std::vector<bssl::UniquePtr<CRYPTO_BUFFER>> intermediates,
+    UnsafeCreateOptions options)
+    : cert_buffer_(std::move(cert_buffer)),
+      intermediate_ca_certs_(std::move(intermediates)) {
   // Platform-specific initialization.
-  if (!Initialize(options) && cert_handle_) {
-    // Signal initialization failure by clearing cert_handle_.
-    FreeOSCertHandle(cert_handle_);
-    cert_handle_ = nullptr;
+  if (!Initialize(options) && cert_buffer_) {
+    // Signal initialization failure by clearing cert_buffer_.
+    cert_buffer_.reset();
   }
 }
 
-X509Certificate::~X509Certificate() {
-  if (cert_handle_)
-    FreeOSCertHandle(cert_handle_);
-  for (size_t i = 0; i < intermediate_ca_certs_.size(); ++i)
-    FreeOSCertHandle(intermediate_ca_certs_[i]);
-}
+X509Certificate::~X509Certificate() = default;
 
 bool X509Certificate::Initialize(UnsafeCreateOptions options) {
   der::Input tbs_certificate_tlv;
   der::Input signature_algorithm_tlv;
   der::BitString signature_value;
 
-  if (!ParseCertificate(der::Input(CRYPTO_BUFFER_data(cert_handle_),
-                                   CRYPTO_BUFFER_len(cert_handle_)),
+  if (!ParseCertificate(der::Input(CRYPTO_BUFFER_data(cert_buffer_.get()),
+                                   CRYPTO_BUFFER_len(cert_buffer_.get())),
                         &tbs_certificate_tlv, &signature_algorithm_tlv,
                         &signature_value, nullptr)) {
     return false;
diff --git a/net/cert/x509_certificate.h b/net/cert/x509_certificate.h
index 70cc20c..d52d8796 100644
--- a/net/cert/x509_certificate.h
+++ b/net/cert/x509_certificate.h
@@ -38,15 +38,6 @@
 class NET_EXPORT X509Certificate
     : public base::RefCountedThreadSafe<X509Certificate> {
  public:
-  // An OSCertHandle is a handle to a certificate object in the underlying
-  // crypto library. We assume that OSCertHandle is a pointer type on all
-  // platforms and that NULL represents an invalid OSCertHandle.
-  // TODO(mattm): Remove OSCertHandle type and clean up the interfaces once all
-  // platforms use the CRYPTO_BUFFER version.
-  typedef CRYPTO_BUFFER* OSCertHandle;
-
-  typedef std::vector<OSCertHandle> OSCertHandles;
-
   enum PublicKeyType {
     kPublicKeyTypeUnknown,
     kPublicKeyTypeRSA,
@@ -78,15 +69,15 @@
                   FORMAT_PKCS7,
   };
 
-  // Create an X509Certificate from a handle to the certificate object in the
-  // underlying crypto library. Returns NULL on failure to parse or extract
-  // data from the the certificate. Note that this does not guarantee the
-  // certificate is fully parsed and validated, only that the members of this
-  // class, such as subject, issuer, expiry times, and serial number, could be
-  // successfully initialized from the certificate.
-  static scoped_refptr<X509Certificate> CreateFromHandle(
-      OSCertHandle cert_handle,
-      const OSCertHandles& intermediates);
+  // Create an X509Certificate from a CRYPTO_BUFFER containing the DER-encoded
+  // representation. Returns NULL on failure to parse or extract data from the
+  // the certificate. Note that this does not guarantee the certificate is
+  // fully parsed and validated, only that the members of this class, such as
+  // subject, issuer, expiry times, and serial number, could be successfully
+  // initialized from the certificate.
+  static scoped_refptr<X509Certificate> CreateFromBuffer(
+      bssl::UniquePtr<CRYPTO_BUFFER> cert_buffer,
+      std::vector<bssl::UniquePtr<CRYPTO_BUFFER>> intermediates);
 
   // Options for configuring certificate parsing.
   // Do not use without consulting //net owners.
@@ -95,9 +86,9 @@
   };
   // Create an X509Certificate with non-standard parsing options.
   // Do not use without consulting //net owners.
-  static scoped_refptr<X509Certificate> CreateFromHandleUnsafeOptions(
-      OSCertHandle cert_handle,
-      const OSCertHandles& intermediates,
+  static scoped_refptr<X509Certificate> CreateFromBufferUnsafeOptions(
+      bssl::UniquePtr<CRYPTO_BUFFER> cert_buffer,
+      std::vector<bssl::UniquePtr<CRYPTO_BUFFER>> intermediates,
       UnsafeCreateOptions options);
 
   // Create an X509Certificate from a chain of DER encoded certificates. The
@@ -187,14 +178,6 @@
   // Does not consider any associated intermediates.
   bool Equals(const X509Certificate* other) const;
 
-  // Returns the associated intermediate certificates that were specified
-  // during creation of this object, if any.
-  // Ownership follows the "get" rule: it is the caller's responsibility to
-  // retain the elements of the result.
-  const OSCertHandles& GetIntermediateCertificates() const {
-    return intermediate_ca_certs_;
-  }
-
   // Do any of the given issuer names appear in this cert's chain of trust?
   // |valid_issuers| is a list of DER-encoded X.509 DistinguishedNames.
   bool IsIssuedByEncoded(const std::vector<std::string>& valid_issuers);
@@ -208,20 +191,15 @@
   bool VerifyNameMatch(const std::string& hostname,
                        bool allow_common_name_fallback) const;
 
-  // Obtains the DER encoded certificate data for |cert_handle|. On success,
-  // returns true and writes the DER encoded certificate to |*der_encoded|.
-  static bool GetDEREncoded(OSCertHandle cert_handle,
-                            std::string* der_encoded);
-
   // Returns the PEM encoded data from a DER encoded certificate. If the return
   // value is true, then the PEM encoded certificate is written to
   // |pem_encoded|.
-  static bool GetPEMEncodedFromDER(const std::string& der_encoded,
+  static bool GetPEMEncodedFromDER(base::StringPiece der_encoded,
                                    std::string* pem_encoded);
 
-  // Returns the PEM encoded data from an OSCertHandle. If the return value is
+  // Returns the PEM encoded data from a CRYPTO_BUFFER. If the return value is
   // true, then the PEM encoded certificate is written to |pem_encoded|.
-  static bool GetPEMEncoded(OSCertHandle cert_handle,
+  static bool GetPEMEncoded(const CRYPTO_BUFFER* cert_buffer,
                             std::string* pem_encoded);
 
   // Encodes the entire certificate chain (this certificate and any
@@ -234,40 +212,42 @@
   // Sets |*size_bits| to be the length of the public key in bits, and sets
   // |*type| to one of the |PublicKeyType| values. In case of
   // |kPublicKeyTypeUnknown|, |*size_bits| will be set to 0.
-  static void GetPublicKeyInfo(OSCertHandle cert_handle,
+  static void GetPublicKeyInfo(const CRYPTO_BUFFER* cert_buffer,
                                size_t* size_bits,
                                PublicKeyType* type);
 
-  // Returns the OSCertHandle of this object. Because of caching, this may
-  // differ from the OSCertHandle originally supplied during initialization.
-  // Note: On Windows, CryptoAPI may return unexpected results if this handle
-  // is used across multiple threads. For more details, see
-  // CreateOSCertChainForCert().
-  OSCertHandle os_cert_handle() const { return cert_handle_; }
+  // Returns the CRYPTO_BUFFER holding this certificate's DER encoded data. The
+  // data is not guaranteed to be valid DER or to encode a valid Certificate
+  // object.
+  CRYPTO_BUFFER* cert_buffer() const { return cert_buffer_.get(); }
 
-  // Returns true if two OSCertHandles refer to identical certificates.
-  static bool IsSameOSCert(OSCertHandle a, OSCertHandle b);
+  // Returns the associated intermediate certificates that were specified
+  // during creation of this object, if any. The intermediates are not
+  // guaranteed to be valid DER or to encode valid Certificate objects.
+  // Ownership follows the "get" rule: it is the caller's responsibility to
+  // retain the elements of the result.
+  const std::vector<bssl::UniquePtr<CRYPTO_BUFFER>>& intermediate_buffers()
+      const {
+    return intermediate_ca_certs_;
+  }
 
-  // Creates an OS certificate handle from the DER-encoded representation.
+  // Creates a CRYPTO_BUFFER from the DER-encoded representation. Unlike
+  // creating a CRYPTO_BUFFER directly, this function does some minimal
+  // checking to reject obviously invalid inputs.
   // Returns NULL on failure.
-  static OSCertHandle CreateOSCertHandleFromBytes(const char* data,
-                                                  size_t length);
+  static bssl::UniquePtr<CRYPTO_BUFFER> CreateCertBufferFromBytes(
+      const char* data,
+      size_t length);
 
-  // Creates all possible OS certificate handles from |data| encoded in a
-  // specific |format|. Returns an empty collection on failure.
-  static OSCertHandles CreateOSCertHandlesFromBytes(const char* data,
-                                                    size_t length,
-                                                    Format format);
-
-  // Duplicates (or adds a reference to) an OS certificate handle.
-  static OSCertHandle DupOSCertHandle(OSCertHandle cert_handle);
-
-  // Frees (or releases a reference to) an OS certificate handle.
-  static void FreeOSCertHandle(OSCertHandle cert_handle);
+  // Creates all possible CRYPTO_BUFFERs from |data| encoded in a specific
+  // |format|. Returns an empty collection on failure.
+  static std::vector<bssl::UniquePtr<CRYPTO_BUFFER>>
+  CreateCertBuffersFromBytes(const char* data, size_t length, Format format);
 
   // Calculates the SHA-256 fingerprint of the certificate.  Returns an empty
   // (all zero) fingerprint on failure.
-  static SHA256HashValue CalculateFingerprint256(OSCertHandle cert_handle);
+  static SHA256HashValue CalculateFingerprint256(
+      const CRYPTO_BUFFER* cert_buffer);
 
   // Calculates the SHA-256 fingerprint for the complete chain, including the
   // leaf certificate and all intermediate CA certificates. Returns an empty
@@ -275,7 +255,7 @@
   SHA256HashValue CalculateChainFingerprint256() const;
 
   // Returns true if the certificate is self-signed.
-  static bool IsSelfSigned(OSCertHandle cert_handle);
+  static bool IsSelfSigned(const CRYPTO_BUFFER* cert_buffer);
 
  private:
   friend class base::RefCountedThreadSafe<X509Certificate>;
@@ -284,12 +264,12 @@
   FRIEND_TEST_ALL_PREFIXES(X509CertificateNameVerifyTest, VerifyHostname);
   FRIEND_TEST_ALL_PREFIXES(X509CertificateTest, SerialNumbers);
 
-  // Construct an X509Certificate from a handle to the certificate object
-  // in the underlying crypto library.
-  X509Certificate(OSCertHandle cert_handle,
-                  const OSCertHandles& intermediates);
-  X509Certificate(OSCertHandle cert_handle,
-                  const OSCertHandles& intermediates,
+  // Construct an X509Certificate from a CRYPTO_BUFFER containing the
+  // DER-encoded representation.
+  X509Certificate(bssl::UniquePtr<CRYPTO_BUFFER> cert_buffer,
+                  std::vector<bssl::UniquePtr<CRYPTO_BUFFER>> intermediates);
+  X509Certificate(bssl::UniquePtr<CRYPTO_BUFFER> cert_buffer,
+                  std::vector<bssl::UniquePtr<CRYPTO_BUFFER>> intermediates,
                   UnsafeCreateOptions options);
 
   ~X509Certificate();
@@ -330,12 +310,12 @@
   // The serial number of this certificate, DER encoded.
   std::string serial_number_;
 
-  // A handle to the certificate object in the underlying crypto library.
-  OSCertHandle cert_handle_;
+  // A handle to the DER encoded certificate data.
+  bssl::UniquePtr<CRYPTO_BUFFER> cert_buffer_;
 
   // Untrusted intermediate certificates associated with this certificate
   // that may be needed for chain building.
-  OSCertHandles intermediate_ca_certs_;
+  std::vector<bssl::UniquePtr<CRYPTO_BUFFER>> intermediate_ca_certs_;
 
   DISALLOW_COPY_AND_ASSIGN(X509Certificate);
 };
diff --git a/net/cert/x509_certificate_unittest.cc b/net/cert/x509_certificate_unittest.cc
index a9cee29..76ba850 100644
--- a/net/cert/x509_certificate_unittest.cc
+++ b/net/cert/x509_certificate_unittest.cc
@@ -103,7 +103,7 @@
   EXPECT_EQ(valid_to, valid_expiry.ToDoubleT());
 
   EXPECT_EQ(expected_fingerprint, X509Certificate::CalculateFingerprint256(
-                                      google_cert->os_cert_handle()));
+                                      google_cert->cert_buffer()));
 
   std::vector<std::string> dns_names;
   google_cert->GetDNSNames(&dns_names);
@@ -284,13 +284,14 @@
       x509_util::CreateCryptoBuffer(cert_der);
   ASSERT_TRUE(cert_handle);
 
-  EXPECT_FALSE(X509Certificate::CreateFromHandle(cert_handle.get(), {}));
+  EXPECT_FALSE(X509Certificate::CreateFromBuffer(
+      x509_util::DupCryptoBuffer(cert_handle.get()), {}));
 
   X509Certificate::UnsafeCreateOptions options;
   options.printable_string_is_utf8 = true;
   scoped_refptr<X509Certificate> cert =
-      X509Certificate::CreateFromHandleUnsafeOptions(cert_handle.get(), {},
-                                                     options);
+      X509Certificate::CreateFromBufferUnsafeOptions(
+          x509_util::DupCryptoBuffer(cert_handle.get()), {}, options);
 
   const CertPrincipal& subject = cert->subject();
   EXPECT_EQ("Foo@#_ Clïênt Cërt", subject.common_name);
@@ -456,7 +457,7 @@
        0x7f, 0x77, 0x49, 0x38, 0x42, 0x81, 0x26, 0x7f, 0xed, 0x38}};
 
   EXPECT_EQ(google_sha256_fingerprint, X509Certificate::CalculateFingerprint256(
-                                           google_cert->os_cert_handle()));
+                                           google_cert->cert_buffer()));
 }
 
 TEST(X509CertificateTest, CAFingerprints) {
@@ -474,25 +475,30 @@
       ImportCertFromFile(certs_dir, "verisign_intermediate_ca_2016.pem");
   ASSERT_NE(static_cast<X509Certificate*>(NULL), intermediate_cert2.get());
 
-  X509Certificate::OSCertHandles intermediates;
-  intermediates.push_back(intermediate_cert1->os_cert_handle());
+  std::vector<bssl::UniquePtr<CRYPTO_BUFFER>> intermediates;
+  intermediates.push_back(
+      x509_util::DupCryptoBuffer(intermediate_cert1->cert_buffer()));
   scoped_refptr<X509Certificate> cert_chain1 =
-      X509Certificate::CreateFromHandle(server_cert->os_cert_handle(),
-                                        intermediates);
+      X509Certificate::CreateFromBuffer(
+          x509_util::DupCryptoBuffer(server_cert->cert_buffer()),
+          std::move(intermediates));
   ASSERT_TRUE(cert_chain1);
 
   intermediates.clear();
-  intermediates.push_back(intermediate_cert2->os_cert_handle());
+  intermediates.push_back(
+      x509_util::DupCryptoBuffer(intermediate_cert2->cert_buffer()));
   scoped_refptr<X509Certificate> cert_chain2 =
-      X509Certificate::CreateFromHandle(server_cert->os_cert_handle(),
-                                        intermediates);
+      X509Certificate::CreateFromBuffer(
+          x509_util::DupCryptoBuffer(server_cert->cert_buffer()),
+          std::move(intermediates));
   ASSERT_TRUE(cert_chain2);
 
   // No intermediate CA certicates.
   intermediates.clear();
   scoped_refptr<X509Certificate> cert_chain3 =
-      X509Certificate::CreateFromHandle(server_cert->os_cert_handle(),
-                                        intermediates);
+      X509Certificate::CreateFromBuffer(
+          x509_util::DupCryptoBuffer(server_cert->cert_buffer()),
+          std::move(intermediates));
   ASSERT_TRUE(cert_chain3);
 
   SHA256HashValue cert_chain1_chain_fingerprint_256 = {
@@ -576,12 +582,9 @@
       ImportCertFromFile(certs_dir, "nist.der");
   ASSERT_NE(static_cast<X509Certificate*>(NULL), cert.get());
 
-  std::string derBytes;
-  EXPECT_TRUE(X509Certificate::GetDEREncoded(cert->os_cert_handle(),
-                                             &derBytes));
-
   base::StringPiece spkiBytes;
-  EXPECT_TRUE(asn1::ExtractSPKIFromDERCert(derBytes, &spkiBytes));
+  EXPECT_TRUE(asn1::ExtractSPKIFromDERCert(
+      x509_util::CryptoBufferAsStringPiece(cert->cert_buffer()), &spkiBytes));
 
   uint8_t hash[base::kSHA1Length];
   base::SHA1HashBytes(reinterpret_cast<const uint8_t*>(spkiBytes.data()),
@@ -596,11 +599,8 @@
       ImportCertFromFile(certs_dir, "tls_feature_extension.pem");
   ASSERT_NE(static_cast<X509Certificate*>(NULL), cert.get());
 
-  std::string derBytes;
-  EXPECT_TRUE(
-      X509Certificate::GetDEREncoded(cert->os_cert_handle(), &derBytes));
-
-  EXPECT_TRUE(asn1::HasTLSFeatureExtension(derBytes));
+  EXPECT_TRUE(asn1::HasTLSFeatureExtension(
+      x509_util::CryptoBufferAsStringPiece(cert->cert_buffer())));
 }
 
 TEST(X509CertificateTest, DoesNotHaveTLSFeatureExtension) {
@@ -609,83 +609,79 @@
       ImportCertFromFile(certs_dir, "ok_cert.pem");
   ASSERT_NE(static_cast<X509Certificate*>(NULL), cert.get());
 
-  std::string derBytes;
-  EXPECT_TRUE(
-      X509Certificate::GetDEREncoded(cert->os_cert_handle(), &derBytes));
-
-  EXPECT_FALSE(asn1::HasTLSFeatureExtension(derBytes));
+  EXPECT_FALSE(asn1::HasTLSFeatureExtension(
+      x509_util::CryptoBufferAsStringPiece(cert->cert_buffer())));
 }
 
-// Tests OSCertHandle deduping via X509Certificate::CreateFromHandle.  We
-// call X509Certificate::CreateFromHandle several times and observe whether
-// it returns a cached or new OSCertHandle.
+// Tests CRYPTO_BUFFER deduping via X509Certificate::CreateFromBuffer.  We
+// call X509Certificate::CreateFromBuffer several times and observe whether
+// it returns a cached or new CRYPTO_BUFFER.
 TEST(X509CertificateTest, Cache) {
-  X509Certificate::OSCertHandle google_cert_handle;
-  X509Certificate::OSCertHandle thawte_cert_handle;
+  bssl::UniquePtr<CRYPTO_BUFFER> google_cert_handle;
+  bssl::UniquePtr<CRYPTO_BUFFER> thawte_cert_handle;
 
   // Add a single certificate to the certificate cache.
-  google_cert_handle = X509Certificate::CreateOSCertHandleFromBytes(
+  google_cert_handle = X509Certificate::CreateCertBufferFromBytes(
       reinterpret_cast<const char*>(google_der), sizeof(google_der));
-  scoped_refptr<X509Certificate> cert1(X509Certificate::CreateFromHandle(
-      google_cert_handle, X509Certificate::OSCertHandles()));
-  X509Certificate::FreeOSCertHandle(google_cert_handle);
+  ASSERT_TRUE(google_cert_handle);
+  scoped_refptr<X509Certificate> cert1(
+      X509Certificate::CreateFromBuffer(std::move(google_cert_handle), {}));
   ASSERT_TRUE(cert1);
 
   // Add the same certificate, but as a new handle.
-  google_cert_handle = X509Certificate::CreateOSCertHandleFromBytes(
+  google_cert_handle = X509Certificate::CreateCertBufferFromBytes(
       reinterpret_cast<const char*>(google_der), sizeof(google_der));
-  scoped_refptr<X509Certificate> cert2(X509Certificate::CreateFromHandle(
-      google_cert_handle, X509Certificate::OSCertHandles()));
-  X509Certificate::FreeOSCertHandle(google_cert_handle);
+  ASSERT_TRUE(google_cert_handle);
+  scoped_refptr<X509Certificate> cert2(
+      X509Certificate::CreateFromBuffer(std::move(google_cert_handle), {}));
   ASSERT_TRUE(cert2);
 
   // A new X509Certificate should be returned.
   EXPECT_NE(cert1.get(), cert2.get());
   // But both instances should share the underlying OS certificate handle.
-  EXPECT_EQ(cert1->os_cert_handle(), cert2->os_cert_handle());
-  EXPECT_EQ(0u, cert1->GetIntermediateCertificates().size());
-  EXPECT_EQ(0u, cert2->GetIntermediateCertificates().size());
+  EXPECT_EQ(cert1->cert_buffer(), cert2->cert_buffer());
+  EXPECT_EQ(0u, cert1->intermediate_buffers().size());
+  EXPECT_EQ(0u, cert2->intermediate_buffers().size());
 
   // Add the same certificate, but this time with an intermediate. This
   // should result in the intermediate being cached. Note that this is not
   // a legitimate chain, but is suitable for testing.
-  google_cert_handle = X509Certificate::CreateOSCertHandleFromBytes(
+  google_cert_handle = X509Certificate::CreateCertBufferFromBytes(
       reinterpret_cast<const char*>(google_der), sizeof(google_der));
-  thawte_cert_handle = X509Certificate::CreateOSCertHandleFromBytes(
+  thawte_cert_handle = X509Certificate::CreateCertBufferFromBytes(
       reinterpret_cast<const char*>(thawte_der), sizeof(thawte_der));
-  X509Certificate::OSCertHandles intermediates;
-  intermediates.push_back(thawte_cert_handle);
-  scoped_refptr<X509Certificate> cert3(X509Certificate::CreateFromHandle(
-      google_cert_handle, intermediates));
-  X509Certificate::FreeOSCertHandle(google_cert_handle);
-  X509Certificate::FreeOSCertHandle(thawte_cert_handle);
+  ASSERT_TRUE(google_cert_handle);
+  ASSERT_TRUE(thawte_cert_handle);
+  std::vector<bssl::UniquePtr<CRYPTO_BUFFER>> intermediates;
+  intermediates.push_back(std::move(thawte_cert_handle));
+  scoped_refptr<X509Certificate> cert3(X509Certificate::CreateFromBuffer(
+      std::move(google_cert_handle), std::move(intermediates)));
   ASSERT_TRUE(cert3);
 
   // Test that the new certificate, even with intermediates, results in the
   // same underlying handle being used.
-  EXPECT_EQ(cert1->os_cert_handle(), cert3->os_cert_handle());
+  EXPECT_EQ(cert1->cert_buffer(), cert3->cert_buffer());
   // Though they use the same OS handle, the intermediates should be different.
-  EXPECT_NE(cert1->GetIntermediateCertificates().size(),
-      cert3->GetIntermediateCertificates().size());
+  EXPECT_NE(cert1->intermediate_buffers().size(),
+            cert3->intermediate_buffers().size());
 }
 
 TEST(X509CertificateTest, Pickle) {
-  X509Certificate::OSCertHandle google_cert_handle =
-      X509Certificate::CreateOSCertHandleFromBytes(
+  bssl::UniquePtr<CRYPTO_BUFFER> google_cert_handle =
+      X509Certificate::CreateCertBufferFromBytes(
           reinterpret_cast<const char*>(google_der), sizeof(google_der));
-  X509Certificate::OSCertHandle thawte_cert_handle =
-      X509Certificate::CreateOSCertHandleFromBytes(
+  ASSERT_TRUE(google_cert_handle);
+  bssl::UniquePtr<CRYPTO_BUFFER> thawte_cert_handle =
+      X509Certificate::CreateCertBufferFromBytes(
           reinterpret_cast<const char*>(thawte_der), sizeof(thawte_der));
+  ASSERT_TRUE(thawte_cert_handle);
 
-  X509Certificate::OSCertHandles intermediates;
-  intermediates.push_back(thawte_cert_handle);
-  scoped_refptr<X509Certificate> cert = X509Certificate::CreateFromHandle(
-      google_cert_handle, intermediates);
+  std::vector<bssl::UniquePtr<CRYPTO_BUFFER>> intermediates;
+  intermediates.push_back(std::move(thawte_cert_handle));
+  scoped_refptr<X509Certificate> cert = X509Certificate::CreateFromBuffer(
+      std::move(google_cert_handle), std::move(intermediates));
   ASSERT_TRUE(cert);
 
-  X509Certificate::FreeOSCertHandle(google_cert_handle);
-  X509Certificate::FreeOSCertHandle(thawte_cert_handle);
-
   base::Pickle pickle;
   cert->Persist(&pickle);
 
@@ -693,16 +689,14 @@
   scoped_refptr<X509Certificate> cert_from_pickle =
       X509Certificate::CreateFromPickle(&iter);
   ASSERT_TRUE(cert_from_pickle);
-  EXPECT_TRUE(X509Certificate::IsSameOSCert(
-      cert->os_cert_handle(), cert_from_pickle->os_cert_handle()));
-  const X509Certificate::OSCertHandles& cert_intermediates =
-      cert->GetIntermediateCertificates();
-  const X509Certificate::OSCertHandles& pickle_intermediates =
-      cert_from_pickle->GetIntermediateCertificates();
+  EXPECT_TRUE(x509_util::CryptoBufferEqual(cert->cert_buffer(),
+                                           cert_from_pickle->cert_buffer()));
+  const auto& cert_intermediates = cert->intermediate_buffers();
+  const auto& pickle_intermediates = cert_from_pickle->intermediate_buffers();
   ASSERT_EQ(cert_intermediates.size(), pickle_intermediates.size());
   for (size_t i = 0; i < cert_intermediates.size(); ++i) {
-    EXPECT_TRUE(X509Certificate::IsSameOSCert(cert_intermediates[i],
-                                              pickle_intermediates[i]));
+    EXPECT_TRUE(x509_util::CryptoBufferEqual(cert_intermediates[i].get(),
+                                             pickle_intermediates[i].get()));
   }
 }
 
@@ -717,35 +711,34 @@
           reinterpret_cast<const char*>(thawte_der), sizeof(thawte_der)));
   ASSERT_TRUE(thawte_cert);
 
-  X509Certificate::OSCertHandle google_handle;
+  bssl::UniquePtr<CRYPTO_BUFFER> google_handle;
   // Create object with no intermediates:
-  google_handle = X509Certificate::CreateOSCertHandleFromBytes(
+  google_handle = X509Certificate::CreateCertBufferFromBytes(
       reinterpret_cast<const char*>(google_der), sizeof(google_der));
-  X509Certificate::OSCertHandles intermediates1;
   scoped_refptr<X509Certificate> cert1;
-  cert1 = X509Certificate::CreateFromHandle(google_handle, intermediates1);
+  cert1 = X509Certificate::CreateFromBuffer(
+      x509_util::DupCryptoBuffer(google_handle.get()), {});
   ASSERT_TRUE(cert1);
-  EXPECT_EQ(0u, cert1->GetIntermediateCertificates().size());
+  EXPECT_EQ(0u, cert1->intermediate_buffers().size());
 
   // Create object with 2 intermediates:
-  X509Certificate::OSCertHandles intermediates2;
-  intermediates2.push_back(webkit_cert->os_cert_handle());
-  intermediates2.push_back(thawte_cert->os_cert_handle());
+  std::vector<bssl::UniquePtr<CRYPTO_BUFFER>> intermediates2;
+  intermediates2.push_back(
+      x509_util::DupCryptoBuffer(webkit_cert->cert_buffer()));
+  intermediates2.push_back(
+      x509_util::DupCryptoBuffer(thawte_cert->cert_buffer()));
   scoped_refptr<X509Certificate> cert2;
-  cert2 = X509Certificate::CreateFromHandle(google_handle, intermediates2);
+  cert2 = X509Certificate::CreateFromBuffer(std::move(google_handle),
+                                            std::move(intermediates2));
   ASSERT_TRUE(cert2);
 
   // Verify it has all the intermediates:
-  const X509Certificate::OSCertHandles& cert2_intermediates =
-      cert2->GetIntermediateCertificates();
+  const auto& cert2_intermediates = cert2->intermediate_buffers();
   ASSERT_EQ(2u, cert2_intermediates.size());
-  EXPECT_TRUE(X509Certificate::IsSameOSCert(cert2_intermediates[0],
-                                            webkit_cert->os_cert_handle()));
-  EXPECT_TRUE(X509Certificate::IsSameOSCert(cert2_intermediates[1],
-                                            thawte_cert->os_cert_handle()));
-
-  // Cleanup
-  X509Certificate::FreeOSCertHandle(google_handle);
+  EXPECT_TRUE(x509_util::CryptoBufferEqual(cert2_intermediates[0].get(),
+                                           webkit_cert->cert_buffer()));
+  EXPECT_TRUE(x509_util::CryptoBufferEqual(cert2_intermediates[1].get(),
+                                           thawte_cert->cert_buffer()));
 }
 
 TEST(X509CertificateTest, IsIssuedByEncoded) {
@@ -796,22 +789,22 @@
   scoped_refptr<X509Certificate> cert(
       ImportCertFromFile(certs_dir, "mit.davidben.der"));
   ASSERT_NE(static_cast<X509Certificate*>(NULL), cert.get());
-  EXPECT_FALSE(X509Certificate::IsSelfSigned(cert->os_cert_handle()));
+  EXPECT_FALSE(X509Certificate::IsSelfSigned(cert->cert_buffer()));
 
   scoped_refptr<X509Certificate> self_signed(
       ImportCertFromFile(certs_dir, "aia-root.pem"));
   ASSERT_NE(static_cast<X509Certificate*>(NULL), self_signed.get());
-  EXPECT_TRUE(X509Certificate::IsSelfSigned(self_signed->os_cert_handle()));
+  EXPECT_TRUE(X509Certificate::IsSelfSigned(self_signed->cert_buffer()));
 
   scoped_refptr<X509Certificate> bad_name(
       ImportCertFromFile(certs_dir, "self-signed-invalid-name.pem"));
   ASSERT_NE(static_cast<X509Certificate*>(NULL), bad_name.get());
-  EXPECT_FALSE(X509Certificate::IsSelfSigned(bad_name->os_cert_handle()));
+  EXPECT_FALSE(X509Certificate::IsSelfSigned(bad_name->cert_buffer()));
 
   scoped_refptr<X509Certificate> bad_sig(
       ImportCertFromFile(certs_dir, "self-signed-invalid-sig.pem"));
   ASSERT_NE(static_cast<X509Certificate*>(NULL), bad_sig.get());
-  EXPECT_FALSE(X509Certificate::IsSelfSigned(bad_sig->os_cert_handle()));
+  EXPECT_FALSE(X509Certificate::IsSelfSigned(bad_sig->cert_buffer()));
 }
 
 TEST(X509CertificateTest, IsIssuedByEncodedWithIntermediates) {
@@ -841,11 +834,12 @@
   std::string policy_root_dn(reinterpret_cast<const char*>(kPolicyRootDN),
                              sizeof(kPolicyRootDN));
 
-  X509Certificate::OSCertHandles intermediates;
-  intermediates.push_back(policy_chain[1]->os_cert_handle());
-  scoped_refptr<X509Certificate> cert_chain =
-      X509Certificate::CreateFromHandle(policy_chain[0]->os_cert_handle(),
-                                        intermediates);
+  std::vector<bssl::UniquePtr<CRYPTO_BUFFER>> intermediates;
+  intermediates.push_back(
+      x509_util::DupCryptoBuffer(policy_chain[1]->cert_buffer()));
+  scoped_refptr<X509Certificate> cert_chain = X509Certificate::CreateFromBuffer(
+      x509_util::DupCryptoBuffer(policy_chain[0]->cert_buffer()),
+      std::move(intermediates));
   ASSERT_TRUE(cert_chain);
 
   std::vector<std::string> issuers;
@@ -878,11 +872,6 @@
   EXPECT_FALSE(cert_chain->IsIssuedByEncoded(issuers));
 }
 
-// Tests that FreeOSCertHandle ignores NULL on each OS.
-TEST(X509CertificateTest, FreeNullHandle) {
-  X509Certificate::FreeOSCertHandle(NULL);
-}
-
 const struct CertificateFormatTestData {
   const char* file_name;
   X509Certificate::Format format;
@@ -1005,7 +994,7 @@
     // comparing fingerprints.
     EXPECT_EQ(
         *test_data_.chain_fingerprints[i],
-        X509Certificate::CalculateFingerprint256(certs[i]->os_cert_handle()));
+        X509Certificate::CalculateFingerprint256(certs[i]->cert_buffer()));
   }
 }
 
@@ -1281,7 +1270,7 @@
   X509Certificate::PublicKeyType actual_type =
       X509Certificate::kPublicKeyTypeUnknown;
 
-  X509Certificate::GetPublicKeyInfo(cert->os_cert_handle(), &actual_bits,
+  X509Certificate::GetPublicKeyInfo(cert->cert_buffer(), &actual_bits,
                                     &actual_type);
 
   EXPECT_EQ(data.expected_bits, actual_bits);
diff --git a/net/cert/x509_util.cc b/net/cert/x509_util.cc
index 9f39287..48eb739 100644
--- a/net/cert/x509_util.cc
+++ b/net/cert/x509_util.cc
@@ -4,6 +4,7 @@
 
 #include "net/cert/x509_util.h"
 
+#include <string.h>
 #include <memory>
 
 #include "base/lazy_instance.h"
@@ -159,15 +160,13 @@
                                         std::string* token) {
   static const char kChannelBindingPrefix[] = "tls-server-end-point:";
 
-  std::string der_encoded_certificate;
-  if (!X509Certificate::GetDEREncoded(certificate.os_cert_handle(),
-                                      &der_encoded_certificate))
-    return false;
+  base::StringPiece der_encoded_certificate =
+      x509_util::CryptoBufferAsStringPiece(certificate.cert_buffer());
 
   der::Input tbs_certificate_tlv;
   der::Input signature_algorithm_tlv;
   der::BitString signature_value;
-  if (!ParseCertificate(der::Input(&der_encoded_certificate),
+  if (!ParseCertificate(der::Input(der_encoded_certificate),
                         &tbs_certificate_tlv, &signature_algorithm_tlv,
                         &signature_value, nullptr))
     return false;
@@ -393,6 +392,20 @@
                         data.size(), GetBufferPool()));
 }
 
+bssl::UniquePtr<CRYPTO_BUFFER> DupCryptoBuffer(CRYPTO_BUFFER* buffer) {
+  CRYPTO_BUFFER_up_ref(buffer);
+  return bssl::UniquePtr<CRYPTO_BUFFER>(buffer);
+}
+
+bool CryptoBufferEqual(const CRYPTO_BUFFER* a, const CRYPTO_BUFFER* b) {
+  DCHECK(a && b);
+  if (a == b)
+    return true;
+  return CRYPTO_BUFFER_len(a) == CRYPTO_BUFFER_len(b) &&
+         memcmp(CRYPTO_BUFFER_data(a), CRYPTO_BUFFER_data(b),
+                CRYPTO_BUFFER_len(a)) == 0;
+}
+
 base::StringPiece CryptoBufferAsStringPiece(const CRYPTO_BUFFER* buffer) {
   return base::StringPiece(
       reinterpret_cast<const char*>(CRYPTO_BUFFER_data(buffer)),
@@ -406,11 +419,14 @@
     return nullptr;
   }
 
-  std::vector<CRYPTO_BUFFER*> intermediate_chain;
-  for (size_t i = 1; i < sk_CRYPTO_BUFFER_num(buffers); ++i)
-    intermediate_chain.push_back(sk_CRYPTO_BUFFER_value(buffers, i));
-  return X509Certificate::CreateFromHandle(sk_CRYPTO_BUFFER_value(buffers, 0),
-                                           intermediate_chain);
+  std::vector<bssl::UniquePtr<CRYPTO_BUFFER>> intermediate_chain;
+  for (size_t i = 1; i < sk_CRYPTO_BUFFER_num(buffers); ++i) {
+    intermediate_chain.push_back(
+        DupCryptoBuffer(sk_CRYPTO_BUFFER_value(buffers, i)));
+  }
+  return X509Certificate::CreateFromBuffer(
+      DupCryptoBuffer(sk_CRYPTO_BUFFER_value(buffers, 0)),
+      std::move(intermediate_chain));
 }
 
 ParseCertificateOptions DefaultParseCertificateOptions() {
diff --git a/net/cert/x509_util.h b/net/cert/x509_util.h
index c75059a..a954ebc 100644
--- a/net/cert/x509_util.h
+++ b/net/cert/x509_util.h
@@ -102,6 +102,15 @@
 NET_EXPORT bssl::UniquePtr<CRYPTO_BUFFER> CreateCryptoBuffer(
     const char* invalid_data);
 
+// Increments the reference count of |buffer| and returns a UniquePtr owning
+// that reference.
+NET_EXPORT bssl::UniquePtr<CRYPTO_BUFFER> DupCryptoBuffer(
+    CRYPTO_BUFFER* buffer);
+
+// Compares two CRYPTO_BUFFERs and returns true if they have the same contents.
+NET_EXPORT bool CryptoBufferEqual(const CRYPTO_BUFFER* a,
+                                  const CRYPTO_BUFFER* b);
+
 // Returns a StringPiece pointing to the data in |buffer|.
 NET_EXPORT base::StringPiece CryptoBufferAsStringPiece(
     const CRYPTO_BUFFER* buffer);
diff --git a/net/cert/x509_util_ios.cc b/net/cert/x509_util_ios.cc
index 26c4354..0ae1e77 100644
--- a/net/cert/x509_util_ios.cc
+++ b/net/cert/x509_util_ios.cc
@@ -26,9 +26,8 @@
 
 base::ScopedCFTypeRef<SecCertificateRef>
 CreateSecCertificateFromX509Certificate(const X509Certificate* cert) {
-  return CreateSecCertificateFromBytes(
-      CRYPTO_BUFFER_data(cert->os_cert_handle()),
-      CRYPTO_BUFFER_len(cert->os_cert_handle()));
+  return CreateSecCertificateFromBytes(CRYPTO_BUFFER_data(cert->cert_buffer()),
+                                       CRYPTO_BUFFER_len(cert->cert_buffer()));
 }
 
 scoped_refptr<X509Certificate> CreateX509CertificateFromSecCertificate(
@@ -40,13 +39,12 @@
   if (!der_data)
     return nullptr;
   bssl::UniquePtr<CRYPTO_BUFFER> cert_handle(
-      X509Certificate::CreateOSCertHandleFromBytes(
+      X509Certificate::CreateCertBufferFromBytes(
           reinterpret_cast<const char*>(CFDataGetBytePtr(der_data)),
           CFDataGetLength(der_data)));
   if (!cert_handle)
     return nullptr;
   std::vector<bssl::UniquePtr<CRYPTO_BUFFER>> intermediates;
-  X509Certificate::OSCertHandles intermediates_raw;
   for (const SecCertificateRef& sec_intermediate : sec_chain) {
     if (!sec_intermediate)
       return nullptr;
@@ -54,16 +52,15 @@
     if (!der_data)
       return nullptr;
     bssl::UniquePtr<CRYPTO_BUFFER> intermediate_cert_handle(
-        X509Certificate::CreateOSCertHandleFromBytes(
+        X509Certificate::CreateCertBufferFromBytes(
             reinterpret_cast<const char*>(CFDataGetBytePtr(der_data)),
             CFDataGetLength(der_data)));
     if (!intermediate_cert_handle)
       return nullptr;
-    intermediates_raw.push_back(intermediate_cert_handle.get());
     intermediates.push_back(std::move(intermediate_cert_handle));
   }
-  scoped_refptr<X509Certificate> result(
-      X509Certificate::CreateFromHandle(cert_handle.get(), intermediates_raw));
+  scoped_refptr<X509Certificate> result(X509Certificate::CreateFromBuffer(
+      std::move(cert_handle), std::move(intermediates)));
   return result;
 }
 
diff --git a/net/cert/x509_util_ios_and_mac.cc b/net/cert/x509_util_ios_and_mac.cc
index 0659e43..8e41cd8 100644
--- a/net/cert/x509_util_ios_and_mac.cc
+++ b/net/cert/x509_util_ios_and_mac.cc
@@ -32,16 +32,15 @@
     return base::ScopedCFTypeRef<CFMutableArrayRef>();
   std::string bytes;
   base::ScopedCFTypeRef<SecCertificateRef> sec_cert(
-      CreateSecCertificateFromBytes(CRYPTO_BUFFER_data(cert->os_cert_handle()),
-                                    CRYPTO_BUFFER_len(cert->os_cert_handle())));
+      CreateSecCertificateFromBytes(CRYPTO_BUFFER_data(cert->cert_buffer()),
+                                    CRYPTO_BUFFER_len(cert->cert_buffer())));
   if (!sec_cert)
     return base::ScopedCFTypeRef<CFMutableArrayRef>();
   CFArrayAppendValue(cert_list, sec_cert);
-  for (X509Certificate::OSCertHandle intermediate :
-       cert->GetIntermediateCertificates()) {
+  for (const auto& intermediate : cert->intermediate_buffers()) {
     base::ScopedCFTypeRef<SecCertificateRef> sec_cert(
-        CreateSecCertificateFromBytes(CRYPTO_BUFFER_data(intermediate),
-                                      CRYPTO_BUFFER_len(intermediate)));
+        CreateSecCertificateFromBytes(CRYPTO_BUFFER_data(intermediate.get()),
+                                      CRYPTO_BUFFER_len(intermediate.get())));
     if (!sec_cert) {
       if (invalid_intermediate_behavior == InvalidIntermediateBehavior::kFail)
         return base::ScopedCFTypeRef<CFMutableArrayRef>();
diff --git a/net/cert/x509_util_ios_and_mac_unittest.cc b/net/cert/x509_util_ios_and_mac_unittest.cc
index 5b2eae1..d2e6883b 100644
--- a/net/cert/x509_util_ios_and_mac_unittest.cc
+++ b/net/cert/x509_util_ios_and_mac_unittest.cc
@@ -39,17 +39,6 @@
       reinterpret_cast<SecCertificateRef>(const_cast<void*>(sec_cert)));
 }
 
-std::string BytesForX509CertHandle(X509Certificate::OSCertHandle handle) {
-  std::string result;
-  if (!X509Certificate::GetDEREncoded(handle, &result))
-    ADD_FAILURE();
-  return result;
-}
-
-std::string BytesForX509Cert(X509Certificate* cert) {
-  return BytesForX509CertHandle(cert->os_cert_handle());
-}
-
 }  // namespace
 
 TEST(X509UtilTest, CreateSecCertificateArrayForX509Certificate) {
@@ -57,7 +46,7 @@
       GetTestCertsDirectory(), "multi-root-chain1.pem",
       X509Certificate::FORMAT_PEM_CERT_SEQUENCE);
   ASSERT_TRUE(cert);
-  EXPECT_EQ(3U, cert->GetIntermediateCertificates().size());
+  EXPECT_EQ(3U, cert->intermediate_buffers().size());
 
   base::ScopedCFTypeRef<CFMutableArrayRef> sec_certs(
       CreateSecCertificateArrayForX509Certificate(cert.get()));
@@ -66,13 +55,16 @@
   for (int i = 0; i < 4; ++i)
     ASSERT_TRUE(CFArrayGetValueAtIndex(sec_certs.get(), i));
 
-  EXPECT_EQ(BytesForX509Cert(cert.get()),
+  EXPECT_EQ(x509_util::CryptoBufferAsStringPiece(cert->cert_buffer()),
             BytesForSecCert(CFArrayGetValueAtIndex(sec_certs.get(), 0)));
-  EXPECT_EQ(BytesForX509CertHandle(cert->GetIntermediateCertificates()[0]),
+  EXPECT_EQ(x509_util::CryptoBufferAsStringPiece(
+                cert->intermediate_buffers()[0].get()),
             BytesForSecCert(CFArrayGetValueAtIndex(sec_certs.get(), 1)));
-  EXPECT_EQ(BytesForX509CertHandle(cert->GetIntermediateCertificates()[1]),
+  EXPECT_EQ(x509_util::CryptoBufferAsStringPiece(
+                cert->intermediate_buffers()[1].get()),
             BytesForSecCert(CFArrayGetValueAtIndex(sec_certs.get(), 2)));
-  EXPECT_EQ(BytesForX509CertHandle(cert->GetIntermediateCertificates()[2]),
+  EXPECT_EQ(x509_util::CryptoBufferAsStringPiece(
+                cert->intermediate_buffers()[2].get()),
             BytesForSecCert(CFArrayGetValueAtIndex(sec_certs.get(), 3)));
 }
 
@@ -89,12 +81,15 @@
       ImportCertFromFile(GetTestCertsDirectory(), "root_ca_cert.pem"));
   ASSERT_TRUE(ok_cert);
 
+  std::vector<bssl::UniquePtr<CRYPTO_BUFFER>> intermediates;
+  intermediates.push_back(std::move(bad_cert));
+  intermediates.push_back(x509_util::DupCryptoBuffer(ok_cert2->cert_buffer()));
   scoped_refptr<X509Certificate> cert_with_intermediates(
-      X509Certificate::CreateFromHandle(
-          ok_cert->os_cert_handle(),
-          {bad_cert.get(), ok_cert2->os_cert_handle()}));
+      X509Certificate::CreateFromBuffer(
+          x509_util::DupCryptoBuffer(ok_cert->cert_buffer()),
+          std::move(intermediates)));
   ASSERT_TRUE(cert_with_intermediates);
-  EXPECT_EQ(2U, cert_with_intermediates->GetIntermediateCertificates().size());
+  EXPECT_EQ(2U, cert_with_intermediates->intermediate_buffers().size());
 
   // Normal CreateSecCertificateArrayForX509Certificate fails with invalid
   // certs in chain.
@@ -111,9 +106,9 @@
   for (int i = 0; i < 2; ++i)
     ASSERT_TRUE(CFArrayGetValueAtIndex(sec_certs.get(), i));
 
-  EXPECT_EQ(BytesForX509Cert(ok_cert.get()),
+  EXPECT_EQ(x509_util::CryptoBufferAsStringPiece(ok_cert->cert_buffer()),
             BytesForSecCert(CFArrayGetValueAtIndex(sec_certs.get(), 0)));
-  EXPECT_EQ(BytesForX509Cert(ok_cert2.get()),
+  EXPECT_EQ(x509_util::CryptoBufferAsStringPiece(ok_cert2->cert_buffer()),
             BytesForSecCert(CFArrayGetValueAtIndex(sec_certs.get(), 1)));
 }
 
@@ -124,10 +119,14 @@
       X509Certificate::FORMAT_PEM_CERT_SEQUENCE);
   ASSERT_EQ(4u, certs.size());
 
-  std::string bytes_cert0 = BytesForX509CertHandle(certs[0]->os_cert_handle());
-  std::string bytes_cert1 = BytesForX509CertHandle(certs[1]->os_cert_handle());
-  std::string bytes_cert2 = BytesForX509CertHandle(certs[2]->os_cert_handle());
-  std::string bytes_cert3 = BytesForX509CertHandle(certs[3]->os_cert_handle());
+  std::string bytes_cert0(
+      x509_util::CryptoBufferAsStringPiece(certs[0]->cert_buffer()));
+  std::string bytes_cert1(
+      x509_util::CryptoBufferAsStringPiece(certs[1]->cert_buffer()));
+  std::string bytes_cert2(
+      x509_util::CryptoBufferAsStringPiece(certs[2]->cert_buffer()));
+  std::string bytes_cert3(
+      x509_util::CryptoBufferAsStringPiece(certs[3]->cert_buffer()));
 
   base::ScopedCFTypeRef<SecCertificateRef> sec_cert0(
       CreateSecCertificateFromBytes(
@@ -156,37 +155,34 @@
   scoped_refptr<X509Certificate> x509_cert_no_intermediates =
       CreateX509CertificateFromSecCertificate(sec_cert0.get(), {});
   ASSERT_TRUE(x509_cert_no_intermediates);
-  EXPECT_EQ(0U,
-            x509_cert_no_intermediates->GetIntermediateCertificates().size());
-  EXPECT_EQ(bytes_cert0, BytesForX509CertHandle(
-                             x509_cert_no_intermediates->os_cert_handle()));
+  EXPECT_EQ(0U, x509_cert_no_intermediates->intermediate_buffers().size());
+  EXPECT_EQ(bytes_cert0, x509_util::CryptoBufferAsStringPiece(
+                             x509_cert_no_intermediates->cert_buffer()));
 
   scoped_refptr<X509Certificate> x509_cert_one_intermediate =
       CreateX509CertificateFromSecCertificate(sec_cert0.get(),
                                               {sec_cert1.get()});
   ASSERT_TRUE(x509_cert_one_intermediate);
-  EXPECT_EQ(bytes_cert0, BytesForX509CertHandle(
-                             x509_cert_one_intermediate->os_cert_handle()));
-  ASSERT_EQ(1U,
-            x509_cert_one_intermediate->GetIntermediateCertificates().size());
+  EXPECT_EQ(bytes_cert0, x509_util::CryptoBufferAsStringPiece(
+                             x509_cert_one_intermediate->cert_buffer()));
+  ASSERT_EQ(1U, x509_cert_one_intermediate->intermediate_buffers().size());
   EXPECT_EQ(bytes_cert1,
-            BytesForX509CertHandle(
-                x509_cert_one_intermediate->GetIntermediateCertificates()[0]));
+            x509_util::CryptoBufferAsStringPiece(
+                x509_cert_one_intermediate->intermediate_buffers()[0].get()));
 
   scoped_refptr<X509Certificate> x509_cert_two_intermediates =
       CreateX509CertificateFromSecCertificate(
           sec_cert0.get(), {sec_cert1.get(), sec_cert2.get()});
   ASSERT_TRUE(x509_cert_two_intermediates);
-  EXPECT_EQ(bytes_cert0, BytesForX509CertHandle(
-                             x509_cert_two_intermediates->os_cert_handle()));
-  ASSERT_EQ(2U,
-            x509_cert_two_intermediates->GetIntermediateCertificates().size());
+  EXPECT_EQ(bytes_cert0, x509_util::CryptoBufferAsStringPiece(
+                             x509_cert_two_intermediates->cert_buffer()));
+  ASSERT_EQ(2U, x509_cert_two_intermediates->intermediate_buffers().size());
   EXPECT_EQ(bytes_cert1,
-            BytesForX509CertHandle(
-                x509_cert_two_intermediates->GetIntermediateCertificates()[0]));
+            x509_util::CryptoBufferAsStringPiece(
+                x509_cert_two_intermediates->intermediate_buffers()[0].get()));
   EXPECT_EQ(bytes_cert2,
-            BytesForX509CertHandle(
-                x509_cert_two_intermediates->GetIntermediateCertificates()[1]));
+            x509_util::CryptoBufferAsStringPiece(
+                x509_cert_two_intermediates->intermediate_buffers()[1].get()));
 }
 
 }  // namespace x509_util
diff --git a/net/cert/x509_util_mac.cc b/net/cert/x509_util_mac.cc
index 51c5a19d..5285c4bc 100644
--- a/net/cert/x509_util_mac.cc
+++ b/net/cert/x509_util_mac.cc
@@ -80,9 +80,8 @@
 
 base::ScopedCFTypeRef<SecCertificateRef>
 CreateSecCertificateFromX509Certificate(const X509Certificate* cert) {
-  return CreateSecCertificateFromBytes(
-      CRYPTO_BUFFER_data(cert->os_cert_handle()),
-      CRYPTO_BUFFER_len(cert->os_cert_handle()));
+  return CreateSecCertificateFromBytes(CRYPTO_BUFFER_data(cert->cert_buffer()),
+                                       CRYPTO_BUFFER_len(cert->cert_buffer()));
 }
 
 scoped_refptr<X509Certificate> CreateX509CertificateFromSecCertificate(
@@ -99,28 +98,26 @@
   if (!sec_cert || SecCertificateGetData(sec_cert, &der_data) != noErr)
     return nullptr;
   bssl::UniquePtr<CRYPTO_BUFFER> cert_handle(
-      X509Certificate::CreateOSCertHandleFromBytes(
+      X509Certificate::CreateCertBufferFromBytes(
           reinterpret_cast<const char*>(der_data.Data), der_data.Length));
   if (!cert_handle)
     return nullptr;
   std::vector<bssl::UniquePtr<CRYPTO_BUFFER>> intermediates;
-  X509Certificate::OSCertHandles intermediates_raw;
   for (const SecCertificateRef& sec_intermediate : sec_chain) {
     if (!sec_intermediate ||
         SecCertificateGetData(sec_intermediate, &der_data) != noErr) {
       return nullptr;
     }
     bssl::UniquePtr<CRYPTO_BUFFER> intermediate_cert_handle(
-        X509Certificate::CreateOSCertHandleFromBytes(
+        X509Certificate::CreateCertBufferFromBytes(
             reinterpret_cast<const char*>(der_data.Data), der_data.Length));
     if (!intermediate_cert_handle)
       return nullptr;
-    intermediates_raw.push_back(intermediate_cert_handle.get());
     intermediates.push_back(std::move(intermediate_cert_handle));
   }
   scoped_refptr<X509Certificate> result(
-      X509Certificate::CreateFromHandleUnsafeOptions(
-          cert_handle.get(), intermediates_raw, options));
+      X509Certificate::CreateFromBufferUnsafeOptions(
+          std::move(cert_handle), std::move(intermediates), options));
   return result;
 }
 
diff --git a/net/cert/x509_util_nss.cc b/net/cert/x509_util_nss.cc
index 33f39d2a..9ba26e3 100644
--- a/net/cert/x509_util_nss.cc
+++ b/net/cert/x509_util_nss.cc
@@ -142,8 +142,8 @@
 }
 
 bool IsSameCertificate(CERTCertificate* a, const X509Certificate* b) {
-  return a->derCert.len == CRYPTO_BUFFER_len(b->os_cert_handle()) &&
-         memcmp(a->derCert.data, CRYPTO_BUFFER_data(b->os_cert_handle()),
+  return a->derCert.len == CRYPTO_BUFFER_len(b->cert_buffer()) &&
+         memcmp(a->derCert.data, CRYPTO_BUFFER_data(b->cert_buffer()),
                 a->derCert.len) == 0;
 }
 bool IsSameCertificate(const X509Certificate* a, CERTCertificate* b) {
@@ -170,9 +170,8 @@
 
 ScopedCERTCertificate CreateCERTCertificateFromX509Certificate(
     const X509Certificate* cert) {
-  return CreateCERTCertificateFromBytes(
-      CRYPTO_BUFFER_data(cert->os_cert_handle()),
-      CRYPTO_BUFFER_len(cert->os_cert_handle()));
+  return CreateCERTCertificateFromBytes(CRYPTO_BUFFER_data(cert->cert_buffer()),
+                                        CRYPTO_BUFFER_len(cert->cert_buffer()));
 }
 
 ScopedCERTCertificateList CreateCERTCertificateListFromX509Certificate(
@@ -185,16 +184,16 @@
     const X509Certificate* cert,
     InvalidIntermediateBehavior invalid_intermediate_behavior) {
   ScopedCERTCertificateList nss_chain;
-  nss_chain.reserve(1 + cert->GetIntermediateCertificates().size());
+  nss_chain.reserve(1 + cert->intermediate_buffers().size());
   ScopedCERTCertificate nss_cert =
       CreateCERTCertificateFromX509Certificate(cert);
   if (!nss_cert)
     return {};
   nss_chain.push_back(std::move(nss_cert));
-  for (net::X509Certificate::OSCertHandle intermediate :
-       cert->GetIntermediateCertificates()) {
-    ScopedCERTCertificate nss_intermediate = CreateCERTCertificateFromBytes(
-        CRYPTO_BUFFER_data(intermediate), CRYPTO_BUFFER_len(intermediate));
+  for (const auto& intermediate : cert->intermediate_buffers()) {
+    ScopedCERTCertificate nss_intermediate =
+        CreateCERTCertificateFromBytes(CRYPTO_BUFFER_data(intermediate.get()),
+                                       CRYPTO_BUFFER_len(intermediate.get()));
     if (!nss_intermediate) {
       if (invalid_intermediate_behavior == InvalidIntermediateBehavior::kFail)
         return {};
@@ -249,7 +248,7 @@
   if (!nss_cert || !nss_cert->derCert.len)
     return nullptr;
   bssl::UniquePtr<CRYPTO_BUFFER> cert_handle(
-      X509Certificate::CreateOSCertHandleFromBytes(
+      X509Certificate::CreateCertBufferFromBytes(
           reinterpret_cast<const char*>(nss_cert->derCert.data),
           nss_cert->derCert.len));
   if (!cert_handle)
@@ -257,23 +256,20 @@
 
   std::vector<bssl::UniquePtr<CRYPTO_BUFFER>> intermediates;
   intermediates.reserve(nss_chain.size());
-  X509Certificate::OSCertHandles intermediates_raw;
-  intermediates_raw.reserve(nss_chain.size());
   for (const CERTCertificate* nss_intermediate : nss_chain) {
     if (!nss_intermediate || !nss_intermediate->derCert.len)
       return nullptr;
     bssl::UniquePtr<CRYPTO_BUFFER> intermediate_cert_handle(
-        X509Certificate::CreateOSCertHandleFromBytes(
+        X509Certificate::CreateCertBufferFromBytes(
             reinterpret_cast<const char*>(nss_intermediate->derCert.data),
             nss_intermediate->derCert.len));
     if (!intermediate_cert_handle)
       return nullptr;
-    intermediates_raw.push_back(intermediate_cert_handle.get());
     intermediates.push_back(std::move(intermediate_cert_handle));
   }
   scoped_refptr<X509Certificate> result(
-      X509Certificate::CreateFromHandleUnsafeOptions(
-          cert_handle.get(), intermediates_raw, options));
+      X509Certificate::CreateFromBufferUnsafeOptions(
+          std::move(cert_handle), std::move(intermediates), options));
   return result;
 }
 
diff --git a/net/cert/x509_util_nss_unittest.cc b/net/cert/x509_util_nss_unittest.cc
index d9b9a700..fb671259 100644
--- a/net/cert/x509_util_nss_unittest.cc
+++ b/net/cert/x509_util_nss_unittest.cc
@@ -25,17 +25,6 @@
   return der_encoded;
 }
 
-std::string BytesForX509CertHandle(X509Certificate::OSCertHandle handle) {
-  std::string result;
-  if (!X509Certificate::GetDEREncoded(handle, &result))
-    ADD_FAILURE();
-  return result;
-}
-
-std::string BytesForX509Cert(X509Certificate* cert) {
-  return BytesForX509CertHandle(cert->os_cert_handle());
-}
-
 }  // namespace
 
 TEST(X509UtilNSSTest, IsSameCertificate) {
@@ -121,7 +110,7 @@
       GetTestCertsDirectory(), "multi-root-chain1.pem",
       X509Certificate::FORMAT_PEM_CERT_SEQUENCE);
   ASSERT_TRUE(x509_cert);
-  EXPECT_EQ(3U, x509_cert->GetIntermediateCertificates().size());
+  EXPECT_EQ(3U, x509_cert->intermediate_buffers().size());
 
   ScopedCERTCertificateList nss_certs =
       x509_util::CreateCERTCertificateListFromX509Certificate(x509_cert.get());
@@ -129,13 +118,16 @@
   for (int i = 0; i < 4; ++i)
     ASSERT_TRUE(nss_certs[i]);
 
-  EXPECT_EQ(BytesForX509Cert(x509_cert.get()),
+  EXPECT_EQ(x509_util::CryptoBufferAsStringPiece(x509_cert->cert_buffer()),
             BytesForNSSCert(nss_certs[0].get()));
-  EXPECT_EQ(BytesForX509CertHandle(x509_cert->GetIntermediateCertificates()[0]),
+  EXPECT_EQ(x509_util::CryptoBufferAsStringPiece(
+                x509_cert->intermediate_buffers()[0].get()),
             BytesForNSSCert(nss_certs[1].get()));
-  EXPECT_EQ(BytesForX509CertHandle(x509_cert->GetIntermediateCertificates()[1]),
+  EXPECT_EQ(x509_util::CryptoBufferAsStringPiece(
+                x509_cert->intermediate_buffers()[1].get()),
             BytesForNSSCert(nss_certs[2].get()));
-  EXPECT_EQ(BytesForX509CertHandle(x509_cert->GetIntermediateCertificates()[2]),
+  EXPECT_EQ(x509_util::CryptoBufferAsStringPiece(
+                x509_cert->intermediate_buffers()[2].get()),
             BytesForNSSCert(nss_certs[3].get()));
 }
 
@@ -152,12 +144,15 @@
       ImportCertFromFile(GetTestCertsDirectory(), "root_ca_cert.pem"));
   ASSERT_TRUE(ok_cert);
 
+  std::vector<bssl::UniquePtr<CRYPTO_BUFFER>> intermediates;
+  intermediates.push_back(std::move(bad_cert));
+  intermediates.push_back(x509_util::DupCryptoBuffer(ok_cert2->cert_buffer()));
   scoped_refptr<X509Certificate> cert_with_intermediates(
-      X509Certificate::CreateFromHandle(
-          ok_cert->os_cert_handle(),
-          {bad_cert.get(), ok_cert2->os_cert_handle()}));
+      X509Certificate::CreateFromBuffer(
+          x509_util::DupCryptoBuffer(ok_cert->cert_buffer()),
+          std::move(intermediates)));
   ASSERT_TRUE(cert_with_intermediates);
-  EXPECT_EQ(2U, cert_with_intermediates->GetIntermediateCertificates().size());
+  EXPECT_EQ(2U, cert_with_intermediates->intermediate_buffers().size());
 
   // Normal CreateCERTCertificateListFromX509Certificate fails with invalid
   // certs in chain.
@@ -175,9 +170,9 @@
   for (const auto& nss_cert : nss_certs)
     ASSERT_TRUE(nss_cert.get());
 
-  EXPECT_EQ(BytesForX509Cert(ok_cert.get()),
+  EXPECT_EQ(x509_util::CryptoBufferAsStringPiece(ok_cert->cert_buffer()),
             BytesForNSSCert(nss_certs[0].get()));
-  EXPECT_EQ(BytesForX509Cert(ok_cert2.get()),
+  EXPECT_EQ(x509_util::CryptoBufferAsStringPiece(ok_cert2->cert_buffer()),
             BytesForNSSCert(nss_certs[1].get()));
 }
 
@@ -254,8 +249,9 @@
   ASSERT_TRUE(nss_cert);
   scoped_refptr<X509Certificate> x509_cert =
       x509_util::CreateX509CertificateFromCERTCertificate(nss_cert.get());
-  EXPECT_EQ(BytesForNSSCert(nss_cert.get()), BytesForX509Cert(x509_cert.get()));
-  EXPECT_TRUE(x509_cert->GetIntermediateCertificates().empty());
+  EXPECT_EQ(BytesForNSSCert(nss_cert.get()),
+            x509_util::CryptoBufferAsStringPiece(x509_cert->cert_buffer()));
+  EXPECT_TRUE(x509_cert->intermediate_buffers().empty());
 }
 
 TEST(X509UtilNSSTest, CreateX509CertificateFromCERTCertificate_EmptyChain) {
@@ -265,8 +261,9 @@
   scoped_refptr<X509Certificate> x509_cert =
       x509_util::CreateX509CertificateFromCERTCertificate(
           nss_cert.get(), std::vector<CERTCertificate*>());
-  EXPECT_EQ(BytesForNSSCert(nss_cert.get()), BytesForX509Cert(x509_cert.get()));
-  EXPECT_TRUE(x509_cert->GetIntermediateCertificates().empty());
+  EXPECT_EQ(BytesForNSSCert(nss_cert.get()),
+            x509_util::CryptoBufferAsStringPiece(x509_cert->cert_buffer()));
+  EXPECT_TRUE(x509_cert->intermediate_buffers().empty());
 }
 
 TEST(X509UtilNSSTest, CreateX509CertificateFromCERTCertificate_WithChain) {
@@ -283,9 +280,11 @@
   scoped_refptr<X509Certificate> x509_cert =
       x509_util::CreateX509CertificateFromCERTCertificate(nss_cert.get(),
                                                           chain);
-  EXPECT_EQ(BytesForNSSCert(nss_cert.get()), BytesForX509Cert(x509_cert.get()));
-  ASSERT_EQ(1U, x509_cert->GetIntermediateCertificates().size());
-  EXPECT_EQ(BytesForX509CertHandle(x509_cert->GetIntermediateCertificates()[0]),
+  EXPECT_EQ(BytesForNSSCert(nss_cert.get()),
+            x509_util::CryptoBufferAsStringPiece(x509_cert->cert_buffer()));
+  ASSERT_EQ(1U, x509_cert->intermediate_buffers().size());
+  EXPECT_EQ(x509_util::CryptoBufferAsStringPiece(
+                x509_cert->intermediate_buffers()[0].get()),
             BytesForNSSCert(nss_cert2.get()));
 }
 
@@ -305,9 +304,9 @@
   ASSERT_EQ(2U, x509_certs.size());
 
   EXPECT_EQ(BytesForNSSCert(nss_certs[0].get()),
-            BytesForX509Cert(x509_certs[0].get()));
+            x509_util::CryptoBufferAsStringPiece(x509_certs[0]->cert_buffer()));
   EXPECT_EQ(BytesForNSSCert(nss_certs[1].get()),
-            BytesForX509Cert(x509_certs[1].get()));
+            x509_util::CryptoBufferAsStringPiece(x509_certs[1]->cert_buffer()));
 }
 
 TEST(X509UtilNSSTest, CreateX509CertificateListFromCERTCertificates_EmptyList) {
diff --git a/net/cert/x509_util_win.cc b/net/cert/x509_util_win.cc
index 09d9457..9def51f9 100644
--- a/net/cert/x509_util_win.cc
+++ b/net/cert/x509_util_win.cc
@@ -35,29 +35,27 @@
   if (!os_cert || !os_cert->pbCertEncoded || !os_cert->cbCertEncoded)
     return nullptr;
   bssl::UniquePtr<CRYPTO_BUFFER> cert_handle(
-      X509Certificate::CreateOSCertHandleFromBytes(
+      X509Certificate::CreateCertBufferFromBytes(
           reinterpret_cast<const char*>(os_cert->pbCertEncoded),
           os_cert->cbCertEncoded));
   if (!cert_handle)
     return nullptr;
   std::vector<bssl::UniquePtr<CRYPTO_BUFFER>> intermediates;
-  X509Certificate::OSCertHandles intermediates_raw;
   for (PCCERT_CONTEXT os_intermediate : os_chain) {
     if (!os_intermediate || !os_intermediate->pbCertEncoded ||
         !os_intermediate->cbCertEncoded)
       return nullptr;
     bssl::UniquePtr<CRYPTO_BUFFER> intermediate_cert_handle(
-        X509Certificate::CreateOSCertHandleFromBytes(
+        X509Certificate::CreateCertBufferFromBytes(
             reinterpret_cast<const char*>(os_intermediate->pbCertEncoded),
             os_intermediate->cbCertEncoded));
     if (!intermediate_cert_handle)
       return nullptr;
-    intermediates_raw.push_back(intermediate_cert_handle.get());
     intermediates.push_back(std::move(intermediate_cert_handle));
   }
   scoped_refptr<X509Certificate> result(
-      X509Certificate::CreateFromHandleUnsafeOptions(
-          cert_handle.get(), intermediates_raw, options));
+      X509Certificate::CreateFromBufferUnsafeOptions(
+          std::move(cert_handle), std::move(intermediates), options));
   return result;
 }
 
@@ -80,19 +78,17 @@
   PCCERT_CONTEXT primary_cert = nullptr;
 
   BOOL ok = CertAddEncodedCertificateToStore(
-      store.get(), X509_ASN_ENCODING,
-      CRYPTO_BUFFER_data(cert->os_cert_handle()),
-      base::checked_cast<DWORD>(CRYPTO_BUFFER_len(cert->os_cert_handle())),
+      store.get(), X509_ASN_ENCODING, CRYPTO_BUFFER_data(cert->cert_buffer()),
+      base::checked_cast<DWORD>(CRYPTO_BUFFER_len(cert->cert_buffer())),
       CERT_STORE_ADD_ALWAYS, &primary_cert);
   if (!ok || !primary_cert)
     return nullptr;
   ScopedPCCERT_CONTEXT scoped_primary_cert(primary_cert);
 
-  for (X509Certificate::OSCertHandle intermediate :
-       cert->GetIntermediateCertificates()) {
+  for (const auto& intermediate : cert->intermediate_buffers()) {
     ok = CertAddEncodedCertificateToStore(
-        store.get(), X509_ASN_ENCODING, CRYPTO_BUFFER_data(intermediate),
-        base::checked_cast<DWORD>(CRYPTO_BUFFER_len(intermediate)),
+        store.get(), X509_ASN_ENCODING, CRYPTO_BUFFER_data(intermediate.get()),
+        base::checked_cast<DWORD>(CRYPTO_BUFFER_len(intermediate.get())),
         CERT_STORE_ADD_ALWAYS, NULL);
     if (!ok) {
       if (invalid_intermediate_behavior == InvalidIntermediateBehavior::kFail)
diff --git a/net/dns/mdns_client_impl.cc b/net/dns/mdns_client_impl.cc
index a4902c4..04e2bb5 100644
--- a/net/dns/mdns_client_impl.cc
+++ b/net/dns/mdns_client_impl.cc
@@ -417,19 +417,18 @@
 }
 
 MDnsClientImpl::MDnsClientImpl()
-    : clock_(new base::DefaultClock),
-      cleanup_timer_(new base::Timer(false, false)) {
-}
+    : clock_(base::DefaultClock::GetInstance()),
+      cleanup_timer_(new base::Timer(false, false)) {}
 
-MDnsClientImpl::MDnsClientImpl(std::unique_ptr<base::Clock> clock,
+MDnsClientImpl::MDnsClientImpl(base::Clock* clock,
                                std::unique_ptr<base::Timer> timer)
-    : clock_(std::move(clock)), cleanup_timer_(std::move(timer)) {}
+    : clock_(clock), cleanup_timer_(std::move(timer)) {}
 
 MDnsClientImpl::~MDnsClientImpl() = default;
 
 bool MDnsClientImpl::StartListening(MDnsSocketFactory* socket_factory) {
   DCHECK(!core_.get());
-  core_.reset(new Core(clock_.get(), cleanup_timer_.get()));
+  core_.reset(new Core(clock_, cleanup_timer_.get()));
   if (!core_->Init(socket_factory)) {
     core_.reset();
     return false;
@@ -450,7 +449,7 @@
     const std::string& name,
     MDnsListener::Delegate* delegate) {
   return std::unique_ptr<MDnsListener>(
-      new MDnsListenerImpl(rrtype, name, clock_.get(), delegate, this));
+      new MDnsListenerImpl(rrtype, name, clock_, delegate, this));
 }
 
 std::unique_ptr<MDnsTransaction> MDnsClientImpl::CreateTransaction(
diff --git a/net/dns/mdns_client_impl.h b/net/dns/mdns_client_impl.h
index ad47898..c35aaa8b 100644
--- a/net/dns/mdns_client_impl.h
+++ b/net/dns/mdns_client_impl.h
@@ -209,11 +209,11 @@
   FRIEND_TEST_ALL_PREFIXES(MDnsTest, CacheCleanupWithShortTTL);
 
   // Test constructor, takes a mock clock and mock timer.
-  MDnsClientImpl(std::unique_ptr<base::Clock> clock,
+  MDnsClientImpl(base::Clock* clock,
                  std::unique_ptr<base::Timer> cleanup_timer);
 
   std::unique_ptr<Core> core_;
-  std::unique_ptr<base::Clock> clock_;
+  base::Clock* clock_;
   std::unique_ptr<base::Timer> cleanup_timer_;
 
   DISALLOW_COPY_AND_ASSIGN(MDnsClientImpl);
diff --git a/net/dns/mdns_client_unittest.cc b/net/dns/mdns_client_unittest.cc
index 76eb106..a8dff273 100644
--- a/net/dns/mdns_client_unittest.cc
+++ b/net/dns/mdns_client_unittest.cc
@@ -361,9 +361,9 @@
   int ttl_;
 };
 
-class MockClock : public base::DefaultClock {
+class MockClock : public base::Clock {
  public:
-  MockClock() : base::DefaultClock() {}
+  MockClock() = default;
   virtual ~MockClock() = default;
 
   MOCK_METHOD0(Now, base::Time());
@@ -557,15 +557,14 @@
   // Use a nonzero starting time as a base.
   base::Time start_time = base::Time() + base::TimeDelta::FromSeconds(1);
 
-  MockClock* clock = new MockClock;
+  MockClock clock;
   MockTimer* timer = new MockTimer;
 
-  test_client_.reset(
-      new MDnsClientImpl(base::WrapUnique(clock), base::WrapUnique(timer)));
+  test_client_.reset(new MDnsClientImpl(&clock, base::WrapUnique(timer)));
   test_client_->StartListening(&socket_factory_);
 
   EXPECT_CALL(*timer, StartObserver(_, _, _)).Times(1);
-  EXPECT_CALL(*clock, Now())
+  EXPECT_CALL(clock, Now())
       .Times(3)
       .WillRepeatedly(Return(start_time))
       .RetiresOnSaturation();
@@ -600,10 +599,10 @@
   // Set the clock to 2.0s, which should clean up the 'privet' record, but not
   // the printer. The mock clock will change Now() mid-execution from 2s to 4s.
   // Note: expectations are FILO-ordered -- t+2 seconds is returned, then t+4.
-  EXPECT_CALL(*clock, Now())
+  EXPECT_CALL(clock, Now())
       .WillOnce(Return(start_time + base::TimeDelta::FromSeconds(4)))
       .RetiresOnSaturation();
-  EXPECT_CALL(*clock, Now())
+  EXPECT_CALL(clock, Now())
       .WillOnce(Return(start_time + base::TimeDelta::FromSeconds(2)))
       .RetiresOnSaturation();
 
diff --git a/net/http/http_cache.cc b/net/http/http_cache.cc
index 0653b25..3ce4c4b 100644
--- a/net/http/http_cache.cc
+++ b/net/http/http_cache.cc
@@ -321,7 +321,7 @@
       fail_conditionalization_for_test_(false),
       mode_(NORMAL),
       network_layer_(std::move(network_layer)),
-      clock_(new base::DefaultClock()),
+      clock_(base::DefaultClock::GetInstance()),
       weak_factory_(this) {
   HttpNetworkSession* session = network_layer_->GetSession();
   // Session may be NULL in unittests.
diff --git a/net/http/http_cache.h b/net/http/http_cache.h
index 975812e..407dcb3 100644
--- a/net/http/http_cache.h
+++ b/net/http/http_cache.h
@@ -170,10 +170,8 @@
   Mode mode() { return mode_; }
 
   // Get/Set the cache's clock. These are public only for testing.
-  void SetClockForTesting(std::unique_ptr<base::Clock> clock) {
-    clock_ = std::move(clock);
-  }
-  base::Clock* clock() const { return clock_.get(); }
+  void SetClockForTesting(base::Clock* clock) { clock_ = clock; }
+  base::Clock* clock() const { return clock_; }
 
   // Close currently active sockets so that fresh page loads will not use any
   // recycled connections.  For sockets currently in use, they may not close
@@ -566,7 +564,7 @@
   std::unique_ptr<PlaybackCacheMap> playback_cache_map_;
 
   // A clock that can be swapped out for testing.
-  std::unique_ptr<base::Clock> clock_;
+  base::Clock* clock_;
 
   THREAD_CHECKER(thread_checker_);
 
diff --git a/net/http/http_cache_unittest.cc b/net/http/http_cache_unittest.cc
index 7a77075..09275c45 100644
--- a/net/http/http_cache_unittest.cc
+++ b/net/http/http_cache_unittest.cc
@@ -9028,9 +9028,9 @@
 // transactions unless LOAD_SKIP_CACHE_VALIDATION is set.
 TEST(HttpCache, ValidLoadOnlyFromCache) {
   MockHttpCache cache;
-  base::SimpleTestClock* clock = new base::SimpleTestClock();
-  cache.http_cache()->SetClockForTesting(base::WrapUnique(clock));
-  cache.network_layer()->SetClock(clock);
+  base::SimpleTestClock clock;
+  cache.http_cache()->SetClockForTesting(&clock);
+  cache.network_layer()->SetClock(&clock);
 
   // Write a resource that will expire in 100 seconds.
   ScopedMockTransaction transaction(kSimpleGET_Transaction);
@@ -9038,7 +9038,7 @@
   RunTransactionTest(cache.http_cache(), transaction);
 
   // Move forward in time such that the cached response is no longer valid.
-  clock->Advance(base::TimeDelta::FromSeconds(101));
+  clock.Advance(base::TimeDelta::FromSeconds(101));
 
   // Skipping cache validation should still return a response.
   transaction.load_flags = LOAD_ONLY_FROM_CACHE | LOAD_SKIP_CACHE_VALIDATION;
@@ -9915,9 +9915,8 @@
   HttpCachePrefetchValidationTest() : transaction_(kSimpleGET_Transaction) {
     DCHECK_LT(kMaxAgeSecs, prefetch_reuse_mins() * kNumSecondsPerMinute);
 
-    clock_ = new base::SimpleTestClock();
-    cache_.http_cache()->SetClockForTesting(base::WrapUnique(clock_));
-    cache_.network_layer()->SetClock(clock_);
+    cache_.http_cache()->SetClockForTesting(&clock_);
+    cache_.network_layer()->SetClock(&clock_);
 
     transaction_.response_headers = "Cache-Control: max-age=100\n";
   }
@@ -9930,7 +9929,7 @@
   }
 
   void AdvanceTime(int seconds) {
-    clock_->Advance(base::TimeDelta::FromSeconds(seconds));
+    clock_.Advance(base::TimeDelta::FromSeconds(seconds));
   }
 
   int prefetch_reuse_mins() { return HttpCache::kPrefetchReuseMins; }
@@ -9945,7 +9944,7 @@
   MockHttpCache cache_;
   ScopedMockTransaction transaction_;
   std::string response_headers_;
-  base::SimpleTestClock* clock_;
+  base::SimpleTestClock clock_;
 };
 
 TEST_F(HttpCachePrefetchValidationTest, SkipValidationShortlyAfterPrefetch) {
diff --git a/net/http/http_server_properties_impl.cc b/net/http/http_server_properties_impl.cc
index 37248e6..a17489c8 100644
--- a/net/http/http_server_properties_impl.cc
+++ b/net/http/http_server_properties_impl.cc
@@ -21,7 +21,9 @@
 namespace net {
 
 HttpServerPropertiesImpl::HttpServerPropertiesImpl(base::TickClock* clock)
-    : broken_alternative_services_(this, clock ? clock : &default_clock_),
+    : broken_alternative_services_(
+          this,
+          clock ? clock : base::DefaultTickClock::GetInstance()),
       quic_server_info_map_(kDefaultMaxQuicServerEntries),
       max_server_configs_stored_in_properties_(kDefaultMaxQuicServerEntries) {
   canonical_suffixes_.push_back(".ggpht.com");
diff --git a/net/http/http_server_properties_impl.h b/net/http/http_server_properties_impl.h
index dbb0ffd..d523f32 100644
--- a/net/http/http_server_properties_impl.h
+++ b/net/http/http_server_properties_impl.h
@@ -176,8 +176,6 @@
   // have an entry associated with |server|, the method will add one.
   void UpdateCanonicalServerInfoMap(const QuicServerId& server);
 
-  base::DefaultTickClock default_clock_;
-
   SpdyServersMap spdy_servers_map_;
   Http11ServerHostPortSet http11_servers_;
 
diff --git a/net/http/http_server_properties_manager.cc b/net/http/http_server_properties_manager.cc
index 38948714..b10e408 100644
--- a/net/http/http_server_properties_manager.cc
+++ b/net/http/http_server_properties_manager.cc
@@ -98,7 +98,7 @@
     NetLog* net_log,
     base::TickClock* clock)
     : pref_delegate_(std::move(pref_delegate)),
-      clock_(clock ? clock : &default_clock_),
+      clock_(clock ? clock : base::DefaultTickClock::GetInstance()),
       net_log_(
           NetLogWithSource::Make(net_log,
                                  NetLogSourceType::HTTP_SERVER_PROPERTIES)) {
diff --git a/net/http/http_server_properties_manager.h b/net/http/http_server_properties_manager.h
index b77b9057c..c1ee36a 100644
--- a/net/http/http_server_properties_manager.h
+++ b/net/http/http_server_properties_manager.h
@@ -253,8 +253,6 @@
           recently_broken_alternative_services,
       base::DictionaryValue* http_server_properties_dict);
 
-  base::DefaultTickClock default_clock_;
-
   // Used to post cache update tasks.
   base::OneShotTimer pref_cache_update_timer_;
 
diff --git a/net/http/http_server_properties_manager_unittest.cc b/net/http/http_server_properties_manager_unittest.cc
index e5eea96..ecdb1c3 100644
--- a/net/http/http_server_properties_manager_unittest.cc
+++ b/net/http/http_server_properties_manager_unittest.cc
@@ -104,10 +104,11 @@
     advertised_versions_ = HttpNetworkSession::Params().quic_supported_versions;
     pref_delegate_ = new MockPrefDelegate;
 
-    net_test_task_runner_clock_ = test_task_runner_->GetMockTickClock();
+    clock_ = test_task_runner_->GetMockTickClock();
+    net_test_task_runner_clock_ = clock_.get();
     http_server_props_manager_ = std::make_unique<HttpServerPropertiesManager>(
         base::WrapUnique(pref_delegate_), /*net_log=*/nullptr,
-        net_test_task_runner_clock_.get());
+        net_test_task_runner_clock_);
 
     EXPECT_FALSE(http_server_props_manager_->IsInitialized());
     pref_delegate_->SetPrefs(base::DictionaryValue());
@@ -140,7 +141,11 @@
   // Overrides the main thread's message loop with a mock tick clock.
   base::ScopedMockTimeMessageLoopTaskRunner test_task_runner_;
 
-  std::unique_ptr<base::TickClock> net_test_task_runner_clock_;
+  // TODO(tzik): Remove |clock_| after updating GetMockTickClock to own the
+  // instance.
+  std::unique_ptr<base::TickClock> clock_;
+
+  base::TickClock* net_test_task_runner_clock_;
 
  private:
   DISALLOW_COPY_AND_ASSIGN(HttpServerPropertiesManagerTest);
diff --git a/net/http/http_stream_factory_impl_job.cc b/net/http/http_stream_factory_impl_job.cc
index d90620f..9dfc650 100644
--- a/net/http/http_stream_factory_impl_job.cc
+++ b/net/http/http_stream_factory_impl_job.cc
@@ -928,9 +928,10 @@
   // connection this request can pool to.  If so, then go straight to using
   // that.
   if (CanUseExistingSpdySession()) {
-    existing_spdy_session_ =
-        session_->spdy_session_pool()->push_promise_index()->FindSession(
-            spdy_session_key_, origin_url_);
+    // TODO(bnc): Use outparam.  https://crbug.com/776415.
+    SpdyStreamId unused;
+    session_->spdy_session_pool()->push_promise_index()->FindSession(
+        spdy_session_key_, origin_url_, &existing_spdy_session_, &unused);
     if (!existing_spdy_session_) {
       existing_spdy_session_ =
           session_->spdy_session_pool()->FindAvailableSession(
@@ -1205,9 +1206,10 @@
   // It is possible that a pushed stream has been opened by a server since last
   // time Job checked above.
   if (!existing_spdy_session_) {
-    existing_spdy_session_ =
-        session_->spdy_session_pool()->push_promise_index()->FindSession(
-            spdy_session_key_, origin_url_);
+    // TODO(bnc): Use outparam.  https://crbug.com/776415.
+    SpdyStreamId unused;
+    session_->spdy_session_pool()->push_promise_index()->FindSession(
+        spdy_session_key_, origin_url_, &existing_spdy_session_, &unused);
     // It is also possible that an HTTP/2 connection has been established since
     // last time Job checked above.
     if (!existing_spdy_session_) {
diff --git a/net/http/transport_security_state_unittest.cc b/net/http/transport_security_state_unittest.cc
index d7a0df2..b21338c 100644
--- a/net/http/transport_security_state_unittest.cc
+++ b/net/http/transport_security_state_unittest.cc
@@ -2220,8 +2220,8 @@
   ASSERT_TRUE(cert);
 
   HashValueVector hashes;
-  hashes.push_back(HashValue(
-      X509Certificate::CalculateFingerprint256(cert->os_cert_handle())));
+  hashes.push_back(
+      HashValue(X509Certificate::CalculateFingerprint256(cert->cert_buffer())));
 
   {
     TransportSecurityState state;
diff --git a/net/network_error_logging/network_error_logging_service.cc b/net/network_error_logging/network_error_logging_service.cc
index b1773129..1b1b313 100644
--- a/net/network_error_logging/network_error_logging_service.cc
+++ b/net/network_error_logging/network_error_logging_service.cc
@@ -192,13 +192,13 @@
 }
 
 void NetworkErrorLoggingService::SetTickClockForTesting(
-    std::unique_ptr<base::TickClock> tick_clock) {
+    base::TickClock* tick_clock) {
   DCHECK(tick_clock);
-  tick_clock_ = std::move(tick_clock);
+  tick_clock_ = tick_clock;
 }
 
 NetworkErrorLoggingService::NetworkErrorLoggingService()
-    : tick_clock_(base::MakeUnique<base::DefaultTickClock>()),
+    : tick_clock_(base::DefaultTickClock::GetInstance()),
       reporting_service_(nullptr) {}
 
 bool NetworkErrorLoggingService::ParseHeader(const std::string& json_value,
diff --git a/net/network_error_logging/network_error_logging_service.h b/net/network_error_logging/network_error_logging_service.h
index 759bb45..53a577f 100644
--- a/net/network_error_logging/network_error_logging_service.h
+++ b/net/network_error_logging/network_error_logging_service.h
@@ -67,7 +67,7 @@
 
   void OnNetworkError(const ErrorDetails& details) override;
 
-  void SetTickClockForTesting(std::unique_ptr<base::TickClock> tick_clock);
+  void SetTickClockForTesting(base::TickClock* tick_clock);
 
  private:
   // NEL Policy set by an origin.
@@ -113,7 +113,7 @@
       const std::string& type,
       const ErrorDetails& details) const;
 
-  std::unique_ptr<base::TickClock> tick_clock_;
+  base::TickClock* tick_clock_;
 
   // Unowned.
   ReportingService* reporting_service_;
diff --git a/net/nqe/network_quality_estimator.cc b/net/nqe/network_quality_estimator.cc
index d5d3190..098e660 100644
--- a/net/nqe/network_quality_estimator.cc
+++ b/net/nqe/network_quality_estimator.cc
@@ -218,7 +218,7 @@
     : params_(std::move(params)),
       use_localhost_requests_(false),
       disable_offline_check_(false),
-      tick_clock_(new base::DefaultTickClock()),
+      tick_clock_(base::DefaultTickClock::GetInstance()),
       last_connection_change_(tick_clock_->NowTicks()),
       current_network_id_(nqe::internal::NetworkID(
           NetworkChangeNotifier::ConnectionType::CONNECTION_UNKNOWN,
@@ -226,17 +226,17 @@
           INT32_MIN)),
       http_downstream_throughput_kbps_observations_(
           params_.get(),
-          tick_clock_.get(),
+          tick_clock_,
           params_->weight_multiplier_per_second(),
           params_->weight_multiplier_per_signal_strength_level()),
       http_rtt_ms_observations_(
           params_.get(),
-          tick_clock_.get(),
+          tick_clock_,
           params_->weight_multiplier_per_second(),
           params_->weight_multiplier_per_signal_strength_level()),
       transport_rtt_ms_observations_(
           params_.get(),
-          tick_clock_.get(),
+          tick_clock_,
           params_->weight_multiplier_per_second(),
           params_->weight_multiplier_per_signal_strength_level()),
       effective_connection_type_at_last_main_frame_(
@@ -272,7 +272,7 @@
       this, params_.get(), base::ThreadTaskRunnerHandle::Get(),
       base::Bind(&NetworkQualityEstimator::OnNewThroughputObservationAvailable,
                  base::Unretained(this)),
-      tick_clock_.get(), net_log_));
+      tick_clock_, net_log_));
 
   watcher_factory_.reset(new nqe::internal::SocketWatcherFactory(
       base::ThreadTaskRunnerHandle::Get(),
@@ -281,7 +281,7 @@
                  base::Unretained(this)),
       base::Bind(&NetworkQualityEstimator::ShouldSocketWatcherNotifyRTT,
                  base::Unretained(this)),
-      tick_clock_.get()));
+      tick_clock_));
 
   // Record accuracy after a 15 second interval. The values used here must
   // remain in sync with the suffixes specified in
@@ -1669,15 +1669,15 @@
 }
 
 void NetworkQualityEstimator::SetTickClockForTesting(
-    std::unique_ptr<base::TickClock> tick_clock) {
+    base::TickClock* tick_clock) {
   DCHECK(thread_checker_.CalledOnValidThread());
-  tick_clock_ = std::move(tick_clock);
-  http_rtt_ms_observations_.SetTickClockForTesting(tick_clock_.get());
-  transport_rtt_ms_observations_.SetTickClockForTesting(tick_clock_.get());
+  tick_clock_ = tick_clock;
+  http_rtt_ms_observations_.SetTickClockForTesting(tick_clock_);
+  transport_rtt_ms_observations_.SetTickClockForTesting(tick_clock_);
   http_downstream_throughput_kbps_observations_.SetTickClockForTesting(
-      tick_clock_.get());
-  throughput_analyzer_->SetTickClockForTesting(tick_clock_.get());
-  watcher_factory_->SetTickClockForTesting(tick_clock_.get());
+      tick_clock_);
+  throughput_analyzer_->SetTickClockForTesting(tick_clock_);
+  watcher_factory_->SetTickClockForTesting(tick_clock_);
 }
 
 double NetworkQualityEstimator::RandDouble() const {
diff --git a/net/nqe/network_quality_estimator.h b/net/nqe/network_quality_estimator.h
index 86f0a3f1..85ae272 100644
--- a/net/nqe/network_quality_estimator.h
+++ b/net/nqe/network_quality_estimator.h
@@ -272,7 +272,7 @@
       const;
 
   // Overrides the tick clock used by |this| for testing.
-  void SetTickClockForTesting(std::unique_ptr<base::TickClock> tick_clock);
+  void SetTickClockForTesting(base::TickClock* tick_clock);
 
   // Returns a random double in the range [0.0, 1.0). Virtualized for testing.
   virtual double RandDouble() const;
@@ -567,7 +567,7 @@
   bool disable_offline_check_;
 
   // Tick clock used by the network quality estimator.
-  std::unique_ptr<base::TickClock> tick_clock_;
+  base::TickClock* tick_clock_;
 
   // Intervals after the main frame request arrives at which accuracy of network
   // quality prediction is recorded.
diff --git a/net/nqe/network_quality_estimator_unittest.cc b/net/nqe/network_quality_estimator_unittest.cc
index 7b28ded..1ee6136 100644
--- a/net/nqe/network_quality_estimator_unittest.cc
+++ b/net/nqe/network_quality_estimator_unittest.cc
@@ -1669,9 +1669,7 @@
 // interval, and that the observers are notified of any change.
 TEST(NetworkQualityEstimatorTest, MAYBE_TestEffectiveConnectionTypeObserver) {
   base::HistogramTester histogram_tester;
-  std::unique_ptr<base::SimpleTestTickClock> tick_clock(
-      new base::SimpleTestTickClock());
-  base::SimpleTestTickClock* tick_clock_ptr = tick_clock.get();
+  base::SimpleTestTickClock tick_clock;
 
   TestEffectiveConnectionTypeObserver observer;
   std::map<std::string, std::string> variation_params;
@@ -1681,7 +1679,7 @@
   // |observer| may be notified as soon as it is added. Run the loop to so that
   // the notification to |observer| is finished.
   base::RunLoop().RunUntilIdle();
-  estimator.SetTickClockForTesting(std::move(tick_clock));
+  estimator.SetTickClockForTesting(&tick_clock);
 
   TestDelegate test_delegate;
   TestURLRequestContext context(true);
@@ -1694,7 +1692,7 @@
       base::TimeDelta::FromMilliseconds(1500));
   estimator.set_start_time_null_downlink_throughput_kbps(100000);
 
-  tick_clock_ptr->Advance(base::TimeDelta::FromMinutes(60));
+  tick_clock.Advance(base::TimeDelta::FromMinutes(60));
 
   std::unique_ptr<URLRequest> request(
       context.CreateRequest(estimator.GetEchoURL(), DEFAULT_PRIORITY,
@@ -1872,11 +1870,9 @@
     variation_params["add_default_platform_observations"] = "false";
     TestNetworkQualityEstimator estimator(variation_params);
 
-    std::unique_ptr<base::SimpleTestTickClock> tick_clock(
-        new base::SimpleTestTickClock());
-    tick_clock->Advance(base::TimeDelta::FromSeconds(1));
-    base::SimpleTestTickClock* tick_clock_ptr = tick_clock.get();
-    estimator.SetTickClockForTesting(std::move(tick_clock));
+    base::SimpleTestTickClock tick_clock;
+    tick_clock.Advance(base::TimeDelta::FromSeconds(1));
+    estimator.SetTickClockForTesting(&tick_clock);
 
     estimator.set_start_time_null_http_rtt(test.http_rtt);
     estimator.set_start_time_null_transport_rtt(test.transport_rtt);
@@ -1888,7 +1884,7 @@
 
     // Add one observation to ensure ECT is not computed for each request.
     estimator.AddAndNotifyObserversOfRTT(NetworkQualityEstimator::Observation(
-        test.http_rtt.InMilliseconds(), tick_clock_ptr->NowTicks(), INT32_MIN,
+        test.http_rtt.InMilliseconds(), tick_clock.NowTicks(), INT32_MIN,
         NETWORK_QUALITY_OBSERVATION_SOURCE_HTTP));
 
     estimator.RunOneRequest();
@@ -1903,16 +1899,14 @@
 // that the network quality observers are notified of any change.
 TEST(NetworkQualityEstimatorTest, TestRTTAndThroughputEstimatesObserver) {
   base::HistogramTester histogram_tester;
-  std::unique_ptr<base::SimpleTestTickClock> tick_clock(
-      new base::SimpleTestTickClock());
-  base::SimpleTestTickClock* tick_clock_ptr = tick_clock.get();
+  base::SimpleTestTickClock tick_clock;
 
   TestRTTAndThroughputEstimatesObserver observer;
   std::map<std::string, std::string> variation_params;
   variation_params["add_default_platform_observations"] = "false";
   TestNetworkQualityEstimator estimator(variation_params);
   estimator.AddRTTAndThroughputEstimatesObserver(&observer);
-  estimator.SetTickClockForTesting(std::move(tick_clock));
+  estimator.SetTickClockForTesting(&tick_clock);
 
   TestDelegate test_delegate;
   TestURLRequestContext context(true);
@@ -1933,7 +1927,7 @@
   estimator.set_start_time_null_transport_rtt(transport_rtt);
   estimator.set_start_time_null_downlink_throughput_kbps(
       downstream_throughput_kbps);
-  tick_clock_ptr->Advance(base::TimeDelta::FromMinutes(60));
+  tick_clock.Advance(base::TimeDelta::FromMinutes(60));
 
   std::unique_ptr<URLRequest> request(
       context.CreateRequest(estimator.GetEchoURL(), DEFAULT_PRIORITY,
@@ -2005,17 +1999,15 @@
 // Tests that the effective connection type is computed on every RTT
 // observation if the last computed effective connection type was unknown.
 TEST(NetworkQualityEstimatorTest, UnknownEffectiveConnectionType) {
-  std::unique_ptr<base::SimpleTestTickClock> tick_clock(
-      new base::SimpleTestTickClock());
-  base::SimpleTestTickClock* tick_clock_ptr = tick_clock.get();
+  base::SimpleTestTickClock tick_clock;
 
   TestEffectiveConnectionTypeObserver observer;
   std::map<std::string, std::string> variation_params;
   variation_params["add_default_platform_observations"] = "false";
   TestNetworkQualityEstimator estimator(variation_params);
-  estimator.SetTickClockForTesting(std::move(tick_clock));
+  estimator.SetTickClockForTesting(&tick_clock);
   estimator.AddEffectiveConnectionTypeObserver(&observer);
-  tick_clock_ptr->Advance(base::TimeDelta::FromMinutes(60));
+  tick_clock.Advance(base::TimeDelta::FromMinutes(60));
 
   size_t expected_effective_connection_type_notifications = 0;
   estimator.set_recent_effective_connection_type(
@@ -2027,7 +2019,7 @@
                                   "test");
 
   NetworkQualityEstimator::Observation rtt_observation(
-      5000, tick_clock_ptr->NowTicks(), INT32_MIN,
+      5000, tick_clock.NowTicks(), INT32_MIN,
       NETWORK_QUALITY_OBSERVATION_SOURCE_HTTP);
 
   for (size_t i = 0; i < 10; ++i) {
@@ -2041,7 +2033,7 @@
   // more RTT sample should trigger recomputation of the effective connection
   // type since the last computed effective connection type was unknown.
   estimator.AddAndNotifyObserversOfRTT(NetworkQualityEstimator::Observation(
-      5000, tick_clock_ptr->NowTicks(), INT32_MIN,
+      5000, tick_clock.NowTicks(), INT32_MIN,
       NETWORK_QUALITY_OBSERVATION_SOURCE_HTTP));
   ++expected_effective_connection_type_notifications;
   EXPECT_EQ(expected_effective_connection_type_notifications,
@@ -2053,15 +2045,13 @@
 TEST(NetworkQualityEstimatorTest,
      AdaptiveRecomputationEffectiveConnectionType) {
   base::HistogramTester histogram_tester;
-  std::unique_ptr<base::SimpleTestTickClock> tick_clock(
-      new base::SimpleTestTickClock());
-  base::SimpleTestTickClock* tick_clock_ptr = tick_clock.get();
+  base::SimpleTestTickClock tick_clock;
 
   TestEffectiveConnectionTypeObserver observer;
   std::map<std::string, std::string> variation_params;
   variation_params["add_default_platform_observations"] = "false";
   TestNetworkQualityEstimator estimator(variation_params);
-  estimator.SetTickClockForTesting(std::move(tick_clock));
+  estimator.SetTickClockForTesting(&tick_clock);
   estimator.SimulateNetworkChange(NetworkChangeNotifier::CONNECTION_WIFI,
                                   "test");
   estimator.AddEffectiveConnectionTypeObserver(&observer);
@@ -2077,7 +2067,7 @@
   EXPECT_EQ(0U, observer.effective_connection_types().size());
 
   estimator.set_recent_effective_connection_type(EFFECTIVE_CONNECTION_TYPE_2G);
-  tick_clock_ptr->Advance(base::TimeDelta::FromMinutes(60));
+  tick_clock.Advance(base::TimeDelta::FromMinutes(60));
 
   std::unique_ptr<URLRequest> request(
       context.CreateRequest(estimator.GetEchoURL(), DEFAULT_PRIORITY,
@@ -2129,7 +2119,7 @@
     // effective connection type.
     for (size_t i = 0; i < rtt_observations_count + 1; ++i) {
       estimator.AddAndNotifyObserversOfRTT(NetworkQualityEstimator::Observation(
-          5000, tick_clock_ptr->NowTicks(), INT32_MIN,
+          5000, tick_clock.NowTicks(), INT32_MIN,
           NETWORK_QUALITY_OBSERVATION_SOURCE_HTTP));
 
       if (i == rtt_observations_count) {
@@ -2245,15 +2235,13 @@
 }
 
 TEST(NetworkQualityEstimatorTest, TestGlobalSocketWatcherThrottle) {
-  std::unique_ptr<base::SimpleTestTickClock> tick_clock(
-      new base::SimpleTestTickClock());
-  base::SimpleTestTickClock* tick_clock_ptr = tick_clock.get();
-  tick_clock_ptr->Advance(base::TimeDelta::FromSeconds(1));
+  base::SimpleTestTickClock tick_clock;
+  tick_clock.Advance(base::TimeDelta::FromSeconds(1));
 
   std::map<std::string, std::string> variation_params;
   variation_params["add_default_platform_observations"] = "false";
   TestNetworkQualityEstimator estimator(variation_params);
-  estimator.SetTickClockForTesting(std::move(tick_clock));
+  estimator.SetTickClockForTesting(&tick_clock);
 
   TestRTTObserver rtt_observer;
   estimator.AddRTTObserver(&rtt_observer);
@@ -2294,7 +2282,7 @@
   EXPECT_EQ(2U, rtt_observer.observations().size());
   // Advancing the clock should make it possible to notify new RTT
   // notifications.
-  tick_clock_ptr->Advance(
+  tick_clock.Advance(
       estimator.params()->socket_watchers_min_notification_interval());
   EXPECT_TRUE(tcp_watcher->ShouldNotifyUpdatedRTT());
 
@@ -2314,10 +2302,8 @@
 // Tests that the TCP socket notifies the Network Quality Estimator of TCP RTTs,
 // which in turn notifies registered RTT observers.
 TEST(NetworkQualityEstimatorTest, MAYBE_TestTCPSocketRTT) {
-  std::unique_ptr<base::SimpleTestTickClock> tick_clock(
-      new base::SimpleTestTickClock());
-  base::SimpleTestTickClock* tick_clock_ptr = tick_clock.get();
-  tick_clock_ptr->Advance(base::TimeDelta::FromSeconds(1));
+  base::SimpleTestTickClock tick_clock;
+  tick_clock.Advance(base::TimeDelta::FromSeconds(1));
 
   base::HistogramTester histogram_tester;
   TestRTTObserver rtt_observer;
@@ -2328,7 +2314,7 @@
   TestNetworkQualityEstimator estimator(
       nullptr, variation_params, true, true,
       std::make_unique<BoundTestNetLog>());
-  estimator.SetTickClockForTesting(std::move(tick_clock));
+  estimator.SetTickClockForTesting(&tick_clock);
   estimator.SimulateNetworkChange(
       NetworkChangeNotifier::ConnectionType::CONNECTION_2G, "test");
 
@@ -2372,7 +2358,7 @@
                               &test_delegate, TRAFFIC_ANNOTATION_FOR_TESTS));
     request->SetLoadFlags(request->load_flags() | LOAD_MAIN_FRAME_DEPRECATED);
     request->Start();
-    tick_clock_ptr->Advance(
+    tick_clock.Advance(
         estimator.params()->socket_watchers_min_notification_interval());
 
     base::RunLoop().Run();
@@ -2494,10 +2480,8 @@
 
   for (const auto& accuracy_recording_delay : accuracy_recording_delays) {
     for (const auto& test : tests) {
-      std::unique_ptr<base::SimpleTestTickClock> tick_clock(
-          new base::SimpleTestTickClock());
-      base::SimpleTestTickClock* tick_clock_ptr = tick_clock.get();
-      tick_clock_ptr->Advance(base::TimeDelta::FromSeconds(1));
+      base::SimpleTestTickClock tick_clock;
+      tick_clock.Advance(base::TimeDelta::FromSeconds(1));
 
       std::unique_ptr<ExternalEstimateProvider> external_estimate_provider(
           new TestExternalEstimateProvider(test.rtt, 0));
@@ -2506,10 +2490,10 @@
       TestNetworkQualityEstimator estimator(
           variation_params, std::move(external_estimate_provider));
 
-      estimator.SetTickClockForTesting(std::move(tick_clock));
+      estimator.SetTickClockForTesting(&tick_clock);
       estimator.SimulateNetworkChange(
           NetworkChangeNotifier::ConnectionType::CONNECTION_WIFI, "test-1");
-      tick_clock_ptr->Advance(base::TimeDelta::FromSeconds(1));
+      tick_clock.Advance(base::TimeDelta::FromSeconds(1));
 
       std::vector<base::TimeDelta> accuracy_recording_intervals;
       accuracy_recording_intervals.push_back(accuracy_recording_delay);
@@ -2544,7 +2528,7 @@
       base::RunLoop().Run();
 
       if (accuracy_recording_delay != base::TimeDelta()) {
-        tick_clock_ptr->Advance(accuracy_recording_delay);
+        tick_clock.Advance(accuracy_recording_delay);
 
         // Sleep for some time to ensure that the delayed task is posted.
         base::PlatformThread::Sleep(accuracy_recording_delay * 2);
@@ -3321,17 +3305,15 @@
 
 TEST(NetworkQualityEstimatorTest,
      TestComputeIncreaseInTransportRTTFullHostsOverlap) {
-  std::unique_ptr<base::SimpleTestTickClock> tick_clock(
-      new base::SimpleTestTickClock());
-  base::SimpleTestTickClock* tick_clock_ptr = tick_clock.get();
-  tick_clock_ptr->Advance(base::TimeDelta::FromMinutes(1));
+  base::SimpleTestTickClock tick_clock;
+  tick_clock.Advance(base::TimeDelta::FromMinutes(1));
 
   std::map<std::string, std::string> variation_params;
   variation_params["add_default_platform_observations"] = "false";
   TestNetworkQualityEstimator estimator(variation_params);
-  estimator.SetTickClockForTesting(std::move(tick_clock));
+  estimator.SetTickClockForTesting(&tick_clock);
 
-  base::TimeTicks now = tick_clock_ptr->NowTicks();
+  base::TimeTicks now = tick_clock.NowTicks();
   base::TimeTicks recent = now - base::TimeDelta::FromMilliseconds(2500);
   base::TimeTicks historical = now - base::TimeDelta::FromSeconds(20);
 
@@ -3363,17 +3345,15 @@
 
 TEST(NetworkQualityEstimatorTest,
      TestComputeIncreaseInTransportRTTPartialHostsOverlap) {
-  std::unique_ptr<base::SimpleTestTickClock> tick_clock(
-      new base::SimpleTestTickClock());
-  base::SimpleTestTickClock* tick_clock_ptr = tick_clock.get();
-  tick_clock_ptr->Advance(base::TimeDelta::FromMinutes(1));
+  base::SimpleTestTickClock tick_clock;
+  tick_clock.Advance(base::TimeDelta::FromMinutes(1));
 
   std::map<std::string, std::string> variation_params;
   variation_params["add_default_platform_observations"] = "false";
   TestNetworkQualityEstimator estimator(variation_params);
-  estimator.SetTickClockForTesting(std::move(tick_clock));
+  estimator.SetTickClockForTesting(&tick_clock);
 
-  base::TimeTicks now = tick_clock_ptr->NowTicks();
+  base::TimeTicks now = tick_clock.NowTicks();
   base::TimeTicks recent = now - base::TimeDelta::FromMilliseconds(2500);
   base::TimeTicks historical = now - base::TimeDelta::FromSeconds(20);
 
@@ -3518,20 +3498,18 @@
 // Tests that the ECT is computed when more than N RTT samples have been
 // received.
 TEST(NetworkQualityEstimatorTest, MaybeComputeECTAfterNSamples) {
-  std::unique_ptr<base::SimpleTestTickClock> tick_clock(
-      new base::SimpleTestTickClock());
-  base::SimpleTestTickClock* tick_clock_ptr = tick_clock.get();
-  tick_clock_ptr->Advance(base::TimeDelta::FromMinutes(1));
+  base::SimpleTestTickClock tick_clock;
+  tick_clock.Advance(base::TimeDelta::FromMinutes(1));
 
   std::map<std::string, std::string> variation_params;
   variation_params["add_default_platform_observations"] = "false";
   TestNetworkQualityEstimator estimator(variation_params);
   estimator.DisableOfflineCheckForTesting(true);
   base::RunLoop().RunUntilIdle();
-  estimator.SetTickClockForTesting(std::move(tick_clock));
+  estimator.SetTickClockForTesting(&tick_clock);
   estimator.SimulateNetworkChange(
       NetworkChangeNotifier::ConnectionType::CONNECTION_UNKNOWN, "test");
-  tick_clock_ptr->Advance(base::TimeDelta::FromMinutes(1));
+  tick_clock.Advance(base::TimeDelta::FromMinutes(1));
 
   const base::TimeDelta rtt = base::TimeDelta::FromSeconds(1);
   uint64_t host = 1u;
@@ -3540,18 +3518,18 @@
   // to observation buffer's size increasing to 1.5x.
   for (size_t i = 0; i < estimator.params()->observation_buffer_size(); ++i) {
     estimator.AddAndNotifyObserversOfRTT(NetworkQualityEstimator::Observation(
-        rtt.InMilliseconds(), tick_clock_ptr->NowTicks(), INT32_MIN,
+        rtt.InMilliseconds(), tick_clock.NowTicks(), INT32_MIN,
         NETWORK_QUALITY_OBSERVATION_SOURCE_HTTP, host));
   }
   EXPECT_EQ(rtt, estimator.GetHttpRTT().value());
-  tick_clock_ptr->Advance(base::TimeDelta::FromMinutes(60));
+  tick_clock.Advance(base::TimeDelta::FromMinutes(60));
 
   const base::TimeDelta rtt_new = base::TimeDelta::FromSeconds(3);
   for (size_t i = 0;
        i < estimator.params()->count_new_observations_received_compute_ect();
        ++i) {
     estimator.AddAndNotifyObserversOfRTT(NetworkQualityEstimator::Observation(
-        rtt_new.InMilliseconds(), tick_clock_ptr->NowTicks(), INT32_MIN,
+        rtt_new.InMilliseconds(), tick_clock.NowTicks(), INT32_MIN,
         NETWORK_QUALITY_OBSERVATION_SOURCE_HTTP, host));
   }
   EXPECT_EQ(rtt_new, estimator.GetHttpRTT().value());
diff --git a/net/nqe/throughput_analyzer_unittest.cc b/net/nqe/throughput_analyzer_unittest.cc
index 66432232..4e9c3106 100644
--- a/net/nqe/throughput_analyzer_unittest.cc
+++ b/net/nqe/throughput_analyzer_unittest.cc
@@ -126,12 +126,12 @@
                }};
 
   for (const auto& test : tests) {
-    base::DefaultTickClock tick_clock;
+    base::DefaultTickClock* tick_clock = base::DefaultTickClock::GetInstance();
     TestNetworkQualityProvider network_quality_provider;
     std::map<std::string, std::string> variation_params;
     NetworkQualityEstimatorParams params(variation_params);
     TestThroughputAnalyzer throughput_analyzer(&network_quality_provider,
-                                               &params, &tick_clock);
+                                               &params, tick_clock);
 
     TestDelegate test_delegate;
     TestURLRequestContext context;
@@ -168,7 +168,7 @@
 // Tests that the throughput observation is taken only if there are sufficient
 // number of requests in-flight.
 TEST(ThroughputAnalyzerTest, TestMinRequestsForThroughputSample) {
-  base::DefaultTickClock tick_clock;
+  base::DefaultTickClock* tick_clock = base::DefaultTickClock::GetInstance();
   TestNetworkQualityProvider network_quality_provider;
   std::map<std::string, std::string> variation_params;
   NetworkQualityEstimatorParams params(variation_params);
@@ -177,7 +177,7 @@
        num_requests <= params.throughput_min_requests_in_flight() + 1;
        ++num_requests) {
     TestThroughputAnalyzer throughput_analyzer(&network_quality_provider,
-                                               &params, &tick_clock);
+                                               &params, tick_clock);
     TestDelegate test_delegate;
     TestURLRequestContext context;
     throughput_analyzer.AddIPAddressResolution(&context);
@@ -270,7 +270,7 @@
 
   for (const auto& test : tests) {
     base::HistogramTester histogram_tester;
-    base::DefaultTickClock tick_clock;
+    base::DefaultTickClock* tick_clock = base::DefaultTickClock::GetInstance();
     TestNetworkQualityProvider network_quality_provider;
     if (test.http_rtt >= base::TimeDelta())
       network_quality_provider.SetHttpRtt(test.http_rtt);
@@ -283,7 +283,7 @@
 
     const size_t num_requests = params.throughput_min_requests_in_flight();
     TestThroughputAnalyzer throughput_analyzer(&network_quality_provider,
-                                               &params, &tick_clock);
+                                               &params, tick_clock);
     TestDelegate test_delegate;
     TestURLRequestContext context;
     throughput_analyzer.AddIPAddressResolution(&context);
@@ -557,13 +557,13 @@
   };
 
   for (const auto& test : tests) {
-    base::DefaultTickClock tick_clock;
+    base::DefaultTickClock* tick_clock = base::DefaultTickClock::GetInstance();
     TestNetworkQualityProvider network_quality_provider;
     // Localhost requests are not allowed for estimation purposes.
     std::map<std::string, std::string> variation_params;
     NetworkQualityEstimatorParams params(variation_params);
     TestThroughputAnalyzer throughput_analyzer(&network_quality_provider,
-                                               &params, &tick_clock);
+                                               &params, tick_clock);
 
     TestDelegate test_delegate;
     TestURLRequestContext context;
@@ -658,7 +658,7 @@
   };
 
   for (const auto& test : tests) {
-    base::DefaultTickClock tick_clock;
+    base::DefaultTickClock* tick_clock = base::DefaultTickClock::GetInstance();
     TestNetworkQualityProvider network_quality_provider;
     // Localhost requests are not allowed for estimation purposes.
     std::map<std::string, std::string> variation_params;
@@ -666,7 +666,7 @@
         base::IntToString(test.throughput_min_requests_in_flight);
     NetworkQualityEstimatorParams params(variation_params);
     TestThroughputAnalyzer throughput_analyzer(&network_quality_provider,
-                                               &params, &tick_clock);
+                                               &params, tick_clock);
     TestDelegate test_delegate;
     TestURLRequestContext context;
     throughput_analyzer.AddIPAddressResolution(&context);
@@ -716,13 +716,13 @@
 // of network requests overlap, and the minimum number of in flight requests
 // when taking an observation is more than 1.
 TEST(ThroughputAnalyzerTest, TestThroughputWithMultipleNetworkRequests) {
-  base::DefaultTickClock tick_clock;
+  base::DefaultTickClock* tick_clock = base::DefaultTickClock::GetInstance();
   TestNetworkQualityProvider network_quality_provider;
   std::map<std::string, std::string> variation_params;
   variation_params["throughput_min_requests_in_flight"] = "3";
   NetworkQualityEstimatorParams params(variation_params);
   TestThroughputAnalyzer throughput_analyzer(&network_quality_provider, &params,
-                                             &tick_clock);
+                                             tick_clock);
   TestDelegate test_delegate;
   TestURLRequestContext context;
   throughput_analyzer.AddIPAddressResolution(&context);
diff --git a/net/quic/chromium/crypto/proof_source_chromium.cc b/net/quic/chromium/crypto/proof_source_chromium.cc
index fdce1e9..6231a159 100644
--- a/net/quic/chromium/crypto/proof_source_chromium.cc
+++ b/net/quic/chromium/crypto/proof_source_chromium.cc
@@ -6,6 +6,7 @@
 
 #include "base/strings/string_number_conversions.h"
 #include "crypto/openssl_util.h"
+#include "net/cert/x509_util.h"
 #include "net/quic/core/crypto/crypto_protocol.h"
 #include "third_party/boringssl/src/include/openssl/digest.h"
 #include "third_party/boringssl/src/include/openssl/evp.h"
@@ -41,12 +42,8 @@
 
   std::vector<string> certs;
   for (const scoped_refptr<X509Certificate>& cert : certs_in_file) {
-    std::string der_encoded_cert;
-    if (!X509Certificate::GetDEREncoded(cert->os_cert_handle(),
-                                        &der_encoded_cert)) {
-      return false;
-    }
-    certs.push_back(der_encoded_cert);
+    certs.emplace_back(
+        x509_util::CryptoBufferAsStringPiece(cert->cert_buffer()));
   }
   chain_ = new ProofSource::Chain(certs);
 
diff --git a/net/quic/chromium/crypto/proof_verifier_chromium.cc b/net/quic/chromium/crypto/proof_verifier_chromium.cc
index fa695a1..e10b710 100644
--- a/net/quic/chromium/crypto/proof_verifier_chromium.cc
+++ b/net/quic/chromium/crypto/proof_verifier_chromium.cc
@@ -522,7 +522,7 @@
 
   size_t size_bits;
   X509Certificate::PublicKeyType type;
-  X509Certificate::GetPublicKeyInfo(cert_->os_cert_handle(), &size_bits, &type);
+  X509Certificate::GetPublicKeyInfo(cert_->cert_buffer(), &size_bits, &type);
   if (type == X509Certificate::kPublicKeyTypeRSA) {
     crypto::SignatureVerifier::HashAlgorithm hash_alg =
         crypto::SignatureVerifier::SHA256;
diff --git a/net/quic/chromium/crypto/proof_verifier_chromium_test.cc b/net/quic/chromium/crypto/proof_verifier_chromium_test.cc
index 6155dd35..6695479 100644
--- a/net/quic/chromium/crypto/proof_verifier_chromium_test.cc
+++ b/net/quic/chromium/crypto/proof_verifier_chromium_test.cc
@@ -15,6 +15,7 @@
 #include "net/cert/ct_serialization.h"
 #include "net/cert/mock_cert_verifier.h"
 #include "net/cert/multi_log_ct_verifier.h"
+#include "net/cert/x509_util.h"
 #include "net/http/transport_security_state.h"
 #include "net/quic/chromium/crypto/proof_source_chromium.h"
 #include "net/quic/core/crypto/proof_verifier.h"
@@ -134,12 +135,9 @@
     scoped_refptr<X509Certificate> cert = GetTestServerCertificate();
     ASSERT_TRUE(cert);
 
-    std::string der_bytes;
-    ASSERT_TRUE(
-        X509Certificate::GetDEREncoded(cert->os_cert_handle(), &der_bytes));
-
     certs->clear();
-    certs->push_back(der_bytes);
+    certs->emplace_back(
+        x509_util::CryptoBufferAsStringPiece(cert->cert_buffer()));
   }
 
   std::string GetTestSignature() {
@@ -161,12 +159,9 @@
         der_test_cert.data(), der_test_cert.length());
     ASSERT_TRUE(test_cert.get());
 
-    std::string der_bytes;
-    ASSERT_TRUE(X509Certificate::GetDEREncoded(test_cert->os_cert_handle(),
-                                               &der_bytes));
-
     certs->clear();
-    certs->push_back(der_bytes);
+    certs->emplace_back(
+        x509_util::CryptoBufferAsStringPiece(test_cert->cert_buffer()));
   }
 
   void CheckSCT(bool sct_expected_ok) {
diff --git a/net/quic/chromium/quic_stream_factory_peer.cc b/net/quic/chromium/quic_stream_factory_peer.cc
index b338abd..21a7b74f 100644
--- a/net/quic/chromium/quic_stream_factory_peer.cc
+++ b/net/quic/chromium/quic_stream_factory_peer.cc
@@ -8,6 +8,7 @@
 #include <vector>
 
 #include "net/cert/x509_certificate.h"
+#include "net/cert/x509_util.h"
 #include "net/quic/chromium/quic_chromium_client_session.h"
 #include "net/quic/chromium/quic_http_stream.h"
 #include "net/quic/chromium/quic_stream_factory.h"
@@ -137,11 +138,7 @@
   scoped_refptr<X509Certificate> cert(
       ImportCertFromFile(GetTestCertsDirectory(), "wildcard.pem"));
   DCHECK(cert);
-  std::string der_bytes;
-  bool success =
-      X509Certificate::GetDEREncoded(cert->os_cert_handle(), &der_bytes);
-  DCHECK(success);
-  certs.push_back(der_bytes);
+  certs.emplace_back(x509_util::CryptoBufferAsStringPiece(cert->cert_buffer()));
 
   QuicCryptoClientConfig* crypto_config = &factory->crypto_config_;
   QuicCryptoClientConfig::CachedState* cached =
diff --git a/net/reporting/reporting_context.cc b/net/reporting/reporting_context.cc
index 6aa69733..4514993 100644
--- a/net/reporting/reporting_context.cc
+++ b/net/reporting/reporting_context.cc
@@ -34,8 +34,8 @@
   ReportingContextImpl(const ReportingPolicy& policy,
                        URLRequestContext* request_context)
       : ReportingContext(policy,
-                         std::make_unique<base::DefaultClock>(),
-                         std::make_unique<base::DefaultTickClock>(),
+                         base::DefaultClock::GetInstance(),
+                         base::DefaultTickClock::GetInstance(),
                          ReportingUploader::Create(request_context),
                          ReportingDelegate::Create(request_context)) {}
 };
@@ -67,13 +67,13 @@
 }
 
 ReportingContext::ReportingContext(const ReportingPolicy& policy,
-                                   std::unique_ptr<base::Clock> clock,
-                                   std::unique_ptr<base::TickClock> tick_clock,
+                                   base::Clock* clock,
+                                   base::TickClock* tick_clock,
                                    std::unique_ptr<ReportingUploader> uploader,
                                    std::unique_ptr<ReportingDelegate> delegate)
     : policy_(policy),
-      clock_(std::move(clock)),
-      tick_clock_(std::move(tick_clock)),
+      clock_(clock),
+      tick_clock_(tick_clock),
       uploader_(std::move(uploader)),
       delegate_(std::move(delegate)),
       cache_(ReportingCache::Create(this)),
diff --git a/net/reporting/reporting_context.h b/net/reporting/reporting_context.h
index 4f44334..b38c176 100644
--- a/net/reporting/reporting_context.h
+++ b/net/reporting/reporting_context.h
@@ -42,8 +42,8 @@
 
   const ReportingPolicy& policy() { return policy_; }
 
-  base::Clock* clock() { return clock_.get(); }
-  base::TickClock* tick_clock() { return tick_clock_.get(); }
+  base::Clock* clock() { return clock_; }
+  base::TickClock* tick_clock() { return tick_clock_; }
   ReportingUploader* uploader() { return uploader_.get(); }
 
   ReportingDelegate* delegate() { return delegate_.get(); }
@@ -63,16 +63,16 @@
 
  protected:
   ReportingContext(const ReportingPolicy& policy,
-                   std::unique_ptr<base::Clock> clock,
-                   std::unique_ptr<base::TickClock> tick_clock,
+                   base::Clock* clock,
+                   base::TickClock* tick_clock,
                    std::unique_ptr<ReportingUploader> uploader,
                    std::unique_ptr<ReportingDelegate> delegate);
 
  private:
   ReportingPolicy policy_;
 
-  std::unique_ptr<base::Clock> clock_;
-  std::unique_ptr<base::TickClock> tick_clock_;
+  base::Clock* clock_;
+  base::TickClock* tick_clock_;
   std::unique_ptr<ReportingUploader> uploader_;
 
   base::ObserverList<ReportingObserver, /* check_empty= */ true> observers_;
diff --git a/net/reporting/reporting_header_parser_fuzzer.cc b/net/reporting/reporting_header_parser_fuzzer.cc
index 1c31b9ec..470d496a 100644
--- a/net/reporting/reporting_header_parser_fuzzer.cc
+++ b/net/reporting/reporting_header_parser_fuzzer.cc
@@ -2,6 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "base/time/default_clock.h"
+#include "base/time/default_tick_clock.h"
 #include "base/time/time.h"
 #include "net/reporting/reporting_cache.h"
 #include "net/reporting/reporting_client.h"
@@ -24,7 +26,9 @@
 
 void FuzzReportingHeaderParser(const std::string& data,
                               const net::ReportingPolicy& policy) {
-  net::TestReportingContext context(policy);
+  net::TestReportingContext context(base::DefaultClock::GetInstance(),
+                                    base::DefaultTickClock::GetInstance(),
+                                    policy);
   net::ReportingHeaderParser::ParseHeader(&context, kUrl_, data.c_str());
   std::vector<const net::ReportingClient*> clients;
   context.cache()->GetClients(&clients);
diff --git a/net/reporting/reporting_service_unittest.cc b/net/reporting/reporting_service_unittest.cc
index d8978c81..24ebced 100644
--- a/net/reporting/reporting_service_unittest.cc
+++ b/net/reporting/reporting_service_unittest.cc
@@ -30,7 +30,8 @@
   const std::string kType_ = "type";
 
   ReportingServiceTest()
-      : context_(new TestReportingContext(ReportingPolicy())),
+      : context_(
+            new TestReportingContext(&clock_, &tick_clock_, ReportingPolicy())),
         service_(
             ReportingService::CreateForTesting(base::WrapUnique(context_))) {}
 
@@ -38,6 +39,9 @@
   ReportingService* service() { return service_.get(); }
 
  private:
+  base::SimpleTestClock clock_;
+  base::SimpleTestTickClock tick_clock_;
+
   TestReportingContext* context_;
   std::unique_ptr<ReportingService> service_;
 };
diff --git a/net/reporting/reporting_test_util.cc b/net/reporting/reporting_test_util.cc
index af02dd6..9fe8335 100644
--- a/net/reporting/reporting_test_util.cc
+++ b/net/reporting/reporting_test_util.cc
@@ -125,10 +125,12 @@
   return true;
 }
 
-TestReportingContext::TestReportingContext(const ReportingPolicy& policy)
+TestReportingContext::TestReportingContext(base::Clock* clock,
+                                           base::TickClock* tick_clock,
+                                           const ReportingPolicy& policy)
     : ReportingContext(policy,
-                       std::make_unique<base::SimpleTestClock>(),
-                       std::make_unique<base::SimpleTestTickClock>(),
+                       clock,
+                       tick_clock,
                        std::make_unique<TestReportingUploader>(),
                        std::make_unique<TestReportingDelegate>()),
       delivery_timer_(new base::MockTimer(/* retain_user_task= */ false,
@@ -169,7 +171,8 @@
 void ReportingTestBase::CreateContext(const ReportingPolicy& policy,
                                       base::Time now,
                                       base::TimeTicks now_ticks) {
-  context_ = std::make_unique<TestReportingContext>(policy);
+  context_ =
+      std::make_unique<TestReportingContext>(&clock_, &tick_clock_, policy);
   clock()->SetNow(now);
   tick_clock()->SetNowTicks(now_ticks);
 }
diff --git a/net/reporting/reporting_test_util.h b/net/reporting/reporting_test_util.h
index 1e98ab4..f7b83113 100644
--- a/net/reporting/reporting_test_util.h
+++ b/net/reporting/reporting_test_util.h
@@ -10,6 +10,8 @@
 #include <vector>
 
 #include "base/macros.h"
+#include "base/test/simple_test_clock.h"
+#include "base/test/simple_test_tick_clock.h"
 #include "net/reporting/reporting_context.h"
 #include "net/reporting/reporting_delegate.h"
 #include "net/reporting/reporting_uploader.h"
@@ -102,15 +104,11 @@
 // Clock, TickClock, Timer, and ReportingUploader.
 class TestReportingContext : public ReportingContext {
  public:
-  TestReportingContext(const ReportingPolicy& policy);
+  TestReportingContext(base::Clock* clock,
+                       base::TickClock* tick_clock,
+                       const ReportingPolicy& policy);
   ~TestReportingContext();
 
-  base::SimpleTestClock* test_clock() {
-    return reinterpret_cast<base::SimpleTestClock*>(clock());
-  }
-  base::SimpleTestTickClock* test_tick_clock() {
-    return reinterpret_cast<base::SimpleTestTickClock*>(tick_clock());
-  }
   base::MockTimer* test_delivery_timer() { return delivery_timer_; }
   base::MockTimer* test_garbage_collection_timer() {
     return garbage_collection_timer_;
@@ -151,10 +149,8 @@
 
   const ReportingPolicy& policy() { return context_->policy(); }
 
-  base::SimpleTestClock* clock() { return context_->test_clock(); }
-  base::SimpleTestTickClock* tick_clock() {
-    return context_->test_tick_clock();
-  }
+  base::SimpleTestClock* clock() { return &clock_; }
+  base::SimpleTestTickClock* tick_clock() { return &tick_clock_; }
   base::MockTimer* delivery_timer() { return context_->test_delivery_timer(); }
   base::MockTimer* garbage_collection_timer() {
     return context_->test_garbage_collection_timer();
@@ -186,6 +182,8 @@
                      base::Time now,
                      base::TimeTicks now_ticks);
 
+  base::SimpleTestClock clock_;
+  base::SimpleTestTickClock tick_clock_;
   std::unique_ptr<TestReportingContext> context_;
 
   DISALLOW_COPY_AND_ASSIGN(ReportingTestBase);
diff --git a/net/socket/ssl_client_socket_impl.cc b/net/socket/ssl_client_socket_impl.cc
index c13ccac..8d28daa 100644
--- a/net/socket/ssl_client_socket_impl.cc
+++ b/net/socket/ssl_client_socket_impl.cc
@@ -1621,7 +1621,7 @@
         NetLogEventType::SSL_CLIENT_CERT_PROVIDED,
         NetLog::IntCallback(
             "cert_count",
-            1 + ssl_config_.client_cert->GetIntermediateCertificates().size()));
+            1 + ssl_config_.client_cert->intermediate_buffers().size()));
     return 1;
   }
 #endif  // defined(OS_IOS)
diff --git a/net/socket/ssl_client_socket_unittest.cc b/net/socket/ssl_client_socket_unittest.cc
index 466bc71..9add1a6 100644
--- a/net/socket/ssl_client_socket_unittest.cc
+++ b/net/socket/ssl_client_socket_unittest.cc
@@ -37,6 +37,7 @@
 #include "net/cert/mock_cert_verifier.h"
 #include "net/cert/signed_certificate_timestamp_and_status.h"
 #include "net/cert/test_root_certs.h"
+#include "net/cert/x509_util.h"
 #include "net/der/input.h"
 #include "net/der/parser.h"
 #include "net/der/tag.h"
@@ -2339,24 +2340,23 @@
   scoped_refptr<X509Certificate> server_certificate = ssl_info.unverified_cert;
 
   // Get the intermediates as received  client side.
-  const X509Certificate::OSCertHandles& server_intermediates =
-      server_certificate->GetIntermediateCertificates();
+  const auto& server_intermediates = server_certificate->intermediate_buffers();
 
   // Check that the unverified server certificate chain is properly retrieved
   // from the underlying ssl stack.
   ASSERT_EQ(4U, server_certs.size());
 
-  EXPECT_TRUE(X509Certificate::IsSameOSCert(
-      server_certificate->os_cert_handle(), server_certs[0]->os_cert_handle()));
+  EXPECT_TRUE(x509_util::CryptoBufferEqual(server_certificate->cert_buffer(),
+                                           server_certs[0]->cert_buffer()));
 
   ASSERT_EQ(3U, server_intermediates.size());
 
-  EXPECT_TRUE(X509Certificate::IsSameOSCert(server_intermediates[0],
-                                            server_certs[1]->os_cert_handle()));
-  EXPECT_TRUE(X509Certificate::IsSameOSCert(server_intermediates[1],
-                                            server_certs[2]->os_cert_handle()));
-  EXPECT_TRUE(X509Certificate::IsSameOSCert(server_intermediates[2],
-                                            server_certs[3]->os_cert_handle()));
+  EXPECT_TRUE(x509_util::CryptoBufferEqual(server_intermediates[0].get(),
+                                           server_certs[1]->cert_buffer()));
+  EXPECT_TRUE(x509_util::CryptoBufferEqual(server_intermediates[1].get(),
+                                           server_certs[2]->cert_buffer()));
+  EXPECT_TRUE(x509_util::CryptoBufferEqual(server_intermediates[2].get(),
+                                           server_certs[3]->cert_buffer()));
 
   sock_->Disconnect();
   EXPECT_FALSE(sock_->IsConnected());
@@ -2393,13 +2393,16 @@
 
   ASSERT_TRUE(certs[0]->Equals(unverified_certs[0].get()));
 
-  X509Certificate::OSCertHandles temp_intermediates;
-  temp_intermediates.push_back(certs[1]->os_cert_handle());
-  temp_intermediates.push_back(certs[2]->os_cert_handle());
+  std::vector<bssl::UniquePtr<CRYPTO_BUFFER>> temp_intermediates;
+  temp_intermediates.push_back(
+      x509_util::DupCryptoBuffer(certs[1]->cert_buffer()));
+  temp_intermediates.push_back(
+      x509_util::DupCryptoBuffer(certs[2]->cert_buffer()));
 
   CertVerifyResult verify_result;
-  verify_result.verified_cert = X509Certificate::CreateFromHandle(
-      certs[0]->os_cert_handle(), temp_intermediates);
+  verify_result.verified_cert = X509Certificate::CreateFromBuffer(
+      x509_util::DupCryptoBuffer(certs[0]->cert_buffer()),
+      std::move(temp_intermediates));
   ASSERT_TRUE(verify_result.verified_cert);
 
   // Add a rule that maps the server cert (A) to the chain of A->B->C2
@@ -2432,29 +2435,28 @@
   // Verify that SSLInfo contains the corrected re-constructed chain A -> B
   // -> C2.
   ASSERT_TRUE(ssl_info.cert);
-  const X509Certificate::OSCertHandles& intermediates =
-      ssl_info.cert->GetIntermediateCertificates();
+  const auto& intermediates = ssl_info.cert->intermediate_buffers();
   ASSERT_EQ(2U, intermediates.size());
-  EXPECT_TRUE(X509Certificate::IsSameOSCert(ssl_info.cert->os_cert_handle(),
-                                            certs[0]->os_cert_handle()));
-  EXPECT_TRUE(X509Certificate::IsSameOSCert(intermediates[0],
-                                            certs[1]->os_cert_handle()));
-  EXPECT_TRUE(X509Certificate::IsSameOSCert(intermediates[1],
-                                            certs[2]->os_cert_handle()));
+  EXPECT_TRUE(x509_util::CryptoBufferEqual(ssl_info.cert->cert_buffer(),
+                                           certs[0]->cert_buffer()));
+  EXPECT_TRUE(x509_util::CryptoBufferEqual(intermediates[0].get(),
+                                           certs[1]->cert_buffer()));
+  EXPECT_TRUE(x509_util::CryptoBufferEqual(intermediates[1].get(),
+                                           certs[2]->cert_buffer()));
 
   // Verify that SSLInfo also contains the chain as received from the server.
   ASSERT_TRUE(ssl_info.unverified_cert);
-  const X509Certificate::OSCertHandles& served_intermediates =
-      ssl_info.unverified_cert->GetIntermediateCertificates();
+  const auto& served_intermediates =
+      ssl_info.unverified_cert->intermediate_buffers();
   ASSERT_EQ(3U, served_intermediates.size());
-  EXPECT_TRUE(X509Certificate::IsSameOSCert(
-      ssl_info.cert->os_cert_handle(), unverified_certs[0]->os_cert_handle()));
-  EXPECT_TRUE(X509Certificate::IsSameOSCert(
-      served_intermediates[0], unverified_certs[1]->os_cert_handle()));
-  EXPECT_TRUE(X509Certificate::IsSameOSCert(
-      served_intermediates[1], unverified_certs[2]->os_cert_handle()));
-  EXPECT_TRUE(X509Certificate::IsSameOSCert(
-      served_intermediates[2], unverified_certs[3]->os_cert_handle()));
+  EXPECT_TRUE(x509_util::CryptoBufferEqual(ssl_info.cert->cert_buffer(),
+                                           unverified_certs[0]->cert_buffer()));
+  EXPECT_TRUE(x509_util::CryptoBufferEqual(served_intermediates[0].get(),
+                                           unverified_certs[1]->cert_buffer()));
+  EXPECT_TRUE(x509_util::CryptoBufferEqual(served_intermediates[1].get(),
+                                           unverified_certs[2]->cert_buffer()));
+  EXPECT_TRUE(x509_util::CryptoBufferEqual(served_intermediates[2].get(),
+                                           unverified_certs[3]->cert_buffer()));
 
   sock_->Disconnect();
   EXPECT_FALSE(sock_->IsConnected());
diff --git a/net/socket/ssl_server_socket_impl.cc b/net/socket/ssl_server_socket_impl.cc
index 00a8816f..a541820 100644
--- a/net/socket/ssl_server_socket_impl.cc
+++ b/net/socket/ssl_server_socket_impl.cc
@@ -542,7 +542,7 @@
     return ERR_UNEXPECTED;
 
   // Set certificate and private key.
-  DCHECK(context_->cert_->os_cert_handle());
+  DCHECK(context_->cert_->cert_buffer());
   DCHECK(context_->key_->key());
   if (!SetSSLChainAndKey(ssl_.get(), context_->cert_.get(),
                          context_->key_->key(), nullptr)) {
diff --git a/net/spdy/chromium/http2_push_promise_index.cc b/net/spdy/chromium/http2_push_promise_index.cc
index 3dfce23f..7eb3378 100644
--- a/net/spdy/chromium/http2_push_promise_index.cc
+++ b/net/spdy/chromium/http2_push_promise_index.cc
@@ -14,47 +14,57 @@
   DCHECK(unclaimed_pushed_streams_.empty());
 }
 
-base::WeakPtr<SpdySession> Http2PushPromiseIndex::FindSession(
-    const SpdySessionKey& key,
-    const GURL& url) const {
+void Http2PushPromiseIndex::FindSession(const SpdySessionKey& key,
+                                        const GURL& url,
+                                        base::WeakPtr<SpdySession>* session,
+                                        SpdyStreamId* stream_id) const {
   DCHECK(!url.is_empty());
 
-  UnclaimedPushedStreamMap::const_iterator it =
-      unclaimed_pushed_streams_.lower_bound(std::make_pair(url, nullptr));
+  *session = nullptr;
+  *stream_id = kNoPushedStreamFound;
 
-  if (it == unclaimed_pushed_streams_.end() || it->first != url) {
-    return base::WeakPtr<SpdySession>();
-  }
+  auto it = unclaimed_pushed_streams_.lower_bound(
+      UnclaimedPushedStream{url, kNoPushedStreamFound, nullptr});
+
+  if (it == unclaimed_pushed_streams_.end() || it->url != url)
+    return;
 
   DCHECK(url.SchemeIsCryptographic());
-  while (it != unclaimed_pushed_streams_.end() && it->first == url) {
-    if (it->second->ValidatePushedStream(key)) {
-      it->second->OnPushedStreamClaimed(url);
-      return it->second->GetWeakPtrToSession();
+  while (it != unclaimed_pushed_streams_.end() && it->url == url) {
+    if (it->delegate->ValidatePushedStream(key)) {
+      *session = it->delegate->GetWeakPtrToSession();
+      *stream_id = it->stream_id;
+      it->delegate->OnPushedStreamClaimed(it->url, it->stream_id);
+      return;
     }
     ++it;
   }
-
-  return base::WeakPtr<SpdySession>();
 }
 
-void Http2PushPromiseIndex::RegisterUnclaimedPushedStream(const GURL& url,
-                                                          Delegate* delegate) {
+void Http2PushPromiseIndex::RegisterUnclaimedPushedStream(
+    const GURL& url,
+    SpdyStreamId stream_id,
+    Delegate* delegate) {
   DCHECK(!url.is_empty());
   DCHECK(url.SchemeIsCryptographic());
+  DCHECK(delegate);
 
-  unclaimed_pushed_streams_.insert(std::make_pair(url, delegate));
+  unclaimed_pushed_streams_.insert(
+      UnclaimedPushedStream{url, stream_id, delegate});
 }
 
 void Http2PushPromiseIndex::UnregisterUnclaimedPushedStream(
     const GURL& url,
+    SpdyStreamId stream_id,
     Delegate* delegate) {
   DCHECK(!url.is_empty());
   DCHECK(url.SchemeIsCryptographic());
+  DCHECK(delegate);
 
-  size_t result =
-      unclaimed_pushed_streams_.erase(std::make_pair(url, delegate));
-  DCHECK_EQ(1u, result);
+  size_t result = unclaimed_pushed_streams_.erase(
+      UnclaimedPushedStream{url, stream_id, delegate});
+  LOG_IF(DFATAL, result != 1)
+      << "Only a previously registered entry can be unregistered.";
 }
 
 }  // namespace net
diff --git a/net/spdy/chromium/http2_push_promise_index.h b/net/spdy/chromium/http2_push_promise_index.h
index 9e4b8cb..b7e85ec 100644
--- a/net/spdy/chromium/http2_push_promise_index.h
+++ b/net/spdy/chromium/http2_push_promise_index.h
@@ -11,12 +11,25 @@
 #include "base/memory/weak_ptr.h"
 #include "net/base/net_export.h"
 #include "net/spdy/chromium/spdy_session_key.h"
+#include "net/spdy/core/spdy_protocol.h"
 #include "url/gurl.h"
 
 namespace net {
 
 class SpdySession;
 
+namespace test {
+
+class Http2PushPromiseIndexPeer;
+
+}  // namespace test
+
+// This value is returned by Http2PushPromiseIndex::FindSession() and
+// UnclaimedPushedStreamContainer::FindStream() if no stream is found.
+// TODO(bnc): Move UnclaimedPushedStreamContainer::FindStream() to this class.
+// https://crbug.com/791054
+const SpdyStreamId kNoPushedStreamFound = 0;
+
 // This class manages cross-origin unclaimed pushed streams (push promises) from
 // the receipt of PUSH_PROMISE frame until they are matched to a request.  Each
 // SpdySessionPool owns one instance of this class, which then allows requests
@@ -42,7 +55,8 @@
     virtual bool ValidatePushedStream(const SpdySessionKey& key) const = 0;
 
     // Called when a pushed stream is claimed.
-    virtual void OnPushedStreamClaimed(const GURL& url) = 0;
+    virtual void OnPushedStreamClaimed(const GURL& url,
+                                       SpdyStreamId stream_id) = 0;
 
     // Generate weak pointer.
     virtual base::WeakPtr<SpdySession> GetWeakPtrToSession() = 0;
@@ -54,25 +68,72 @@
   Http2PushPromiseIndex();
   ~Http2PushPromiseIndex();
 
-  // Returns a session with |key| that has an unclaimed push stream for |url| if
-  // such exists.  Makes no guarantee on which one it returns if there are
-  // multiple.  Returns nullptr if no such session exists.
-  base::WeakPtr<SpdySession> FindSession(const SpdySessionKey& key,
-                                         const GURL& url) const;
+  // If there exists a session compatible with |key| that has an unclaimed push
+  // stream for |url|, then sets |*session| and |*stream| to one such session
+  // and stream.  Makes no guarantee on which (session, stream_id) pair it
+  // returns if there are multiple matches.  Sets |*session| to nullptr and
+  // |*stream| to kNoPushedStreamFound if no such session exists.
+  void FindSession(const SpdySessionKey& key,
+                   const GURL& url,
+                   base::WeakPtr<SpdySession>* session,
+                   SpdyStreamId* stream_id) const;
 
   // (Un)registers a Delegate with an unclaimed pushed stream for |url|.
   // Caller must make sure |delegate| stays valid by unregistering the exact
   // same entry before |delegate| is destroyed.
-  void RegisterUnclaimedPushedStream(const GURL& url, Delegate* delegate);
-  void UnregisterUnclaimedPushedStream(const GURL& url, Delegate* delegate);
+  void RegisterUnclaimedPushedStream(const GURL& url,
+                                     SpdyStreamId stream_id,
+                                     Delegate* delegate);
+  void UnregisterUnclaimedPushedStream(const GURL& url,
+                                       SpdyStreamId stream_id,
+                                       Delegate* delegate);
 
  private:
-  using UnclaimedPushedStreamMap = std::set<std::pair<GURL, Delegate*>>;
+  friend test::Http2PushPromiseIndexPeer;
+
+  // An unclaimed pushed stream entry.
+  struct UnclaimedPushedStream {
+    GURL url;
+    SpdyStreamId stream_id;
+    Delegate* delegate;
+  };
+
+  // Function object satisfying the requirements of "Compare", see
+  // http://en.cppreference.com/w/cpp/concept/Compare.
+  // Used for sorting entries by URL.  Among entries with identical URL, put the
+  // one with |stream_id == kNoPushedStreamFound| first, so that it can be used
+  // with lower_bound() to search for the first entry with given URL.  For
+  // entries with identical URL and stream ID, sort by |delegate| memory
+  // address.
+  struct CompareByUrl {
+    bool operator()(const UnclaimedPushedStream& a,
+                    const UnclaimedPushedStream& b) const {
+      if (a.url < b.url)
+        return true;
+      if (a.url > b.url)
+        return false;
+      // Identical URL.
+      if (a.stream_id == kNoPushedStreamFound &&
+          b.stream_id != kNoPushedStreamFound) {
+        return true;
+      }
+      if (a.stream_id != kNoPushedStreamFound &&
+          b.stream_id == kNoPushedStreamFound) {
+        return false;
+      }
+      if (a.stream_id < b.stream_id)
+        return true;
+      if (a.stream_id > b.stream_id)
+        return false;
+      // Identical URL and stream ID.
+      return a.delegate < b.delegate;
+    }
+  };
 
   // A collection of all unclaimed pushed streams.  Delegate must unregister its
   // streams before destruction, so that all pointers remain valid.  It is
   // possible that multiple Delegates have pushed streams for the same GURL.
-  UnclaimedPushedStreamMap unclaimed_pushed_streams_;
+  std::set<UnclaimedPushedStream, CompareByUrl> unclaimed_pushed_streams_;
 
   DISALLOW_COPY_AND_ASSIGN(Http2PushPromiseIndex);
 };
diff --git a/net/spdy/chromium/http2_push_promise_index_test.cc b/net/spdy/chromium/http2_push_promise_index_test.cc
index 5ae837c..78675d45 100644
--- a/net/spdy/chromium/http2_push_promise_index_test.cc
+++ b/net/spdy/chromium/http2_push_promise_index_test.cc
@@ -4,178 +4,387 @@
 
 #include "net/spdy/chromium/http2_push_promise_index.h"
 
-#include "base/run_loop.h"
 #include "net/base/host_port_pair.h"
 #include "net/base/privacy_mode.h"
-#include "net/log/test_net_log.h"
-#include "net/socket/socket_test_util.h"
-#include "net/spdy/chromium/spdy_session.h"
-#include "net/spdy/chromium/spdy_test_util_common.h"
-#include "net/test/cert_test_util.h"
-#include "net/test/test_data_directory.h"
+#include "net/test/gtest_util.h"
+#include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "url/gurl.h"
 
+// For simplicity, these tests do not create SpdySession instances
+// (necessary for a non-null WeakPtr<SpdySession>), instead they use nullptr.
+// Streams are identified by SpdyStreamId only.
+
+using ::testing::Return;
+using ::testing::_;
+
 namespace net {
 namespace test {
+namespace {
+
+// Delegate implementation for tests that requires exact match of SpdySessionKey
+// in ValidatePushedStream().  Note that SpdySession, unlike TestDelegate,
+// allows cross-origin pooling.
+class TestDelegate : public Http2PushPromiseIndex::Delegate {
+ public:
+  TestDelegate() = delete;
+  TestDelegate(const SpdySessionKey& key) : key_(key) {}
+  ~TestDelegate() override {}
+
+  bool ValidatePushedStream(const SpdySessionKey& key) const override {
+    return key == key_;
+  }
+
+  void OnPushedStreamClaimed(const GURL& url, SpdyStreamId stream_id) override {
+  }
+
+  base::WeakPtr<SpdySession> GetWeakPtrToSession() override { return nullptr; }
+
+ private:
+  SpdySessionKey key_;
+};
+
+// Mock implementation.
+class MockDelegate : public Http2PushPromiseIndex::Delegate {
+ public:
+  MockDelegate() = default;
+  ~MockDelegate() override {}
+
+  MOCK_CONST_METHOD1(ValidatePushedStream, bool(const SpdySessionKey& key));
+  MOCK_METHOD2(OnPushedStreamClaimed,
+               void(const GURL& url, SpdyStreamId stream_id));
+
+  base::WeakPtr<SpdySession> GetWeakPtrToSession() override { return nullptr; }
+};
+
+}  // namespace
+
+class Http2PushPromiseIndexPeer {
+ public:
+  using UnclaimedPushedStream = Http2PushPromiseIndex::UnclaimedPushedStream;
+  using CompareByUrl = Http2PushPromiseIndex::CompareByUrl;
+};
 
 class Http2PushPromiseIndexTest : public testing::Test {
  protected:
   Http2PushPromiseIndexTest()
       : url1_("https://www.example.org"),
         url2_("https://mail.example.com"),
-        host_port_pair1_(HostPortPair::FromURL(url1_)),
-        host_port_pair2_(HostPortPair::FromURL(url2_)),
-        key1_(host_port_pair1_, ProxyServer::Direct(), PRIVACY_MODE_ENABLED),
-        key2_(host_port_pair2_, ProxyServer::Direct(), PRIVACY_MODE_ENABLED),
-        http_network_session_(
-            SpdySessionDependencies::SpdyCreateSession(&session_deps_)) {}
+        key1_(HostPortPair::FromURL(url1_),
+              ProxyServer::Direct(),
+              PRIVACY_MODE_ENABLED),
+        key2_(HostPortPair::FromURL(url2_),
+              ProxyServer::Direct(),
+              PRIVACY_MODE_ENABLED) {}
 
-  NetLogWithSource log_;
   const GURL url1_;
   const GURL url2_;
-  const HostPortPair host_port_pair1_;
-  const HostPortPair host_port_pair2_;
   const SpdySessionKey key1_;
   const SpdySessionKey key2_;
-  SpdySessionDependencies session_deps_;
-  std::unique_ptr<HttpNetworkSession> http_network_session_;
   Http2PushPromiseIndex index_;
 };
 
+// If |index_| is empty, then FindSession() should set its |stream_id| outparam
+// to kNoPushedStreamFound for any values of inparams.
 TEST_F(Http2PushPromiseIndexTest, Empty) {
-  EXPECT_FALSE(index_.FindSession(key1_, url1_));
-  EXPECT_FALSE(index_.FindSession(key2_, url2_));
+  base::WeakPtr<SpdySession> session;
+  SpdyStreamId stream_id = 2;
+  index_.FindSession(key1_, url1_, &session, &stream_id);
+  EXPECT_EQ(kNoPushedStreamFound, stream_id);
+
+  stream_id = 2;
+  index_.FindSession(key1_, url2_, &session, &stream_id);
+  EXPECT_EQ(kNoPushedStreamFound, stream_id);
+
+  stream_id = 2;
+  index_.FindSession(key1_, url2_, &session, &stream_id);
+  EXPECT_EQ(kNoPushedStreamFound, stream_id);
+
+  stream_id = 2;
+  index_.FindSession(key2_, url2_, &session, &stream_id);
+  EXPECT_EQ(kNoPushedStreamFound, stream_id);
 }
 
-TEST_F(Http2PushPromiseIndexTest, FindMultipleSessionsWithDifferentUrl) {
-  MockRead reads[] = {MockRead(SYNCHRONOUS, ERR_IO_PENDING, 0)};
-  SSLSocketDataProvider ssl(SYNCHRONOUS, OK);
-  ssl.ssl_info.cert =
-      ImportCertFromFile(GetTestCertsDirectory(), "spdy_pooling.pem");
-  ASSERT_TRUE(ssl.ssl_info.cert);
-  // For first session.
-  SequencedSocketData data1(reads, arraysize(reads), nullptr, 0);
-  session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl);
-  session_deps_.socket_factory->AddSocketDataProvider(&data1);
-  // For second session.
-  SequencedSocketData data2(reads, arraysize(reads), nullptr, 0);
-  session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl);
-  session_deps_.socket_factory->AddSocketDataProvider(&data2);
-
-  base::WeakPtr<SpdySession> spdy_session1 =
-      CreateSpdySession(http_network_session_.get(), key1_, log_);
-  base::WeakPtr<SpdySession> spdy_session2 =
-      CreateSpdySession(http_network_session_.get(), key2_, log_);
-  // Read hanging socket data.
-  base::RunLoop().RunUntilIdle();
-
-  EXPECT_FALSE(index_.FindSession(key1_, url1_));
-  EXPECT_FALSE(index_.FindSession(key2_, url2_));
-
-  index_.RegisterUnclaimedPushedStream(url1_, spdy_session1.get());
-
-  EXPECT_EQ(spdy_session1.get(), index_.FindSession(key1_, url1_).get());
-  EXPECT_FALSE(index_.FindSession(key2_, url2_));
-
-  index_.RegisterUnclaimedPushedStream(url2_, spdy_session2.get());
-
-  EXPECT_EQ(spdy_session1.get(), index_.FindSession(key1_, url1_).get());
-  EXPECT_EQ(spdy_session2.get(), index_.FindSession(key2_, url2_).get());
-
-  index_.UnregisterUnclaimedPushedStream(url1_, spdy_session1.get());
-
-  EXPECT_FALSE(index_.FindSession(key1_, url1_));
-  EXPECT_EQ(spdy_session2.get(), index_.FindSession(key2_, url2_).get());
-
-  index_.UnregisterUnclaimedPushedStream(url2_, spdy_session2.get());
-
-  EXPECT_FALSE(index_.FindSession(key1_, url1_));
-  EXPECT_FALSE(index_.FindSession(key2_, url2_));
-
-  // SpdySession weak pointers must still be valid,
-  // otherwise comparisons above are not meaningful.
-  EXPECT_TRUE(spdy_session1);
-  EXPECT_TRUE(spdy_session2);
-
-  EXPECT_TRUE(data1.AllReadDataConsumed());
-  EXPECT_TRUE(data1.AllWriteDataConsumed());
-  EXPECT_TRUE(data2.AllReadDataConsumed());
-  EXPECT_TRUE(data2.AllWriteDataConsumed());
+// Trying to unregister a stream not in the index should log to DFATAL.
+// Case 1: no streams for the given URL.
+TEST_F(Http2PushPromiseIndexTest, UnregisterNonexistingEntryCrashes1) {
+  TestDelegate delegate(key1_);
+  EXPECT_DFATAL(index_.UnregisterUnclaimedPushedStream(url1_, 2, &delegate),
+                "Only a previously registered entry can be unregistered.");
 }
 
-TEST_F(Http2PushPromiseIndexTest, MultipleSessionsForSingleUrl) {
-  MockRead reads[] = {MockRead(SYNCHRONOUS, ERR_IO_PENDING, 0)};
-  SSLSocketDataProvider ssl(SYNCHRONOUS, OK);
-  ssl.ssl_info.cert =
-      ImportCertFromFile(GetTestCertsDirectory(), "spdy_pooling.pem");
-  ASSERT_TRUE(ssl.ssl_info.cert);
-  // For first session.
-  SequencedSocketData data1(reads, arraysize(reads), nullptr, 0);
-  session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl);
-  session_deps_.socket_factory->AddSocketDataProvider(&data1);
-  // For second session.
-  SequencedSocketData data2(reads, arraysize(reads), nullptr, 0);
-  session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl);
-  session_deps_.socket_factory->AddSocketDataProvider(&data2);
-
-  base::WeakPtr<SpdySession> spdy_session1 =
-      CreateSpdySession(http_network_session_.get(), key1_, log_);
-  base::WeakPtr<SpdySession> spdy_session2 =
-      CreateSpdySession(http_network_session_.get(), key2_, log_);
-  // Read hanging socket data.
-  base::RunLoop().RunUntilIdle();
-
-  EXPECT_FALSE(index_.FindSession(key1_, url1_));
-  EXPECT_FALSE(index_.FindSession(key2_, url1_));
-  EXPECT_FALSE(index_.FindSession(key1_, url2_));
-  EXPECT_FALSE(index_.FindSession(key2_, url2_));
-
-  index_.RegisterUnclaimedPushedStream(url1_, spdy_session1.get());
-
-  // Note that FindSession() only uses its SpdySessionKey argument to verify
-  // proxy and privacy mode.  Cross-origin pooling is supported, therefore
-  // HostPortPair of SpdySessionKey does not matter.
-  EXPECT_EQ(spdy_session1.get(), index_.FindSession(key1_, url1_).get());
-  EXPECT_EQ(spdy_session1.get(), index_.FindSession(key2_, url1_).get());
-  EXPECT_FALSE(index_.FindSession(key1_, url2_));
-  EXPECT_FALSE(index_.FindSession(key2_, url2_));
-
-  index_.RegisterUnclaimedPushedStream(url1_, spdy_session2.get());
-
-  // FindSession() makes no guarantee about which SpdySession it returns if
-  // there are multiple for the same URL.
-  SpdySession* result = index_.FindSession(key1_, url1_).get();
-  EXPECT_TRUE(result == spdy_session1.get() || result == spdy_session2.get());
-  result = index_.FindSession(key2_, url1_).get();
-  EXPECT_TRUE(result == spdy_session1.get() || result == spdy_session2.get());
-  EXPECT_FALSE(index_.FindSession(key1_, url2_));
-  EXPECT_FALSE(index_.FindSession(key2_, url2_));
-
-  index_.UnregisterUnclaimedPushedStream(url1_, spdy_session1.get());
-
-  EXPECT_EQ(spdy_session2.get(), index_.FindSession(key1_, url1_).get());
-  EXPECT_EQ(spdy_session2.get(), index_.FindSession(key2_, url1_).get());
-  EXPECT_FALSE(index_.FindSession(key1_, url2_));
-  EXPECT_FALSE(index_.FindSession(key2_, url2_));
-
-  index_.UnregisterUnclaimedPushedStream(url1_, spdy_session2.get());
-
-  EXPECT_FALSE(index_.FindSession(key1_, url1_));
-  EXPECT_FALSE(index_.FindSession(key2_, url1_));
-  EXPECT_FALSE(index_.FindSession(key1_, url2_));
-  EXPECT_FALSE(index_.FindSession(key2_, url2_));
-
-  // SpdySession weak pointers must still be valid,
-  // otherwise comparisons above are not meaningful.
-  EXPECT_TRUE(spdy_session1);
-  EXPECT_TRUE(spdy_session2);
-
-  EXPECT_TRUE(data1.AllReadDataConsumed());
-  EXPECT_TRUE(data1.AllWriteDataConsumed());
-  EXPECT_TRUE(data2.AllReadDataConsumed());
-  EXPECT_TRUE(data2.AllWriteDataConsumed());
+// Trying to unregister a stream not in the index should log to DFATAL.
+// Case 2: there is a stream for the given URL, but not with the same stream ID.
+TEST_F(Http2PushPromiseIndexTest, UnregisterNonexistingEntryCrashes2) {
+  TestDelegate delegate(key1_);
+  index_.RegisterUnclaimedPushedStream(url1_, 2, &delegate);
+  EXPECT_DFATAL(index_.UnregisterUnclaimedPushedStream(url1_, 4, &delegate),
+                "Only a previously registered entry can be unregistered.");
+  // Stream must be unregistered so that Http2PushPromiseIndex destructor
+  // does not crash.
+  index_.UnregisterUnclaimedPushedStream(url1_, 2, &delegate);
 }
 
+// Create two entries, both with a delegate that requires |key| to be equal to
+// |key1_|.  Register the two entries with different URLs.  Check that they can
+// be found by their respective URLs.
+TEST_F(Http2PushPromiseIndexTest, FindMultipleStreamsWithDifferentUrl) {
+  // Register first entry.
+  TestDelegate delegate1(key1_);
+  index_.RegisterUnclaimedPushedStream(url1_, 2, &delegate1);
+
+  // Retrieve first entry by its URL, no entry found for |url2_|.
+  base::WeakPtr<SpdySession> session;
+  SpdyStreamId stream_id = kNoPushedStreamFound;
+  index_.FindSession(key1_, url1_, &session, &stream_id);
+  EXPECT_EQ(2u, stream_id);
+
+  stream_id = 2;
+  index_.FindSession(key1_, url2_, &session, &stream_id);
+  EXPECT_EQ(kNoPushedStreamFound, stream_id);
+
+  // Register second entry.
+  TestDelegate delegate2(key1_);
+  index_.RegisterUnclaimedPushedStream(url2_, 4, &delegate2);
+
+  // Retrieve each entry by their respective URLs.
+  stream_id = kNoPushedStreamFound;
+  index_.FindSession(key1_, url1_, &session, &stream_id);
+  EXPECT_EQ(2u, stream_id);
+
+  stream_id = kNoPushedStreamFound;
+  index_.FindSession(key1_, url2_, &session, &stream_id);
+  EXPECT_EQ(4u, stream_id);
+
+  // Unregister first entry.
+  index_.UnregisterUnclaimedPushedStream(url1_, 2, &delegate1);
+
+  // No entry found for |url1_|, retrieve second entry by its URL.
+  stream_id = 2;
+  index_.FindSession(key1_, url1_, &session, &stream_id);
+  EXPECT_EQ(kNoPushedStreamFound, stream_id);
+
+  stream_id = kNoPushedStreamFound;
+  index_.FindSession(key1_, url2_, &session, &stream_id);
+  EXPECT_EQ(4u, stream_id);
+
+  // Unregister second entry.
+  index_.UnregisterUnclaimedPushedStream(url2_, 4, &delegate2);
+
+  // No entries found for either URL.
+  stream_id = 2;
+  index_.FindSession(key1_, url1_, &session, &stream_id);
+  EXPECT_EQ(kNoPushedStreamFound, stream_id);
+
+  stream_id = 2;
+  index_.FindSession(key1_, url2_, &session, &stream_id);
+  EXPECT_EQ(kNoPushedStreamFound, stream_id);
+}
+
+// Create two entries with delegates that validate different SpdySessionKeys.
+// Register the two entries with the same URL.  Check that they can be found by
+// their respective SpdySessionKeys.
+TEST_F(Http2PushPromiseIndexTest, MultipleStreamsWithDifferentKeys) {
+  // Register first entry.
+  TestDelegate delegate1(key1_);
+  index_.RegisterUnclaimedPushedStream(url1_, 2, &delegate1);
+
+  // Retrieve first entry by its SpdySessionKey, no entry found for |key2_|.
+  base::WeakPtr<SpdySession> session;
+  SpdyStreamId stream_id = kNoPushedStreamFound;
+  index_.FindSession(key1_, url1_, &session, &stream_id);
+  EXPECT_EQ(2u, stream_id);
+
+  stream_id = 2;
+  index_.FindSession(key2_, url1_, &session, &stream_id);
+  EXPECT_EQ(kNoPushedStreamFound, stream_id);
+
+  // Register second entry.
+  TestDelegate delegate2(key2_);
+  index_.RegisterUnclaimedPushedStream(url1_, 4, &delegate2);
+
+  // Retrieve each entry by their respective SpdySessionKeys.
+  stream_id = kNoPushedStreamFound;
+  index_.FindSession(key1_, url1_, &session, &stream_id);
+  EXPECT_EQ(2u, stream_id);
+
+  stream_id = kNoPushedStreamFound;
+  index_.FindSession(key2_, url1_, &session, &stream_id);
+  EXPECT_EQ(4u, stream_id);
+
+  // Unregister first entry.
+  index_.UnregisterUnclaimedPushedStream(url1_, 2, &delegate1);
+
+  // No entry found for |key1_|, retrieve second entry by its SpdySessionKey.
+  stream_id = 2;
+  index_.FindSession(key1_, url1_, &session, &stream_id);
+  EXPECT_EQ(kNoPushedStreamFound, stream_id);
+
+  stream_id = kNoPushedStreamFound;
+  index_.FindSession(key2_, url1_, &session, &stream_id);
+  EXPECT_EQ(4u, stream_id);
+
+  // Unregister second entry.
+  index_.UnregisterUnclaimedPushedStream(url1_, 4, &delegate2);
+
+  // No entries found for either SpdySessionKeys.
+  stream_id = 2;
+  index_.FindSession(key1_, url1_, &session, &stream_id);
+  EXPECT_EQ(kNoPushedStreamFound, stream_id);
+
+  stream_id = 2;
+  index_.FindSession(key2_, url1_, &session, &stream_id);
+  EXPECT_EQ(kNoPushedStreamFound, stream_id);
+}
+
+TEST_F(Http2PushPromiseIndexTest, MultipleMatchingStreams) {
+  // Register two entries with identical URLs that have delegates that accept
+  // the same SpdySessionKey.
+  TestDelegate delegate1(key1_);
+  TestDelegate delegate2(key1_);
+  index_.RegisterUnclaimedPushedStream(url1_, 2, &delegate1);
+  index_.RegisterUnclaimedPushedStream(url1_, 4, &delegate2);
+
+  // Test that FindSession() returns one of the two entries.  FindSession()
+  // makes no guarantee about which entry it returns if there are multiple
+  // matches.
+  base::WeakPtr<SpdySession> session;
+  SpdyStreamId stream_id = kNoPushedStreamFound;
+  index_.FindSession(key1_, url1_, &session, &stream_id);
+  EXPECT_NE(kNoPushedStreamFound, stream_id);
+
+  // Unregister the first entry.
+  index_.UnregisterUnclaimedPushedStream(url1_, 2, &delegate1);
+
+  // Test that the second entry can still be retrieved.
+  stream_id = kNoPushedStreamFound;
+  index_.FindSession(key1_, url1_, &session, &stream_id);
+  EXPECT_EQ(4u, stream_id);
+
+  // Unregister the second entry.
+  index_.UnregisterUnclaimedPushedStream(url1_, 4, &delegate2);
+
+  // Test that no entry is found.
+  stream_id = 2;
+  index_.FindSession(key1_, url1_, &session, &stream_id);
+  EXPECT_EQ(kNoPushedStreamFound, stream_id);
+}
+
+// Test that Delegate::ValidatePushedStream() is called by FindSession(), and if
+// it returns true, then Delegate::OnPushedStreamClaimed() is called with the
+// appropriate arguments.
+TEST_F(Http2PushPromiseIndexTest, MatchCallsOnPushedStreamClaimed) {
+  MockDelegate delegate;
+  EXPECT_CALL(delegate, ValidatePushedStream(key1_)).WillOnce(Return(true));
+  EXPECT_CALL(delegate, OnPushedStreamClaimed(url1_, 2)).Times(1);
+
+  index_.RegisterUnclaimedPushedStream(url1_, 2, &delegate);
+
+  base::WeakPtr<SpdySession> session;
+  SpdyStreamId stream_id = kNoPushedStreamFound;
+  index_.FindSession(key1_, url1_, &session, &stream_id);
+  EXPECT_EQ(2u, stream_id);
+
+  index_.UnregisterUnclaimedPushedStream(url1_, 2, &delegate);
+};
+
+// Test that Delegate::ValidatePushedStream() is called by FindSession(), and if
+// it returns false, then Delegate::OnPushedStreamClaimed() is not called.
+TEST_F(Http2PushPromiseIndexTest, MismatchDoesNotCallOnPushedStreamClaimed) {
+  MockDelegate delegate;
+  EXPECT_CALL(delegate, ValidatePushedStream(key1_)).WillOnce(Return(false));
+  EXPECT_CALL(delegate, OnPushedStreamClaimed(_, _)).Times(0);
+
+  index_.RegisterUnclaimedPushedStream(url1_, 2, &delegate);
+
+  base::WeakPtr<SpdySession> session;
+  SpdyStreamId stream_id = 2;
+  index_.FindSession(key1_, url1_, &session, &stream_id);
+  EXPECT_EQ(kNoPushedStreamFound, stream_id);
+
+  index_.UnregisterUnclaimedPushedStream(url1_, 2, &delegate);
+};
+
+// Test that an entry is equivalent to itself.
+TEST(Http2PushPromiseIndexCompareByUrlTest, Reflexivity) {
+  // Test with two entries: with and without a pushed stream.
+  Http2PushPromiseIndexPeer::UnclaimedPushedStream entry1{GURL(), 2, nullptr};
+  Http2PushPromiseIndexPeer::UnclaimedPushedStream entry2{
+      GURL(), kNoPushedStreamFound, nullptr};
+
+  // For "Compare", it is a requirement that comp(A, A) == false, see
+  // http://en.cppreference.com/w/cpp/concept/Compare.  This will in fact imply
+  // that equiv(A, A) == true.
+  EXPECT_FALSE(Http2PushPromiseIndexPeer::CompareByUrl()(entry1, entry1));
+  EXPECT_FALSE(Http2PushPromiseIndexPeer::CompareByUrl()(entry2, entry2));
+
+  std::set<Http2PushPromiseIndexPeer::UnclaimedPushedStream,
+           Http2PushPromiseIndexPeer::CompareByUrl>
+      entries;
+  bool success;
+  std::tie(std::ignore, success) = entries.insert(entry1);
+  EXPECT_TRUE(success);
+
+  // Test that |entry1| is considered equivalent to itself by ensuring that
+  // a second insertion fails.
+  std::tie(std::ignore, success) = entries.insert(entry1);
+  EXPECT_FALSE(success);
+
+  // Test that |entry1| and |entry2| are not equivalent.
+  std::tie(std::ignore, success) = entries.insert(entry2);
+  EXPECT_TRUE(success);
+
+  // Test that |entry2| is equivalent to an existing entry
+  // (which then must be |entry2|).
+  std::tie(std::ignore, success) = entries.insert(entry2);
+  EXPECT_FALSE(success);
+};
+
+TEST(Http2PushPromiseIndexCompareByUrlTest, LookupByURL) {
+  const GURL url1("https://example.com:1");
+  const GURL url2("https://example.com:2");
+  const GURL url3("https://example.com:3");
+  // This test relies on the order of these GURLs.
+  ASSERT_LT(url1, url2);
+  ASSERT_LT(url2, url3);
+
+  // Create four entries, two for the middle URL, with distinct stream IDs not
+  // in ascending order.
+  Http2PushPromiseIndexPeer::UnclaimedPushedStream entry1{url1, 8, nullptr};
+  Http2PushPromiseIndexPeer::UnclaimedPushedStream entry2{url2, 4, nullptr};
+  Http2PushPromiseIndexPeer::UnclaimedPushedStream entry3{url2, 6, nullptr};
+  Http2PushPromiseIndexPeer::UnclaimedPushedStream entry4{url3, 2, nullptr};
+
+  // Fill up a set.
+  std::set<Http2PushPromiseIndexPeer::UnclaimedPushedStream,
+           Http2PushPromiseIndexPeer::CompareByUrl>
+      entries;
+  entries.insert(entry1);
+  entries.insert(entry2);
+  entries.insert(entry3);
+  entries.insert(entry4);
+  ASSERT_EQ(4u, entries.size());
+
+  // Test that entries are ordered by URL first, not stream ID.
+  std::set<Http2PushPromiseIndexPeer::UnclaimedPushedStream,
+           Http2PushPromiseIndexPeer::CompareByUrl>::iterator it =
+      entries.begin();
+  EXPECT_EQ(8u, it->stream_id);
+  ++it;
+  EXPECT_EQ(4u, it->stream_id);
+  ++it;
+  EXPECT_EQ(6u, it->stream_id);
+  ++it;
+  EXPECT_EQ(2u, it->stream_id);
+  ++it;
+  EXPECT_TRUE(it == entries.end());
+
+  // Test that kNoPushedStreamFound can be used to look up the first entry for a
+  // given URL.  In particular, the first entry with |url2| is |entry2|.
+  EXPECT_TRUE(
+      entries.lower_bound(Http2PushPromiseIndexPeer::UnclaimedPushedStream{
+          url2, kNoPushedStreamFound, nullptr}) == entries.find(entry2));
+};
+
 }  // namespace test
 }  // namespace net
diff --git a/net/spdy/chromium/spdy_session.cc b/net/spdy/chromium/spdy_session.cc
index c541069..e9bb369 100644
--- a/net/spdy/chromium/spdy_session.cc
+++ b/net/spdy/chromium/spdy_session.cc
@@ -1347,14 +1347,9 @@
          VerifyDomainAuthentication(key.host_port_pair().host());
 }
 
-void SpdySession::OnPushedStreamClaimed(const GURL& url) {
-  SpdyStreamId stream_id = unclaimed_pushed_streams_.FindStream(url);
-  // This is only possible in tests.
-  // TODO(bnc): Change to DCHECK once Http2PushPromiseIndexTest stops using
-  // actual SpdySession instances.  https://crbug.com/791055.
-  if (stream_id == kNoPushedStreamFound)
-    return;
-
+void SpdySession::OnPushedStreamClaimed(const GURL& url,
+                                        SpdyStreamId stream_id) {
+  DCHECK_NE(kNoPushedStreamFound, stream_id);
   LogPushStreamClaimed(url, stream_id);
 }
 
@@ -1411,7 +1406,7 @@
   // Only allow cross-origin push for secure resources.
   if (it->first.SchemeIsCryptographic()) {
     spdy_session_->pool_->push_promise_index()->UnregisterUnclaimedPushedStream(
-        it->first, spdy_session_);
+        it->first, stream_id, spdy_session_);
   }
   streams_.erase(it);
   return true;
@@ -1429,7 +1424,7 @@
   // Only allow cross-origin push for https resources.
   if (url.SchemeIsCryptographic()) {
     spdy_session_->pool_->push_promise_index()->RegisterUnclaimedPushedStream(
-        url, spdy_session_);
+        url, stream_id, spdy_session_);
   }
   return true;
 }
diff --git a/net/spdy/chromium/spdy_session.h b/net/spdy/chromium/spdy_session.h
index 51c7236..61b4223 100644
--- a/net/spdy/chromium/spdy_session.h
+++ b/net/spdy/chromium/spdy_session.h
@@ -58,11 +58,6 @@
 class SpdyStreamTest;
 }
 
-// This value means that UnclaimedPushedStreamContainer::FindStream() has not
-// found any streams.
-// TODO(bnc): Move to Http2PushPromiseIndex.  https://crbug.com/791054
-const SpdyStreamId kNoPushedStreamFound = 0;
-
 // This is somewhat arbitrary and not really fixed, but it will always work
 // reasonably with ethernet. Chop the world into 2-packet chunks.  This is
 // somewhat arbitrary, but is reasonably small and ensures that we elicit
@@ -484,7 +479,7 @@
 
   // Http2PushPromiseIndex::Delegate implementation:
   bool ValidatePushedStream(const SpdySessionKey& key) const override;
-  void OnPushedStreamClaimed(const GURL& url) override;
+  void OnPushedStreamClaimed(const GURL& url, SpdyStreamId stream_id) override;
   base::WeakPtr<SpdySession> GetWeakPtrToSession() override;
 
   // Dumps memory allocation stats to |stats|. Sets |*is_session_active| to
diff --git a/net/spdy/chromium/spdy_session_key.cc b/net/spdy/chromium/spdy_session_key.cc
index 41e7afb..6395af71 100644
--- a/net/spdy/chromium/spdy_session_key.cc
+++ b/net/spdy/chromium/spdy_session_key.cc
@@ -45,7 +45,7 @@
                   other.host_port_proxy_pair_.second);
 }
 
-bool SpdySessionKey::Equals(const SpdySessionKey& other) const {
+bool SpdySessionKey::operator==(const SpdySessionKey& other) const {
   return privacy_mode_ == other.privacy_mode_ &&
       host_port_proxy_pair_.first.Equals(other.host_port_proxy_pair_.first) &&
       host_port_proxy_pair_.second == other.host_port_proxy_pair_.second;
diff --git a/net/spdy/chromium/spdy_session_key.h b/net/spdy/chromium/spdy_session_key.h
index 7aa59a0c..61d78194 100644
--- a/net/spdy/chromium/spdy_session_key.h
+++ b/net/spdy/chromium/spdy_session_key.h
@@ -30,8 +30,8 @@
   // Comparator function so this can be placed in a std::map.
   bool operator<(const SpdySessionKey& other) const;
 
-  // Equality test of contents. (Probably another violation of style guide).
-  bool Equals(const SpdySessionKey& other) const;
+  // Equality test of contents.
+  bool operator==(const SpdySessionKey& other) const;
 
   const HostPortProxyPair& host_port_proxy_pair() const {
     return host_port_proxy_pair_;
diff --git a/net/spdy/chromium/spdy_session_pool.cc b/net/spdy/chromium/spdy_session_pool.cc
index e0e7d35..60519610 100644
--- a/net/spdy/chromium/spdy_session_pool.cc
+++ b/net/spdy/chromium/spdy_session_pool.cc
@@ -138,7 +138,7 @@
     const NetLogWithSource& net_log) {
   AvailableSessionMap::iterator it = LookupAvailableSessionByKey(key);
   if (it != available_sessions_.end()) {
-    if (key.Equals(it->second->spdy_session_key())) {
+    if (key == it->second->spdy_session_key()) {
       UMA_HISTOGRAM_ENUMERATION("Net.SpdySessionGet", FOUND_EXISTING,
                                 SPDY_SESSION_GET_MAX);
       net_log.AddEvent(
@@ -286,7 +286,7 @@
     // host_port_proxy_pair (not an alias).
     const SpdySessionKey& key = it->first;
     const SpdySessionKey& session_key = it->second->spdy_session_key();
-    if (key.Equals(session_key))
+    if (key == session_key)
       list->Append(it->second->GetInfoAsValue());
   }
   return std::move(list);
@@ -498,7 +498,7 @@
   // Walk the aliases map, find references to this pair.
   // TODO(mbelshe):  Figure out if this is too expensive.
   for (AliasMap::iterator it = aliases_.begin(); it != aliases_.end(); ) {
-    if (it->second.Equals(key)) {
+    if (it->second == key) {
       AliasMap::iterator old_it = it;
       ++it;
       aliases_.erase(old_it);
diff --git a/net/ssl/client_cert_identity.cc b/net/ssl/client_cert_identity.cc
index 3b89f41..928aafd 100644
--- a/net/ssl/client_cert_identity.cc
+++ b/net/ssl/client_cert_identity.cc
@@ -5,6 +5,7 @@
 #include "net/ssl/client_cert_identity.h"
 
 #include "base/bind.h"
+#include "net/cert/x509_util.h"
 #include "net/ssl/ssl_private_key.h"
 
 namespace net {
@@ -38,7 +39,7 @@
 }
 
 void ClientCertIdentity::SetIntermediates(
-    X509Certificate::OSCertHandles intermediates) {
+    std::vector<bssl::UniquePtr<CRYPTO_BUFFER>> intermediates) {
   // Allow UTF-8 inside PrintableStrings in client certificates. See
   // crbug.com/770323.
   // TODO(mattm): Perhaps X509Certificate should have a method to clone the
@@ -47,9 +48,10 @@
   // X509Certificate was initially created.)
   X509Certificate::UnsafeCreateOptions options;
   options.printable_string_is_utf8 = true;
-  cert_ = X509Certificate::CreateFromHandleUnsafeOptions(
-      cert_->os_cert_handle(), intermediates, options);
-  // |cert_->os_cert_handle()| was already successfully parsed, so this should
+  cert_ = X509Certificate::CreateFromBufferUnsafeOptions(
+      x509_util::DupCryptoBuffer(cert_->cert_buffer()),
+      std::move(intermediates), options);
+  // |cert_->cert_buffer()| was already successfully parsed, so this should
   // never fail.
   DCHECK(cert_);
 }
@@ -82,10 +84,8 @@
     return a->valid_start() > b->valid_start();
 
   // Otherwise, prefer client certificates with shorter chains.
-  const X509Certificate::OSCertHandles& a_intermediates =
-      a->GetIntermediateCertificates();
-  const X509Certificate::OSCertHandles& b_intermediates =
-      b->GetIntermediateCertificates();
+  const auto& a_intermediates = a->intermediate_buffers();
+  const auto& b_intermediates = b->intermediate_buffers();
   return a_intermediates.size() < b_intermediates.size();
 }
 
diff --git a/net/ssl/client_cert_identity.h b/net/ssl/client_cert_identity.h
index 1f8e4cb7..6848217 100644
--- a/net/ssl/client_cert_identity.h
+++ b/net/ssl/client_cert_identity.h
@@ -56,7 +56,8 @@
   // this will change the value of |certificate()|, and any references that
   // were retained to the previous value will not reflect the updated
   // intermediates list.
-  void SetIntermediates(X509Certificate::OSCertHandles intermediates);
+  void SetIntermediates(
+      std::vector<bssl::UniquePtr<CRYPTO_BUFFER>> intermediates);
 
  private:
   scoped_refptr<net::X509Certificate> cert_;
diff --git a/net/ssl/client_cert_store_mac.cc b/net/ssl/client_cert_store_mac.cc
index 4f8c91b..b2fb32d 100644
--- a/net/ssl/client_cert_store_mac.cc
+++ b/net/ssl/client_cert_store_mac.cc
@@ -134,7 +134,13 @@
   if (!new_cert || !new_cert->IsIssuedByEncoded(valid_issuers))
     return false;
 
-  identity->SetIntermediates(new_cert->GetIntermediateCertificates());
+  std::vector<bssl::UniquePtr<CRYPTO_BUFFER>> intermediate_buffers;
+  intermediate_buffers.reserve(new_cert->intermediate_buffers().size());
+  for (const auto& intermediate : new_cert->intermediate_buffers()) {
+    intermediate_buffers.push_back(
+        x509_util::DupCryptoBuffer(intermediate.get()));
+  }
+  identity->SetIntermediates(std::move(intermediate_buffers));
   return true;
 }
 
@@ -195,7 +201,7 @@
 // storing the matching certificates in |selected_identities|.
 // If |query_keychain| is true, Keychain Services will be queried to construct
 // full certificate chains. If it is false, only the the certificates and their
-// intermediates (available via X509Certificate::GetIntermediateCertificates())
+// intermediates (available via X509Certificate::intermediate_buffers())
 // will be considered.
 void GetClientCertsImpl(std::unique_ptr<ClientCertIdentity> preferred_identity,
                         ClientCertIdentityList regular_identities,
@@ -221,9 +227,9 @@
         selected_identities->begin(), selected_identities->end(),
         [&cert](
             const std::unique_ptr<ClientCertIdentity>& other_cert_identity) {
-          return X509Certificate::IsSameOSCert(
-              cert->certificate()->os_cert_handle(),
-              other_cert_identity->certificate()->os_cert_handle());
+          return x509_util::CryptoBufferEqual(
+              cert->certificate()->cert_buffer(),
+              other_cert_identity->certificate()->cert_buffer());
         });
     if (cert_iter != selected_identities->end())
       continue;
@@ -238,14 +244,14 @@
   }
 
   // Preferred cert should appear first in the ui, so exclude it from the
-  // sorting.  Compare the os_cert_handle since the X509Certificate object may
+  // sorting.  Compare the cert_buffer since the X509Certificate object may
   // have changed if intermediates were added.
   ClientCertIdentityList::iterator sort_begin = selected_identities->begin();
   ClientCertIdentityList::iterator sort_end = selected_identities->end();
   if (preferred_cert_orig && sort_begin != sort_end &&
-      X509Certificate::IsSameOSCert(
-          sort_begin->get()->certificate()->os_cert_handle(),
-          preferred_cert_orig->os_cert_handle())) {
+      x509_util::CryptoBufferEqual(
+          sort_begin->get()->certificate()->cert_buffer(),
+          preferred_cert_orig->cert_buffer())) {
     ++sort_begin;
   }
   sort(sort_begin, sort_end, ClientCertIdentitySorter());
diff --git a/net/ssl/client_cert_store_nss.cc b/net/ssl/client_cert_store_nss.cc
index 512b38e..7c773ee 100644
--- a/net/ssl/client_cert_store_nss.cc
+++ b/net/ssl/client_cert_store_nss.cc
@@ -115,25 +115,22 @@
       continue;
     }
 
-    X509Certificate::OSCertHandles intermediates_raw;
-    intermediates_raw.reserve(nss_intermediates.size());
     std::vector<bssl::UniquePtr<CRYPTO_BUFFER>> intermediates;
     intermediates.reserve(nss_intermediates.size());
     for (const ScopedCERTCertificate& nss_intermediate : nss_intermediates) {
       bssl::UniquePtr<CRYPTO_BUFFER> intermediate_cert_handle(
-          X509Certificate::CreateOSCertHandleFromBytes(
+          X509Certificate::CreateCertBufferFromBytes(
               reinterpret_cast<const char*>(nss_intermediate->derCert.data),
               nss_intermediate->derCert.len));
       if (!intermediate_cert_handle)
         break;
-      intermediates_raw.push_back(intermediate_cert_handle.get());
       intermediates.push_back(std::move(intermediate_cert_handle));
     }
 
     // Retain a copy of the intermediates. Some deployments expect the client to
     // supply intermediates out of the local store. See
     // https://crbug.com/548631.
-    (*examine_iter)->SetIntermediates(intermediates_raw);
+    (*examine_iter)->SetIntermediates(std::move(intermediates));
 
     if (examine_iter == keep_iter)
       ++keep_iter;
diff --git a/net/ssl/client_cert_store_nss_unittest.cc b/net/ssl/client_cert_store_nss_unittest.cc
index 5b9b323..859a38c 100644
--- a/net/ssl/client_cert_store_nss_unittest.cc
+++ b/net/ssl/client_cert_store_nss_unittest.cc
@@ -110,9 +110,9 @@
     ASSERT_EQ(1u, selected_identities.size());
     scoped_refptr<X509Certificate> selected_cert =
         selected_identities[0]->certificate();
-    EXPECT_TRUE(X509Certificate::IsSameOSCert(client_1->os_cert_handle(),
-                                              selected_cert->os_cert_handle()));
-    ASSERT_EQ(0u, selected_cert->GetIntermediateCertificates().size());
+    EXPECT_TRUE(x509_util::CryptoBufferEqual(client_1->cert_buffer(),
+                                             selected_cert->cert_buffer()));
+    ASSERT_EQ(0u, selected_cert->intermediate_buffers().size());
 
     scoped_refptr<SSLPrivateKey> ssl_private_key;
     base::RunLoop key_loop;
@@ -144,12 +144,12 @@
     ASSERT_EQ(1u, selected_identities.size());
     scoped_refptr<X509Certificate> selected_cert =
         selected_identities[0]->certificate();
-    EXPECT_TRUE(X509Certificate::IsSameOSCert(client_1->os_cert_handle(),
-                                              selected_cert->os_cert_handle()));
-    ASSERT_EQ(1u, selected_cert->GetIntermediateCertificates().size());
-    EXPECT_TRUE(X509Certificate::IsSameOSCert(
-        client_1_ca->os_cert_handle(),
-        selected_cert->GetIntermediateCertificates()[0]));
+    EXPECT_TRUE(x509_util::CryptoBufferEqual(client_1->cert_buffer(),
+                                             selected_cert->cert_buffer()));
+    ASSERT_EQ(1u, selected_cert->intermediate_buffers().size());
+    EXPECT_TRUE(x509_util::CryptoBufferEqual(
+        client_1_ca->cert_buffer(),
+        selected_cert->intermediate_buffers()[0].get()));
 
     scoped_refptr<SSLPrivateKey> ssl_private_key;
     base::RunLoop key_loop;
@@ -221,7 +221,7 @@
   scoped_refptr<X509Certificate> selected_cert =
       selected_identities[0]->certificate();
   EXPECT_TRUE(x509_util::IsSameCertificate(cert.get(), selected_cert.get()));
-  EXPECT_EQ(0u, selected_cert->GetIntermediateCertificates().size());
+  EXPECT_EQ(0u, selected_cert->intermediate_buffers().size());
 
   scoped_refptr<SSLPrivateKey> ssl_private_key;
   base::RunLoop key_loop;
diff --git a/net/ssl/client_cert_store_unittest-inl.h b/net/ssl/client_cert_store_unittest-inl.h
index 4da72c4..7cc02d3 100644
--- a/net/ssl/client_cert_store_unittest-inl.h
+++ b/net/ssl/client_cert_store_unittest-inl.h
@@ -152,7 +152,7 @@
   X509Certificate::UnsafeCreateOptions options;
   options.printable_string_is_utf8 = true;
   scoped_refptr<X509Certificate> cert =
-      X509Certificate::CreateFromHandleUnsafeOptions(cert_handle.get(), {},
+      X509Certificate::CreateFromBufferUnsafeOptions(std::move(cert_handle), {},
                                                      options);
   ASSERT_TRUE(cert);
 
diff --git a/net/ssl/client_cert_store_win.cc b/net/ssl/client_cert_store_win.cc
index 6622ea4..d9c271f3 100644
--- a/net/ssl/client_cert_store_win.cc
+++ b/net/ssl/client_cert_store_win.cc
@@ -25,6 +25,7 @@
 #include "net/ssl/ssl_platform_key_util.h"
 #include "net/ssl/ssl_platform_key_win.h"
 #include "net/ssl/ssl_private_key.h"
+#include "third_party/boringssl/src/include/openssl/pool.h"
 
 namespace net {
 
@@ -273,16 +274,16 @@
     return false;
 
   // Add available certificates to the test store.
-  for (size_t i = 0; i < input_certs.size(); ++i) {
+  for (const auto& input_cert : input_certs) {
     // Add the certificate to the test store.
     PCCERT_CONTEXT cert = NULL;
-    std::string der_cert;
-    X509Certificate::GetDEREncoded(input_certs[i]->os_cert_handle(), &der_cert);
     if (!CertAddEncodedCertificateToStore(
             test_store, X509_ASN_ENCODING,
-            reinterpret_cast<const BYTE*>(der_cert.data()),
-            base::checked_cast<DWORD>(der_cert.size()), CERT_STORE_ADD_NEW,
-            &cert)) {
+            reinterpret_cast<const BYTE*>(
+                CRYPTO_BUFFER_data(input_cert->cert_buffer())),
+            base::checked_cast<DWORD>(
+                CRYPTO_BUFFER_len(input_cert->cert_buffer())),
+            CERT_STORE_ADD_NEW, &cert)) {
       return false;
     }
     // Hold the reference to the certificate (since we requested a copy).
diff --git a/net/ssl/openssl_ssl_util.cc b/net/ssl/openssl_ssl_util.cc
index ae0fb4f7..b2067f1 100644
--- a/net/ssl/openssl_ssl_util.cc
+++ b/net/ssl/openssl_ssl_util.cc
@@ -231,11 +231,10 @@
                        EVP_PKEY* pkey,
                        const SSL_PRIVATE_KEY_METHOD* custom_key) {
   std::vector<CRYPTO_BUFFER*> chain_raw;
-  chain_raw.push_back(cert->os_cert_handle());
-  for (X509Certificate::OSCertHandle handle :
-       cert->GetIntermediateCertificates()) {
-    chain_raw.push_back(handle);
-  }
+  chain_raw.reserve(1 + cert->intermediate_buffers().size());
+  chain_raw.push_back(cert->cert_buffer());
+  for (const auto& handle : cert->intermediate_buffers())
+    chain_raw.push_back(handle.get());
 
   if (!SSL_set_chain_and_key(ssl, chain_raw.data(), chain_raw.size(), pkey,
                              custom_key)) {
diff --git a/net/ssl/ssl_client_session_cache.cc b/net/ssl/ssl_client_session_cache.cc
index eebca7640..f7fcdfa6 100644
--- a/net/ssl/ssl_client_session_cache.cc
+++ b/net/ssl/ssl_client_session_cache.cc
@@ -17,7 +17,7 @@
 namespace net {
 
 SSLClientSessionCache::SSLClientSessionCache(const Config& config)
-    : clock_(new base::DefaultClock),
+    : clock_(base::DefaultClock::GetInstance()),
       config_(config),
       cache_(config.max_entries),
       lookups_since_flush_(0) {
@@ -87,9 +87,8 @@
   cache_.Clear();
 }
 
-void SSLClientSessionCache::SetClockForTesting(
-    std::unique_ptr<base::Clock> clock) {
-  clock_ = std::move(clock);
+void SSLClientSessionCache::SetClockForTesting(base::Clock* clock) {
+  clock_ = clock;
 }
 
 bool SSLClientSessionCache::IsExpired(SSL_SESSION* session, time_t now) {
diff --git a/net/ssl/ssl_client_session_cache.h b/net/ssl/ssl_client_session_cache.h
index 865206ff..ad64c80 100644
--- a/net/ssl/ssl_client_session_cache.h
+++ b/net/ssl/ssl_client_session_cache.h
@@ -64,7 +64,7 @@
   // Removes all entries from the cache.
   void Flush();
 
-  void SetClockForTesting(std::unique_ptr<base::Clock> clock);
+  void SetClockForTesting(base::Clock* clock);
 
   // Dumps memory allocation stats. |pmd| is the ProcessMemoryDump of the
   // browser process.
@@ -101,7 +101,7 @@
   void OnMemoryPressure(
       base::MemoryPressureListener::MemoryPressureLevel memory_pressure_level);
 
-  std::unique_ptr<base::Clock> clock_;
+  base::Clock* clock_;
   Config config_;
   base::HashingMRUCache<std::string, Entry> cache_;
   size_t lookups_since_flush_;
diff --git a/net/ssl/ssl_client_session_cache_unittest.cc b/net/ssl/ssl_client_session_cache_unittest.cc
index 6b629918..461fb18 100644
--- a/net/ssl/ssl_client_session_cache_unittest.cc
+++ b/net/ssl/ssl_client_session_cache_unittest.cc
@@ -313,8 +313,8 @@
   SSLClientSessionCache::Config config;
   config.expiration_check_count = kExpirationCheckCount;
   SSLClientSessionCache cache(config);
-  base::SimpleTestClock* clock = MakeTestClock().release();
-  cache.SetClockForTesting(base::WrapUnique(clock));
+  std::unique_ptr<base::SimpleTestClock> clock = MakeTestClock();
+  cache.SetClockForTesting(clock.get());
 
   // Add |kNumEntries - 1| entries.
   for (size_t i = 0; i < kNumEntries - 1; i++) {
@@ -362,8 +362,8 @@
   SSLClientSessionCache::Config config;
   config.expiration_check_count = kExpirationCheckCount;
   SSLClientSessionCache cache(config);
-  base::SimpleTestClock* clock = MakeTestClock().release();
-  cache.SetClockForTesting(base::WrapUnique(clock));
+  std::unique_ptr<base::SimpleTestClock> clock = MakeTestClock();
+  cache.SetClockForTesting(clock.get());
 
   // Insert an entry into the session cache.
   bssl::UniquePtr<SSL_SESSION> session =
@@ -410,8 +410,8 @@
   SSLClientSessionCache::Config config;
   config.expiration_check_count = kExpirationCheckCount;
   SSLClientSessionCache cache(config);
-  base::SimpleTestClock* clock = MakeTestClock().release();
-  cache.SetClockForTesting(base::WrapUnique(clock));
+  std::unique_ptr<base::SimpleTestClock> clock = MakeTestClock();
+  cache.SetClockForTesting(clock.get());
 
   // Insert an entry into the session cache.
   bssl::UniquePtr<SSL_SESSION> session1 =
diff --git a/net/ssl/ssl_platform_key_util.cc b/net/ssl/ssl_platform_key_util.cc
index 46ba59f..70df11b4 100644
--- a/net/ssl/ssl_platform_key_util.cc
+++ b/net/ssl/ssl_platform_key_util.cc
@@ -12,6 +12,7 @@
 #include "crypto/openssl_util.h"
 #include "net/cert/asn1_util.h"
 #include "net/cert/x509_certificate.h"
+#include "net/cert/x509_util.h"
 #include "third_party/boringssl/src/include/openssl/bytestring.h"
 #include "third_party/boringssl/src/include/openssl/ec_key.h"
 #include "third_party/boringssl/src/include/openssl/evp.h"
@@ -54,11 +55,10 @@
                        size_t* out_max_length) {
   crypto::OpenSSLErrStackTracer tracker(FROM_HERE);
 
-  std::string der_encoded;
   base::StringPiece spki;
-  if (!X509Certificate::GetDEREncoded(certificate->os_cert_handle(),
-                                      &der_encoded) ||
-      !asn1::ExtractSPKIFromDERCert(der_encoded, &spki)) {
+  if (!asn1::ExtractSPKIFromDERCert(
+          x509_util::CryptoBufferAsStringPiece(certificate->cert_buffer()),
+          &spki)) {
     LOG(ERROR) << "Could not extract SPKI from certificate.";
     return false;
   }
diff --git a/net/test/cert_test_util.cc b/net/test/cert_test_util.cc
index 0295d7b8..454071f2 100644
--- a/net/test/cert_test_util.cc
+++ b/net/test/cert_test_util.cc
@@ -9,6 +9,7 @@
 #include "base/threading/thread_restrictions.h"
 #include "net/cert/ev_root_ca_metadata.h"
 #include "net/cert/x509_certificate.h"
+#include "net/cert/x509_util.h"
 #include "net/test/test_data_directory.h"
 
 namespace net {
@@ -52,12 +53,14 @@
   if (certs.empty())
     return NULL;
 
-  X509Certificate::OSCertHandles intermediates;
+  std::vector<bssl::UniquePtr<CRYPTO_BUFFER>> intermediates;
   for (size_t i = 1; i < certs.size(); ++i)
-    intermediates.push_back(certs[i]->os_cert_handle());
+    intermediates.push_back(
+        x509_util::DupCryptoBuffer(certs[i]->cert_buffer()));
 
-  scoped_refptr<X509Certificate> result(X509Certificate::CreateFromHandle(
-        certs[0]->os_cert_handle(), intermediates));
+  scoped_refptr<X509Certificate> result(X509Certificate::CreateFromBuffer(
+      x509_util::DupCryptoBuffer(certs[0]->cert_buffer()),
+      std::move(intermediates)));
   return result;
 }
 
diff --git a/net/third_party/nss/ssl/cmpcert.cc b/net/third_party/nss/ssl/cmpcert.cc
index 64e4828..27ceeb8 100644
--- a/net/third_party/nss/ssl/cmpcert.cc
+++ b/net/third_party/nss/ssl/cmpcert.cc
@@ -35,8 +35,8 @@
   der::Input tbs_certificate_tlv;
   der::Input signature_algorithm_tlv;
   der::BitString signature_value;
-  if (!ParseCertificate(der::Input(CRYPTO_BUFFER_data(cert->os_cert_handle()),
-                                   CRYPTO_BUFFER_len(cert->os_cert_handle())),
+  if (!ParseCertificate(der::Input(CRYPTO_BUFFER_data(cert->cert_buffer()),
+                                   CRYPTO_BUFFER_len(cert->cert_buffer())),
                         &tbs_certificate_tlv, &signature_algorithm_tlv,
                         &signature_value, nullptr)) {
     return false;
diff --git a/net/tools/cert_verify_tool/verify_using_cert_verify_proc.cc b/net/tools/cert_verify_tool/verify_using_cert_verify_proc.cc
index 24e9231..38f7c18f 100644
--- a/net/tools/cert_verify_tool/verify_using_cert_verify_proc.cc
+++ b/net/tools/cert_verify_tool/verify_using_cert_verify_proc.cc
@@ -6,6 +6,7 @@
 
 #include <iostream>
 
+#include "base/strings/strcat.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
@@ -15,6 +16,7 @@
 #include "net/cert/cert_verify_proc.h"
 #include "net/cert/cert_verify_result.h"
 #include "net/cert/x509_certificate.h"
+#include "net/cert/x509_util.h"
 #include "net/tools/cert_verify_tool/cert_verify_tool_util.h"
 
 namespace {
@@ -40,12 +42,11 @@
     std::cerr << "ERROR: X509Certificate::GetPEMEncodedChain failed.\n";
     return false;
   }
-  return WriteToFile(file_path, base::JoinString(pem_encoded, ""));
+  return WriteToFile(file_path, base::StrCat(pem_encoded));
 }
 
 // Returns a hex-encoded sha256 of the DER-encoding of |cert_handle|.
-std::string FingerPrintOSCertHandle(
-    net::X509Certificate::OSCertHandle cert_handle) {
+std::string FingerPrintCryptoBuffer(const CRYPTO_BUFFER* cert_handle) {
   net::SHA256HashValue hash =
       net::X509Certificate::CalculateFingerprint256(cert_handle);
   return base::HexEncode(hash.data, arraysize(hash.data));
@@ -57,11 +58,10 @@
 }
 
 // Returns a textual representation of the Subject of |cert_handle|.
-std::string SubjectFromOSCertHandle(
-    net::X509Certificate::OSCertHandle cert_handle) {
+std::string SubjectFromCryptoBuffer(CRYPTO_BUFFER* cert_handle) {
   scoped_refptr<net::X509Certificate> cert =
-      net::X509Certificate::CreateFromHandle(
-          cert_handle, net::X509Certificate::OSCertHandles());
+      net::X509Certificate::CreateFromBuffer(
+          net::x509_util::DupCryptoBuffer(cert_handle), {});
   if (!cert)
     return std::string();
   return SubjectFromX509Certificate(cert.get());
@@ -97,12 +97,13 @@
 
   if (result.verified_cert) {
     std::cout << "chain:\n "
-              << FingerPrintOSCertHandle(result.verified_cert->os_cert_handle())
+              << FingerPrintCryptoBuffer(result.verified_cert->cert_buffer())
               << " " << SubjectFromX509Certificate(result.verified_cert.get())
               << "\n";
-    for (auto* os_cert : result.verified_cert->GetIntermediateCertificates()) {
-      std::cout << " " << FingerPrintOSCertHandle(os_cert) << " "
-                << SubjectFromOSCertHandle(os_cert) << "\n";
+    for (const auto& intermediate :
+         result.verified_cert->intermediate_buffers()) {
+      std::cout << " " << FingerPrintCryptoBuffer(intermediate.get()) << " "
+                << SubjectFromCryptoBuffer(intermediate.get()) << "\n";
     }
   }
 }
diff --git a/net/url_request/url_request_quic_unittest.cc b/net/url_request/url_request_quic_unittest.cc
index 580f652..d2fbf34b 100644
--- a/net/url_request/url_request_quic_unittest.cc
+++ b/net/url_request/url_request_quic_unittest.cc
@@ -99,7 +99,7 @@
 
   void ExtractNetLog(NetLogEventType type,
                      TestNetLogEntry::List* entry_list) const {
-    net::TestNetLogEntry::List entries;
+    TestNetLogEntry::List entries;
     net_log_.GetEntries(&entries);
 
     for (const auto& entry : entries) {
@@ -114,6 +114,33 @@
         ->GetRstErrorCount(error_code);
   }
 
+  static const NetLogSource FindPushUrlSource(
+      const TestNetLogEntry::List& entries,
+      const std::string& push_url) {
+    std::string entry_push_url;
+    for (const auto& entry : entries) {
+      if (entry.phase == NetLogEventPhase::BEGIN &&
+          entry.source.type ==
+              NetLogSourceType::SERVER_PUSH_LOOKUP_TRANSACTION &&
+          entry.GetStringValue("push_url", &entry_push_url) &&
+          entry_push_url == push_url) {
+        return entry.source;
+      }
+    }
+    return NetLogSource();
+  }
+
+  static const TestNetLogEntry* FindEndBySource(
+      const TestNetLogEntry::List& entries,
+      const NetLogSource& source) {
+    for (const auto& entry : entries) {
+      if (entry.phase == NetLogEventPhase::END &&
+          entry.source.type == source.type && entry.source.id == source.id)
+        return &entry;
+    }
+    return nullptr;
+  }
+
  private:
   void StartQuicServer() {
     // Set up in-memory cache.
@@ -301,46 +328,25 @@
   std::string push_url_2 =
       base::StringPrintf("https://%s%s", kTestServerHost, "/favicon.ico");
 
-  ASSERT_EQ(entries[0].type,
-            net::NetLogEventType::SERVER_PUSH_LOOKUP_TRANSACTION);
-  EXPECT_EQ(entries[0].phase, net::NetLogEventPhase::BEGIN);
-  EXPECT_EQ(entries[0].source.type,
-            net::NetLogSourceType::SERVER_PUSH_LOOKUP_TRANSACTION);
-  EXPECT_TRUE(entries[0].params);
-  EXPECT_TRUE(entries[0].GetStringValue("push_url", &value));
-  EXPECT_EQ(value, push_url_1);
+  const NetLogSource source_1 = FindPushUrlSource(entries, push_url_1);
+  EXPECT_TRUE(source_1.IsValid());
 
-  ASSERT_EQ(entries[1].type,
-            net::NetLogEventType::SERVER_PUSH_LOOKUP_TRANSACTION);
-  EXPECT_EQ(entries[1].phase, net::NetLogEventPhase::BEGIN);
-  EXPECT_EQ(entries[1].source.type,
-            net::NetLogSourceType::SERVER_PUSH_LOOKUP_TRANSACTION);
-  EXPECT_TRUE(entries[1].params);
-  EXPECT_TRUE(entries[1].GetStringValue("push_url", &value));
-  EXPECT_EQ(value, push_url_2);
+  // No net error code for this lookup transaction, the push is found.
+  const TestNetLogEntry* end_entry_1 = FindEndBySource(entries, source_1);
+  EXPECT_FALSE(end_entry_1->params);
+  EXPECT_FALSE(end_entry_1->GetIntegerValue("net_error", &net_error));
 
-  ASSERT_EQ(entries[2].type,
-            net::NetLogEventType::SERVER_PUSH_LOOKUP_TRANSACTION);
-  EXPECT_EQ(entries[2].phase, net::NetLogEventPhase::END);
-  EXPECT_EQ(entries[2].source.type,
-            net::NetLogSourceType::SERVER_PUSH_LOOKUP_TRANSACTION);
-  EXPECT_EQ(entries[2].source.id, entries[1].source.id);
-  EXPECT_TRUE(entries[2].params);
+  const NetLogSource source_2 = FindPushUrlSource(entries, push_url_2);
+  EXPECT_TRUE(source_2.IsValid());
+  EXPECT_NE(source_1.id, source_2.id);
+
   // Net error code -400 is found for this lookup transaction, the push is not
   // found in the cache.
-  EXPECT_TRUE(entries[2].GetIntegerValue("net_error", &net_error));
+  const TestNetLogEntry* end_entry_2 = FindEndBySource(entries, source_2);
+  EXPECT_TRUE(end_entry_2->params);
+  EXPECT_TRUE(end_entry_2->GetIntegerValue("net_error", &net_error));
   EXPECT_EQ(net_error, -400);
 
-  ASSERT_EQ(entries[3].type,
-            net::NetLogEventType::SERVER_PUSH_LOOKUP_TRANSACTION);
-  EXPECT_EQ(entries[3].phase, net::NetLogEventPhase::END);
-  EXPECT_EQ(entries[3].source.type,
-            net::NetLogSourceType::SERVER_PUSH_LOOKUP_TRANSACTION);
-  EXPECT_EQ(entries[3].source.id, entries[0].source.id);
-  EXPECT_FALSE(entries[3].params);
-  // No net error code for this lookup transaction, the push is found.
-  EXPECT_FALSE(entries[3].GetIntegerValue("net_error", &net_error));
-
   // Verify the reset error count received on the server side.
   EXPECT_LE(1u, GetRstErrorCountReceivedByServer(QUIC_STREAM_CANCELLED));
 }
@@ -416,41 +422,22 @@
   std::string push_url_2 =
       base::StringPrintf("https://%s%s", kTestServerHost, "/favicon.ico");
 
-  ASSERT_EQ(entries[0].type,
-            net::NetLogEventType::SERVER_PUSH_LOOKUP_TRANSACTION);
-  EXPECT_EQ(entries[0].phase, net::NetLogEventPhase::BEGIN);
-  EXPECT_EQ(entries[0].source.type,
-            net::NetLogSourceType::SERVER_PUSH_LOOKUP_TRANSACTION);
-  EXPECT_TRUE(entries[0].params);
-  EXPECT_TRUE(entries[0].GetStringValue("push_url", &value));
-  EXPECT_EQ(value, push_url_1);
+  const NetLogSource source_1 = FindPushUrlSource(entries, push_url_1);
+  EXPECT_TRUE(source_1.IsValid());
 
-  ASSERT_EQ(entries[1].type,
-            net::NetLogEventType::SERVER_PUSH_LOOKUP_TRANSACTION);
-  EXPECT_EQ(entries[1].phase, net::NetLogEventPhase::BEGIN);
-  EXPECT_EQ(entries[1].source.type,
-            net::NetLogSourceType::SERVER_PUSH_LOOKUP_TRANSACTION);
-  EXPECT_TRUE(entries[1].params);
-  EXPECT_TRUE(entries[1].GetStringValue("push_url", &value));
-  EXPECT_EQ(value, push_url_2);
-
-  ASSERT_EQ(entries[2].type,
-            net::NetLogEventType::SERVER_PUSH_LOOKUP_TRANSACTION);
-  EXPECT_EQ(entries[2].phase, net::NetLogEventPhase::END);
-  EXPECT_EQ(entries[2].source.type,
-            net::NetLogSourceType::SERVER_PUSH_LOOKUP_TRANSACTION);
-  EXPECT_FALSE(entries[2].params);
   // No net error code for this lookup transaction, the push is found.
-  EXPECT_FALSE(entries[2].GetIntegerValue("net_error", &net_error));
+  const TestNetLogEntry* end_entry_1 = FindEndBySource(entries, source_1);
+  EXPECT_FALSE(end_entry_1->params);
+  EXPECT_FALSE(end_entry_1->GetIntegerValue("net_error", &net_error));
 
-  ASSERT_EQ(entries[3].type,
-            net::NetLogEventType::SERVER_PUSH_LOOKUP_TRANSACTION);
-  EXPECT_EQ(entries[3].phase, net::NetLogEventPhase::END);
-  EXPECT_EQ(entries[3].source.type,
-            net::NetLogSourceType::SERVER_PUSH_LOOKUP_TRANSACTION);
-  EXPECT_FALSE(entries[3].params);
+  const NetLogSource source_2 = FindPushUrlSource(entries, push_url_2);
+  EXPECT_TRUE(source_1.IsValid());
+  EXPECT_NE(source_1.id, source_2.id);
+
   // No net error code for this lookup transaction, the push is found.
-  EXPECT_FALSE(entries[3].GetIntegerValue("net_error", &net_error));
+  const TestNetLogEntry* end_entry_2 = FindEndBySource(entries, source_2);
+  EXPECT_FALSE(end_entry_2->params);
+  EXPECT_FALSE(end_entry_2->GetIntegerValue("net_error", &net_error));
 
   // Verify the reset error count received on the server side.
   EXPECT_LE(2u, GetRstErrorCountReceivedByServer(QUIC_STREAM_CANCELLED));
@@ -490,14 +477,19 @@
   std::string push_url_2 =
       base::StringPrintf("https://%s%s", kTestServerHost, "/favicon.ico");
 
-  EXPECT_TRUE(entries[0].GetStringValue("push_url", &value));
-  EXPECT_EQ(value, push_url_1);
-  EXPECT_TRUE(entries[1].GetIntegerValue("net_error", &net_error));
+  const NetLogSource source_1 = FindPushUrlSource(entries, push_url_1);
+  EXPECT_TRUE(source_1.IsValid());
+  const TestNetLogEntry* end_entry_1 = FindEndBySource(entries, source_1);
+  EXPECT_TRUE(end_entry_1->params);
+  EXPECT_TRUE(end_entry_1->GetIntegerValue("net_error", &net_error));
   EXPECT_EQ(net_error, -400);
 
-  EXPECT_TRUE(entries[2].GetStringValue("push_url", &value));
-  EXPECT_EQ(value, push_url_2);
-  EXPECT_TRUE(entries[3].GetIntegerValue("net_error", &net_error));
+  const NetLogSource source_2 = FindPushUrlSource(entries, push_url_2);
+  EXPECT_TRUE(source_2.IsValid());
+  EXPECT_NE(source_1.id, source_2.id);
+  const TestNetLogEntry* end_entry_2 = FindEndBySource(entries, source_2);
+  EXPECT_TRUE(end_entry_2->params);
+  EXPECT_TRUE(end_entry_2->GetIntegerValue("net_error", &net_error));
   EXPECT_EQ(net_error, -400);
 
   // Verify the reset error count received on the server side.
diff --git a/net/url_request/url_request_unittest.cc b/net/url_request/url_request_unittest.cc
index cd24979..daf0d40 100644
--- a/net/url_request/url_request_unittest.cc
+++ b/net/url_request/url_request_unittest.cc
@@ -11189,14 +11189,13 @@
     EXPECT_EQ(OK, d.request_status());
     EXPECT_EQ(0u, cert_status & CERT_STATUS_ALL_ERRORS);
     ASSERT_TRUE(r->ssl_info().cert);
-    EXPECT_EQ(2u, r->ssl_info().cert->GetIntermediateCertificates().size());
+    EXPECT_EQ(2u, r->ssl_info().cert->intermediate_buffers().size());
   } else {
     EXPECT_EQ(CERT_STATUS_AUTHORITY_INVALID,
               cert_status & CERT_STATUS_ALL_ERRORS);
   }
   ASSERT_TRUE(r->ssl_info().unverified_cert);
-  EXPECT_EQ(
-      0u, r->ssl_info().unverified_cert->GetIntermediateCertificates().size());
+  EXPECT_EQ(0u, r->ssl_info().unverified_cert->intermediate_buffers().size());
 }
 
 class HTTPSHardFailTest : public HTTPSOCSPTest {
diff --git a/remoting/base/buffered_socket_writer.cc b/remoting/base/buffered_socket_writer.cc
index 520f9995..bb13d36 100644
--- a/remoting/base/buffered_socket_writer.cc
+++ b/remoting/base/buffered_socket_writer.cc
@@ -63,7 +63,8 @@
 
 void BufferedSocketWriter::Write(
     const scoped_refptr<net::IOBufferWithSize>& data,
-    const base::Closure& done_task) {
+    const base::Closure& done_task,
+    const net::NetworkTrafficAnnotationTag& traffic_annotation) {
   DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(data.get());
 
@@ -71,6 +72,7 @@
   if (closed_)
     return;
 
+  // TODO(crbug.com/656607): Handle traffic annotation.
   queue_.push_back(base::MakeUnique<PendingPacket>(
       new net::DrainableIOBuffer(data.get(), data->size()), done_task));
 
diff --git a/remoting/base/buffered_socket_writer.h b/remoting/base/buffered_socket_writer.h
index 9ac6517..43e1cfc 100644
--- a/remoting/base/buffered_socket_writer.h
+++ b/remoting/base/buffered_socket_writer.h
@@ -49,7 +49,8 @@
   // Puts a new data chunk in the buffer. If called before Start() then all data
   // is buffered until Start().
   void Write(const scoped_refptr<net::IOBufferWithSize>& buffer,
-             const base::Closure& done_task);
+             const base::Closure& done_task,
+             const net::NetworkTrafficAnnotationTag& traffic_annotation);
 
   // Returns true when there is data waiting to be written.
   bool has_data_pending() { return !queue_.empty(); }
diff --git a/remoting/base/buffered_socket_writer_unittest.cc b/remoting/base/buffered_socket_writer_unittest.cc
index 854804e..b86cb877 100644
--- a/remoting/base/buffered_socket_writer_unittest.cc
+++ b/remoting/base/buffered_socket_writer_unittest.cc
@@ -137,17 +137,19 @@
   }
 
   void TestWrite() {
-    writer_->Write(test_buffer_, base::Closure());
-    writer_->Write(test_buffer_2_, base::Closure());
+    writer_->Write(test_buffer_, base::Closure(), TRAFFIC_ANNOTATION_FOR_TESTS);
+    writer_->Write(test_buffer_2_, base::Closure(),
+                   TRAFFIC_ANNOTATION_FOR_TESTS);
     base::RunLoop().RunUntilIdle();
     VerifyWrittenData();
   }
 
   void TestAppendInCallback() {
-    writer_->Write(test_buffer_, base::Bind(
-        base::IgnoreResult(&BufferedSocketWriter::Write),
-        base::Unretained(writer_.get()), test_buffer_2_,
-        base::Closure()));
+    writer_->Write(test_buffer_,
+                   base::Bind(base::IgnoreResult(&BufferedSocketWriter::Write),
+                              base::Unretained(writer_.get()), test_buffer_2_,
+                              base::Closure(), TRAFFIC_ANNOTATION_FOR_TESTS),
+                   TRAFFIC_ANNOTATION_FOR_TESTS);
     base::RunLoop().RunUntilIdle();
     VerifyWrittenData();
   }
@@ -201,12 +203,14 @@
 TEST_F(BufferedSocketWriterTest, DestroyFromCallback) {
   StartWriter();
   socket_data_provider_.set_async_write(true);
-  writer_->Write(test_buffer_, base::Bind(
-      &BufferedSocketWriterTest::DestroyWriter,
-      base::Unretained(this)));
-  writer_->Write(test_buffer_2_, base::Bind(
-      &BufferedSocketWriterTest::Unexpected,
-      base::Unretained(this)));
+  writer_->Write(test_buffer_,
+                 base::Bind(&BufferedSocketWriterTest::DestroyWriter,
+                            base::Unretained(this)),
+                 TRAFFIC_ANNOTATION_FOR_TESTS);
+  writer_->Write(
+      test_buffer_2_,
+      base::Bind(&BufferedSocketWriterTest::Unexpected, base::Unretained(this)),
+      TRAFFIC_ANNOTATION_FOR_TESTS);
   socket_data_provider_.set_async_write(false);
   base::RunLoop().RunUntilIdle();
   ASSERT_GE(socket_data_provider_.written_data().size(),
@@ -220,12 +224,13 @@
 TEST_F(BufferedSocketWriterTest, TestWriteErrorSync) {
   StartWriter();
   socket_data_provider_.set_write_limit(kWriteChunkSize);
-  writer_->Write(test_buffer_, base::Closure());
+  writer_->Write(test_buffer_, base::Closure(), TRAFFIC_ANNOTATION_FOR_TESTS);
   socket_data_provider_.set_async_write(true);
   socket_data_provider_.set_next_write_error(net::ERR_FAILED);
-  writer_->Write(test_buffer_2_,
-                 base::Bind(&BufferedSocketWriterTest::Unexpected,
-                            base::Unretained(this)));
+  writer_->Write(
+      test_buffer_2_,
+      base::Bind(&BufferedSocketWriterTest::Unexpected, base::Unretained(this)),
+      TRAFFIC_ANNOTATION_FOR_TESTS);
   socket_data_provider_.set_async_write(false);
   base::RunLoop().RunUntilIdle();
   EXPECT_EQ(net::ERR_FAILED, write_error_);
@@ -237,12 +242,13 @@
 TEST_F(BufferedSocketWriterTest, TestWriteErrorAsync) {
   StartWriter();
   socket_data_provider_.set_write_limit(kWriteChunkSize);
-  writer_->Write(test_buffer_, base::Closure());
+  writer_->Write(test_buffer_, base::Closure(), TRAFFIC_ANNOTATION_FOR_TESTS);
   socket_data_provider_.set_async_write(true);
   socket_data_provider_.set_next_write_error(net::ERR_FAILED);
-  writer_->Write(test_buffer_2_,
-                 base::Bind(&BufferedSocketWriterTest::Unexpected,
-                            base::Unretained(this)));
+  writer_->Write(
+      test_buffer_2_,
+      base::Bind(&BufferedSocketWriterTest::Unexpected, base::Unretained(this)),
+      TRAFFIC_ANNOTATION_FOR_TESTS);
   base::RunLoop().RunUntilIdle();
   EXPECT_EQ(net::ERR_FAILED, write_error_);
   EXPECT_EQ(static_cast<size_t>(test_buffer_->size()),
@@ -250,8 +256,8 @@
 }
 
 TEST_F(BufferedSocketWriterTest, WriteBeforeStart) {
-  writer_->Write(test_buffer_, base::Closure());
-  writer_->Write(test_buffer_2_, base::Closure());
+  writer_->Write(test_buffer_, base::Closure(), TRAFFIC_ANNOTATION_FOR_TESTS);
+  writer_->Write(test_buffer_2_, base::Closure(), TRAFFIC_ANNOTATION_FOR_TESTS);
 
   StartWriter();
   base::RunLoop().RunUntilIdle();
diff --git a/remoting/client/audio/audio_player_buffer.cc b/remoting/client/audio/audio_player_buffer.cc
index d55a452e..906d7367 100644
--- a/remoting/client/audio/audio_player_buffer.cc
+++ b/remoting/client/audio/audio_player_buffer.cc
@@ -166,7 +166,6 @@
 
       memcpy(next_frame, packet_data.data() + bytes_consumed_, bytes_to_copy);
 
-      next_frame += bytes_to_copy;
       bytes_consumed_ += bytes_to_copy;
       activeRequest->bytes_extracted_ += bytes_to_copy;
       queued_bytes_ -= bytes_to_copy;
diff --git a/remoting/ios/app/app_view_controller_chromium.mm b/remoting/ios/app/app_view_controller_chromium.mm
index fb91461..d5779e0 100644
--- a/remoting/ios/app/app_view_controller_chromium.mm
+++ b/remoting/ios/app/app_view_controller_chromium.mm
@@ -32,6 +32,8 @@
 }
 
 - (void)viewDidLoad {
+  [super viewDidLoad];
+
   [self addChildViewController:_mainViewController];
   [self.view addSubview:_mainViewController.view];
   [_mainViewController didMoveToParentViewController:self];
diff --git a/remoting/ios/app/first_launch_view_controller.mm b/remoting/ios/app/first_launch_view_controller.mm
index c407ba2..3fa4897 100644
--- a/remoting/ios/app/first_launch_view_controller.mm
+++ b/remoting/ios/app/first_launch_view_controller.mm
@@ -31,6 +31,8 @@
 #pragma mark - UIViewController
 
 - (void)viewDidLoad {
+  [super viewDidLoad];
+
   UIImageView* imageView = [[UIImageView alloc]
       initWithImage:[UIImage imageNamed:@"launchscreen_app_logo"]];
   imageView.translatesAutoresizingMaskIntoConstraints = NO;
diff --git a/remoting/ios/app/host_fetching_error_view_controller.mm b/remoting/ios/app/host_fetching_error_view_controller.mm
index 2e82d67..134ac85 100644
--- a/remoting/ios/app/host_fetching_error_view_controller.mm
+++ b/remoting/ios/app/host_fetching_error_view_controller.mm
@@ -41,6 +41,8 @@
 }
 
 - (void)viewDidLoad {
+  [super viewDidLoad];
+
   UIView* contentView = [[UIView alloc] initWithFrame:CGRectZero];
   contentView.backgroundColor = RemotingTheme.setupListBackgroundColor;
   contentView.translatesAutoresizingMaskIntoConstraints = NO;
diff --git a/remoting/ios/app/host_fetching_view_controller.mm b/remoting/ios/app/host_fetching_view_controller.mm
index bd4cd297..c53e7a2 100644
--- a/remoting/ios/app/host_fetching_view_controller.mm
+++ b/remoting/ios/app/host_fetching_view_controller.mm
@@ -17,6 +17,8 @@
 @implementation HostFetchingViewController
 
 - (void)viewDidLoad {
+  [super viewDidLoad];
+
   MDCActivityIndicator* activityIndicator = [[MDCActivityIndicator alloc] init];
   activityIndicator.translatesAutoresizingMaskIntoConstraints = NO;
   activityIndicator.cycleColors = @[ RemotingTheme.refreshIndicatorColor ];
diff --git a/remoting/ios/keychain_wrapper.mm b/remoting/ios/keychain_wrapper.mm
index 593c7ab..414be0e6 100644
--- a/remoting/ios/keychain_wrapper.mm
+++ b/remoting/ios/keychain_wrapper.mm
@@ -125,13 +125,12 @@
   if (mapString &&
       [mapString respondsToSelector:@selector(dataUsingEncoding:)]) {
     NSData* data = [mapString dataUsingEncoding:NSUTF8StringEncoding];
-    NSDictionary* pairingMap;
-    if (data) {
-      pairingMap = (NSDictionary*)[NSJSONSerialization
-          JSONObjectWithData:data
-                     options:NSJSONReadingMutableContainers
-                       error:&err];
-    }
+    NSDictionary* pairingMap =
+        data ? (NSDictionary*)[NSJSONSerialization
+                   JSONObjectWithData:data
+                              options:NSJSONReadingMutableContainers
+                                error:&err]
+             : @{};
     if (!err) {
       return [NSMutableDictionary dictionaryWithDictionary:pairingMap];
     }
diff --git a/remoting/protocol/channel_multiplexer.cc b/remoting/protocol/channel_multiplexer.cc
index fcaf5533..f766da5 100644
--- a/remoting/protocol/channel_multiplexer.cc
+++ b/remoting/protocol/channel_multiplexer.cc
@@ -19,7 +19,6 @@
 #include "base/single_thread_task_runner.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "net/base/net_errors.h"
-#include "net/traffic_annotation/network_traffic_annotation.h"
 #include "remoting/protocol/message_serialization.h"
 #include "remoting/protocol/p2p_stream_socket.h"
 
@@ -83,7 +82,8 @@
   // Called by MuxSocket.
   void OnSocketDestroyed();
   void DoWrite(std::unique_ptr<MultiplexPacket> packet,
-               const base::Closure& done_task);
+               const base::Closure& done_task,
+               const net::NetworkTrafficAnnotationTag& traffic_annotation);
   int DoRead(const scoped_refptr<net::IOBuffer>& buffer, int buffer_len);
 
  private:
@@ -184,13 +184,14 @@
 
 void ChannelMultiplexer::MuxChannel::DoWrite(
     std::unique_ptr<MultiplexPacket> packet,
-    const base::Closure& done_task) {
+    const base::Closure& done_task,
+    const net::NetworkTrafficAnnotationTag& traffic_annotation) {
   packet->set_channel_id(send_id_);
   if (!id_sent_) {
     packet->set_channel_name(name_);
     id_sent_ = true;
   }
-  multiplexer_->DoWrite(std::move(packet), done_task);
+  multiplexer_->DoWrite(std::move(packet), done_task, traffic_annotation);
 }
 
 int ChannelMultiplexer::MuxChannel::DoRead(
@@ -248,8 +249,6 @@
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   DCHECK(write_callback_.is_null());
 
-  // TODO(crbug.com/656607): Handle traffic annotation.
-
   if (base_channel_error_ != net::OK)
     return base_channel_error_;
 
@@ -260,7 +259,8 @@
   write_pending_ = true;
   channel_->DoWrite(std::move(packet),
                     base::Bind(&ChannelMultiplexer::MuxSocket::OnWriteComplete,
-                               weak_factory_.GetWeakPtr()));
+                               weak_factory_.GetWeakPtr()),
+                    traffic_annotation);
 
   // OnWriteComplete() might be called above synchronously.
   if (write_pending_) {
@@ -461,9 +461,12 @@
   channel->OnIncomingPacket(std::move(packet));
 }
 
-void ChannelMultiplexer::DoWrite(std::unique_ptr<MultiplexPacket> packet,
-                                 const base::Closure& done_task) {
-  writer_.Write(SerializeAndFrameMessage(*packet), done_task);
+void ChannelMultiplexer::DoWrite(
+    std::unique_ptr<MultiplexPacket> packet,
+    const base::Closure& done_task,
+    const net::NetworkTrafficAnnotationTag& traffic_annotation) {
+  writer_.Write(SerializeAndFrameMessage(*packet), done_task,
+                traffic_annotation);
 }
 
 }  // namespace protocol
diff --git a/remoting/protocol/channel_multiplexer.h b/remoting/protocol/channel_multiplexer.h
index 16af179..f99d9764 100644
--- a/remoting/protocol/channel_multiplexer.h
+++ b/remoting/protocol/channel_multiplexer.h
@@ -9,6 +9,7 @@
 
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
+#include "net/traffic_annotation/network_traffic_annotation.h"
 #include "remoting/base/buffered_socket_writer.h"
 #include "remoting/proto/mux.pb.h"
 #include "remoting/protocol/message_reader.h"
@@ -58,7 +59,8 @@
 
   // Called by MuxChannel.
   void DoWrite(std::unique_ptr<MultiplexPacket> packet,
-               const base::Closure& done_task);
+               const base::Closure& done_task,
+               const net::NetworkTrafficAnnotationTag& traffic_annotation);
 
   // Factory used to create |base_channel_|. Set to nullptr once creation is
   // finished or failed.
diff --git a/remoting/protocol/channel_multiplexer_unittest.cc b/remoting/protocol/channel_multiplexer_unittest.cc
index 6ff2a84..c23db481 100644
--- a/remoting/protocol/channel_multiplexer_unittest.cc
+++ b/remoting/protocol/channel_multiplexer_unittest.cc
@@ -16,6 +16,7 @@
 #include "net/base/net_errors.h"
 #include "net/socket/socket.h"
 #include "net/socket/stream_socket.h"
+#include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
 #include "remoting/base/constants.h"
 #include "remoting/protocol/connection_tester.h"
 #include "remoting/protocol/fake_stream_socket.h"
@@ -242,9 +243,11 @@
   EXPECT_CALL(cb2, Run(net::ERR_FAILED));
 
   EXPECT_EQ(net::ERR_IO_PENDING,
-            host_socket1_->Write(buf.get(), buf->size(), cb1.Get()));
+            host_socket1_->Write(buf.get(), buf->size(), cb1.Get(),
+                                 TRAFFIC_ANNOTATION_FOR_TESTS));
   EXPECT_EQ(net::ERR_IO_PENDING,
-            host_socket2_->Write(buf.get(), buf->size(), cb2.Get()));
+            host_socket2_->Write(buf.get(), buf->size(), cb2.Get(),
+                                 TRAFFIC_ANNOTATION_FOR_TESTS));
 
   base::RunLoop().RunUntilIdle();
 }
@@ -268,9 +271,11 @@
   EXPECT_CALL(cb2, Run(net::ERR_FAILED));
 
   EXPECT_EQ(net::ERR_IO_PENDING,
-            host_socket1_->Write(buf.get(), buf->size(), cb1.Get()));
+            host_socket1_->Write(buf.get(), buf->size(), cb1.Get(),
+                                 TRAFFIC_ANNOTATION_FOR_TESTS));
   EXPECT_EQ(net::ERR_IO_PENDING,
-            host_socket2_->Write(buf.get(), buf->size(), cb2.Get()));
+            host_socket2_->Write(buf.get(), buf->size(), cb2.Get(),
+                                 TRAFFIC_ANNOTATION_FOR_TESTS));
 
   base::RunLoop().RunUntilIdle();
 }
@@ -297,9 +302,11 @@
       .WillOnce(InvokeWithoutArgs(this, &ChannelMultiplexerTest::DeleteAll));
 
   EXPECT_EQ(net::ERR_IO_PENDING,
-            host_socket1_->Write(buf.get(), buf->size(), cb1.Get()));
+            host_socket1_->Write(buf.get(), buf->size(), cb1.Get(),
+                                 TRAFFIC_ANNOTATION_FOR_TESTS));
   EXPECT_EQ(net::ERR_IO_PENDING,
-            host_socket2_->Write(buf.get(), buf->size(), cb2.Get()));
+            host_socket2_->Write(buf.get(), buf->size(), cb2.Get(),
+                                 TRAFFIC_ANNOTATION_FOR_TESTS));
 
   base::RunLoop().RunUntilIdle();
 
diff --git a/remoting/protocol/client_video_dispatcher_unittest.cc b/remoting/protocol/client_video_dispatcher_unittest.cc
index d4722f4..badb72b 100644
--- a/remoting/protocol/client_video_dispatcher_unittest.cc
+++ b/remoting/protocol/client_video_dispatcher_unittest.cc
@@ -10,6 +10,7 @@
 #include "base/bind.h"
 #include "base/message_loop/message_loop.h"
 #include "base/run_loop.h"
+#include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
 #include "remoting/base/buffered_socket_writer.h"
 #include "remoting/base/constants.h"
 #include "remoting/proto/video.pb.h"
@@ -128,7 +129,8 @@
   packet.set_data(std::string());
 
   // Send a VideoPacket and verify that the client receives it.
-  writer_.Write(SerializeAndFrameMessage(packet), base::Closure());
+  writer_.Write(SerializeAndFrameMessage(packet), base::Closure(),
+                TRAFFIC_ANNOTATION_FOR_TESTS);
   base::RunLoop().RunUntilIdle();
   EXPECT_EQ(1U, video_packets_.size());
 
@@ -148,7 +150,8 @@
   packet.set_frame_id(kTestFrameId);
 
   // Send a VideoPacket and verify that the client receives it.
-  writer_.Write(SerializeAndFrameMessage(packet), base::Closure());
+  writer_.Write(SerializeAndFrameMessage(packet), base::Closure(),
+                TRAFFIC_ANNOTATION_FOR_TESTS);
   base::RunLoop().RunUntilIdle();
   EXPECT_EQ(1U, video_packets_.size());
 
@@ -184,7 +187,8 @@
       .WillOnce(testing::SaveArg<0>(&layout));
 
   // Send a VideoPacket and verify that the client receives it.
-  writer_.Write(SerializeAndFrameMessage(packet), base::Closure());
+  writer_.Write(SerializeAndFrameMessage(packet), base::Closure(),
+                TRAFFIC_ANNOTATION_FOR_TESTS);
   base::RunLoop().RunUntilIdle();
 
   ASSERT_EQ(1, layout.video_track_size());
@@ -205,11 +209,13 @@
   packet.set_frame_id(kTestFrameId);
 
   // Send two VideoPackets.
-  writer_.Write(SerializeAndFrameMessage(packet), base::Closure());
+  writer_.Write(SerializeAndFrameMessage(packet), base::Closure(),
+                TRAFFIC_ANNOTATION_FOR_TESTS);
   base::RunLoop().RunUntilIdle();
 
   packet.set_frame_id(kTestFrameId + 1);
-  writer_.Write(SerializeAndFrameMessage(packet), base::Closure());
+  writer_.Write(SerializeAndFrameMessage(packet), base::Closure(),
+                TRAFFIC_ANNOTATION_FOR_TESTS);
   base::RunLoop().RunUntilIdle();
 
   EXPECT_EQ(2U, video_packets_.size());
diff --git a/remoting/protocol/connection_tester.cc b/remoting/protocol/connection_tester.cc
index f965739..4cd34bf 100644
--- a/remoting/protocol/connection_tester.cc
+++ b/remoting/protocol/connection_tester.cc
@@ -9,6 +9,7 @@
 #include "base/threading/thread_task_runner_handle.h"
 #include "net/base/io_buffer.h"
 #include "net/base/net_errors.h"
+#include "net/traffic_annotation/network_traffic_annotation.h"
 #include "remoting/proto/video.pb.h"
 #include "remoting/protocol/message_pipe.h"
 #include "remoting/protocol/message_serialization.h"
@@ -76,10 +77,11 @@
 
     int bytes_to_write = std::min(output_buffer_->BytesRemaining(),
                                   message_size_);
+    // TODO(crbug.com/656607): Add proper annotation.
     result = client_socket_->Write(
-        output_buffer_.get(),
-        bytes_to_write,
-        base::Bind(&StreamConnectionTester::OnWritten, base::Unretained(this)));
+        output_buffer_.get(), bytes_to_write,
+        base::Bind(&StreamConnectionTester::OnWritten, base::Unretained(this)),
+        NO_TRAFFIC_ANNOTATION_BUG_656607);
     HandleWriteResult(result);
   }
 }
diff --git a/remoting/protocol/fake_authenticator.cc b/remoting/protocol/fake_authenticator.cc
index 8793492d..663cd50 100644
--- a/remoting/protocol/fake_authenticator.cc
+++ b/remoting/protocol/fake_authenticator.cc
@@ -14,6 +14,7 @@
 #include "base/strings/string_number_conversions.h"
 #include "net/base/io_buffer.h"
 #include "net/base/net_errors.h"
+#include "net/traffic_annotation/network_traffic_annotation.h"
 #include "remoting/base/constants.h"
 #include "remoting/protocol/p2p_stream_socket.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -44,10 +45,12 @@
     } else {
       scoped_refptr<net::IOBuffer> write_buf = new net::IOBuffer(1);
       write_buf->data()[0] = 0;
+      // TODO(crbug.com/656607): Add proper annotation.
       int result = socket_->Write(
           write_buf.get(), 1,
           base::Bind(&FakeChannelAuthenticator::OnAuthBytesWritten,
-                     weak_factory_.GetWeakPtr()));
+                     weak_factory_.GetWeakPtr()),
+          NO_TRAFFIC_ANNOTATION_BUG_656607);
       if (result != net::ERR_IO_PENDING) {
         // This will not call the callback because |did_read_bytes_| is
         // still set to false.
diff --git a/remoting/protocol/fake_stream_socket.h b/remoting/protocol/fake_stream_socket.h
index 778dbffe..fbe8d6c 100644
--- a/remoting/protocol/fake_stream_socket.h
+++ b/remoting/protocol/fake_stream_socket.h
@@ -74,12 +74,11 @@
   // P2PStreamSocket interface.
   int Read(const scoped_refptr<net::IOBuffer>& buf, int buf_len,
            const net::CompletionCallback& callback) override;
-  // TODO(crbug.com/656607): Remove default value.
-  int Write(const scoped_refptr<net::IOBuffer>& buf,
-            int buf_len,
-            const net::CompletionCallback& callback,
-            const net::NetworkTrafficAnnotationTag& traffic_annotation =
-                NO_TRAFFIC_ANNOTATION_BUG_656607) override;
+  int Write(
+      const scoped_refptr<net::IOBuffer>& buf,
+      int buf_len,
+      const net::CompletionCallback& callback,
+      const net::NetworkTrafficAnnotationTag& traffic_annotation) override;
 
  private:
   void DoAsyncWrite(const scoped_refptr<net::IOBuffer>& buf, int buf_len,
diff --git a/remoting/protocol/p2p_stream_socket.h b/remoting/protocol/p2p_stream_socket.h
index 27b605c..8ca09663 100644
--- a/remoting/protocol/p2p_stream_socket.h
+++ b/remoting/protocol/p2p_stream_socket.h
@@ -40,12 +40,11 @@
   // the callback is invoked or the socket is closed. Implementations of this
   // method should not modify the contents of the actual buffer that is written
   // to the socket.
-  // TODO(crbug.com/656607): Remove default value.
-  virtual int Write(const scoped_refptr<net::IOBuffer>& buf,
-                    int buf_len,
-                    const net::CompletionCallback& callback,
-                    const net::NetworkTrafficAnnotationTag& traffic_annotation =
-                        NO_TRAFFIC_ANNOTATION_BUG_656607) = 0;
+  virtual int Write(
+      const scoped_refptr<net::IOBuffer>& buf,
+      int buf_len,
+      const net::CompletionCallback& callback,
+      const net::NetworkTrafficAnnotationTag& traffic_annotation) = 0;
 };
 
 }  // namespace protocol
diff --git a/remoting/protocol/pseudotcp_adapter.cc b/remoting/protocol/pseudotcp_adapter.cc
index ff854123..382cc5c4 100644
--- a/remoting/protocol/pseudotcp_adapter.cc
+++ b/remoting/protocol/pseudotcp_adapter.cc
@@ -38,8 +38,10 @@
   // Functions used to implement net::StreamSocket.
   int Read(const scoped_refptr<net::IOBuffer>& buffer, int buffer_size,
            const net::CompletionCallback& callback);
-  int Write(const scoped_refptr<net::IOBuffer>& buffer, int buffer_size,
-            const net::CompletionCallback& callback);
+  int Write(const scoped_refptr<net::IOBuffer>& buffer,
+            int buffer_size,
+            const net::CompletionCallback& callback,
+            const net::NetworkTrafficAnnotationTag& traffic_annotation);
   int Connect(const net::CompletionCallback& callback);
 
   // cricket::IPseudoTcpNotify interface.
@@ -153,14 +155,17 @@
   return result;
 }
 
-int PseudoTcpAdapter::Core::Write(const scoped_refptr<net::IOBuffer>& buffer,
-                                  int buffer_size,
-                                  const net::CompletionCallback& callback) {
+int PseudoTcpAdapter::Core::Write(
+    const scoped_refptr<net::IOBuffer>& buffer,
+    int buffer_size,
+    const net::CompletionCallback& callback,
+    const net::NetworkTrafficAnnotationTag& traffic_annotation) {
   DCHECK(write_callback_.is_null());
 
   // Reference the Core in case a callback deletes the adapter.
   scoped_refptr<Core> core(this);
 
+  // TODO(crbug.com/656607): Handle traffic annotation.
   int result = pseudo_tcp_.Send(buffer->data(), buffer_size);
   if (result < 0) {
     result = net::MapSystemError(pseudo_tcp_.GetError());
@@ -473,8 +478,7 @@
     const net::CompletionCallback& callback,
     const net::NetworkTrafficAnnotationTag& traffic_annotation) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  // TODO(crbug.com/656607): Handle traffic annotation.
-  return core_->Write(buffer, buffer_size, callback);
+  return core_->Write(buffer, buffer_size, callback, traffic_annotation);
 }
 
 int PseudoTcpAdapter::SetReceiveBufferSize(int32_t size) {
diff --git a/remoting/protocol/pseudotcp_adapter.h b/remoting/protocol/pseudotcp_adapter.h
index 3f89b78..68aa499 100644
--- a/remoting/protocol/pseudotcp_adapter.h
+++ b/remoting/protocol/pseudotcp_adapter.h
@@ -36,12 +36,11 @@
   // P2PStreamSocket implementation.
   int Read(const scoped_refptr<net::IOBuffer>& buffer, int buffer_size,
            const net::CompletionCallback& callback) override;
-  // TODO(crbug.com/656607): Remove default value.
-  int Write(const scoped_refptr<net::IOBuffer>& buffer,
-            int buffer_size,
-            const net::CompletionCallback& callback,
-            const net::NetworkTrafficAnnotationTag& traffic_annotation =
-                NO_TRAFFIC_ANNOTATION_BUG_656607) override;
+  int Write(
+      const scoped_refptr<net::IOBuffer>& buffer,
+      int buffer_size,
+      const net::CompletionCallback& callback,
+      const net::NetworkTrafficAnnotationTag& traffic_annotation) override;
 
   int Connect(const net::CompletionCallback& callback);
 
diff --git a/remoting/protocol/pseudotcp_adapter_unittest.cc b/remoting/protocol/pseudotcp_adapter_unittest.cc
index 92da3c2..e64e1c3 100644
--- a/remoting/protocol/pseudotcp_adapter_unittest.cc
+++ b/remoting/protocol/pseudotcp_adapter_unittest.cc
@@ -21,6 +21,7 @@
 #include "net/base/io_buffer.h"
 #include "net/base/net_errors.h"
 #include "net/base/test_completion_callback.h"
+#include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
 #include "remoting/protocol/p2p_datagram_socket.h"
 #include "remoting/protocol/p2p_stream_socket.h"
 #include "testing/gmock/include/gmock/gmock.h"
@@ -221,9 +222,9 @@
       int bytes_to_write = std::min(output_buffer_->BytesRemaining(),
                                     kMessageSize);
       result = client_socket_->Write(
-          output_buffer_.get(),
-          bytes_to_write,
-          base::Bind(&TCPChannelTester::OnWritten, base::Unretained(this)));
+          output_buffer_.get(), bytes_to_write,
+          base::Bind(&TCPChannelTester::OnWritten, base::Unretained(this)),
+          TRAFFIC_ANNOTATION_FOR_TESTS);
       HandleWriteResult(result);
     }
   }
diff --git a/remoting/protocol/ssl_hmac_channel_authenticator.cc b/remoting/protocol/ssl_hmac_channel_authenticator.cc
index ee703db..1ab773e9 100644
--- a/remoting/protocol/ssl_hmac_channel_authenticator.cc
+++ b/remoting/protocol/ssl_hmac_channel_authenticator.cc
@@ -94,12 +94,11 @@
            const net::CompletionCallback& callback) override {
     return socket_->Read(buf, buf_len, callback);
   }
-  // TODO(crbug.com/656607): Remove default value.
-  int Write(net::IOBuffer* buf,
-            int buf_len,
-            const net::CompletionCallback& callback,
-            const net::NetworkTrafficAnnotationTag& traffic_annotation =
-                NO_TRAFFIC_ANNOTATION_BUG_656607) override {
+  int Write(
+      net::IOBuffer* buf,
+      int buf_len,
+      const net::CompletionCallback& callback,
+      const net::NetworkTrafficAnnotationTag& traffic_annotation) override {
     return socket_->Write(buf, buf_len, callback, traffic_annotation);
   }
 
diff --git a/remoting/protocol/ssl_hmac_channel_authenticator_unittest.cc b/remoting/protocol/ssl_hmac_channel_authenticator_unittest.cc
index 31a404e..95b414d 100644
--- a/remoting/protocol/ssl_hmac_channel_authenticator_unittest.cc
+++ b/remoting/protocol/ssl_hmac_channel_authenticator_unittest.cc
@@ -17,6 +17,7 @@
 #include "base/timer/timer.h"
 #include "crypto/rsa_private_key.h"
 #include "net/base/net_errors.h"
+#include "net/cert/x509_util.h"
 #include "net/test/cert_test_util.h"
 #include "net/test/test_data_directory.h"
 #include "remoting/base/rsa_key_pair.h"
@@ -188,12 +189,11 @@
   // Import a second certificate for the client to expect.
   scoped_refptr<net::X509Certificate> host_cert2(
       net::ImportCertFromFile(net::GetTestCertsDirectory(), "ok_cert.pem"));
-  std::string host_cert2_der;
-  ASSERT_TRUE(net::X509Certificate::GetDEREncoded(host_cert2->os_cert_handle(),
-                                                  &host_cert2_der));
 
   client_auth_ = SslHmacChannelAuthenticator::CreateForClient(
-      host_cert2_der, kTestSharedSecret);
+      std::string(
+          net::x509_util::CryptoBufferAsStringPiece(host_cert2->cert_buffer())),
+      kTestSharedSecret);
   host_auth_ = SslHmacChannelAuthenticator::CreateForHost(
       host_cert_, key_pair_, kTestSharedSecret);
 
diff --git a/remoting/protocol/stream_message_pipe_adapter.cc b/remoting/protocol/stream_message_pipe_adapter.cc
index 1b677c8..92879af 100644
--- a/remoting/protocol/stream_message_pipe_adapter.cc
+++ b/remoting/protocol/stream_message_pipe_adapter.cc
@@ -10,6 +10,7 @@
 #include "base/callback_helpers.h"
 #include "base/memory/ptr_util.h"
 #include "net/base/net_errors.h"
+#include "net/traffic_annotation/network_traffic_annotation.h"
 #include "remoting/base/buffered_socket_writer.h"
 #include "remoting/base/compound_buffer.h"
 #include "remoting/protocol/message_serialization.h"
@@ -51,8 +52,10 @@
 
 void StreamMessagePipeAdapter::Send(google::protobuf::MessageLite* message,
                                     const base::Closure& done) {
+  // TODO(crbug.com/656607): Add proper annotation.
   if (writer_)
-    writer_->Write(SerializeAndFrameMessage(*message), done);
+    writer_->Write(SerializeAndFrameMessage(*message), done,
+                   NO_TRAFFIC_ANNOTATION_BUG_656607);
 }
 
 void StreamMessagePipeAdapter::CloseOnError(int error) {
diff --git a/remoting/signaling/xmpp_signal_strategy.cc b/remoting/signaling/xmpp_signal_strategy.cc
index 8ca16f1..0ce36ed 100644
--- a/remoting/signaling/xmpp_signal_strategy.cc
+++ b/remoting/signaling/xmpp_signal_strategy.cc
@@ -27,6 +27,7 @@
 #include "net/socket/client_socket_factory.h"
 #include "net/socket/client_socket_handle.h"
 #include "net/socket/ssl_client_socket.h"
+#include "net/traffic_annotation/network_traffic_annotation.h"
 #include "net/url_request/url_request_context_getter.h"
 #include "remoting/base/buffered_socket_writer.h"
 #include "remoting/base/logging.h"
@@ -275,8 +276,11 @@
   scoped_refptr<net::IOBufferWithSize> buffer =
       new net::IOBufferWithSize(message.size());
   memcpy(buffer->data(), message.data(), message.size());
+
+  // TODO(crbug.com/656607): Add proper annotation.
   writer_->Write(buffer,
-                 base::Bind(&Core::OnMessageSent, base::Unretained(this)));
+                 base::Bind(&Core::OnMessageSent, base::Unretained(this)),
+                 NO_TRAFFIC_ANNOTATION_BUG_656607);
 }
 
 void XmppSignalStrategy::Core::StartTls() {
diff --git a/sandbox/linux/syscall_broker/broker_client.cc b/sandbox/linux/syscall_broker/broker_client.cc
index 82e43d33..39848caa 100644
--- a/sandbox/linux/syscall_broker/broker_client.cc
+++ b/sandbox/linux/syscall_broker/broker_client.cc
@@ -25,9 +25,114 @@
 #endif
 
 namespace sandbox {
-
 namespace syscall_broker {
 
+BrokerClient::BrokerClient(const BrokerPolicy& broker_policy,
+                           BrokerChannel::EndPoint ipc_channel,
+                           const BrokerCommandSet& allowed_command_set,
+                           bool fast_check_in_client,
+                           bool quiet_failures_for_tests)
+    : broker_policy_(broker_policy),
+      ipc_channel_(std::move(ipc_channel)),
+      allowed_command_set_(allowed_command_set),
+      fast_check_in_client_(fast_check_in_client),
+      quiet_failures_for_tests_(quiet_failures_for_tests) {}
+
+BrokerClient::~BrokerClient() {}
+
+int BrokerClient::Access(const char* pathname, int mode) const {
+  return PathAndFlagsSyscall(COMMAND_ACCESS, pathname, mode);
+}
+
+int BrokerClient::Open(const char* pathname, int flags) const {
+  return PathAndFlagsSyscall(COMMAND_OPEN, pathname, flags);
+}
+
+int BrokerClient::Stat(const char* pathname, struct stat* sb) {
+  return StatFamilySyscall(COMMAND_STAT, pathname, sb, sizeof(*sb));
+}
+
+int BrokerClient::Stat64(const char* pathname, struct stat64* sb) {
+  return StatFamilySyscall(COMMAND_STAT64, pathname, sb, sizeof(*sb));
+}
+
+int BrokerClient::Rename(const char* oldpath, const char* newpath) {
+  if (fast_check_in_client_ &&
+      !CommandRenameIsSafe(allowed_command_set_, broker_policy_, oldpath,
+                           newpath, nullptr, nullptr)) {
+    return -broker_policy_.denied_errno();
+  }
+
+  base::Pickle write_pickle;
+  write_pickle.WriteInt(COMMAND_RENAME);
+  write_pickle.WriteString(oldpath);
+  write_pickle.WriteString(newpath);
+  RAW_CHECK(write_pickle.size() <= kMaxMessageLength);
+
+  int returned_fd = -1;
+  uint8_t reply_buf[kMaxMessageLength];
+  ssize_t msg_len = base::UnixDomainSocket::SendRecvMsg(
+      ipc_channel_.get(), reply_buf, sizeof(reply_buf), &returned_fd,
+      write_pickle);
+
+  if (msg_len <= 0) {
+    if (!quiet_failures_for_tests_)
+      RAW_LOG(ERROR, "Could not make request to broker process");
+    return -ENOMEM;
+  }
+
+  base::Pickle read_pickle(reinterpret_cast<char*>(reply_buf), msg_len);
+  base::PickleIterator iter(read_pickle);
+  int return_value = -1;
+  if (!iter.ReadInt(&return_value))
+    return -ENOMEM;
+
+  return return_value;
+}
+
+int BrokerClient::Readlink(const char* path, char* buf, size_t bufsize) {
+  if (fast_check_in_client_ &&
+      !CommandReadlinkIsSafe(allowed_command_set_, broker_policy_, path,
+                             nullptr)) {
+    return -broker_policy_.denied_errno();
+  }
+
+  base::Pickle write_pickle;
+  write_pickle.WriteInt(COMMAND_READLINK);
+  write_pickle.WriteString(path);
+  RAW_CHECK(write_pickle.size() <= kMaxMessageLength);
+
+  int returned_fd = -1;
+  uint8_t reply_buf[kMaxMessageLength];
+  ssize_t msg_len = base::UnixDomainSocket::SendRecvMsg(
+      ipc_channel_.get(), reply_buf, sizeof(reply_buf), &returned_fd,
+      write_pickle);
+
+  if (msg_len <= 0) {
+    if (!quiet_failures_for_tests_)
+      RAW_LOG(ERROR, "Could not make request to broker process");
+    return -ENOMEM;
+  }
+
+  base::Pickle read_pickle(reinterpret_cast<char*>(reply_buf), msg_len);
+  base::PickleIterator iter(read_pickle);
+  int return_value = -1;
+  int return_length = 0;
+  const char* return_data = nullptr;
+  if (!iter.ReadInt(&return_value))
+    return -ENOMEM;
+  if (return_value < 0)
+    return return_value;
+  if (!iter.ReadData(&return_data, &return_length))
+    return -ENOMEM;
+  if (return_length < 0)
+    return -ENOMEM;
+  if (static_cast<size_t>(return_length) > bufsize)
+    return -ENAMETOOLONG;
+  memcpy(buf, return_data, return_length);
+  return return_value;
+}
+
 // Make a remote system call over IPC for syscalls that take a path and flags
 // as arguments, currently open() and access().
 // Will return -errno like a real system call.
@@ -121,41 +226,13 @@
   }
 }
 
-BrokerClient::BrokerClient(const BrokerPolicy& broker_policy,
-                           BrokerChannel::EndPoint ipc_channel,
-                           const BrokerCommandSet& allowed_command_set,
-                           bool fast_check_in_client,
-                           bool quiet_failures_for_tests)
-    : broker_policy_(broker_policy),
-      ipc_channel_(std::move(ipc_channel)),
-      allowed_command_set_(allowed_command_set),
-      fast_check_in_client_(fast_check_in_client),
-      quiet_failures_for_tests_(quiet_failures_for_tests) {}
-
-BrokerClient::~BrokerClient() {}
-
-int BrokerClient::Access(const char* pathname, int mode) const {
-  return PathAndFlagsSyscall(COMMAND_ACCESS, pathname, mode);
-}
-
-int BrokerClient::Open(const char* pathname, int flags) const {
-  return PathAndFlagsSyscall(COMMAND_OPEN, pathname, flags);
-}
-
-int BrokerClient::Stat(const char* pathname, struct stat* sb) {
-  return StatFamilySyscall(COMMAND_STAT, pathname, sb, sizeof(*sb));
-}
-
-int BrokerClient::Stat64(const char* pathname, struct stat64* sb) {
-  return StatFamilySyscall(COMMAND_STAT64, pathname, sb, sizeof(*sb));
-}
-
 int BrokerClient::StatFamilySyscall(BrokerCommand syscall_type,
                                     const char* pathname,
                                     void* result_ptr,
                                     size_t expected_result_size) const {
   if (fast_check_in_client_ &&
-      !broker_policy_.GetFileNameIfAllowedToAccess(pathname, R_OK, nullptr)) {
+      !CommandStatIsSafe(allowed_command_set_, broker_policy_, pathname,
+                         nullptr)) {
     return -broker_policy_.denied_errno();
   }
 
@@ -193,88 +270,5 @@
   return return_value;
 }
 
-int BrokerClient::Rename(const char* oldpath, const char* newpath) {
-  if (fast_check_in_client_) {
-    bool ignore;
-    if (!broker_policy_.GetFileNameIfAllowedToOpen(oldpath, O_RDWR, nullptr,
-                                                   &ignore) ||
-        !broker_policy_.GetFileNameIfAllowedToOpen(newpath, O_RDWR, nullptr,
-                                                   &ignore)) {
-      return -broker_policy_.denied_errno();
-    }
-  }
-
-  base::Pickle write_pickle;
-  write_pickle.WriteInt(COMMAND_RENAME);
-  write_pickle.WriteString(oldpath);
-  write_pickle.WriteString(newpath);
-  RAW_CHECK(write_pickle.size() <= kMaxMessageLength);
-
-  int returned_fd = -1;
-  uint8_t reply_buf[kMaxMessageLength];
-  ssize_t msg_len = base::UnixDomainSocket::SendRecvMsg(
-      ipc_channel_.get(), reply_buf, sizeof(reply_buf), &returned_fd,
-      write_pickle);
-
-  if (msg_len <= 0) {
-    if (!quiet_failures_for_tests_)
-      RAW_LOG(ERROR, "Could not make request to broker process");
-    return -ENOMEM;
-  }
-
-  base::Pickle read_pickle(reinterpret_cast<char*>(reply_buf), msg_len);
-  base::PickleIterator iter(read_pickle);
-  int return_value = -1;
-  if (!iter.ReadInt(&return_value))
-    return -ENOMEM;
-
-  return return_value;
-}
-
-int BrokerClient::Readlink(const char* path, char* buf, size_t bufsize) {
-  if (fast_check_in_client_) {
-    bool ignore;
-    if (!broker_policy_.GetFileNameIfAllowedToOpen(path, O_RDONLY, nullptr,
-                                                   &ignore)) {
-      return -broker_policy_.denied_errno();
-    }
-  }
-
-  base::Pickle write_pickle;
-  write_pickle.WriteInt(COMMAND_READLINK);
-  write_pickle.WriteString(path);
-  RAW_CHECK(write_pickle.size() <= kMaxMessageLength);
-
-  int returned_fd = -1;
-  uint8_t reply_buf[kMaxMessageLength];
-  ssize_t msg_len = base::UnixDomainSocket::SendRecvMsg(
-      ipc_channel_.get(), reply_buf, sizeof(reply_buf), &returned_fd,
-      write_pickle);
-
-  if (msg_len <= 0) {
-    if (!quiet_failures_for_tests_)
-      RAW_LOG(ERROR, "Could not make request to broker process");
-    return -ENOMEM;
-  }
-
-  base::Pickle read_pickle(reinterpret_cast<char*>(reply_buf), msg_len);
-  base::PickleIterator iter(read_pickle);
-  int return_value = -1;
-  int return_length = 0;
-  const char* return_data = nullptr;
-  if (!iter.ReadInt(&return_value))
-    return -ENOMEM;
-  if (return_value < 0)
-    return return_value;
-  if (!iter.ReadData(&return_data, &return_length))
-    return -ENOMEM;
-  if (return_length < 0)
-    return -ENOMEM;
-  if (static_cast<size_t>(return_length) > bufsize)
-    return -ENAMETOOLONG;
-  memcpy(buf, return_data, return_length);
-  return return_value;
-}
-
 }  // namespace syscall_broker
 }  // namespace sandbox
diff --git a/sandbox/linux/syscall_broker/broker_client.h b/sandbox/linux/syscall_broker/broker_client.h
index 0a591ac..c97fc3b 100644
--- a/sandbox/linux/syscall_broker/broker_client.h
+++ b/sandbox/linux/syscall_broker/broker_client.h
@@ -41,37 +41,33 @@
                bool quiet_failures_for_tests);
   ~BrokerClient();
 
+  // Get the file descriptor used for IPC. This is used for tests.
+  int GetIPCDescriptor() const { return ipc_channel_.get(); }
+
+  // The following public methods can be used in place of the equivalently
+  // name system calls. They all return -errno on errors. They are all async
+  // signal safe so they may be called from a SIGSYS trap handler.
+
   // Can be used in place of access().
   // X_OK will always return an error in practice since the broker process
   // doesn't support execute permissions.
-  // It's similar to the access() system call and will return -errno on errors.
-  // This is async signal safe.
   int Access(const char* pathname, int mode) const;
 
   // Can be used in place of open().
   // The implementation only supports certain white listed flags and will
   // return -EPERM on other flags.
-  // It's similar to the open() system call and will return -errno on errors.
-  // This is async signal safe.
   int Open(const char* pathname, int flags) const;
 
   // Can be used in place of stat()/stat64().
-  // It's similar to the stat() system call and will return -errno on errors.
-  // This is async signal safe.
   int Stat(const char* pathname, struct stat* sb);
   int Stat64(const char* pathname, struct stat64* sb);
 
   // Can be used in place of rename().
-  // It's similar to the rename() system call and will return -errno on errors.
-  // This is async signal safe.
   int Rename(const char* oldpath, const char* newpath);
 
   // Can be used in place of Readlink().
   int Readlink(const char* path, char* buf, size_t bufsize);
 
-  // Get the file descriptor used for IPC. This is used for tests.
-  int GetIPCDescriptor() const { return ipc_channel_.get(); }
-
  private:
   int PathAndFlagsSyscall(BrokerCommand syscall_type,
                           const char* pathname,
diff --git a/services/resource_coordinator/memory_instrumentation/queued_request_dispatcher.cc b/services/resource_coordinator/memory_instrumentation/queued_request_dispatcher.cc
index 005a5ca..b198a9ab 100644
--- a/services/resource_coordinator/memory_instrumentation/queued_request_dispatcher.cc
+++ b/services/resource_coordinator/memory_instrumentation/queued_request_dispatcher.cc
@@ -62,6 +62,10 @@
 
   os_dump->resident_set_kb = internal_os_dump.resident_set_kb;
   os_dump->private_footprint_kb = CalculatePrivateFootprintKb(internal_os_dump);
+#if defined(OS_LINUX) || defined(OS_ANDROID)
+  os_dump->private_footprint_swap_kb =
+      internal_os_dump.platform_private_footprint->vm_swap_bytes / 1024;
+#endif
   return os_dump;
 }
 
diff --git a/services/resource_coordinator/public/interfaces/memory_instrumentation/memory_instrumentation.mojom b/services/resource_coordinator/public/interfaces/memory_instrumentation/memory_instrumentation.mojom
index 36fbc83..188b4aa0 100644
--- a/services/resource_coordinator/public/interfaces/memory_instrumentation/memory_instrumentation.mojom
+++ b/services/resource_coordinator/public/interfaces/memory_instrumentation/memory_instrumentation.mojom
@@ -164,6 +164,12 @@
   // Coordinator.GetVmRegionsForHeapProfiler(), empty in the generic case of
   // RequestGlobalMemoryDump().
   array<VmRegion> memory_maps_for_heap_profiler;
+
+  // This is private swapped memory in kilobytes reported on Linux and Android
+  // only.
+  // TODO(crbug.com/676224): add platform restrictions when preprocessing in
+  // mojoms is supported.
+  uint32 private_footprint_swap_kb = 0;
 };
 
 // This struct is used for the public-facing API
diff --git a/services/service_manager/public/cpp/connector.cc b/services/service_manager/public/cpp/connector.cc
index 6f0b1bc7..5bb2cb10 100644
--- a/services/service_manager/public/cpp/connector.cc
+++ b/services/service_manager/public/cpp/connector.cc
@@ -87,12 +87,11 @@
 }
 
 std::unique_ptr<Connector> Connector::Clone() {
-  if (!BindConnectorIfNecessary())
-    return nullptr;
-
-  mojom::ConnectorPtr connector;
-  connector_->Clone(mojo::MakeRequest(&connector));
-  return std::make_unique<Connector>(connector.PassInterface());
+  mojom::ConnectorPtrInfo connector;
+  auto request = mojo::MakeRequest(&connector);
+  if (BindConnectorIfNecessary())
+    connector_->Clone(std::move(request));
+  return std::make_unique<Connector>(std::move(connector));
 }
 
 bool Connector::IsBound() const {
diff --git a/services/service_manager/public/cpp/interface_provider.h b/services/service_manager/public/cpp/interface_provider.h
index 75c3f55..a7e9996e 100644
--- a/services/service_manager/public/cpp/interface_provider.h
+++ b/services/service_manager/public/cpp/interface_provider.h
@@ -76,9 +76,6 @@
   // be called before any calls to GetInterface() are made.
   void Forward(const ForwardCallback& callback);
 
-  // Returns a raw pointer to the remote InterfaceProvider.
-  mojom::InterfaceProvider* get() { return interface_provider_.get(); }
-
   // Sets a closure to be run when the remote InterfaceProvider pipe is closed.
   void SetConnectionLostClosure(const base::Closure& connection_lost_closure);
 
diff --git a/services/service_manager/tests/service_manager/service_manager_unittest.cc b/services/service_manager/tests/service_manager/service_manager_unittest.cc
index 86e5ac2a..1d40c05 100644
--- a/services/service_manager/tests/service_manager/service_manager_unittest.cc
+++ b/services/service_manager/tests/service_manager/service_manager_unittest.cc
@@ -582,4 +582,9 @@
   EXPECT_EQ(1u, instances().size());
 }
 
+TEST_F(ServiceManagerTest, ClonesDisconnectedConnectors) {
+  Connector connector((mojom::ConnectorPtrInfo()));
+  EXPECT_TRUE(connector.Clone());
+}
+
 }  // namespace service_manager
diff --git a/services/video_capture/public/cpp/constants.cc b/services/video_capture/public/cpp/constants.cc
index 37a25ed..42390d7c 100644
--- a/services/video_capture/public/cpp/constants.cc
+++ b/services/video_capture/public/cpp/constants.cc
@@ -4,9 +4,18 @@
 
 #include "services/video_capture/public/cpp/constants.h"
 
+#include "build/build_config.h"
+
 namespace video_capture {
 
-const base::Feature kMojoVideoCapture{"MojoVideoCapture",
-                                      base::FEATURE_DISABLED_BY_DEFAULT};
+const base::Feature kMojoVideoCapture {
+  "MojoVideoCapture",
+#if (defined(OS_LINUX) && !defined(OS_CHROMEOS)) || defined(OS_MACOSX) || \
+    defined(OS_WIN)
+      base::FEATURE_ENABLED_BY_DEFAULT
+#else
+      base::FEATURE_DISABLED_BY_DEFAULT
+#endif
+};
 
 }  // namespace video_capture
diff --git a/services/viz/privileged/interfaces/compositing/display_private.mojom b/services/viz/privileged/interfaces/compositing/display_private.mojom
index 75dbde6..ee8824d23 100644
--- a/services/viz/privileged/interfaces/compositing/display_private.mojom
+++ b/services/viz/privileged/interfaces/compositing/display_private.mojom
@@ -6,12 +6,18 @@
 
 import "mojo/common/time.mojom";
 import "ui/gfx/mojo/color_space.mojom";
+import "ui/gfx/mojo/transform.mojom";
 
 // See ui/compositor/compositor.h: ContextFactoryPrivate.
 // The DisplayPrivate is used by privileged clients to talk to Display.
 // DisplayPrivate would eventually replace or be used by ContextFactoryPrivate.
 interface DisplayPrivate {
   SetDisplayVisible(bool visible);
+
+  // Sets the matrix that will be used to transform the output color of the
+  // display. This only works in GPU compositing.
+  SetDisplayColorMatrix(gfx.mojom.Transform color_matrix);
+
   SetDisplayColorSpace(gfx.mojom.ColorSpace blending_color_space,
                        gfx.mojom.ColorSpace device_color_space);
   SetOutputIsSecure(bool secure);
diff --git a/skia/config/SkUserConfig.h b/skia/config/SkUserConfig.h
index 45a8a32..4f5e57c 100644
--- a/skia/config/SkUserConfig.h
+++ b/skia/config/SkUserConfig.h
@@ -232,6 +232,10 @@
 #define SK_COLOR_SPACE_XFORM_LEGACY_PIPELINE
 #endif
 
+// remove after rebaselining svg layout tests
+#ifndef SK_SUPPORT_LEGACY_SVG_ARC_TO
+#define SK_SUPPORT_LEGACY_SVG_ARC_TO
+#endif
 
 ///////////////////////// Imported from BUILD.gn and skia_common.gypi
 
diff --git a/storage/browser/quota/quota_manager.h b/storage/browser/quota/quota_manager.h
index 8963ab6..1e9d545d 100644
--- a/storage/browser/quota/quota_manager.h
+++ b/storage/browser/quota/quota_manager.h
@@ -105,6 +105,7 @@
 // The quota manager class.  This class is instantiated per profile and
 // held by the profile.  With the exception of the constructor and the
 // proxy() method, all methods should only be called on the IO thread.
+// TODO(sashab): Refactor this class to take a url::Origin, crbug.com/598424.
 class STORAGE_EXPORT QuotaManager
     : public QuotaTaskObserver,
       public QuotaEvictionHandler,
diff --git a/testing/buildbot/chromium.chromiumos.json b/testing/buildbot/chromium.chromiumos.json
index da35887..303a995 100644
--- a/testing/buildbot/chromium.chromiumos.json
+++ b/testing/buildbot/chromium.chromiumos.json
@@ -862,8 +862,7 @@
         "args": [
           "--mus",
           "--ozone-platform=headless",
-          "--override-use-software-gl-for-tests",
-          "--test-launcher-filter-file=../../testing/buildbot/filters/mus.browser_tests.filter"
+          "--override-use-software-gl-for-tests"
         ],
         "name": "mus_browser_tests",
         "swarming": {
diff --git a/testing/buildbot/chromium.fyi.json b/testing/buildbot/chromium.fyi.json
index 0b8aae1b..4bdfc09 100644
--- a/testing/buildbot/chromium.fyi.json
+++ b/testing/buildbot/chromium.fyi.json
@@ -3634,20 +3634,6 @@
         "test": "mojo_common_unittests"
       },
       {
-        "args": [
-          "--test-launcher-filter-file=../../testing/buildbot/filters/fuchsia.mojo_js_unittests.filter"
-        ],
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "kvm": "1"
-            }
-          ]
-        },
-        "test": "mojo_js_unittests"
-      },
-      {
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -3817,20 +3803,6 @@
         "test": "mojo_common_unittests"
       },
       {
-        "args": [
-          "--test-launcher-filter-file=../../testing/buildbot/filters/fuchsia.mojo_js_unittests.filter"
-        ],
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "kvm": "1"
-            }
-          ]
-        },
-        "test": "mojo_js_unittests"
-      },
-      {
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -3954,15 +3926,6 @@
         "test": "mojo_common_unittests"
       },
       {
-        "args": [
-          "--test-launcher-filter-file=../../testing/buildbot/filters/fuchsia.mojo_js_unittests.filter"
-        ],
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
-        "test": "mojo_js_unittests"
-      },
-      {
         "swarming": {
           "can_use_on_swarming_builders": true
         },
@@ -4305,8 +4268,7 @@
       {
         "args": [
           "--mus",
-          "--override-use-software-gl-for-tests",
-          "--test-launcher-filter-file=../../testing/buildbot/filters/mojo.fyi.mus.browser_tests.filter"
+          "--override-use-software-gl-for-tests"
         ],
         "name": "mus_browser_tests",
         "swarming": {
diff --git a/testing/buildbot/chromium.json b/testing/buildbot/chromium.json
index 0953b7f..3763f70 100644
--- a/testing/buildbot/chromium.json
+++ b/testing/buildbot/chromium.json
@@ -1,4 +1,6 @@
 {
+  "AAAAA1 AUTOGENERATED FILE DO NOT EDIT": {},
+  "AAAAA2 See generate_buildbot_json.py to make changes": {},
   "Linux x64": {
     "additional_compile_targets": [
       "all"
diff --git a/testing/buildbot/chromium.linux.json b/testing/buildbot/chromium.linux.json
index 8966e43..d46879d 100644
--- a/testing/buildbot/chromium.linux.json
+++ b/testing/buildbot/chromium.linux.json
@@ -830,12 +830,6 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
-        "test": "mojo_js_unittests"
-      },
-      {
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
         "test": "mojo_public_bindings_unittests"
       },
       {
@@ -1450,12 +1444,6 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
-        "test": "mojo_js_unittests"
-      },
-      {
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
         "test": "mojo_public_bindings_unittests"
       },
       {
diff --git a/testing/buildbot/chromium.sandbox.json b/testing/buildbot/chromium.sandbox.json
index 0205e002..b526542 100644
--- a/testing/buildbot/chromium.sandbox.json
+++ b/testing/buildbot/chromium.sandbox.json
@@ -9,7 +9,6 @@
       "ipc_tests",
       "media_unittests",
       "mojo_common_unittests",
-      "mojo_js_unittests",
       "mojo_public_bindings_unittests",
       "mojo_public_system_unittests",
       "mojo_system_unittests",
@@ -352,12 +351,6 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
-        "test": "mojo_js_unittests"
-      },
-      {
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
         "test": "mojo_public_bindings_unittests"
       },
       {
diff --git a/testing/buildbot/client.v8.chromium.json b/testing/buildbot/client.v8.chromium.json
index 09e30211..fa8ad44c 100644
--- a/testing/buildbot/client.v8.chromium.json
+++ b/testing/buildbot/client.v8.chromium.json
@@ -236,12 +236,6 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
-        "test": "mojo_js_unittests"
-      },
-      {
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
         "test": "nacl_loader_unittests"
       },
       {
diff --git a/testing/buildbot/filters/BUILD.gn b/testing/buildbot/filters/BUILD.gn
index 505d936..28da71d 100644
--- a/testing/buildbot/filters/BUILD.gn
+++ b/testing/buildbot/filters/BUILD.gn
@@ -31,9 +31,7 @@
   data = [
     "//testing/buildbot/filters/mash.browser_tests.filter",
     "//testing/buildbot/filters/mojo.fyi.mash.browser_tests.filter",
-    "//testing/buildbot/filters/mojo.fyi.mus.browser_tests.filter",
     "//testing/buildbot/filters/mojo.fyi.network_browser_tests.filter",
-    "//testing/buildbot/filters/mus.browser_tests.filter",
     "//testing/buildbot/filters/browser_tests_cros_asan.filter",
     "//testing/buildbot/filters/site-per-process.browser_tests.filter",
   ]
@@ -82,7 +80,6 @@
     "//testing/buildbot/filters/fuchsia.base_unittests.filter",
     "//testing/buildbot/filters/fuchsia.content_unittests.filter",
     "//testing/buildbot/filters/fuchsia.ipc_tests.filter",
-    "//testing/buildbot/filters/fuchsia.mojo_js_unittests.filter",
     "//testing/buildbot/filters/fuchsia.mojo_system_unittests.filter",
     "//testing/buildbot/filters/fuchsia.net_unittests.filter",
     "//testing/buildbot/filters/fuchsia.service_manager_unittests.filter",
diff --git a/testing/buildbot/filters/fuchsia.mojo_js_unittests.filter b/testing/buildbot/filters/fuchsia.mojo_js_unittests.filter
deleted file mode 100644
index 57c9ce6..0000000
--- a/testing/buildbot/filters/fuchsia.mojo_js_unittests.filter
+++ /dev/null
@@ -1,3 +0,0 @@
-# TODO(fuchsia): Fix the test and delete this file. crbug.com/740791
-
--JSTest.Core
diff --git a/testing/buildbot/filters/mojo.fyi.mash.browser_tests.filter b/testing/buildbot/filters/mojo.fyi.mash.browser_tests.filter
index ea38a16..43e32c5 100644
--- a/testing/buildbot/filters/mojo.fyi.mash.browser_tests.filter
+++ b/testing/buildbot/filters/mojo.fyi.mash.browser_tests.filter
@@ -268,3 +268,6 @@
 -WebViewTests/WebViewFocusTest.*
 -WebViewTests/WebViewSizeTest.*
 -WebViewTests/WebViewTest.*
+
+# crbug.com/792641 - Disable tests on mash during Wallpaper re-factoring
+-WallPaperPrivateApiTest.*
diff --git a/testing/buildbot/filters/mojo.fyi.mus.browser_tests.filter b/testing/buildbot/filters/mojo.fyi.mus.browser_tests.filter
deleted file mode 100644
index 72684569..0000000
--- a/testing/buildbot/filters/mojo.fyi.mus.browser_tests.filter
+++ /dev/null
@@ -1,28 +0,0 @@
-# TODO: Investigate failure, http://crbug.com/754864.
--CastStreamingApiTestWithPixelOutput.EndToEnd
-
-# TODO: fails because of screen capture. http://crbug.com/754899.
--ChromeScreenshotGrabberBrowserTest.TakeScreenshot
--LoginFeedbackTest.Basic
--TabCaptureApiPixelTest.EndToEndThroughWebRTC
--TabCaptureApiPixelTest.EndToEndWithoutRemoting
--TabCaptureApiPixelTest.OffscreenTabEndToEnd
--TabCaptureApiPixelTest.OffscreenTabEvilTests
-
-# TODO: fix, see http://crbug.com/755303.
--StartupMetricsTest.ReportsValues
-
-# TODO: fix, see http://crbug.com/755318.
--WebViewScrollBubbling/WebViewGuestScrollTouchTest.TestGuestGestureScrollsBubble/0
--WebViewScrollBubbling/WebViewGuestScrollTouchTest.TestGuestGestureScrollsBubble/1
--WebViewScrollBubbling/WebViewGuestScrollTouchTest.TestGuestGestureScrollsBubble/2
--WebViewScrollBubbling/WebViewGuestScrollTouchTest.TestGuestGestureScrollsBubble/3
-
-# TODO: fix, http://crbug.com/755328
--WebViewTests/WebViewFocusTest.TouchFocusesEmbedder/0
--WebViewTests/WebViewTest.InterstitialPageFocusedWidget/1
--WebViewTests/WebViewTest.InterstitialPageRouteEvents/1
-
-# content::WaitForChildFrameSurfaceReady unsupported, https://crbug.com/763452
--PDFExtensionTest.ContextMenuCoordinates
--WebViewTests/WebViewTest.ReloadAfterCrash/1
diff --git a/testing/buildbot/filters/mojo.fyi.network_browser_tests.filter b/testing/buildbot/filters/mojo.fyi.network_browser_tests.filter
index 2006403a..2cbbdb5 100644
--- a/testing/buildbot/filters/mojo.fyi.network_browser_tests.filter
+++ b/testing/buildbot/filters/mojo.fyi.network_browser_tests.filter
@@ -384,11 +384,6 @@
 # Added in r519342.
 -PreviewsNoScriptBrowserTest.NoScriptPreviewsEnabledHttpRedirectToHttps
 
-# crbug.com/756642 Need to add support for URL blacklist.
--PolicyTest.FileURLBlacklist
--PolicyTest.URLBlacklist
--PolicyTest.URLBlacklistSubresources
-
 # crbug.com/751738 Service worker subresource loader doesn't yet support request bodies.
 # crbug.com/778821 Null response body is given to NavigationURLLoaderDelegate::OnResponseStarted() as parameter.
 -WebRtcBrowserTest.RunsAudioVideoWebRTCCallInTwoTabsVP8
@@ -847,6 +842,9 @@
 -ChromeResourceDispatcherHostDelegateBrowserTest.ThrottlesAddedExactlyOnceToTinySniffedDownloads
 -ChromeResourceDispatcherHostDelegateBrowserTest.MirrorRequestHeader
 
+# Failing NoStatePrefetch tests
+# https://crbug.com/792776
+#
 # Depends on the prerender's ResourceThrottle which updates the histogram the
 # test monitors (PrerenderResourceThrottle).
 -NoStatePrefetchBrowserTest/NoStatePrefetchBrowserTest.PrefetchHistograms/0
@@ -854,6 +852,11 @@
 # TODO(jam): switch the tests to hook in via URLLoaderFactory to check load flags.
 -NoStatePrefetchBrowserTest/NoStatePrefetchBrowserTest.IssuesIdlePriorityRequests/0
 -NoStatePrefetchBrowserTest/NoStatePrefetchBrowserTest.IssuesIdlePriorityRequests/1
+# Crashing.
+-NoStatePrefetchBrowserTest/NoStatePrefetchBrowserTest.PrefetchCookie/1
+-NoStatePrefetchBrowserTest/NoStatePrefetchBrowserTest.PrefetchCookie/0
+-NoStatePrefetchBrowserTest/NoStatePrefetchBrowserTest.PrefetchCookieCrossDomain/0
+-NoStatePrefetchBrowserTest/NoStatePrefetchBrowserTest.PrefetchCookieCrossDomain/1
 
 # Add support of download_to_file for URLLoader.
 # http://crbug.com/791702
diff --git a/testing/buildbot/filters/mus.browser_tests.filter b/testing/buildbot/filters/mus.browser_tests.filter
deleted file mode 100644
index 72684569..0000000
--- a/testing/buildbot/filters/mus.browser_tests.filter
+++ /dev/null
@@ -1,28 +0,0 @@
-# TODO: Investigate failure, http://crbug.com/754864.
--CastStreamingApiTestWithPixelOutput.EndToEnd
-
-# TODO: fails because of screen capture. http://crbug.com/754899.
--ChromeScreenshotGrabberBrowserTest.TakeScreenshot
--LoginFeedbackTest.Basic
--TabCaptureApiPixelTest.EndToEndThroughWebRTC
--TabCaptureApiPixelTest.EndToEndWithoutRemoting
--TabCaptureApiPixelTest.OffscreenTabEndToEnd
--TabCaptureApiPixelTest.OffscreenTabEvilTests
-
-# TODO: fix, see http://crbug.com/755303.
--StartupMetricsTest.ReportsValues
-
-# TODO: fix, see http://crbug.com/755318.
--WebViewScrollBubbling/WebViewGuestScrollTouchTest.TestGuestGestureScrollsBubble/0
--WebViewScrollBubbling/WebViewGuestScrollTouchTest.TestGuestGestureScrollsBubble/1
--WebViewScrollBubbling/WebViewGuestScrollTouchTest.TestGuestGestureScrollsBubble/2
--WebViewScrollBubbling/WebViewGuestScrollTouchTest.TestGuestGestureScrollsBubble/3
-
-# TODO: fix, http://crbug.com/755328
--WebViewTests/WebViewFocusTest.TouchFocusesEmbedder/0
--WebViewTests/WebViewTest.InterstitialPageFocusedWidget/1
--WebViewTests/WebViewTest.InterstitialPageRouteEvents/1
-
-# content::WaitForChildFrameSurfaceReady unsupported, https://crbug.com/763452
--PDFExtensionTest.ContextMenuCoordinates
--WebViewTests/WebViewTest.ReloadAfterCrash/1
diff --git a/testing/buildbot/generate_buildbot_json.py b/testing/buildbot/generate_buildbot_json.py
index a802afa..f70b30ad 100755
--- a/testing/buildbot/generate_buildbot_json.py
+++ b/testing/buildbot/generate_buildbot_json.py
@@ -309,7 +309,8 @@
       test = self.dictionary_merge(test, modifications)
     for k in self.get_test_key_removals(test_name, tester_name):
       del test[k]
-    self.clean_swarming_dictionary(test['swarming'])
+    if 'swarming' in test:
+      self.clean_swarming_dictionary(test['swarming'])
     return test
 
   def generate_gtest(self, waterfall, tester_name, tester_config, test_name,
@@ -378,6 +379,7 @@
       'name': test_name,
       'script': test_config['script']
     }
+    result = self.update_and_cleanup_test(result, test_name, tester_name)
     return result
 
   def generate_junit_test(self, waterfall, tester_name, tester_config,
diff --git a/testing/buildbot/generate_buildbot_json_unittest.py b/testing/buildbot/generate_buildbot_json_unittest.py
index 412391ed..077c1f0 100755
--- a/testing/buildbot/generate_buildbot_json_unittest.py
+++ b/testing/buildbot/generate_buildbot_json_unittest.py
@@ -300,6 +300,16 @@
 }
 """
 
+SCRIPT_SUITE = """\
+{
+  'foo_scripts': {
+    'foo_test': {
+      'script': 'foo.py',
+    },
+  },
+}
+"""
+
 UNREFED_TEST_SUITE = """\
 {
   'foo_tests': {},
@@ -326,6 +336,18 @@
 }
 """
 
+SCRIPT_WITH_ARGS_EXCEPTIONS = """\
+{
+  'foo_test': {
+    'modifications': {
+      'Fake Tester': {
+        'args': ['--fake-arg'],
+      },
+    },
+  },
+}
+"""
+
 NO_BAR_TEST_EXCEPTIONS = """\
 {
   'bar_test': {
@@ -532,6 +554,24 @@
 }
 """
 
+SCRIPT_WITH_ARGS_OUTPUT = """\
+{
+  "AAAAA1 AUTOGENERATED FILE DO NOT EDIT": {},
+  "AAAAA2 See generate_buildbot_json.py to make changes": {},
+  "Fake Tester": {
+    "scripts": [
+      {
+        "args": [
+          "--fake-arg"
+        ],
+        "name": "foo_test",
+        "script": "foo.py"
+      }
+    ]
+  }
+}
+"""
+
 JUNIT_OUTPUT = """\
 {
   "AAAAA1 AUTOGENERATED FILE DO NOT EDIT": {},
@@ -758,7 +798,15 @@
     fbb.files['chromium.test.json'] = ISOLATED_SCRIPT_OUTPUT
     fbb.check_output_file_consistency(verbose=True)
 
-  def test_script_tests(self):
+  def test_script_with_args(self):
+    fbb = FakeBBGen(FOO_SCRIPT_WATERFALL,
+                    SCRIPT_SUITE,
+                    SCRIPT_WITH_ARGS_EXCEPTIONS,
+                    )
+    fbb.files['chromium.test.json'] = SCRIPT_WITH_ARGS_OUTPUT
+    fbb.check_output_file_consistency(verbose=True)
+
+  def test_script(self):
     fbb = FakeBBGen(FOO_SCRIPT_WATERFALL,
                     FOO_SCRIPT_SUITE,
                     NO_BAR_TEST_EXCEPTIONS)
@@ -818,6 +866,7 @@
                             'The following nonexistent machines.*',
                             fbb.check_input_file_consistency)
 
+
 if __name__ == '__main__':
   unittest.main()
 
diff --git a/testing/buildbot/gn_isolate_map.pyl b/testing/buildbot/gn_isolate_map.pyl
index 1130fcc..689ae0a 100644
--- a/testing/buildbot/gn_isolate_map.pyl
+++ b/testing/buildbot/gn_isolate_map.pyl
@@ -761,10 +761,6 @@
     "label": "//mojo/common:mojo_common_unittests",
     "type": "console_test_launcher",
   },
-  "mojo_js_unittests": {
-    "label": "//mojo/edk/js/tests:mojo_js_unittests",
-    "type": "console_test_launcher",
-  },
   "mojo_public_bindings_unittests": {
     "label": "//mojo/edk/test:mojo_public_bindings_unittests",
     "type": "console_test_launcher",
diff --git a/testing/buildbot/test_suite_exceptions.pyl b/testing/buildbot/test_suite_exceptions.pyl
index 0ce8bf5..dbef7873 100644
--- a/testing/buildbot/test_suite_exceptions.pyl
+++ b/testing/buildbot/test_suite_exceptions.pyl
@@ -283,6 +283,12 @@
       },
     },
   },
+  'checkbins': {
+    'remove_from': [
+      'Linux x64',
+      'Mac',
+    ],
+  },
   'chrome_public_test_apk': {
     'remove_from': [
       # TODO(kbr): on chromium.android this removal looks like an accident.
@@ -1104,11 +1110,6 @@
       },
     },
   },
-  'mojo_js_unittests': {
-    'remove_from': [
-      'Linux Tests (dbg)(1)(32)',
-    ],
-  },
   'mojo_public_bindings_unittests': {
     'remove_from': [
       # On chromium.android, unclear why these aren't run on all bots.
@@ -1452,6 +1453,24 @@
       'Linux Tests (dbg)(1)(32)',
     ],
   },
+  'sizes': {
+    'remove_from': [
+      'Win',
+      'Win x64',
+    ],
+    'modifications': {
+      'Mac': {
+        'args': [
+          'mac-release/sizes',
+        ],
+      },
+      'Linux x64': {
+        'args': [
+          'linux-release-64/sizes',
+        ],
+      },
+    },
+  },
   'skia_unittests': {
     'remove_from': [
       # On chromium.android, unclear why these aren't run.
diff --git a/testing/buildbot/test_suites.pyl b/testing/buildbot/test_suites.pyl
index e8f692b8..2271dea0 100644
--- a/testing/buildbot/test_suites.pyl
+++ b/testing/buildbot/test_suites.pyl
@@ -390,7 +390,6 @@
     'dbus_unittests': {},
     'filesystem_service_unittests': {},
     'leveldb_service_unittests': {},
-    'mojo_js_unittests': {},
     'site_per_process_browser_tests': {
       'args': [
         '--site-per-process',
@@ -485,6 +484,18 @@
     'ui_touch_selection_unittests': {},
   },
 
+  # TODO(dpranke): These are run on the p/chromium waterfall; they should
+  # probably be run on other builders, and we should get rid of the p/chromium
+  # waterfall.
+  'public_build_scripts': {
+    'checkbins': {
+      'script': 'checkbins.py',
+    },
+    'sizes': {
+      'script': 'sizes.py',
+    },
+  },
+
   'system_webview_shell_instrumentation_tests': {
     'system_webview_shell_layout_test_apk': {},
   },
diff --git a/testing/buildbot/trybot_analyze_config.json b/testing/buildbot/trybot_analyze_config.json
index 859ed2e..8f86c7af2 100644
--- a/testing/buildbot/trybot_analyze_config.json
+++ b/testing/buildbot/trybot_analyze_config.json
@@ -7,6 +7,7 @@
   "base": {
     "exclusions": [
       ".*isolate",
+      ".vpython",
       "build/.*gyp[i]?",
       "build/android/.*py",
       "build/android/devil/.*",
diff --git a/testing/buildbot/waterfalls.pyl b/testing/buildbot/waterfalls.pyl
index 4ddfbd93..27f88d6 100644
--- a/testing/buildbot/waterfalls.pyl
+++ b/testing/buildbot/waterfalls.pyl
@@ -10,6 +10,43 @@
 
 [
   {
+    'name': 'chromium',
+    'machines': {
+      'Linux x64': {
+        'additional_compile_targets': [
+          'all',
+        ],
+        'test_suites': {
+          'scripts': 'public_build_scripts',
+        },
+      },
+      'Mac': {
+        'additional_compile_targets': [
+          'all',
+        ],
+        'test_suites': {
+          'scripts': 'public_build_scripts',
+        },
+      },
+      'Win': {
+        'additional_compile_targets': [
+          'all',
+        ],
+        'test_suites': {
+          'scripts': 'public_build_scripts',
+        },
+      },
+      'Win x64': {
+        'additional_compile_targets': [
+          'all',
+        ],
+        'test_suites': {
+          'scripts': 'public_build_scripts',
+        },
+      },
+    }
+  },
+  {
     'name': 'chromium.android',
     'machines': {
       'Android ASAN (dbg)': {
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json
index 054488d..6c56334 100644
--- a/testing/variations/fieldtrial_testing_config.json
+++ b/testing/variations/fieldtrial_testing_config.json
@@ -927,7 +927,7 @@
                 {
                     "name": "Expected",
                     "params": {
-                        "contextual-search-ranker-model-url": "https://www.gstatic.com/chrome/intelligence/assist/ranker/models/contextual_search/test_ranker_model_20171109_short_words.pb.bin"
+                        "contextual-search-ranker-model-url": "https://www.gstatic.com/chrome/intelligence/assist/ranker/models/contextual_search/test_ranker_model_20171109_short_words_v2.pb.bin"
                     },
                     "enable_features": [
                         "ContextualSearchMlTapSuppression",
diff --git a/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG b/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG
index 4473e14..9389b02b 100644
--- a/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG
+++ b/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG
@@ -1177,9 +1177,8 @@
 crbug.com/591099 css3/filters/simple-filter-rendering.html [ Failure ]
 crbug.com/591099 css3/flexbox/button.html [ Failure ]
 crbug.com/591099 css3/flexbox/child-overflow.html [ Failure ]
-crbug.com/591099 css3/flexbox/flex-flow-auto-margins.html [ Failure ]
 crbug.com/591099 css3/flexbox/flex-flow-border.html [ Failure ]
-crbug.com/591099 css3/flexbox/flex-flow-margins.html [ Failure ]
+crbug.com/591099 css3/flexbox/flex-flow-margins-auto-size.html [ Failure Pass ]
 crbug.com/591099 css3/flexbox/flex-flow-padding.html [ Failure ]
 crbug.com/591099 css3/flexbox/flex-item-contains-strict.html [ Failure ]
 crbug.com/591099 css3/flexbox/flexbox-baseline-margins.html [ Failure ]
@@ -2106,7 +2105,6 @@
 crbug.com/591099 editing/pasteboard/5761530-1.html [ Failure ]
 crbug.com/591099 editing/pasteboard/7955.html [ Failure ]
 crbug.com/591099 editing/pasteboard/bad-placeholder.html [ Failure ]
-crbug.com/591099 editing/pasteboard/copy-backslash-with-euc.html [ Crash Pass ]
 crbug.com/591099 editing/pasteboard/copy-in-password-field.html [ Failure ]
 crbug.com/591099 editing/pasteboard/copy-paste-white-space.html [ Crash ]
 crbug.com/591099 editing/pasteboard/copy-standalone-image.html [ Failure ]
@@ -2164,7 +2162,6 @@
 crbug.com/591099 editing/selection/6476.html [ Failure ]
 crbug.com/591099 editing/selection/caret-and-focus-ring.html [ Failure ]
 crbug.com/591099 editing/selection/caret-at-bidi-boundary.html [ Failure ]
-crbug.com/591099 editing/selection/caret-in-empty-inline-2.html [ Failure Pass ]
 crbug.com/591099 editing/selection/caret-ltr-2-left.html [ Failure ]
 crbug.com/591099 editing/selection/caret-ltr-2.html [ Failure ]
 crbug.com/591099 editing/selection/caret-ltr-right.html [ Failure ]
@@ -2334,7 +2331,6 @@
 crbug.com/591099 external/wpt/WebCryptoAPI/import_export/rsa_importKey.worker.html [ Failure Timeout ]
 crbug.com/709227 external/wpt/WebCryptoAPI/import_export/symmetric_importKey.worker.html [ Failure ]
 crbug.com/591099 external/wpt/XMLHttpRequest/send-authentication-prompt-2-manual.htm [ Failure ]
-crbug.com/591099 external/wpt/css/CSS2/floats-clear/floats-143.xht [ Failure ]
 crbug.com/591099 external/wpt/css/CSS2/floats/floats-wrap-bfc-003-left-table.xht [ Failure Pass ]
 crbug.com/591099 external/wpt/css/CSS2/floats/floats-wrap-bfc-003-right-table.xht [ Failure Pass ]
 crbug.com/591099 external/wpt/css/CSS2/floats/floats-wrap-bfc-004.xht [ Failure ]
@@ -2617,12 +2613,9 @@
 crbug.com/591099 external/wpt/css/geometry/interfaces.worker.html [ Pass Timeout ]
 crbug.com/591099 external/wpt/css/selectors/focus-within-004.html [ Failure ]
 crbug.com/591099 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-align-content-vert-001a.xhtml [ Failure ]
-crbug.com/591099 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-align-self-horiz-002.xhtml [ Failure ]
-crbug.com/591099 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-align-self-horiz-004.xhtml [ Crash ]
 crbug.com/591099 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-align-self-vert-rtl-002.xhtml [ Failure ]
 crbug.com/591099 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-align-self-vert-rtl-004.xhtml [ Failure ]
 crbug.com/591099 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-baseline-multi-item-vert-001b.html [ Failure Pass ]
-crbug.com/591099 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-flex-wrap-horiz-002.html [ Failure ]
 crbug.com/591099 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-min-height-auto-003.html [ Failure ]
 crbug.com/591099 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-min-height-auto-004.html [ Failure ]
 crbug.com/591099 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/variables/variable-declaration-15.html [ Failure Pass ]
@@ -2946,8 +2939,6 @@
 crbug.com/591099 fast/block/float/014.html [ Failure ]
 crbug.com/591099 fast/block/float/018.html [ Failure ]
 crbug.com/591099 fast/block/float/022.html [ Failure ]
-crbug.com/591099 fast/block/float/031.html [ Failure ]
-crbug.com/591099 fast/block/float/035.html [ Failure ]
 crbug.com/591099 fast/block/float/assert-when-moving-float-2.html [ Failure ]
 crbug.com/591099 fast/block/float/assert-when-moving-float.html [ Failure ]
 crbug.com/591099 fast/block/float/block-with-negative-margin-clears-float.html [ Failure ]
@@ -2962,13 +2953,11 @@
 crbug.com/591099 fast/block/float/float-in-float-hit-testing.html [ Failure ]
 crbug.com/591099 fast/block/float/float-in-float-painting.html [ Failure ]
 crbug.com/591099 fast/block/float/float-inserted-into-clean-line.html [ Failure ]
-crbug.com/591099 fast/block/float/float-overflow-hidden-containing-block-width.html [ Failure ]
 crbug.com/591099 fast/block/float/floats-and-text-indent-rl.html [ Failure ]
 crbug.com/591099 fast/block/float/floats-and-text-indent.html [ Failure ]
 crbug.com/591099 fast/block/float/floats-do-not-overhang-from-block-formatting-context.html [ Failure ]
 crbug.com/591099 fast/block/float/floats-offset-image-strict-line-height.html [ Failure ]
 crbug.com/591099 fast/block/float/floats-offset-inline-block-strict-line-height.html [ Failure ]
-crbug.com/591099 fast/block/float/floats-with-margin-should-not-wrap.html [ Failure ]
 crbug.com/591099 fast/block/float/independent-align-positioning.html [ Failure ]
 crbug.com/591099 fast/block/float/logical-bottom-exceeds-layoutunit-max.html [ Failure ]
 crbug.com/591099 fast/block/float/negative-margin-on-element-avoiding-floats-with-margin-on-parent.html [ Failure ]
@@ -3811,7 +3800,6 @@
 crbug.com/591099 fast/events/autoscroll-should-not-stop-on-keypress.html [ Failure ]
 crbug.com/591099 fast/events/autoscroll-upwards-propagation-overflow-hidden-iframe-body.html [ Failure ]
 crbug.com/591099 fast/events/autoscroll-with-non-scrollable-parent.html [ Failure ]
-crbug.com/591099 fast/events/autoscroll.html [ Failure Pass ]
 crbug.com/591099 fast/events/change-frame-focus.html [ Failure ]
 crbug.com/591099 fast/events/check-defocus-event-order-when-triggered-by-mouse-click.html [ Failure ]
 crbug.com/591099 fast/events/check-defocus-event-order-when-triggered-by-tab.html [ Failure ]
@@ -4341,7 +4329,7 @@
 crbug.com/591099 fast/html/draggable-controls.html [ Failure ]
 crbug.com/591099 fast/html/select-dropdown-consistent-background-color.html [ Failure ]
 crbug.com/591099 fast/inline-block/002.html [ Failure ]
-crbug.com/591099 fast/inline-block/baseline-vertical.html [ Failure ]
+crbug.com/591099 fast/inline-block/baseline-vertical.html [ Crash Failure ]
 crbug.com/591099 fast/inline-block/contenteditable-baseline.html [ Failure ]
 crbug.com/591099 fast/inline-block/vertical-align-top-and-bottom-2.html [ Failure ]
 crbug.com/591099 fast/inline/absolute-positioned-inline-in-centred-block.html [ Failure ]
@@ -4463,7 +4451,7 @@
 crbug.com/591099 fast/lists/marker-before-empty-inline.html [ Failure ]
 crbug.com/591099 fast/lists/marker-image-error.html [ Failure ]
 crbug.com/591099 fast/lists/markers-in-selection.html [ Failure ]
-crbug.com/591099 fast/lists/ol-display-types.html [ Failure ]
+crbug.com/591099 fast/lists/ol-display-types.html [ Crash Failure ]
 crbug.com/591099 fast/lists/ordered-list-with-no-ol-tag.html [ Failure ]
 crbug.com/591099 fast/lists/remove-listmarker-and-make-anonblock-empty-2.html [ Failure Pass ]
 crbug.com/591099 fast/lists/scrolled-marker-paint.html [ Failure ]
@@ -4789,7 +4777,6 @@
 crbug.com/591099 fast/multicol/span/padding-before-unbreakable-content-crash.html [ Crash ]
 crbug.com/591099 fast/multicol/span/percent-margins.html [ Failure ]
 crbug.com/591099 fast/multicol/span/preferred-widths-with-column-content.html [ Crash ]
-crbug.com/591099 fast/multicol/span/preferred-widths.html [ Failure ]
 crbug.com/591099 fast/multicol/span/pseudo-after-then-content.html [ Crash ]
 crbug.com/591099 fast/multicol/span/pseudo-after.html [ Crash ]
 crbug.com/591099 fast/multicol/span/pseudo-before-after-in-content.html [ Crash ]
@@ -4962,6 +4949,7 @@
 crbug.com/591099 editing/selection/mouse/double_click_after_last_cell.html [ Failure ]
 crbug.com/591099 editing/selection/mouse/drag_focus_node.html [ Failure ]
 crbug.com/591099 editing/selection/mouse/drags_within_user-select_combos.html [ Failure ]
+crbug.com/591099 editing/selection/selection-linebreaks-rtl-writing-modes.html [ Failure ]
 crbug.com/591099 external/wpt/WebCryptoAPI/generateKey/failures_AES-CBC.https.worker.html [ Pass Timeout ]
 crbug.com/591099 external/wpt/WebCryptoAPI/generateKey/failures_AES-CTR.https.worker.html [ Pass Timeout ]
 crbug.com/591099 external/wpt/WebCryptoAPI/generateKey/failures_AES-GCM.https.worker.html [ Pass Timeout ]
@@ -5058,6 +5046,7 @@
 crbug.com/591099 external/wpt/css/css-multicol/multicol-margin-002.xht [ Failure ]
 crbug.com/591099 external/wpt/css/css-multicol/multicol-nested-002.xht [ Failure ]
 crbug.com/591099 external/wpt/css/css-multicol/multicol-nested-005.xht [ Failure ]
+crbug.com/591099 external/wpt/css/css-multicol/multicol-nested-column-rule-001.xht [ Failure ]
 crbug.com/591099 external/wpt/css/css-multicol/multicol-nested-margin-002.xht [ Failure ]
 crbug.com/591099 external/wpt/css/css-multicol/multicol-nested-margin-003.xht [ Failure ]
 crbug.com/591099 external/wpt/css/css-multicol/multicol-nested-margin-004.xht [ Failure ]
@@ -5077,6 +5066,7 @@
 crbug.com/591099 external/wpt/css/css-multicol/multicol-rule-double-000.xht [ Failure ]
 crbug.com/591099 external/wpt/css/css-multicol/multicol-rule-fraction-001.xht [ Failure ]
 crbug.com/591099 external/wpt/css/css-multicol/multicol-rule-fraction-002.xht [ Failure ]
+crbug.com/591099 external/wpt/css/css-multicol/multicol-rule-fraction-003.xht [ Failure ]
 crbug.com/591099 external/wpt/css/css-multicol/multicol-rule-groove-000.xht [ Failure ]
 crbug.com/591099 external/wpt/css/css-multicol/multicol-rule-hidden-000.xht [ Failure ]
 crbug.com/591099 external/wpt/css/css-multicol/multicol-rule-large-001.xht [ Failure ]
@@ -5110,6 +5100,7 @@
 crbug.com/591099 external/wpt/css/css-multicol/multicol-table-cell-001.xht [ Failure ]
 crbug.com/591099 external/wpt/css/css-multicol/multicol-table-cell-height-001.xht [ Failure ]
 crbug.com/591099 external/wpt/css/css-multicol/multicol-table-cell-height-002.xht [ Failure ]
+crbug.com/591099 external/wpt/css/css-multicol/multicol-table-cell-vertical-align-001.xht [ Failure ]
 crbug.com/591099 external/wpt/css/css-multicol/multicol-width-001.xht [ Failure ]
 crbug.com/591099 external/wpt/css/css-multicol/multicol-width-002.xht [ Failure ]
 crbug.com/591099 external/wpt/css/css-multicol/multicol-width-003.xht [ Failure ]
@@ -5622,7 +5613,7 @@
 crbug.com/591099 fast/shapes/shape-outside-floats/shape-outside-clip-path-selection.html [ Failure ]
 crbug.com/591099 fast/shapes/shape-outside-floats/shape-outside-dynamic-shape-margin.html [ Failure ]
 crbug.com/591099 fast/shapes/shape-outside-floats/shape-outside-dynamic-shape-overhang.html [ Failure ]
-crbug.com/591099 fast/shapes/shape-outside-floats/shape-outside-dynamic-shape.html [ Failure ]
+crbug.com/591099 fast/shapes/shape-outside-floats/shape-outside-dynamic-shape.html [ Crash Failure ]
 crbug.com/591099 fast/shapes/shape-outside-floats/shape-outside-edge-case.html [ Failure ]
 crbug.com/591099 fast/shapes/shape-outside-floats/shape-outside-floats-diamond-margin-polygon.html [ Failure ]
 crbug.com/591099 fast/shapes/shape-outside-floats/shape-outside-floats-different-writing-direction-border-box.html [ Crash Failure ]
@@ -5687,15 +5678,11 @@
 crbug.com/591099 fast/spatial-navigation/snav-hidden-iframe.html [ Failure ]
 crbug.com/591099 fast/spatial-navigation/snav-iframe-with-offscreen-focusable-element.html [ Failure Pass ]
 crbug.com/591099 fast/spatial-navigation/snav-multiple-select-focusring.html [ Failure ]
-crbug.com/591099 fast/sub-pixel/block-preferred-widths-with-sub-pixel-floats.html [ Failure ]
 crbug.com/591099 fast/sub-pixel/computedstylemargin.html [ Failure ]
-crbug.com/591099 fast/sub-pixel/float-list-inside.html [ Failure ]
-crbug.com/591099 fast/sub-pixel/float-with-right-margin-zoom.html [ Failure ]
 crbug.com/591099 fast/sub-pixel/float-wrap-zoom.html [ Failure ]
 crbug.com/591099 fast/sub-pixel/inline-block-with-padding.html [ Failure ]
 crbug.com/591099 fast/sub-pixel/repaint-subpixel-layer-in-subpixel-composited-layer.html [ Failure ]
 crbug.com/591099 fast/sub-pixel/should-not-repaint-subpixel-composited-layer.html [ Failure ]
-crbug.com/591099 fast/sub-pixel/size-of-box-with-zoom.html [ Failure ]
 crbug.com/591099 fast/sub-pixel/sub-pixel-border-2.html [ Failure ]
 crbug.com/591099 fast/sub-pixel/table-cells-with-padding-do-not-wrap.html [ Failure Pass ]
 crbug.com/591099 fast/sub-pixel/table-rtl-padding.html [ Failure Pass ]
@@ -5955,7 +5942,6 @@
 crbug.com/591099 fast/writing-mode/japanese-ruby-vertical-lr.html [ Failure ]
 crbug.com/591099 fast/writing-mode/japanese-ruby-vertical-rl.html [ Failure ]
 crbug.com/591099 fast/writing-mode/logical-height-after-clear.html [ Failure ]
-crbug.com/591099 fast/writing-mode/margins.html [ Failure ]
 crbug.com/591099 fast/writing-mode/orthogonal-writing-modes-available-width-absolute-crash.html [ Failure ]
 crbug.com/591099 fast/writing-mode/orthogonal-writing-modes-in-layoutview-with-floats.html [ Crash ]
 crbug.com/591099 fast/writing-mode/percentage-height-orthogonal-writing-modes-quirks.html [ Failure ]
@@ -6243,8 +6229,6 @@
 crbug.com/591099 http/tests/devtools/console/shadow-element.js [ Crash Timeout ]
 crbug.com/591099 http/tests/devtools/editor/text-editor-ctrl-d-1.js [ Crash Timeout ]
 crbug.com/591099 http/tests/devtools/editor/text-editor-ctrl-d-2.js [ Pass Timeout ]
-crbug.com/591099 http/tests/devtools/elements/edit/edit-dom-actions-1.js [ Crash Pass Timeout ]
-crbug.com/591099 http/tests/devtools/elements/edit/edit-dom-actions-4.js [ Timeout ]
 crbug.com/591099 http/tests/devtools/elements/elements-panel-restore-selection-when-node-comes-later.js [ Failure ]
 crbug.com/591099 http/tests/devtools/elements/event-listener-sidebar-jquery1.js [ Failure ]
 crbug.com/591099 http/tests/devtools/elements/event-listener-sidebar-jquery2.js [ Failure ]
@@ -6255,8 +6239,6 @@
 crbug.com/591099 http/tests/devtools/elements/highlight/highlight-node-scaled.js [ Failure ]
 crbug.com/591099 http/tests/devtools/elements/highlight/highlight-node-scroll.js [ Failure ]
 crbug.com/591099 http/tests/devtools/elements/highlight/highlight-node.js [ Failure ]
-crbug.com/591099 http/tests/devtools/elements/styles-2/add-import-rule.js [ Failure Pass ]
-crbug.com/591099 http/tests/devtools/elements/styles-3/style-rule-from-imported-stylesheet.js [ Failure Pass ]
 crbug.com/591099 http/tests/devtools/elements/styles-3/styles-add-new-rule-tab.js [ Failure Pass ]
 crbug.com/591099 http/tests/devtools/elements/styles-3/styles-add-new-rule.js [ Failure Pass ]
 crbug.com/591099 http/tests/devtools/elements/styles-3/styles-change-node-while-editing.js [ Failure ]
@@ -6270,12 +6252,12 @@
 crbug.com/591099 http/tests/devtools/network/network-datareceived.js [ Failure ]
 crbug.com/591099 http/tests/devtools/network/network-disable-cache-preloads.php [ Failure ]
 crbug.com/591099 http/tests/devtools/persistence/automapping-sourcemap-nameclash.js [ Failure ]
-crbug.com/591099 http/tests/devtools/persistence/persistence-tabbed-editor-opens-filesystem-uisourcecode.js [ Failure ]
+crbug.com/591099 http/tests/devtools/persistence/persistence-tabbed-editor-opens-filesystem-uisourcecode.js [ Failure Timeout ]
 crbug.com/591099 http/tests/devtools/runtime/runtime-getProperties.js [ Failure ]
-crbug.com/591099 http/tests/devtools/sources/debugger-async/async-await/async-pause-on-exception.js [ Failure ]
+crbug.com/591099 http/tests/devtools/sources/debugger-async/async-await/async-pause-on-exception.js [ Failure Pass ]
 crbug.com/591099 http/tests/devtools/sources/debugger-pause/debugger-pause-in-internal.js [ Failure ]
-crbug.com/591099 http/tests/devtools/sources/debugger-pause/debugger-pause-on-exception.js [ Failure ]
-crbug.com/591099 http/tests/devtools/sources/debugger-pause/debugger-pause-on-promise-rejection.js [ Failure ]
+crbug.com/591099 http/tests/devtools/sources/debugger-pause/debugger-pause-on-exception.js [ Failure Pass ]
+crbug.com/591099 http/tests/devtools/sources/debugger-pause/debugger-pause-on-promise-rejection.js [ Failure Pass ]
 crbug.com/591099 http/tests/devtools/sources/debugger-ui/function-generator-details.js [ Failure ]
 crbug.com/591099 http/tests/devtools/sources/debugger/live-edit-no-reveal.js [ Failure Pass ]
 crbug.com/591099 http/tests/devtools/sources/debugger/properties-special.js [ Failure ]
@@ -7346,7 +7328,7 @@
 crbug.com/591099 payments/payment-request-in-iframe.html [ Failure ]
 crbug.com/591099 plugins/change-widget-and-click-crash.html [ Failure ]
 crbug.com/591099 plugins/embed-attributes-style.html [ Failure ]
-crbug.com/591099 plugins/focus.html [ Failure ]
+crbug.com/591099 plugins/focus.html [ Failure Timeout ]
 crbug.com/591099 plugins/iframe-plugin-bgcolor.html [ Failure ]
 crbug.com/591099 plugins/keyboard-events.html [ Failure ]
 crbug.com/591099 plugins/mouse-capture-inside-shadow.html [ Timeout ]
@@ -8088,7 +8070,6 @@
 crbug.com/591099 virtual/mouseevent_fractional/fast/events/autoscroll-should-not-stop-on-keypress.html [ Failure ]
 crbug.com/591099 virtual/mouseevent_fractional/fast/events/autoscroll-upwards-propagation-overflow-hidden-iframe-body.html [ Failure ]
 crbug.com/591099 virtual/mouseevent_fractional/fast/events/autoscroll-with-non-scrollable-parent.html [ Failure ]
-crbug.com/591099 virtual/mouseevent_fractional/fast/events/autoscroll.html [ Failure Pass ]
 crbug.com/591099 virtual/mouseevent_fractional/fast/events/change-frame-focus.html [ Failure ]
 crbug.com/591099 virtual/mouseevent_fractional/fast/events/check-defocus-event-order-when-triggered-by-mouse-click.html [ Failure ]
 crbug.com/591099 virtual/mouseevent_fractional/fast/events/check-defocus-event-order-when-triggered-by-tab.html [ Failure ]
@@ -8140,7 +8121,6 @@
 crbug.com/591099 virtual/mouseevent_fractional/fast/events/mousemove-to-resizer-changes-cursor.html [ Failure ]
 crbug.com/591099 virtual/mouseevent_fractional/fast/events/mouseover-mouseout.html [ Failure ]
 crbug.com/591099 virtual/mouseevent_fractional/fast/events/no-blur-on-enter-button.html [ Failure ]
-crbug.com/591099 virtual/mouseevent_fractional/fast/events/offsetX-offsetY.html [ Failure Pass ]
 crbug.com/591099 virtual/mouseevent_fractional/fast/events/onblur-remove.html [ Failure ]
 crbug.com/591099 virtual/mouseevent_fractional/fast/events/onchange-range-slider.html [ Crash ]
 crbug.com/591099 virtual/mouseevent_fractional/fast/events/onclick-list-marker.html [ Failure ]
@@ -9039,7 +9019,7 @@
 crbug.com/591099 virtual/spv175/paint/invalidation/svg/relative-sized-deep-shadow-tree-content.xhtml [ Failure ]
 crbug.com/591099 virtual/spv175/paint/invalidation/svg/relative-sized-image.xhtml [ Failure ]
 crbug.com/591099 virtual/spv175/paint/invalidation/svg/relative-sized-inner-svg.xhtml [ Crash Failure ]
-crbug.com/591099 virtual/spv175/paint/invalidation/svg/relative-sized-shadow-tree-content-with-symbol.xhtml [ Failure ]
+crbug.com/591099 virtual/spv175/paint/invalidation/svg/relative-sized-shadow-tree-content-with-symbol.xhtml [ Crash Failure ]
 crbug.com/591099 virtual/spv175/paint/invalidation/svg/relative-sized-shadow-tree-content.xhtml [ Failure ]
 crbug.com/591099 virtual/spv175/paint/invalidation/svg/relative-sized-use-on-symbol.xhtml [ Crash Failure ]
 crbug.com/591099 virtual/spv175/paint/invalidation/svg/relative-sized-use-without-attributes-on-symbol.xhtml [ Failure ]
diff --git a/third_party/WebKit/LayoutTests/FlagExpectations/enable-features=NetworkService b/third_party/WebKit/LayoutTests/FlagExpectations/enable-features=NetworkService
index f86439b..ebcc5853 100644
--- a/third_party/WebKit/LayoutTests/FlagExpectations/enable-features=NetworkService
+++ b/third_party/WebKit/LayoutTests/FlagExpectations/enable-features=NetworkService
@@ -232,3 +232,9 @@
 
 # Started flaking after test was rewritten in r517585.
 Bug(none) http/tests/devtools/service-workers/service-worker-agents.js [ Crash Pass ]
+
+crbug.com/777879 external/wpt/FileAPI/file/send-file-form-iso-2022-jp.tentative.html [ Crash ]
+crbug.com/777879 external/wpt/FileAPI/file/send-file-form-utf-8.html [ Crash ]
+crbug.com/777879 external/wpt/FileAPI/file/send-file-form-windows-1252.tentative.html [ Crash ]
+crbug.com/777879 external/wpt/FileAPI/file/send-file-form-x-user-defined.tentative.html [ Crash ]
+crbug.com/777879 external/wpt/FileAPI/file/send-file-form.html [ Crash ]
diff --git a/third_party/WebKit/LayoutTests/NeverFixTests b/third_party/WebKit/LayoutTests/NeverFixTests
index 900503f..2b19953 100644
--- a/third_party/WebKit/LayoutTests/NeverFixTests
+++ b/third_party/WebKit/LayoutTests/NeverFixTests
@@ -1835,7 +1835,3 @@
 # in testing, whereas otherwise we do not do so if the composited layer has a
 # direct compositing reason (for performance). Only applies to SPv1.
 paint/invalidation/compositing/subpixel-offset-scaled-transform-composited.html [ WontFix ]
-
-# These tests should always fail because the modern media controls are not yet enabled
-crbug.com/761305 media/controls/modern/ [ WontFix ]
-crbug.com/761306 virtual/new-remote-playback-pipeline/media/controls/modern/ [ WontFix ]
diff --git a/third_party/WebKit/LayoutTests/TestExpectations b/third_party/WebKit/LayoutTests/TestExpectations
index bf6595b..74d30c5 100644
--- a/third_party/WebKit/LayoutTests/TestExpectations
+++ b/third_party/WebKit/LayoutTests/TestExpectations
@@ -388,7 +388,6 @@
 crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/floats-clear/floats-130.xht [ Skip ]
 crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/floats-clear/floats-131.xht [ Skip ]
 crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/floats-clear/floats-137.xht [ Skip ]
-crbug.com/635619 virtual/layout_ng/external/wpt/css/CSS2/floats-clear/floats-143.xht [ Failure ]
 
 ### virtual/layout_ng/external/wpt/css/CSS2/linebox
 
@@ -506,8 +505,6 @@
 crbug.com/635619 virtual/layout_ng/fast/block/float/018.html [ Failure ]
 crbug.com/635619 [ Mac ] virtual/layout_ng/fast/block/float/020.html [ Failure ]
 crbug.com/635619 virtual/layout_ng/fast/block/float/022.html [ Failure ]
-crbug.com/635619 virtual/layout_ng/fast/block/float/031.html [ Failure ]
-crbug.com/635619 virtual/layout_ng/fast/block/float/035.html [ Failure ]
 crbug.com/635619 virtual/layout_ng/fast/block/float/assert-when-moving-float.html [ Failure ]
 crbug.com/635619 virtual/layout_ng/fast/block/float/assert-when-moving-float-2.html [ Failure ]
 crbug.com/635619 virtual/layout_ng/fast/block/float/block-with-negative-margin-clears-float.html [ Failure ]
@@ -526,7 +523,6 @@
 crbug.com/635619 virtual/layout_ng/fast/block/float/float-list-changed-before-layout-crash.html [ Crash Pass ]
 crbug.com/635619 virtual/layout_ng/fast/block/float/float-not-removed-from-next-sibling4.html [ Crash Pass ]
 crbug.com/635619 virtual/layout_ng/fast/block/float/float-on-line-obeys-container-padding.html [ Failure ]
-crbug.com/635619 virtual/layout_ng/fast/block/float/float-overflow-hidden-containing-block-width.html [ Failure ]
 crbug.com/635619 virtual/layout_ng/fast/block/float/float-reparent-during-detach-crash.html [ Crash Pass ]
 crbug.com/635619 virtual/layout_ng/fast/block/float/floats-and-text-indent-rl.html [ Failure ]
 crbug.com/635619 virtual/layout_ng/fast/block/float/floats-and-text-indent.html [ Failure ]
@@ -534,7 +530,6 @@
 crbug.com/635619 virtual/layout_ng/fast/block/float/floats-offset-image-strict-line-height.html [ Failure ]
 crbug.com/635619 virtual/layout_ng/fast/block/float/floats-offset-inline-block-strict-line-height.html [ Failure ]
 
-crbug.com/635619 virtual/layout_ng/fast/block/float/floats-with-margin-should-not-wrap.html [ Failure ]
 crbug.com/635619 virtual/layout_ng/fast/block/float/independent-align-positioning.html [ Failure ]
 crbug.com/635619 [ Win10 ] virtual/layout_ng/fast/block/float/intruding-float-add-in-sibling-block-on-static-position.html [ Failure ]
 crbug.com/635619 [ Win10 ]  virtual/layout_ng/fast/block/float/intruding-float-add-in-sibling-block-on-static-position2.html [ Failure ]
@@ -1976,6 +1971,7 @@
 crbug.com/751952 virtual/origin-trials-runtimeflags-disabled/http/tests/origin_trials/webexposed/budget-api-origin-trial-interfaces.html [ Pass Failure ]
 
 # ====== New tests from wpt-importer added here ======
+crbug.com/626703 [ Mac10.12 ] external/wpt/longtask-timing/longtask-in-sibling-iframe.html [ Timeout ]
 crbug.com/626703 external/wpt/html/rendering/non-replaced-elements/the-page/body-margin-1i.html [ Failure ]
 crbug.com/626703 external/wpt/html/rendering/non-replaced-elements/the-page/body-margin-1j.html [ Failure ]
 crbug.com/626703 external/wpt/html/rendering/non-replaced-elements/the-page/body-margin-1k.html [ Failure ]
@@ -2421,7 +2417,6 @@
 crbug.com/788337 external/wpt/css/css-multicol/multicol-span-all-child-002.xht [ Failure ]
 crbug.com/788337 external/wpt/css/css-multicol/multicol-span-all-margin-nested-002.xht [ Failure ]
 crbug.com/788337 external/wpt/css/css-multicol/multicol-span-float-001.xht [ Failure ]
-crbug.com/788337 external/wpt/css/css-multicol/multicol-table-cell-vertical-align-001.xht [ Failure ]
 crbug.com/788337 external/wpt/css/css-multicol/multicol-width-ems-001.xht [ Failure ]
 crbug.com/788337 external/wpt/css/css-multicol/multicol-width-small-001.xht [ Failure ]
 crbug.com/788337 external/wpt/css/css-multicol/multicol-zero-height-001.xht [ Failure ]
@@ -3631,14 +3626,3 @@
 crbug.com/788390 [ Linux ] http/tests/media/autoplay/document-user-activation-feature-policy-iframe-no-gesture.html [ Failure Pass Timeout ]
 crbug.com/788390 [ Linux ] http/tests/media/autoplay/document-user-activation-feature-policy-same-origin.html [ Failure Pass Timeout ]
 crbug.com/788390 [ Linux ] http/tests/media/autoplay/document-user-activation-iframe-delegation.html [ Failure Pass Timeout ]
-
-# Double tap on modern media controls is a bit more complicated on Mac but
-# since we are not targeting Mac yet we can come back and fix this later.
-crbug.com/783154 [ Mac ] virtual/modern-media-controls/media/controls/modern/doubletap-to-jump-backwards.html [ Skip ]
-crbug.com/783154 [ Mac ] virtual/modern-media-controls/media/controls/modern/doubletap-to-jump-forwards.html [ Skip ]
-crbug.com/783154 virtual/modern-media-controls/media/controls/modern/doubletap-to-jump-forwards-too-short.html [ Skip ]
-crbug.com/783154 [ Mac ] virtual/modern-media-controls/media/controls/modern/doubletap-on-play-button.html [ Skip ]
-crbug.com/783154 [ Mac ] virtual/modern-media-controls/media/controls/modern/doubletap-to-toggle-fullscreen.html [ Skip ]
-crbug.com/783154 [ Mac ] virtual/modern-media-controls/media/controls/modern/singletap-on-outside.html [ Skip ]
-crbug.com/783154 [ Mac ] virtual/modern-media-controls/media/controls/modern/singletap-on-play-button.html [ Skip ]
-crbug.com/783154 [ Mac ] virtual/modern-media-controls/media/controls/modern/slow-doubletap.html [ Skip ]
diff --git a/third_party/WebKit/LayoutTests/VirtualTestSuites b/third_party/WebKit/LayoutTests/VirtualTestSuites
index f905f50d..ffa8aef5 100644
--- a/third_party/WebKit/LayoutTests/VirtualTestSuites
+++ b/third_party/WebKit/LayoutTests/VirtualTestSuites
@@ -596,10 +596,5 @@
     "prefix": "incremental-shadow-dom",
     "base": "shadow-dom",
     "args": ["--enable-blink-features=IncrementalShadowDOM"]
-  },
-  {
-    "prefix": "modern-media-controls",
-    "base": "media/controls/modern",
-    "args": ["--enable-features=UseModernMediaControls"]
   }
 ]
diff --git a/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST.json b/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST.json
index c5920cfc..ed4aeea 100644
--- a/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST.json
+++ b/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST.json
@@ -43385,54 +43385,6 @@
      {}
     ]
    ],
-   "css/css-multicol/multicol-rule-style-groove-001.xht": [
-    [
-     "/css/css-multicol/multicol-rule-style-groove-001.xht",
-     [
-      [
-       "/css/css-multicol/multicol-rule-style-groove-001-ref.xht",
-       "=="
-      ]
-     ],
-     {}
-    ]
-   ],
-   "css/css-multicol/multicol-rule-style-inset-001.xht": [
-    [
-     "/css/css-multicol/multicol-rule-style-inset-001.xht",
-     [
-      [
-       "/css/css-multicol/multicol-rule-style-ridge-001-ref.xht",
-       "=="
-      ]
-     ],
-     {}
-    ]
-   ],
-   "css/css-multicol/multicol-rule-style-outset-001.xht": [
-    [
-     "/css/css-multicol/multicol-rule-style-outset-001.xht",
-     [
-      [
-       "/css/css-multicol/multicol-rule-style-groove-001-ref.xht",
-       "=="
-      ]
-     ],
-     {}
-    ]
-   ],
-   "css/css-multicol/multicol-rule-style-ridge-001.xht": [
-    [
-     "/css/css-multicol/multicol-rule-style-ridge-001.xht",
-     [
-      [
-       "/css/css-multicol/multicol-rule-style-ridge-001-ref.xht",
-       "=="
-      ]
-     ],
-     {}
-    ]
-   ],
    "css/css-multicol/multicol-shorthand-001.xht": [
     [
      "/css/css-multicol/multicol-shorthand-001.xht",
@@ -43589,18 +43541,6 @@
      {}
     ]
    ],
-   "css/css-multicol/multicol-span-all-margin-nested-003.xht": [
-    [
-     "/css/css-multicol/multicol-span-all-margin-nested-003.xht",
-     [
-      [
-       "/css/css-multicol/multicol-span-all-margin-nested-3-ref.xht",
-       "=="
-      ]
-     ],
-     {}
-    ]
-   ],
    "css/css-multicol/multicol-span-all-margin-nested-firstchild-001.xht": [
     [
      "/css/css-multicol/multicol-span-all-margin-nested-firstchild-001.xht",
@@ -90267,6 +90207,11 @@
      {}
     ]
    ],
+   "FileAPI/support/send-file-form-helper.js": [
+    [
+     {}
+    ]
+   ],
    "FileAPI/support/upload.txt": [
     [
      {}
@@ -109322,16 +109267,6 @@
      {}
     ]
    ],
-   "css/css-multicol/multicol-rule-style-groove-001-ref.xht": [
-    [
-     {}
-    ]
-   ],
-   "css/css-multicol/multicol-rule-style-ridge-001-ref.xht": [
-    [
-     {}
-    ]
-   ],
    "css/css-multicol/multicol-span-000-ref.xht": [
     [
      {}
@@ -109382,11 +109317,6 @@
      {}
     ]
    ],
-   "css/css-multicol/multicol-span-all-margin-nested-3-ref.xht": [
-    [
-     {}
-    ]
-   ],
    "css/css-multicol/multicol-span-all-margin-nested-firstchild-ref.xht": [
     [
      {}
@@ -125782,16 +125712,6 @@
      {}
     ]
    ],
-   "fetch/api/cors/cors-expose-star-expected.txt": [
-    [
-     {}
-    ]
-   ],
-   "fetch/api/cors/cors-expose-star-worker-expected.txt": [
-    [
-     {}
-    ]
-   ],
    "fetch/api/cors/cors-expose-star.js": [
     [
      {}
@@ -145382,6 +145302,11 @@
      {}
     ]
    ],
+   "service-workers/service-worker/resources/fetch-cors-exposed-header-names-worker.js": [
+    [
+     {}
+    ]
+   ],
    "service-workers/service-worker/resources/fetch-cors-xhr-iframe.html": [
     [
      {}
@@ -156800,6 +156725,36 @@
      {}
     ]
    ],
+   "FileAPI/file/send-file-form-iso-2022-jp.tentative.html": [
+    [
+     "/FileAPI/file/send-file-form-iso-2022-jp.tentative.html",
+     {}
+    ]
+   ],
+   "FileAPI/file/send-file-form-utf-8.html": [
+    [
+     "/FileAPI/file/send-file-form-utf-8.html",
+     {}
+    ]
+   ],
+   "FileAPI/file/send-file-form-windows-1252.tentative.html": [
+    [
+     "/FileAPI/file/send-file-form-windows-1252.tentative.html",
+     {}
+    ]
+   ],
+   "FileAPI/file/send-file-form-x-user-defined.tentative.html": [
+    [
+     "/FileAPI/file/send-file-form-x-user-defined.tentative.html",
+     {}
+    ]
+   ],
+   "FileAPI/file/send-file-form.html": [
+    [
+     "/FileAPI/file/send-file-form.html",
+     {}
+    ]
+   ],
    "FileAPI/fileReader.html": [
     [
      "/FileAPI/fileReader.html",
@@ -208640,6 +208595,12 @@
      {}
     ]
    ],
+   "service-workers/service-worker/fetch-cors-exposed-header-names.https.html": [
+    [
+     "/service-workers/service-worker/fetch-cors-exposed-header-names.https.html",
+     {}
+    ]
+   ],
    "service-workers/service-worker/fetch-cors-xhr.https.html": [
     [
      "/service-workers/service-worker/fetch-cors-xhr.https.html",
@@ -227579,6 +227540,26 @@
    "187acfc89c6123286cd759aac390c7de3b25c5a1",
    "testharness"
   ],
+  "FileAPI/file/send-file-form-iso-2022-jp.tentative.html": [
+   "89f7e08e63145e07f06a5c45f6ba5e4835a75ece",
+   "testharness"
+  ],
+  "FileAPI/file/send-file-form-utf-8.html": [
+   "f2cfbcc800aacd8a98ee496db7d123a35d2a1b2c",
+   "testharness"
+  ],
+  "FileAPI/file/send-file-form-windows-1252.tentative.html": [
+   "43b967a2543c07ed8349db572eb10fc589b202fc",
+   "testharness"
+  ],
+  "FileAPI/file/send-file-form-x-user-defined.tentative.html": [
+   "f07b9491bf42650379f187c36c8c306f88928120",
+   "testharness"
+  ],
+  "FileAPI/file/send-file-form.html": [
+   "3bc42189304cd2ae051cfb015d8209176c699f0b",
+   "testharness"
+  ],
   "FileAPI/fileReader.html": [
    "fdfa73b1182058d10c1eb1b447885ecdce77fa6a",
    "testharness"
@@ -227671,6 +227652,10 @@
    "36ccc5cb2de09589d02430b1c0582280d3240f32",
    "support"
   ],
+  "FileAPI/support/send-file-form-helper.js": [
+   "f9bf42d1296f4fc6410b3bf77f3e29530bc58ad8",
+   "support"
+  ],
   "FileAPI/support/upload.txt": [
    "f7ff9e8b7bb2e09b70935a5d785e0cc5d9d0abf0",
    "support"
@@ -231216,7 +231201,7 @@
    "testharness"
   ],
   "XMLHttpRequest/send-network-error-sync-events.sub.htm": [
-   "c455c57e952ca5d44843b42840becd2c56f11213",
+   "8dd189e5d654c1fc46808dbd860ed0b055851227",
    "testharness"
   ],
   "XMLHttpRequest/send-no-response-event-loadend.htm": [
@@ -265932,7 +265917,7 @@
    "reftest"
   ],
   "css/css-multicol/multicol-rule-fraction-3-ref.xht": [
-   "95c5bb1a096aa9e2508561849528200c6e794783",
+   "840335fafb6bbf23f2cff696145c5e4f093a077f",
    "support"
   ],
   "css/css-multicol/multicol-rule-groove-000-ref.xht": [
@@ -266031,30 +266016,6 @@
    "b16e79ec96569a463be9b47b2f8f7f214f8500f7",
    "support"
   ],
-  "css/css-multicol/multicol-rule-style-groove-001-ref.xht": [
-   "2529f1c9842f1bc415221dddc350b5f96a84c25a",
-   "support"
-  ],
-  "css/css-multicol/multicol-rule-style-groove-001.xht": [
-   "e6e56b0328c105ff123c33d3d552f00922e490d2",
-   "reftest"
-  ],
-  "css/css-multicol/multicol-rule-style-inset-001.xht": [
-   "40dba383e061009d8a63a3b239534a51f777d86d",
-   "reftest"
-  ],
-  "css/css-multicol/multicol-rule-style-outset-001.xht": [
-   "c2a1d8fef6176e0d87198a8784bb9ea7e3eef94a",
-   "reftest"
-  ],
-  "css/css-multicol/multicol-rule-style-ridge-001-ref.xht": [
-   "f09150d0eb9cca3c1479d7e240624e7913fb0a18",
-   "support"
-  ],
-  "css/css-multicol/multicol-rule-style-ridge-001.xht": [
-   "b75870bee5f5ec6f4669f9de58ea95393c686752",
-   "reftest"
-  ],
   "css/css-multicol/multicol-shorthand-001.xht": [
    "2be00be60652208da1a87c2175b02f1fbda381c9",
    "reftest"
@@ -266084,7 +266045,7 @@
    "reftest"
   ],
   "css/css-multicol/multicol-span-all-003.xht": [
-   "79ab6a7b47537d3dadcd0aa707ad045563d03165",
+   "c88e3393a8c0a214ed11e85736d35b5a383a03ac",
    "reftest"
   ],
   "css/css-multicol/multicol-span-all-block-sibling-003.xht": [
@@ -266147,14 +266108,6 @@
    "8bdc105a0b441556da0b287dd5d6b98a3fedc7ad",
    "reftest"
   ],
-  "css/css-multicol/multicol-span-all-margin-nested-003.xht": [
-   "a8f61138dc6e68e7910a29e4eaeac6f2d20adae4",
-   "reftest"
-  ],
-  "css/css-multicol/multicol-span-all-margin-nested-3-ref.xht": [
-   "d18c55ffc3c4a490ebe37c2c5fdf8e22e8710800",
-   "support"
-  ],
   "css/css-multicol/multicol-span-all-margin-nested-firstchild-001.xht": [
    "d912a7254753afebe5ade2f58af29484d2fd8d51",
    "reftest"
@@ -266200,11 +266153,11 @@
    "reftest"
   ],
   "css/css-multicol/multicol-table-cell-vertical-align-001.xht": [
-   "c60f477324d7ca5b73f19b637c965c20cc6764b4",
+   "b6323036968dbf0584f94e116bb019347c0d6a42",
    "reftest"
   ],
   "css/css-multicol/multicol-table-cell-vertical-align-ref.xht": [
-   "6376bfbeb38858740053cdc384a5a8d2d49d0c7e",
+   "7515baa6b82894146207efaae85aaf832ff41a36",
    "support"
   ],
   "css/css-multicol/multicol-width-001-ref.xht": [
@@ -298771,14 +298724,6 @@
    "246a6e661ef1179330f9109131cfcb2fa9f5bf64",
    "testharness"
   ],
-  "fetch/api/cors/cors-expose-star-expected.txt": [
-   "4f7b7f72a370de56e276aa349bf677990ed7622e",
-   "support"
-  ],
-  "fetch/api/cors/cors-expose-star-worker-expected.txt": [
-   "4f7b7f72a370de56e276aa349bf677990ed7622e",
-   "support"
-  ],
   "fetch/api/cors/cors-expose-star-worker.html": [
    "fff53964064bd5f0a7f216b940dda7b01854105c",
    "testharness"
@@ -298788,7 +298733,7 @@
    "testharness"
   ],
   "fetch/api/cors/cors-expose-star.js": [
-   "2403a7d229377d03230f32383e71960e32a84271",
+   "338dc1bf4cfe3b61209b5ffd362ecc3175890c1b",
    "support"
   ],
   "fetch/api/cors/cors-filtering-worker.html": [
@@ -337712,7 +337657,7 @@
    "support"
   ],
   "service-workers/cache-storage/script-tests/cache-match.js": [
-   "0204ef8205dd31a9af01b3dacd0f2608fa6eb35d",
+   "2e56e6185845e752fb828e20e2f1e10143c95073",
    "support"
   ],
   "service-workers/cache-storage/script-tests/cache-matchAll.js": [
@@ -337804,7 +337749,7 @@
    "testharness"
   ],
   "service-workers/cache-storage/window/cache-match.https.html": [
-   "511502a763c53d3fd642aca9e1e1c0c4b610f8ce",
+   "43346c7dbd6592a33c35146d7ea6fa4495f9a353",
    "testharness"
   ],
   "service-workers/cache-storage/window/cache-matchAll.https-expected.txt": [
@@ -338135,6 +338080,10 @@
    "9c2e160f95d2915a961bd7da840ac53779c9387d",
    "testharness"
   ],
+  "service-workers/service-worker/fetch-cors-exposed-header-names.https.html": [
+   "2013c1862eb3fd63187f570239a0cc64001fc34c",
+   "testharness"
+  ],
   "service-workers/service-worker/fetch-cors-xhr.https.html": [
    "448c071ddeaaaf828800d8fad20d8ce672e56590",
    "testharness"
@@ -338879,6 +338828,10 @@
    "aee62d5b6ee22664c493036c879ed8d530b5ba1d",
    "support"
   ],
+  "service-workers/service-worker/resources/fetch-cors-exposed-header-names-worker.js": [
+   "39aa0c0af84872b5910afd933bfb1642fc28a60d",
+   "support"
+  ],
   "service-workers/service-worker/resources/fetch-cors-xhr-iframe.html": [
    "604a64021a30d3cb9ecef7c3d8d6ec14bc75f5e8",
    "support"
diff --git a/third_party/WebKit/LayoutTests/http/tests/fileapi/send-file-form-iso-2022-jp.html b/third_party/WebKit/LayoutTests/external/wpt/FileAPI/file/send-file-form-iso-2022-jp.tentative.html
similarity index 77%
rename from third_party/WebKit/LayoutTests/http/tests/fileapi/send-file-form-iso-2022-jp.html
rename to third_party/WebKit/LayoutTests/external/wpt/FileAPI/file/send-file-form-iso-2022-jp.tentative.html
index 8efa80a..421de30 100644
--- a/third_party/WebKit/LayoutTests/http/tests/fileapi/send-file-form-iso-2022-jp.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/FileAPI/file/send-file-form-iso-2022-jp.tentative.html
@@ -1,13 +1,24 @@
 <!DOCTYPE html>
 <meta charset="utf-8">
-<title>Upload files in ISO-2022-JP form</title>
+<title>Upload files in ISO-2022-JP form (tentative)</title>
+<!--
+    NOTE: This test is tentative because encoding for filename
+    characters unrepresentable in the form charset is not yet
+    standardized.
+  -->
+<link rel="help"
+      href="https://github.com/whatwg/html/issues/3223">
 <link rel="help"
       href="https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#multipart-form-data">
+<link rel="help"
+      href="https://html.spec.whatwg.org/multipage/dnd.html#datatransferitemlist">
+<link rel="help"
+      href="https://w3c.github.io/FileAPI/#file-constructor">
 <link rel="author" title="Benjamin C. Wiley Sittler"
       href="mailto:bsittler@chromium.org">
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
-<script src="resources/send-file-form-helper.js"></script>
+<script src="../support/send-file-form-helper.js"></script>
 <script>
 'use strict';
 
diff --git a/third_party/WebKit/LayoutTests/http/tests/fileapi/send-file-form-utf-8.html b/third_party/WebKit/LayoutTests/external/wpt/FileAPI/file/send-file-form-utf-8.html
similarity index 87%
rename from third_party/WebKit/LayoutTests/http/tests/fileapi/send-file-form-utf-8.html
rename to third_party/WebKit/LayoutTests/external/wpt/FileAPI/file/send-file-form-utf-8.html
index 2c4ed7f2..03417ba 100644
--- a/third_party/WebKit/LayoutTests/http/tests/fileapi/send-file-form-utf-8.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/FileAPI/file/send-file-form-utf-8.html
@@ -3,11 +3,15 @@
 <title>Upload files in UTF-8 form</title>
 <link rel="help"
       href="https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#multipart-form-data">
+<link rel="help"
+      href="https://html.spec.whatwg.org/multipage/dnd.html#datatransferitemlist">
+<link rel="help"
+      href="https://w3c.github.io/FileAPI/#file-constructor">
 <link rel="author" title="Benjamin C. Wiley Sittler"
       href="mailto:bsittler@chromium.org">
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
-<script src="resources/send-file-form-helper.js"></script>
+<script src="../support/send-file-form-helper.js"></script>
 <script>
 'use strict';
 
diff --git a/third_party/WebKit/LayoutTests/http/tests/fileapi/send-file-form-windows-1252.html b/third_party/WebKit/LayoutTests/external/wpt/FileAPI/file/send-file-form-windows-1252.tentative.html
similarity index 76%
rename from third_party/WebKit/LayoutTests/http/tests/fileapi/send-file-form-windows-1252.html
rename to third_party/WebKit/LayoutTests/external/wpt/FileAPI/file/send-file-form-windows-1252.tentative.html
index eddc19d..8e9463f 100644
--- a/third_party/WebKit/LayoutTests/http/tests/fileapi/send-file-form-windows-1252.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/FileAPI/file/send-file-form-windows-1252.tentative.html
@@ -1,13 +1,24 @@
 <!DOCTYPE html>
 <meta charset="utf-8">
-<title>Upload files in Windows-1252 form</title>
+<title>Upload files in Windows-1252 form (tentative)</title>
+<!--
+    NOTE: This test is tentative because encoding for filename
+    characters unrepresentable in the form charset is not yet
+    standardized.
+  -->
+<link rel="help"
+      href="https://github.com/whatwg/html/issues/3223">
 <link rel="help"
       href="https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#multipart-form-data">
+<link rel="help"
+      href="https://html.spec.whatwg.org/multipage/dnd.html#datatransferitemlist">
+<link rel="help"
+      href="https://w3c.github.io/FileAPI/#file-constructor">
 <link rel="author" title="Benjamin C. Wiley Sittler"
       href="mailto:bsittler@chromium.org">
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
-<script src="resources/send-file-form-helper.js"></script>
+<script src="../support/send-file-form-helper.js"></script>
 <script>
 'use strict';
 
diff --git a/third_party/WebKit/LayoutTests/http/tests/fileapi/send-file-form-x-user-defined.html b/third_party/WebKit/LayoutTests/external/wpt/FileAPI/file/send-file-form-x-user-defined.tentative.html
similarity index 77%
rename from third_party/WebKit/LayoutTests/http/tests/fileapi/send-file-form-x-user-defined.html
rename to third_party/WebKit/LayoutTests/external/wpt/FileAPI/file/send-file-form-x-user-defined.tentative.html
index 93851e2e..072e3bb1 100644
--- a/third_party/WebKit/LayoutTests/http/tests/fileapi/send-file-form-x-user-defined.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/FileAPI/file/send-file-form-x-user-defined.tentative.html
@@ -1,13 +1,24 @@
 <!DOCTYPE html>
 <meta charset="utf-8">
-<title>Upload files in x-user-defined form</title>
+<title>Upload files in x-user-defined form (tentative)</title>
+<!--
+    NOTE: This test is tentative because encoding for filename
+    characters unrepresentable in the form charset is not yet
+    standardized.
+  -->
+<link rel="help"
+      href="https://github.com/whatwg/html/issues/3223">
 <link rel="help"
       href="https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#multipart-form-data">
+<link rel="help"
+      href="https://html.spec.whatwg.org/multipage/dnd.html#datatransferitemlist">
+<link rel="help"
+      href="https://w3c.github.io/FileAPI/#file-constructor">
 <link rel="author" title="Benjamin C. Wiley Sittler"
       href="mailto:bsittler@chromium.org">
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
-<script src="resources/send-file-form-helper.js"></script>
+<script src="../support/send-file-form-helper.js"></script>
 <script>
 'use strict';
 
diff --git a/third_party/WebKit/LayoutTests/http/tests/fileapi/send-file-form.html b/third_party/WebKit/LayoutTests/external/wpt/FileAPI/file/send-file-form.html
similarity index 72%
rename from third_party/WebKit/LayoutTests/http/tests/fileapi/send-file-form.html
rename to third_party/WebKit/LayoutTests/external/wpt/FileAPI/file/send-file-form.html
index d0f12b3c..baa8d42 100644
--- a/third_party/WebKit/LayoutTests/http/tests/fileapi/send-file-form.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/FileAPI/file/send-file-form.html
@@ -3,11 +3,15 @@
 <title>Upload ASCII-named file in UTF-8 form</title>
 <link rel="help"
       href="https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#multipart-form-data">
+<link rel="help"
+      href="https://html.spec.whatwg.org/multipage/dnd.html#datatransferitemlist">
+<link rel="help"
+      href="https://w3c.github.io/FileAPI/#file-constructor">
 <link rel="author" title="Benjamin C. Wiley Sittler"
       href="mailto:bsittler@chromium.org">
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
-<script src="resources/send-file-form-helper.js"></script>
+<script src="../support/send-file-form-helper.js"></script>
 <script>
 'use strict';
 
diff --git a/third_party/WebKit/LayoutTests/http/tests/fileapi/resources/send-file-form-helper.js b/third_party/WebKit/LayoutTests/external/wpt/FileAPI/support/send-file-form-helper.js
similarity index 98%
rename from third_party/WebKit/LayoutTests/http/tests/fileapi/resources/send-file-form-helper.js
rename to third_party/WebKit/LayoutTests/external/wpt/FileAPI/support/send-file-form-helper.js
index fd0a10d2..a7522c7 100644
--- a/third_party/WebKit/LayoutTests/http/tests/fileapi/resources/send-file-form-helper.js
+++ b/third_party/WebKit/LayoutTests/external/wpt/FileAPI/support/send-file-form-helper.js
@@ -97,7 +97,7 @@
 // numeric character reference replacement for filenames, field names,
 // and field values.
 //
-// Uses /xmlhttprequest/resources/post-echo.cgi to echo the upload
+// Uses /fetch/api/resources/echo-content.py to echo the upload
 // POST with UTF-8 byte interpretation, leading to the "UTF-8 goggles"
 // behavior documented below for expectedEncodedBaseName when non-
 // UTF-8-compatible byte sequences appear in the formEncoding-encoded
@@ -140,7 +140,7 @@
 
     const form = Object.assign(document.createElement('form'), {
       acceptCharset: formEncoding,
-      action: '/xmlhttprequest/resources/post-echo.cgi',
+      action: '/fetch/api/resources/echo-content.py',
       method: 'POST',
       enctype: 'multipart/form-data',
       target: formTargetFrame.name,
diff --git a/third_party/WebKit/LayoutTests/external/wpt/XMLHttpRequest/send-network-error-sync-events.sub.htm b/third_party/WebKit/LayoutTests/external/wpt/XMLHttpRequest/send-network-error-sync-events.sub.htm
index 0ae94069..b899580 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/XMLHttpRequest/send-network-error-sync-events.sub.htm
+++ b/third_party/WebKit/LayoutTests/external/wpt/XMLHttpRequest/send-network-error-sync-events.sub.htm
@@ -17,7 +17,7 @@
         {
             var xhr = new XMLHttpRequest();
 
-            xhr.open("POST", "http://nonexistent-origin.{{host}}}:{{ports[http][0]}}", false);
+            xhr.open("POST", "http://nonexistent-origin.{{host}}:{{ports[http][0]}}", false);
 
             assert_throws("NetworkError", function()
             {
@@ -25,6 +25,12 @@
             });
             assert_equals(xhr.readyState, 4)
 
+        }, "http URL");
+
+        test(function()
+        {
+            var xhr = new XMLHttpRequest();
+
             xhr.open("GET", "data:text/html;charset=utf-8;base64,PT0NUWVBFIGh0bWw%2BDQo8", false);
 
             assert_throws("NetworkError", function()
@@ -33,7 +39,7 @@
             });
             assert_equals(xhr.readyState, 4)
 
-        });
+        }, "data URL");
     </script>
 </body>
 </html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-multicol/multicol-table-cell-vertical-align-001.xht b/third_party/WebKit/LayoutTests/external/wpt/css/css-multicol/multicol-table-cell-vertical-align-001.xht
index 5f73cec..f50d0af 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/css-multicol/multicol-table-cell-vertical-align-001.xht
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-multicol/multicol-table-cell-vertical-align-001.xht
@@ -10,13 +10,13 @@
 <style type="text/css"><![CDATA[
 div {
 	font-family: ahem;
-	font-size: 1em;
+	font-size: 20px;
 	line-height: 1em;
 	vertical-align: middle;
 	color: white;
 	background: #3366CC;
 	width: 6em;
-	height: 400px;
+	height: 20em;
 	display: table-cell;
 
 	column-count: 2;
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-multicol/multicol-table-cell-vertical-align-ref.xht b/third_party/WebKit/LayoutTests/external/wpt/css/css-multicol/multicol-table-cell-vertical-align-ref.xht
index 023c9c6..bbb2d3c 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/css-multicol/multicol-table-cell-vertical-align-ref.xht
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-multicol/multicol-table-cell-vertical-align-ref.xht
@@ -7,16 +7,16 @@
 <style type="text/css"><![CDATA[
 div {
 	font-family: ahem;
-	font-size: 1em;
+	font-size: 20px;
 	line-height: 1em;
 	vertical-align: middle;
 	color: white;
 	background: #3366CC;
 	width: 6em;
-	height: 8em;
+	height: 5.5em;
 }
 div+div {
-	margin-top: 10em;
+	margin-top: 9em;
 }
 ]]></style>
 </head>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-typed-om/styleMap-update-function-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/css/css-typed-om/styleMap-update-function-expected.txt
deleted file mode 100644
index 3c87472..0000000
--- a/third_party/WebKit/LayoutTests/external/wpt/css/css-typed-om/styleMap-update-function-expected.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-This is a testharness.js-based test.
-FAIL styleMap objects provide an 'update' function assert_equals: update expected to apply callback to old value in map expected 62 but got 42
-Harness: the test ran to completion.
-
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-typed-om/styleMap-update-function.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-typed-om/styleMap-update-function.html
index 4dea009..19f6399 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/css-typed-om/styleMap-update-function.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-typed-om/styleMap-update-function.html
@@ -10,7 +10,7 @@
   <script>
     test(function() {
       element.attributeStyleMap.set('width', new CSSUnitValue(42, 'px'));
-      element.attributeStyleMap.update('width', length => new CSSSimpleLength(length.value + 20, length.type))
+      element.attributeStyleMap.update('width', length => new CSSUnitValue(length.value + 20, length.unit))
       assert_equals(element.attributeStyleMap.get('width').value, 62, 'update expected to apply callback to old value in map');
     });
   </script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/interfaces/HTMLElement/HTMLTrackElement/readyState.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/interfaces/HTMLElement/HTMLTrackElement/readyState.html
index e18f2193..cde21e6 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/interfaces/HTMLElement/HTMLTrackElement/readyState.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/interfaces/HTMLElement/HTMLTrackElement/readyState.html
@@ -8,4 +8,11 @@
     var track = document.createElement('track');
     assert_equals(track.readyState, 0);
 }, document.title + ' default value');
+
+test(function(){
+    assert_equals(HTMLTrackElement.NONE, 0);
+    assert_equals(HTMLTrackElement.LOADING, 1);
+    assert_equals(HTMLTrackElement.LOADED, 2);
+    assert_equals(HTMLTrackElement.ERROR, 3);
+}, document.title + ' values');
 </script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/track/track-element/resources/captions-fast.vtt b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/track/track-element/resources/captions-fast.vtt
new file mode 100644
index 0000000..cd138fd
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/track/track-element/resources/captions-fast.vtt
@@ -0,0 +1,13 @@
+WEBVTT
+
+1
+00:00:00.000 --> 00:00:00.300
+Lorem
+
+2
+00:00:00.300 --> 00:00:00.700
+ipsum
+
+3
+00:00:01.200 --> 00:00:01.500
+dolor
diff --git a/third_party/WebKit/LayoutTests/media/track/track-active-cues.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/track/track-element/track-active-cues.html
similarity index 72%
rename from third_party/WebKit/LayoutTests/media/track/track-active-cues.html
rename to third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/track/track-element/track-active-cues.html
index 78ac354a..67ab3bdb 100644
--- a/third_party/WebKit/LayoutTests/media/track/track-active-cues.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/track/track-element/track-active-cues.html
@@ -1,8 +1,8 @@
-<!doctype html>
-<title>Test to ensure that no text track cues are active after the video is unloaded.</title>
-<script src="../media-file.js"></script>
-<script src="../../resources/testharness.js"></script>
-<script src="../../resources/testharnessreport.js"></script>
+<!DOCTYPE html>
+<title>Ensure that no text track cues are active after the video is unloaded</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 eventCount = 0;
@@ -16,7 +16,7 @@
     }
 
     var video = document.createElement('video');
-    video.src = findMediaFile('video', '../content/test');
+    video.src = getVideoURI('/media/movie_5');
     var trackElement = document.createElement('track');
 
     trackElement.onload = t.step_func(eventCallback);
@@ -31,7 +31,7 @@
         assert_equals(trackElement.track.activeCues.length, 0);
     });
 
-    trackElement.src = 'captions-webvtt/captions-fast.vtt';
+    trackElement.src = 'resources/captions-fast.vtt';
     trackElement.kind = 'captions';
     trackElement.default = true;
     video.appendChild(trackElement);
diff --git a/third_party/WebKit/LayoutTests/fast/mediastream/argument-types-expected.txt b/third_party/WebKit/LayoutTests/fast/mediastream/argument-types-expected.txt
index afd6e1b..cc3fca2 100644
--- a/third_party/WebKit/LayoutTests/fast/mediastream/argument-types-expected.txt
+++ b/third_party/WebKit/LayoutTests/fast/mediastream/argument-types-expected.txt
@@ -6,9 +6,9 @@
 PASS navigator.webkitGetUserMedia() threw exception TypeError: Failed to execute 'webkitGetUserMedia' on 'Navigator': 3 arguments required, but only 0 present..
 PASS navigator.webkitGetUserMedia({video: true}) threw exception TypeError: Failed to execute 'webkitGetUserMedia' on 'Navigator': 3 arguments required, but only 1 present..
 PASS navigator.webkitGetUserMedia({video: true}, emptyFunction) threw exception TypeError: Failed to execute 'webkitGetUserMedia' on 'Navigator': 3 arguments required, but only 2 present..
-PASS navigator.webkitGetUserMedia({video: true}, emptyFunction, emptyFunction) did not throw exception.
-PASS navigator.webkitGetUserMedia({audio: true}, emptyFunction, emptyFunction) did not throw exception.
-PASS navigator.webkitGetUserMedia({audio: true, video: true}, emptyFunction, emptyFunction) did not throw exception.
+PASS navigator.webkitGetUserMedia({video: true}, callbackFunction, callbackFunction) did not throw exception.
+PASS navigator.webkitGetUserMedia({audio: true}, callbackFunction, callbackFunction) did not throw exception.
+PASS navigator.webkitGetUserMedia({audio: true, video: true}, callbackFunction, callbackFunction) did not throw exception.
 PASS navigator.webkitGetUserMedia(-Infinity, emptyFunction, emptyFunction) threw exception TypeError: Failed to execute 'webkitGetUserMedia' on 'Navigator': parameter 1 ('constraints') is not an object..
 PASS navigator.webkitGetUserMedia(42, emptyFunction, emptyFunction) threw exception TypeError: Failed to execute 'webkitGetUserMedia' on 'Navigator': parameter 1 ('constraints') is not an object..
 PASS navigator.webkitGetUserMedia(Infinity, emptyFunction, emptyFunction) threw exception TypeError: Failed to execute 'webkitGetUserMedia' on 'Navigator': parameter 1 ('constraints') is not an object..
diff --git a/third_party/WebKit/LayoutTests/fast/mediastream/argument-types.html b/third_party/WebKit/LayoutTests/fast/mediastream/argument-types.html
index b9028e3..bdcf3e0 100644
--- a/third_party/WebKit/LayoutTests/fast/mediastream/argument-types.html
+++ b/third_party/WebKit/LayoutTests/fast/mediastream/argument-types.html
@@ -6,7 +6,18 @@
 <body>
 <script>
 description("Tests the acceptable types for arguments to navigator.getUserMedia methods.");
+window.jsTestIsAsync = true;
 
+// Pending callbacks may cause the leak detector run at the end of the test to
+// find leaked blink nodes. Therefore, we must wait for all callbacks to arrive
+// before finishing the test run.
+var remainingExpectedCallbackCount = 3;
+var callbackFunction = function() {
+  remainingExpectedCallbackCount--;
+  if (remainingExpectedCallbackCount == 0) {
+    finishJSTest();
+  }
+};
 var emptyFunction = function() {};
 
 // No arguments
@@ -17,9 +28,9 @@
 shouldThrow('navigator.webkitGetUserMedia({video: true}, emptyFunction)');
 
 // 3 arguments (getUserMedia requires at least 3 arguments).
-shouldNotThrow('navigator.webkitGetUserMedia({video: true}, emptyFunction, emptyFunction)');
-shouldNotThrow('navigator.webkitGetUserMedia({audio: true}, emptyFunction, emptyFunction)');
-shouldNotThrow('navigator.webkitGetUserMedia({audio: true, video: true}, emptyFunction, emptyFunction)');
+shouldNotThrow('navigator.webkitGetUserMedia({video: true}, callbackFunction, callbackFunction)');
+shouldNotThrow('navigator.webkitGetUserMedia({audio: true}, callbackFunction, callbackFunction)');
+shouldNotThrow('navigator.webkitGetUserMedia({audio: true, video: true}, callbackFunction, callbackFunction)');
 shouldThrow('navigator.webkitGetUserMedia(-Infinity, emptyFunction, emptyFunction)');
 shouldThrow('navigator.webkitGetUserMedia(42, emptyFunction, emptyFunction)');
 shouldThrow('navigator.webkitGetUserMedia(Infinity, emptyFunction, emptyFunction)');
@@ -47,7 +58,6 @@
 shouldThrow('navigator.webkitGetUserMedia({video: true}, undefined, emptyFunction)');
 shouldThrow('navigator.webkitGetUserMedia({video: true}, {}, emptyFunction)');
 
-window.jsTestIsAsync = false;
 </script>
 </body>
 </html>
diff --git a/third_party/WebKit/LayoutTests/fast/webgl/resources/tex-image-and-sub-image-image-bitmap-utils-resize.js b/third_party/WebKit/LayoutTests/fast/webgl/resources/tex-image-and-sub-image-image-bitmap-utils-resize.js
index c004acb..b67a1b6 100644
--- a/third_party/WebKit/LayoutTests/fast/webgl/resources/tex-image-and-sub-image-image-bitmap-utils-resize.js
+++ b/third_party/WebKit/LayoutTests/fast/webgl/resources/tex-image-and-sub-image-image-bitmap-utils-resize.js
@@ -1,28 +1,140 @@
-var refBufPremul = new Uint8Array([
-    255,0,0,255,    204,0,0,204,    84,0,0,84,      18,0,0,18,
-    192,62,0,255,   149,48,0,198,   61,20,0,82,     13,4,0,18,
-    62,192,0,255,   48,149,0,198,   20,61,0,82,     4,13,0,18,
-    0,255,0,255,    0,204,0,204,    0,84,0,84,      0,18,0,18]);
+//------------- Reference Buffers for Pixelated Filter Quality -------------//
+var refBufPixelatedPremul = [
+    255,0,0,255,    255,0,0,255,    26,0,0,26,      26,0,0,26,
+    255,0,0,255,    255,0,0,255,    26,0,0,26,      26,0,0,26,
+    0,255,0,255,    0,255,0,255,    0,26,0,26,      0,26,0,26,
+    0,255,0,255,    0,255,0,255,    0,26,0,26,      0,26,0,26];
 
-var refBufUnpremul = new Uint8Array([
-    255,0,0,255,    255,0,0,204,    255,0,0,84,     255,0,0,18,
-    192,62,0,255,   192,62,0,198,   190,62,0,82,    184,57,0,18,
-    62,192,0,255,   62,192,0,198,   62,190,0,82,    57,184,0,18,
-    0,255,0,255,    0,255,0,204,    0,255,0,84,     0,255,0,18]);
+var refBufPixelatedUnpremul = [
+    255,0,0,255,    255,0,0,255,    255,0,0,26,     255,0,0,26,
+    255,0,0,255,    255,0,0,255,    255,0,0,26,     255,0,0,26,
+    0,255,0,255,    0,255,0,255,    0,255,0,26,     0,255,0,26,
+    0,255,0,255,    0,255,0,255,    0,255,0,26,     0,255,0,26];
 
-var refBufFlipY = new Uint8Array([
-    0,255,0,255,    0,204,0,204,    0,84,0,84,      0,18,0,18,
-    62,192,0,255,   48,149,0,198,   20,61,0,82,     4,13,0,18,
-    192,62,0,255,   149,48,0,198,   61,20,0,82,     13,4,0,18,
-    255,0,0,255,    204,0,0,204,    84,0,0,84,      18,0,0,18]);
+var refBufPixelatedPremulFlipY = [
+    0,255,0,255,    0,255,0,255,    0,26,0,26,      0,26,0,26,
+    0,255,0,255,    0,255,0,255,    0,26,0,26,      0,26,0,26,
+    255,0,0,255,    255,0,0,255,    26,0,0,26,      26,0,0,26,
+    255,0,0,255,    255,0,0,255,    26,0,0,26,      26,0,0,26];
 
-var refBufUnpremulFlipY = new Uint8Array([
-    0,255,0,255,    0,255,0,204,    0,255,0,84,     0,255,0,18,
-    62,192,0,255,   62,192,0,198,   62,190,0,82,    57,184,0,18,
-    192,62,0,255,   192,62,0,198,   190,62,0,82,    184,57,0,18,
-    255,0,0,255,    255,0,0,204,    255,0,0,84,     255,0,0,18]);
+var refBufPixelatedUnpremulFlipY = [
+    0,255,0,255,    0,255,0,255,    0,255,0,26,     0,255,0,26,
+    0,255,0,255,    0,255,0,255,    0,255,0,26,     0,255,0,26,
+    255,0,0,255,    255,0,0,255,    255,0,0,26,     255,0,0,26,
+    255,0,0,255,    255,0,0,255,    255,0,0,26,     255,0,0,26];
 
-function checkCanvas(buf, refBuf, tolerance, retVal)
+//---------------- Reference Buffers for Low Filter Quality ----------------//
+var refBufLowPremul= [
+    255,0,0,255,    197,0,0,197,    83,0,0,83,      26,0,0,26,
+    191,63,0,255,   148,49,0,197,   62,20,0,83,     19,6,0,26,
+    63,191,0,255,   49,148,0,197,   20,62,0,83,     6,19,0,26,
+    0,255,0,255,    0,197,0,197,    0,83,0,83,      0,26,0,26];
+
+var refBufLowUnpremul = [
+    255,0,0,255,    255,0,0,197,    255,0,0,83,     255,0,0,26,
+    191,63,0,255,   192,63,0,197,   190,61,0,83,    186,59,0,26,
+    63,191,0,255,   63,192,0,197,   61,190,0,83,    59,186,0,26,
+    0,255,0,255,    0,255,0,197,    0,255,0,83,     0,255,0,26];
+
+var refBufLowPremulFlipY = [
+    0,255,0,255,    0,197,0,197,    0,83,0,83,      0,26,0,26,
+    63,191,0,255,   49,148,0,197,   20,62,0,83,     6,19,0,26,
+    191,63,0,255,   148,49,0,197,   62,20,0,83,     19,6,0,26,
+    255,0,0,255,    197,0,0,197,    83,0,0,83,      26,0,0,26];
+
+var refBufLowUnpremulFlipY = [
+    0,255,0,255,    0,255,0,197,    0,255,0,83,     0,255,0,26,
+    63,191,0,255,   63,192,0,197,   61,190,0,83,    59,186,0,26,
+    191,63,0,255,   192,63,0,197,   190,61,0,83,    186,59,0,26,
+    255,0,0,255,    255,0,0,197,    255,0,0,83,     255,0,0,26];
+
+//-------------- Reference Buffers for Medium Filter Quality ---------------//
+var refBufMediumPremul = refBufLowPremul;
+var refBufMediumUnpremul = refBufLowUnpremul;
+var refBufMediumPremulFlipY = refBufLowPremulFlipY;
+var refBufMediumUnpremulFlipY = refBufLowUnpremulFlipY;
+
+//-------- Reference Buffers for High Filter Quality (Premul Source) -------//
+var refBufHighPremulSourcePremul = [
+    255,0,0,255,    200,0,0,200,    81,0,0,81,      21,0,0,21,
+    198,63,0,255,   152,48,0,200,   62,20,0,81,     16,5,0,21,
+    63,198,0,255,   48,152,0,200,   20,62,0,81,     5,16,0,21,
+    0,255,0,255,    0,200,0,200,    0,81,0,81,      0,21,0,21];
+
+var refBufHighUnpremulSourcePremul = [
+    255,0,0,255,    255,0,0,200,    255,0,0,81,     255,0,0,21,
+    198,63,0,255,   194,61,0,200,   195,63,0,81,    194,61,0,21,
+    63,198,0,255,   61,194,0,200,   63,195,0,81,    61,194,0,21,
+    0,255,0,255,    0,255,0,200,    0,255,0,81,     0,255,0,21];
+
+var refBufHighPremulFlipYSourcePremul = [
+    0,255,0,255,    0,200,0,200,    0,81,0,81,      0,21,0,21,
+    63,198,0,255,   48,152,0,200,   20,62,0,81,     5,16,0,21,
+    198,63,0,255,   152,48,0,200,   62,20,0,81,     16,5,0,21,
+    255,0,0,255,    200,0,0,200,    81,0,0,81,      21,0,0,21];
+
+var refBufHighUnpremulFlipYSourcePremul = [
+    0,255,0,255,    0,255,0,200,    0,255,0,81,     0,255,0,21,
+    63,198,0,255,   61,194,0,200,   63,195,0,81,    61,194,0,21,
+    198,63,0,255,   194,61,0,200,   195,63,0,81,    194,61,0,21,
+    255,0,0,255,    255,0,0,200,    255,0,0,81,     255,0,0,21];
+
+//------- Reference Buffers for High Filter Quality (Unpremul Source) ------//
+var refBufHighPremulSourceUnpremul = [
+    255,0,0,255,    200,0,0,200,    81,0,0,81,      21,0,0,21,
+    198,63,0,255,   152,48,0,200,   62,20,0,81,     16,5,0,21,
+    63,198,0,255,   48,152,0,200,   20,62,0,81,     5,16,0,21,
+    0,255,0,255,    0,200,0,200,    0,81,0,81,      0,21,0,21];
+
+var refBufHighUnpremulSourceUnpremul = [
+    255,0,0,255,    255,0,0,200,    255,0,0,81,     255,0,0,21,
+    193,62,0,255,   193,62,0,200,   193,62,0,81,    193,62,0,21,
+    62,193,0,255,   62,193,0,200,   62,193,0,81,    62,193,0,21,
+    0,255,0,255,    0,255,0,200,    0,255,0,81,     0,255,0,21];
+
+var refBufHighPremulFlipYSourceUnpremul = [
+    0,255,0,255,    0,200,0,200,    0,81,0,81,      0,21,0,21,
+    63,198,0,255,   48,152,0,200,   20,62,0,81,     5,16,0,21,
+    198,63,0,255,   152,48,0,200,   62,20,0,81,     16,5,0,21,
+    255,0,0,255,    200,0,0,200,    81,0,0,81,      21,0,0,21];
+
+var refBufHighUnpremulFlipYSourceUnpremul = [
+    0,255,0,255,    0,255,0,200,    0,255,0,81,     0,255,0,21,
+    62,193,0,255,   62,193,0,200,   62,193,0,81,    62,193,0,21,
+    193,62,0,255,   193,62,0,200,   193,62,0,81,    193,62,0,21,
+    255,0,0,255,    255,0,0,200,    255,0,0,81,     255,0,0,21];
+
+
+var wtu = WebGLTestUtils;
+var tiu = TexImageUtils;
+var gl = null;
+var internalFormat = "RGBA";
+var pixelFormat = "RGBA";
+var pixelType = "UNSIGNED_BYTE";
+var opaqueTolerance = 0;
+var transparentTolerance = 0;
+var transparentToleranceForBlob = 5;
+
+function getRefBuffer(testOptions, flipY, premultiplyAlpha) {
+    var refBufName = "refBuf" +
+                     testOptions.resizeQuality.charAt(0).toUpperCase() +
+                     testOptions.resizeQuality.slice(1);
+    if (premultiplyAlpha)
+        refBufName += "Premul";
+    else
+        refBufName += "Unpremul";
+    if (flipY)
+        refBufName += "FlipY";
+    if (testOptions.resizeQuality == "high") {
+        if (testOptions.sourceIsPremul)
+            refBufName += "SourcePremul";
+        else
+            refBufName += "SourceUnpremul";
+    }
+    return eval(refBufName);
+}
+
+function checkPixels(buf, refBuf, tolerance, retVal)
 {
     if (buf.length != refBuf.length) {
         retVal.testPassed = false;
@@ -37,7 +149,8 @@
 }
 
 function runOneIteration(useTexSubImage2D, bindingTarget, program, bitmap,
-                         flipY, premultiplyAlpha, retVal, colorSpace = 'empty')
+                         flipY, premultiplyAlpha, retVal, colorSpace,
+                         testOptions)
 {
     gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
     // Enable writes to the RGBA channels
@@ -80,7 +193,12 @@
         loc = gl.getUniformLocation(program, "face");
     }
 
-    var tolerance = (retVal.alpha == 0) ? 0 : 10;
+    var tolerance = opaqueTolerance;
+    if (retVal.alpha != 0) {
+        tolerance = transparentTolerance;
+        if (testOptions.sourceName == "Blob")
+            tolerance = transparentToleranceForBlob;
+    }
     for (var tt = 0; tt < targets.length; ++tt) {
         if (bindingTarget == gl.TEXTURE_CUBE_MAP) {
             gl.uniform1i(loc, targets[tt]);
@@ -89,22 +207,16 @@
         gl.clearColor(0, 0, 0, 1);
         gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
         gl.drawArrays(gl.TRIANGLES, 0, 6);
-        // Select the proper reference buffer
-        var refBuf = refBufPremul;
-        if (flipY && !premultiplyAlpha)
-            refBuf = refBufUnpremulFlipY;
-        else if (!premultiplyAlpha)
-            refBuf = refBufUnpremul;
-        else if (flipY)
-            refBuf = refBufFlipY;
-        // Check the pixels
+        // Check the buf
+        var refBuf = getRefBuffer(testOptions, flipY, premultiplyAlpha);
         var buf = new Uint8Array(width * height * 4);
         gl.readPixels(0, 0, width, height, gl.RGBA, gl.UNSIGNED_BYTE, buf);
-        checkCanvas(buf, refBuf, tolerance, retVal);
+        checkPixels(buf, refBuf, tolerance, retVal);
     }
 }
 
-function runTestOnBindingTarget(bindingTarget, program, bitmaps, retVal) {
+function runTestOnBindingTarget(bindingTarget, program, bitmaps, retVal,
+                                testOptions) {
     var cases = [
         { sub: false, bitmap: bitmaps.defaultOption, flipY: false,
             premultiply: true, colorSpace: 'empty' },
@@ -156,17 +268,103 @@
 
     for (var i in cases) {
         runOneIteration(cases[i].sub, bindingTarget, program, cases[i].bitmap,
-            cases[i].flipY, cases[i].premultiply, retVal, cases[i].colorSpace);
+            cases[i].flipY, cases[i].premultiply, retVal, cases[i].colorSpace,
+            testOptions);
     }
 }
 
-function runTest(bitmaps, alphaVal, colorSpaceEffective)
+// createImageBitmap resize code has two separate code paths for premul and
+// unpremul image sources when the resize quality is set to high.
+function runTest(bitmaps, alphaVal, colorSpaceEffective, testOptions)
 {
     var retVal = {testPassed: true, alpha: alphaVal,
         colorSpaceEffect: colorSpaceEffective};
     var program = tiu.setupTexturedQuad(gl, internalFormat);
-    runTestOnBindingTarget(gl.TEXTURE_2D, program, bitmaps, retVal);
+    runTestOnBindingTarget(gl.TEXTURE_2D, program, bitmaps, retVal,
+                           testOptions);
     program = tiu.setupTexturedQuadWithCubeMap(gl, internalFormat);
-    runTestOnBindingTarget(gl.TEXTURE_CUBE_MAP, program, bitmaps, retVal);
+    runTestOnBindingTarget(gl.TEXTURE_CUBE_MAP, program, bitmaps, retVal,
+                           testOptions);
     return retVal.testPassed;
 }
+
+function prepareResizedImageBitmapsAndRuntTest(testOptions) {
+    var bitmaps = [];
+    var imageSource= testOptions.imageSource;
+    var options = {resizeWidth: testOptions.resizeWidth,
+                   resizeHeight: testOptions.resizeHeight,
+                   resizeQuality: testOptions.resizeQuality};
+    var p1 = createImageBitmap(imageSource, options).then(
+        function(imageBitmap) { bitmaps.defaultOption = imageBitmap });
+
+    options.imageOrientation = "none";
+    options.premultiplyAlpha = "premultiply";
+    var p2 = createImageBitmap(imageSource, options).then(
+        function(imageBitmap) { bitmaps.noFlipYPremul = imageBitmap });
+
+    options.premultiplyAlpha = "default";
+    var p3 = createImageBitmap(imageSource, options).then(
+        function(imageBitmap) { bitmaps.noFlipYDefault = imageBitmap });
+
+    options.premultiplyAlpha = "none";
+    var p4 = createImageBitmap(imageSource, options).then(
+        function(imageBitmap) { bitmaps.noFlipYUnpremul = imageBitmap });
+
+    options.imageOrientation = "flipY";
+    options.premultiplyAlpha = "premultiply";
+    var p5 = createImageBitmap(imageSource, options).then(
+        function(imageBitmap) { bitmaps.flipYPremul = imageBitmap });
+
+    options.premultiplyAlpha = "default";
+    var p6 = createImageBitmap(imageSource, options).then(
+        function(imageBitmap) { bitmaps.flipYDefault = imageBitmap });
+
+    options.premultiplyAlpha = "none";
+    var p7 = createImageBitmap(imageSource, options).then(
+        function(imageBitmap) { bitmaps.flipYUnpremul = imageBitmap });
+
+    options = {resizeWidth: testOptions.resizeWidth,
+               resizeHeight: testOptions.resizeHeight,
+               resizeQuality: testOptions.resizeQuality};
+    var p8 = createImageBitmap(imageSource, options).then(
+        function(imageBitmap) { bitmaps.colorSpaceDef = imageBitmap });
+
+    options.colorSpaceConversion = "none";
+    var p9 = createImageBitmap(imageSource, options).then(
+        function(imageBitmap) { bitmaps.colorSpaceNone = imageBitmap });
+
+    options.colorSpaceConversion = "default";
+    var p10 = createImageBitmap(imageSource, options).then(
+        function(imageBitmap) { bitmaps.colorSpaceDefault = imageBitmap });
+
+    return Promise.all([p1, p2, p3, p4, p5, p6, p7, p8, p9, p10]).then(
+        function() {
+            var alphaVal = 0.5;
+            var testPassed = runTest(bitmaps, alphaVal, false, testOptions);
+            if (!testPassed)
+                assert_true(false, 'Test failed');
+        }, function() {
+            assert_true(false, 'Promise rejected');
+        });
+}
+
+function prepareResizedImageBitmapsAndRuntTests(testOptions) {
+    var resizeQualities = ["pixelated", "low", "medium", "high"];
+    for (i = 0; i < resizeQualities.length; i++) {
+        testOptions.resizeQuality = resizeQualities[i];
+        promise_test(function() {
+            return prepareResizedImageBitmapsAndRuntTest(testOptions);
+        }, 'createImageBitmap(' + testOptions.sourceName + ') resize with ' +
+           testOptions.resizeQuality + ' resize quality.');
+    }
+}
+
+function prepareWebGLContext() {
+    var canvas = document.createElement('canvas');
+    canvas.width = 4;
+    canvas.height = 4;
+    document.body.appendChild(canvas);
+    gl = canvas.getContext("webgl");
+    gl.clearColor(0,0,0,1);
+    gl.clearDepth(1);
+}
diff --git a/third_party/WebKit/LayoutTests/fast/webgl/texImage-imageBitmap-from-blob-resize.html b/third_party/WebKit/LayoutTests/fast/webgl/texImage-imageBitmap-from-blob-resize.html
index f2faec0d..1c7d54a 100644
--- a/third_party/WebKit/LayoutTests/fast/webgl/texImage-imageBitmap-from-blob-resize.html
+++ b/third_party/WebKit/LayoutTests/fast/webgl/texImage-imageBitmap-from-blob-resize.html
@@ -1,6 +1,4 @@
-<!DOCTYPE html>
 <html>
-<head>
 <script src="./resources/webgl-test-utils-full.js"></script>
 <script src="./resources/tex-image-and-sub-image-utils.js"></script>
 <script src="./resources/tex-image-and-sub-image-image-bitmap-utils-resize.js"></script>
@@ -8,92 +6,18 @@
 <script src="../../resources/testharnessreport.js"></script>
 <body>
 <script>
-var wtu = WebGLTestUtils;
-var tiu = TexImageUtils;
-var gl = null;
-var internalFormat = "RGBA";
-var pixelFormat = "RGBA";
-var pixelType = "UNSIGNED_BYTE";
 
-var blob = null;
-var blob2 = null;
-
-function generateTest()
-{
-    var bitmaps = [];
-
-    var canvas = document.createElement('canvas');
-    canvas.width = 4;
-    canvas.height = 4;
-    document.body.appendChild(canvas);
-    gl = canvas.getContext("webgl");
-
-    gl.clearColor(0,0,0,1);
-    gl.clearDepth(1);
-
-    var options = {resizeWidth: 4, resizeHeight: 4, resizeQuality: "high"};
-    var p1 = createImageBitmap(blob, options).then(
-        function(imageBitmap) { bitmaps.defaultOption = imageBitmap });
-
-    options.imageOrientation = "none";
-    options.premultiplyAlpha = "premultiply";
-    var p2 = createImageBitmap(blob, options).then(
-        function(imageBitmap) { bitmaps.noFlipYPremul = imageBitmap });
-
-    options.premultiplyAlpha = "default";
-    var p3 = createImageBitmap(blob, options).then(
-        function(imageBitmap) { bitmaps.noFlipYDefault = imageBitmap });
-
-    options.premultiplyAlpha = "none";
-    var p4 = createImageBitmap(blob, options).then(
-        function(imageBitmap) { bitmaps.noFlipYUnpremul = imageBitmap });
-
-    options.imageOrientation = "flipY";
-    options.premultiplyAlpha = "premultiply";
-    var p5 = createImageBitmap(blob, options).then(
-        function(imageBitmap) { bitmaps.flipYPremul = imageBitmap });
-
-    options.premultiplyAlpha = "default";
-    var p6 = createImageBitmap(blob, options).then(
-        function(imageBitmap) { bitmaps.flipYDefault = imageBitmap });
-
-    options.premultiplyAlpha = "none";
-    var p7 = createImageBitmap(blob, options).then(
-        function(imageBitmap) { bitmaps.flipYUnpremul = imageBitmap });
-
-    options = {resizeWidth: 4, resizeHeight: 4, resizeQuality: "high"};
-    var p8 = createImageBitmap(blob, options).then(
-        function(imageBitmap) { bitmaps.colorSpaceDef = imageBitmap });
-
-    options.colorSpaceConversion = "none";
-    var p9 = createImageBitmap(blob, options).then(
-        function(imageBitmap) { bitmaps.colorSpaceNone = imageBitmap });
-
-    options.colorSpaceConversion = "default";
-    var p10 = createImageBitmap(blob, options).then(
-        function(imageBitmap) { bitmaps.colorSpaceDefault = imageBitmap });
-
-    return Promise.all([p1, p2, p3, p4, p5, p6, p7, p8, p9, p10]).then(
-        t.step_func_done(function() {
-            var alphaVal = 0.5;
-            var testPassed = runTest(bitmaps, alphaVal, true);
-            if (!testPassed)
-                assert_true(false, 'Test failed');
-        }), t.step_func_done(function() {
-        assert_true(false, 'Promise rejected');
-    }));
-}
-
-var t = async_test("createImageBitmap(Blob) with resize and other options");
+var testOptions = {sourceName: "Blob", sourceIsPremul: true,
+                   resizeWidth: 4, resizeHeight: 4};
+prepareWebGLContext();
 
 var xhr = new XMLHttpRequest();
 xhr.open("GET", 'resources/red-green-semi-transparent-2x2.png');
 xhr.responseType = 'blob';
 xhr.send();
-xhr.onload = t.step_func(function() {
-    blob = xhr.response;
-    generateTest();
-})
+xhr.onload = function() {
+    testOptions.imageSource = xhr.response;
+    prepareResizedImageBitmapsAndRuntTests(testOptions);
+};
+
 </script>
-</body>
-</html>
diff --git a/third_party/WebKit/LayoutTests/fast/webgl/texImage-imageBitmap-from-canvas-resize.html b/third_party/WebKit/LayoutTests/fast/webgl/texImage-imageBitmap-from-canvas-resize.html
index d9c39b9c..d38b5d1b 100644
--- a/third_party/WebKit/LayoutTests/fast/webgl/texImage-imageBitmap-from-canvas-resize.html
+++ b/third_party/WebKit/LayoutTests/fast/webgl/texImage-imageBitmap-from-canvas-resize.html
@@ -1,6 +1,4 @@
-<!DOCTYPE html>
 <html>
-<head>
 <script src="./resources/webgl-test-utils-full.js"></script>
 <script src="./resources/tex-image-and-sub-image-utils.js"></script>
 <script src="./resources/tex-image-and-sub-image-image-bitmap-utils-resize.js"></script>
@@ -8,12 +6,6 @@
 <script src="../../resources/testharnessreport.js"></script>
 <body>
 <script>
-var wtu = WebGLTestUtils;
-var tiu = TexImageUtils;
-var gl = null;
-var internalFormat = "RGBA";
-var pixelFormat = "RGBA";
-var pixelType = "UNSIGNED_BYTE";
 
 function setCanvasToRedGreen(ctx) {
     var width = ctx.canvas.width;
@@ -30,73 +22,16 @@
     ctx.fillRect(halfWidth, halfHeight, halfWidth, halfHeight);
 }
 
-promise_test(function() {
-    var bitmaps = [];
+var testCanvas = document.createElement('canvas');
+testCanvas.width = 2;
+testCanvas.height = 2;
+var ctx = testCanvas.getContext("2d");
+setCanvasToRedGreen(ctx);
 
-    var canvas = document.createElement('canvas');
-    canvas.width = 4;
-    canvas.height = 4;
-    document.body.appendChild(canvas);
-    gl = canvas.getContext("webgl");
+var testOptions = {sourceName: "HTMLCanvasElement", imageSource: testCanvas,
+                   sourceIsPremul: true, resizeWidth: 4, resizeHeight: 4};
 
-    gl.clearColor(0,0,0,1);
-    gl.clearDepth(1);
+prepareWebGLContext();
+prepareResizedImageBitmapsAndRuntTests(testOptions);
 
-    var testCanvas = document.createElement('canvas');
-    testCanvas.width = 2;
-    testCanvas.height = 2;
-    var ctx = testCanvas.getContext("2d");
-    setCanvasToRedGreen(ctx);
-
-    var options = {resizeWidth: 4, resizeHeight: 4, resizeQuality: "high"};
-    var p1 = createImageBitmap(testCanvas, options).then(
-        function(imageBitmap) { bitmaps.defaultOption = imageBitmap });
-
-    options.imageOrientation = "none";
-    options.premultiplyAlpha = "premultiply";
-    var p2 = createImageBitmap(testCanvas, options).then(
-        function(imageBitmap) { bitmaps.noFlipYPremul = imageBitmap });
-
-    options.premultiplyAlpha = "default";
-    var p3 = createImageBitmap(testCanvas, options).then(
-        function(imageBitmap) { bitmaps.noFlipYDefault = imageBitmap });
-
-    options.premultiplyAlpha = "none";
-    var p4 = createImageBitmap(testCanvas, options).then(
-        function(imageBitmap) { bitmaps.noFlipYUnpremul = imageBitmap });
-
-    options.imageOrientation = "flipY";
-    options.premultiplyAlpha = "premultiply";
-    var p5 = createImageBitmap(testCanvas, options).then(
-        function(imageBitmap) { bitmaps.flipYPremul = imageBitmap });
-
-    options.premultiplyAlpha = "default";
-    var p6 = createImageBitmap(testCanvas, options).then(
-        function(imageBitmap) { bitmaps.flipYDefault = imageBitmap });
-
-    options.premultiplyAlpha = "none";
-    var p7 = createImageBitmap(testCanvas, options).then(
-        function(imageBitmap) { bitmaps.flipYUnpremul = imageBitmap });
-
-    options = {resizeWidth: 4, resizeHeight: 4, resizeQuality: "high"};
-    var p8 = createImageBitmap(testCanvas, options).then(
-        function(imageBitmap) { bitmaps.colorSpaceDef = imageBitmap });
-
-    options.colorSpaceConversion = "none";
-    var p9 = createImageBitmap(testCanvas, options).then(
-        function(imageBitmap) { bitmaps.colorSpaceNone = imageBitmap });
-
-    options.colorSpaceConversion = "default";
-    var p10 = createImageBitmap(testCanvas, options).then(
-        function(imageBitmap) { bitmaps.colorSpaceDefault = imageBitmap });
-
-    return Promise.all([p1, p2, p3, p4, p5, p6, p7, p8, p9, p10]).then(function() {
-        var alphaVal = 0.5;
-        var testPassed = runTest(bitmaps, alphaVal, false);
-        if (!testPassed)
-            assert_true(false, 'Test failed');
-    }, function() {
-        assert_true(false, 'Promise rejected');
-    });
-}, 'createImageBitmap(HTMLCanvasElement) with resize and other options');
 </script>
diff --git a/third_party/WebKit/LayoutTests/fast/webgl/texImage-imageBitmap-from-image-resize.html b/third_party/WebKit/LayoutTests/fast/webgl/texImage-imageBitmap-from-image-resize.html
index f077f56..2a69081 100644
--- a/third_party/WebKit/LayoutTests/fast/webgl/texImage-imageBitmap-from-image-resize.html
+++ b/third_party/WebKit/LayoutTests/fast/webgl/texImage-imageBitmap-from-image-resize.html
@@ -1,95 +1,21 @@
-
-<!DOCTYPE html>
 <html>
-<head>
 <script src="./resources/webgl-test-utils-full.js"></script>
 <script src="./resources/tex-image-and-sub-image-utils.js"></script>
 <script src="./resources/tex-image-and-sub-image-image-bitmap-utils-resize.js"></script>
 <script src="../../resources/testharness.js"></script>
 <script src="../../resources/testharnessreport.js"></script>
-</head>
 <body>
 <script>
-var wtu = WebGLTestUtils;
-var tiu = TexImageUtils;
-var gl = null;
-var internalFormat = "RGBA";
-var pixelFormat = "RGBA";
-var pixelType = "UNSIGNED_BYTE";
-
-function generateTest()
-{
-    var bitmaps = [];
-
-    var canvas = document.createElement('canvas');
-    canvas.width = 4;
-    canvas.height = 4;
-    document.body.appendChild(canvas);
-    gl = canvas.getContext("webgl");
-
-    gl.clearColor(0,0,0,1);
-    gl.clearDepth(1);
-
-    var options = {resizeWidth: 4, resizeHeight: 4, resizeQuality: "high"};
-    var p1 = createImageBitmap(image, options).then(
-        function(imageBitmap) { bitmaps.defaultOption = imageBitmap });
-
-    options.imageOrientation = "none";
-    options.premultiplyAlpha = "premultiply";
-    var p2 = createImageBitmap(image, options).then(
-        function(imageBitmap) { bitmaps.noFlipYPremul = imageBitmap });
-
-    options.premultiplyAlpha = "default";
-    var p3 = createImageBitmap(image, options).then(
-        function(imageBitmap) { bitmaps.noFlipYDefault = imageBitmap });
-
-    options.premultiplyAlpha = "none";
-    var p4 = createImageBitmap(image, options).then(
-        function(imageBitmap) { bitmaps.noFlipYUnpremul = imageBitmap });
-
-    options.imageOrientation = "flipY";
-    options.premultiplyAlpha = "premultiply";
-    var p5 = createImageBitmap(image, options).then(
-        function(imageBitmap) { bitmaps.flipYPremul = imageBitmap });
-
-    options.premultiplyAlpha = "default";
-    var p6 = createImageBitmap(image, options).then(
-        function(imageBitmap) { bitmaps.flipYDefault = imageBitmap });
-
-    options.premultiplyAlpha = "none";
-    var p7 = createImageBitmap(image, options).then(
-        function(imageBitmap) { bitmaps.flipYUnpremul = imageBitmap });
-
-    options = {resizeWidth: 4, resizeHeight: 4, resizeQuality: "high"};
-    var p8 = createImageBitmap(image, options).then(
-        function(imageBitmap) { bitmaps.colorSpaceDef = imageBitmap });
-
-    options.colorSpaceConversion = "none";
-    var p9 = createImageBitmap(image, options).then(
-        function(imageBitmap) { bitmaps.colorSpaceNone = imageBitmap });
-
-    options.colorSpaceConversion = "default";
-    var p10 = createImageBitmap(image, options).then(
-        function(imageBitmap) { bitmaps.colorSpaceDefault = imageBitmap });
-
-    return Promise.all([p1, p2, p3, p4, p5, p6, p7, p8, p9, p10]).then(
-        t.step_func_done(function() {
-            var alphaVal = 0.5;
-            var testPassed = runTest(bitmaps, alphaVal, true);
-            if (!testPassed)
-                assert_true(false, 'Test failed');
-        }), t.step_func_done(function() {
-            assert_true(false, 'Promise rejected');
-    }));
-}
-
-var t = async_test("createImageBitmap(HTMLImageElement) with resize and other options");
 
 var image = new Image();
-image.onload = t.step_func(function() {
-    generateTest();
-});
+var testOptions = {sourceName: "HTMLImageElement", imageSource: image,
+                   sourceIsPremul: true, resizeWidth: 4, resizeHeight: 4};
+prepareWebGLContext();
+
+image.onload = function() {
+    prepareResizedImageBitmapsAndRuntTests(testOptions);
+};
+
 image.src = 'resources/red-green-semi-transparent-2x2.png';
+
 </script>
-</body>
-</html>
diff --git a/third_party/WebKit/LayoutTests/fast/webgl/texImage-imageBitmap-from-imageData-resize.html b/third_party/WebKit/LayoutTests/fast/webgl/texImage-imageBitmap-from-imageData-resize.html
index ae094c8..4ce8185 100644
--- a/third_party/WebKit/LayoutTests/fast/webgl/texImage-imageBitmap-from-imageData-resize.html
+++ b/third_party/WebKit/LayoutTests/fast/webgl/texImage-imageBitmap-from-imageData-resize.html
@@ -1,91 +1,24 @@
-<!DOCTYPE html>
 <html>
-<head>
 <script src="./resources/webgl-test-utils-full.js"></script>
 <script src="./resources/tex-image-and-sub-image-utils.js"></script>
 <script src="./resources/tex-image-and-sub-image-image-bitmap-utils-resize.js"></script>
 <script src="../../resources/testharness.js"></script>
 <script src="../../resources/testharnessreport.js"></script>
-</head>
 <body>
 <script>
-var wtu = WebGLTestUtils;
-var tiu = TexImageUtils;
-var gl = null;
-var internalFormat = "RGBA";
-var pixelFormat = "RGBA";
-var pixelType = "UNSIGNED_BYTE";
 
-promise_test(function() {
-    var bitmaps = [];
+var imageData = new ImageData(new Uint8ClampedArray(
+                              [255, 0, 0, 255,
+                               255, 0, 0, 26,
+                               0, 255, 0, 255,
+                               0, 255, 0, 26]),
+                               2, 2);
 
-    var canvas = document.createElement('canvas');
-    canvas.width = 4;
-    canvas.height = 4;
-    gl = canvas.getContext("webgl");
+var testOptions = {sourceName: "ImageData",
+                   imageSource: imageData, sourceIsPremul: false,
+                   resizeWidth: 4, resizeHeight: 4};
 
-    gl.clearColor(0,0,0,1);
-    gl.clearDepth(1);
+prepareWebGLContext();
+prepareResizedImageBitmapsAndRuntTests(testOptions);
 
-    var imageData = new ImageData(new Uint8ClampedArray(
-                                  [255, 0, 0, 255,
-                                   255, 0, 0, 26,
-                                   0, 255, 0, 255,
-                                   0, 255, 0, 26]),
-                                   2, 2);
-
-    var options = {resizeWidth: 4, resizeHeight: 4, resizeQuality: "high"};
-    var p1 = createImageBitmap(imageData, options).then(
-        function(imageBitmap) { bitmaps.defaultOption = imageBitmap });
-
-    options.imageOrientation = "none";
-    options.premultiplyAlpha = "premultiply";
-    var p2 = createImageBitmap(imageData, options).then(
-        function(imageBitmap) { bitmaps.noFlipYPremul = imageBitmap });
-
-    options.premultiplyAlpha = "default";
-    var p3 = createImageBitmap(imageData, options).then(
-        function(imageBitmap) { bitmaps.noFlipYDefault = imageBitmap });
-
-    options.premultiplyAlpha = "none";
-    var p4 = createImageBitmap(imageData, options).then(
-        function(imageBitmap) { bitmaps.noFlipYUnpremul = imageBitmap });
-
-    options.imageOrientation = "flipY";
-    options.premultiplyAlpha = "premultiply";
-    var p5 = createImageBitmap(imageData, options).then(
-        function(imageBitmap) { bitmaps.flipYPremul = imageBitmap });
-
-    options.premultiplyAlpha = "default";
-    var p6 = createImageBitmap(imageData, options).then(
-        function(imageBitmap) { bitmaps.flipYDefault = imageBitmap });
-
-    options.premultiplyAlpha = "none";
-    var p7 = createImageBitmap(imageData, options).then(
-        function(imageBitmap) { bitmaps.flipYUnpremul = imageBitmap });
-
-    options = {resizeWidth: 4, resizeHeight: 4, resizeQuality: "high"};
-    var p8 = createImageBitmap(imageData, options).then(
-        function(imageBitmap) { bitmaps.colorSpaceDef = imageBitmap });
-
-    options.colorSpaceConversion = "none";
-    var p9 = createImageBitmap(imageData, options).then(
-        function(imageBitmap) { bitmaps.colorSpaceNone = imageBitmap });
-
-    options.colorSpaceConversion = "default";
-    var p10 = createImageBitmap(imageData, options).then(
-        function(imageBitmap) { bitmaps.colorSpaceDefault = imageBitmap });
-
-    return Promise.all([p1, p2, p3, p4, p5, p6, p7, p8, p9, p10]).then(
-        function() {
-            var alphaVal = 0.5;
-            var testPassed = runTest(bitmaps, alphaVal, false);
-            if (!testPassed)
-                assert_true(false, 'Test failed');
-        }, function() {
-            assert_true(false, 'Promise rejected');
-    });
-}, 'createImageBitmap(ImageData) with resize and other options');
-</script>
-</body>
-</html>
+</script>
\ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/fast/webgl/texImage-imageBitmap-from-offscreen-canvas-resize.html b/third_party/WebKit/LayoutTests/fast/webgl/texImage-imageBitmap-from-offscreen-canvas-resize.html
index 90f943f..2d06e9f8 100644
--- a/third_party/WebKit/LayoutTests/fast/webgl/texImage-imageBitmap-from-offscreen-canvas-resize.html
+++ b/third_party/WebKit/LayoutTests/fast/webgl/texImage-imageBitmap-from-offscreen-canvas-resize.html
@@ -1,6 +1,4 @@
-<!DOCTYPE html>
 <html>
-<head>
 <script src="./resources/webgl-test-utils-full.js"></script>
 <script src="./resources/tex-image-and-sub-image-utils.js"></script>
 <script src="./resources/tex-image-and-sub-image-image-bitmap-utils-resize.js"></script>
@@ -8,12 +6,6 @@
 <script src="../../resources/testharnessreport.js"></script>
 <body>
 <script>
-var wtu = WebGLTestUtils;
-var tiu = TexImageUtils;
-var gl = null;
-var internalFormat = "RGBA";
-var pixelFormat = "RGBA";
-var pixelType = "UNSIGNED_BYTE";
 
 function setCanvasToRedGreen(ctx) {
     var width = ctx.canvas.width;
@@ -30,74 +22,17 @@
     ctx.fillRect(halfWidth, halfHeight, halfWidth, halfHeight);
 }
 
-promise_test(function() {
-    var bitmaps = [];
+var testCanvas = document.createElement('canvas');
+testCanvas.width = 2;
+testCanvas.height = 2;
+var offscreen = testCanvas.transferControlToOffscreen();
+var ctx = offscreen.getContext("2d");
+setCanvasToRedGreen(ctx);
 
-    var canvas = document.createElement('canvas');
-    canvas.width = 4;
-    canvas.height = 4;
-    document.body.appendChild(canvas);
-    gl = canvas.getContext("webgl");
+var testOptions = {sourceName: "OffscreenCanvas", imageSource: offscreen,
+                   sourceIsPremul: true, resizeWidth: 4, resizeHeight: 4};
 
-    gl.clearColor(0,0,0,1);
-    gl.clearDepth(1);
+prepareWebGLContext();
+prepareResizedImageBitmapsAndRuntTests(testOptions);
 
-    var testCanvas = document.createElement('canvas');
-    testCanvas.width = 2;
-    testCanvas.height = 2;
-    var offscreen = testCanvas.transferControlToOffscreen();
-    var ctx = offscreen.getContext('2d');
-    setCanvasToRedGreen(ctx);
-
-    var options = {resizeWidth: 4, resizeHeight: 4, resizeQuality: "high"};
-    var p1 = createImageBitmap(offscreen, options).then(
-        function(imageBitmap) { bitmaps.defaultOption = imageBitmap });
-
-    options.imageOrientation = "none";
-    options.premultiplyAlpha = "premultiply";
-    var p2 = createImageBitmap(offscreen, options).then(
-        function(imageBitmap) { bitmaps.noFlipYPremul = imageBitmap });
-
-    options.premultiplyAlpha = "default";
-    var p3 = createImageBitmap(offscreen, options).then(
-        function(imageBitmap) { bitmaps.noFlipYDefault = imageBitmap });
-
-    options.premultiplyAlpha = "none";
-    var p4 = createImageBitmap(offscreen, options).then(
-        function(imageBitmap) { bitmaps.noFlipYUnpremul = imageBitmap });
-
-    options.imageOrientation = "flipY";
-    options.premultiplyAlpha = "premultiply";
-    var p5 = createImageBitmap(offscreen, options).then(
-        function(imageBitmap) { bitmaps.flipYPremul = imageBitmap });
-
-    options.premultiplyAlpha = "default";
-    var p6 = createImageBitmap(offscreen, options).then(
-        function(imageBitmap) { bitmaps.flipYDefault = imageBitmap });
-
-    options.premultiplyAlpha = "none";
-    var p7 = createImageBitmap(offscreen, options).then(
-        function(imageBitmap) { bitmaps.flipYUnpremul = imageBitmap });
-
-    options = {resizeWidth: 4, resizeHeight: 4, resizeQuality: "high"};
-    var p8 = createImageBitmap(offscreen, options).then(
-        function(imageBitmap) { bitmaps.colorSpaceDef = imageBitmap });
-
-    options.colorSpaceConversion = "none";
-    var p9 = createImageBitmap(offscreen, options).then(
-        function(imageBitmap) { bitmaps.colorSpaceNone = imageBitmap });
-
-    options.colorSpaceConversion = "default";
-    var p10 = createImageBitmap(offscreen, options).then(
-        function(imageBitmap) { bitmaps.colorSpaceDefault = imageBitmap });
-
-    return Promise.all([p1, p2, p3, p4, p5, p6, p7, p8, p9, p10]).then(function() {
-        var alphaVal = 0.5;
-        var testPassed = runTest(bitmaps, alphaVal, false);
-        if (!testPassed)
-            assert_true(false, 'Test failed');
-    }, function() {
-        assert_true(false, 'Promise rejected');
-    });
-}, 'createImageBitmap(HTMLCanvasElement) with resize and other options');
 </script>
diff --git a/third_party/WebKit/LayoutTests/http/tests/credentialmanager/credentialscontainer-create-basics.html b/third_party/WebKit/LayoutTests/http/tests/credentialmanager/credentialscontainer-create-basics.html
index 1dca01c..d9afee3 100644
--- a/third_party/WebKit/LayoutTests/http/tests/credentialmanager/credentialscontainer-create-basics.html
+++ b/third_party/WebKit/LayoutTests/http/tests/credentialmanager/credentialscontainer-create-basics.html
@@ -80,6 +80,13 @@
 
 promise_test(t => {
     mockAuthenticator.setAuthenticatorStatus(
+      webauth.mojom.AuthenticatorStatus.PENDING_REQUEST);
+    return promise_rejects(t, "InvalidStateError",
+        navigator.credentials.create({ publicKey }));
+}, "Verify that pending request error returned by mock is properly handled.");
+
+promise_test(function (t) {
+    mockAuthenticator.setAuthenticatorStatus(
         webauth.mojom.AuthenticatorStatus.UNKNOWN_ERROR);
     return promise_rejects(t, "NotReadableError",
         navigator.credentials.create({ publicKey }));
@@ -169,14 +176,14 @@
     mockAuthenticator.setAuthenticatorStatus(
           webauth.mojom.AuthenticatorStatus.SUCCESS);
 
-    var publicKey = {
+    var custom_public_key = {
         challenge,
         rp: { name: "Acme" },
         user: public_key_user,
         pubKeyCredParams: public_key_parameters,
     };
 
-    return navigator.credentials.create({publicKey: publicKey}).then(r => {
+    return navigator.credentials.create({publicKey: custom_public_key}).then(r => {
         assert_equals(r.id, id, 'id');
         assert_true(r.rawId instanceof ArrayBuffer);
         assert_array_equals(new Uint8Array(r.rawId),
@@ -265,7 +272,7 @@
     mockAuthenticator.setAuthenticatorStatus(
           webauth.mojom.AuthenticatorStatus.SUCCESS);
 
-    var public_key = {
+    var custom_public_key = {
         challenge,
         rp: public_key_rp,
         user: {
@@ -276,7 +283,7 @@
         pubKeyCredParams: public_key_parameters,
     };
 
-    return navigator.credentials.create({publicKey: public_key}).then(r => {
+    return navigator.credentials.create({publicKey: custom_public_key}).then(r => {
         assert_equals(r.id, id, 'id');
         assert_true(r.rawId instanceof ArrayBuffer);
         assert_array_equals(new Uint8Array(r.rawId),
@@ -292,5 +299,4 @@
         assert_not_exists(r.response, 'signature');
     });
 }, "navigator.credentials.create() with missing user.icon");
-
 </script>
diff --git a/third_party/WebKit/LayoutTests/http/tests/css3/filters/fedisplacementmap-tainted.html b/third_party/WebKit/LayoutTests/http/tests/css3/filters/fedisplacementmap-tainted.html
index 0808103..629ec90 100644
--- a/third_party/WebKit/LayoutTests/http/tests/css3/filters/fedisplacementmap-tainted.html
+++ b/third_party/WebKit/LayoutTests/http/tests/css3/filters/fedisplacementmap-tainted.html
@@ -17,7 +17,8 @@
 img.onload = function () {

   var ctx = document.getElementById("canvas").getContext("2d");

   ctx.filter = "url(#filter)";

-

+  // Fill rect will force resolving of the filter before drawImage.

+  ctx.fillRect(-10, -10, 1, 1);

   ctx.drawImage(img, 0, 0);

   window.testRunner.notifyDone();

 }

diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/elements/styles-4/styles-should-not-force-sync-style-recalc.js b/third_party/WebKit/LayoutTests/http/tests/devtools/elements/styles-4/styles-should-not-force-sync-style-recalc.js
index 620c9bd7..c36a1886 100644
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/elements/styles-4/styles-should-not-force-sync-style-recalc.js
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/elements/styles-4/styles-should-not-force-sync-style-recalc.js
@@ -34,13 +34,11 @@
   `);
 
   UI.context.setFlavor(Timeline.TimelinePanel, UI.panels.timeline);
-  PerformanceTestRunner.evaluateWithTimeline('performActions()', callback);
+  await PerformanceTestRunner.evaluateWithTimeline('performActions()');
 
-  function callback() {
-    PerformanceTestRunner.timelineModel().mainThreadEvents().forEach(event => {
-      if (event.name === TimelineModel.TimelineModel.RecordType.UpdateLayoutTree)
-        TestRunner.addResult(event.name);
-    });
-    TestRunner.completeTest();
-  }
+  PerformanceTestRunner.timelineModel().mainThreadEvents().forEach(event => {
+    if (event.name === TimelineModel.TimelineModel.RecordType.UpdateLayoutTree)
+      TestRunner.addResult(event.name);
+  });
+  TestRunner.completeTest();
 })();
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/extensions/extensions-timeline-api.html b/third_party/WebKit/LayoutTests/http/tests/devtools/extensions/extensions-timeline-api.html
index e07194c..3fba3eb 100644
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/extensions/extensions-timeline-api.html
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/extensions/extensions-timeline-api.html
@@ -15,7 +15,7 @@
     setting.set(true);
     TestRunner.addResult(`Provider short display name: ${provider.shortDisplayName()}`);
     TestRunner.addResult(`Provider long display name: ${provider.longDisplayName()}`);
-    PerformanceTestRunner.startTimeline(callback);
+    PerformanceTestRunner.startTimeline().then(callback);
 }
 
 }
@@ -73,7 +73,7 @@
 
 function extension_stopTimeline(callback)
 {
-    evaluateOnFrontend("PerformanceTestRunner.stopTimeline(reply);", callback);
+    evaluateOnFrontend("PerformanceTestRunner.stopTimeline().then(reply);", callback);
 }
 
 function extension_dumpFlameChart(callback)
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/forced-layout-in-microtask.js b/third_party/WebKit/LayoutTests/http/tests/devtools/forced-layout-in-microtask.js
index 276c4e6f..f131b1f 100644
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/forced-layout-in-microtask.js
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/forced-layout-in-microtask.js
@@ -23,9 +23,7 @@
       }
   `);
 
-  PerformanceTestRunner.invokeAsyncWithTimeline('performActions', onTimelineRecorded);
-  function onTimelineRecorded() {
-    PerformanceTestRunner.printTimelineRecordsWithDetails('Layout');
-    TestRunner.completeTest();
-  }
+  await PerformanceTestRunner.invokeAsyncWithTimeline('performActions');
+  PerformanceTestRunner.printTimelineRecordsWithDetails('Layout');
+  TestRunner.completeTest();
 })();
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/service-workers/service-worker-v8-cache.js b/third_party/WebKit/LayoutTests/http/tests/devtools/service-workers/service-worker-v8-cache.js
index 677b450..67b9ccc 100644
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/service-workers/service-worker-v8-cache.js
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/service-workers/service-worker-v8-cache.js
@@ -27,19 +27,14 @@
   const scope = 'resources/v8-cache-iframe.html';
   const frameId = 'frame_id';
 
-  await new Promise(
-        (r) =>
-        PerformanceTestRunner.invokeAsyncWithTimeline(
-            'registerServiceWorkerAndwaitForActivated', r));
+  await PerformanceTestRunner.invokeAsyncWithTimeline('registerServiceWorkerAndwaitForActivated');
   TestRunner.addResult('--- Trace events while installing -------------');
   PerformanceTestRunner.printTimelineRecordsWithDetails(
       TimelineModel.TimelineModel.RecordType.CompileScript);
   TestRunner.addResult('-----------------------------------------------');
   await ApplicationTestRunner.waitForActivated(scope);
   await TestRunner.addIframe(scope, {id: frameId});
-  await new Promise(
-        (r) =>
-        PerformanceTestRunner.invokeAsyncWithTimeline('loadScript', r));
+  await PerformanceTestRunner.invokeAsyncWithTimeline('loadScript');
   TestRunner.addResult('--- Trace events while executing scripts ------');
   PerformanceTestRunner.printTimelineRecordsWithDetails(
       TimelineModel.TimelineModel.RecordType.CompileScript);
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/tracing-session-id.js b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing-session-id.js
index 18fac19..8ffbfa8 100644
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/tracing-session-id.js
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing-session-id.js
@@ -12,16 +12,14 @@
       </p>
     `);
 
-  PerformanceTestRunner.evaluateWithTimeline('(function() {})', processTracingEvents);
+  await PerformanceTestRunner.evaluateWithTimeline('(function() {})');
 
-  function processTracingEvents() {
-    PerformanceTestRunner.tracingModel().sortedProcesses().forEach(function(process) {
-      process.sortedThreads().forEach(function(thread) {
-        thread.events().forEach(processEvent);
-      });
+  PerformanceTestRunner.tracingModel().sortedProcesses().forEach(function(process) {
+    process.sortedThreads().forEach(function(thread) {
+      thread.events().forEach(processEvent);
     });
-    TestRunner.completeTest();
-  }
+  });
+  TestRunner.completeTest();
 
   function processEvent(event) {
     var metadataEvents = [
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/anonymous-image-object.js b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/anonymous-image-object.js
index bd5f583..2c1ab8d6 100644
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/anonymous-image-object.js
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/anonymous-image-object.js
@@ -32,10 +32,7 @@
       }
   `);
 
-  PerformanceTestRunner.invokeAsyncWithTimeline('doActions', onRecordingDone);
-
-  function onRecordingDone() {
-    TestRunner.addResult('DONE');
-    TestRunner.completeTest();
-  }
+  await PerformanceTestRunner.invokeAsyncWithTimeline('doActions');
+  TestRunner.addResult('DONE');
+  TestRunner.completeTest();
 })();
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/console-timeline.js b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/console-timeline.js
index c2493e1f..da6130e 100644
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/console-timeline.js
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/console-timeline.js
@@ -82,30 +82,21 @@
   `);
 
   TestRunner.runTestSuite([
-    function testStartStopTimeline(next) {
-      PerformanceTestRunner.evaluateWithTimeline('startStopTimeline()', allEventsReceived);
-
-      function allEventsReceived() {
-        printTimelineAndTimestampEvents();
-        next();
-      }
+    async function testStartStopTimeline(next) {
+      await PerformanceTestRunner.evaluateWithTimeline('startStopTimeline()');
+      printTimelineAndTimestampEvents();
+      next();
     },
 
-    function testStartStopMultiple(next) {
-      PerformanceTestRunner.evaluateWithTimeline('startStopMultiple()', allEventsReceived);
-
-      function allEventsReceived() {
-        printTimelineAndTimestampEvents();
-        next();
-      }
+    async function testStartStopMultiple(next) {
+      await PerformanceTestRunner.evaluateWithTimeline('startStopMultiple()');
+      printTimelineAndTimestampEvents();
+      next();
     },
 
-    function testStartMultipleStopInsideEvals(next) {
-      PerformanceTestRunner.startTimeline(step1);
-
-      function step1() {
-        TestRunner.evaluateInPage('startMultiple()', step2);
-      }
+    async function testStartMultipleStopInsideEvals(next) {
+      await PerformanceTestRunner.startTimeline();
+      TestRunner.evaluateInPage('startMultiple()', step2);
 
       function step2() {
         TestRunner.evaluateInPage('stopTwo()', step3);
@@ -115,41 +106,29 @@
         TestRunner.evaluateInPage('stopOne()', step4);
       }
 
-      function step4() {
-        PerformanceTestRunner.stopTimeline(finish);
-      }
-
-      function finish() {
+      async function step4() {
+        await PerformanceTestRunner.stopTimeline();
         printTimelineAndTimestampEvents();
         next();
       }
     },
 
-    function testStopUnknown(next) {
-      PerformanceTestRunner.evaluateWithTimeline('stopUnknown()', allEventsReceived);
-
-      function allEventsReceived() {
-        printTimelineAndTimestampEvents();
-        next();
-      }
+    async function testStopUnknown(next) {
+      await PerformanceTestRunner.evaluateWithTimeline('stopUnknown()');
+      printTimelineAndTimestampEvents();
+      next();
     },
 
-    function testStartFromPanel(next) {
-      PerformanceTestRunner.evaluateWithTimeline('startStopTimeline()', finish);
-
-      function finish() {
-        printTimelineAndTimestampEvents();
-        next();
-      }
+    async function testStartFromPanel(next) {
+      await PerformanceTestRunner.evaluateWithTimeline('startStopTimeline()');
+      printTimelineAndTimestampEvents();
+      next();
     },
 
-    function testStopFromPanel(next) {
-      PerformanceTestRunner.evaluateWithTimeline('startTimeline()', finish);
-
-      function finish() {
-        printTimelineAndTimestampEvents();
-        next();
-      }
+    async function testStopFromPanel(next) {
+      await PerformanceTestRunner.evaluateWithTimeline('startTimeline()');
+      printTimelineAndTimestampEvents();
+      next();
     }
   ]);
 
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-js/timeline-gc-event.js b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-js/timeline-gc-event.js
index f27246a0..ad49930 100644
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-js/timeline-gc-event.js
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-js/timeline-gc-event.js
@@ -14,15 +14,13 @@
       }
   `);
 
-  PerformanceTestRunner.invokeAsyncWithTimeline('produceGarbageForGCEvents', validate);
+  await PerformanceTestRunner.invokeAsyncWithTimeline('produceGarbageForGCEvents');
 
-  function validate() {
-    var gcEvent = PerformanceTestRunner.findTimelineEvent(TimelineModel.TimelineModel.RecordType.MajorGC) ||
-        PerformanceTestRunner.findTimelineEvent(TimelineModel.TimelineModel.RecordType.MinorGC);
-    if (gcEvent)
-      TestRunner.addResult('SUCCESS: Found expected GC event record');
-    else
-      TestRunner.addResult('FAIL: GC event record wasn\'t found');
-    TestRunner.completeTest();
-  }
+  const gcEvent = PerformanceTestRunner.findTimelineEvent(TimelineModel.TimelineModel.RecordType.MajorGC) ||
+      PerformanceTestRunner.findTimelineEvent(TimelineModel.TimelineModel.RecordType.MinorGC);
+  if (gcEvent)
+    TestRunner.addResult('SUCCESS: Found expected GC event record');
+  else
+    TestRunner.addResult(`FAIL: GC event record wasn't found`);
+  TestRunner.completeTest();
 })();
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-js/timeline-microtasks.js b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-js/timeline-microtasks.js
index fc7b75e..d0eed56 100644
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-js/timeline-microtasks.js
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-js/timeline-microtasks.js
@@ -26,12 +26,9 @@
       }
   `);
 
-  PerformanceTestRunner.invokeAsyncWithTimeline('performActions', finish);
-
-  function finish() {
-    var event = PerformanceTestRunner.timelineModel().mainThreadEvents().find(
-        e => e.name === TimelineModel.TimelineModel.RecordType.RunMicrotasks);
-    PerformanceTestRunner.printTraceEventProperties(event);
-    TestRunner.completeTest();
-  }
+  await PerformanceTestRunner.invokeAsyncWithTimeline('performActions');
+  const event = PerformanceTestRunner.timelineModel().mainThreadEvents().find(
+      e => e.name === TimelineModel.TimelineModel.RecordType.RunMicrotasks);
+  PerformanceTestRunner.printTraceEventProperties(event);
+  TestRunner.completeTest();
 })();
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-js/timeline-runtime-stats.js b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-js/timeline-runtime-stats.js
index 8a8c596a..fba65b33 100644
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-js/timeline-runtime-stats.js
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-js/timeline-runtime-stats.js
@@ -24,15 +24,13 @@
 
   Runtime.experiments.enableForTest('timelineV8RuntimeCallStats');
   Runtime.experiments.enableForTest('timelineShowAllEvents');
-  PerformanceTestRunner.evaluateWithTimeline('performActions()', finish);
+  await PerformanceTestRunner.evaluateWithTimeline('performActions()');
 
-  function finish() {
-    var frame = PerformanceTestRunner.timelineModel()
-                    .mainThreadEvents()
-                    .filter(e => e.name === TimelineModel.TimelineModel.RecordType.JSFrame)
-                    .map(e => e.args['data']['callFrame'])
-                    .find(frame => frame.functionName === 'FunctionCallback' && frame.url === 'native V8Runtime');
-    TestRunner.assertTrue(!!frame, 'FunctionCallback frame not found');
-    TestRunner.completeTest();
-  }
+  var frame = PerformanceTestRunner.timelineModel()
+                  .mainThreadEvents()
+                  .filter(e => e.name === TimelineModel.TimelineModel.RecordType.JSFrame)
+                  .map(e => e.args['data']['callFrame'])
+                  .find(frame => frame.functionName === 'FunctionCallback' && frame.url === 'native V8Runtime');
+  TestRunner.assertTrue(!!frame, 'FunctionCallback frame not found');
+  TestRunner.completeTest();
 })();
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-js/timeline-script-id-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-js/timeline-script-id-expected.txt
index ec669246..08a0a3a 100644
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-js/timeline-script-id-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-js/timeline-script-id-expected.txt
@@ -1,14 +1,14 @@
 Test that checks location resolving mechanics for TimerInstall TimerRemove and FunctionCall events with scriptId.
        It expects two FunctionCall for InjectedScript, two TimerInstall events, two FunctionCall events and one TimerRemove event to be logged with performActions.js script name and some line number.
 
+detailsTextContent for TimerInstall event: 'performActions.js:32'
+details.textContent for TimerInstall event: 'performActions.js:32'
 detailsTextContent for TimerInstall event: 'performActions.js:33'
 details.textContent for TimerInstall event: 'performActions.js:33'
-detailsTextContent for TimerInstall event: 'performActions.js:34'
-details.textContent for TimerInstall event: 'performActions.js:34'
-detailsTextContent for FunctionCall event: 'performActions.js:38'
-details.textContent for FunctionCall event: 'intervalTimerWork @ performActions.js:38'
-detailsTextContent for FunctionCall event: 'performActions.js:38'
-details.textContent for FunctionCall event: 'intervalTimerWork @ performActions.js:38'
-detailsTextContent for TimerRemove event: 'performActions.js:41'
-details.textContent for TimerRemove event: 'performActions.js:41'
+detailsTextContent for FunctionCall event: 'performActions.js:37'
+details.textContent for FunctionCall event: 'intervalTimerWork @ performActions.js:37'
+detailsTextContent for FunctionCall event: 'performActions.js:37'
+details.textContent for FunctionCall event: 'intervalTimerWork @ performActions.js:37'
+detailsTextContent for TimerRemove event: 'performActions.js:40'
+details.textContent for TimerRemove event: 'performActions.js:40'
 
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-js/timeline-script-id.js b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-js/timeline-script-id.js
index a9d97968..ea6279c 100644
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-js/timeline-script-id.js
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-js/timeline-script-id.js
@@ -25,17 +25,16 @@
     }
   }
 
-  var source = performActions.toString();
-  source += '\n//# sourceURL=performActions.js';
-  TestRunner.evaluateInPage(source, startTimeline);
+  const source = performActions.toString() + '\n//# sourceURL=performActions.js';
+  await new Promise(resolve => TestRunner.evaluateInPage(source, resolve));
 
-  function startTimeline() {
-    PerformanceTestRunner.invokeAsyncWithTimeline('performActions', finish);
-  }
+  const linkifier = new Components.Linkifier();
+  const recordTypes = new Set(['TimerInstall', 'TimerRemove', 'FunctionCall']);
 
-  var linkifier = new Components.Linkifier();
+  await PerformanceTestRunner.invokeAsyncWithTimeline('performActions');
+  PerformanceTestRunner.walkTimelineEventTree(formatter);
+  TestRunner.completeTest();
 
-  var recordTypes = new Set(['TimerInstall', 'TimerRemove', 'FunctionCall']);
   function formatter(event) {
     if (!recordTypes.has(event.name))
       return;
@@ -51,9 +50,4 @@
     TestRunner.addResult(
         'details.textContent for ' + event.name + ' event: \'' + details.textContent.replace(/VM[\d]+/, 'VM') + '\'');
   }
-
-  function finish() {
-    PerformanceTestRunner.walkTimelineEventTree(formatter);
-    TestRunner.completeTest();
-  }
 })();
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-js/timeline-script-tag-1.js b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-js/timeline-script-tag-1.js
index fc4a382..ba0a906d 100644
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-js/timeline-script-tag-1.js
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-js/timeline-script-tag-1.js
@@ -17,24 +17,17 @@
   `);
 
   UI.panels.timeline._disableCaptureJSProfileSetting.set(true);
-  PerformanceTestRunner.startTimeline(step1);
-  function step1() {
-    ConsoleTestRunner.addConsoleSniffer(step2);
-    TestRunner.evaluateInPage('performActions()');
-  }
+  await PerformanceTestRunner.startTimeline();
+  TestRunner.evaluateInPage('performActions()');
+  await ConsoleTestRunner.waitUntilMessageReceivedPromise();
+  await PerformanceTestRunner.stopTimeline();
 
-  function step2() {
-    PerformanceTestRunner.stopTimeline(step3);
-  }
-
-  function step3() {
-    PerformanceTestRunner.timelineModel().mainThreadEvents().forEach(event => {
-      if (event.name === TimelineModel.TimelineModel.RecordType.EvaluateScript) {
-        PerformanceTestRunner.printTraceEventProperties(event);
-      } else if (event.name === TimelineModel.TimelineModel.RecordType.TimeStamp) {
-        TestRunner.addResult(`----> ${Timeline.TimelineUIUtils.eventTitle(event)}`);
-      }
-    });
-    TestRunner.completeTest();
-  }
+  PerformanceTestRunner.timelineModel().mainThreadEvents().forEach(event => {
+    if (event.name === TimelineModel.TimelineModel.RecordType.EvaluateScript) {
+      PerformanceTestRunner.printTraceEventProperties(event);
+    } else if (event.name === TimelineModel.TimelineModel.RecordType.TimeStamp) {
+      TestRunner.addResult(`----> ${Timeline.TimelineUIUtils.eventTitle(event)}`);
+    }
+  });
+  TestRunner.completeTest();
 })();
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-js/timeline-script-tag-2.js b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-js/timeline-script-tag-2.js
index cd69558..d5f1473 100644
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-js/timeline-script-tag-2.js
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-js/timeline-script-tag-2.js
@@ -16,18 +16,11 @@
       }
   `);
 
-  PerformanceTestRunner.startTimeline(step1);
-  function step1() {
-    ConsoleTestRunner.addConsoleSniffer(step2);
-    TestRunner.evaluateInPage('performActions()');
-  }
+  await PerformanceTestRunner.startTimeline();
+  TestRunner.evaluateInPage('performActions()');
+  await ConsoleTestRunner.waitUntilMessageReceivedPromise();
 
-  function step2() {
-    PerformanceTestRunner.stopTimeline(step3);
-  }
-
-  function step3() {
-    PerformanceTestRunner.printTimelineRecords('EvaluateScript');
-    TestRunner.completeTest();
-  }
+  await PerformanceTestRunner.stopTimeline();
+  PerformanceTestRunner.printTimelineRecords('EvaluateScript');
+  TestRunner.completeTest();
 })();
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-layout/timeline-layout-reason.js b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-layout/timeline-layout-reason.js
index 7b24bc8f..dcb868f 100644
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-layout/timeline-layout-reason.js
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-layout/timeline-layout-reason.js
@@ -32,13 +32,11 @@
       }
   `);
 
-  PerformanceTestRunner.evaluateWithTimeline('performActions()', onTimelineRecorded);
-  function onTimelineRecorded() {
-    var event = PerformanceTestRunner.findTimelineEvent(TimelineModel.TimelineModel.RecordType.Layout);
-    var initiator = TimelineModel.TimelineData.forEvent(event).initiator();
-    TestRunner.addResult(
-        'layout invalidated: ' + TimelineModel.TimelineData.forEvent(initiator).stackTrace[0].functionName);
-    TestRunner.addResult('layout forced: ' + TimelineModel.TimelineData.forEvent(event).stackTrace[0].functionName);
-    TestRunner.completeTest();
-  }
+  await PerformanceTestRunner.evaluateWithTimeline('performActions()');
+  var event = PerformanceTestRunner.findTimelineEvent(TimelineModel.TimelineModel.RecordType.Layout);
+  var initiator = TimelineModel.TimelineData.forEvent(event).initiator();
+  TestRunner.addResult(
+      'layout invalidated: ' + TimelineModel.TimelineData.forEvent(initiator).stackTrace[0].functionName);
+  TestRunner.addResult('layout forced: ' + TimelineModel.TimelineData.forEvent(event).stackTrace[0].functionName);
+  TestRunner.completeTest();
 })();
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-layout/timeline-layout-with-invalidations.js b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-layout/timeline-layout-with-invalidations.js
index 943d6056..59c96ed 100644
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-layout/timeline-layout-with-invalidations.js
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-layout/timeline-layout-with-invalidations.js
@@ -34,24 +34,22 @@
   Runtime.experiments.enableForTest('timelineInvalidationTracking');
 
   TestRunner.runTestSuite([
-    function testLocalFrame(next) {
-      PerformanceTestRunner.invokeAsyncWithTimeline('display', function() {
-        PerformanceTestRunner.dumpInvalidations(
-            TimelineModel.TimelineModel.RecordType.Layout, 0, 'first layout invalidations');
-        PerformanceTestRunner.dumpInvalidations(
-            TimelineModel.TimelineModel.RecordType.Layout, 1, 'second layout invalidations');
-        next();
-      });
+    async function testLocalFrame(next) {
+      await PerformanceTestRunner.invokeAsyncWithTimeline('display');
+      PerformanceTestRunner.dumpInvalidations(
+          TimelineModel.TimelineModel.RecordType.Layout, 0, 'first layout invalidations');
+      PerformanceTestRunner.dumpInvalidations(
+          TimelineModel.TimelineModel.RecordType.Layout, 1, 'second layout invalidations');
+      next();
     },
 
-    function testSubframe(next) {
-      PerformanceTestRunner.invokeAsyncWithTimeline('updateSubframeAndDisplay', function() {
-        PerformanceTestRunner.dumpInvalidations(
-            TimelineModel.TimelineModel.RecordType.Layout, 0, 'first layout invalidations');
-        PerformanceTestRunner.dumpInvalidations(
-            TimelineModel.TimelineModel.RecordType.Layout, 1, 'second layout invalidations');
-        next();
-      });
+    async function testSubframe(next) {
+      await PerformanceTestRunner.invokeAsyncWithTimeline('updateSubframeAndDisplay');
+      PerformanceTestRunner.dumpInvalidations(
+          TimelineModel.TimelineModel.RecordType.Layout, 0, 'first layout invalidations');
+      PerformanceTestRunner.dumpInvalidations(
+          TimelineModel.TimelineModel.RecordType.Layout, 1, 'second layout invalidations');
+      next();
     }
   ]);
 })();
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-misc/timeline-animation-frame.js b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-misc/timeline-animation-frame.js
index 8948de8..be9430d9 100644
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-misc/timeline-animation-frame.js
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-misc/timeline-animation-frame.js
@@ -22,12 +22,10 @@
       }
   `);
 
-  PerformanceTestRunner.invokeAsyncWithTimeline('performActions', finish);
+  await PerformanceTestRunner.invokeAsyncWithTimeline('performActions');
 
-  function finish() {
-    PerformanceTestRunner.printTimelineRecordsWithDetails('RequestAnimationFrame');
-    PerformanceTestRunner.printTimelineRecordsWithDetails('FireAnimationFrame');
-    PerformanceTestRunner.printTimelineRecordsWithDetails('CancelAnimationFrame');
-    TestRunner.completeTest();
-  }
+  PerformanceTestRunner.printTimelineRecordsWithDetails('RequestAnimationFrame');
+  PerformanceTestRunner.printTimelineRecordsWithDetails('FireAnimationFrame');
+  PerformanceTestRunner.printTimelineRecordsWithDetails('CancelAnimationFrame');
+  TestRunner.completeTest();
 })();
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-misc/timeline-bound-function.js b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-misc/timeline-bound-function.js
index 52e6027..4f536611 100644
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-misc/timeline-bound-function.js
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-misc/timeline-bound-function.js
@@ -21,17 +21,15 @@
       }
   `);
 
-  PerformanceTestRunner.evaluateWithTimeline('performActions()', finish);
+  await PerformanceTestRunner.evaluateWithTimeline('performActions()');
 
-  function finish() {
-    PerformanceTestRunner.timelineModel().mainThreadEvents().forEach(event => {
-      if (event.name !== TimelineModel.TimelineModel.RecordType.FunctionCall)
-        return;
-      var data = event.args['data'];
-      var scriptName = data.scriptName;
-      var scriptNameShort = scriptName.substring(scriptName.lastIndexOf('/') + 1);
-      TestRunner.addResult(`${event.name} ${scriptNameShort}: ${data.scriptLine}`);
-    });
-    TestRunner.completeTest();
-  }
+  PerformanceTestRunner.timelineModel().mainThreadEvents().forEach(event => {
+    if (event.name !== TimelineModel.TimelineModel.RecordType.FunctionCall)
+      return;
+    var data = event.args['data'];
+    var scriptName = data.scriptName;
+    var scriptNameShort = scriptName.substring(scriptName.lastIndexOf('/') + 1);
+    TestRunner.addResult(`${event.name} ${scriptNameShort}: ${data.scriptLine}`);
+  });
+  TestRunner.completeTest();
 })();
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-misc/timeline-event-causes.js b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-misc/timeline-event-causes.js
index 74af7cb82..33a87bc4 100644
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-misc/timeline-event-causes.js
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-misc/timeline-event-causes.js
@@ -17,7 +17,7 @@
   }
 
   TestRunner.runTestSuite([
-    function testTimerInstall(next) {
+    async function testTimerInstall(next) {
       function setTimeoutFunction() {
         return new Promise((fulfill) => setTimeout(fulfill, 0));
       }
@@ -26,23 +26,22 @@
       source += '\n//# sourceURL=setTimeoutFunction.js';
       TestRunner.evaluateInPage(source);
 
-      PerformanceTestRunner.invokeAsyncWithTimeline('setTimeoutFunction', finishAndRunNextTest);
-      function finishAndRunNextTest() {
-        var linkifier = new Components.Linkifier();
-        var event = PerformanceTestRunner.findTimelineEvent('TimerFire');
-        TestRunner.check(event, 'Should receive a TimerFire event.');
-        var contentHelper = new Timeline.TimelineDetailsContentHelper(
-            PerformanceTestRunner.timelineModel().targetByEvent(event), linkifier, true);
-        Timeline.TimelineUIUtils._generateCauses(
-            event, PerformanceTestRunner.timelineModel().targetByEvent(event), null, contentHelper);
-        var causes = contentHelper.element.deepTextContent();
-        TestRunner.check(causes, 'Should generate causes');
-        checkStringContains(causes, 'Timer Installed\nPromise @ setTimeoutFunction.js:');
-        next();
-      }
+      await PerformanceTestRunner.invokeAsyncWithTimeline('setTimeoutFunction');
+
+      var linkifier = new Components.Linkifier();
+      var event = PerformanceTestRunner.findTimelineEvent('TimerFire');
+      TestRunner.check(event, 'Should receive a TimerFire event.');
+      var contentHelper = new Timeline.TimelineDetailsContentHelper(
+          PerformanceTestRunner.timelineModel().targetByEvent(event), linkifier, true);
+      Timeline.TimelineUIUtils._generateCauses(
+          event, PerformanceTestRunner.timelineModel().targetByEvent(event), null, contentHelper);
+      var causes = contentHelper.element.deepTextContent();
+      TestRunner.check(causes, 'Should generate causes');
+      checkStringContains(causes, 'Timer Installed\nPromise @ setTimeoutFunction.js:');
+      next();
     },
 
-    function testRequestAnimationFrame(next) {
+    async function testRequestAnimationFrame(next) {
       function requestAnimationFrameFunction(callback) {
         return new Promise((fulfill) => requestAnimationFrame(fulfill));
       }
@@ -51,23 +50,21 @@
       source += '\n//# sourceURL=requestAnimationFrameFunction.js';
       TestRunner.evaluateInPage(source);
 
-      PerformanceTestRunner.invokeAsyncWithTimeline('requestAnimationFrameFunction', finishAndRunNextTest);
-      function finishAndRunNextTest() {
-        var linkifier = new Components.Linkifier();
-        var event = PerformanceTestRunner.findTimelineEvent('FireAnimationFrame');
-        TestRunner.check(event, 'Should receive a FireAnimationFrame event.');
-        var contentHelper = new Timeline.TimelineDetailsContentHelper(
-            PerformanceTestRunner.timelineModel().targetByEvent(event), linkifier, true);
-        Timeline.TimelineUIUtils._generateCauses(
-            event, PerformanceTestRunner.timelineModel().targetByEvent(event), null, contentHelper);
-        var causes = contentHelper.element.deepTextContent();
-        TestRunner.check(causes, 'Should generate causes');
-        checkStringContains(causes, 'Animation Frame Requested\nPromise @ requestAnimationFrameFunction.js:');
-        next();
-      }
+      await PerformanceTestRunner.invokeAsyncWithTimeline('requestAnimationFrameFunction');
+      var linkifier = new Components.Linkifier();
+      var event = PerformanceTestRunner.findTimelineEvent('FireAnimationFrame');
+      TestRunner.check(event, 'Should receive a FireAnimationFrame event.');
+      var contentHelper = new Timeline.TimelineDetailsContentHelper(
+          PerformanceTestRunner.timelineModel().targetByEvent(event), linkifier, true);
+      Timeline.TimelineUIUtils._generateCauses(
+          event, PerformanceTestRunner.timelineModel().targetByEvent(event), null, contentHelper);
+      var causes = contentHelper.element.deepTextContent();
+      TestRunner.check(causes, 'Should generate causes');
+      checkStringContains(causes, 'Animation Frame Requested\nPromise @ requestAnimationFrameFunction.js:');
+      next();
     },
 
-    function testStyleRecalc(next) {
+    async function testStyleRecalc(next) {
       function styleRecalcFunction() {
         var element = document.getElementById('testElement');
         element.style.backgroundColor = 'papayawhip';
@@ -78,23 +75,21 @@
       source += '\n//# sourceURL=styleRecalcFunction.js';
       TestRunner.evaluateInPage(source);
 
-      PerformanceTestRunner.evaluateWithTimeline('styleRecalcFunction()', finishAndRunNextTest);
-      function finishAndRunNextTest() {
-        var linkifier = new Components.Linkifier();
-        var event = PerformanceTestRunner.findTimelineEvent('UpdateLayoutTree');
-        TestRunner.check(event, 'Should receive a UpdateLayoutTree event.');
-        var contentHelper = new Timeline.TimelineDetailsContentHelper(
-            PerformanceTestRunner.timelineModel().targetByEvent(event), linkifier, true);
-        Timeline.TimelineUIUtils._generateCauses(
-            event, PerformanceTestRunner.timelineModel().targetByEvent(event), null, contentHelper);
-        var causes = contentHelper.element.deepTextContent();
-        TestRunner.check(causes, 'Should generate causes');
-        checkStringContains(causes, 'First Invalidated\nstyleRecalcFunction @ styleRecalcFunction.js:');
-        next();
-      }
+      await PerformanceTestRunner.evaluateWithTimeline('styleRecalcFunction()');
+      var linkifier = new Components.Linkifier();
+      var event = PerformanceTestRunner.findTimelineEvent('UpdateLayoutTree');
+      TestRunner.check(event, 'Should receive a UpdateLayoutTree event.');
+      var contentHelper = new Timeline.TimelineDetailsContentHelper(
+          PerformanceTestRunner.timelineModel().targetByEvent(event), linkifier, true);
+      Timeline.TimelineUIUtils._generateCauses(
+          event, PerformanceTestRunner.timelineModel().targetByEvent(event), null, contentHelper);
+      var causes = contentHelper.element.deepTextContent();
+      TestRunner.check(causes, 'Should generate causes');
+      checkStringContains(causes, 'First Invalidated\nstyleRecalcFunction @ styleRecalcFunction.js:');
+      next();
     },
 
-    function testLayout(next) {
+    async function testLayout(next) {
       function layoutFunction() {
         var element = document.getElementById('testElement');
         element.style.width = '200px';
@@ -105,21 +100,19 @@
       source += '\n//# sourceURL=layoutFunction.js';
       TestRunner.evaluateInPage(source);
 
-      PerformanceTestRunner.evaluateWithTimeline('layoutFunction()', finishAndRunNextTest);
-      function finishAndRunNextTest() {
-        var linkifier = new Components.Linkifier();
-        var event = PerformanceTestRunner.findTimelineEvent('Layout');
-        TestRunner.check(event, 'Should receive a Layout event.');
-        var contentHelper = new Timeline.TimelineDetailsContentHelper(
-            PerformanceTestRunner.timelineModel().targetByEvent(event), linkifier, true);
-        Timeline.TimelineUIUtils._generateCauses(
-            event, PerformanceTestRunner.timelineModel().targetByEvent(event), null, contentHelper);
-        var causes = contentHelper.element.deepTextContent();
-        TestRunner.check(causes, 'Should generate causes');
-        checkStringContains(causes, 'Layout Forced\nlayoutFunction @ layoutFunction.js:');
-        checkStringContains(causes, 'First Layout Invalidation\nlayoutFunction @ layoutFunction.js:');
-        next();
-      }
+      await PerformanceTestRunner.evaluateWithTimeline('layoutFunction()');
+      var linkifier = new Components.Linkifier();
+      var event = PerformanceTestRunner.findTimelineEvent('Layout');
+      TestRunner.check(event, 'Should receive a Layout event.');
+      var contentHelper = new Timeline.TimelineDetailsContentHelper(
+          PerformanceTestRunner.timelineModel().targetByEvent(event), linkifier, true);
+      Timeline.TimelineUIUtils._generateCauses(
+          event, PerformanceTestRunner.timelineModel().targetByEvent(event), null, contentHelper);
+      var causes = contentHelper.element.deepTextContent();
+      TestRunner.check(causes, 'Should generate causes');
+      checkStringContains(causes, 'Layout Forced\nlayoutFunction @ layoutFunction.js:');
+      checkStringContains(causes, 'First Layout Invalidation\nlayoutFunction @ layoutFunction.js:');
+      next();
     }
   ]);
 })();
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-misc/timeline-node-reference.js b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-misc/timeline-node-reference.js
index 7221708..53529d6 100644
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-misc/timeline-node-reference.js
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-misc/timeline-node-reference.js
@@ -30,8 +30,11 @@
       }
   `);
 
-  TestRunner.evaluateInPage('var unused = document.body.offsetWidth;', function() {
-    PerformanceTestRunner.evaluateWithTimeline('performActions()', onTimelineRecorded);
+  TestRunner.evaluateInPage('var unused = document.body.offsetWidth;', async function() {
+    const records = await PerformanceTestRunner.evaluateWithTimeline('performActions()');
+    const layoutEvent = PerformanceTestRunner.findTimelineEvent(TimelineModel.TimelineModel.RecordType.Layout);
+    UI.context.addFlavorChangeListener(SDK.DOMNode, onSelectedNodeChanged);
+    clickValueLink(layoutEvent, 'Layout root');
   });
 
   async function clickValueLink(event, row) {
@@ -46,12 +49,6 @@
     }
   }
 
-  function onTimelineRecorded(records) {
-    var layoutEvent = PerformanceTestRunner.findTimelineEvent(TimelineModel.TimelineModel.RecordType.Layout);
-    UI.context.addFlavorChangeListener(SDK.DOMNode, onSelectedNodeChanged);
-    clickValueLink(layoutEvent, 'Layout root');
-  }
-
   function onSelectedNodeChanged() {
     var node = UI.panels.elements.selectedDOMNode();
     // We may first get an old selected node while switching to the Elements panel.
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-misc/timeline-trivial.js b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-misc/timeline-trivial.js
index e89913c6..714a4919 100644
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-misc/timeline-trivial.js
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-misc/timeline-trivial.js
@@ -8,9 +8,7 @@
   await TestRunner.showPanel('timeline');
 
   /* This test seems silly, but originally it tickled bug 31080 */
-  function callback() {
-    TestRunner.addResult('Timeline started');
-    TestRunner.completeTest();
-  }
-  PerformanceTestRunner.startTimeline(callback);
+  await PerformanceTestRunner.startTimeline();
+  TestRunner.addResult('Timeline started');
+  TestRunner.completeTest();
 })();
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-network-received-data.js b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-network-received-data.js
index a9ac100..330f54c8 100644
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-network-received-data.js
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-network-received-data.js
@@ -24,16 +24,14 @@
       }
   `);
 
-  PerformanceTestRunner.invokeAsyncWithTimeline('performActions', done);
+  await PerformanceTestRunner.invokeAsyncWithTimeline('performActions');
 
-  function done() {
-    TestRunner.addResult('Script evaluated.');
-    var event = PerformanceTestRunner.findTimelineEvent('ResourceReceivedData');
-    if (event) {
-      var data = event.args['data'];
-      if (data && typeof data.encodedDataLength === 'number')
-        TestRunner.addResult('Resource received data has length, test passed.');
-    }
-    TestRunner.completeTest();
+  TestRunner.addResult('Script evaluated.');
+  var event = PerformanceTestRunner.findTimelineEvent('ResourceReceivedData');
+  if (event) {
+    var data = event.args['data'];
+    if (data && typeof data.encodedDataLength === 'number')
+      TestRunner.addResult('Resource received data has length, test passed.');
   }
+  TestRunner.completeTest();
 })();
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-network/timeline-network-resource.js b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-network/timeline-network-resource.js
index 288cb88..b0a80a3 100644
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-network/timeline-network-resource.js
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-network/timeline-network-resource.js
@@ -23,20 +23,18 @@
   var requestId;
   var scriptUrl = 'timeline-network-resource.js';
 
-  PerformanceTestRunner.invokeAsyncWithTimeline('performActions', finish);
+  await PerformanceTestRunner.invokeAsyncWithTimeline('performActions');
 
-  function finish() {
-    var model = PerformanceTestRunner.timelineModel();
-    model.mainThreadEvents().forEach(event => {
-      if (event.name === TimelineModel.TimelineModel.RecordType.ResourceSendRequest)
-        printSend(event);
-      else if (event.name === TimelineModel.TimelineModel.RecordType.ResourceReceiveResponse)
-        printReceive(event);
-      else if (event.name === TimelineModel.TimelineModel.RecordType.ResourceFinish)
-        printFinish(event);
-    });
-    TestRunner.completeTest();
-  }
+  var model = PerformanceTestRunner.timelineModel();
+  model.mainThreadEvents().forEach(event => {
+    if (event.name === TimelineModel.TimelineModel.RecordType.ResourceSendRequest)
+      printSend(event);
+    else if (event.name === TimelineModel.TimelineModel.RecordType.ResourceReceiveResponse)
+      printReceive(event);
+    else if (event.name === TimelineModel.TimelineModel.RecordType.ResourceFinish)
+      printFinish(event);
+  });
+  TestRunner.completeTest();
 
   function printEvent(event) {
     TestRunner.addResult('');
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-paint/layer-tree.js b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-paint/layer-tree.js
index 75a8174..5b56188a 100644
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-paint/layer-tree.js
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-paint/layer-tree.js
@@ -33,15 +33,11 @@
 
   UI.panels.timeline._captureLayersAndPicturesSetting.set(true);
 
-  PerformanceTestRunner.invokeAsyncWithTimeline('doActions', step1);
-  function step1() {
-    var frames = PerformanceTestRunner.timelineFrameModel().frames();
-    var lastFrame = PerformanceTestRunner.timelineFrameModel().frames().peekLast();
-    lastFrame.layerTree.layerTreePromise().then(TestRunner.safeWrap(layerTreeResolved));
-  }
+  await PerformanceTestRunner.invokeAsyncWithTimeline('doActions');
+  const frames = PerformanceTestRunner.timelineFrameModel().frames();
+  const lastFrame = PerformanceTestRunner.timelineFrameModel().frames().peekLast();
+  const layerTreeModel = await lastFrame.layerTree.layerTreePromise();
+  LayersTestRunner.dumpLayerTree(undefined, layerTreeModel.contentRoot());
 
-  function layerTreeResolved(layerTreeModel) {
-    LayersTestRunner.dumpLayerTree(undefined, layerTreeModel.contentRoot());
-    TestRunner.completeTest();
-  }
+  TestRunner.completeTest();
 })();
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-paint/paint-profiler-update.js b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-paint/paint-profiler-update.js
index 3c7cafa..1fdd171 100644
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-paint/paint-profiler-update.js
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-paint/paint-profiler-update.js
@@ -36,26 +36,24 @@
   panel._captureLayersAndPicturesSetting.set(true);
   panel._onModeChanged();
 
-  PerformanceTestRunner.invokeAsyncWithTimeline('performActions', onRecordingDone);
   var paintEvents = [];
-  function onRecordingDone() {
-    var events = PerformanceTestRunner.timelineModel()._mainThreadEvents;
-    for (var event of events) {
-      if (event.name === TimelineModel.TimelineModel.RecordType.Paint) {
-        paintEvents.push(event);
-        if (!TimelineModel.TimelineData.forEvent(event).picture)
-          TestRunner.addResult('Event without picture at ' + paintEvents.length);
-      }
+  await PerformanceTestRunner.invokeAsyncWithTimeline('performActions');
+  var events = PerformanceTestRunner.timelineModel()._mainThreadEvents;
+  for (var event of events) {
+    if (event.name === TimelineModel.TimelineModel.RecordType.Paint) {
+      paintEvents.push(event);
+      if (!TimelineModel.TimelineData.forEvent(event).picture)
+        TestRunner.addResult('Event without picture at ' + paintEvents.length);
     }
-
-    if (paintEvents.length < 2)
-      throw new Error('FAIL: Expect at least two paint events');
-
-    TestRunner.addSniffer(
-        panel._flameChart._detailsView, '_appendDetailsTabsForTraceEventAndShowDetails', onRecordDetailsReady, false);
-    panel.select(Timeline.TimelineSelection.fromTraceEvent(paintEvents[0]));
   }
 
+  if (paintEvents.length < 2)
+    throw new Error('FAIL: Expect at least two paint events');
+
+  TestRunner.addSniffer(
+      panel._flameChart._detailsView, '_appendDetailsTabsForTraceEventAndShowDetails', onRecordDetailsReady, false);
+  panel.select(Timeline.TimelineSelection.fromTraceEvent(paintEvents[0]));
+
   function onRecordDetailsReady() {
     var updateCount = 0;
 
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-paint/timeline-paint-and-multiple-style-invalidations.js b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-paint/timeline-paint-and-multiple-style-invalidations.js
index 6b5a6b9a79..6652a045 100644
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-paint/timeline-paint-and-multiple-style-invalidations.js
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-paint/timeline-paint-and-multiple-style-invalidations.js
@@ -35,20 +35,18 @@
   `);
 
   Runtime.experiments.enableForTest('timelineInvalidationTracking');
-  PerformanceTestRunner.invokeAsyncWithTimeline('multipleStyleRecalcsAndDisplay', testMultipleStyleRecalcs);
+  await PerformanceTestRunner.invokeAsyncWithTimeline('multipleStyleRecalcsAndDisplay');
 
-  function testMultipleStyleRecalcs() {
-    PerformanceTestRunner.dumpInvalidations(
-        TimelineModel.TimelineModel.RecordType.UpdateLayoutTree, 0, 'first style recalc');
-    PerformanceTestRunner.dumpInvalidations(
-        TimelineModel.TimelineModel.RecordType.UpdateLayoutTree, 1, 'second style recalc');
-    PerformanceTestRunner.dumpInvalidations(TimelineModel.TimelineModel.RecordType.Paint, 0, 'first paint');
+  PerformanceTestRunner.dumpInvalidations(
+      TimelineModel.TimelineModel.RecordType.UpdateLayoutTree, 0, 'first style recalc');
+  PerformanceTestRunner.dumpInvalidations(
+      TimelineModel.TimelineModel.RecordType.UpdateLayoutTree, 1, 'second style recalc');
+  PerformanceTestRunner.dumpInvalidations(TimelineModel.TimelineModel.RecordType.Paint, 0, 'first paint');
+  var thirdRecalc =
+      PerformanceTestRunner.findTimelineEvent(TimelineModel.TimelineModel.RecordType.UpdateLayoutTree, 2);
+  TestRunner.assertTrue(thirdRecalc === undefined, 'There should be no additional style recalc records.');
+  var secondPaint = PerformanceTestRunner.findTimelineEvent(TimelineModel.TimelineModel.RecordType.Paint, 1);
+  TestRunner.assertTrue(secondPaint === undefined, 'There should be no additional paint records.');
 
-    var thirdRecalc =
-        PerformanceTestRunner.findTimelineEvent(TimelineModel.TimelineModel.RecordType.UpdateLayoutTree, 2);
-    TestRunner.assertTrue(thirdRecalc === undefined, 'There should be no additional style recalc records.');
-    var secondPaint = PerformanceTestRunner.findTimelineEvent(TimelineModel.TimelineModel.RecordType.Paint, 1);
-    TestRunner.assertTrue(secondPaint === undefined, 'There should be no additional paint records.');
-    TestRunner.completeTest();
-  }
+  TestRunner.completeTest();
 })();
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-paint/timeline-paint-with-layout-invalidations-on-deleted-node.js b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-paint/timeline-paint-with-layout-invalidations-on-deleted-node.js
index 32e2c57b..a3a293fe 100644
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-paint/timeline-paint-with-layout-invalidations-on-deleted-node.js
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-paint/timeline-paint-with-layout-invalidations-on-deleted-node.js
@@ -35,26 +35,24 @@
   Runtime.experiments.enableForTest('timelineInvalidationTracking');
 
   TestRunner.runTestSuite([
-    function testLocalFrame(next) {
-      PerformanceTestRunner.invokeAsyncWithTimeline('display', function() {
-        PerformanceTestRunner.dumpInvalidations(TimelineModel.TimelineModel.RecordType.Paint, 0, 'paint invalidations');
-        next();
-      });
+    async function testLocalFrame(next) {
+      await PerformanceTestRunner.invokeAsyncWithTimeline('display');
+      PerformanceTestRunner.dumpInvalidations(TimelineModel.TimelineModel.RecordType.Paint, 0, 'paint invalidations');
+      next();
     },
 
-    function testSubframe(next) {
-      PerformanceTestRunner.invokeAsyncWithTimeline('updateSubframeAndDisplay', function() {
-        // The first paint corresponds to the local frame and should have no invalidations.
-        var firstPaintEvent = PerformanceTestRunner.findTimelineEvent(TimelineModel.TimelineModel.RecordType.Paint);
-        var firstInvalidations = TimelineModel.InvalidationTracker.invalidationEventsFor(firstPaintEvent);
-        TestRunner.assertEquals(firstInvalidations, null);
+    async function testSubframe(next) {
+      await PerformanceTestRunner.invokeAsyncWithTimeline('updateSubframeAndDisplay');
+      // The first paint corresponds to the local frame and should have no invalidations.
+      var firstPaintEvent = PerformanceTestRunner.findTimelineEvent(TimelineModel.TimelineModel.RecordType.Paint);
+      var firstInvalidations = TimelineModel.InvalidationTracker.invalidationEventsFor(firstPaintEvent);
+      TestRunner.assertEquals(firstInvalidations, null);
 
-        // The second paint corresponds to the subframe and should have our layout/style invalidations.
-        PerformanceTestRunner.dumpInvalidations(
-            TimelineModel.TimelineModel.RecordType.Paint, 1, 'second paint invalidations');
+      // The second paint corresponds to the subframe and should have our layout/style invalidations.
+      PerformanceTestRunner.dumpInvalidations(
+          TimelineModel.TimelineModel.RecordType.Paint, 1, 'second paint invalidations');
 
-        next();
-      });
+      next();
     }
   ]);
 })();
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-paint/timeline-paint-with-layout-invalidations.js b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-paint/timeline-paint-with-layout-invalidations.js
index e17b8cf..72a2840 100644
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-paint/timeline-paint-with-layout-invalidations.js
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-paint/timeline-paint-with-layout-invalidations.js
@@ -31,25 +31,23 @@
   Runtime.experiments.enableForTest('timelineInvalidationTracking');
 
   TestRunner.runTestSuite([
-    function testLocalFrame(next) {
-      PerformanceTestRunner.invokeAsyncWithTimeline('display', function() {
-        PerformanceTestRunner.dumpInvalidations(TimelineModel.TimelineModel.RecordType.Paint, 0, 'paint invalidations');
-        next();
-      });
+    async function testLocalFrame(next) {
+      await PerformanceTestRunner.invokeAsyncWithTimeline('display');
+      PerformanceTestRunner.dumpInvalidations(TimelineModel.TimelineModel.RecordType.Paint, 0, 'paint invalidations');
+      next();
     },
 
-    function testSubframe(next) {
-      PerformanceTestRunner.invokeAsyncWithTimeline('updateSubframeAndDisplay', function() {
-        // The first paint corresponds to the local frame and should have no invalidations.
-        var firstPaintEvent = PerformanceTestRunner.findTimelineEvent(TimelineModel.TimelineModel.RecordType.Paint);
-        var firstInvalidations = TimelineModel.InvalidationTracker.invalidationEventsFor(firstPaintEvent);
-        TestRunner.assertEquals(firstInvalidations, null);
+   async function testSubframe(next) {
+      await PerformanceTestRunner.invokeAsyncWithTimeline('updateSubframeAndDisplay');
+      // The first paint corresponds to the local frame and should have no invalidations.
+      var firstPaintEvent = PerformanceTestRunner.findTimelineEvent(TimelineModel.TimelineModel.RecordType.Paint);
+      var firstInvalidations = TimelineModel.InvalidationTracker.invalidationEventsFor(firstPaintEvent);
+      TestRunner.assertEquals(firstInvalidations, null);
 
-        // The second paint corresponds to the subframe and should have our layout/style invalidations.
-        PerformanceTestRunner.dumpInvalidations(
-            TimelineModel.TimelineModel.RecordType.Paint, 1, 'second paint invalidations');
-        next();
-      });
+      // The second paint corresponds to the subframe and should have our layout/style invalidations.
+      PerformanceTestRunner.dumpInvalidations(
+          TimelineModel.TimelineModel.RecordType.Paint, 1, 'second paint invalidations');
+      next();
     }
   ]);
 })();
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-paint/timeline-paint-with-style-recalc-invalidations.js b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-paint/timeline-paint-with-style-recalc-invalidations.js
index fe8d86db..cc73c009 100644
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-paint/timeline-paint-with-style-recalc-invalidations.js
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-paint/timeline-paint-with-style-recalc-invalidations.js
@@ -29,26 +29,24 @@
   Runtime.experiments.enableForTest('timelineInvalidationTracking');
 
   TestRunner.runTestSuite([
-    function testLocalFrame(next) {
-      PerformanceTestRunner.invokeAsyncWithTimeline('display', function() {
-        PerformanceTestRunner.dumpInvalidations(
-            TimelineModel.TimelineModel.RecordType.Paint, 0, 'first paint invalidations');
-        next();
-      });
+    async function testLocalFrame(next) {
+      await PerformanceTestRunner.invokeAsyncWithTimeline('display');
+      PerformanceTestRunner.dumpInvalidations(
+          TimelineModel.TimelineModel.RecordType.Paint, 0, 'first paint invalidations');
+      next();
     },
 
-    function testSubframe(next) {
-      PerformanceTestRunner.invokeAsyncWithTimeline('updateSubframeAndDisplay', function() {
-        // The first paint corresponds to the local frame and should have no invalidations.
-        var firstPaintEvent = PerformanceTestRunner.findTimelineEvent(TimelineModel.TimelineModel.RecordType.Paint);
-        var firstInvalidations = TimelineModel.InvalidationTracker.invalidationEventsFor(firstPaintEvent);
-        TestRunner.assertEquals(firstInvalidations, null);
+    async function testSubframe(next) {
+      await PerformanceTestRunner.invokeAsyncWithTimeline('updateSubframeAndDisplay');
+      // The first paint corresponds to the local frame and should have no invalidations.
+      var firstPaintEvent = PerformanceTestRunner.findTimelineEvent(TimelineModel.TimelineModel.RecordType.Paint);
+      var firstInvalidations = TimelineModel.InvalidationTracker.invalidationEventsFor(firstPaintEvent);
+      TestRunner.assertEquals(firstInvalidations, null);
 
-        // The second paint corresponds to the subframe and should have our style invalidations.
-        PerformanceTestRunner.dumpInvalidations(
-            TimelineModel.TimelineModel.RecordType.Paint, 1, 'second paint invalidations');
-        next();
-      });
+      // The second paint corresponds to the subframe and should have our style invalidations.
+      PerformanceTestRunner.dumpInvalidations(
+          TimelineModel.TimelineModel.RecordType.Paint, 1, 'second paint invalidations');
+      next();
     }
   ]);
 })();
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-paint/timeline-paint.js b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-paint/timeline-paint.js
index 37d5dd1..c8529924 100644
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-paint/timeline-paint.js
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-paint/timeline-paint.js
@@ -23,37 +23,33 @@
       }
   `);
 
-  PerformanceTestRunner.invokeAsyncWithTimeline('display', step1);
+  await PerformanceTestRunner.invokeAsyncWithTimeline('display');
 
-  function step1() {
-    var event = PerformanceTestRunner.findTimelineEvent(TimelineModel.TimelineModel.RecordType.Paint);
-    if (event)
-      PerformanceTestRunner.printTraceEventProperties(event);
-    else
-      TestRunner.addResult('FAIL: no paint record found');
-    PerformanceTestRunner.invokeAsyncWithTimeline('updateSubframeAndDisplay', step3);
-  }
+  var event = PerformanceTestRunner.findTimelineEvent(TimelineModel.TimelineModel.RecordType.Paint);
+  if (event)
+    PerformanceTestRunner.printTraceEventProperties(event);
+  else
+    TestRunner.addResult('FAIL: no paint record found');
+  await PerformanceTestRunner.invokeAsyncWithTimeline('updateSubframeAndDisplay');
 
-  function step3() {
-    var events = PerformanceTestRunner.timelineModel().mainThreadEvents().filter(
-        e => e.name === TimelineModel.TimelineModel.RecordType.Paint);
-    TestRunner.assertGreaterOrEqual(events.length, 2, 'Paint record with subframe paint not found');
-    var topQuad = events[0].args['data'].clip;
-    var subframePaint = events[1];
-    TestRunner.assertGreaterOrEqual(
-        events[0].endTime, subframePaint.endTime, 'Subframe paint is not a child of frame paint');
-    var subframeQuad = subframePaint.args['data'].clip;
-    TestRunner.assertEquals(8, topQuad.length);
-    TestRunner.assertEquals(8, subframeQuad.length);
-    TestRunner.assertGreaterOrEqual(subframeQuad[0], topQuad[0]);
-    TestRunner.assertGreaterOrEqual(subframeQuad[1], topQuad[1]);
-    TestRunner.assertGreaterOrEqual(topQuad[2], subframeQuad[2]);
-    TestRunner.assertGreaterOrEqual(subframeQuad[3], topQuad[3]);
-    TestRunner.assertGreaterOrEqual(topQuad[4], subframeQuad[4]);
-    TestRunner.assertGreaterOrEqual(topQuad[5], subframeQuad[5]);
-    TestRunner.assertGreaterOrEqual(subframeQuad[6], topQuad[6]);
-    TestRunner.assertGreaterOrEqual(topQuad[7], subframeQuad[7]);
+  var events = PerformanceTestRunner.timelineModel().mainThreadEvents().filter(
+      e => e.name === TimelineModel.TimelineModel.RecordType.Paint);
+  TestRunner.assertGreaterOrEqual(events.length, 2, 'Paint record with subframe paint not found');
+  var topQuad = events[0].args['data'].clip;
+  var subframePaint = events[1];
+  TestRunner.assertGreaterOrEqual(
+      events[0].endTime, subframePaint.endTime, 'Subframe paint is not a child of frame paint');
+  var subframeQuad = subframePaint.args['data'].clip;
+  TestRunner.assertEquals(8, topQuad.length);
+  TestRunner.assertEquals(8, subframeQuad.length);
+  TestRunner.assertGreaterOrEqual(subframeQuad[0], topQuad[0]);
+  TestRunner.assertGreaterOrEqual(subframeQuad[1], topQuad[1]);
+  TestRunner.assertGreaterOrEqual(topQuad[2], subframeQuad[2]);
+  TestRunner.assertGreaterOrEqual(subframeQuad[3], topQuad[3]);
+  TestRunner.assertGreaterOrEqual(topQuad[4], subframeQuad[4]);
+  TestRunner.assertGreaterOrEqual(topQuad[5], subframeQuad[5]);
+  TestRunner.assertGreaterOrEqual(subframeQuad[6], topQuad[6]);
+  TestRunner.assertGreaterOrEqual(topQuad[7], subframeQuad[7]);
 
-    TestRunner.completeTest();
-  }
+  TestRunner.completeTest();
 })();
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-receive-response-event.js b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-receive-response-event.js
index 28bedd80..c108320 100644
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-receive-response-event.js
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-receive-response-event.js
@@ -30,34 +30,32 @@
   UI.viewManager.showView('timeline');
   const panel = UI.panels.timeline;
   panel._disableCaptureJSProfileSetting.set(true);
-  PerformanceTestRunner.invokeAsyncWithTimeline('performActions', finish);
+  await PerformanceTestRunner.invokeAsyncWithTimeline('performActions');
 
-  function finish() {
-    var recordTypes = TimelineModel.TimelineModel.RecordType;
-    var typesToDump = new Set([
-      recordTypes.ResourceSendRequest, recordTypes.ResourceReceiveResponse, recordTypes.ResourceReceivedData,
-      recordTypes.ResourceFinish, recordTypes.EventDispatch, recordTypes.FunctionCall
-    ]);
-    let hasAlreadyDumptReceivedDataFor = new Map();
-    function dumpEvent(traceEvent, level) {
-      // Ignore stray paint & rendering events for better stability.
-      var categoryName = Timeline.TimelineUIUtils.eventStyle(traceEvent).category.name;
-      if (categoryName !== 'loading' && categoryName !== 'scripting')
+  var recordTypes = TimelineModel.TimelineModel.RecordType;
+  var typesToDump = new Set([
+    recordTypes.ResourceSendRequest, recordTypes.ResourceReceiveResponse, recordTypes.ResourceReceivedData,
+    recordTypes.ResourceFinish, recordTypes.EventDispatch, recordTypes.FunctionCall
+  ]);
+  let hasAlreadyDumptReceivedDataFor = new Map();
+  function dumpEvent(traceEvent, level) {
+    // Ignore stray paint & rendering events for better stability.
+    var categoryName = Timeline.TimelineUIUtils.eventStyle(traceEvent).category.name;
+    if (categoryName !== 'loading' && categoryName !== 'scripting')
+      return;
+    if (traceEvent.name === 'ResourceReceivedData') {
+      const requestId = traceEvent.args['data']['requestId'];
+      // Dump only the first ResourceReceivedData for a request for stability.
+      if (hasAlreadyDumptReceivedDataFor[requestId])
         return;
-      if (traceEvent.name === 'ResourceReceivedData') {
-        const requestId = traceEvent.args['data']['requestId'];
-        // Dump only the first ResourceReceivedData for a request for stability.
-        if (hasAlreadyDumptReceivedDataFor[requestId])
-          return;
-        hasAlreadyDumptReceivedDataFor[requestId] = true;
-      }
-
-      // Here and below: pretend coalesced record are just not there, as coalescation is time dependent and, hence, not stable.
-      // Filter out InjectedScript function call because they happen out of sync.
-      if (typesToDump.has(traceEvent.name) && (traceEvent.name !== 'FunctionCall' || traceEvent.args['data']['url']))
-        TestRunner.addResult('    '.repeat(level - 1) + traceEvent.name);
+      hasAlreadyDumptReceivedDataFor[requestId] = true;
     }
-    PerformanceTestRunner.walkTimelineEventTree(dumpEvent);
-    TestRunner.completeTest();
+
+    // Here and below: pretend coalesced record are just not there, as coalescation is time dependent and, hence, not stable.
+    // Filter out InjectedScript function call because they happen out of sync.
+    if (typesToDump.has(traceEvent.name) && (traceEvent.name !== 'FunctionCall' || traceEvent.args['data']['url']))
+      TestRunner.addResult('    '.repeat(level - 1) + traceEvent.name);
   }
+  PerformanceTestRunner.walkTimelineEventTree(dumpEvent);
+  TestRunner.completeTest();
 })();
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-script-parse.js b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-script-parse.js
index ffadb74..293d2b9c 100644
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-script-parse.js
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-script-parse.js
@@ -21,14 +21,12 @@
       }
   `);
 
-  PerformanceTestRunner.invokeAsyncWithTimeline('performActions', finish);
+  await PerformanceTestRunner.invokeAsyncWithTimeline('performActions');
 
-  function finish() {
-    const tracingModel = PerformanceTestRunner.tracingModel();
-    tracingModel.sortedProcesses().forEach(p => p.sortedThreads().forEach(t => t.events().forEach(event => {
-      if (event.name === TimelineModel.TimelineModel.RecordType.ParseScriptOnBackground)
-        PerformanceTestRunner.printTraceEventPropertiesWithDetails(event);
-    })));
-    TestRunner.completeTest();
-  }
+  const tracingModel = PerformanceTestRunner.tracingModel();
+  tracingModel.sortedProcesses().forEach(p => p.sortedThreads().forEach(t => t.events().forEach(event => {
+    if (event.name === TimelineModel.TimelineModel.RecordType.ParseScriptOnBackground)
+      PerformanceTestRunner.printTraceEventPropertiesWithDetails(event);
+  })));
+  TestRunner.completeTest();
 })();
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-style/timeline-style-recalc-all-invalidator-types.js b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-style/timeline-style-recalc-all-invalidator-types.js
index 6b3ebfb..a754037 100644
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-style/timeline-style-recalc-all-invalidator-types.js
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-style/timeline-style-recalc-all-invalidator-types.js
@@ -86,47 +86,41 @@
   Runtime.experiments.enableForTest('timelineInvalidationTracking');
 
   TestRunner.runTestSuite([
-    function testClassName(next) {
-      PerformanceTestRunner.invokeAsyncWithTimeline('changeClassNameAndDisplay', function() {
-        PerformanceTestRunner.dumpInvalidations(TimelineModel.TimelineModel.RecordType.UpdateLayoutTree, 0);
-        next();
-      });
+    async function testClassName(next) {
+      await PerformanceTestRunner.invokeAsyncWithTimeline('changeClassNameAndDisplay');
+      PerformanceTestRunner.dumpInvalidations(TimelineModel.TimelineModel.RecordType.UpdateLayoutTree, 0);
+      next();
     },
 
-    function testIdWithoutStyleChange(next) {
-      PerformanceTestRunner.invokeAsyncWithTimeline('changeIdWithoutStyleChangeAndDisplay', function() {
-        var event = PerformanceTestRunner.findTimelineEvent(TimelineModel.TimelineModel.RecordType.UpdateLayoutTree);
-        TestRunner.assertTrue(!event, 'There should be no style recalculation for an id change without style changes.');
-        next();
-      });
+    async function testIdWithoutStyleChange(next) {
+      await PerformanceTestRunner.invokeAsyncWithTimeline('changeIdWithoutStyleChangeAndDisplay');
+      var event = PerformanceTestRunner.findTimelineEvent(TimelineModel.TimelineModel.RecordType.UpdateLayoutTree);
+      TestRunner.assertTrue(!event, 'There should be no style recalculation for an id change without style changes.');
+      next();
     },
 
-    function testId(next) {
-      PerformanceTestRunner.invokeAsyncWithTimeline('changeIdAndDisplay', function() {
-        PerformanceTestRunner.dumpInvalidations(TimelineModel.TimelineModel.RecordType.UpdateLayoutTree, 0);
-        next();
-      });
+    async function testId(next) {
+      await PerformanceTestRunner.invokeAsyncWithTimeline('changeIdAndDisplay');
+      PerformanceTestRunner.dumpInvalidations(TimelineModel.TimelineModel.RecordType.UpdateLayoutTree, 0);
+      next();
     },
 
-    function testStyleAttributeChange(next) {
-      PerformanceTestRunner.invokeAsyncWithTimeline('changeStyleAttributeAndDisplay', function() {
-        PerformanceTestRunner.dumpInvalidations(TimelineModel.TimelineModel.RecordType.UpdateLayoutTree, 0);
-        next();
-      });
+    async function testStyleAttributeChange(next) {
+      await PerformanceTestRunner.invokeAsyncWithTimeline('changeStyleAttributeAndDisplay');
+      PerformanceTestRunner.dumpInvalidations(TimelineModel.TimelineModel.RecordType.UpdateLayoutTree, 0);
+      next();
     },
 
-    function testAttributeChange(next) {
-      PerformanceTestRunner.invokeAsyncWithTimeline('changeAttributeAndDisplay', function() {
-        PerformanceTestRunner.dumpInvalidations(TimelineModel.TimelineModel.RecordType.UpdateLayoutTree, 0);
-        next();
-      });
+    async function testAttributeChange(next) {
+      await PerformanceTestRunner.invokeAsyncWithTimeline('changeAttributeAndDisplay');
+      PerformanceTestRunner.dumpInvalidations(TimelineModel.TimelineModel.RecordType.UpdateLayoutTree, 0);
+      next();
     },
 
-    function testPseudoChange(next) {
-      PerformanceTestRunner.invokeAsyncWithTimeline('changePseudoAndDisplay', function() {
-        PerformanceTestRunner.dumpInvalidations(TimelineModel.TimelineModel.RecordType.UpdateLayoutTree, 0);
-        next();
-      });
+    async function testPseudoChange(next) {
+      await PerformanceTestRunner.invokeAsyncWithTimeline('changePseudoAndDisplay');
+      PerformanceTestRunner.dumpInvalidations(TimelineModel.TimelineModel.RecordType.UpdateLayoutTree, 0);
+      next();
     }
   ]);
 })();
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-style/timeline-style-recalc-with-invalidations.js b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-style/timeline-style-recalc-with-invalidations.js
index dbaec3c2..109a962 100644
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-style/timeline-style-recalc-with-invalidations.js
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-style/timeline-style-recalc-with-invalidations.js
@@ -50,32 +50,29 @@
   Runtime.experiments.enableForTest('timelineInvalidationTracking');
 
   TestRunner.runTestSuite([
-    function testLocalFrame(next) {
-      PerformanceTestRunner.invokeAsyncWithTimeline('changeStylesAndDisplay', function() {
-        PerformanceTestRunner.dumpInvalidations(
-            TimelineModel.TimelineModel.RecordType.UpdateLayoutTree, 0, 'first recalc style invalidations');
-        next();
-      });
+    async function testLocalFrame(next) {
+      await PerformanceTestRunner.invokeAsyncWithTimeline('changeStylesAndDisplay');
+      PerformanceTestRunner.dumpInvalidations(
+          TimelineModel.TimelineModel.RecordType.UpdateLayoutTree, 0, 'first recalc style invalidations');
+      next();
     },
 
-    function multipleStyleRecalcs(next) {
-      PerformanceTestRunner.invokeAsyncWithTimeline('changeMultipleStylesAndDisplay', function() {
-        PerformanceTestRunner.dumpInvalidations(
-            TimelineModel.TimelineModel.RecordType.UpdateLayoutTree, 0, 'first recalc style invalidations');
-        PerformanceTestRunner.dumpInvalidations(
-            TimelineModel.TimelineModel.RecordType.UpdateLayoutTree, 1, 'second recalc style invalidations');
-        PerformanceTestRunner.dumpInvalidations(
-            TimelineModel.TimelineModel.RecordType.UpdateLayoutTree, 2, 'third recalc style invalidations');
-        next();
-      });
+    async function multipleStyleRecalcs(next) {
+      await PerformanceTestRunner.invokeAsyncWithTimeline('changeMultipleStylesAndDisplay');
+      PerformanceTestRunner.dumpInvalidations(
+          TimelineModel.TimelineModel.RecordType.UpdateLayoutTree, 0, 'first recalc style invalidations');
+      PerformanceTestRunner.dumpInvalidations(
+          TimelineModel.TimelineModel.RecordType.UpdateLayoutTree, 1, 'second recalc style invalidations');
+      PerformanceTestRunner.dumpInvalidations(
+          TimelineModel.TimelineModel.RecordType.UpdateLayoutTree, 2, 'third recalc style invalidations');
+      next();
     },
 
-    function testSubframe(next) {
-      PerformanceTestRunner.invokeAsyncWithTimeline('changeSubframeStylesAndDisplay', function() {
-        PerformanceTestRunner.dumpInvalidations(
-            TimelineModel.TimelineModel.RecordType.UpdateLayoutTree, 0, 'first recalc style invalidations');
-        next();
-      });
+    async function testSubframe(next) {
+      await PerformanceTestRunner.invokeAsyncWithTimeline('changeSubframeStylesAndDisplay');
+      PerformanceTestRunner.dumpInvalidations(
+          TimelineModel.TimelineModel.RecordType.UpdateLayoutTree, 0, 'first recalc style invalidations');
+      next();
     }
   ]);
 })();
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-style/timeline-style-recalc-with-invalidator-invalidations.js b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-style/timeline-style-recalc-with-invalidator-invalidations.js
index 288be61..11442552 100644
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-style/timeline-style-recalc-with-invalidator-invalidations.js
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-style/timeline-style-recalc-with-invalidator-invalidations.js
@@ -71,36 +71,33 @@
   Runtime.experiments.enableForTest('timelineInvalidationTracking');
 
   TestRunner.runTestSuite([
-    function testLocalFrame(next) {
-      PerformanceTestRunner.invokeAsyncWithTimeline('changeStylesAndDisplay', function() {
-        PerformanceTestRunner.dumpInvalidations(
-            TimelineModel.TimelineModel.RecordType.UpdateLayoutTree, 0, 'first recalculate styles');
-        next();
-      });
+    async function testLocalFrame(next) {
+      await PerformanceTestRunner.invokeAsyncWithTimeline('changeStylesAndDisplay');
+      PerformanceTestRunner.dumpInvalidations(
+          TimelineModel.TimelineModel.RecordType.UpdateLayoutTree, 0, 'first recalculate styles');
+      next();
     },
 
-    function multipleStyleRecalcs(next) {
-      PerformanceTestRunner.invokeAsyncWithTimeline('changeMultipleStylesAndDisplay', function() {
-        PerformanceTestRunner.dumpInvalidations(
-            TimelineModel.TimelineModel.RecordType.UpdateLayoutTree, 0, 'first recalculate styles');
-        PerformanceTestRunner.dumpInvalidations(
-            TimelineModel.TimelineModel.RecordType.UpdateLayoutTree, 1, 'second recalculate styles');
-        PerformanceTestRunner.dumpInvalidations(
-            TimelineModel.TimelineModel.RecordType.UpdateLayoutTree, 2, 'third recalculate styles');
-        next();
-      });
+    async function multipleStyleRecalcs(next) {
+      await PerformanceTestRunner.invokeAsyncWithTimeline('changeMultipleStylesAndDisplay');
+      PerformanceTestRunner.dumpInvalidations(
+          TimelineModel.TimelineModel.RecordType.UpdateLayoutTree, 0, 'first recalculate styles');
+      PerformanceTestRunner.dumpInvalidations(
+          TimelineModel.TimelineModel.RecordType.UpdateLayoutTree, 1, 'second recalculate styles');
+      PerformanceTestRunner.dumpInvalidations(
+          TimelineModel.TimelineModel.RecordType.UpdateLayoutTree, 2, 'third recalculate styles');
+      next();
     },
 
-    function testSubframe(next) {
-      PerformanceTestRunner.invokeAsyncWithTimeline('changeMultipleSubframeStylesAndDisplay', function() {
-        PerformanceTestRunner.dumpInvalidations(
-            TimelineModel.TimelineModel.RecordType.UpdateLayoutTree, 0, 'first recalculate styles');
-        PerformanceTestRunner.dumpInvalidations(
-            TimelineModel.TimelineModel.RecordType.UpdateLayoutTree, 1, 'second recalculate styles');
-        PerformanceTestRunner.dumpInvalidations(
-            TimelineModel.TimelineModel.RecordType.UpdateLayoutTree, 2, 'third recalculate styles');
-        next();
-      });
+    async function testSubframe(next) {
+      await PerformanceTestRunner.invokeAsyncWithTimeline('changeMultipleSubframeStylesAndDisplay');
+      PerformanceTestRunner.dumpInvalidations(
+          TimelineModel.TimelineModel.RecordType.UpdateLayoutTree, 0, 'first recalculate styles');
+      PerformanceTestRunner.dumpInvalidations(
+          TimelineModel.TimelineModel.RecordType.UpdateLayoutTree, 1, 'second recalculate styles');
+      PerformanceTestRunner.dumpInvalidations(
+          TimelineModel.TimelineModel.RecordType.UpdateLayoutTree, 2, 'third recalculate styles');
+      next();
     }
   ]);
 })();
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-time/timeline-time.js b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-time/timeline-time.js
index 439c780f..76a8c7b 100644
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-time/timeline-time.js
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-time/timeline-time.js
@@ -73,17 +73,15 @@
     }
   ]);
 
-  function performActions(actions, next) {
+  async function performActions(actions, next) {
     var namesToDump = new Set(['FunctionCall', 'ConsoleTime', 'TimeStamp']);
     function dumpName(event, level) {
       if (namesToDump.has(event.name))
         TestRunner.addResult('----'.repeat(level) + '> ' + Timeline.TimelineUIUtils.eventTitle(event));
     }
-    function callback() {
-      PerformanceTestRunner.walkTimelineEventTree(dumpName);
-      next();
-    }
     UI.panels.timeline._disableCaptureJSProfileSetting.set(true);
-    PerformanceTestRunner.evaluateWithTimeline(actions, TestRunner.safeWrap(callback), true);
-  }
+    await PerformanceTestRunner.evaluateWithTimeline(actions);
+    PerformanceTestRunner.walkTimelineEventTree(dumpName);
+    next();
+}
 })();
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-time/timeline-timer.js b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-time/timeline-timer.js
index 175e5df..6d8e4a3 100644
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-time/timeline-timer.js
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-time/timeline-timer.js
@@ -27,14 +27,12 @@
   `);
 
   UI.panels.timeline._disableCaptureJSProfileSetting.set(true);
-  PerformanceTestRunner.invokeAsyncWithTimeline('performActions', finish);
+  await PerformanceTestRunner.invokeAsyncWithTimeline('performActions');
 
-  function finish() {
-    PerformanceTestRunner.printTimelineRecordsWithDetails('TimerInstall');
-    PerformanceTestRunner.printTimelineRecordsWithDetails('TimerFire');
-    PerformanceTestRunner.printTimelineRecordsWithDetails('TimerRemove');
-    PerformanceTestRunner.printTimelineRecords('FunctionCall');
-    PerformanceTestRunner.printTimelineRecordsWithDetails('EvaluateScript');
-    TestRunner.completeTest();
-  }
+  PerformanceTestRunner.printTimelineRecordsWithDetails('TimerInstall');
+  PerformanceTestRunner.printTimelineRecordsWithDetails('TimerFire');
+  PerformanceTestRunner.printTimelineRecordsWithDetails('TimerRemove');
+  PerformanceTestRunner.printTimelineRecords('FunctionCall');
+  PerformanceTestRunner.printTimelineRecordsWithDetails('EvaluateScript');
+  TestRunner.completeTest();
 })();
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-time/timeline-usertiming.js b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-time/timeline-usertiming.js
index 61fdf592..6d77da8b 100644
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-time/timeline-usertiming.js
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-time/timeline-usertiming.js
@@ -92,10 +92,9 @@
     });
   }
 
-  function performActions(actions, next) {
-    PerformanceTestRunner.evaluateWithTimeline(actions, _ => {
-      dumpUserTimings();
-      next();
-    });
+  async function performActions(actions, next) {
+    await PerformanceTestRunner.evaluateWithTimeline(actions);
+    dumpUserTimings();
+    next();
   }
 })();
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-xhr-event.js b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-xhr-event.js
index 810af8f..c32e627 100644
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-xhr-event.js
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-xhr-event.js
@@ -21,11 +21,9 @@
       }
   `);
 
-  PerformanceTestRunner.invokeAsyncWithTimeline('performActions', finish);
+  await PerformanceTestRunner.invokeAsyncWithTimeline('performActions');
 
-  function finish() {
-    PerformanceTestRunner.printTimelineRecordsWithDetails('XHRReadyStateChange');
-    PerformanceTestRunner.printTimelineRecordsWithDetails('XHRLoad');
-    TestRunner.completeTest();
-  }
+  PerformanceTestRunner.printTimelineRecordsWithDetails('XHRReadyStateChange');
+  PerformanceTestRunner.printTimelineRecordsWithDetails('XHRLoad');
+  TestRunner.completeTest();
 })();
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-xhr-response-type-blob-event.js b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-xhr-response-type-blob-event.js
index c731fa10..928198f 100644
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-xhr-response-type-blob-event.js
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/timeline-xhr-response-type-blob-event.js
@@ -33,11 +33,9 @@
       }
   `);
 
-  PerformanceTestRunner.invokeAsyncWithTimeline('performActions', finish);
+  await PerformanceTestRunner.invokeAsyncWithTimeline('performActions');
 
-  function finish() {
-    PerformanceTestRunner.printTimelineRecords('XHRReadyStateChange');
-    PerformanceTestRunner.printTimelineRecords('XHRLoad');
-    TestRunner.completeTest();
-  }
+  PerformanceTestRunner.printTimelineRecords('XHRReadyStateChange');
+  PerformanceTestRunner.printTimelineRecords('XHRLoad');
+  TestRunner.completeTest();
 })();
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/websocket/timeline-websocket-event.js b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/websocket/timeline-websocket-event.js
index dd5b72c1..003074b 100644
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/websocket/timeline-websocket-event.js
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/tracing/websocket/timeline-websocket-event.js
@@ -14,13 +14,11 @@
       }
   `);
 
-  PerformanceTestRunner.invokeAsyncWithTimeline('performActions', finish);
+  await PerformanceTestRunner.invokeAsyncWithTimeline('performActions');
 
-  function finish() {
-    PerformanceTestRunner.printTimelineRecordsWithDetails('WebSocketCreate');
-    PerformanceTestRunner.printTimelineRecordsWithDetails('WebSocketSendHandshakeRequest');
-    PerformanceTestRunner.printTimelineRecordsWithDetails('WebSocketReceiveHandshakeResponse');
-    PerformanceTestRunner.printTimelineRecordsWithDetails('WebSocketDestroy');
-    TestRunner.completeTest();
-  }
+  PerformanceTestRunner.printTimelineRecordsWithDetails('WebSocketCreate');
+  PerformanceTestRunner.printTimelineRecordsWithDetails('WebSocketSendHandshakeRequest');
+  PerformanceTestRunner.printTimelineRecordsWithDetails('WebSocketReceiveHandshakeResponse');
+  PerformanceTestRunner.printTimelineRecordsWithDetails('WebSocketDestroy');
+  TestRunner.completeTest();
 })();
diff --git a/third_party/WebKit/LayoutTests/media/content/60_sec_video.webm b/third_party/WebKit/LayoutTests/media/content/60_sec_video.webm
deleted file mode 100644
index 969e7be6..0000000
--- a/third_party/WebKit/LayoutTests/media/content/60_sec_video.webm
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/media/content/corrupt.mp4 b/third_party/WebKit/LayoutTests/media/content/corrupt.mp4
new file mode 100644
index 0000000..de58942
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/media/content/corrupt.mp4
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/media/content/corrupt.ogv b/third_party/WebKit/LayoutTests/media/content/corrupt.ogv
new file mode 100644
index 0000000..41a2576
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/media/content/corrupt.ogv
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/media/content/corrupt.webm b/third_party/WebKit/LayoutTests/media/content/corrupt.webm
new file mode 100644
index 0000000..81e3034
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/media/content/corrupt.webm
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/media/controls/modern/doubletap-on-play-button.html b/third_party/WebKit/LayoutTests/media/controls/modern/doubletap-on-play-button.html
deleted file mode 100644
index 989517c..0000000
--- a/third_party/WebKit/LayoutTests/media/controls/modern/doubletap-on-play-button.html
+++ /dev/null
@@ -1,30 +0,0 @@
-<!DOCTYPE html>
-<html>
-<title>Test that player will play then pause if double tapped on the play button.</title>
-<script src="../../../resources/testharness.js"></script>
-<script src="../../../resources/testharnessreport.js"></script>
-<script src="../../media-controls.js"></script>
-<video controls width=400 src="../../content/60_sec_video.webm"></video>
-<script>
-async_test(t => {
-  const video = document.querySelector('video');
-  let didPause = false;
-
-  video.onplaying = t.step_func(() => {
-    if (didPause) {
-      t.done();
-    } else {
-      const coordinates =
-        elementCoordinates(mediaControlsOverlayPlayButtonInternal(video));
-      doubleTapAtCoordinates(coordinates[0], coordinates[1]);
-    }
-  });
-
-  video.addEventListener('pause', t.step_func(() => {
-    didPause = true;
-  }), { once: true });
-
-  video.play();
-});
-</script>
-</html>
diff --git a/third_party/WebKit/LayoutTests/media/controls/modern/doubletap-to-jump-backwards-at-start.html b/third_party/WebKit/LayoutTests/media/controls/modern/doubletap-to-jump-backwards-at-start.html
deleted file mode 100644
index 9339482..0000000
--- a/third_party/WebKit/LayoutTests/media/controls/modern/doubletap-to-jump-backwards-at-start.html
+++ /dev/null
@@ -1,37 +0,0 @@
-<!DOCTYPE html>
-<html>
-<title>Test that player will jump to the beginning if it's in the first 10 seconds.</title>
-<script src="../../../resources/testharness.js"></script>
-<script src="../../../resources/testharnessreport.js"></script>
-<script src="../../media-controls.js"></script>
-<video controls width=400 src="../../content/60_sec_video.webm"></video>
-<script>
-async_test(t => {
-  enableDoubleTapToJumpForTest(t);
-
-  const video = document.querySelector('video');
-  let count = 0;
-
-  video.addEventListener('playing', t.step_func(() => {
-    // Double tap in the top left hand corner
-    const coordinates =
-      coordinatesOutsideElement(mediaControlsOverlayPlayButton(video));
-    doubleTapAtCoordinates(coordinates[0] + 1, coordinates[1] + 1);
-  }), { once: true });
-
-  video.ontimeupdate = t.step_func(() => {
-    // The time should reach 0 seconds twice, the first time when playing and
-    // the second because of tapping.
-    if (Math.round(video.currentTime) == 0) {
-      count++;
-
-      if (count == 2)
-       t.done();
-    }
-  });
-
-  video.play();
-});
-</script>
-</html></script>
-</html>
diff --git a/third_party/WebKit/LayoutTests/media/controls/modern/doubletap-to-jump-backwards.html b/third_party/WebKit/LayoutTests/media/controls/modern/doubletap-to-jump-backwards.html
deleted file mode 100644
index ec5f56f..0000000
--- a/third_party/WebKit/LayoutTests/media/controls/modern/doubletap-to-jump-backwards.html
+++ /dev/null
@@ -1,45 +0,0 @@
-<!DOCTYPE html>
-<html>
-<title>Test that player will jump backwards 10 seconds if double tapped on the left hand side.</title>
-<script src="../../../resources/testharness.js"></script>
-<script src="../../../resources/testharnessreport.js"></script>
-<script src="../../media-controls.js"></script>
-<video controls width=400 src="../../content/60_sec_video.webm"></video>
-<script>
-async_test(t => {
-  enableDoubleTapToJumpForTest(t);
-
-  const video = document.querySelector('video');
-  let time = 0;
-
-  video.addEventListener('playing', t.step_func(() => {
-    // Seek the video to the middle
-    video.currentTime = 30;
-  }), { once: true });
-
-  video.ontimeupdate = t.step_func(() => {
-    // The time should never reach 25 seconds as we skipped over it
-    assert_not_equals(Math.round(video.currentTime), 25);
-  });
-
-  video.onseeked = t.step_func(() => {
-    const currentTime = Math.round(video.currentTime);
-
-    if (currentTime == 30) {
-      // Double tap in the top left hand corner
-      time = currentTime;
-      const coordinates =
-        coordinatesOutsideElement(mediaControlsOverlayPlayButton(video));
-      doubleTapAtCoordinates(coordinates[0] + 1, coordinates[1] + 1);
-    } else if (time > 0) {
-      // Check the video went back 10 seconds
-      assert_greater_than(time, 0);
-      assert_equals(currentTime, time - 10);
-      t.done();
-    }
-  });
-
-  video.play();
-});
-</script>
-</html>
diff --git a/third_party/WebKit/LayoutTests/media/controls/modern/doubletap-to-jump-forwards-too-short.html b/third_party/WebKit/LayoutTests/media/controls/modern/doubletap-to-jump-forwards-too-short.html
deleted file mode 100644
index b36f95a2..0000000
--- a/third_party/WebKit/LayoutTests/media/controls/modern/doubletap-to-jump-forwards-too-short.html
+++ /dev/null
@@ -1,37 +0,0 @@
-<!DOCTYPE html>
-<html>
-<title>Test that player will jump to the end if less than 10 seconds remaining.</title>
-<script src="../../../resources/testharness.js"></script>
-<script src="../../../resources/testharnessreport.js"></script>
-<script src="../../media-controls.js"></script>
-<video controls width=400 src="../../content/60_sec_video.webm"></video>
-<script>
-async_test(t => {
-  enableDoubleTapToJumpForTest(t);
-
-  const video = document.querySelector('video');
-
-  video.addEventListener('playing', () => {
-    // Seek the video to the end
-    if (video.currentTime < 55) {
-      video.currentTime = 55;
-
-      // Double tap in the top right hand corner
-      const coordinates =
-        coordinatesOutsideElement(mediaControlsOverlayPlayButton(video));
-      doubleTapAtCoordinates(coordinates[0] + video.width, coordinates[1] + 1);
-    }
-  }, { once: true });
-
-  video.ontimeupdate = t.step_func(() => {
-    // The time should never reach 57 seconds as we skipped over it
-    assert_not_equals(57, Math.round(video.currentTime));
-  });
-
-  video.addEventListener('ended', t.step_func_done(), { once: true });
-
-  video.play();
-});
-</script>
-</html></script>
-</html>
diff --git a/third_party/WebKit/LayoutTests/media/controls/modern/doubletap-to-jump-forwards.html b/third_party/WebKit/LayoutTests/media/controls/modern/doubletap-to-jump-forwards.html
deleted file mode 100644
index f601632..0000000
--- a/third_party/WebKit/LayoutTests/media/controls/modern/doubletap-to-jump-forwards.html
+++ /dev/null
@@ -1,36 +0,0 @@
-<!DOCTYPE html>
-<html>
-<title>Test that player will jump forwards 10 seconds if double tapped.</title>
-<script src="../../../resources/testharness.js"></script>
-<script src="../../../resources/testharnessreport.js"></script>
-<script src="../../media-controls.js"></script>
-<video controls width=400 src="../../content/60_sec_video.webm"></video>
-<script>
-async_test(t => {
-  enableDoubleTapToJumpForTest(t);
-
-  const video = document.querySelector('video');
-  let time = 0;
-
-  video.addEventListener('playing', t.step_func(() => {
-    // Double tap in the top right hand corner
-    time = Math.round(video.currentTime);
-    const coordinates =
-      coordinatesOutsideElement(mediaControlsOverlayPlayButton(video));
-    doubleTapAtCoordinates(coordinates[0] + video.width, coordinates[1] + 1);
-  }), { once: true });
-
-  video.ontimeupdate = t.step_func(() => {
-    // The time should never be 5 seconds as we skipped over it
-    assert_not_equals(Math.round(video.currentTime), 5);
-  });
-
-  video.addEventListener('seeked', t.step_func_done(() => {
-    // Check the video advanced 10 seconds
-    assert_equals(Math.round(video.currentTime), time + 10);
-  }), { once: true });
-
-  video.play();
-});
-</script>
-</html>
diff --git a/third_party/WebKit/LayoutTests/media/controls/modern/doubletap-to-toggle-fullscreen.html b/third_party/WebKit/LayoutTests/media/controls/modern/doubletap-to-toggle-fullscreen.html
deleted file mode 100644
index 934af68b..0000000
--- a/third_party/WebKit/LayoutTests/media/controls/modern/doubletap-to-toggle-fullscreen.html
+++ /dev/null
@@ -1,34 +0,0 @@
-<!DOCTYPE html>
-<html>
-<title>Test that player will enter fullscreen if double tapped.</title>
-<script src="../../../resources/testharness.js"></script>
-<script src="../../../resources/testharnessreport.js"></script>
-<script src="../../media-controls.js"></script>
-<video controls width=400 src="../../content/60_sec_video.webm"></video>
-<script>
-async_test(t => {
-  const video = document.querySelector('video');
-
-  video.addEventListener('playing', () => {
-    // Double tap in the top left hand corner
-    const coordinates =
-      coordinatesOutsideElement(mediaControlsOverlayPlayButton(video));
-    doubleTapAtCoordinates(coordinates[0] + 1, coordinates[1] + 1);
-  }, { once: true });
-
-  video.addEventListener('webkitfullscreenchange', t.step_func(() => {
-    assert_equals(video, document.fullscreenElement);
-
-    // We are now fullscreen, update the event handler and doubletap to exit
-    video.addEventListener('webkitfullscreenchange',
-        t.step_func_done(), { once: true });
-
-    const coordinates =
-      coordinatesOutsideElement(mediaControlsOverlayPlayButton(video));
-    doubleTapAtCoordinates(coordinates[0] + 1, coordinates[1] + 1);
-  }), { once: true });
-
-  video.play();
-});
-</script>
-</html>
diff --git a/third_party/WebKit/LayoutTests/media/controls/modern/singletap-on-outside.html b/third_party/WebKit/LayoutTests/media/controls/modern/singletap-on-outside.html
deleted file mode 100644
index 999ce3c..0000000
--- a/third_party/WebKit/LayoutTests/media/controls/modern/singletap-on-outside.html
+++ /dev/null
@@ -1,24 +0,0 @@
-<!DOCTYPE html>
-<html>
-<title>Test that the player pauses if single taped in the outer region.</title>
-<script src="../../../resources/testharness.js"></script>
-<script src="../../../resources/testharnessreport.js"></script>
-<script src="../../media-controls.js"></script>
-<video controls width=400 src="../../content/60_sec_video.webm"></video>
-<script>
-async_test(t => {
-  const video = document.querySelector('video');
-
-  video.addEventListener('playing', t.step_func(() => {
-    // Single tap in the top right hand corner
-    const coordinates =
-      coordinatesOutsideElement(mediaControlsOverlayPlayButtonInternal(video));
-    singleTapAtCoordinates(coordinates[0] + 1, coordinates[1] + 1);
-  }), { once: true });
-
-  video.addEventListener('pause', t.step_func_done(), { once: true });
-
-  video.play();
-});
-</script>
-</html>
diff --git a/third_party/WebKit/LayoutTests/media/controls/modern/singletap-on-play-button.html b/third_party/WebKit/LayoutTests/media/controls/modern/singletap-on-play-button.html
deleted file mode 100644
index e7460298..0000000
--- a/third_party/WebKit/LayoutTests/media/controls/modern/singletap-on-play-button.html
+++ /dev/null
@@ -1,24 +0,0 @@
-<!DOCTYPE html>
-<html>
-<title>Test that the player pauses if single tapped on the play button.</title>
-<script src="../../../resources/testharness.js"></script>
-<script src="../../../resources/testharnessreport.js"></script>
-<script src="../../media-controls.js"></script>
-<video controls width=400 src="../../content/60_sec_video.webm"></video>
-<script>
-async_test(t => {
-  const video = document.querySelector('video');
-
-  video.addEventListener('playing', t.step_func(() => {
-    // Single tap in the middle of the button.
-    const coordinates =
-      elementCoordinates(mediaControlsOverlayPlayButtonInternal(video));
-    singleTapAtCoordinates(coordinates[0], coordinates[1]);
-  }), { once: true });
-
-  video.addEventListener('pause', t.step_func_done(), { once: true });
-
-  video.play();
-});
-</script>
-</html>
diff --git a/third_party/WebKit/LayoutTests/media/controls/modern/slow-doubletap.html b/third_party/WebKit/LayoutTests/media/controls/modern/slow-doubletap.html
deleted file mode 100644
index 8f0471e2..0000000
--- a/third_party/WebKit/LayoutTests/media/controls/modern/slow-doubletap.html
+++ /dev/null
@@ -1,31 +0,0 @@
-<!DOCTYPE html>
-<html>
-<title>Test that player will not jump if the tap is too slow.</title>
-<script src="../../../resources/testharness.js"></script>
-<script src="../../../resources/testharnessreport.js"></script>
-<script src="../../media-controls.js"></script>
-<video controls width=400 src="../../content/60_sec_video.webm"></video>
-<script>
-async_test(t => {
-  const video = document.querySelector('video');
-  let didPause = false;
-
-  video.onplaying = t.step_func(() => {
-    if (didPause) {
-      t.done();
-    } else {
-      // Double tap in the top right hand corner
-      const coordinates =
-        coordinatesOutsideElement(mediaControlsOverlayPlayButton(video));
-      doubleTapAtCoordinates(coordinates[0] + 1, coordinates[1] + 1, 400);
-    }
-  });
-
-  video.addEventListener('pause', t.step_func(() => {
-    didPause = true;
-  }), { once: true });
-
-  video.play();
-});
-</script>
-</html>
diff --git a/third_party/WebKit/LayoutTests/media/media-controls.js b/third_party/WebKit/LayoutTests/media/media-controls.js
index d9d637b..42cb039 100644
--- a/third_party/WebKit/LayoutTests/media/media-controls.js
+++ b/third_party/WebKit/LayoutTests/media/media-controls.js
@@ -286,51 +286,3 @@
 function checkControlsClassName(videoElement, className) {
   assert_equals(window.internals.shadowRoot(videoElement).firstChild.className, className);
 }
-
-function mediaControlsOverlayPlayButton(videoElement) {
-  return mediaControlsButton(videoElement, 'overlay-play-button');
-}
-
-function mediaControlsOverlayPlayButtonInternal(videoElement) {
-  var controlID = '-internal-media-controls-overlay-play-button-internal';
-  var element = mediaControlsElement(
-      window.internals.shadowRoot(
-          mediaControlsOverlayPlayButton(videoElement)).firstChild, controlID);
-  if (!element)
-    throw 'Failed to find the internal overlay play button';
-  return element;
-}
-
-function doubleTapAtCoordinates(x, y, timeout) {
-  if (timeout == undefined)
-    timeout = 100;
-
-  singleTapAtCoordinates(x, y);
-
-  setTimeout(() => {
-    singleTapAtCoordinates(x, y);
-  }, timeout);
-}
-
-function singleTapAtCoordinates(xPos, yPos) {
-  chrome.gpuBenchmarking.pointerActionSequence([
-    {
-      source: 'touch',
-      actions: [
-        { name: 'pointerDown', x: xPos, y: yPos },
-        { name: 'pointerUp' }
-      ]
-    }
-  ]);
-}
-
-function enableDoubleTapToJumpForTest(t) {
-  var doubleTapToJumpOnVideoEnabledValue =
-      internals.runtimeFlags.doubleTapToJumpOnVideoEnabled;
-  internals.runtimeFlags.doubleTapToJumpOnVideoEnabled = true;
-
-  t.add_cleanup(() => {
-    internals.runtimeFlags.doubleTapToJumpOnVideoEnabled =
-        doubleTapToJumpOnVideoEnabledValue;
-  });
-}
diff --git a/third_party/WebKit/LayoutTests/media/track/track-constants.html b/third_party/WebKit/LayoutTests/media/track/track-constants.html
deleted file mode 100644
index 0bea905..0000000
--- a/third_party/WebKit/LayoutTests/media/track/track-constants.html
+++ /dev/null
@@ -1,12 +0,0 @@
-<!DOCTYPE html>
-<title>Test TextTrack constants</title>
-<script src="../../resources/testharness.js"></script>
-<script src="../../resources/testharnessreport.js"></script>
-<script>
-test(function() {
-    assert_equals(HTMLTrackElement.NONE, 0);
-    assert_equals(HTMLTrackElement.LOADING, 1);
-    assert_equals(HTMLTrackElement.LOADED, 2);
-    assert_equals(HTMLTrackElement.ERROR, 3);
-});
-</script>
diff --git a/third_party/WebKit/LayoutTests/media/video-error-networkState.html b/third_party/WebKit/LayoutTests/media/video-error-networkState.html
new file mode 100644
index 0000000..535e2eff
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/media/video-error-networkState.html
@@ -0,0 +1,34 @@
+<!DOCTYPE html>
+<title>Test media element networkState value in an error corner case.</title>
+<script src="../resources/testharness.js"></script>
+<script src="../resources/testharnessreport.js"></script>
+<script src="media-file.js"></script>
+<video></video>
+<script>
+async_test(function(t) {
+    var video = document.querySelector("video");
+    assert_equals(video.readyState, HTMLMediaElement.HAVE_NOTHING);
+    video.onended = t.unreached_func();
+    video.onerror = t.step_func(() => {
+      assert_equals(video.readyState, HTMLMediaElement.HAVE_ENOUGH_DATA);
+      assert_equals(video.networkState, HTMLMediaElement.NETWORK_IDLE);
+
+      var source = document.createElement("source");
+      video.removeAttribute("src");
+      video.appendChild(source);  // Schedules load timer.
+      video.removeChild(source);  // Good luck with that load.
+      window.setTimeout(t.step_func_done(() => {
+        // If we wait before removing the child, we will get HAVE_ENOUGH_DATA,
+        // and NETWORK_NO_SOURCE. It's not really clear if that's correct, nor
+        // is it clear whether removing the child immediately should change the
+        // result. In any case, the load algorithm handles NETWORK_EMPTY as a
+        // special case. For now we'll just test that we don't trigger that.
+        assert_true(video.readyState != HTMLMediaElement.HAVE_ENOUGH_DATA ||
+                    video.networkState != HTMLMediaElement.NETWORK_EMPTY);
+      }), 0);
+    });
+
+    video.src = findMediaFile("video", "content/corrupt");
+    video.play();
+});
+</script>
diff --git a/third_party/WebKit/LayoutTests/typedcssom/inlinestyle/properties/background-image.html b/third_party/WebKit/LayoutTests/typedcssom/inlinestyle/properties/background-image.html
index 7870bfd..fff4a87a 100644
--- a/third_party/WebKit/LayoutTests/typedcssom/inlinestyle/properties/background-image.html
+++ b/third_party/WebKit/LayoutTests/typedcssom/inlinestyle/properties/background-image.html
@@ -9,8 +9,8 @@
 test(function() {
   testElement.attributeStyleMap.set('background-image', new CSSURLImageValue(''));
   document.body.offsetTop;
-  assert_equals(testElement.attributeStyleMap.get('background-image').intrinsicHeight, 0);
-  assert_equals(testElement.attributeStyleMap.get('background-image').intrinsicWidth, 0);
+  assert_equals(testElement.attributeStyleMap.get('background-image').intrinsicHeight, null);
+  assert_equals(testElement.attributeStyleMap.get('background-image').intrinsicWidth, null);
 }, "Check that setting background-image to CSSURLImageValue('') doesn't cause a crash");
 
 runInlineStylePropertyMapTests( {
diff --git a/third_party/WebKit/LayoutTests/typedcssom/stylevalue-subclasses/cssUrlImageValue-expected.txt b/third_party/WebKit/LayoutTests/typedcssom/stylevalue-subclasses/cssUrlImageValue-expected.txt
deleted file mode 100644
index ee42606..0000000
--- a/third_party/WebKit/LayoutTests/typedcssom/stylevalue-subclasses/cssUrlImageValue-expected.txt
+++ /dev/null
@@ -1,9 +0,0 @@
-This is a testharness.js-based test.
-PASS Constructing a CSSURLImageValue with an invalid URL throws a TypeError
-PASS Constructing a CSSURLImageValue with a valid URL puts it in an unloaded state
-PASS CSSURLImageValue.url is readonly
-PASS Loading a CSSURLImageValue from a URL sets its state to loaded
-PASS Loading a CSSURLImageValue from a base64 URL sets its state to loaded
-FAIL Loading a CSSURLImageValue from a URL to an invalid image sets its state to error assert_equals: expected (object) null but got (number) 0
-Harness: the test ran to completion.
-
diff --git a/third_party/WebKit/LayoutTests/typedcssom/the-stylepropertymap/update-expected.txt b/third_party/WebKit/LayoutTests/typedcssom/the-stylepropertymap/update-expected.txt
index 5670383..dea45763 100644
--- a/third_party/WebKit/LayoutTests/typedcssom/the-stylepropertymap/update-expected.txt
+++ b/third_party/WebKit/LayoutTests/typedcssom/the-stylepropertymap/update-expected.txt
@@ -1,14 +1,14 @@
 This is a testharness.js-based test.
-FAIL Updating a StylePropertyMap with an unsupported property name throws TypeError assert_throws: function "() => styleMap.update(property, () => value)" did not throw
-FAIL Updating a StylePropertyMap with an null property name throws TypeError assert_throws: function "() => styleMap.update(property, () => value)" did not throw
-FAIL Updating a StylePropertyMap with an invalid CSSStyleValue throws TypeError assert_throws: function "() => styleMap.update(property, () => value)" did not throw
-FAIL Updating a StylePropertyMap with an invalid String throws TypeError assert_throws: function "() => styleMap.update(property, () => value)" did not throw
-FAIL Updating a property with CSSStyleValue updates its value Cannot read property 'length' of null
-FAIL Updating a list-valued property with CSSStyleValue updates its value assert_equals: expected 1 but got 0
-FAIL Updating a custom property with CSSStyleValue updates its value Cannot read property 'length' of null
+PASS Updating a StylePropertyMap with an unsupported property name throws TypeError
+PASS Updating a StylePropertyMap with an null property name throws TypeError
+PASS Updating a StylePropertyMap with an invalid CSSStyleValue throws TypeError
+PASS Updating a StylePropertyMap with an invalid String throws TypeError
+PASS Updating a property with CSSStyleValue updates its value
+PASS Updating a list-valued property with CSSStyleValue updates its value
+FAIL Updating a custom property with CSSStyleValue updates its value Failed to execute 'update' on 'StylePropertyMap': Invalid propertyName: --foo
 PASS Calling StylePropertyMap.update on an empty property model calls update function with null
 PASS Calling StylePropertyMap.update on an existing property calls update function with old value
 PASS Calling StylePropertyMap.update on an existing list-valued property calls update function with first value
-FAIL StylePropertyMap.update is case-insensitive assert_approx_equals: expected 20 +/- 0.000001 but got 10
+PASS StylePropertyMap.update is case-insensitive
 Harness: the test ran to completion.
 
diff --git a/third_party/WebKit/LayoutTests/typedcssom/the-stylepropertymap/update.html b/third_party/WebKit/LayoutTests/typedcssom/the-stylepropertymap/update.html
index 1064333..ccb9c74 100644
--- a/third_party/WebKit/LayoutTests/typedcssom/the-stylepropertymap/update.html
+++ b/third_party/WebKit/LayoutTests/typedcssom/the-stylepropertymap/update.html
@@ -54,17 +54,26 @@
 
 test(() => {
   let styleMap = newDivWithStyle('').attributeStyleMap;
-  styleMap.update('width', oldValue => assert_equals(oldValue, null));
+  styleMap.update('width', oldValue => {
+    assert_equals(oldValue, null);
+    return CSS.px(10);
+  });
 }, 'Calling StylePropertyMap.update on an empty property model calls update function with null');
 
 test(() => {
   let styleMap = newDivWithStyle('width: 10px').attributeStyleMap;
-  styleMap.update('width', oldValue => assert_style_value_equals(oldValue, CSS.px(10)));
+  styleMap.update('width', oldValue => {
+    assert_style_value_equals(oldValue, CSS.px(10));
+    return CSS.px(20);
+  });
 }, 'Calling StylePropertyMap.update on an existing property calls update function with old value');
 
 test(() => {
   let styleMap = newDivWithStyle('transition-duration: 1s, 2s').attributeStyleMap;
-  styleMap.update('transition-duration', oldValue => assert_style_value_equals(oldValue, CSS.s(1)));
+  styleMap.update('transition-duration', oldValue => {
+    assert_style_value_equals(oldValue, CSS.s(1));
+    return CSS.s(2);
+  });
 }, 'Calling StylePropertyMap.update on an existing list-valued property calls update function with first value');
 
 test(() => {
diff --git a/third_party/WebKit/LayoutTests/virtual/modern-media-controls/media/controls/modern/README.txt b/third_party/WebKit/LayoutTests/virtual/modern-media-controls/media/controls/modern/README.txt
deleted file mode 100644
index 83608d41..0000000
--- a/third_party/WebKit/LayoutTests/virtual/modern-media-controls/media/controls/modern/README.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-These are tests specific to the modern media controls. As such they should be
-run with the modern media controls enabled.
diff --git a/third_party/WebKit/Source/DEPS b/third_party/WebKit/Source/DEPS
index a5a830a..a48bc83 100644
--- a/third_party/WebKit/Source/DEPS
+++ b/third_party/WebKit/Source/DEPS
@@ -1,4 +1,6 @@
 include_rules = [
+    "+base/callback.h",
+    "+base/callback_forward.h",
     "+base/debug",
     "+base/macros.h",
     "+base/memory/weak_ptr.h",
diff --git a/third_party/WebKit/Source/bindings/core/BUILD.gn b/third_party/WebKit/Source/bindings/core/BUILD.gn
index b6a02d1..5676b7b 100644
--- a/third_party/WebKit/Source/bindings/core/BUILD.gn
+++ b/third_party/WebKit/Source/bindings/core/BUILD.gn
@@ -39,3 +39,10 @@
     ":core_global_objects",
   ]
 }
+
+generate_web_idl_collection("core_web_idl_collection") {
+  sources = core_static_interface_idl_files - core_testing_definition_idl_files
+  output = "WebIdlCollectionForCore.pickle"
+  component = "core"
+  output_dir = bindings_core_output_dir
+}
diff --git a/third_party/WebKit/Source/bindings/core/v8/ScriptStreamer.cpp b/third_party/WebKit/Source/bindings/core/v8/ScriptStreamer.cpp
index e922f36..16db306 100644
--- a/third_party/WebKit/Source/bindings/core/v8/ScriptStreamer.cpp
+++ b/third_party/WebKit/Source/bindings/core/v8/ScriptStreamer.cpp
@@ -514,7 +514,7 @@
     v8::ScriptCompiler::CompileOptions compile_options,
     scoped_refptr<WebTaskRunner> loading_task_runner)
     : pending_script_(script),
-      resource_(script->GetResource()),
+      resource_(ToScriptResource(script->GetResource())),
       detached_(false),
       stream_(nullptr),
       loading_finished_(false),
@@ -579,7 +579,7 @@
     scoped_refptr<WebTaskRunner> loading_task_runner) {
   DCHECK(IsMainThread());
   DCHECK(script_state->ContextIsValid());
-  ScriptResource* resource = script->GetResource();
+  ScriptResource* resource = ToScriptResource(script->GetResource());
   if (!resource->Url().ProtocolIsInHTTPFamily()) {
     RecordNotStreamingReasonHistogram(script_type, kNotHTTP);
     RecordStartedStreamingHistogram(script_type, 0);
diff --git a/third_party/WebKit/Source/bindings/modules/BUILD.gn b/third_party/WebKit/Source/bindings/modules/BUILD.gn
index 2fcd3a68..9515aeb 100644
--- a/third_party/WebKit/Source/bindings/modules/BUILD.gn
+++ b/third_party/WebKit/Source/bindings/modules/BUILD.gn
@@ -198,3 +198,10 @@
     "//v8",
   ]
 }
+
+generate_web_idl_collection("modules_web_idl_collection") {
+  sources = modules_definition_idl_files + modules_dependency_idl_files
+  output = "WebIdlCollectionForModules.pickle"
+  component = "modules"
+  output_dir = bindings_modules_output_dir
+}
diff --git a/third_party/WebKit/Source/bindings/scripts/generate_web_idl_collection.py b/third_party/WebKit/Source/bindings/scripts/generate_web_idl_collection.py
new file mode 100644
index 0000000..e2a2030
--- /dev/null
+++ b/third_party/WebKit/Source/bindings/scripts/generate_web_idl_collection.py
@@ -0,0 +1,44 @@
+# 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.
+
+"""Generates a data collection of IDL information per component.
+In this data collection, we use identifier strings to point IDL definitions
+(i.e. interface, dictionary, namespace, etc.) instead of references, because
+some referred definitions can be in other components.
+"""
+
+
+import blink_idl_parser
+import optparse
+import utilities
+from web_idl.collector import Collector
+
+
+def parse_options():
+    parser = optparse.OptionParser()
+    parser.add_option('--idl-list-file', help='a file path which lists IDL file paths to process')
+    parser.add_option('--component', help='decide which component to collect IDLs', default=None)
+    parser.add_option('--output', help='pickle file of IDL definition')
+    options, args = parser.parse_args()
+
+    if options.idl_list_file is None:
+        parser.error('Must specify a file listing IDL files using --idl-files-list.')
+    if options.output is None:
+        parser.error('Must specify a pickle file to output using --output.')
+
+    return options, args
+
+
+def main():
+    options, _ = parse_options()
+    idl_file_names = utilities.read_idl_files_list_from_file(options.idl_list_file, False)
+
+    parser = blink_idl_parser.BlinkIDLParser()
+    collector = Collector(component=options.component, parser=parser)
+    collection = collector.collect_from_idl_files(idl_file_names)
+    utilities.write_pickle_file(options.output, collection)
+
+
+if __name__ == '__main__':
+    main()
diff --git a/third_party/WebKit/Source/bindings/scripts/scripts.gni b/third_party/WebKit/Source/bindings/scripts/scripts.gni
index 697f3abc..8b0e1b6 100644
--- a/third_party/WebKit/Source/bindings/scripts/scripts.gni
+++ b/third_party/WebKit/Source/bindings/scripts/scripts.gni
@@ -58,6 +58,29 @@
         ],
         "abspath")
 
+web_idl_scripts = get_path_info([
+                                  "web_idl/argument.py",
+                                  "web_idl/attribute.py",
+                                  "web_idl/callback_function.py",
+                                  "web_idl/collection.py",
+                                  "web_idl/collector.py",
+                                  "web_idl/constant.py",
+                                  "web_idl/dictionary.py",
+                                  "web_idl/ecma_script_types.py",
+                                  "web_idl/enumeration.py",
+                                  "web_idl/extended_attribute.py",
+                                  "web_idl/idl_types.py",
+                                  "web_idl/implements.py",
+                                  "web_idl/interface.py",
+                                  "web_idl/literal_token.py",
+                                  "web_idl/namespace.py",
+                                  "web_idl/operation.py",
+                                  "web_idl/typedef.py",
+                                  "web_idl/utilities.py",
+                                  "web_idl/idl_definition_builder.py",
+                                ],
+                                "abspath")
+
 # Calls the compute_interfaces_info_individual script.
 #
 # Parameters:
@@ -540,3 +563,27 @@
            [ "//third_party/WebKit/Source/bindings/modules:interfaces_info" ]
   }
 }
+
+template("generate_web_idl_collection") {
+  action(target_name) {
+    script = "//third_party/WebKit/Source/bindings/scripts/generate_web_idl_collection.py"
+    output_dir = invoker.output_dir
+    output_file_name = invoker.output
+    output_path = "${output_dir}/${output_file_name}"
+    inputs = web_idl_scripts + invoker.sources
+    outputs = [
+      output_path,
+    ]
+
+    # List input file names in a temporary file.
+    response_file_contents = rebase_path(invoker.sources, root_build_dir)
+    args = [
+      "--idl-list-file",
+      "{{response_file_name}}",
+      "--component",
+      invoker.component,
+      "--output",
+      rebase_path(output_path, root_build_dir),
+    ]
+  }
+}
diff --git a/third_party/WebKit/Source/bindings/scripts/web_idl/__init__.py b/third_party/WebKit/Source/bindings/scripts/web_idl/__init__.py
new file mode 100644
index 0000000..a22a6ee
--- /dev/null
+++ b/third_party/WebKit/Source/bindings/scripts/web_idl/__init__.py
@@ -0,0 +1,3 @@
+# 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.
diff --git a/third_party/WebKit/Source/bindings/scripts/web_idl/argument.py b/third_party/WebKit/Source/bindings/scripts/web_idl/argument.py
new file mode 100644
index 0000000..8d0a70c
--- /dev/null
+++ b/third_party/WebKit/Source/bindings/scripts/web_idl/argument.py
@@ -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.
+
+from .extended_attribute import ExtendedAttributeList
+from .utilities import assert_no_extra_args
+
+
+class Argument(object):
+
+    def __init__(self, **kwargs):
+        self._identifier = kwargs.pop('identifier')
+        self._type = kwargs.pop('type')
+        self._is_optional = kwargs.pop('is_optional', False)
+        self._is_variadic = kwargs.pop('is_variadic', False)
+        self._default_value = kwargs.pop('default_value', None)
+        self._extended_attribute_list = kwargs.pop('extended_attribute_list', ExtendedAttributeList())
+        assert_no_extra_args(kwargs)
+
+    @property
+    def identifier(self):
+        return self._identifier
+
+    @property
+    def type(self):
+        return self._type
+
+    @property
+    def is_optional(self):
+        return self._is_optional
+
+    @property
+    def is_variadic(self):
+        return self._is_variadic
+
+    @property
+    def default_value(self):
+        return self._default_value
+
+    @property
+    def extended_attribute_list(self):
+        return self._extended_attribute_list
diff --git a/third_party/WebKit/Source/bindings/scripts/web_idl/attribute.py b/third_party/WebKit/Source/bindings/scripts/web_idl/attribute.py
new file mode 100644
index 0000000..0e736db
--- /dev/null
+++ b/third_party/WebKit/Source/bindings/scripts/web_idl/attribute.py
@@ -0,0 +1,44 @@
+# 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.
+
+from .extended_attribute import ExtendedAttributeList
+from .idl_types import RecordType
+from .idl_types import SequenceType
+from .utilities import assert_no_extra_args
+
+
+# https://heycam.github.io/webidl/#idl-attributes
+class Attribute(object):
+    _INVALID_TYPES = frozenset([SequenceType, RecordType])
+
+    def __init__(self, **kwargs):
+        self._identifier = kwargs.pop('identifier')
+        self._type = kwargs.pop('type')
+        self._is_static = kwargs.pop('is_static', False)
+        self._is_readonly = kwargs.pop('is_readonly', False)
+        self._extended_attribute_list = kwargs.pop('extended_attribute_list', ExtendedAttributeList())
+        assert_no_extra_args(kwargs)
+
+        if type(self.type) in Attribute._INVALID_TYPES:
+            raise ValueError('The type of an attribute must not be either of sequence<T> and record<K,V>.')
+
+    @property
+    def identifier(self):
+        return self._identifier
+
+    @property
+    def type(self):
+        return self._type
+
+    @property
+    def is_static(self):
+        return self._is_static
+
+    @property
+    def is_readonly(self):
+        return self._is_readonly
+
+    @property
+    def extended_attribute_list(self):
+        return self._extended_attribute_list
diff --git a/third_party/WebKit/Source/bindings/scripts/web_idl/callback_function.py b/third_party/WebKit/Source/bindings/scripts/web_idl/callback_function.py
new file mode 100644
index 0000000..438be019
--- /dev/null
+++ b/third_party/WebKit/Source/bindings/scripts/web_idl/callback_function.py
@@ -0,0 +1,33 @@
+# 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.
+
+from .extended_attribute import ExtendedAttributeList
+from .utilities import assert_no_extra_args
+
+
+# https://heycam.github.io/webidl/#idl-callback-functions
+class CallbackFunction(object):
+
+    def __init__(self, **kwargs):
+        self._identifier = kwargs.pop('identifier')
+        self._return_type = kwargs.pop('return_type')
+        self._arguments = tuple(kwargs.pop('arguments', []))
+        self._extended_attribute_list = kwargs.pop('extended_attribute_list', ExtendedAttributeList())
+        assert_no_extra_args(kwargs)
+
+    @property
+    def identifier(self):
+        return self._identifier
+
+    @property
+    def return_type(self):
+        return self._return_type
+
+    @property
+    def arguments(self):
+        return self._arguments
+
+    @property
+    def extended_attribute_list(self):
+        return self._extended_attribute_list
diff --git a/third_party/WebKit/Source/bindings/scripts/web_idl/callback_interface.py b/third_party/WebKit/Source/bindings/scripts/web_idl/callback_interface.py
new file mode 100644
index 0000000..e086667
--- /dev/null
+++ b/third_party/WebKit/Source/bindings/scripts/web_idl/callback_interface.py
@@ -0,0 +1,48 @@
+# 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.
+
+from .extended_attribute import ExtendedAttributeList
+from .utilities import assert_no_extra_args
+
+
+# https://heycam.github.io/webidl/#idl-interfaces
+class CallbackInterface(object):
+
+    def __init__(self, **kwargs):
+        self._identifier = kwargs.pop('identifier')
+        self._attributes = tuple(kwargs.pop('attributes', []))
+        self._operations = tuple(kwargs.pop('operations', []))
+        self._constants = tuple(kwargs.pop('constants', []))
+        self._inherited_interface_name = kwargs.pop('inherited_interface_name', None)
+        self._extended_attribute_list = kwargs.pop('extended_attribute_list', ExtendedAttributeList())
+        assert_no_extra_args(kwargs)
+
+        if any(attribute.is_static for attribute in self.attributes):
+            raise ValueError('Static attributes must not be defined on a callback interface')
+        if any(operation.is_static for operation in self.operations):
+            raise ValueError('Static operations must not be defined on a callback interface')
+
+    @property
+    def identifier(self):
+        return self._identifier
+
+    @property
+    def attributes(self):
+        return self._attributes
+
+    @property
+    def operations(self):
+        return self._operations
+
+    @property
+    def constants(self):
+        return self._constants
+
+    @property
+    def inherited_interface_name(self):
+        return self._inherited_interface_name
+
+    @property
+    def extended_attribute_list(self):
+        return self._extended_attribute_list
diff --git a/third_party/WebKit/Source/bindings/scripts/web_idl/collection.py b/third_party/WebKit/Source/bindings/scripts/web_idl/collection.py
new file mode 100644
index 0000000..a206cc80
--- /dev/null
+++ b/third_party/WebKit/Source/bindings/scripts/web_idl/collection.py
@@ -0,0 +1,163 @@
+# 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.
+
+from .callback_function import CallbackFunction
+from .callback_interface import CallbackInterface
+from .dictionary import Dictionary
+from .enumeration import Enumeration
+from .implements import Implements
+from .interface import Interface
+from .namespace import Namespace
+from .typedef import Typedef
+
+
+class Collection(object):
+    """
+    Collection class stores Web IDL definitions and some meta information.
+    """
+
+    def __init__(self, component=None):
+        self._interfaces = {}
+        self._callback_interfaces = {}
+        self._namespaces = {}
+        self._dictionaries = {}
+        self._enumerations = {}
+        self._callback_functions = {}
+        self._typedefs = {}
+        # In spec, different partial definitions can have same identifiers.
+        # So they are stored in a list, which is indexed by the identifier.
+        # i.e. {'identifer': [definition, definition, ...]}
+        self._partial_interfaces = {}
+        self._partial_namespaces = {}
+        self._partial_dictionaries = {}
+        # Implements statements are not named definitions.
+        self._implements = []
+        # These members are not in spec., but they are necessary for code generators.
+        self._metadata_store = []
+        self._component = component
+
+    def find_non_partial_definition(self, identifier):
+        """Returns a non-partial named definition, if it is defined. Otherwise returns None."""
+        if identifier in self._interfaces:
+            return self._interfaces[identifier]
+        if identifier in self._callback_interfaces:
+            return self._callback_interfaces[identifier]
+        if identifier in self._namespaces:
+            return self._namespaces[identifier]
+        if identifier in self._dictionaries:
+            return self._dictionaries[identifier]
+        if identifier in self._enumerations:
+            return self._enumerations[identifier]
+        if identifier in self._callback_functions:
+            return self._callback_functions[identifier]
+        if identifier in self._typedefs:
+            return self._typedefs[identifier]
+        return None
+
+    def find_partial_definition(self, identifier):
+        if identifier in self._partial_interfaces:
+            return self._partial_interfaces[identifier]
+        if identifier in self._partial_namespaces:
+            return self._partial_namespaces[identifier]
+        if identifier in self._partial_dictionaries:
+            return self._partial_dictionaries[identifier]
+        return []
+
+    def find_filepath(self, definition):
+        for metadata in self._metadata_store:
+            if metadata.definition == definition:
+                return metadata.filepath
+        return None
+
+    def register_definition(self, definition, filepath):
+        if type(definition) == Interface:
+            if definition.is_partial:
+                self._register_partial_definition(self._partial_interfaces, definition)
+            else:
+                self._register_definition(self._interfaces, definition)
+        elif type(definition) == Namespace:
+            if definition.is_partial:
+                self._register_partial_definition(self._partial_namespaces, definition)
+            else:
+                self._register_definition(self._namespaces, definition)
+        elif type(definition) == Dictionary:
+            if definition.is_partial:
+                self._register_partial_definition(self._partial_dictionaries, definition)
+            else:
+                self._register_definition(self._dictionaries, definition)
+        elif type(definition) == CallbackInterface:
+            self._register_definition(self._callback_interfaces, definition)
+        elif type(definition) == Enumeration:
+            self._register_definition(self._enumerations, definition)
+        elif type(definition) == Typedef:
+            self._register_definition(self._typedefs, definition)
+        elif type(definition) == CallbackFunction:
+            self._register_definition(self._callback_functions, definition)
+        elif type(definition) == Implements:
+            self._implements.append(definition)
+        else:
+            raise ValueError('Unrecognized class definition %s in %s' % (str(type(definition)), filepath))
+
+        metadata = _Metadata(definition, filepath)
+        self._metadata_store.append(metadata)
+
+    @property
+    def interface_identifiers(self):
+        return self._interfaces.keys()
+
+    @property
+    def callback_interface_identifiers(self):
+        return self._callback_interfaces.keys()
+
+    @property
+    def namespace_identifiers(self):
+        return self._namespaces.keys()
+
+    @property
+    def dictionary_identifiers(self):
+        return self._dictionaries.keys()
+
+    @property
+    def enumeration_identifiers(self):
+        return self._enumerations.keys()
+
+    @property
+    def callback_function_identifiers(self):
+        return self._callback_functions.keys()
+
+    @property
+    def typedef_identifiers(self):
+        return self._typedefs.keys()
+
+    @property
+    def implements(self):
+        return self._implements
+
+    @property
+    def component(self):
+        return self._component
+
+    def _register_definition(self, definitions, definition):
+        identifier = definition.identifier
+        previous_definition = self.find_non_partial_definition(identifier)
+        if previous_definition and previous_definition == definition:
+            raise ValueError('Conflict: %s is defined in %s and %s' %
+                             (identifier, self.find_filepath(previous_definition),
+                              self.find_filepath(definition)))
+        definitions[identifier] = definition
+
+    def _register_partial_definition(self, definitions, definition):
+        identifier = definition.identifier
+        if identifier not in definitions:
+            definitions[identifier] = []
+        definitions[identifier].append(definition)
+
+
+class _Metadata(object):
+    """Metadata holds information of a definition which is not in spec.
+    - |filepath| shows the .idl file name where the definition is described.
+    """
+    def __init__(self, definition, filepath):
+        self._definition = definition
+        self._filepath = filepath
diff --git a/third_party/WebKit/Source/bindings/scripts/web_idl/collector.py b/third_party/WebKit/Source/bindings/scripts/web_idl/collector.py
new file mode 100644
index 0000000..180ea47
--- /dev/null
+++ b/third_party/WebKit/Source/bindings/scripts/web_idl/collector.py
@@ -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.
+
+import os
+import sys
+
+from .idl_definition_builder import IdlDefinitionBuilder
+from .collection import Collection
+
+
+# TODO(peria): Merge bindings/scripts/blink_idl_parser.py with tools/idl_parser,
+# and put in this directory. Then we can remove this sys.path update.
+_SCRIPTS_PATH = os.path.join(os.path.abspath(os.path.dirname(__file__)), os.pardir)
+sys.path.append(_SCRIPTS_PATH)
+
+import blink_idl_parser
+
+
+class Collector(object):
+
+    def __init__(self, component, parser=blink_idl_parser.BlinkIDLParser()):
+        self._component = component
+        self._collection = Collection(component)
+        self._parser = parser
+
+    def collect_from_idl_files(self, filepaths):
+        if type(filepaths) == str:
+            filepaths = [filepaths]
+        for filepath in filepaths:
+            try:
+                ast = blink_idl_parser.parse_file(self._parser, filepath)
+                self.collect_from_ast(ast)
+            except ValueError as ve:
+                raise ValueError('%s\nin file %s' % (str(ve), filepath))
+
+    def collect_from_idl_text(self, text, filename='TEXT'):
+        ast = self._parser.ParseText(filename, text)  # pylint: disable=no-member
+        self.collect_from_ast(ast)
+
+    def collect_from_ast(self, node):
+        for definition, filepath in IdlDefinitionBuilder.idl_definitions(node):
+            self._collection.register_definition(definition, filepath)
+
+    def get_collection(self):
+        return self._collection
diff --git a/third_party/WebKit/Source/bindings/scripts/web_idl/collector_test.py b/third_party/WebKit/Source/bindings/scripts/web_idl/collector_test.py
new file mode 100755
index 0000000..0678b03
--- /dev/null
+++ b/third_party/WebKit/Source/bindings/scripts/web_idl/collector_test.py
@@ -0,0 +1,180 @@
+#!/usr/bin/python
+# Copyright 2017 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import unittest
+
+from .collector import Collector
+
+
+class CollectorTest(unittest.TestCase):
+
+    def setUp(self):
+        self._collector = Collector(component='test')
+
+    def collect_from_idl_text(self, idl_text):
+        self._collector.collect_from_idl_text(idl_text)
+        return self._collector.get_collection()
+
+    def test_definition_filters(self):
+        idl_text = """
+        interface MyInterface {};
+        partial interface MyInterface {};
+        dictionary MyDictionary {};
+        dictionary MyDictionary2 {};
+        partial dictionary MyPartialDictionary {};
+        namespace MyNamespace {};
+        partial namespace MyNamespace {};
+        partial namespace MyNamespace2 {};
+        partial namespace MyNamespace2 {};
+        enum MyEnum { "FOO" };
+        callback MyCallbackFunction = void (DOMString arg);
+        typedef sequence<Point> Points;
+        Foo implements Bar;
+        """
+        collection = self.collect_from_idl_text(idl_text)
+        self.assertEqual(1, len(collection.callback_function_identifiers))
+        self.assertEqual(1, len(collection.enumeration_identifiers))
+        self.assertEqual(1, len(collection.interface_identifiers))
+        self.assertEqual(1, len(collection.namespace_identifiers))
+        self.assertEqual(1, len(collection.typedef_identifiers))
+        self.assertEqual(2, len(collection.dictionary_identifiers))
+        self.assertEqual(1, len(collection.implements))
+        self.assertEqual(2, len(collection.find_partial_definition('MyNamespace2')))
+
+    def test_interface(self):
+        idl_text = """
+        interface InterfaceSimpleMembers {
+            void operation1(DOMString arg);
+            attribute long longMember;
+        };
+        interface InheritInterface : InheritedInterface {};
+        partial interface PartialInterface {
+            attribute long longMember;
+        };
+        partial interface PartialInterface {
+            attribute long long longlongMember;
+        };
+        """
+        collection = self.collect_from_idl_text(idl_text)
+
+        interface = collection.find_non_partial_definition('InterfaceSimpleMembers')
+        self.assertEqual('InterfaceSimpleMembers', interface.identifier)
+        self.assertEqual(1, len(interface.attributes))
+        self.assertEqual(1, len(interface.operations))
+        self.assertEqual('operation1', interface.operations[0].identifier)
+        self.assertEqual('longMember', interface.attributes[0].identifier)
+
+        interface = collection.find_non_partial_definition('InheritInterface')
+        self.assertEqual('InheritInterface', interface.identifier)
+        self.assertEqual('InheritedInterface', interface.inherited_interface_name)
+
+        partial_interfaces = collection.find_partial_definition('PartialInterface')
+        self.assertTrue(partial_interfaces[0].is_partial)
+        self.assertTrue(partial_interfaces[1].is_partial)
+        attribute = partial_interfaces[0].attributes[0]
+        self.assertEqual('longMember', attribute.identifier)
+        attribute = partial_interfaces[1].attributes[0]
+        self.assertEqual('longlongMember', attribute.identifier)
+
+        idl_text = """
+        interface InterfaceAttributes {
+            attribute long longAttr;
+            readonly attribute octet readonlyAttr;
+            static attribute DOMString staticStringAttr;
+            attribute [TreatNullAs=EmptyString] DOMString annotatedTypeAttr;
+            [Unforgeable] attribute DOMString? extendedAttributeAttr;
+        };
+        """
+        collection = self.collect_from_idl_text(idl_text)
+        interface = collection.find_non_partial_definition('InterfaceAttributes')
+        attributes = interface.attributes
+        self.assertEqual(5, len(attributes))
+        attribute = attributes[0]
+        self.assertEqual('longAttr', attribute.identifier)
+        self.assertEqual('Long', attribute.type.type_name)
+
+        attribute = attributes[1]
+        self.assertEqual('readonlyAttr', attribute.identifier)
+        self.assertEqual('Octet', attribute.type.type_name)
+        self.assertTrue(attribute.is_readonly)
+
+        attribute = attributes[2]
+        self.assertEqual('staticStringAttr', attribute.identifier)
+        self.assertEqual('String', attribute.type.type_name)
+        self.assertTrue(attribute.is_static)
+
+        attribute = attributes[3]
+        self.assertEqual('annotatedTypeAttr', attribute.identifier)
+        self.assertEqual('String', attribute.type.type_name)
+        self.assertEqual('EmptyString', attribute.type.treat_null_as)
+
+        attribute = attributes[4]
+        self.assertEqual('extendedAttributeAttr', attribute.identifier)
+        self.assertEqual('String', attribute.type.type_name)
+        self.assertTrue(attribute.type.is_nullable)
+        self.assertTrue(attribute.extended_attribute_list.has('Unforgeable'))
+
+    def test_extended_attributes(self):
+        idl_text = """
+        [
+            NoInterfaceObject,
+            OriginTrialEnabled=FooBar
+        ] interface ExtendedAttributeInterface {};
+        """
+        collection = self.collect_from_idl_text(idl_text)
+
+        interface = collection.find_non_partial_definition('ExtendedAttributeInterface')
+        extended_attribute_list = interface.extended_attribute_list
+        self.assertTrue(extended_attribute_list.has('OriginTrialEnabled'))
+        self.assertTrue(extended_attribute_list.has('NoInterfaceObject'))
+        self.assertEqual('FooBar', extended_attribute_list.get('OriginTrialEnabled'))
+
+        idl_text = """
+        [
+            Constructor,
+            Constructor(DOMString arg),
+            CustomConstructor,
+            CustomConstructor(long arg),
+            NamedConstructor=Audio,
+            NamedConstructor=Audio(DOMString src)
+        ] interface ConstructorInterface {};
+        """
+        collection = self.collect_from_idl_text(idl_text)
+
+        interface = collection.find_non_partial_definition('ConstructorInterface')
+        constructors = interface.constructors
+        self.assertEqual(4, len(constructors))
+        self.assertFalse(constructors[0].is_custom)
+        self.assertFalse(constructors[1].is_custom)
+        self.assertTrue(constructors[2].is_custom)
+        self.assertTrue(constructors[3].is_custom)
+        named_constructors = interface.named_constructors
+        self.assertEqual('Audio', named_constructors[0].identifier)
+        self.assertEqual('Audio', named_constructors[1].identifier)
+        self.assertEqual('arg', constructors[1].arguments[0].identifier)
+        self.assertEqual('arg', constructors[3].arguments[0].identifier)
+        self.assertEqual('src', named_constructors[1].arguments[0].identifier)
+
+        idl_text = """
+        [
+            Exposed=(Window, Worker),
+            Exposed(Window Feature1, Worker Feature2)
+        ] interface ExposedInterface {};
+        """
+        collection = self.collect_from_idl_text(idl_text)
+
+        interface = collection.find_non_partial_definition('ExposedInterface')
+        exposures = interface.exposures
+        self.assertEqual(4, len(exposures))
+        self.assertEqual('Window', exposures[0].global_interface)
+        self.assertEqual('Worker', exposures[1].global_interface)
+        self.assertEqual('Window', exposures[2].global_interface)
+        self.assertEqual('Worker', exposures[3].global_interface)
+        self.assertEqual('Feature1', exposures[2].runtime_enabled_feature)
+        self.assertEqual('Feature2', exposures[3].runtime_enabled_feature)
+
+
+if __name__ == '__main__':
+    unittest.main(verbosity=2)
diff --git a/third_party/WebKit/Source/bindings/scripts/web_idl/constant.py b/third_party/WebKit/Source/bindings/scripts/web_idl/constant.py
new file mode 100644
index 0000000..a7e4072
--- /dev/null
+++ b/third_party/WebKit/Source/bindings/scripts/web_idl/constant.py
@@ -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.
+
+from .extended_attribute import ExtendedAttributeList
+from .idl_types import RecordType
+from .idl_types import SequenceType
+from .utilities import assert_no_extra_args
+
+
+# https://heycam.github.io/webidl/#idl-constants
+class Constant(object):
+    _INVALID_IDENTIFIERS = frozenset(['length', 'name', 'prototype'])
+    _INVALID_TYPES = frozenset([SequenceType, RecordType])
+
+    def __init__(self, **kwargs):
+        self._identifier = kwargs.pop('identifier')
+        self._type = kwargs.pop('type')
+        self._value = kwargs.pop('value')
+        self._extended_attribute_list = kwargs.pop('extended_attribute_list', ExtendedAttributeList())
+        assert_no_extra_args(kwargs)
+
+        if self.identifier in Constant._INVALID_IDENTIFIERS:
+            raise ValueError('Invalid identifier for a constant: %s' % self.identifier)
+        if type(self.type) in Constant._INVALID_TYPES:
+            raise ValueError('sequence<T> must not be used as the type of a constant.')
+
+    @property
+    def identifier(self):
+        return self._identifier
+
+    @property
+    def type(self):
+        return self._type
+
+    @property
+    def value(self):
+        return self._value
+
+    @property
+    def extended_attribute_list(self):
+        return self._extended_attribute_list
diff --git a/third_party/WebKit/Source/bindings/scripts/web_idl/dictionary.py b/third_party/WebKit/Source/bindings/scripts/web_idl/dictionary.py
new file mode 100644
index 0000000..238aaf0
--- /dev/null
+++ b/third_party/WebKit/Source/bindings/scripts/web_idl/dictionary.py
@@ -0,0 +1,69 @@
+# 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.
+
+from .extended_attribute import ExtendedAttributeList
+from .utilities import assert_no_extra_args
+
+
+# https://heycam.github.io/webidl/#idl-dictionaries
+class Dictionary(object):
+
+    def __init__(self, **kwargs):
+        self._identifier = kwargs.pop('identifier')
+        self._members = kwargs.pop('members', {})
+        self._inherited_dictionary_name = kwargs.pop('inherited_dictionary_name', None)
+        self._is_partial = kwargs.pop('is_partial', False)
+        self._extended_attribute_list = kwargs.pop('extended_attribute_list', ExtendedAttributeList())
+        assert_no_extra_args(kwargs)
+
+    @property
+    def identifier(self):
+        return self._identifier
+
+    @property
+    def members(self):
+        return self._members
+
+    @property
+    def inherited_dictionary_name(self):
+        return self._inherited_dictionary_name
+
+    @property
+    def is_partial(self):
+        return self._is_partial
+
+    @property
+    def extended_attribute_list(self):
+        return self._extended_attribute_list
+
+
+class DictionaryMember(object):
+
+    def __init__(self, **kwargs):
+        self._identifier = kwargs.pop('identifier')
+        self._type = kwargs.pop('type')
+        self._default_value = kwargs.pop('default_value', None)
+        self._is_required = kwargs.pop('is_required', False)
+        self._extended_attribute_list = kwargs.pop('extended_attribute_list', ExtendedAttributeList())
+        assert_no_extra_args(kwargs)
+
+    @property
+    def identifier(self):
+        return self._identifier
+
+    @property
+    def type(self):
+        return self._type
+
+    @property
+    def default_value(self):
+        return self._default_value
+
+    @property
+    def is_required(self):
+        return self._is_required
+
+    @property
+    def extended_attribute_list(self):
+        return self._extended_attribute_list
diff --git a/third_party/WebKit/Source/bindings/scripts/web_idl/ecma_script_types.py b/third_party/WebKit/Source/bindings/scripts/web_idl/ecma_script_types.py
new file mode 100644
index 0000000..8d2dd0c
--- /dev/null
+++ b/third_party/WebKit/Source/bindings/scripts/web_idl/ecma_script_types.py
@@ -0,0 +1,32 @@
+# 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.
+
+from .idl_types import TypeBase
+from .utilities import assert_no_extra_args
+
+
+class EcmaScriptType(TypeBase):
+    """
+    EcmascriptType represents an EcmaScript type, which appears in Chromium IDL files.
+    @param string type_name   : the identifier of a named definition to refer
+    @param bool   is_nullable : True if the type is nullable (optional)
+    """
+    _ALLOWED_TYPE_NAMES = frozenset(['Date'])
+
+    def __init__(self, **kwargs):
+        self._type_name = kwargs.pop('type_name')
+        self._is_nullable = kwargs.pop('is_nullable', False)
+        assert_no_extra_args(kwargs)
+
+        # Now we use only 'Date' type.
+        if self.type_name not in EcmaScriptType._ALLOWED_TYPE_NAMES:
+            raise ValueError('Unknown type name: %s' % self.type_name)
+
+    @property
+    def type_name(self):
+        return self._type_name
+
+    @property
+    def is_nullable(self):
+        return self._is_nullable
diff --git a/third_party/WebKit/Source/bindings/scripts/web_idl/enumeration.py b/third_party/WebKit/Source/bindings/scripts/web_idl/enumeration.py
new file mode 100644
index 0000000..6fccc6d
--- /dev/null
+++ b/third_party/WebKit/Source/bindings/scripts/web_idl/enumeration.py
@@ -0,0 +1,29 @@
+# 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.
+
+from .extended_attribute import ExtendedAttributeList
+from .utilities import assert_no_extra_args
+
+
+# https://heycam.github.io/webidl/#idl-enums
+class Enumeration(object):
+
+    def __init__(self, **kwargs):
+        self._identifier = kwargs.pop('identifier')
+        self._values = kwargs.pop('values', [])
+        # Extended attributes on enumerations are not allowed in spec, but Blink uses them.
+        self._extended_attribute_list = kwargs.pop('extended_attribute_list', ExtendedAttributeList())
+        assert_no_extra_args(kwargs)
+
+    @property
+    def identifier(self):
+        return self._identifier
+
+    @property
+    def values(self):
+        return self._values
+
+    @property
+    def extended_attribute_list(self):
+        return self._extended_attribute_list
diff --git a/third_party/WebKit/Source/bindings/scripts/web_idl/extended_attribute.py b/third_party/WebKit/Source/bindings/scripts/web_idl/extended_attribute.py
new file mode 100644
index 0000000..07847734
--- /dev/null
+++ b/third_party/WebKit/Source/bindings/scripts/web_idl/extended_attribute.py
@@ -0,0 +1,108 @@
+# 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.
+
+from .utilities import assert_no_extra_args
+
+
+# https://heycam.github.io/webidl/#idl-extended-attributes
+# To work with [Exposed], [Constructor], [CustomConstrucotr], and [NamedConstructor] easily, we define some classes
+# for them in this file.
+
+class ExtendedAttributeList(object):
+
+    def __init__(self, **kwargs):
+        self._extended_attributes = kwargs.pop('extended_attributes', {})
+        self._exposures = tuple(kwargs.pop('exposures', []))
+        constructors = kwargs.pop('constructors', [])
+        self._constructors = tuple([ctor for ctor in constructors if type(ctor) == Constructor])
+        self._named_constructors = tuple([ctor for ctor in constructors if type(ctor) == NamedConstructor])
+
+        if self.exposures:
+            self._extended_attributes['Exposed'] = self.exposures
+        if self.named_constructors:
+            self._extended_attributes['NamedConstructor'] = self.named_constructors
+        if any(ctor.is_custom for ctor in self.constructors):
+            self._extended_attributes['CustomConstructor'] = [ctor for ctor in self.constructors if ctor.is_custom]
+        if any(not ctor.is_custom for ctor in self.constructors):
+            self._extended_attributes['CustomConstructor'] = [ctor for ctor in self.constructors if not ctor.is_custom]
+
+    def get(self, key):
+        return self.extended_attributes.get(key)
+
+    def has(self, key):
+        return key in self.extended_attributes
+
+    @property
+    def extended_attributes(self):
+        """
+        [Exposed], [Constructor], [CustomConstrucotr], and [NamedConstructor] can be taken with
+        other property methods, but the returned value of this method also includes them.
+        """
+        return self._extended_attributes
+
+    @property
+    def constructors(self):
+        return self._constructors
+
+    @property
+    def named_constructors(self):
+        return self._named_constructors
+
+    @property
+    def exposures(self):
+        return self._exposures
+
+
+# https://heycam.github.io/webidl/#Constructor
+class Constructor(object):
+
+    def __init__(self, **kwargs):
+        self._arguments = kwargs.pop('arguments', [])
+        self._is_custom = kwargs.pop('is_custom', False)
+        assert_no_extra_args(kwargs)
+
+    @property
+    def arguments(self):
+        return self._arguments
+
+    @property
+    def is_custom(self):
+        return self._is_custom
+
+
+# https://heycam.github.io/webidl/#NamedConstructor
+class NamedConstructor(object):
+
+    def __init__(self, **kwargs):
+        self._identifier = kwargs.pop('identifier', None)
+        self._arguments = kwargs.pop('arguments', [])
+        assert_no_extra_args(kwargs)
+
+    @property
+    def identifier(self):
+        return self._identifier
+
+    @property
+    def arguments(self):
+        return self._arguments
+
+
+# https://heycam.github.io/webidl/#Exposed
+class Exposure(object):
+    """Exposure holds an exposed target, and can hold a runtime enabled condition.
+    "[Exposed=global_interface]" is represented as Exposure(global_interface), and
+    "[Exposed(global_interface runtime_enabled_feature)] is represented as Exposure(global_interface, runtime_enabled_feature).
+    """
+    def __init__(self, **kwargs):
+        self._global_interface = kwargs.pop('global_interface')
+        self._runtime_enabled_feature = kwargs.pop('runtime_enabled_feature', None)
+        assert_no_extra_args(kwargs)
+
+    @property
+    def global_interface(self):
+        return self._global_interface
+
+    @property
+    def runtime_enabled_feature(self):
+        return self._runtime_enabled_feature
diff --git a/third_party/WebKit/Source/bindings/scripts/web_idl/idl_definition_builder.py b/third_party/WebKit/Source/bindings/scripts/web_idl/idl_definition_builder.py
new file mode 100644
index 0000000..45d40a8
--- /dev/null
+++ b/third_party/WebKit/Source/bindings/scripts/web_idl/idl_definition_builder.py
@@ -0,0 +1,705 @@
+# 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.
+
+from . import literal_token
+from .argument import Argument
+from .attribute import Attribute
+from .callback_function import CallbackFunction
+from .callback_interface import CallbackInterface
+from .constant import Constant
+from .dictionary import Dictionary
+from .dictionary import DictionaryMember
+from .ecma_script_types import EcmaScriptType
+from .enumeration import Enumeration
+from .extended_attribute import Constructor
+from .extended_attribute import Exposure
+from .extended_attribute import ExtendedAttributeList
+from .extended_attribute import NamedConstructor
+from .idl_types import AnyType
+from .idl_types import FrozenArrayType
+from .idl_types import ObjectType
+from .idl_types import PrimitiveType
+from .idl_types import PromiseType
+from .idl_types import RecordType
+from .idl_types import SequenceType
+from .idl_types import StringType
+from .idl_types import TypePlaceHolder
+from .idl_types import UnionType
+from .idl_types import VoidType
+from .implements import Implements
+from .interface import Interface
+from .interface import Iterable
+from .interface import Maplike
+from .interface import Serializer
+from .interface import Setlike
+from .literal_token import LiteralToken
+from .namespace import Namespace
+from .operation import Operation
+from .typedef import Typedef
+
+
+class IdlDefinitionBuilder(object):
+
+    @staticmethod
+    def idl_definitions(node):
+        """
+        This method is a generator that returns an instance of an IDL definition class(*) and the IDL file path |node| refers
+        on each call.  |node| must be a root node of an AST tree, and while the same |node| is used, this method iterates
+        the AST tree from |node|.
+        (*) "IDL definition class" means either of Interface, Namespace, Dictionary, Enumeration, Typedef, CallbackFunction,
+            or Implements classes.
+        """
+        assert node.GetClass() == 'File', (
+            'Root node of AST must be a File node, but is %s.' % node.GetClass())
+
+        filepath = node.GetProperty('FILENAME')
+        for child in node.GetChildren():
+            child_class = child.GetClass()
+            if child_class == 'Interface':
+                # interface, partial interface, callback interface
+                interface = IdlDefinitionBuilder.create_interface(child)
+                yield interface, filepath
+            elif child_class == 'Namespace':
+                # namespace, partial namespace
+                namespace = IdlDefinitionBuilder.create_namespace(child)
+                yield namespace, filepath
+            elif child_class == 'Dictionary':
+                # dictionary, partial dictionary
+                dictionary = IdlDefinitionBuilder.create_dictionary(child)
+                yield dictionary, filepath
+            elif child_class == 'Enum':
+                enumeration = IdlDefinitionBuilder.create_enumeration(child)
+                yield enumeration, filepath
+            elif child_class == 'Typedef':
+                typedef = IdlDefinitionBuilder.create_typedef(child)
+                yield typedef, filepath
+            elif child_class == 'Callback':
+                callback_function = IdlDefinitionBuilder.create_callback_function(child)
+                yield callback_function, filepath
+            elif child_class == 'Implements':
+                implements = IdlDefinitionBuilder.create_implements(child)
+                yield implements, filepath
+            else:
+                raise ValueError('Unrecognized class definition: %s' % child_class)
+
+    @staticmethod
+    def create_interface(node):
+        assert node.GetClass() == 'Interface', 'Unknown node class: %s' % node.GetClass()
+
+        identifier = node.GetName()
+        is_callback = bool(node.GetProperty('CALLBACK'))
+        is_partial = bool(node.GetProperty('PARTIAL'))
+        attributes = []
+        operations = []
+        constants = []
+        iterable = None
+        maplike = None
+        setlike = None
+        serializer = None
+        inherited_interface_name = None
+        extended_attribute_list = None
+
+        for child in node.GetChildren():
+            child_class = child.GetClass()
+            if child_class == 'Inherit':
+                inherited_interface_name = child.GetName()
+            elif child_class == 'Attribute':
+                attributes.append(IdlDefinitionBuilder.create_attribute(child))
+            elif child_class == 'Operation':
+                operations.append(IdlDefinitionBuilder.create_operation(child))
+            elif child_class == 'Const':
+                constants.append(IdlDefinitionBuilder.create_constant(child))
+            elif child_class == 'Stringifier':
+                stringifier = IdlDefinitionBuilder.create_stringifier(child)
+                # Stringifier is either of Attribute or Operation.
+                if type(stringifier) == Operation:
+                    operations.append(stringifier)
+                elif type(stringifier) == Attribute:
+                    attributes.append(stringifier)
+                else:
+                    assert False, 'Stringifer must be an attribute or an operation.'
+            elif child_class == 'Iterable':
+                iterable = IdlDefinitionBuilder.create_iterable(child)
+            elif child_class == 'Maplike':
+                maplike = IdlDefinitionBuilder.create_maplike(child)
+            elif child_class == 'Setlike':
+                setlike = IdlDefinitionBuilder.create_setlike(child)
+            elif child_class == 'Serializer':
+                serializer = IdlDefinitionBuilder.create_serializer(child)
+            elif child_class == 'ExtAttributes':
+                extended_attribute_list = IdlDefinitionBuilder.create_extended_attribute_list(child)
+            else:
+                assert False, 'Unrecognized node class: %s' % child_class
+
+        if is_callback:
+            return CallbackInterface(identifier=identifier, attributes=attributes, operations=operations, constants=constants,
+                                     inherited_interface_name=inherited_interface_name,
+                                     extended_attribute_list=extended_attribute_list)
+
+        return Interface(identifier=identifier, attributes=attributes, operations=operations, constants=constants,
+                         iterable=iterable, maplike=maplike, setlike=setlike, serializer=serializer,
+                         inherited_interface_name=inherited_interface_name, is_partial=is_partial,
+                         extended_attribute_list=extended_attribute_list)
+
+    @staticmethod
+    def create_iterable(node):
+        assert node.GetClass() == 'Iterable', 'Unknown node class: %s' % node.GetClass()
+
+        key_type = None
+        value_type = None
+        extended_attribute_list = None
+        type_nodes = []
+        for child in node.GetChildren():
+            child_class = child.GetClass()
+            if child_class == 'ExtAttributes':
+                extended_attribute_list = IdlDefinitionBuilder.create_extended_attribute_list(child)
+            elif child_class == 'Type':
+                type_nodes.append(child)
+            else:
+                assert False, 'Unrecognized node class: %s' % child_class
+        assert len(type_nodes) in [1, 2], 'iterable<> expects 1 or 2 type parameters, but got %d.' % len(type_nodes)
+
+        if len(type_nodes) == 1:
+            value_type = IdlDefinitionBuilder.create_type(type_nodes[0])
+        elif len(type_nodes) == 2:
+            key_type = IdlDefinitionBuilder.create_type(type_nodes[0])
+            value_type = IdlDefinitionBuilder.create_type(type_nodes[1])
+
+        return Iterable(key_type=key_type, value_type=value_type, extended_attribute_list=extended_attribute_list)
+
+    @staticmethod
+    def create_maplike(node):
+        assert node.GetClass() == 'Maplike', 'Unknown node class: %s' % node.GetClass()
+
+        is_readonly = bool(node.GetProperty('READONLY'))
+        types = []
+        for child in node.GetChildren():
+            if child.GetClass() == 'Type':
+                types.append(child)
+            else:
+                raise ValueError('Unrecognized node class: %s' % child.GetClass())
+
+        assert len(types) == 2, 'maplike<K, V> requires two type parameters, but got %d.' % len(types)
+        key_type = IdlDefinitionBuilder.create_type(types[0])
+        value_type = IdlDefinitionBuilder.create_type(types[1])
+        return Maplike(key_type=key_type, value_type=value_type, is_readonly=is_readonly)
+
+    @staticmethod
+    def create_setlike(node):
+        assert node.GetClass() == 'Setlike', 'Unknown node class: %s' % node.GetClass()
+
+        is_readonly = bool(node.GetProperty('READONLY'))
+        children = node.GetChildren()
+        assert len(children) == 1, 'setlike<T> requires one type parameter, but got %d' % len(children)
+        value_type = IdlDefinitionBuilder.create_type(children[0])
+        return Setlike(value_type=value_type, is_readonly=is_readonly)
+
+    # BUG(736332): Remove support of legacy serializer.
+    @staticmethod
+    def create_serializer(node):
+        assert node.GetClass() == 'Serializer', 'Unknown node class: %s' % node.GetClass()
+
+        is_map = False
+        has_attribute = False
+        has_inherit = False
+
+        for child in node.GetChildren():
+            child_class = child.GetClass()
+            if child_class == 'Map':
+                is_map = True
+                has_attribute = bool(child.GetProperty('ATTRIBUTE'))
+                has_inherit = bool(child.GetProperty('INHERIT'))
+            else:
+                assert False, 'Unrecognized node class: %s' % child_class
+        return Serializer(is_map=is_map, has_attribute=has_attribute, has_inherit=has_inherit)
+
+    @staticmethod
+    def create_namespace(node):
+        assert node.GetClass() == 'Namespace', 'Unknown node class: %s' % node.GetClass()
+
+        identifier = node.GetName()
+        is_partial = bool(node.GetProperty('PARTIAL'))
+        attributes = []
+        operations = []
+        extended_attribute_list = None
+
+        children = node.GetChildren()
+        for child in children:
+            child_class = child.GetClass()
+            if child_class == 'Attribute':
+                attributes.append(IdlDefinitionBuilder.create_attribute(child))
+            elif child_class == 'Operation':
+                operations.append(IdlDefinitionBuilder.create_operation(child))
+            elif child_class == 'ExtAttributes':
+                extended_attribute_list = IdlDefinitionBuilder.create_extended_attribute_list(child)
+            else:
+                assert False, 'Unrecognized node class: %s' % child_class
+
+        return Namespace(identifier=identifier, attributes=attributes, operations=operations,
+                         is_partial=is_partial, extended_attribute_list=extended_attribute_list)
+
+    @staticmethod
+    def create_constant(node):
+        assert node.GetClass() == 'Const', 'Unknown node class: %s' % node.GetClass()
+
+        identifier = node.GetName()
+        idl_type = None
+        value = None
+        extended_attribute_list = None
+
+        children = node.GetChildren()
+        assert len(children) in [2, 3], 'Expected 2 or 3 children for Constant, got %s' % len(children)
+        idl_type = IdlDefinitionBuilder.create_base_type(children[0])
+
+        value_node = children[1]
+        assert value_node.GetClass() == 'Value', 'Expected Value node, got %s' % value_node.GetClass()
+        # Regardless of its type, value is stored in string format.
+        value = value_node.GetProperty('VALUE')
+
+        if len(children) == 3:
+            extended_attribute_list = IdlDefinitionBuilder.create_extended_attribute_list(children[2])
+
+        return Constant(identifier=identifier, type=idl_type, value=value, extended_attribute_list=extended_attribute_list)
+
+    @staticmethod
+    def create_attribute(node, ext_attrs=None):
+        assert node.GetClass() == 'Attribute', 'Unknown node class: %s' % node.GetClass()
+
+        identifier = node.GetName()
+        is_static = bool(node.GetProperty('STATIC'))
+        is_readonly = bool(node.GetProperty('READONLY'))
+        idl_type = None
+        extended_attribute_list = ext_attrs
+        for child in node.GetChildren():
+            child_class = child.GetClass()
+            if child_class == 'Type':
+                idl_type = IdlDefinitionBuilder.create_type(child)
+            elif child_class == 'ExtAttributes':
+                extended_attribute_list = IdlDefinitionBuilder.create_extended_attribute_list(child, extended_attribute_list)
+            else:
+                assert False, 'Unrecognized node class: %s' % child_class
+
+        return Attribute(identifier=identifier, type=idl_type, is_static=is_static, is_readonly=is_readonly,
+                         extended_attribute_list=extended_attribute_list)
+
+    @staticmethod
+    def create_operation(node, ext_attrs=None):
+        assert node.GetClass() == 'Operation', 'Unknown node class: %s' % node.GetClass()
+
+        return_type = None
+        arguments = None
+        special_keywords = []
+        is_static = False
+        extended_attribute_list = ext_attrs
+
+        identifier = node.GetName()
+        is_static = bool(node.GetProperty('STATIC'))
+        properties = node.GetProperties()
+        for special_keyword in ['DELETER', 'GETTER', 'LEGACYCALLER', 'SETTER']:
+            if special_keyword in properties:
+                special_keywords.append(special_keyword.lower())
+
+        for child in node.GetChildren():
+            child_class = child.GetClass()
+            if child_class == 'Arguments':
+                arguments = IdlDefinitionBuilder.create_arguments(child)
+            elif child_class == 'Type':
+                return_type = IdlDefinitionBuilder.create_type(child)
+            elif child_class == 'ExtAttributes':
+                extended_attribute_list = IdlDefinitionBuilder.create_extended_attribute_list(child, extended_attribute_list)
+            else:
+                assert False, 'Unrecognized node class: %s' % child_class
+
+        assert identifier or special_keywords, 'Regular operations must have an identifier.'
+        return Operation(identifier=identifier, return_type=return_type, arguments=arguments,
+                         special_keywords=special_keywords, is_static=is_static,
+                         extended_attribute_list=extended_attribute_list)
+
+    @staticmethod
+    def create_stringifier(node):
+        assert node.GetClass() == 'Stringifier'
+
+        # stringifier can be either of an attribute or an operation. This method checks which type we can
+        # convert the given |node| subtree.
+        ext_attributes = None
+        stringifier = None
+
+        for child in node.GetChildren():
+            child_class = child.GetClass()
+            if child_class == 'ExtAttributes':
+                ext_attributes = IdlDefinitionBuilder.create_extended_attribute_list(child)
+            elif child_class == 'Attribute':
+                assert stringifier is None
+                stringifier = IdlDefinitionBuilder.create_attribute(child, ext_attributes)
+            elif child_class == 'Operation':
+                assert stringifier is None
+                stringifier = IdlDefinitionBuilder.create_operation(child, ext_attributes)
+
+        if stringifier is None:
+            # The stringifer keyword is declared in a shorthand style.
+            # https://heycam.github.io/webidl/#idl-stringifiers
+            return_type = StringType(string_type='DOMString')
+            stringifier = Operation(identifier='', return_type=return_type, extended_attribute_list=ext_attributes)
+
+        return stringifier
+
+    @staticmethod
+    def create_dictionary(node):
+        assert node.GetClass() == 'Dictionary', 'Unknown node class: %s' % node.GetClass()
+
+        identifier = node.GetName()
+        is_partial = bool(node.GetProperty('PARTIAL'))
+        members = {}
+        inherited_dictionary_name = None
+        extended_attribute_list = None
+        for child in node.GetChildren():
+            child_class = child.GetClass()
+            if child_class == 'Inherit':
+                inherited_dictionary_name = child.GetName()
+            elif child_class == 'Key':
+                member = IdlDefinitionBuilder.create_dictionary_member(child)
+                # No duplicates are allowed through inheritances.
+                assert member.identifier not in members, 'Duplicated dictionary members: %s' % member.identifier
+                members[member.identifier] = member
+            elif child.GetClass() == 'ExtAttributes':
+                # Extended attributes are not applicable to Dictionary in spec, but Blink defines an extended attribute which
+                # is applicable to Dictionary.
+                extended_attribute_list = IdlDefinitionBuilder.create_extended_attribute_list(child)
+            else:
+                assert False, 'Unrecognized node class: %s' % child_class
+
+        return Dictionary(identifier=identifier, members=members, inherited_dictionary_name=inherited_dictionary_name,
+                          is_partial=is_partial, extended_attribute_list=extended_attribute_list)
+
+    @staticmethod
+    def create_dictionary_member(node):
+        assert node.GetClass() == 'Key', 'Unknown node class: %s' % node.GetClass()
+
+        identifier = node.GetName()
+        is_required = bool(node.GetProperty('REQUIRED'))
+        idl_type = None
+        default_value = None
+        extended_attribute_list = None
+        for child in node.GetChildren():
+            child_class = child.GetClass()
+            if child_class == 'Type':
+                idl_type = IdlDefinitionBuilder.create_type(child)
+            elif child_class == 'Default':
+                default_value = IdlDefinitionBuilder.create_literal_token(child)
+            elif child_class == 'ExtAttributes':
+                extended_attribute_list = IdlDefinitionBuilder.create_extended_attribute_list(child)
+            else:
+                assert False, 'Unrecognized node class: %s' % child_class
+        return DictionaryMember(identifier=identifier, type=idl_type, default_value=default_value,
+                                is_required=is_required, extended_attribute_list=extended_attribute_list)
+
+    @staticmethod
+    def create_enumeration(node):
+        assert node.GetClass() == 'Enum', 'Unknown node class: %s' % node.GetClass()
+        identifier = node.GetName()
+        values = []
+        extended_attribute_list = None
+
+        for child in node.GetChildren():
+            if child.GetClass() == 'ExtAttributes':
+                extended_attribute_list = IdlDefinitionBuilder.create_extended_attribute_list(child)
+            else:
+                values.append(child.GetName())
+        return Enumeration(identifier=identifier, values=values, extended_attribute_list=extended_attribute_list)
+
+    @staticmethod
+    def create_callback_function(node):
+        assert node.GetClass() == 'Callback', 'Unknown node class: %s' % node.GetClass()
+        identifier = node.GetName()
+        return_type = None
+        arguments = None
+        extended_attribute_list = None
+
+        children = node.GetChildren()
+        assert len(children) in [2, 3], 'Expected 2 or 3 children, got %s' % len(children)
+        for child in children:
+            child_class = child.GetClass()
+            if child_class == 'Type':
+                return_type = IdlDefinitionBuilder.create_type(child)
+            elif child_class == 'Arguments':
+                arguments = IdlDefinitionBuilder.create_arguments(child)
+            elif child_class == 'ExtAttributes':
+                extended_attribute_list = IdlDefinitionBuilder.create_extended_attribute_list(child)
+            else:
+                assert False, 'Unknown node: %s' % child_class
+        return CallbackFunction(identifier=identifier, return_type=return_type, arguments=arguments,
+                                extended_attribute_list=extended_attribute_list)
+
+    @staticmethod
+    def create_typedef(node):
+        assert node.GetClass() == 'Typedef', 'Unknown node class: %s' % node.GetClass()
+        identifier = node.GetName()
+        children = node.GetChildren()
+        assert len(children) == 1, 'Typedef requires 1 child node, but got %d.' % len(children)
+        actual_type = IdlDefinitionBuilder.create_type(children[0])
+
+        return Typedef(identifier=identifier, type=actual_type)
+
+    @staticmethod
+    def create_implements(node):
+        assert node.GetClass() == 'Implements', 'Unknown node class: %s' % node.GetClass()
+        implementer_name = node.GetName()
+        implementee_name = node.GetProperty('REFERENCE')
+
+        return Implements(implementer_name=implementer_name, implementee_name=implementee_name)
+
+    @staticmethod
+    def create_type(node):
+        assert node.GetClass() == 'Type', 'Expecting Type node, but %s' % node.GetClass()
+
+        children = node.GetChildren()
+        assert len(children) in [1, 2], 'Type node expects 1 or 2 child(ren), got %s.' % len(children)
+
+        is_nullable = bool(node.GetProperty('NULLABLE'))
+        extended_attribute_list = None
+        if len(children) == 2:
+            extended_attribute_list = IdlDefinitionBuilder.create_extended_attribute_list(children[1])
+
+        return IdlDefinitionBuilder.create_base_type(children[0], is_nullable, extended_attribute_list)
+
+    @staticmethod
+    def create_base_type(node, is_nullable=False, extended_attribute_list=None):
+        node_class = node.GetClass()
+        if node_class == 'Typeref':
+            return IdlDefinitionBuilder.create_type_place_holder(node, is_nullable)
+        if node_class == 'PrimitiveType':
+            return IdlDefinitionBuilder.create_primitive(node, is_nullable, extended_attribute_list)
+        if node_class == 'StringType':
+            return IdlDefinitionBuilder.create_string(node, is_nullable, extended_attribute_list)
+        if node_class == 'Any':
+            return IdlDefinitionBuilder.create_any()
+        if node_class == 'UnionType':
+            return IdlDefinitionBuilder.create_union(node, is_nullable)
+        if node_class == 'Promise':
+            return IdlDefinitionBuilder.create_promise(node)
+        if node_class == 'Record':
+            return IdlDefinitionBuilder.create_record(node, is_nullable)
+        if node_class == 'Sequence':
+            return IdlDefinitionBuilder.create_sequence(node, is_nullable)
+        if node_class == 'FrozenArray':
+            return IdlDefinitionBuilder.create_frozen_array(node, is_nullable)
+        assert False, 'Unrecognized node class: %s' % node_class
+
+    @staticmethod
+    def create_type_place_holder(node, is_nullable=False):
+        assert node.GetClass() == 'Typeref', 'Unknown node class: %s' % node.GetClass()
+        return TypePlaceHolder(identifier=node.GetName(), is_nullable=is_nullable)
+
+    @staticmethod
+    def create_string(node, is_nullable=False, extended_attribute_list=None):
+        assert node.GetClass() == 'StringType', 'Unknown node class: %s' % node.GetClass()
+
+        string_type = node.GetName()
+        treat_null_as = None
+        if extended_attribute_list:
+            treat_null_as = extended_attribute_list.get('TreatNullAs')
+        return StringType(string_type=string_type, is_nullable=is_nullable, treat_null_as=treat_null_as)
+
+    @staticmethod
+    def create_primitive(node, is_nullable=False, extended_attribute_list=None):
+        assert node.GetClass() == 'PrimitiveType', 'Unknown node class: %s' % node.GetClass()
+
+        type_name = node.GetName()
+        if type_name == 'object':
+            return ObjectType(is_nullable=is_nullable)
+        if type_name == 'void':
+            return VoidType()
+        if type_name in ['Date']:
+            return EcmaScriptType(type_name=type_name, is_nullable=is_nullable)
+
+        if node.GetProperty('UNRESTRICTED'):
+            type_name = 'unrestricted ' + type_name
+        is_clamp = False
+        is_enforce_range = False
+        if extended_attribute_list:
+            is_clamp = extended_attribute_list.has('Clamp')
+            is_enforce_range = extended_attribute_list.has('EnforceRange')
+
+        return PrimitiveType(name=type_name, is_nullable=is_nullable, is_clamp=is_clamp, is_enforce_range=is_enforce_range)
+
+    @staticmethod
+    def create_any():
+        return AnyType()
+
+    @staticmethod
+    def create_union(node, is_nullable=False):
+        assert node.GetClass() == 'UnionType', 'Unknown node class: %s' % node.GetClass()
+
+        member_types = [IdlDefinitionBuilder.create_type(child) for child in node.GetChildren()]
+        return UnionType(member_types=member_types, is_nullable=is_nullable)
+
+    @staticmethod
+    def create_promise(node):
+        assert node.GetClass() == 'Promise', 'Unknown node class: %s' % node.GetClass()
+
+        children = node.GetChildren()
+        assert len(children) == 1, 'Promise<T> node expects 1 child, got %d' % len(children)
+        result_type = IdlDefinitionBuilder.create_type(children[0])
+        return PromiseType(result_type=result_type)
+
+    @staticmethod
+    def create_record(node, is_nullable=False):
+        assert node.GetClass() == 'Record', 'Unknown node class: %s' % node.GetClass()
+
+        children = node.GetChildren()
+        assert len(children) == 2, 'record<K,V> node expects exactly 2 children, got %d.' % len(children)
+
+        key_node = children[0]
+        assert key_node.GetClass() == 'StringType', 'Key in record<K,V> node must be a string type, got %s.' % key_node.GetClass()
+        key_type = IdlDefinitionBuilder.create_string(key_node, False, key_node.GetProperty('ExtAttributes'))
+
+        value_node = children[1]
+        assert value_node.GetClass() == 'Type', 'Unrecognized node class for record<K,V> value: %s' % value_node.GetClass()
+        value_type = IdlDefinitionBuilder.create_type(value_node)
+
+        return RecordType(key_type=key_type, value_type=value_type, is_nullable=is_nullable)
+
+    @staticmethod
+    def create_sequence(node, is_nullable=False):
+        assert node.GetClass() == 'Sequence', 'Unknown node class: %s' % node.GetClass()
+
+        children = node.GetChildren()
+        assert len(children) == 1, 'sequence<T> node expects exactly 1 child, got %d' % len(children)
+
+        element_type = IdlDefinitionBuilder.create_type(children[0])
+        return SequenceType(element_type=element_type, is_nullable=is_nullable)
+
+    @staticmethod
+    def create_frozen_array(node, is_nullable=False):
+        assert node.GetClass() == 'FrozenArray', 'Unknown node class: %s' % node.GetClass()
+
+        children = node.GetChildren()
+        assert len(children) == 1, 'FrozenArray<T> node expects exactly 1 child, got %d' % len(children)
+
+        element_type = IdlDefinitionBuilder.create_type(children[0])
+        return FrozenArrayType(element_type=element_type, is_nullable=is_nullable)
+
+    @staticmethod
+    def create_argument(node):
+        assert node.GetClass() == 'Argument', 'Unknown node class: %s' % node.GetClass()
+        identifier = node.GetName()
+        is_optional = node.GetProperty('OPTIONAL')
+        idl_type = None
+        is_variadic = False
+        default_value = None
+        extended_attribute_list = None
+
+        for child in node.GetChildren():
+            child_class = child.GetClass()
+            if child_class == 'Type':
+                idl_type = IdlDefinitionBuilder.create_type(child)
+            elif child_class == 'ExtAttributes':
+                extended_attribute_list = IdlDefinitionBuilder.create_extended_attribute_list(child)
+            elif child_class == 'Argument':
+                child_name = child.GetName()
+                assert child_name == '...', 'Unrecognized Argument node; expected "...", got "%s"' % child_name
+                is_variadic = bool(child.GetProperty('ELLIPSIS'))
+            elif child_class == 'Default':
+                default_value = IdlDefinitionBuilder.create_literal_token(child)
+            else:
+                assert False, 'Unrecognized node class: %s' % child_class
+        return Argument(identifier=identifier, type=idl_type, is_optional=is_optional, is_variadic=is_variadic,
+                        default_value=default_value, extended_attribute_list=extended_attribute_list)
+
+    @staticmethod
+    def create_arguments(node):
+        assert node.GetClass() == 'Arguments', 'Unknown node class: %s' % node.GetClass()
+        return [IdlDefinitionBuilder.create_argument(child) for child in node.GetChildren()]
+
+    @staticmethod
+    def create_extended_attribute_list(node, existing_list=None):
+        """
+        Returns a dict for extended attributes. For most cases, keys and values are strings, but we have following exceptions:
+        'Constructors': value is a list of Constructor's.
+        'Exposures': value is a list of Exposed's.
+        """
+        assert node.GetClass() == 'ExtAttributes', 'Unknown node class: %s' % node.GetClass()
+
+        extended_attributes = {}
+        constructors = []
+        exposures = []
+        for child in node.GetChildren():
+            name = child.GetName()
+            if name in ('Constructor', 'CustomConstructor', 'NamedConstructor'):
+                constructors.append(IdlDefinitionBuilder.create_constructor(child))
+            elif name == 'Exposed':
+                exposures.extend(IdlDefinitionBuilder.create_exposures(child))
+            else:
+                value = child.GetProperty('VALUE')
+                extended_attributes[name] = value
+
+        if existing_list:
+            constructors = constructors + list(existing_list.constructors)
+            exposures = exposures + list(existing_list.exposures)
+            extended_attributes = extended_attributes.update(existing_list.extended_attributes)
+
+        return ExtendedAttributeList(extended_attributes=extended_attributes, constructors=constructors, exposures=exposures)
+
+    @staticmethod
+    def create_constructor(node):
+        assert node.GetClass() == 'ExtAttribute' and node.GetName() in ('Constructor', 'CustomConstructor', 'NamedConstructor')
+
+        identifier = node.GetProperty('VALUE', None)
+        arguments = []
+
+        children = node.GetChildren()
+        constructor_type = node.GetName()
+        if len(children) > 0:
+            child = children[0]
+            if child.GetClass() == 'Arguments':
+                arguments = IdlDefinitionBuilder.create_arguments(child)
+            elif child.GetClass() == 'Call':
+                arguments = IdlDefinitionBuilder.create_arguments(child.GetChildren()[0])
+                identifier = child.GetName()
+            else:
+                assert False, 'Unexpected class: %s' % child.GetClass()
+
+        assert constructor_type in ('Constructor', 'CustomConstructor', 'NamedConstructor'), \
+            'Unknown constructor type: %s' % constructor_type
+        if constructor_type == 'NamedConstructor':
+            return NamedConstructor(identifier=identifier, arguments=arguments)
+
+        is_custom = (constructor_type == 'CustomConstructor')
+        return Constructor(arguments=arguments, is_custom=is_custom)
+
+    @staticmethod
+    def create_exposures(node):
+        assert node.GetClass() == 'ExtAttribute' and node.GetName() == 'Exposed'
+
+        value = node.GetProperty('VALUE')
+        if value:
+            # No runtime enabled feature flags
+            if isinstance(value, list):
+                return [Exposure(global_interface=v) for v in value]
+            else:
+                return [Exposure(global_interface=value)]
+        arguments = IdlDefinitionBuilder.create_arguments(node.GetChildren()[0])
+        exposures = []
+        for arg in arguments:
+            idl_type = arg.type
+            assert type(idl_type) == TypePlaceHolder, 'Invalid arguments in Exposed'
+            exposures.append(Exposure(global_interface=idl_type.type_name, runtime_enabled_feature=arg.identifier))
+        return exposures
+
+    @staticmethod
+    def create_literal_token(node):
+        assert node.GetClass() in ('Literal', 'Default')
+
+        type_name = node.GetProperty('TYPE')
+        value = node.GetProperty('VALUE')
+        if type_name == 'integer':
+            value = int(value, base=0)
+        elif type_name == 'float':
+            value = float(value)
+        elif type_name == 'NULL':
+            return literal_token.NULL_TOKEN
+        else:
+            assert type_name in ['DOMString', 'boolean', 'sequence'], 'Unrecognized type: %s' % type_name
+
+        return LiteralToken(type_name=type_name, value=value)
diff --git a/third_party/WebKit/Source/bindings/scripts/web_idl/idl_types.py b/third_party/WebKit/Source/bindings/scripts/web_idl/idl_types.py
new file mode 100644
index 0000000..d1884ec79
--- /dev/null
+++ b/third_party/WebKit/Source/bindings/scripts/web_idl/idl_types.py
@@ -0,0 +1,341 @@
+# 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.
+
+from .utilities import assert_no_extra_args
+
+
+# Details of each type is described in
+# https://heycam.github.io/webidl/#idl-types
+
+class TypeBase(object):
+    """
+    TypeBase is a base class for all classes for IDL types.
+    """
+
+    @property
+    def type_name(self):
+        assert False, 'type_name() is not implemented'
+
+
+class AnyType(TypeBase):
+
+    @property
+    def type_name(self):
+        return 'Any'
+
+
+class PrimitiveType(TypeBase):
+    """
+    PrimitiveType represents either of integer types, float types, or 'boolean'.
+    * integer types: byte, octet, (unsigned) short, (unsigned) long, (unsigned) long long
+    * float types: (unrestricted) float, (unrestricted) double
+    @param string name             : the name of a primitive type
+    @param bool   is_nullable      : True if the type is nullable (optional)
+    @param bool   is_clamp         : True if the type has [Clamp] annotation (optional)
+    @param bool   is_enforce_range : True if the type has [EnforceRange] annotation (optional)
+    """
+
+    _INTEGER_TYPES = frozenset([
+        'byte', 'octet', 'short', 'unsigned short', 'long', 'unsigned long', 'long long', 'unsigned long long'
+    ])
+    _FLOAT_TYPES = frozenset([
+        'float', 'unrestricted float', 'double', 'unrestricted double'
+    ])
+    _PRIMITIVE_TYPES = _INTEGER_TYPES | _FLOAT_TYPES | frozenset(['boolean'])
+
+    def __init__(self, **kwargs):
+        self._name = kwargs.pop('name')
+        self._is_nullable = kwargs.pop('is_nullable', False)
+        self._is_clamp = kwargs.pop('is_clamp', False)
+        self._is_enforce_range = kwargs.pop('is_enforce_range', False)
+        assert_no_extra_args(kwargs)
+
+        if self._name not in PrimitiveType._PRIMITIVE_TYPES:
+            raise ValueError('Unknown type name: %s' % self._name)
+        if self.is_clamp and self.is_enforce_range:
+            raise ValueError('[Clamp] and [EnforceRange] cannot be associated together')
+        if (self.is_clamp or self.is_enforce_range) and not self.is_integer_type:
+            raise ValueError('[Clamp] or [EnforceRange] cannot be associated with %s' % self._name)
+
+    @property
+    def type_name(self):
+        return ''.join([word.capitalize() for word in self._name.split(' ')])
+
+    @property
+    def is_nullable(self):
+        return self._is_nullable
+
+    @property
+    def is_clamp(self):
+        return self._is_clamp
+
+    @property
+    def is_enforce_range(self):
+        return self._is_enforce_range
+
+    @property
+    def is_integer_type(self):
+        return self._name in PrimitiveType._INTEGER_TYPES
+
+    @property
+    def is_float_type(self):
+        return self._name in PrimitiveType._FLOAT_TYPES
+
+    @property
+    def is_numeric_type(self):
+        return self.is_integer_type or self.is_float_type
+
+
+class StringType(TypeBase):
+    """
+    StringType represents a string type.
+    @param StringType.Type        string_type   : a type of string
+    @param bool                   is_nullable   : True if the string is nullable (optional)
+    @param StringType.TreatNullAs treat_null_as : argument of an extended attribute [TreatNullAs] (optional)
+    """
+    STRING_TYPES = ('DOMString', 'ByteString', 'USVString')
+    TREAT_NULL_AS = ('EmptyString', 'NullString')
+
+    def __init__(self, **kwargs):
+        self._string_type = kwargs.pop('string_type')
+        self._is_nullable = kwargs.pop('is_nullable', False)
+        self._treat_null_as = kwargs.pop('treat_null_as', None)
+        assert_no_extra_args(kwargs)
+
+        if self._string_type not in StringType.STRING_TYPES:
+            raise ValueError('Unknown string type: %s' % self._string_type)
+        if self.treat_null_as and self.treat_null_as not in StringType.TREAT_NULL_AS:
+            raise ValueError('Unknown TreatAsNull parameter: %s' % self.treat_null_as)
+
+    @property
+    def type_name(self):
+        if self._string_type == 'DOMString':
+            return 'String'
+        return self._string_type
+
+    @property
+    def is_nullable(self):
+        return self._is_nullable
+
+    @property
+    def treat_null_as(self):
+        return self._treat_null_as
+
+
+class ObjectType(TypeBase):
+    """
+    ObjectType represents 'object' type in Web IDL spec.
+    @param bool is_nullable : True if the type is nullable (optional)
+    """
+
+    def __init__(self, **kwargs):
+        self._is_nullable = kwargs.pop('is_nullable', False)
+        assert_no_extra_args(kwargs)
+
+    @property
+    def type_name(self):
+        return 'Object'
+
+    @property
+    def is_nullable(self):
+        return self._is_nullable
+
+
+class SequenceType(TypeBase):
+    """
+    SequenceType represents a sequence type 'sequence<T>' in Web IDL spec.
+    @param TypeBase element_type : Type of element T
+    @param bool     is_nullable  : True if the type is nullable (optional)
+    """
+
+    def __init__(self, **kwargs):
+        self._element_type = kwargs.pop('element_type')
+        self._is_nullable = kwargs.pop('is_nullable', False)
+        assert_no_extra_args(kwargs)
+
+        if not isinstance(self.element_type, TypeBase):
+            raise ValueError('element_type must be an instance of TypeBase inheritances')
+
+    @property
+    def type_name(self):
+        return self.element_type.type_name + 'Sequence'
+
+    @property
+    def is_nullable(self):
+        return self._is_nullable
+
+    @property
+    def element_type(self):
+        return self._element_type
+
+
+class RecordType(TypeBase):
+    """
+    RecordType represents a record type 'record<K, V>' in Web IDL spec.
+    @param StringType key_type    : Type of key K
+    @param TypeBase   value_type  : Type of value V
+    @param bool       is_nullable : True if the record type is nullable (optional)
+    """
+
+    def __init__(self, **kwargs):
+        self._key_type = kwargs.pop('key_type')
+        self._value_type = kwargs.pop('value_type')
+        self._is_nullable = kwargs.pop('is_nullable', False)
+        assert_no_extra_args(kwargs)
+
+        if type(self.key_type) != StringType:
+            raise ValueError('key_type parameter must be an instance of StringType.')
+        if not isinstance(self.value_type, TypeBase):
+            raise ValueError('value_type parameter must be an instance of TypeBase inheritances.')
+
+    @property
+    def type_name(self):
+        return self.key_type.type_name + self.value_type.type_name + 'Record'
+
+    @property
+    def key_type(self):
+        return self._key_type
+
+    @property
+    def value_type(self):
+        return self._value_type
+
+    @property
+    def is_nullable(self):
+        return self._is_nullable
+
+
+class PromiseType(TypeBase):
+    """
+    PromiseType represents a promise type 'promise<T>' in Web IDL spec.
+    @param TypeBase result_type : Type of the promise's result V
+    """
+
+    def __init__(self, **kwargs):
+        self._result_type = kwargs.pop('result_type')
+        assert_no_extra_args(kwargs)
+
+    @property
+    def type_name(self):
+        return self.result_type.type_name + 'Promise'
+
+    @property
+    def result_type(self):
+        return self._result_type
+
+
+class UnionType(TypeBase):
+    """
+    UnionType represents a union type in Web IDL spec.
+    @param [TypeBase] member_types : List of member types
+    @param bool       is_nullable  : True if the type is nullable (optional)
+    """
+
+    def __init__(self, **kwargs):
+        def count_nullable_member_types():
+            number = 0
+            for member in self.member_types:
+                if type(member) == UnionType:
+                    number = number + member.number_of_nullable_member_types
+                elif type(member) not in (AnyType, PromiseType) and member.is_nullable:
+                    number = number + 1
+            return number
+
+        self._member_types = tuple(kwargs.pop('member_types'))
+        self._is_nullable = kwargs.pop('is_nullable', False)
+        self._number_of_nullable_member_types = count_nullable_member_types()  # pylint: disable=invalid-name
+        assert_no_extra_args(kwargs)
+
+        if len(self.member_types) < 2:
+            raise ValueError('Union type must have 2 or more member types, but got %d.' % len(self.member_types))
+        if any(type(member) == AnyType for member in self.member_types):
+            raise ValueError('any type must not be used as a union member type.')
+        if self.number_of_nullable_member_types > 1:
+            raise ValueError('The number of nullable member types of a union type must be 0 or 1, but %d' %
+                             self.number_of_nullable_member_types)
+
+    @property
+    def type_name(self):
+        return 'Or'.join(member.type_name for member in self.member_types)
+
+    @property
+    def member_types(self):
+        return self._member_types
+
+    @property
+    def is_nullable(self):
+        return self._is_nullable
+
+    @property
+    def number_of_nullable_member_types(self):
+        return self._number_of_nullable_member_types
+
+    @property
+    def flattened_member_types(self):
+        flattened = set()
+        # TODO(peria): In spec, we have to remove type annotations and nullable flags.
+        for member in self.member_types:
+            if type(member) != UnionType:
+                flattened.add(member)
+            else:
+                flattened.update(member.flattened_member_types)
+        return flattened
+
+
+class FrozenArrayType(TypeBase):
+    """
+    FrozenArrayType represents a frozen array type 'FrozenArray<T>' in Web IDL.
+    @param TypeBase element_type : Type of element T
+    @param bool     is_nullable  : True if the type is nullable (optional)
+    """
+
+    def __init__(self, **kwargs):
+        self._element_type = kwargs.pop('element_type')
+        self._is_nullable = kwargs.pop('is_nullable', False)
+        assert_no_extra_args(kwargs)
+
+    @property
+    def type_name(self):
+        return self.element_type.type_name + 'Array'
+
+    @property
+    def element_type(self):
+        return self._element_type
+
+    @property
+    def is_nullable(self):
+        return self._is_nullable
+
+
+class VoidType(TypeBase):
+
+    @property
+    def type_name(self):
+        return 'Void'
+
+
+class TypePlaceHolder(TypeBase):
+    """
+    TypePlaceHolder is a pseudo type as a place holder of types which use identifers;
+    interface types, dictionary types, enumeration types, and callback function types.
+    Because it is not guaranteed that we have a definition of target defintions when
+    we meet the type used, we use this class as a place holder.
+    All place holders will be replaced with references after all the defintions in
+    all components are collected.
+    @param string identifier  : the identifier of a named definition to refer
+    @param bool   is_nullable : True if the type is nullable (optional)
+    """
+
+    def __init__(self, **kwargs):
+        self._identifier = kwargs.pop('identifier')
+        self._is_nullable = kwargs.pop('is_nullable', False)
+        assert_no_extra_args(kwargs)
+
+    @property
+    def type_name(self):
+        return self._identifier
+
+    @property
+    def is_nullable(self):
+        return self._is_nullable
diff --git a/third_party/WebKit/Source/bindings/scripts/web_idl/implements.py b/third_party/WebKit/Source/bindings/scripts/web_idl/implements.py
new file mode 100644
index 0000000..4ac6b31
--- /dev/null
+++ b/third_party/WebKit/Source/bindings/scripts/web_idl/implements.py
@@ -0,0 +1,26 @@
+# 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.
+
+from .utilities import assert_no_extra_args
+
+
+# https://heycam.github.io/webidl/#idl-implements-statements
+class Implements(object):
+    """Implement class represents Implements statement in Web IDL spec."""
+
+    def __init__(self, **kwargs):
+        self._implementer_name = kwargs.pop('implementer_name')
+        self._implementee_name = kwargs.pop('implementee_name')
+        assert_no_extra_args(kwargs)
+
+        if self.implementer_name == self.implementee_name:
+            raise ValueError('Implements cannot refer same identifiers: %s' % self.implementer_name)
+
+    @property
+    def implementer_name(self):
+        return self._implementer_name
+
+    @property
+    def implementee_name(self):
+        return self._implementee_name
diff --git a/third_party/WebKit/Source/bindings/scripts/web_idl/interface.py b/third_party/WebKit/Source/bindings/scripts/web_idl/interface.py
new file mode 100644
index 0000000..573c2d87
--- /dev/null
+++ b/third_party/WebKit/Source/bindings/scripts/web_idl/interface.py
@@ -0,0 +1,176 @@
+# 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.
+
+from .extended_attribute import ExtendedAttributeList
+from .utilities import assert_no_extra_args
+
+
+# https://heycam.github.io/webidl/#idl-interfaces
+class Interface(object):
+
+    def __init__(self, **kwargs):
+        self._identifier = kwargs.pop('identifier')
+        self._attributes = tuple(kwargs.pop('attributes', []))
+        self._operations = tuple(kwargs.pop('operations', []))
+        self._constants = tuple(kwargs.pop('constants', []))
+        self._iterable = kwargs.pop('iterable', None)
+        self._maplike = kwargs.pop('maplike', None)
+        self._setlike = kwargs.pop('setlike', None)
+        # BUG(736332): Remove support of legacy serializer members.
+        self._serializer = kwargs.pop('serializer', None)
+        self._inherited_interface_name = kwargs.pop('inherited_interface_name', None)
+        self._is_partial = kwargs.pop('is_partial', False)
+        self._extended_attribute_list = kwargs.pop('extended_attribute_list', ExtendedAttributeList())
+        assert_no_extra_args(kwargs)
+
+        num_declaration = (1 if self.iterable else 0) + (1 if self.maplike else 0) + (1 if self.setlike else 0)
+        if num_declaration > 1:
+            raise ValueError('At most one of iterable<>, maplike<>, or setlike<> must be applied.')
+
+    @property
+    def identifier(self):
+        return self._identifier
+
+    @property
+    def attributes(self):
+        return self._attributes
+
+    @property
+    def operations(self):
+        return self._operations
+
+    @property
+    def constants(self):
+        return self._constants
+
+    @property
+    def iterable(self):
+        return self._iterable
+
+    @property
+    def maplike(self):
+        return self._maplike
+
+    @property
+    def setlike(self):
+        return self._setlike
+
+    @property
+    def serializer(self):
+        return self._serializer
+
+    @property
+    def inherited_interface_name(self):
+        return self._inherited_interface_name
+
+    @property
+    def is_partial(self):
+        return self._is_partial
+
+    @property
+    def constructors(self):
+        return self.extended_attribute_list.constructors
+
+    @property
+    def named_constructors(self):
+        return self.extended_attribute_list.named_constructors
+
+    @property
+    def exposures(self):
+        return self.extended_attribute_list.exposures
+
+    @property
+    def extended_attribute_list(self):
+        return self._extended_attribute_list
+
+
+# https://heycam.github.io/webidl/#idl-iterable
+class Iterable(object):
+
+    def __init__(self, **kwargs):
+        self._key_type = kwargs.pop('key_type', None)
+        self._value_type = kwargs.pop('value_type')
+        self._extended_attribute_list = kwargs.pop('extended_attribute_list', ExtendedAttributeList())
+        assert_no_extra_args(kwargs)
+
+    @property
+    def key_type(self):
+        return self._key_type
+
+    @property
+    def value_type(self):
+        return self._value_type
+
+    @property
+    def extended_attribute_list(self):
+        return self._extended_attribute_list
+
+
+# https://heycam.github.io/webidl/#idl-maplike
+class Maplike(object):
+
+    def __init__(self, **kwargs):
+        self._key_type = kwargs.pop('key_type')
+        self._value_type = kwargs.pop('value_type')
+        self._is_readonly = kwargs.pop('is_readonly', False)
+        assert_no_extra_args(kwargs)
+
+    @property
+    def key_type(self):
+        return self._key_type
+
+    @property
+    def value_type(self):
+        return self._value_type
+
+    @property
+    def is_readonly(self):
+        return self._is_readonly
+
+
+# https://heycam.github.io/webidl/#idl-setlike
+class Setlike(object):
+
+    def __init__(self, **kwargs):
+        self._value_type = kwargs.pop('value_type')
+        self._is_readonly = kwargs.pop('is_readonly', False)
+        assert_no_extra_args(kwargs)
+
+    @property
+    def value_type(self):
+        return self._value_type
+
+    @property
+    def is_readonly(self):
+        return self._is_readonly
+
+
+# https://www.w3.org/TR/WebIDL-1/#idl-serializers
+# BUG(736332): Remove support of legacy serializer.
+# We support styles only used in production code. i.e.
+# - serializer;
+# - serializer = { attribute };
+# - serializer = { inherit, attribute };
+class Serializer(object):
+
+    def __init__(self, **kwargs):
+        self._is_map = kwargs.pop('is_map', False)
+        self._has_attribute = kwargs.pop('has_attribute', False)
+        self._has_inherit = kwargs.pop('has_inherit', False)
+        assert_no_extra_args(kwargs)
+
+        if (self.has_attribute or self.has_inherit) and not self._is_map:
+            raise ValueError('has_attribute and has_inherit must be set with is_map')
+
+    @property
+    def is_map(self):
+        return self._is_map
+
+    @property
+    def has_attribute(self):
+        return self._has_attribute
+
+    @property
+    def has_inherit(self):
+        return self._has_inherit
diff --git a/third_party/WebKit/Source/bindings/scripts/web_idl/literal_token.py b/third_party/WebKit/Source/bindings/scripts/web_idl/literal_token.py
new file mode 100644
index 0000000..f395022
--- /dev/null
+++ b/third_party/WebKit/Source/bindings/scripts/web_idl/literal_token.py
@@ -0,0 +1,29 @@
+# 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.
+
+from .utilities import assert_no_extra_args
+
+
+class LiteralToken(object):
+    """Literal class represents literal tokens in Web IDL. It appears
+    - default values of dictionary members
+    - default values of arguments in operations
+    - constant values in interfaces (string and [] are not allowed)
+    - arguments of some extended attributes
+    """
+
+    def __init__(self, **kwargs):
+        self._type_name = kwargs.pop('type_name')
+        self._value = kwargs.pop('value')
+        assert_no_extra_args(kwargs)
+
+    @property
+    def type_name(self):
+        return self._type_name
+
+    @property
+    def value(self):
+        return self._value
+
+NULL_TOKEN = LiteralToken(type_name='NULL', value='null')
diff --git a/third_party/WebKit/Source/bindings/scripts/web_idl/namespace.py b/third_party/WebKit/Source/bindings/scripts/web_idl/namespace.py
new file mode 100644
index 0000000..ebafdc7
--- /dev/null
+++ b/third_party/WebKit/Source/bindings/scripts/web_idl/namespace.py
@@ -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.
+
+from .extended_attribute import ExtendedAttributeList
+from .utilities import assert_no_extra_args
+
+
+# https://heycam.github.io/webidl/#idl-namespaces
+class Namespace(object):
+
+    def __init__(self, **kwargs):
+        self._identifier = kwargs.pop('identifier')
+        self._attributes = tuple(kwargs.pop('attributes', []))
+        self._operations = tuple(kwargs.pop('operations', []))
+        self._is_partial = kwargs.pop('is_partial', False)
+        self._extended_attribute_list = kwargs.pop('extended_attribute_list', ExtendedAttributeList())
+        assert_no_extra_args(kwargs)
+
+    @property
+    def identifier(self):
+        return self._identifier
+
+    @property
+    def attributes(self):
+        return self._attributes
+
+    @property
+    def operations(self):
+        return self._operations
+
+    @property
+    def exposures(self):
+        return self.extended_attribute_list.exposures
+
+    @property
+    def is_partial(self):
+        return self._is_partial
+
+    @property
+    def extended_attribute_list(self):
+        return self._extended_attribute_list
diff --git a/third_party/WebKit/Source/bindings/scripts/web_idl/operation.py b/third_party/WebKit/Source/bindings/scripts/web_idl/operation.py
new file mode 100644
index 0000000..ab56382
--- /dev/null
+++ b/third_party/WebKit/Source/bindings/scripts/web_idl/operation.py
@@ -0,0 +1,56 @@
+# 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.
+
+from .extended_attribute import ExtendedAttributeList
+from .utilities import assert_no_extra_args
+
+
+# https://heycam.github.io/webidl/#idl-operations
+class Operation(object):
+    # https://www.w3.org/TR/WebIDL-1/#idl-special-operations
+    _SPECIAL_KEYWORDS = frozenset(['deleter', 'getter', 'legacycaller', 'setter', 'stringifier', 'serializer'])
+
+    def __init__(self, **kwargs):
+        self._identifier = kwargs.pop('identifier')
+        self._return_type = kwargs.pop('return_type')
+        self._arguments = tuple(kwargs.pop('arguments', []))
+        self._special_keywords = frozenset(kwargs.pop('special_keywords', []))
+        self._is_static = kwargs.pop('is_static', False)
+        self._extended_attribute_list = kwargs.pop('extended_attribute_list', ExtendedAttributeList())
+        assert_no_extra_args(kwargs)
+
+        if any(keyword not in Operation._SPECIAL_KEYWORDS for keyword in self._special_keywords):
+            raise ValueError('Unknown keyword is specified in special keywords')
+
+    @property
+    def identifier(self):
+        return self._identifier
+
+    @property
+    def return_type(self):
+        return self._return_type
+
+    @property
+    def arguments(self):
+        return self._arguments
+
+    @property
+    def special_keywords(self):
+        return self._special_keywords
+
+    @property
+    def is_static(self):
+        return self._is_static
+
+    @property
+    def extended_attribute_list(self):
+        return self._extended_attribute_list
+
+    @property
+    def is_regular(self):
+        return self.identifier and not self.is_static
+
+    @property
+    def is_special(self):
+        return bool(self.special_keywords)
diff --git a/third_party/WebKit/Source/bindings/scripts/web_idl/typedef.py b/third_party/WebKit/Source/bindings/scripts/web_idl/typedef.py
new file mode 100644
index 0000000..fd38ca99
--- /dev/null
+++ b/third_party/WebKit/Source/bindings/scripts/web_idl/typedef.py
@@ -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.
+
+from .utilities import assert_no_extra_args
+
+
+# https://heycam.github.io/webidl/#idl-typedefs
+class Typedef(object):
+
+    def __init__(self, **kwargs):
+        self._identifier = kwargs.pop('identifier')
+        self._type = kwargs.pop('type')
+        assert_no_extra_args(kwargs)
+
+    @property
+    def identifier(self):
+        return self._identifier
+
+    @property
+    def type(self):
+        return self._type
diff --git a/third_party/WebKit/Source/bindings/scripts/web_idl/utilities.py b/third_party/WebKit/Source/bindings/scripts/web_idl/utilities.py
new file mode 100644
index 0000000..5484a6d
--- /dev/null
+++ b/third_party/WebKit/Source/bindings/scripts/web_idl/utilities.py
@@ -0,0 +1,8 @@
+# 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.
+
+
+def assert_no_extra_args(kwargs):
+    if kwargs:
+        raise ValueError('Unknown parameters are passed: %s' % kwargs.keys())
diff --git a/third_party/WebKit/Source/core/animation/Animation.cpp b/third_party/WebKit/Source/core/animation/Animation.cpp
index eb141c9..7efc4d41 100644
--- a/third_party/WebKit/Source/core/animation/Animation.cpp
+++ b/third_party/WebKit/Source/core/animation/Animation.cpp
@@ -339,12 +339,12 @@
         // to that function for more details.
         //
         // In the CompositingRequirementsUpdater::UpdateRecursive, the
-        // (direct_reasons & kCompositingReasonActiveAnimation) can be non-zero
-        // which indicates that there is a compositor animation. However, the
-        // PaintLayerCompositor::CanBeComposited could still return false
-        // because the LocalFrameView is not visible. And in that case, the code
-        // path will get here because there is a compositor animation but it
-        // won't be composited. We have to account for this case.
+        // (direct_reasons & CompositingReason::kActiveAnimation) can be
+        // non-zero which indicates that there is a compositor animation.
+        // However, the PaintLayerCompositor::CanBeComposited could still return
+        // false because the LocalFrameView is not visible. And in that case,
+        // the code path will get here because there is a compositor animation
+        // but it won't be composited. We have to account for this case.
         if (failure_code.can_composite &&
             TimelineInternal()->GetDocument()->View()->IsVisible()) {
           is_non_composited_compositable_ = true;
diff --git a/third_party/WebKit/Source/core/animation/CompositorAnimationsTest.cpp b/third_party/WebKit/Source/core/animation/CompositorAnimationsTest.cpp
index 695c681..61b90fe 100644
--- a/third_party/WebKit/Source/core/animation/CompositorAnimationsTest.cpp
+++ b/third_party/WebKit/Source/core/animation/CompositorAnimationsTest.cpp
@@ -1291,12 +1291,12 @@
 
   // Add a transform with a compositing reason, which should allow starting
   // animation.
-  UpdateDummyTransformNode(properties, kCompositingReasonActiveAnimation);
+  UpdateDummyTransformNode(properties, CompositingReason::kActiveAnimation);
   EXPECT_TRUE(
       CompositorAnimations::CheckCanStartElementOnCompositor(*element).Ok());
 
   // Setting to CompositingReasonNone should produce false.
-  UpdateDummyTransformNode(properties, kCompositingReasonNone);
+  UpdateDummyTransformNode(properties, CompositingReason::kNone);
   EXPECT_FALSE(
       CompositorAnimations::CheckCanStartElementOnCompositor(*element).Ok());
 
@@ -1323,12 +1323,12 @@
 
   // Add an effect with a compositing reason, which should allow starting
   // animation.
-  UpdateDummyEffectNode(properties, kCompositingReasonActiveAnimation);
+  UpdateDummyEffectNode(properties, CompositingReason::kActiveAnimation);
   EXPECT_TRUE(
       CompositorAnimations::CheckCanStartElementOnCompositor(*element).Ok());
 
   // Setting to CompositingReasonNone should produce false.
-  UpdateDummyEffectNode(properties, kCompositingReasonNone);
+  UpdateDummyEffectNode(properties, CompositingReason::kNone);
   EXPECT_FALSE(
       CompositorAnimations::CheckCanStartElementOnCompositor(*element).Ok());
 
diff --git a/third_party/WebKit/Source/core/clipboard/DataTransferItem.h b/third_party/WebKit/Source/core/clipboard/DataTransferItem.h
index 22afb4ab..c45673d8 100644
--- a/third_party/WebKit/Source/core/clipboard/DataTransferItem.h
+++ b/third_party/WebKit/Source/core/clipboard/DataTransferItem.h
@@ -31,6 +31,7 @@
 #ifndef DataTransferItem_h
 #define DataTransferItem_h
 
+#include "base/macros.h"
 #include "core/CoreExport.h"
 #include "platform/bindings/ScriptWrappable.h"
 #include "platform/bindings/TraceWrapperMember.h"
@@ -48,7 +49,6 @@
 
 class CORE_EXPORT DataTransferItem final : public ScriptWrappable {
   DEFINE_WRAPPERTYPEINFO();
-  WTF_MAKE_NONCOPYABLE(DataTransferItem);
 
  public:
   static DataTransferItem* Create(DataTransfer*, DataObjectItem*);
@@ -75,6 +75,7 @@
   Member<DataTransfer> data_transfer_;
   Member<DataObjectItem> item_;
   HeapVector<TraceWrapperMember<V8FunctionStringCallback>> callbacks_;
+  DISALLOW_COPY_AND_ASSIGN(DataTransferItem);
 };
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/clipboard/Pasteboard.h b/third_party/WebKit/Source/core/clipboard/Pasteboard.h
index b606f432..336d7d9 100644
--- a/third_party/WebKit/Source/core/clipboard/Pasteboard.h
+++ b/third_party/WebKit/Source/core/clipboard/Pasteboard.h
@@ -26,10 +26,10 @@
 #ifndef Pasteboard_h
 #define Pasteboard_h
 
+#include "base/macros.h"
 #include "core/CoreExport.h"
 #include "platform/heap/Handle.h"
 #include "platform/wtf/Forward.h"
-#include "platform/wtf/Noncopyable.h"
 #include "platform/wtf/text/WTFString.h"
 #include "public/platform/WebClipboard.h"
 
@@ -40,7 +40,6 @@
 class KURL;
 
 class CORE_EXPORT Pasteboard {
-  WTF_MAKE_NONCOPYABLE(Pasteboard);
   USING_FAST_MALLOC(Pasteboard);
 
  public:
@@ -76,6 +75,7 @@
   Pasteboard();
 
   mojom::ClipboardBuffer buffer_;
+  DISALLOW_COPY_AND_ASSIGN(Pasteboard);
 };
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/css/CSSFontFaceSrcValue.cpp b/third_party/WebKit/Source/core/css/CSSFontFaceSrcValue.cpp
index 85a225a..1086d47 100644
--- a/third_party/WebKit/Source/core/css/CSSFontFaceSrcValue.cpp
+++ b/third_party/WebKit/Source/core/css/CSSFontFaceSrcValue.cpp
@@ -107,7 +107,7 @@
     // is processed by StyleResolver / StyleEngine.
     RestoreCachedResourceIfNeeded(context);
   }
-  return fetched_->GetResource();
+  return ToFontResource(fetched_->GetResource());
 }
 
 void CSSFontFaceSrcValue::RestoreCachedResourceIfNeeded(
diff --git a/third_party/WebKit/Source/core/css/CSSFontFaceSrcValue.h b/third_party/WebKit/Source/core/css/CSSFontFaceSrcValue.h
index 593d350e..b35ec07 100644
--- a/third_party/WebKit/Source/core/css/CSSFontFaceSrcValue.h
+++ b/third_party/WebKit/Source/core/css/CSSFontFaceSrcValue.h
@@ -29,7 +29,6 @@
 #include "base/memory/scoped_refptr.h"
 #include "core/css/CSSValue.h"
 #include "core/loader/resource/FontResource.h"
-#include "platform/loader/fetch/ResourceOwner.h"
 #include "platform/weborigin/Referrer.h"
 #include "platform/wtf/text/WTFString.h"
 
@@ -103,7 +102,7 @@
 
   class FontResourceHelper
       : public GarbageCollectedFinalized<FontResourceHelper>,
-        public ResourceOwner<FontResource> {
+        public FontResourceClient {
     USING_GARBAGE_COLLECTED_MIXIN(FontResourceHelper);
 
    public:
@@ -112,7 +111,7 @@
     }
 
     virtual void Trace(blink::Visitor* visitor) {
-      ResourceOwner<FontResource>::Trace(visitor);
+      FontResourceClient::Trace(visitor);
     }
 
    private:
diff --git a/third_party/WebKit/Source/core/css/RemoteFontFaceSource.cpp b/third_party/WebKit/Source/core/css/RemoteFontFaceSource.cpp
index 72bbce05..0814409 100644
--- a/third_party/WebKit/Source/core/css/RemoteFontFaceSource.cpp
+++ b/third_party/WebKit/Source/core/css/RemoteFontFaceSource.cpp
@@ -30,7 +30,6 @@
                                            FontSelector* font_selector,
                                            FontDisplay display)
     : face_(css_font_face),
-      font_(font),
       font_selector_(font_selector),
       display_(display),
       period_(display == kFontDisplaySwap ? kSwapPeriod : kBlockPeriod),
@@ -44,59 +43,54 @@
     is_intervention_triggered_ = true;
     period_ = kSwapPeriod;
   }
-
-  // Note: this may call notifyFinished() and clear font_.
-  font_->AddClient(this);
+  // Note: this may call NotifyFinished() and ClearResource().
+  SetResource(font);
 }
 
 RemoteFontFaceSource::~RemoteFontFaceSource() = default;
 
 void RemoteFontFaceSource::Dispose() {
-  if (font_) {
-    font_->RemoveClient(this);
-    font_ = nullptr;
-  }
+  ClearResource();
   PruneTable();
 }
 
 bool RemoteFontFaceSource::IsLoading() const {
-  return font_ && font_->IsLoading();
+  return GetResource() && GetResource()->IsLoading();
 }
 
 bool RemoteFontFaceSource::IsLoaded() const {
-  return !font_;
+  return !GetResource();
 }
 
 bool RemoteFontFaceSource::IsValid() const {
-  return font_ || custom_font_data_;
+  return GetResource() || custom_font_data_;
 }
 
-void RemoteFontFaceSource::NotifyFinished(Resource* unused_resource) {
-  DCHECK_EQ(unused_resource, font_);
-  histograms_.MaySetDataSource(font_->GetResponse().WasCached()
+void RemoteFontFaceSource::NotifyFinished(Resource* resource) {
+  FontResource* font = ToFontResource(resource);
+  histograms_.MaySetDataSource(font->GetResponse().WasCached()
                                    ? FontLoadHistograms::kFromDiskCache
                                    : FontLoadHistograms::kFromNetwork);
-  histograms_.RecordRemoteFont(font_.Get());
+  histograms_.RecordRemoteFont(font);
 
-  custom_font_data_ = font_->GetCustomFontData();
+  custom_font_data_ = font->GetCustomFontData();
 
   // FIXME: Provide more useful message such as OTS rejection reason.
   // See crbug.com/97467
-  if (font_->GetStatus() == ResourceStatus::kDecodeError) {
+  if (font->GetStatus() == ResourceStatus::kDecodeError) {
     font_selector_->GetExecutionContext()->AddConsoleMessage(
-        ConsoleMessage::Create(kOtherMessageSource, kWarningMessageLevel,
-                               "Failed to decode downloaded font: " +
-                                   font_->Url().ElidedString()));
-    if (font_->OtsParsingMessage().length() > 1) {
+        ConsoleMessage::Create(
+            kOtherMessageSource, kWarningMessageLevel,
+            "Failed to decode downloaded font: " + font->Url().ElidedString()));
+    if (font->OtsParsingMessage().length() > 1) {
       font_selector_->GetExecutionContext()->AddConsoleMessage(
           ConsoleMessage::Create(
               kOtherMessageSource, kWarningMessageLevel,
-              "OTS parsing error: " + font_->OtsParsingMessage()));
+              "OTS parsing error: " + font->OtsParsingMessage()));
     }
   }
 
-  font_->RemoveClient(this);
-  font_ = nullptr;
+  ClearResource();
 
   PruneTable();
   if (face_->FontLoaded(this))
@@ -212,20 +206,21 @@
 void RemoteFontFaceSource::BeginLoadIfNeeded() {
   if (IsLoaded())
     return;
-  DCHECK(font_);
+  DCHECK(GetResource());
 
-  if (font_->StillNeedsLoad()) {
-    if (!font_->Url().ProtocolIsData() && !font_->IsLoaded() &&
+  FontResource* font = ToFontResource(GetResource());
+  if (font->StillNeedsLoad()) {
+    if (!font->Url().ProtocolIsData() && !font->IsLoaded() &&
         display_ == kFontDisplayAuto &&
-        font_->IsLowPriorityLoadingAllowedForRemoteFont()) {
+        font->IsLowPriorityLoadingAllowedForRemoteFont()) {
       // Set the loading priority to VeryLow since this font is not required
       // for painting the text.
-      font_->DidChangePriority(ResourceLoadPriority::kVeryLow, 0);
+      font->DidChangePriority(ResourceLoadPriority::kVeryLow, 0);
     }
-    if (font_selector_->GetExecutionContext()->Fetcher()->StartLoad(font_)) {
+    if (font_selector_->GetExecutionContext()->Fetcher()->StartLoad(font)) {
       // Start timers only when load is actually started asynchronously.
-      if (!font_->IsLoaded()) {
-        font_->StartLoadLimitTimers(
+      if (!font->IsLoaded()) {
+        font->StartLoadLimitTimers(
             font_selector_->GetExecutionContext()
                 ->GetTaskRunner(TaskType::kUnspecedLoading)
                 .get());
@@ -237,7 +232,7 @@
           ConsoleMessage::Create(kOtherMessageSource, kInfoMessageLevel,
                                  "Slow network is detected. Fallback font will "
                                  "be used while loading: " +
-                                     font_->Url().ElidedString()));
+                                     font->Url().ElidedString()));
     }
   }
 
@@ -246,7 +241,6 @@
 
 void RemoteFontFaceSource::Trace(blink::Visitor* visitor) {
   visitor->Trace(face_);
-  visitor->Trace(font_);
   visitor->Trace(font_selector_);
   CSSFontFaceSource::Trace(visitor);
   FontResourceClient::Trace(visitor);
diff --git a/third_party/WebKit/Source/core/css/RemoteFontFaceSource.h b/third_party/WebKit/Source/core/css/RemoteFontFaceSource.h
index 6e16c8fe..217aae31 100644
--- a/third_party/WebKit/Source/core/css/RemoteFontFaceSource.h
+++ b/third_party/WebKit/Source/core/css/RemoteFontFaceSource.h
@@ -115,8 +115,6 @@
 
   // Our owning font face.
   Member<CSSFontFace> face_;
-  // Cleared once load is finished.
-  Member<FontResource> font_;
   Member<FontSelector> font_selector_;
 
   // |nullptr| if font is not loaded or failed to decode.
diff --git a/third_party/WebKit/Source/core/css/StyleRuleImport.cpp b/third_party/WebKit/Source/core/css/StyleRuleImport.cpp
index c53801b..ba8ddd598 100644
--- a/third_party/WebKit/Source/core/css/StyleRuleImport.cpp
+++ b/third_party/WebKit/Source/core/css/StyleRuleImport.cpp
@@ -52,16 +52,13 @@
 StyleRuleImport::~StyleRuleImport() = default;
 
 void StyleRuleImport::Dispose() {
-  if (resource_)
-    resource_->RemoveClient(style_sheet_client_);
-  resource_ = nullptr;
+  style_sheet_client_->Dispose();
 }
 
 void StyleRuleImport::TraceAfterDispatch(blink::Visitor* visitor) {
   visitor->Trace(style_sheet_client_);
   visitor->Trace(parent_style_sheet_);
   visitor->Trace(style_sheet_);
-  visitor->Trace(resource_);
   StyleRuleBase::TraceAfterDispatch(visitor);
 }
 
@@ -139,8 +136,9 @@
   options.initiator_info.name = FetchInitiatorTypeNames::css;
   FetchParameters params(ResourceRequest(abs_url), options);
   params.SetCharset(parent_style_sheet_->Charset());
-  resource_ = CSSStyleSheetResource::Fetch(params, fetcher);
-  if (resource_) {
+  CSSStyleSheetResource* resource =
+      CSSStyleSheetResource::Fetch(params, fetcher);
+  if (resource) {
     // if the import rule is issued dynamically, the sheet may be
     // removed from the pending sheet count, so let the doc know
     // the sheet being imported is pending.
@@ -148,7 +146,7 @@
         root_sheet == parent_style_sheet_)
       parent_style_sheet_->StartLoadingDynamicSheet();
     loading_ = true;
-    resource_->AddClient(style_sheet_client_);
+    style_sheet_client_->TakeResource(resource);
   }
 }
 
diff --git a/third_party/WebKit/Source/core/css/StyleRuleImport.h b/third_party/WebKit/Source/core/css/StyleRuleImport.h
index c07f6e1..48986fc 100644
--- a/third_party/WebKit/Source/core/css/StyleRuleImport.h
+++ b/third_party/WebKit/Source/core/css/StyleRuleImport.h
@@ -28,7 +28,6 @@
 
 namespace blink {
 
-class CSSStyleSheetResource;
 class MediaQuerySet;
 class StyleSheetContents;
 
@@ -75,6 +74,13 @@
     void NotifyFinished(Resource* resource) override {
       owner_rule_->NotifyFinished(resource);
     }
+
+    void TakeResource(Resource* resource) {
+      DCHECK(!GetResource());
+      SetResource(resource);
+    }
+    void Dispose() { ClearResource(); }
+
     String DebugName() const override { return "ImportedStyleSheetClient"; }
 
     void Trace(blink::Visitor* visitor) {
@@ -98,7 +104,6 @@
   String str_href_;
   scoped_refptr<MediaQuerySet> media_queries_;
   Member<StyleSheetContents> style_sheet_;
-  Member<CSSStyleSheetResource> resource_;
   bool loading_;
 };
 
diff --git a/third_party/WebKit/Source/core/css/cssom/CSSStyleImageValue.cpp b/third_party/WebKit/Source/core/css/cssom/CSSStyleImageValue.cpp
index ad5d2d3..08f7aa97 100644
--- a/third_party/WebKit/Source/core/css/cssom/CSSStyleImageValue.cpp
+++ b/third_party/WebKit/Source/core/css/cssom/CSSStyleImageValue.cpp
@@ -7,21 +7,21 @@
 namespace blink {
 
 double CSSStyleImageValue::intrinsicWidth(bool& is_null) const {
-  is_null = IsCachePending();
+  is_null = Status() != ResourceStatus::kCached;
   if (is_null)
     return 0;
   return ImageSize().Width();
 }
 
 double CSSStyleImageValue::intrinsicHeight(bool& is_null) const {
-  is_null = IsCachePending();
+  is_null = Status() != ResourceStatus::kCached;
   if (is_null)
     return 0;
   return ImageSize().Height();
 }
 
 double CSSStyleImageValue::intrinsicRatio(bool& is_null) {
-  is_null = IsCachePending();
+  is_null = Status() != ResourceStatus::kCached;
   if (is_null || intrinsicHeight(is_null) == 0) {
     is_null = true;
     return 0;
diff --git a/third_party/WebKit/Source/core/css/cssom/CSSStyleImageValueTest.cpp b/third_party/WebKit/Source/core/css/cssom/CSSStyleImageValueTest.cpp
index 24211e0..68ad7ea3 100644
--- a/third_party/WebKit/Source/core/css/cssom/CSSStyleImageValueTest.cpp
+++ b/third_party/WebKit/Source/core/css/cssom/CSSStyleImageValueTest.cpp
@@ -22,6 +22,12 @@
   bool IsCachePending() const override { return cache_pending_; }
   IntSize ImageSize() const override { return size_; }
 
+  ResourceStatus Status() const override {
+    if (IsCachePending())
+      return ResourceStatus::kNotStarted;
+    return ResourceStatus::kCached;
+  }
+
   const CSSValue* ToCSSValue(SecureContextMode) const override {
     return nullptr;
   }
diff --git a/third_party/WebKit/Source/core/css/cssom/StylePropertyMap.cpp b/third_party/WebKit/Source/core/css/cssom/StylePropertyMap.cpp
index 603f424..6d18c28 100644
--- a/third_party/WebKit/Source/core/css/cssom/StylePropertyMap.cpp
+++ b/third_party/WebKit/Source/core/css/cssom/StylePropertyMap.cpp
@@ -172,4 +172,26 @@
   RemoveProperty(property_id);
 }
 
+void StylePropertyMap::update(const ExecutionContext* execution_context,
+                              const String& property_name,
+                              V8UpdateFunction* update_function,
+                              ExceptionState& exception_state) {
+  CSSStyleValue* old_value = get(property_name, exception_state);
+  if (exception_state.HadException())
+    return;
+
+  const auto& new_value = update_function->Invoke(this, old_value);
+  if (new_value.IsNothing())
+    return;
+
+  HeapVector<CSSStyleValueOrString> new_value_vector;
+  new_value_vector.push_back(
+      CSSStyleValueOrString::FromCSSStyleValue(new_value.ToChecked()));
+
+  // FIXME(785132): We shouldn't need an execution_context here, but
+  // CSSUnsupportedStyleValue currently requires parsing.
+  set(execution_context, property_name, std::move(new_value_vector),
+      exception_state);
+}
+
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/css/cssom/StylePropertyMap.h b/third_party/WebKit/Source/core/css/cssom/StylePropertyMap.h
index fcf2314..f991694 100644
--- a/third_party/WebKit/Source/core/css/cssom/StylePropertyMap.h
+++ b/third_party/WebKit/Source/core/css/cssom/StylePropertyMap.h
@@ -28,7 +28,10 @@
               const HeapVector<CSSStyleValueOrString>& values,
               ExceptionState&);
   void remove(const String& property_name, ExceptionState&);
-  void update(const String&, const V8UpdateFunction*) {}
+  void update(const ExecutionContext*,
+              const String&,
+              V8UpdateFunction*,
+              ExceptionState&);
 
  protected:
   virtual void SetProperty(CSSPropertyID, const CSSValue*) = 0;
diff --git a/third_party/WebKit/Source/core/css/cssom/StylePropertyMap.idl b/third_party/WebKit/Source/core/css/cssom/StylePropertyMap.idl
index a6b5ea8..fe9da223 100644
--- a/third_party/WebKit/Source/core/css/cssom/StylePropertyMap.idl
+++ b/third_party/WebKit/Source/core/css/cssom/StylePropertyMap.idl
@@ -13,5 +13,6 @@
     [RaisesException, CallWith=ExecutionContext] void append(DOMString property, (CSSStyleValue or DOMString)... values);
     [RaisesException, ImplementedAs=remove] void delete(DOMString property);
     [RaisesException, CallWith=ExecutionContext] void set(DOMString property, (CSSStyleValue or DOMString)... values);
-    void update(DOMString property, UpdateFunction updateFunction);
+    // FIXME(785132): This shouldn't need a ExecutionContext.
+    [RaisesException, CallWith=ExecutionContext] void update(DOMString property, UpdateFunction updateFunction);
 };
diff --git a/third_party/WebKit/Source/core/css/parser/CSSParserFastPaths.cpp b/third_party/WebKit/Source/core/css/parser/CSSParserFastPaths.cpp
index 48de273..4694fc11 100644
--- a/third_party/WebKit/Source/core/css/parser/CSSParserFastPaths.cpp
+++ b/third_party/WebKit/Source/core/css/parser/CSSParserFastPaths.cpp
@@ -426,7 +426,7 @@
 template <typename CharacterType>
 static inline bool MightBeRGBOrRGBA(const CharacterType* characters,
                                     unsigned length) {
-  if (length < 4)
+  if (length < 5)
     return false;
   return IsASCIIAlphaCaselessEqual(characters[0], 'r') &&
          IsASCIIAlphaCaselessEqual(characters[1], 'g') &&
diff --git a/third_party/WebKit/Source/core/dom/ClassicPendingScript.cpp b/third_party/WebKit/Source/core/dom/ClassicPendingScript.cpp
index 7be44c8..8f32b72 100644
--- a/third_party/WebKit/Source/core/dom/ClassicPendingScript.cpp
+++ b/third_party/WebKit/Source/core/dom/ClassicPendingScript.cpp
@@ -11,6 +11,7 @@
 #include "core/dom/DocumentWriteIntervention.h"
 #include "core/dom/ScriptLoader.h"
 #include "core/frame/LocalFrame.h"
+#include "core/loader/AllowedByNosniff.h"
 #include "core/loader/SubresourceIntegrityHelper.h"
 #include "core/loader/resource/ScriptResource.h"
 #include "platform/bindings/ScriptState.h"
@@ -224,11 +225,20 @@
 
 void ClassicPendingScript::Trace(blink::Visitor* visitor) {
   visitor->Trace(streamer_);
-  ResourceOwner<ScriptResource>::Trace(visitor);
+  ResourceClient::Trace(visitor);
   MemoryCoordinatorClient::Trace(visitor);
   PendingScript::Trace(visitor);
 }
 
+bool ClassicPendingScript::CheckMIMETypeBeforeRunScript(
+    Document* context_document) const {
+  if (!is_external_)
+    return true;
+
+  return AllowedByNosniff::MimeTypeAsScript(context_document,
+                                            GetResource()->GetResponse());
+}
+
 ClassicScript* ClassicPendingScript::GetSource(const KURL& document_url,
                                                bool& error_occurred) const {
   CheckState();
@@ -243,12 +253,12 @@
   }
 
   DCHECK(GetResource()->IsLoaded());
+  ScriptResource* resource = ToScriptResource(GetResource());
   bool streamer_ready = (ready_state_ == kReady) && streamer_ &&
                         !streamer_->StreamingSuppressed();
-  ScriptSourceCode source_code(streamer_ready ? streamer_ : nullptr,
-                               GetResource());
+  ScriptSourceCode source_code(streamer_ready ? streamer_ : nullptr, resource);
   return ClassicScript::Create(source_code, options_,
-                               GetResource()->CalculateAccessControlStatus());
+                               resource->CalculateAccessControlStatus());
 }
 
 void ClassicPendingScript::SetStreamer(ScriptStreamer* streamer) {
diff --git a/third_party/WebKit/Source/core/dom/ClassicPendingScript.h b/third_party/WebKit/Source/core/dom/ClassicPendingScript.h
index 0e06e74..93d8ebd 100644
--- a/third_party/WebKit/Source/core/dom/ClassicPendingScript.h
+++ b/third_party/WebKit/Source/core/dom/ClassicPendingScript.h
@@ -12,7 +12,6 @@
 #include "core/loader/resource/ScriptResource.h"
 #include "platform/MemoryCoordinator.h"
 #include "platform/loader/fetch/FetchParameters.h"
-#include "platform/loader/fetch/ResourceOwner.h"
 
 namespace blink {
 
@@ -24,10 +23,9 @@
 // A RefPtr alone does not prevent the underlying Resource from purging its data
 // buffer. This class holds a dummy client open for its lifetime in order to
 // guarantee that the data buffer will not be purged.
-class CORE_EXPORT ClassicPendingScript final
-    : public PendingScript,
-      public ResourceOwner<ScriptResource>,
-      public MemoryCoordinatorClient {
+class CORE_EXPORT ClassicPendingScript final : public PendingScript,
+                                               public ResourceClient,
+                                               public MemoryCoordinatorClient {
   USING_GARBAGE_COLLECTED_MIXIN(ClassicPendingScript);
   USING_PRE_FINALIZER(ClassicPendingScript, Prefinalize);
 
@@ -65,6 +63,7 @@
     return blink::ScriptType::kClassic;
   }
 
+  bool CheckMIMETypeBeforeRunScript(Document* context_document) const override;
   ClassicScript* GetSource(const KURL& document_url,
                            bool& error_occurred) const override;
   bool IsReady() const override;
diff --git a/third_party/WebKit/Source/core/dom/ClassicScript.cpp b/third_party/WebKit/Source/core/dom/ClassicScript.cpp
index bd769ef..cd3bd9c 100644
--- a/third_party/WebKit/Source/core/dom/ClassicScript.cpp
+++ b/third_party/WebKit/Source/core/dom/ClassicScript.cpp
@@ -5,12 +5,7 @@
 #include "core/dom/ClassicScript.h"
 
 #include "bindings/core/v8/ScriptController.h"
-#include "core/dom/Document.h"
 #include "core/frame/LocalFrame.h"
-#include "core/frame/UseCounter.h"
-#include "core/inspector/ConsoleMessage.h"
-#include "core/loader/AllowedByNosniff.h"
-#include "platform/network/mime/MIMETypeRegistry.h"
 
 namespace blink {
 
@@ -19,13 +14,6 @@
   visitor->Trace(script_source_code_);
 }
 
-bool ClassicScript::CheckMIMETypeBeforeRunScript(
-    Document* context_document,
-    const SecurityOrigin* security_origin) const {
-  return AllowedByNosniff::MimeTypeAsScript(
-      context_document, GetScriptSourceCode().GetResource()->GetResponse());
-}
-
 void ClassicScript::RunScript(LocalFrame* frame,
                               const SecurityOrigin* security_origin) const {
   frame->GetScriptController().ExecuteScriptInMainWorld(
diff --git a/third_party/WebKit/Source/core/dom/ClassicScript.h b/third_party/WebKit/Source/core/dom/ClassicScript.h
index 59b3e690..04d8c96c 100644
--- a/third_party/WebKit/Source/core/dom/ClassicScript.h
+++ b/third_party/WebKit/Source/core/dom/ClassicScript.h
@@ -38,8 +38,6 @@
         access_control_status_(access_control_status) {}
 
   ScriptType GetScriptType() const override { return ScriptType::kClassic; }
-  bool CheckMIMETypeBeforeRunScript(Document* context_document,
-                                    const SecurityOrigin*) const override;
   void RunScript(LocalFrame*, const SecurityOrigin*) const override;
   String InlineSourceTextForCSP() const override {
     return script_source_code_.Source();
diff --git a/third_party/WebKit/Source/core/dom/ModulePendingScript.cpp b/third_party/WebKit/Source/core/dom/ModulePendingScript.cpp
index f909c94..4d3cd90 100644
--- a/third_party/WebKit/Source/core/dom/ModulePendingScript.cpp
+++ b/third_party/WebKit/Source/core/dom/ModulePendingScript.cpp
@@ -85,6 +85,12 @@
     Client()->PendingScriptFinished(this);
 }
 
+bool ModulePendingScript::CheckMIMETypeBeforeRunScript(Document*) const {
+  // We don't check MIME type here because we check the MIME type in
+  // ModuleScriptLoader::WasModuleLoadSuccessful().
+  return true;
+}
+
 Script* ModulePendingScript::GetSource(const KURL& document_url,
                                        bool& error_occurred) const {
   CHECK(IsReady());
diff --git a/third_party/WebKit/Source/core/dom/ModulePendingScript.h b/third_party/WebKit/Source/core/dom/ModulePendingScript.h
index b9302f4e..d11c39e 100644
--- a/third_party/WebKit/Source/core/dom/ModulePendingScript.h
+++ b/third_party/WebKit/Source/core/dom/ModulePendingScript.h
@@ -74,6 +74,7 @@
 
   // PendingScript
   ScriptType GetScriptType() const override { return ScriptType::kModule; }
+  bool CheckMIMETypeBeforeRunScript(Document* context_document) const override;
   Script* GetSource(const KURL& document_url,
                     bool& error_occurred) const override;
   bool IsReady() const override { return ready_; }
diff --git a/third_party/WebKit/Source/core/dom/ModuleScript.cpp b/third_party/WebKit/Source/core/dom/ModuleScript.cpp
index a15e281..c58358ff 100644
--- a/third_party/WebKit/Source/core/dom/ModuleScript.cpp
+++ b/third_party/WebKit/Source/core/dom/ModuleScript.cpp
@@ -226,13 +226,6 @@
   visitor->TraceWrappers(preinstantiation_error_);
 }
 
-bool ModuleScript::CheckMIMETypeBeforeRunScript(Document* context_document,
-                                                const SecurityOrigin*) const {
-  // We don't check MIME type here because we check the MIME type in
-  // ModuleScriptLoader::WasModuleLoadSuccessful().
-  return true;
-}
-
 void ModuleScript::RunScript(LocalFrame* frame, const SecurityOrigin*) const {
   DVLOG(1) << *this << "::RunScript()";
   settings_object_->ExecuteModule(this,
diff --git a/third_party/WebKit/Source/core/dom/ModuleScript.h b/third_party/WebKit/Source/core/dom/ModuleScript.h
index b5bd54e..e3deb06 100644
--- a/third_party/WebKit/Source/core/dom/ModuleScript.h
+++ b/third_party/WebKit/Source/core/dom/ModuleScript.h
@@ -82,8 +82,6 @@
                                       const TextPosition&);
 
   ScriptType GetScriptType() const override { return ScriptType::kModule; }
-  bool CheckMIMETypeBeforeRunScript(Document* context_document,
-                                    const SecurityOrigin*) const override;
   void RunScript(LocalFrame*, const SecurityOrigin*) const override;
   String InlineSourceTextForCSP() const override;
 
diff --git a/third_party/WebKit/Source/core/dom/PendingScript.h b/third_party/WebKit/Source/core/dom/PendingScript.h
index 576d67dd..123e85e 100644
--- a/third_party/WebKit/Source/core/dom/PendingScript.h
+++ b/third_party/WebKit/Source/core/dom/PendingScript.h
@@ -82,6 +82,11 @@
 
   virtual void Trace(blink::Visitor*);
 
+  // Returns false if the script should not be run due to MIME type check.
+  // Should be called just before GetSource().
+  virtual bool CheckMIMETypeBeforeRunScript(
+      Document* context_document) const = 0;
+
   virtual Script* GetSource(const KURL& document_url,
                             bool& error_occurred) const = 0;
 
diff --git a/third_party/WebKit/Source/core/dom/ProcessingInstruction.cpp b/third_party/WebKit/Source/core/dom/ProcessingInstruction.cpp
index 8de30db..fe62888 100644
--- a/third_party/WebKit/Source/core/dom/ProcessingInstruction.cpp
+++ b/third_party/WebKit/Source/core/dom/ProcessingInstruction.cpp
@@ -287,7 +287,7 @@
   visitor->Trace(sheet_);
   visitor->Trace(listener_for_xslt_);
   CharacterData::Trace(visitor);
-  ResourceOwner<TextResource>::Trace(visitor);
+  ResourceClient::Trace(visitor);
 }
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/dom/ProcessingInstruction.h b/third_party/WebKit/Source/core/dom/ProcessingInstruction.h
index c99e301e..c2a77349 100644
--- a/third_party/WebKit/Source/core/dom/ProcessingInstruction.h
+++ b/third_party/WebKit/Source/core/dom/ProcessingInstruction.h
@@ -26,7 +26,6 @@
 #include "core/dom/CharacterData.h"
 #include "core/loader/resource/TextResource.h"
 #include "platform/loader/fetch/ResourceClient.h"
-#include "platform/loader/fetch/ResourceOwner.h"
 
 namespace blink {
 
@@ -34,7 +33,7 @@
 class EventListener;
 
 class ProcessingInstruction final : public CharacterData,
-                                    private ResourceOwner<TextResource> {
+                                    private ResourceClient {
   DEFINE_WRAPPERTYPEINFO();
   USING_GARBAGE_COLLECTED_MIXIN(ProcessingInstruction);
 
diff --git a/third_party/WebKit/Source/core/dom/Script.h b/third_party/WebKit/Source/core/dom/Script.h
index c74525f..be3121a 100644
--- a/third_party/WebKit/Source/core/dom/Script.h
+++ b/third_party/WebKit/Source/core/dom/Script.h
@@ -13,7 +13,6 @@
 
 namespace blink {
 
-class Document;
 class LocalFrame;
 class SecurityOrigin;
 
@@ -28,10 +27,6 @@
 
   virtual ScriptType GetScriptType() const = 0;
 
-  // Returns false if the script should not be run due to MIME type check.
-  virtual bool CheckMIMETypeBeforeRunScript(Document* context_document,
-                                            const SecurityOrigin*) const = 0;
-
   // https://html.spec.whatwg.org/#run-a-classic-script or
   // https://html.spec.whatwg.org/#run-a-module-script,
   // depending on the script type.
diff --git a/third_party/WebKit/Source/core/dom/ScriptLoader.cpp b/third_party/WebKit/Source/core/dom/ScriptLoader.cpp
index 06168e9..693fe320 100644
--- a/third_party/WebKit/Source/core/dom/ScriptLoader.cpp
+++ b/third_party/WebKit/Source/core/dom/ScriptLoader.cpp
@@ -760,12 +760,6 @@
     }
   }
 
-  if (is_external_script_) {
-    if (!script->CheckMIMETypeBeforeRunScript(
-            context_document, element_->GetDocument().GetSecurityOrigin()))
-      return ExecuteScriptResult::kShouldFireErrorEvent;
-  }
-
   const bool is_imported_script = context_document != element_document;
 
   // 3. "If the script is from an external file,
@@ -844,20 +838,28 @@
     return;
   }
 
+  // Do not execute module scripts if they are moved between documents.
+  // TODO(hiroshige): Also do not execute classic scripts. crbug.com/721914
+  if (original_document_ != context_document &&
+      GetScriptType() == ScriptType::kModule) {
+    pending_script->Dispose();
+    return;
+  }
+
   bool error_occurred = false;
   Script* script = pending_script->GetSource(document_url, error_occurred);
+
+  // Consider as if "the script's script is null" retrospectively,
+  // if the MIME check fails, which is considered as load failure.
+  if (!pending_script->CheckMIMETypeBeforeRunScript(context_document))
+    error_occurred = true;
+
   const bool was_canceled = pending_script->WasCanceled();
   const bool is_external = pending_script->IsExternal();
   const double parser_blocking_load_start_time =
       pending_script->ParserBlockingLoadStartTime();
   pending_script->Dispose();
 
-  // Do not execute module scripts if they are moved between documents.
-  // TODO(hiroshige): Also do not execute classic scripts. crbug.com/721914
-  if (original_document_ != context_document &&
-      GetScriptType() == ScriptType::kModule)
-    return;
-
   // 2. "If the script's script is null, fire an event named error at the
   //     element, and abort these steps."
   if (error_occurred) {
diff --git a/third_party/WebKit/Source/core/dom/ScriptLoader.h b/third_party/WebKit/Source/core/dom/ScriptLoader.h
index 44e0fd7..664edcb 100644
--- a/third_party/WebKit/Source/core/dom/ScriptLoader.h
+++ b/third_party/WebKit/Source/core/dom/ScriptLoader.h
@@ -231,7 +231,7 @@
   // This is used only to keep the ScriptResource of a classic script alive
   // and thus to keep it on MemoryCache, even after script execution, as long
   // as ScriptLoader is alive. crbug.com/778799
-  Member<ScriptResource> resource_keep_alive_;
+  Member<Resource> resource_keep_alive_;
 
   // The context document at the time when PrepareScript() is executed.
   // This is only used to check whether the script element is moved between
diff --git a/third_party/WebKit/Source/core/dom/ScriptRunnerTest.cpp b/third_party/WebKit/Source/core/dom/ScriptRunnerTest.cpp
index 1e9094f..d8e5cdcb 100644
--- a/third_party/WebKit/Source/core/dom/ScriptRunnerTest.cpp
+++ b/third_party/WebKit/Source/core/dom/ScriptRunnerTest.cpp
@@ -29,6 +29,7 @@
   ~MockPendingScript() override {}
 
   MOCK_CONST_METHOD0(GetScriptType, ScriptType());
+  MOCK_CONST_METHOD1(CheckMIMETypeBeforeRunScript, bool(Document*));
   MOCK_CONST_METHOD2(GetSource, Script*(const KURL&, bool&));
   MOCK_CONST_METHOD0(IsReady, bool());
   MOCK_CONST_METHOD0(IsExternal, bool());
diff --git a/third_party/WebKit/Source/core/editing/commands/EditorCommand.cpp b/third_party/WebKit/Source/core/editing/commands/EditorCommand.cpp
index bfcf627..8292ea8 100644
--- a/third_party/WebKit/Source/core/editing/commands/EditorCommand.cpp
+++ b/third_party/WebKit/Source/core/editing/commands/EditorCommand.cpp
@@ -1242,7 +1242,7 @@
 }
 
 // Returns true if selection is modified.
-bool ModifySelectionyWithPageGranularity(
+bool ModifySelectionWithPageGranularity(
     LocalFrame& frame,
     SelectionModifyAlteration alter,
     unsigned vertical_distance,
@@ -1274,7 +1274,7 @@
   unsigned distance = VerticalScrollDistance(frame);
   if (!distance)
     return false;
-  return ModifySelectionyWithPageGranularity(
+  return ModifySelectionWithPageGranularity(
       frame, SelectionModifyAlteration::kMove, distance,
       SelectionModifyVerticalDirection::kDown);
 }
@@ -1286,7 +1286,7 @@
   unsigned distance = VerticalScrollDistance(frame);
   if (!distance)
     return false;
-  return ModifySelectionyWithPageGranularity(
+  return ModifySelectionWithPageGranularity(
       frame, SelectionModifyAlteration::kExtend, distance,
       SelectionModifyVerticalDirection::kDown);
 }
@@ -1298,7 +1298,7 @@
   unsigned distance = VerticalScrollDistance(frame);
   if (!distance)
     return false;
-  return ModifySelectionyWithPageGranularity(
+  return ModifySelectionWithPageGranularity(
       frame, SelectionModifyAlteration::kMove, distance,
       SelectionModifyVerticalDirection::kUp);
 }
@@ -1310,7 +1310,7 @@
   unsigned distance = VerticalScrollDistance(frame);
   if (!distance)
     return false;
-  return ModifySelectionyWithPageGranularity(
+  return ModifySelectionWithPageGranularity(
       frame, SelectionModifyAlteration::kExtend, distance,
       SelectionModifyVerticalDirection::kUp);
 }
diff --git a/third_party/WebKit/Source/core/exported/LocalFrameClientImpl.cpp b/third_party/WebKit/Source/core/exported/LocalFrameClientImpl.cpp
index 59f8c901..32886c24 100644
--- a/third_party/WebKit/Source/core/exported/LocalFrameClientImpl.cpp
+++ b/third_party/WebKit/Source/core/exported/LocalFrameClientImpl.cpp
@@ -434,7 +434,8 @@
 
 void LocalFrameClientImpl::DispatchDidCommitLoad(
     HistoryItem* item,
-    HistoryCommitType commit_type) {
+    HistoryCommitType commit_type,
+    WebGlobalObjectReusePolicy global_object_reuse_policy) {
   if (!web_frame_->Parent()) {
     web_frame_->ViewImpl()->DidCommitLoad(commit_type == kStandardCommit,
                                           false);
@@ -442,7 +443,8 @@
 
   if (web_frame_->Client()) {
     web_frame_->Client()->DidCommitProvisionalLoad(
-        WebHistoryItem(item), static_cast<WebHistoryCommitType>(commit_type));
+        WebHistoryItem(item), static_cast<WebHistoryCommitType>(commit_type),
+        global_object_reuse_policy);
   }
   if (WebDevToolsAgentImpl* dev_tools = DevToolsAgent())
     dev_tools->DidCommitLoadForLocalFrame(web_frame_->GetFrame());
diff --git a/third_party/WebKit/Source/core/exported/LocalFrameClientImpl.h b/third_party/WebKit/Source/core/exported/LocalFrameClientImpl.h
index 6c9efb0e..d549908 100644
--- a/third_party/WebKit/Source/core/exported/LocalFrameClientImpl.h
+++ b/third_party/WebKit/Source/core/exported/LocalFrameClientImpl.h
@@ -102,7 +102,9 @@
                                        ResourceRequest&) override;
   void DispatchDidReceiveTitle(const String&) override;
   void DispatchDidChangeIcons(IconType) override;
-  void DispatchDidCommitLoad(HistoryItem*, HistoryCommitType) override;
+  void DispatchDidCommitLoad(HistoryItem*,
+                             HistoryCommitType,
+                             WebGlobalObjectReusePolicy) override;
   void DispatchDidFailProvisionalLoad(const ResourceError&,
                                       HistoryCommitType) override;
   void DispatchDidFailLoad(const ResourceError&, HistoryCommitType) override;
diff --git a/third_party/WebKit/Source/core/exported/WebFrameTest.cpp b/third_party/WebKit/Source/core/exported/WebFrameTest.cpp
index 45f1dad6..c90e69bec 100644
--- a/third_party/WebKit/Source/core/exported/WebFrameTest.cpp
+++ b/third_party/WebKit/Source/core/exported/WebFrameTest.cpp
@@ -4248,7 +4248,8 @@
 
   // FrameTestHelpers::TestWebFrameClient:
   void DidCommitProvisionalLoad(const WebHistoryItem&,
-                                WebHistoryCommitType) override {
+                                WebHistoryCommitType,
+                                WebGlobalObjectReusePolicy) override {
     Frame()->View()->ResetScrollAndScaleState();
   }
 };
@@ -6539,7 +6540,8 @@
                             error.url(), true);
   }
   void DidCommitProvisionalLoad(const WebHistoryItem&,
-                                WebHistoryCommitType) override {
+                                WebHistoryCommitType,
+                                WebGlobalObjectReusePolicy) override {
     if (Frame()->GetDocumentLoader()->GetResponse().Url() !=
         WebURL(URLTestHelpers::ToKURL("about:blank")))
       commit_called_ = true;
@@ -6593,7 +6595,8 @@
 
   // FrameTestHelpers::TestWebFrameClient:
   void DidCommitProvisionalLoad(const WebHistoryItem&,
-                                WebHistoryCommitType) override {
+                                WebHistoryCommitType,
+                                WebGlobalObjectReusePolicy) override {
     num_bodies_ = 0;
     did_load_ = true;
   }
@@ -9429,9 +9432,9 @@
   ~RemoteToLocalSwapWebFrameClient() override {}
 
   // FrameTestHelpers::TestWebFrameClient:
-  void DidCommitProvisionalLoad(
-      const WebHistoryItem&,
-      WebHistoryCommitType history_commit_type) override {
+  void DidCommitProvisionalLoad(const WebHistoryItem&,
+                                WebHistoryCommitType history_commit_type,
+                                WebGlobalObjectReusePolicy) override {
     history_commit_type_ = history_commit_type;
     remote_frame_->Swap(Frame());
   }
@@ -9643,9 +9646,9 @@
   ~CommitTypeWebFrameClient() override {}
 
   // FrameTestHelpers::TestWebFrameClient:
-  void DidCommitProvisionalLoad(
-      const WebHistoryItem&,
-      WebHistoryCommitType history_commit_type) override {
+  void DidCommitProvisionalLoad(const WebHistoryItem&,
+                                WebHistoryCommitType history_commit_type,
+                                WebGlobalObjectReusePolicy) override {
     history_commit_type_ = history_commit_type;
   }
 
@@ -10584,7 +10587,8 @@
     EXPECT_EQ(1, callback_count_++);
   }
   void DidCommitProvisionalLoad(const WebHistoryItem&,
-                                WebHistoryCommitType) override {
+                                WebHistoryCommitType,
+                                WebGlobalObjectReusePolicy) override {
     EXPECT_EQ(2, callback_count_++);
   }
   void DidFinishDocumentLoad() override { EXPECT_EQ(3, callback_count_++); }
diff --git a/third_party/WebKit/Source/core/frame/LocalFrameClient.h b/third_party/WebKit/Source/core/frame/LocalFrameClient.h
index cc840712..4373dfb 100644
--- a/third_party/WebKit/Source/core/frame/LocalFrameClient.h
+++ b/third_party/WebKit/Source/core/frame/LocalFrameClient.h
@@ -56,6 +56,7 @@
 #include "public/platform/WebScopedVirtualTimePauser.h"
 #include "public/platform/WebSuddenTerminationDisablerType.h"
 #include "public/platform/WebURLRequest.h"
+#include "public/web/WebGlobalObjectReusePolicy.h"
 #include "public/web/WebTriggeringEventInfo.h"
 #include "third_party/WebKit/common/feature_policy/feature_policy.h"
 #include "v8/include/v8.h"
@@ -125,7 +126,9 @@
                                                ResourceRequest&) = 0;
   virtual void DispatchDidReceiveTitle(const String&) = 0;
   virtual void DispatchDidChangeIcons(IconType) = 0;
-  virtual void DispatchDidCommitLoad(HistoryItem*, HistoryCommitType) = 0;
+  virtual void DispatchDidCommitLoad(HistoryItem*,
+                                     HistoryCommitType,
+                                     WebGlobalObjectReusePolicy) = 0;
   virtual void DispatchDidFailProvisionalLoad(const ResourceError&,
                                               HistoryCommitType) = 0;
   virtual void DispatchDidFailLoad(const ResourceError&, HistoryCommitType) = 0;
diff --git a/third_party/WebKit/Source/core/fullscreen/Fullscreen.cpp b/third_party/WebKit/Source/core/fullscreen/Fullscreen.cpp
index 0f77992..41340537 100644
--- a/third_party/WebKit/Source/core/fullscreen/Fullscreen.cpp
+++ b/third_party/WebKit/Source/core/fullscreen/Fullscreen.cpp
@@ -29,6 +29,7 @@
 
 #include "core/fullscreen/Fullscreen.h"
 
+#include "base/macros.h"
 #include "core/css/StyleEngine.h"
 #include "core/dom/Document.h"
 #include "core/dom/ElementTraversal.h"
@@ -193,7 +194,6 @@
 // deferring changes in |DidEnterFullscreen()|.
 class RequestFullscreenScope {
   STACK_ALLOCATED();
-  WTF_MAKE_NONCOPYABLE(RequestFullscreenScope);
 
  public:
   RequestFullscreenScope() {
@@ -210,6 +210,7 @@
 
  private:
   static bool running_request_fullscreen_;
+  DISALLOW_COPY_AND_ASSIGN(RequestFullscreenScope);
 };
 
 bool RequestFullscreenScope::running_request_fullscreen_ = false;
diff --git a/third_party/WebKit/Source/core/html/HTMLCanvasElement.cpp b/third_party/WebKit/Source/core/html/HTMLCanvasElement.cpp
index cf4045d..baf9e26 100644
--- a/third_party/WebKit/Source/core/html/HTMLCanvasElement.cpp
+++ b/third_party/WebKit/Source/core/html/HTMLCanvasElement.cpp
@@ -760,9 +760,20 @@
     return nullptr;
   scoped_refptr<StaticBitmapImage> image_bitmap = nullptr;
   if (Is3d()) {
-    context_->PaintRenderingResultsToCanvas(source_buffer);
-    if (GetImageBuffer())
-      image_bitmap = GetImageBuffer()->NewImageSnapshot(hint, reason);
+    if (context_->CreationAttributes().premultipliedAlpha()) {
+      context_->PaintRenderingResultsToCanvas(source_buffer);
+      if (GetImageBuffer())
+        image_bitmap = GetImageBuffer()->NewImageSnapshot(hint, reason);
+    } else {
+      scoped_refptr<Uint8Array> data_array =
+          context_->PaintRenderingResultsToDataArray(source_buffer);
+      if (data_array) {
+        SkImageInfo info =
+            SkImageInfo::Make(size_.Width(), size_.Height(),
+                              kRGBA_8888_SkColorType, kUnpremul_SkAlphaType);
+        image_bitmap = StaticBitmapImage::Create(std::move(data_array), info);
+      }
+    }
   } else if (context_ || PlaceholderFrame()) {
     DCHECK(Is2d() || PlaceholderFrame());
     if (GetImageBuffer()) {
@@ -777,24 +788,6 @@
   return image_bitmap;
 }
 
-ImageData* HTMLCanvasElement::ToImageData(SourceDrawingBuffer source_buffer,
-                                          SnapshotReason reason) const {
-  // Using ImageData requires pixel read back and converting the color
-  // components from half float to float32 if the context is using a wide color
-  // gamut. Therefore, we do this only if the context is texture backed and
-  // premultipledAlpha is set to false by the user.
-  DCHECK(Is3d() && !context_->CreationAttributes().premultipliedAlpha());
-  if (Size().IsEmpty())
-    return nullptr;
-  ImageData* image_data;
-  // Get non-premultiplied data because of inaccurate premultiplied alpha
-  // conversion of buffer()->toDataURL().
-  image_data = context_->PaintRenderingResultsToImageData(source_buffer);
-  if (image_data)
-    return image_data;
-  return ImageData::Create(size_);
-}
-
 String HTMLCanvasElement::ToDataURLInternal(
     const String& mime_type,
     const double& quality,
@@ -826,20 +819,10 @@
     NOTREACHED();
   }
 
-  if (Is3d() && !context_->CreationAttributes().premultipliedAlpha()) {
-    ImageData* image_data = ToImageData(source_buffer, kSnapshotReasonToBlob);
-    if (image_data) {
-      return ImageDataBuffer(image_data->Size(), image_data->data()->Data())
-          .ToDataURL(encoding_mime_type, quality);
-    }
-  } else {
-    scoped_refptr<StaticBitmapImage> image_bitmap = ToStaticBitmapImage(
-        source_buffer, kPreferNoAcceleration, kSnapshotReasonToBlob);
-    if (image_bitmap) {
-      return ImageDataBuffer(image_bitmap)
-          .ToDataURL(encoding_mime_type, quality);
-    }
-  }
+  scoped_refptr<StaticBitmapImage> image_bitmap = ToStaticBitmapImage(
+      source_buffer, kPreferNoAcceleration, kSnapshotReasonToBlob);
+  if (image_bitmap)
+    return ImageDataBuffer(image_bitmap).ToDataURL(encoding_mime_type, quality);
   return String("data:,");
 }
 
@@ -894,14 +877,6 @@
       mime_type, ImageEncoderUtils::kEncodeReasonToBlobCallback);
 
   CanvasAsyncBlobCreator* async_creator = nullptr;
-  if (Is3d() && !context_->CreationAttributes().premultipliedAlpha()) {
-    ImageData* image_data = ToImageData(kBackBuffer, kSnapshotReasonToBlob);
-    if (image_data) {
-      async_creator = CanvasAsyncBlobCreator::Create(
-          image_data->data(), encoding_mime_type, image_data->Size(), callback,
-          start_time, &GetDocument());
-    }
-  } else {
     scoped_refptr<StaticBitmapImage> image_bitmap = ToStaticBitmapImage(
         kBackBuffer, kPreferNoAcceleration, kSnapshotReasonToBlob);
     if (image_bitmap) {
@@ -909,7 +884,6 @@
           CanvasAsyncBlobCreator::Create(image_bitmap, encoding_mime_type,
                                          callback, start_time, &GetDocument());
     }
-  }
 
   if (async_creator) {
     async_creator->ScheduleAsyncBlobCreation(quality);
diff --git a/third_party/WebKit/Source/core/html/HTMLCanvasElement.h b/third_party/WebKit/Source/core/html/HTMLCanvasElement.h
index 55970cb..0c8e790a 100644
--- a/third_party/WebKit/Source/core/html/HTMLCanvasElement.h
+++ b/third_party/WebKit/Source/core/html/HTMLCanvasElement.h
@@ -68,7 +68,6 @@
 class ImageBitmapOptions;
 class ImageBuffer;
 class ImageBufferSurface;
-class ImageData;
 class IntSize;
 
 class
@@ -326,7 +325,6 @@
   scoped_refptr<StaticBitmapImage> ToStaticBitmapImage(SourceDrawingBuffer,
                                                        AccelerationHint,
                                                        SnapshotReason) const;
-  ImageData* ToImageData(SourceDrawingBuffer, SnapshotReason) const;
 
   String ToDataURLInternal(const String& mime_type,
                            const double& quality,
diff --git a/third_party/WebKit/Source/core/html/LinkStyle.cpp b/third_party/WebKit/Source/core/html/LinkStyle.cpp
index c8a7dba..f1e02ac 100644
--- a/third_party/WebKit/Source/core/html/LinkStyle.cpp
+++ b/third_party/WebKit/Source/core/html/LinkStyle.cpp
@@ -406,7 +406,7 @@
 void LinkStyle::Trace(blink::Visitor* visitor) {
   visitor->Trace(sheet_);
   LinkResource::Trace(visitor);
-  ResourceOwner<CSSStyleSheetResource>::Trace(visitor);
+  ResourceClient::Trace(visitor);
 }
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/html/LinkStyle.h b/third_party/WebKit/Source/core/html/LinkStyle.h
index ba2f3a6c..33d51e1c 100644
--- a/third_party/WebKit/Source/core/html/LinkStyle.h
+++ b/third_party/WebKit/Source/core/html/LinkStyle.h
@@ -10,7 +10,6 @@
 #include "core/html/LinkResource.h"
 #include "core/loader/resource/CSSStyleSheetResource.h"
 #include "platform/loader/fetch/ResourceClient.h"
-#include "platform/loader/fetch/ResourceOwner.h"
 #include "platform/wtf/Forward.h"
 
 namespace blink {
@@ -25,8 +24,7 @@
 // types might better be handled by a separate class, but dynamically
 // changing @rel makes it harder to move such a design so we are
 // sticking current way so far.
-class LinkStyle final : public LinkResource,
-                        ResourceOwner<CSSStyleSheetResource> {
+class LinkStyle final : public LinkResource, ResourceClient {
   USING_GARBAGE_COLLECTED_MIXIN(LinkStyle);
 
  public:
diff --git a/third_party/WebKit/Source/core/html/canvas/CanvasAsyncBlobCreator.cpp b/third_party/WebKit/Source/core/html/canvas/CanvasAsyncBlobCreator.cpp
index 4e9a3e5..a6e3ae0 100644
--- a/third_party/WebKit/Source/core/html/canvas/CanvasAsyncBlobCreator.cpp
+++ b/third_party/WebKit/Source/core/html/canvas/CanvasAsyncBlobCreator.cpp
@@ -151,40 +151,14 @@
 }  // anonymous namespace
 
 CanvasAsyncBlobCreator* CanvasAsyncBlobCreator::Create(
-    DOMUint8ClampedArray* unpremultiplied_rgba_image_data,
-    const String& mime_type,
-    const IntSize& size,
-    V8BlobCallback* callback,
-    double start_time,
-    ExecutionContext* context) {
-  return new CanvasAsyncBlobCreator(unpremultiplied_rgba_image_data, nullptr,
-                                    ConvertMimeTypeStringToEnum(mime_type),
-                                    size, callback, start_time, context,
-                                    nullptr);
-}
-
-CanvasAsyncBlobCreator* CanvasAsyncBlobCreator::Create(
-    DOMUint8ClampedArray* unpremultiplied_rgba_image_data,
-    const String& mime_type,
-    const IntSize& size,
-    double start_time,
-    ExecutionContext* context,
-    ScriptPromiseResolver* resolver) {
-  return new CanvasAsyncBlobCreator(unpremultiplied_rgba_image_data, nullptr,
-                                    ConvertMimeTypeStringToEnum(mime_type),
-                                    size, nullptr, start_time, context,
-                                    resolver);
-}
-
-CanvasAsyncBlobCreator* CanvasAsyncBlobCreator::Create(
     scoped_refptr<StaticBitmapImage> image,
     const String& mime_type,
     V8BlobCallback* callback,
     double start_time,
     ExecutionContext* context) {
-  return new CanvasAsyncBlobCreator(
-      nullptr, image, ConvertMimeTypeStringToEnum(mime_type), IntSize(0, 0),
-      callback, start_time, context, nullptr);
+  return new CanvasAsyncBlobCreator(image,
+                                    ConvertMimeTypeStringToEnum(mime_type),
+                                    callback, start_time, context, nullptr);
 }
 
 CanvasAsyncBlobCreator* CanvasAsyncBlobCreator::Create(
@@ -193,21 +167,19 @@
     double start_time,
     ExecutionContext* context,
     ScriptPromiseResolver* resolver) {
-  return new CanvasAsyncBlobCreator(
-      nullptr, image, ConvertMimeTypeStringToEnum(mime_type), IntSize(0, 0),
-      nullptr, start_time, context, resolver);
+  return new CanvasAsyncBlobCreator(image,
+                                    ConvertMimeTypeStringToEnum(mime_type),
+                                    nullptr, start_time, context, resolver);
 }
 
 CanvasAsyncBlobCreator::CanvasAsyncBlobCreator(
-    DOMUint8ClampedArray* data,
     scoped_refptr<StaticBitmapImage> image,
     MimeType mime_type,
-    const IntSize& size,
     V8BlobCallback* callback,
     double start_time,
     ExecutionContext* context,
     ScriptPromiseResolver* resolver)
-    : data_(data),
+    : fail_encoder_initialization_for_test_(false),
       image_(image),
       context_(context),
       mime_type_(mime_type),
@@ -215,23 +187,13 @@
       static_bitmap_image_loaded_(false),
       callback_(callback),
       script_promise_resolver_(resolver) {
-  if (data_) {
-    size_t rowBytes = size.Width() * 4;
-    DCHECK(data_->length() == (unsigned)(size.Height() * rowBytes));
-    SkImageInfo info =
-        SkImageInfo::Make(size.Width(), size.Height(), kRGBA_8888_SkColorType,
-                          kUnpremul_SkAlphaType, nullptr);
-    src_data_.reset(info, data_->Data(), rowBytes);
-  } else {
-    DCHECK(image);
-    sk_sp<SkImage> skia_image =
-        image_->PaintImageForCurrentFrame().GetSkImage();
-    DCHECK(skia_image);
-    if (skia_image->peekPixels(&src_data_))
-      static_bitmap_image_loaded_ = true;
-    else
-      LoadStaticBitmapImage();
-  }
+  DCHECK(image);
+  sk_sp<SkImage> skia_image = image_->PaintImageForCurrentFrame().GetSkImage();
+  DCHECK(skia_image);
+  if (skia_image->peekPixels(&src_data_))
+    static_bitmap_image_loaded_ = true;
+  else
+    LoadStaticBitmapImage();
 
   idle_task_status_ = kIdleTaskNotSupported;
   num_rows_completed_ = 0;
@@ -251,7 +213,6 @@
 void CanvasAsyncBlobCreator::Dispose() {
   // Eagerly let go of references to prevent retention of these
   // resources while any remaining posted tasks are queued.
-  data_.Clear();
   context_.Clear();
   parent_frame_task_runner_.Clear();
   callback_.Clear();
@@ -259,18 +220,12 @@
 }
 
 bool CanvasAsyncBlobCreator::EncodeImage(const double& quality) {
-  if (image_) {
     return ImageDataBuffer(src_data_).EncodeImage("image/webp", quality,
                                                   &encoded_image_);
-  }
-  DCHECK(data_);
-  IntSize size(src_data_.width(), src_data_.height());
-  return ImageDataBuffer(size, data_->Data())
-      .EncodeImage("image/webp", quality, &encoded_image_);
 }
 
 void CanvasAsyncBlobCreator::ScheduleAsyncBlobCreation(const double& quality) {
-  if (image_ && !static_bitmap_image_loaded_) {
+  if (!static_bitmap_image_loaded_) {
     context_->GetTaskRunner(TaskType::kCanvasBlobSerialization)
         ->PostTask(BLINK_FROM_HERE,
                    WTF::Bind(&CanvasAsyncBlobCreator::CreateNullAndReturnResult,
@@ -502,6 +457,9 @@
 }
 
 bool CanvasAsyncBlobCreator::InitializeEncoder(double quality) {
+  // This is solely used for unit tests.
+  if (fail_encoder_initialization_for_test_)
+    return false;
   if (mime_type_ == kMimeTypeJpeg) {
     SkJpegEncoder::Options options;
     options.fQuality = ImageEncoder::ComputeJpegQuality(quality);
@@ -593,7 +551,6 @@
 
 void CanvasAsyncBlobCreator::Trace(blink::Visitor* visitor) {
   visitor->Trace(context_);
-  visitor->Trace(data_);
   visitor->Trace(parent_frame_task_runner_);
   visitor->Trace(script_promise_resolver_);
 }
diff --git a/third_party/WebKit/Source/core/html/canvas/CanvasAsyncBlobCreator.h b/third_party/WebKit/Source/core/html/canvas/CanvasAsyncBlobCreator.h
index 2beeb61..c1f524d 100644
--- a/third_party/WebKit/Source/core/html/canvas/CanvasAsyncBlobCreator.h
+++ b/third_party/WebKit/Source/core/html/canvas/CanvasAsyncBlobCreator.h
@@ -27,20 +27,6 @@
 class CORE_EXPORT CanvasAsyncBlobCreator
     : public GarbageCollectedFinalized<CanvasAsyncBlobCreator> {
  public:
-  static CanvasAsyncBlobCreator* Create(
-      DOMUint8ClampedArray* unpremultiplied_rgba_image_data,
-      const String& mime_type,
-      const IntSize&,
-      V8BlobCallback*,
-      double start_time,
-      ExecutionContext*);
-  static CanvasAsyncBlobCreator* Create(
-      DOMUint8ClampedArray* unpremultiplied_rgba_image_data,
-      const String& mime_type,
-      const IntSize&,
-      double start_time,
-      ExecutionContext*,
-      ScriptPromiseResolver*);
   static CanvasAsyncBlobCreator* Create(scoped_refptr<StaticBitmapImage>,
                                         const String& mime_type,
                                         V8BlobCallback*,
@@ -86,10 +72,8 @@
   virtual void Trace(blink::Visitor*);
 
  protected:
-  CanvasAsyncBlobCreator(DOMUint8ClampedArray* data,
-                         scoped_refptr<StaticBitmapImage>,
+  CanvasAsyncBlobCreator(scoped_refptr<StaticBitmapImage>,
                          MimeType,
-                         const IntSize&,
                          V8BlobCallback*,
                          double,
                          ExecutionContext*,
@@ -105,14 +89,16 @@
   virtual void CreateNullAndReturnResult();
 
   void InitiateEncoding(double quality, double deadline_seconds);
+
+ protected:
   IdleTaskStatus idle_task_status_;
+  bool fail_encoder_initialization_for_test_;
 
  private:
   friend class CanvasAsyncBlobCreatorTest;
 
   void Dispose();
 
-  Member<DOMUint8ClampedArray> data_;
   scoped_refptr<StaticBitmapImage> image_;
   std::unique_ptr<ImageEncoder> encoder_;
   Vector<unsigned char> encoded_image_;
diff --git a/third_party/WebKit/Source/core/html/canvas/CanvasAsyncBlobCreatorTest.cpp b/third_party/WebKit/Source/core/html/canvas/CanvasAsyncBlobCreatorTest.cpp
index 295f1f5..33d3250 100644
--- a/third_party/WebKit/Source/core/html/canvas/CanvasAsyncBlobCreatorTest.cpp
+++ b/third_party/WebKit/Source/core/html/canvas/CanvasAsyncBlobCreatorTest.cpp
@@ -11,6 +11,7 @@
 #include "public/platform/Platform.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/skia/include/core/SkSurface.h"
 
 namespace blink {
 
@@ -18,18 +19,19 @@
 
 class MockCanvasAsyncBlobCreator : public CanvasAsyncBlobCreator {
  public:
-  MockCanvasAsyncBlobCreator(DOMUint8ClampedArray* data,
-                             const IntSize& size,
+  MockCanvasAsyncBlobCreator(scoped_refptr<StaticBitmapImage> image,
                              MimeType mime_type,
-                             Document* document)
-      : CanvasAsyncBlobCreator(data,
-                               nullptr,
+                             Document* document,
+                             bool fail_encoder_initialization = false)
+      : CanvasAsyncBlobCreator(image,
                                mime_type,
-                               size,
                                nullptr,
                                0,
                                document,
-                               nullptr) {}
+                               nullptr) {
+    if (fail_encoder_initialization)
+      fail_encoder_initialization_for_test_ = true;
+  }
 
   CanvasAsyncBlobCreator::IdleTaskStatus GetIdleTaskStatus() {
     return idle_task_status_;
@@ -61,16 +63,13 @@
 }
 
 //==============================================================================
-//=================================PNG==========================================
-//==============================================================================
 
-class MockCanvasAsyncBlobCreatorWithoutStartPng
+class MockCanvasAsyncBlobCreatorWithoutStart
     : public MockCanvasAsyncBlobCreator {
  public:
-  MockCanvasAsyncBlobCreatorWithoutStartPng(DOMUint8ClampedArray* data,
-                                            const IntSize& size,
-                                            Document* document)
-      : MockCanvasAsyncBlobCreator(data, size, kMimeTypePng, document) {}
+  MockCanvasAsyncBlobCreatorWithoutStart(scoped_refptr<StaticBitmapImage> image,
+                                         Document* document)
+      : MockCanvasAsyncBlobCreator(image, kMimeTypePng, document) {}
 
  protected:
   void ScheduleInitiateEncoding(double) override {
@@ -81,65 +80,25 @@
 
 //==============================================================================
 
-class MockCanvasAsyncBlobCreatorWithoutCompletePng
+class MockCanvasAsyncBlobCreatorWithoutComplete
     : public MockCanvasAsyncBlobCreator {
  public:
-  MockCanvasAsyncBlobCreatorWithoutCompletePng(DOMUint8ClampedArray* data,
-                                               const IntSize& size,
-                                               Document* document)
-      : MockCanvasAsyncBlobCreator(data, size, kMimeTypePng, document) {}
+  MockCanvasAsyncBlobCreatorWithoutComplete(
+      scoped_refptr<StaticBitmapImage> image,
+      Document* document,
+      bool fail_encoder_initialization = false)
+      : MockCanvasAsyncBlobCreator(image,
+                                   kMimeTypePng,
+                                   document,
+                                   fail_encoder_initialization) {}
 
  protected:
   void ScheduleInitiateEncoding(double quality) override {
     Platform::Current()->MainThread()->GetWebTaskRunner()->PostTask(
         BLINK_FROM_HERE,
-        WTF::Bind(
-            &MockCanvasAsyncBlobCreatorWithoutCompletePng::InitiateEncoding,
-            WrapPersistent(this), quality, std::numeric_limits<double>::max()));
-  }
-
-  void IdleEncodeRows(double deadline_seconds) override {
-    // Deliberately make idleEncodeRows do nothing so that idle task never
-    // completes
-  }
-};
-
-//==============================================================================
-//=================================JPEG=========================================
-//==============================================================================
-
-class MockCanvasAsyncBlobCreatorWithoutStartJpeg
-    : public MockCanvasAsyncBlobCreator {
- public:
-  MockCanvasAsyncBlobCreatorWithoutStartJpeg(DOMUint8ClampedArray* data,
-                                             const IntSize& size,
-                                             Document* document)
-      : MockCanvasAsyncBlobCreator(data, size, kMimeTypeJpeg, document) {}
-
- protected:
-  void ScheduleInitiateEncoding(double) override {
-    // Deliberately make scheduleInitiateEncoding do nothing so that idle
-    // task never starts
-  }
-};
-
-//==============================================================================
-
-class MockCanvasAsyncBlobCreatorWithoutCompleteJpeg
-    : public MockCanvasAsyncBlobCreator {
- public:
-  MockCanvasAsyncBlobCreatorWithoutCompleteJpeg(DOMUint8ClampedArray* data,
-                                                const IntSize& size,
-                                                Document* document)
-      : MockCanvasAsyncBlobCreator(data, size, kMimeTypeJpeg, document) {}
-
- protected:
-  void ScheduleInitiateEncoding(double quality) override {
-    Platform::Current()->MainThread()->GetWebTaskRunner()->PostTask(
-        BLINK_FROM_HERE,
-        WTF::Bind(
-            &MockCanvasAsyncBlobCreatorWithoutCompleteJpeg::InitiateEncoding,
-            WrapPersistent(this), quality, std::numeric_limits<double>::max()));
+        WTF::Bind(&MockCanvasAsyncBlobCreatorWithoutComplete::InitiateEncoding,
+                  WrapPersistent(this), quality,
+                  std::numeric_limits<double>::max()));
   }
 
   void IdleEncodeRows(double deadline_seconds) override {
@@ -152,15 +111,9 @@
 
 class CanvasAsyncBlobCreatorTest : public PageTestBase {
  public:
-  // Png unit tests
-  void PrepareMockCanvasAsyncBlobCreatorWithoutStartPng();
-  void PrepareMockCanvasAsyncBlobCreatorWithoutCompletePng();
-  void PrepareMockCanvasAsyncBlobCreatorFailPng();
-
-  // Jpeg unit tests
-  void PrepareMockCanvasAsyncBlobCreatorWithoutStartJpeg();
-  void PrepareMockCanvasAsyncBlobCreatorWithoutCompleteJpeg();
-  void PrepareMockCanvasAsyncBlobCreatorFailJpeg();
+  void PrepareMockCanvasAsyncBlobCreatorWithoutStart();
+  void PrepareMockCanvasAsyncBlobCreatorWithoutComplete();
+  void PrepareMockCanvasAsyncBlobCreatorFail();
 
  protected:
   CanvasAsyncBlobCreatorTest();
@@ -177,62 +130,31 @@
 CanvasAsyncBlobCreatorTest::CanvasAsyncBlobCreatorTest() {
 }
 
-void CanvasAsyncBlobCreatorTest::
-    PrepareMockCanvasAsyncBlobCreatorWithoutStartPng() {
-  IntSize test_size(20, 20);
-  ImageData* image_data = ImageData::Create(test_size);
-
-  async_blob_creator_ = new MockCanvasAsyncBlobCreatorWithoutStartPng(
-      image_data->data(), test_size, &GetDocument());
+scoped_refptr<StaticBitmapImage> CreateTransparentImage(int width, int height) {
+  sk_sp<SkSurface> surface = SkSurface::MakeRasterN32Premul(width, height);
+  if (!surface)
+    return nullptr;
+  return StaticBitmapImage::Create(surface->makeImageSnapshot());
 }
 
 void CanvasAsyncBlobCreatorTest::
-    PrepareMockCanvasAsyncBlobCreatorWithoutCompletePng() {
-  IntSize test_size(20, 20);
-  ImageData* image_data = ImageData::Create(test_size);
-
-  async_blob_creator_ = new MockCanvasAsyncBlobCreatorWithoutCompletePng(
-      image_data->data(), test_size, &GetDocument());
+    PrepareMockCanvasAsyncBlobCreatorWithoutStart() {
+  async_blob_creator_ = new MockCanvasAsyncBlobCreatorWithoutStart(
+      CreateTransparentImage(20, 20), &GetDocument());
 }
 
-void CanvasAsyncBlobCreatorTest::PrepareMockCanvasAsyncBlobCreatorFailPng() {
-  IntSize test_size(0, 0);
-  ImageData* image_data = ImageData::CreateForTest(test_size);
+void CanvasAsyncBlobCreatorTest::
+    PrepareMockCanvasAsyncBlobCreatorWithoutComplete() {
+  async_blob_creator_ = new MockCanvasAsyncBlobCreatorWithoutComplete(
+      CreateTransparentImage(20, 20), &GetDocument());
+}
 
-  // We reuse the class MockCanvasAsyncBlobCreatorWithoutCompletePng because
+void CanvasAsyncBlobCreatorTest::PrepareMockCanvasAsyncBlobCreatorFail() {
+  // We reuse the class MockCanvasAsyncBlobCreatorWithoutComplete because
   // this test case is expected to fail at initialization step before
   // completion.
-  async_blob_creator_ = new MockCanvasAsyncBlobCreatorWithoutCompletePng(
-      image_data->data(), test_size, &GetDocument());
-}
-
-void CanvasAsyncBlobCreatorTest::
-    PrepareMockCanvasAsyncBlobCreatorWithoutStartJpeg() {
-  IntSize test_size(20, 20);
-  ImageData* image_data = ImageData::Create(test_size);
-
-  async_blob_creator_ = new MockCanvasAsyncBlobCreatorWithoutStartJpeg(
-      image_data->data(), test_size, &GetDocument());
-}
-
-void CanvasAsyncBlobCreatorTest::
-    PrepareMockCanvasAsyncBlobCreatorWithoutCompleteJpeg() {
-  IntSize test_size(20, 20);
-  ImageData* image_data = ImageData::Create(test_size);
-
-  async_blob_creator_ = new MockCanvasAsyncBlobCreatorWithoutCompleteJpeg(
-      image_data->data(), test_size, &GetDocument());
-}
-
-void CanvasAsyncBlobCreatorTest::PrepareMockCanvasAsyncBlobCreatorFailJpeg() {
-  IntSize test_size(0, 0);
-  ImageData* image_data = ImageData::CreateForTest(test_size);
-
-  // We reuse the class MockCanvasAsyncBlobCreatorWithoutCompleteJpeg because
-  // this test case is expected to fail at initialization step before
-  // completion.
-  async_blob_creator_ = new MockCanvasAsyncBlobCreatorWithoutCompleteJpeg(
-      image_data->data(), test_size, &GetDocument());
+  async_blob_creator_ = new MockCanvasAsyncBlobCreatorWithoutComplete(
+      CreateTransparentImage(20, 20), &GetDocument(), true);
 }
 
 void CanvasAsyncBlobCreatorTest::TearDown() {
@@ -242,12 +164,12 @@
 //==============================================================================
 
 TEST_F(CanvasAsyncBlobCreatorTest,
-       PngIdleTaskNotStartedWhenStartTimeoutEventHappens) {
+       IdleTaskNotStartedWhenStartTimeoutEventHappens) {
   // This test mocks the scenario when idle task is not started when the
   // StartTimeoutEvent is inspecting the idle task status.
   // The whole image encoding process (including initialization)  will then
   // become carried out in the alternative code path instead.
-  PrepareMockCanvasAsyncBlobCreatorWithoutStartPng();
+  PrepareMockCanvasAsyncBlobCreatorWithoutStart();
   EXPECT_CALL(*(AsyncBlobCreator()),
               SignalTaskSwitchInStartTimeoutEventForTesting());
 
@@ -260,12 +182,12 @@
 }
 
 TEST_F(CanvasAsyncBlobCreatorTest,
-       PngIdleTaskNotCompletedWhenCompleteTimeoutEventHappens) {
+       IdleTaskNotCompletedWhenCompleteTimeoutEventHappens) {
   // This test mocks the scenario when idle task is not completed when the
   // CompleteTimeoutEvent is inspecting the idle task status.
   // The remaining image encoding process (excluding initialization)  will
   // then become carried out in the alternative code path instead.
-  PrepareMockCanvasAsyncBlobCreatorWithoutCompletePng();
+  PrepareMockCanvasAsyncBlobCreatorWithoutComplete();
   EXPECT_CALL(*(AsyncBlobCreator()),
               SignalTaskSwitchInCompleteTimeoutEventForTesting());
 
@@ -277,12 +199,11 @@
             AsyncBlobCreator()->GetIdleTaskStatus());
 }
 
-TEST_F(CanvasAsyncBlobCreatorTest,
-       PngIdleTaskFailedWhenStartTimeoutEventHappens) {
+TEST_F(CanvasAsyncBlobCreatorTest, IdleTaskFailedWhenStartTimeoutEventHappens) {
   // This test mocks the scenario when idle task is not failed during when
   // either the StartTimeoutEvent or the CompleteTimeoutEvent is inspecting
   // the idle task status.
-  PrepareMockCanvasAsyncBlobCreatorFailPng();
+  PrepareMockCanvasAsyncBlobCreatorFail();
 
   AsyncBlobCreator()->ScheduleAsyncBlobCreation(true);
   testing::EnterRunLoop();
@@ -291,44 +212,4 @@
             AsyncBlobCreator()->GetIdleTaskStatus());
 }
 
-// The below 3 unit tests have exactly same workflow as the above 3 unit tests
-// except that they are encoding on JPEG image formats instead of PNG.
-TEST_F(CanvasAsyncBlobCreatorTest,
-       JpegIdleTaskNotStartedWhenStartTimeoutEventHappens) {
-  PrepareMockCanvasAsyncBlobCreatorWithoutStartJpeg();
-  EXPECT_CALL(*(AsyncBlobCreator()),
-              SignalTaskSwitchInStartTimeoutEventForTesting());
-
-  AsyncBlobCreator()->ScheduleAsyncBlobCreation(1.0);
-  testing::EnterRunLoop();
-
-  ::testing::Mock::VerifyAndClearExpectations(AsyncBlobCreator());
-  EXPECT_EQ(IdleTaskStatus::kIdleTaskSwitchedToImmediateTask,
-            AsyncBlobCreator()->GetIdleTaskStatus());
-}
-
-TEST_F(CanvasAsyncBlobCreatorTest,
-       JpegIdleTaskNotCompletedWhenCompleteTimeoutEventHappens) {
-  PrepareMockCanvasAsyncBlobCreatorWithoutCompleteJpeg();
-  EXPECT_CALL(*(AsyncBlobCreator()),
-              SignalTaskSwitchInCompleteTimeoutEventForTesting());
-
-  AsyncBlobCreator()->ScheduleAsyncBlobCreation(1.0);
-  testing::EnterRunLoop();
-
-  ::testing::Mock::VerifyAndClearExpectations(AsyncBlobCreator());
-  EXPECT_EQ(IdleTaskStatus::kIdleTaskSwitchedToImmediateTask,
-            AsyncBlobCreator()->GetIdleTaskStatus());
-}
-
-TEST_F(CanvasAsyncBlobCreatorTest,
-       JpegIdleTaskFailedWhenStartTimeoutEventHappens) {
-  PrepareMockCanvasAsyncBlobCreatorFailJpeg();
-
-  AsyncBlobCreator()->ScheduleAsyncBlobCreation(1.0);
-  testing::EnterRunLoop();
-
-  EXPECT_EQ(IdleTaskStatus::kIdleTaskFailed,
-            AsyncBlobCreator()->GetIdleTaskStatus());
-}
 }
diff --git a/third_party/WebKit/Source/core/html/canvas/CanvasRenderingContext.h b/third_party/WebKit/Source/core/html/canvas/CanvasRenderingContext.h
index 9c4f70f..7bb775c 100644
--- a/third_party/WebKit/Source/core/html/canvas/CanvasRenderingContext.h
+++ b/third_party/WebKit/Source/core/html/canvas/CanvasRenderingContext.h
@@ -44,7 +44,6 @@
 
 class CanvasImageSource;
 class HTMLCanvasElement;
-class ImageData;
 class ImageBitmap;
 class WebLayer;
 
@@ -92,7 +91,6 @@
 
   virtual scoped_refptr<StaticBitmapImage> GetImage(AccelerationHint,
                                                     SnapshotReason) const = 0;
-  virtual ImageData* ToImageData(SnapshotReason reason) { return nullptr; }
   virtual ContextType GetContextType() const = 0;
   virtual bool IsComposited() const = 0;
   virtual bool IsAccelerated() const = 0;
@@ -164,7 +162,8 @@
   virtual void SetFilterQuality(SkFilterQuality) { NOTREACHED(); }
   virtual void Reshape(int width, int height) { NOTREACHED(); }
   virtual void MarkLayerComposited() { NOTREACHED(); }
-  virtual ImageData* PaintRenderingResultsToImageData(SourceDrawingBuffer) {
+  virtual scoped_refptr<Uint8Array> PaintRenderingResultsToDataArray(
+      SourceDrawingBuffer) {
     NOTREACHED();
     return nullptr;
   }
diff --git a/third_party/WebKit/Source/core/html/imports/HTMLImportLoader.cpp b/third_party/WebKit/Source/core/html/imports/HTMLImportLoader.cpp
index 917e4b5..71168f0 100644
--- a/third_party/WebKit/Source/core/html/imports/HTMLImportLoader.cpp
+++ b/third_party/WebKit/Source/core/html/imports/HTMLImportLoader.cpp
@@ -210,7 +210,7 @@
   visitor->Trace(document_);
   visitor->Trace(microtask_queue_);
   DocumentParserClient::Trace(visitor);
-  ResourceOwner<RawResource>::Trace(visitor);
+  RawResourceClient::Trace(visitor);
 }
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/html/imports/HTMLImportLoader.h b/third_party/WebKit/Source/core/html/imports/HTMLImportLoader.h
index bdf6e76..97a3d7de 100644
--- a/third_party/WebKit/Source/core/html/imports/HTMLImportLoader.h
+++ b/third_party/WebKit/Source/core/html/imports/HTMLImportLoader.h
@@ -35,7 +35,6 @@
 #include "core/dom/DocumentParserClient.h"
 #include "platform/heap/Handle.h"
 #include "platform/loader/fetch/RawResource.h"
-#include "platform/loader/fetch/ResourceOwner.h"
 #include "platform/wtf/Vector.h"
 
 namespace blink {
@@ -45,12 +44,12 @@
 class HTMLImportChild;
 class HTMLImportsController;
 
-// Owning imported Document lifetime. It also implements ResourceClient through
-// ResourceOwner to feed fetched bytes to the DocumentParser of the imported
+// Owning imported Document lifetime. It also implements RawResourceClient
+// to feed fetched bytes to the DocumentParser of the imported
 // document.  HTMLImportLoader is owned by HTMLImportsController.
 class HTMLImportLoader final
     : public GarbageCollectedFinalized<HTMLImportLoader>,
-      public ResourceOwner<RawResource>,
+      public RawResourceClient,
       public DocumentParserClient {
   USING_GARBAGE_COLLECTED_MIXIN(HTMLImportLoader);
 
diff --git a/third_party/WebKit/Source/core/html/media/HTMLMediaElement.cpp b/third_party/WebKit/Source/core/html/media/HTMLMediaElement.cpp
index 5ef31ff7..c560262 100644
--- a/third_party/WebKit/Source/core/html/media/HTMLMediaElement.cpp
+++ b/third_party/WebKit/Source/core/html/media/HTMLMediaElement.cpp
@@ -1014,9 +1014,19 @@
     // has neither a src attribute nor a source element child: set the
     // networkState to kNetworkEmpty, and abort these steps; the synchronous
     // section ends.
+    // TODO(mlamouri): Setting the network state to empty implies that there
+    // should be no |web_media_player_|. However, if a previous playback ended
+    // due to an error, we can get here and still have one. Decide on a plan
+    // to deal with this properly. https://crbug.com/789737
     load_state_ = kWaitingForSource;
     SetShouldDelayLoadEvent(false);
-    SetNetworkState(kNetworkEmpty);
+    if (!GetWebMediaPlayer() || (ready_state_ < kHaveFutureData &&
+                                 ready_state_maximum_ < kHaveFutureData)) {
+      SetNetworkState(kNetworkEmpty);
+    } else {
+      UseCounter::Count(GetDocument(),
+                        WebFeature::kHTMLMediaElementEmptyLoadWithFutureData);
+    }
     UpdateDisplayState();
 
     BLINK_MEDIA_LOG << "selectMediaResource(" << (void*)this
diff --git a/third_party/WebKit/Source/core/html/parser/CSSPreloadScanner.cpp b/third_party/WebKit/Source/core/html/parser/CSSPreloadScanner.cpp
index 447e3da..90e16322 100644
--- a/third_party/WebKit/Source/core/html/parser/CSSPreloadScanner.cpp
+++ b/third_party/WebKit/Source/core/html/parser/CSSPreloadScanner.cpp
@@ -264,15 +264,14 @@
                       ->GetCSSExternalScannerPreload()
                   ? kScanAndPreload
                   : kScanOnly),
-      preloader_(preloader),
-      resource_(ToCSSStyleSheetResource(resource)) {
-  resource_->AddClient(this);
+      preloader_(preloader) {
+  SetResource(resource);
 }
 
 CSSPreloaderResourceClient::~CSSPreloaderResourceClient() {}
 
 void CSSPreloaderResourceClient::NotifyFinished(Resource*) {
-  ClearResource();
+  MaybeClearResource();
 }
 
 // Only attach for one appendData call, as that's where most imports will likely
@@ -285,7 +284,7 @@
   received_first_data_ = true;
   if (preloader_)
     ScanCSS(ToCSSStyleSheetResource(resource));
-  ClearResource();
+  MaybeClearResource();
 }
 
 void CSSPreloaderResourceClient::ScanCSS(
@@ -344,7 +343,7 @@
   }
 }
 
-void CSSPreloaderResourceClient::ClearResource() {
+void CSSPreloaderResourceClient::MaybeClearResource() {
   // Do not remove the client for unused, speculative markup preloads. This will
   // trigger cancellation of the request and potential removal from memory
   // cache. Link preloads are an exception because they support dynamic removal
@@ -352,19 +351,16 @@
   // Note: Speculative preloads which remain unused for their lifetime will
   // never have this client removed. This should be fine because we only hold
   // weak references to the resource.
-  if (resource_ && resource_->IsUnusedPreload() &&
-      !resource_->IsLinkPreload()) {
+  if (GetResource() && GetResource()->IsUnusedPreload() &&
+      !GetResource()->IsLinkPreload()) {
     return;
   }
 
-  if (resource_)
-    resource_->RemoveClient(this);
-  resource_.Clear();
+  ClearResource();
 }
 
 void CSSPreloaderResourceClient::Trace(blink::Visitor* visitor) {
   visitor->Trace(preloader_);
-  visitor->Trace(resource_);
   ResourceClient::Trace(visitor);
 }
 
diff --git a/third_party/WebKit/Source/core/html/parser/CSSPreloadScanner.h b/third_party/WebKit/Source/core/html/parser/CSSPreloadScanner.h
index 7dd101e..4e0d0bd5 100644
--- a/third_party/WebKit/Source/core/html/parser/CSSPreloadScanner.h
+++ b/third_party/WebKit/Source/core/html/parser/CSSPreloadScanner.h
@@ -33,7 +33,6 @@
 #include "core/loader/resource/CSSStyleSheetResource.h"
 #include "platform/heap/Handle.h"
 #include "platform/loader/fetch/ResourceClient.h"
-#include "platform/loader/fetch/ResourceOwner.h"
 #include "platform/wtf/text/StringBuilder.h"
 
 namespace blink {
@@ -122,7 +121,7 @@
 
  private:
   void ScanCSS(const CSSStyleSheetResource*);
-  void ClearResource();
+  void MaybeClearResource();
 
   enum PreloadPolicy {
     kScanOnly,
@@ -131,7 +130,6 @@
 
   const PreloadPolicy policy_;
   WeakMember<HTMLResourcePreloader> preloader_;
-  WeakMember<CSSStyleSheetResource> resource_;
   bool received_first_data_ = false;
 };
 
diff --git a/third_party/WebKit/Source/core/imagebitmap/ImageBitmap.cpp b/third_party/WebKit/Source/core/imagebitmap/ImageBitmap.cpp
index 577e999c..623e3f2 100644
--- a/third_party/WebKit/Source/core/imagebitmap/ImageBitmap.cpp
+++ b/third_party/WebKit/Source/core/imagebitmap/ImageBitmap.cpp
@@ -206,25 +206,6 @@
   return CopyImageData(std::move(input), info);
 }
 
-void freePixels(const void*, void* pixels) {
-  static_cast<Uint8Array*>(pixels)->Release();
-}
-
-scoped_refptr<StaticBitmapImage> NewImageFromRaster(
-    const SkImageInfo& info,
-    scoped_refptr<Uint8Array>&& image_pixels) {
-  SkPixmap pixmap(info, image_pixels->Data(), info.minRowBytes());
-
-  Uint8Array* pixels = image_pixels.get();
-  if (pixels) {
-    pixels->AddRef();
-    image_pixels = nullptr;
-  }
-
-  return StaticBitmapImage::Create(
-      SkImage::MakeFromRaster(pixmap, freePixels, pixels));
-}
-
 static inline bool ShouldAvoidPremul(
     const ImageBitmap::ParsedOptions& options) {
   return options.source_is_unpremul && !options.premultiply_alpha;
@@ -252,7 +233,7 @@
                        image_pixels->Data() + top_last_element,
                        image_pixels->Data() + bottom_first_element);
     }
-    return NewImageFromRaster(info, std::move(image_pixels));
+    return StaticBitmapImage::Create(std::move(image_pixels), info);
   }
 
   // Since we are allowed to premul the input image if needed, we can use Skia
@@ -297,7 +278,7 @@
         CopyImageData(image, info.makeColorSpace(nullptr));
     if (!dst_pixels)
       return nullptr;
-    return NewImageFromRaster(info, std::move(dst_pixels));
+    return StaticBitmapImage::Create(std::move(dst_pixels), info);
   }
 
   // Draw on a surface. Avoid sRGB gamma transfer curve.
@@ -313,6 +294,10 @@
                                    image->ContextProviderWrapper());
 }
 
+void freePixels(const void*, void* pixels) {
+  static_cast<Uint8Array*>(pixels)->Release();
+}
+
 // Resizes an SkImage using scalePixels(). This code path should not be used if
 // source image is not premul and premul is not allowed and the requested filter
 // quality is high.
@@ -777,7 +762,7 @@
       parsed_options.premultiply_alpha ? kPremul_SkAlphaType
                                        : kUnpremul_SkAlphaType,
       parsed_options.color_params.GetSkColorSpaceForSkSurfaces());
-  image_ = NewImageFromRaster(info, std::move(image_pixels));
+  image_ = StaticBitmapImage::Create(std::move(image_pixels), info);
   if (!image_)
     return;
 
diff --git a/third_party/WebKit/Source/core/inspector/InspectorLayerTreeAgent.cpp b/third_party/WebKit/Source/core/inspector/InspectorLayerTreeAgent.cpp
index face7cc..7286ec0f 100644
--- a/third_party/WebKit/Source/core/inspector/InspectorLayerTreeAgent.cpp
+++ b/third_party/WebKit/Source/core/inspector/InspectorLayerTreeAgent.cpp
@@ -415,15 +415,8 @@
     return response;
   CompositingReasons reasons_bitmask = graphics_layer->GetCompositingReasons();
   *reason_strings = Array<String>::create();
-  for (size_t i = 0; i < kNumberOfCompositingReasons; ++i) {
-    if (!(reasons_bitmask & kCompositingReasonStringMap[i].reason))
-      continue;
-    (*reason_strings)->addItem(kCompositingReasonStringMap[i].short_name);
-#ifndef _NDEBUG
-    reasons_bitmask &= ~kCompositingReasonStringMap[i].reason;
-#endif
-  }
-  DCHECK(!reasons_bitmask);
+  for (const char* name : CompositingReason::ShortNames(reasons_bitmask))
+    (*reason_strings)->addItem(name);
   return Response::OK();
 }
 
diff --git a/third_party/WebKit/Source/core/inspector/InspectorResourceContentLoader.cpp b/third_party/WebKit/Source/core/inspector/InspectorResourceContentLoader.cpp
index 14cc6ec..795f87f 100644
--- a/third_party/WebKit/Source/core/inspector/InspectorResourceContentLoader.cpp
+++ b/third_party/WebKit/Source/core/inspector/InspectorResourceContentLoader.cpp
@@ -37,7 +37,7 @@
   explicit ResourceClient(InspectorResourceContentLoader* loader)
       : loader_(loader) {}
 
-  void WaitForResource(Resource* resource) { resource->AddClient(this); }
+  void WaitForResource(Resource* resource) { SetResource(resource); }
 
   void Trace(blink::Visitor* visitor) override {
     visitor->Trace(loader_);
@@ -50,7 +50,7 @@
   void NotifyFinished(Resource* resource) override {
     if (loader_)
       loader_->ResourceFinished(this);
-    resource->RemoveClient(this);
+    ClearResource();
   }
 
   String DebugName() const override {
diff --git a/third_party/WebKit/Source/core/intersection_observer/IntersectionObserver.cpp b/third_party/WebKit/Source/core/intersection_observer/IntersectionObserver.cpp
index 06ef996..68fdbd8 100644
--- a/third_party/WebKit/Source/core/intersection_observer/IntersectionObserver.cpp
+++ b/third_party/WebKit/Source/core/intersection_observer/IntersectionObserver.cpp
@@ -5,6 +5,7 @@
 #include "core/intersection_observer/IntersectionObserver.h"
 
 #include <algorithm>
+#include "base/macros.h"
 #include "bindings/core/v8/ExceptionState.h"
 #include "bindings/core/v8/V8IntersectionObserverDelegate.h"
 #include "bindings/core/v8/v8_intersection_observer_callback.h"
@@ -35,7 +36,6 @@
 // IntersectionObserver with an EventCallback.
 class IntersectionObserverDelegateImpl final
     : public IntersectionObserverDelegate {
-  WTF_MAKE_NONCOPYABLE(IntersectionObserverDelegateImpl);
 
  public:
   IntersectionObserverDelegateImpl(ExecutionContext* context,
@@ -57,6 +57,7 @@
  private:
   WeakMember<ExecutionContext> context_;
   IntersectionObserver::EventCallback callback_;
+  DISALLOW_COPY_AND_ASSIGN(IntersectionObserverDelegateImpl);
 };
 
 void ParseRootMargin(String root_margin_parameter,
diff --git a/third_party/WebKit/Source/core/layout/LayoutEmbeddedContent.cpp b/third_party/WebKit/Source/core/layout/LayoutEmbeddedContent.cpp
index 025dcc28..e288550 100644
--- a/third_party/WebKit/Source/core/layout/LayoutEmbeddedContent.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutEmbeddedContent.cpp
@@ -247,8 +247,8 @@
 
 CompositingReasons LayoutEmbeddedContent::AdditionalCompositingReasons() const {
   if (RequiresAcceleratedCompositing())
-    return kCompositingReasonIFrame;
-  return kCompositingReasonNone;
+    return CompositingReason::kIFrame;
+  return CompositingReason::kNone;
 }
 
 void LayoutEmbeddedContent::StyleDidChange(StyleDifference diff,
diff --git a/third_party/WebKit/Source/core/layout/LayoutEmbeddedObject.cpp b/third_party/WebKit/Source/core/layout/LayoutEmbeddedObject.cpp
index 757bd7e..5977e8d 100644
--- a/third_party/WebKit/Source/core/layout/LayoutEmbeddedObject.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutEmbeddedObject.cpp
@@ -149,8 +149,8 @@
 
 CompositingReasons LayoutEmbeddedObject::AdditionalCompositingReasons() const {
   if (RequiresAcceleratedCompositing())
-    return kCompositingReasonPlugin;
-  return kCompositingReasonNone;
+    return CompositingReason::kPlugin;
+  return CompositingReason::kNone;
 }
 
 LayoutReplaced* LayoutEmbeddedObject::EmbeddedReplacedContent() const {
diff --git a/third_party/WebKit/Source/core/layout/LayoutHTMLCanvas.cpp b/third_party/WebKit/Source/core/layout/LayoutHTMLCanvas.cpp
index ee6587e..5f0a2d3 100644
--- a/third_party/WebKit/Source/core/layout/LayoutHTMLCanvas.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutHTMLCanvas.cpp
@@ -90,8 +90,8 @@
 
 CompositingReasons LayoutHTMLCanvas::AdditionalCompositingReasons() const {
   if (ToHTMLCanvasElement(GetNode())->ShouldBeDirectComposited())
-    return kCompositingReasonCanvas;
-  return kCompositingReasonNone;
+    return CompositingReason::kCanvas;
+  return CompositingReason::kNone;
 }
 
 void LayoutHTMLCanvas::StyleDidChange(StyleDifference diff,
diff --git a/third_party/WebKit/Source/core/layout/LayoutObject.cpp b/third_party/WebKit/Source/core/layout/LayoutObject.cpp
index ce15b7b..e07159d8 100644
--- a/third_party/WebKit/Source/core/layout/LayoutObject.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutObject.cpp
@@ -2966,7 +2966,7 @@
 }
 
 CompositingReasons LayoutObject::AdditionalCompositingReasons() const {
-  return kCompositingReasonNone;
+  return CompositingReason::kNone;
 }
 
 bool LayoutObject::HitTest(HitTestResult& result,
diff --git a/third_party/WebKit/Source/core/layout/LayoutVideo.cpp b/third_party/WebKit/Source/core/layout/LayoutVideo.cpp
index 34473ab..69a25bc1 100644
--- a/third_party/WebKit/Source/core/layout/LayoutVideo.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutVideo.cpp
@@ -237,12 +237,12 @@
 CompositingReasons LayoutVideo::AdditionalCompositingReasons() const {
   HTMLMediaElement* element = ToHTMLMediaElement(GetNode());
   if (element->IsFullscreen() && element->UsesOverlayFullscreenVideo())
-    return kCompositingReasonVideo;
+    return CompositingReason::kVideo;
 
   if (ShouldDisplayVideo() && SupportsAcceleratedRendering())
-    return kCompositingReasonVideo;
+    return CompositingReason::kVideo;
 
-  return kCompositingReasonNone;
+  return CompositingReason::kNone;
 }
 
 }  // namespace blink
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 48c7c3e..313c4643 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
@@ -118,35 +118,118 @@
   if (Style().ContainsSize())
     return sizes;
 
-  // TODO: handle floats & orthogonal children.
-  for (NGLayoutInputNode node = Node().FirstChild(); node;
-       node = node.NextSibling()) {
-    if (node.IsOutOfFlowPositioned())
+  const TextDirection direction = Style().Direction();
+  LayoutUnit float_left_inline_size;
+  LayoutUnit float_right_inline_size;
+
+  for (NGLayoutInputNode child = Node().FirstChild(); child;
+       child = child.NextSibling()) {
+    if (child.IsOutOfFlowPositioned() || child.IsColumnSpanAll())
       continue;
+
+    const ComputedStyle& child_style = child.Style();
+    const EClear child_clear = child_style.Clear();
+
+    // Conceptually floats and a single new-FC would just get positioned on a
+    // single "line". If there is a float/new-FC with clearance, this creates a
+    // new "line", resetting the appropriate float size trackers.
+    //
+    // Both of the float size trackers get reset for anything that isn't a float
+    // (inflow and new-FC) at the end of the loop, as this creates a new "line".
+    if (child.IsFloating() || child.CreatesNewFormattingContext()) {
+      LayoutUnit float_inline_size =
+          float_left_inline_size + float_right_inline_size;
+
+      if (child_clear != EClear::kNone)
+        sizes.max_size = std::max(sizes.max_size, float_inline_size);
+
+      if (child_clear == EClear::kBoth || child_clear == EClear::kLeft)
+        float_left_inline_size = LayoutUnit();
+
+      if (child_clear == EClear::kBoth || child_clear == EClear::kRight)
+        float_right_inline_size = LayoutUnit();
+    }
+
     MinMaxSize child_sizes;
-    if (node.IsInline()) {
+    if (child.IsInline()) {
       // From |NGBlockLayoutAlgorithm| perspective, we can handle |NGInlineNode|
       // almost the same as |NGBlockNode|, because an |NGInlineNode| includes
-      // all inline nodes following |node| and their descendants, and produces
+      // all inline nodes following |child| and their descendants, and produces
       // an anonymous box that contains all line boxes.
       // |NextSibling| returns the next block sibling, or nullptr, skipping all
       // following inline siblings and descendants.
-      child_sizes = node.ComputeMinMaxSize();
+      child_sizes = child.ComputeMinMaxSize();
     } else {
       Optional<MinMaxSize> child_minmax;
-      if (NeedMinMaxSizeForContentContribution(node.Style())) {
-        child_minmax = node.ComputeMinMaxSize();
+      if (NeedMinMaxSizeForContentContribution(child_style)) {
+        child_minmax = child.ComputeMinMaxSize();
       }
 
       child_sizes =
-          ComputeMinAndMaxContentContribution(node.Style(), child_minmax);
+          ComputeMinAndMaxContentContribution(child_style, child_minmax);
     }
 
-    sizes.min_size = std::max(sizes.min_size, child_sizes.min_size);
-    sizes.max_size = std::max(sizes.max_size, child_sizes.max_size);
+    // Determine the max inline contribution of the child.
+    NGBoxStrut margins = ComputeMinMaxMargins(Style(), child);
+    LayoutUnit max_inline_contribution;
+
+    if (child.IsFloating()) {
+      // A float adds to its inline size to the current "line". The new max
+      // inline contribution is just the sum of all the floats on that "line".
+      LayoutUnit float_inline_size = child_sizes.max_size + margins.InlineSum();
+      if (child_style.Floating() == EFloat::kLeft)
+        float_left_inline_size += float_inline_size;
+      else
+        float_right_inline_size += float_inline_size;
+
+      max_inline_contribution =
+          float_left_inline_size + float_right_inline_size;
+    } else if (child.CreatesNewFormattingContext()) {
+      // As floats are line relative, we perform the margin calculations in the
+      // line relative coordinate system as well.
+      LayoutUnit margin_line_left = margins.LineLeft(direction);
+      LayoutUnit margin_line_right = margins.LineRight(direction);
+
+      // line_left_inset and line_right_inset are the "distance" from their
+      // respective edges of the parent that the new-FC would take. If the
+      // margin is positive the inset is just whichever of the floats inline
+      // size and margin is larger, and if negative it just subtracts from the
+      // float inline size.
+      LayoutUnit line_left_inset =
+          margin_line_left > LayoutUnit()
+              ? std::max(float_left_inline_size, margin_line_left)
+              : float_left_inline_size + margin_line_left;
+
+      LayoutUnit line_right_inset =
+          margin_line_right > LayoutUnit()
+              ? std::max(float_right_inline_size, margin_line_right)
+              : float_right_inline_size + margin_line_right;
+
+      max_inline_contribution =
+          child_sizes.max_size + line_left_inset + line_right_inset;
+    } else {
+      // This is just a standard inflow child.
+      max_inline_contribution = child_sizes.max_size + margins.InlineSum();
+    }
+    sizes.max_size = std::max(sizes.max_size, max_inline_contribution);
+
+    // The min inline contribution just assumes that floats are all on their own
+    // "line".
+    LayoutUnit min_inline_contribution =
+        child_sizes.min_size + margins.InlineSum();
+    sizes.min_size = std::max(sizes.min_size, min_inline_contribution);
+
+    // Anything that isn't a float will create a new "line" resetting the float
+    // size trackers.
+    if (!child.IsFloating()) {
+      float_left_inline_size = LayoutUnit();
+      float_right_inline_size = LayoutUnit();
+    }
   }
 
-  sizes.max_size = std::max(sizes.min_size, sizes.max_size);
+  DCHECK_GE(sizes.min_size, LayoutUnit());
+  DCHECK_GE(sizes.max_size, sizes.min_size);
+
   return sizes;
 }
 
diff --git a/third_party/WebKit/Source/core/layout/ng/ng_block_layout_algorithm_test.cc b/third_party/WebKit/Source/core/layout/ng/ng_block_layout_algorithm_test.cc
index cf11f52..b2db96e4 100644
--- a/third_party/WebKit/Source/core/layout/ng/ng_block_layout_algorithm_test.cc
+++ b/third_party/WebKit/Source/core/layout/ng/ng_block_layout_algorithm_test.cc
@@ -506,13 +506,10 @@
   EXPECT_THAT(body_fragment->Offset().top, LayoutUnit(body_top_offset));
   int body_left_offset = 8;
   EXPECT_THAT(body_fragment->Offset().left, LayoutUnit(body_left_offset));
+
   // height = 70. std::max(vertical height's 70, horizontal's height's 60)
-  // TODO(glebl): Should be 70! Fix this once min/max algorithm handles
-  // orthogonal children.
-  int body_fragment_block_size = 130;
-  ASSERT_EQ(
-      NGPhysicalSize(LayoutUnit(784), LayoutUnit(body_fragment_block_size)),
-      body_fragment->Size());
+  ASSERT_EQ(NGPhysicalSize(LayoutUnit(784), LayoutUnit(70)),
+            body_fragment->Size());
   ASSERT_EQ(1UL, body_fragment->Children().size());
 
   // container
@@ -1358,7 +1355,7 @@
 // Verifies that we compute the right min and max-content size.
 TEST_F(NGBlockLayoutAlgorithmTest, ComputeMinMaxContent) {
   SetBodyInnerHTML(R"HTML(
-    <div id="container" style="width: 50px">
+    <div id="container">
       <div id="first-child" style="width: 20px"></div>
       <div id="second-child" style="width: 30px"></div>
     </div>
@@ -1373,6 +1370,109 @@
   EXPECT_EQ(kSecondChildWidth, sizes.max_size);
 }
 
+TEST_F(NGBlockLayoutAlgorithmTest, ComputeMinMaxContentFloats) {
+  SetBodyInnerHTML(R"HTML(
+    <style>
+      #f1 { float: left; width: 20px; }
+      #f2 { float: left; width: 30px; }
+      #f3 { float: right; width: 40px; }
+    </style>
+    <div id="container">
+      <div id="f1"></div>
+      <div id="f2"></div>
+      <div id="f3"></div>
+    </div>
+  )HTML");
+
+  NGBlockNode container(ToLayoutBox(GetLayoutObjectByElementId("container")));
+
+  MinMaxSize sizes = RunComputeMinAndMax(container);
+  EXPECT_EQ(LayoutUnit(40), sizes.min_size);
+  EXPECT_EQ(LayoutUnit(90), sizes.max_size);
+}
+
+TEST_F(NGBlockLayoutAlgorithmTest, ComputeMinMaxContentFloatsClearance) {
+  SetBodyInnerHTML(R"HTML(
+    <style>
+      #f1 { float: left; width: 20px; }
+      #f2 { float: left; width: 30px; }
+      #f3 { float: right; width: 40px; clear: left; }
+    </style>
+    <div id="container">
+      <div id="f1"></div>
+      <div id="f2"></div>
+      <div id="f3"></div>
+    </div>
+  )HTML");
+
+  NGBlockNode container(ToLayoutBox(GetLayoutObjectByElementId("container")));
+
+  MinMaxSize sizes = RunComputeMinAndMax(container);
+  EXPECT_EQ(LayoutUnit(40), sizes.min_size);
+  EXPECT_EQ(LayoutUnit(50), sizes.max_size);
+}
+
+TEST_F(NGBlockLayoutAlgorithmTest, ComputeMinMaxContentNewFormattingContext) {
+  SetBodyInnerHTML(R"HTML(
+    <style>
+      #f1 { float: left; width: 20px; }
+      #f2 { float: left; width: 30px; }
+      #fc { display: flex; width: 40px; margin-left: 60px; }
+    </style>
+    <div id="container">
+      <div id="f1"></div>
+      <div id="f2"></div>
+      <div id="fc"></div>
+    </div>
+  )HTML");
+
+  NGBlockNode container(ToLayoutBox(GetLayoutObjectByElementId("container")));
+
+  MinMaxSize sizes = RunComputeMinAndMax(container);
+  EXPECT_EQ(LayoutUnit(100), sizes.min_size);
+  EXPECT_EQ(LayoutUnit(100), sizes.max_size);
+}
+
+TEST_F(NGBlockLayoutAlgorithmTest,
+       ComputeMinMaxContentNewFormattingContextNegativeMargins) {
+  SetBodyInnerHTML(R"HTML(
+    <style>
+      #f1 { float: left; width: 20px; }
+      #f2 { float: left; width: 30px; }
+      #fc { display: flex; width: 40px; margin-left: -20px; }
+    </style>
+    <div id="container">
+      <div id="f1"></div>
+      <div id="f2"></div>
+      <div id="fc"></div>
+    </div>
+  )HTML");
+
+  NGBlockNode container(ToLayoutBox(GetLayoutObjectByElementId("container")));
+
+  MinMaxSize sizes = RunComputeMinAndMax(container);
+  EXPECT_EQ(LayoutUnit(30), sizes.min_size);
+  EXPECT_EQ(LayoutUnit(70), sizes.max_size);
+}
+
+TEST_F(NGBlockLayoutAlgorithmTest,
+       ComputeMinMaxContentSingleNewFormattingContextNegativeMargins) {
+  SetBodyInnerHTML(R"HTML(
+    <style>
+      #fc { display: flex; width: 20px; margin-left: -40px; }
+    </style>
+    <div id="container">
+      <div id="fc"></div>
+    </div>
+  )HTML");
+
+  NGBlockNode container(ToLayoutBox(GetLayoutObjectByElementId("container")));
+
+  MinMaxSize sizes = RunComputeMinAndMax(container);
+  EXPECT_EQ(LayoutUnit(), sizes.min_size);
+  EXPECT_EQ(LayoutUnit(), sizes.max_size);
+}
+
 // Tests that we correctly handle shrink-to-fit
 TEST_F(NGBlockLayoutAlgorithmTest, ShrinkToFit) {
   SetBodyInnerHTML(R"HTML(
diff --git a/third_party/WebKit/Source/core/layout/ng/ng_layout_input_node.cc b/third_party/WebKit/Source/core/layout/ng/ng_layout_input_node.cc
index 276b894..f72bf51 100644
--- a/third_party/WebKit/Source/core/layout/ng/ng_layout_input_node.cc
+++ b/third_party/WebKit/Source/core/layout/ng/ng_layout_input_node.cc
@@ -65,6 +65,10 @@
   return type_ == kBlock;
 }
 
+bool NGLayoutInputNode::IsColumnSpanAll() const {
+  return IsBlock() && box_->IsColumnSpanAll();
+}
+
 bool NGLayoutInputNode::IsFloating() const {
   return IsBlock() && Style().IsFloating();
 }
diff --git a/third_party/WebKit/Source/core/layout/ng/ng_layout_input_node.h b/third_party/WebKit/Source/core/layout/ng/ng_layout_input_node.h
index f6713db8..7c046454 100644
--- a/third_party/WebKit/Source/core/layout/ng/ng_layout_input_node.h
+++ b/third_party/WebKit/Source/core/layout/ng/ng_layout_input_node.h
@@ -38,6 +38,8 @@
 
   bool IsInline() const;
   bool IsBlock() const;
+
+  bool IsColumnSpanAll() const;
   bool IsFloating() const;
   bool IsOutOfFlowPositioned() const;
   bool IsReplaced() const;
diff --git a/third_party/WebKit/Source/core/layout/ng/ng_length_utils.cc b/third_party/WebKit/Source/core/layout/ng/ng_length_utils.cc
index e2b610f9d..068d501 100644
--- a/third_party/WebKit/Source/core/layout/ng/ng_length_utils.cc
+++ b/third_party/WebKit/Source/core/layout/ng/ng_length_utils.cc
@@ -237,9 +237,6 @@
   computed_sizes.min_size = std::max(computed_sizes.min_size, min);
   computed_sizes.max_size = std::max(computed_sizes.max_size, min);
 
-  NGBoxStrut margins = ComputeMarginsForSelf(*space, style);
-  computed_sizes.min_size += margins.InlineSum();
-  computed_sizes.max_size += margins.InlineSum();
   return computed_sizes;
 }
 
@@ -482,6 +479,28 @@
       .ConvertToLogical(style.GetWritingMode(), style.Direction());
 }
 
+NGBoxStrut ComputeMinMaxMargins(const ComputedStyle& parent_style,
+                                NGLayoutInputNode child) {
+  // An inline child just produces line-boxes which don't have any margins.
+  if (child.IsInline())
+    return NGBoxStrut();
+
+  Length inline_start_margin_length =
+      child.Style().MarginStartUsing(parent_style);
+  Length inline_end_margin_length = child.Style().MarginEndUsing(parent_style);
+
+  // TODO(ikilpatrick): We may want to re-visit calculated margins at some
+  // point. Currently "margin-left: calc(10px + 50%)" will resolve to 0px, but
+  // 10px would be more correct, (as percentages resolve to zero).
+  NGBoxStrut margins;
+  if (inline_start_margin_length.IsFixed())
+    margins.inline_start = LayoutUnit(inline_start_margin_length.Value());
+  if (inline_end_margin_length.IsFixed())
+    margins.inline_end = LayoutUnit(inline_end_margin_length.Value());
+
+  return margins;
+}
+
 NGBoxStrut ComputeBorders(const NGConstraintSpace& constraint_space,
                           const ComputedStyle& style) {
   // If we are producing an anonymous fragment (e.g. a column) we shouldn't
diff --git a/third_party/WebKit/Source/core/layout/ng/ng_length_utils.h b/third_party/WebKit/Source/core/layout/ng/ng_length_utils.h
index dc1999a..0681313 100644
--- a/third_party/WebKit/Source/core/layout/ng/ng_length_utils.h
+++ b/third_party/WebKit/Source/core/layout/ng/ng_length_utils.h
@@ -124,6 +124,10 @@
 CORE_EXPORT NGBoxStrut ComputeMarginsForSelf(const NGConstraintSpace&,
                                              const ComputedStyle&);
 
+// Compute margins for a child during the min-max size calculation.
+CORE_EXPORT NGBoxStrut ComputeMinMaxMargins(const ComputedStyle& parent_style,
+                                            NGLayoutInputNode child);
+
 CORE_EXPORT NGBoxStrut ComputeBorders(const NGConstraintSpace& constraint_space,
                                       const ComputedStyle&);
 
diff --git a/third_party/WebKit/Source/core/leak_detector/WebLeakDetector.cpp b/third_party/WebKit/Source/core/leak_detector/WebLeakDetector.cpp
index bbf51717..0a0e537 100644
--- a/third_party/WebKit/Source/core/leak_detector/WebLeakDetector.cpp
+++ b/third_party/WebKit/Source/core/leak_detector/WebLeakDetector.cpp
@@ -30,6 +30,7 @@
 
 #include "public/web/WebLeakDetector.h"
 
+#include "base/macros.h"
 #include "core/frame/WebLocalFrameImpl.h"
 #include "core/leak_detector/BlinkLeakDetector.h"
 #include "core/leak_detector/BlinkLeakDetectorClient.h"
@@ -42,7 +43,6 @@
 
 class WebLeakDetectorImpl final : public WebLeakDetector,
                                   public BlinkLeakDetectorClient {
-  WTF_MAKE_NONCOPYABLE(WebLeakDetectorImpl);
 
  public:
   explicit WebLeakDetectorImpl(WebLeakDetectorClient* client)
@@ -61,6 +61,7 @@
  private:
   WebLeakDetectorClient* client_;
   std::unique_ptr<BlinkLeakDetector> detector_;
+  DISALLOW_COPY_AND_ASSIGN(WebLeakDetectorImpl);
 };
 
 void WebLeakDetectorImpl::PrepareForLeakDetection(WebFrame* frame) {
diff --git a/third_party/WebKit/Source/core/loader/DocumentLoader.cpp b/third_party/WebKit/Source/core/loader/DocumentLoader.cpp
index 950d457..1b6a7a4 100644
--- a/third_party/WebKit/Source/core/loader/DocumentLoader.cpp
+++ b/third_party/WebKit/Source/core/loader/DocumentLoader.cpp
@@ -152,7 +152,7 @@
 
 DocumentLoader::~DocumentLoader() {
   DCHECK(!frame_);
-  DCHECK(!main_resource_);
+  DCHECK(!GetResource());
   DCHECK(!application_cache_host_);
   DCHECK_EQ(state_, kSentDidFinishLoad);
 }
@@ -160,7 +160,6 @@
 void DocumentLoader::Trace(blink::Visitor* visitor) {
   visitor->Trace(frame_);
   visitor->Trace(fetcher_);
-  visitor->Trace(main_resource_);
   visitor->Trace(history_item_);
   visitor->Trace(parser_);
   visitor->Trace(subresource_filter_);
@@ -171,7 +170,7 @@
 }
 
 unsigned long DocumentLoader::MainResourceIdentifier() const {
-  return main_resource_ ? main_resource_->Identifier() : 0;
+  return GetResource() ? GetResource()->Identifier() : 0;
 }
 
 ResourceTimingInfo* DocumentLoader::GetNavigationTimingInfo() const {
@@ -384,25 +383,25 @@
 }
 
 void DocumentLoader::NotifyFinished(Resource* resource) {
-  DCHECK_EQ(main_resource_, resource);
-  DCHECK(main_resource_);
+  DCHECK_EQ(GetResource(), resource);
+  DCHECK(GetResource());
 
-  if (!main_resource_->ErrorOccurred() && !main_resource_->WasCanceled()) {
-    FinishedLoading(main_resource_->LoadFinishTime());
+  if (!resource->ErrorOccurred() && !resource->WasCanceled()) {
+    FinishedLoading(resource->LoadFinishTime());
     return;
   }
 
   if (application_cache_host_)
     application_cache_host_->FailedLoadingMainResource();
 
-  if (main_resource_->GetResourceError().WasBlockedByResponse()) {
+  if (resource->GetResourceError().WasBlockedByResponse()) {
     probe::CanceledAfterReceivedResourceResponse(
         frame_, this, MainResourceIdentifier(), resource->GetResponse(),
-        main_resource_.Get());
+        resource);
   }
 
-  LoadFailed(main_resource_->GetResourceError());
-  ClearMainResourceHandle();
+  LoadFailed(resource->GetResourceError());
+  ClearResource();
 }
 
 void DocumentLoader::LoadFailed(const ResourceError& error) {
@@ -462,7 +461,7 @@
     parser_->Finish();
     parser_.Clear();
   }
-  ClearMainResourceHandle();
+  ClearResource();
 }
 
 bool DocumentLoader::RedirectReceived(
@@ -470,7 +469,7 @@
     const ResourceRequest& request,
     const ResourceResponse& redirect_response) {
   DCHECK(frame_);
-  DCHECK_EQ(resource, main_resource_);
+  DCHECK_EQ(resource, GetResource());
   DCHECK(!redirect_response.IsNull());
   request_ = request;
 
@@ -542,7 +541,7 @@
 void DocumentLoader::CancelLoadAfterCSPDenied(
     const ResourceResponse& response) {
   probe::CanceledAfterReceivedResourceResponse(
-      frame_, this, MainResourceIdentifier(), response, main_resource_.Get());
+      frame_, this, MainResourceIdentifier(), response, GetResource());
 
   SetWasBlockedAfterCSP();
 
@@ -551,7 +550,7 @@
   //
   // TODO(mkwst):  Remove this once XFO moves to the browser.
   // https://crbug.com/555418.
-  ClearMainResourceHandle();
+  ClearResource();
   content_security_policy_.Clear();
   KURL blocked_url = SecurityOrigin::UrlWithUniqueSecurityOrigin();
   original_request_.SetURL(blocked_url);
@@ -568,7 +567,7 @@
     Resource* resource,
     const ResourceResponse& response,
     std::unique_ptr<WebDataConsumerHandle> handle) {
-  DCHECK_EQ(main_resource_, resource);
+  DCHECK_EQ(GetResource(), resource);
   DCHECK(!handle);
   DCHECK(frame_);
 
@@ -579,7 +578,7 @@
   // we don't save the result for future use. All responses loaded from appcache
   // will have a non-zero appCacheID().
   if (response.AppCacheID())
-    GetMemoryCache()->Remove(main_resource_.Get());
+    GetMemoryCache()->Remove(resource);
 
   content_security_policy_ = ContentSecurityPolicy::Create();
   content_security_policy_->SetOverrideURLForSelf(response.Url());
@@ -629,12 +628,12 @@
   response_ = response;
 
   if (IsArchiveMIMEType(response_.MimeType()) &&
-      main_resource_->GetDataBufferingPolicy() != kBufferData)
-    main_resource_->SetDataBufferingPolicy(kBufferData);
+      resource->GetDataBufferingPolicy() != kBufferData)
+    resource->SetDataBufferingPolicy(kBufferData);
 
   if (!ShouldContinueForResponse()) {
-    probe::ContinueWithPolicyIgnore(frame_, this, main_resource_->Identifier(),
-                                    response_, main_resource_.Get());
+    probe::ContinueWithPolicyIgnore(frame_, this, resource->Identifier(),
+                                    response_, resource);
     fetcher_->StopFetching();
     return;
   }
@@ -677,14 +676,16 @@
     if (owner_frame && owner_frame->IsLocalFrame())
       owner_document = ToLocalFrame(owner_frame)->GetDocument();
   }
-  bool should_reuse_default_view = frame_->ShouldReuseDefaultView(Url());
   DCHECK(frame_->GetPage());
 
   ParserSynchronizationPolicy parsing_policy = kAllowAsynchronousParsing;
   if (!Document::ThreadedParsingEnabledForTesting())
     parsing_policy = kForceSynchronousParsing;
 
-  InstallNewDocument(Url(), owner_document, should_reuse_default_view,
+  InstallNewDocument(Url(), owner_document,
+                     frame_->ShouldReuseDefaultView(Url())
+                         ? WebGlobalObjectReusePolicy::kUseExisting
+                         : WebGlobalObjectReusePolicy::kCreateNew,
                      mime_type, encoding, InstallNewDocumentReason::kNavigation,
                      parsing_policy, overriding_url);
   parser_->SetDocumentWasLoadedAsPartOfNavigation();
@@ -712,7 +713,7 @@
                                   size_t length) {
   DCHECK(data);
   DCHECK(length);
-  DCHECK_EQ(resource, main_resource_);
+  DCHECK_EQ(resource, GetResource());
   DCHECK(!response_.IsNull());
   DCHECK(!frame_->GetPage()->Paused());
 
@@ -785,26 +786,18 @@
   application_cache_host_.Clear();
   service_worker_network_provider_ = nullptr;
   WeakIdentifierMap<DocumentLoader>::NotifyObjectDestroyed(this);
-  ClearMainResourceHandle();
+  ClearResource();
   frame_ = nullptr;
 }
 
-void DocumentLoader::ClearMainResourceHandle() {
-  if (!main_resource_)
-    return;
-  main_resource_->RemoveClient(this);
-  main_resource_ = nullptr;
-}
-
 bool DocumentLoader::MaybeCreateArchive() {
   // Give the archive machinery a crack at this document. If the MIME type is
   // not an archive type, it will return 0.
   if (!IsArchiveMIMEType(response_.MimeType()))
     return false;
 
-  DCHECK(main_resource_);
-  ArchiveResource* main_resource =
-      fetcher_->CreateArchive(main_resource_.Get());
+  DCHECK(GetResource());
+  ArchiveResource* main_resource = fetcher_->CreateArchive(GetResource());
   if (!main_resource)
     return false;
   // The origin is the MHTML file, we need to set the base URL to the document
@@ -844,7 +837,7 @@
 
 void DocumentLoader::StartLoading() {
   GetTiming().MarkNavigationStart();
-  DCHECK(!main_resource_);
+  DCHECK(!GetResource());
   DCHECK_EQ(state_, kNotStarted);
   state_ = kProvisional;
 
@@ -864,26 +857,25 @@
   options.data_buffering_policy = kDoNotBufferData;
   options.initiator_info.name = FetchInitiatorTypeNames::document;
   FetchParameters fetch_params(request_, options);
-  main_resource_ =
-      RawResource::FetchMainResource(fetch_params, Fetcher(), substitute_data_);
+  SetResource(RawResource::FetchMainResource(fetch_params, Fetcher(),
+                                             substitute_data_));
 
   // PlzNavigate:
   // The final access checks are still performed here, potentially rejecting
   // the "provisional" load, but the browser side already expects the renderer
   // to be able to unconditionally commit.
-  if (!main_resource_ ||
+  if (!GetResource() ||
       (frame_->GetSettings()->GetBrowserSideNavigationEnabled() &&
-       main_resource_->ErrorOccurred())) {
+       GetResource()->ErrorOccurred())) {
     request_ = ResourceRequest(BlankURL());
     MaybeLoadEmpty();
     return;
   }
   // A bunch of headers are set when the underlying resource load begins, and
-  // m_request needs to include those. Even when using a cached resource, we may
+  // request_ needs to include those. Even when using a cached resource, we may
   // make some modification to the request, e.g. adding the referer header.
-  request_ = main_resource_->IsLoading() ? main_resource_->GetResourceRequest()
-                                         : fetch_params.GetResourceRequest();
-  main_resource_->AddClient(this);
+  request_ = GetResource()->IsLoading() ? GetResource()->GetResourceRequest()
+                                        : fetch_params.GetResourceRequest();
 }
 
 void DocumentLoader::DidInstallNewDocument(Document* document) {
@@ -950,7 +942,8 @@
   frame_->GetIdlenessDetector()->WillCommitLoad();
 }
 
-void DocumentLoader::DidCommitNavigation() {
+void DocumentLoader::DidCommitNavigation(
+    WebGlobalObjectReusePolicy global_object_reuse_policy) {
   if (GetFrameLoader().StateMachine()->CreatingInitialEmptyDocument())
     return;
 
@@ -964,7 +957,8 @@
   frame_->FrameScheduler()->DidCommitProvisionalLoad(
       commit_type == kHistoryInertCommit, load_type_ == kFrameLoadTypeReload,
       frame_->IsLocalRoot());
-  GetLocalFrameClient().DispatchDidCommitLoad(history_item_.Get(), commit_type);
+  GetLocalFrameClient().DispatchDidCommitLoad(history_item_.Get(), commit_type,
+                                              global_object_reuse_policy);
 
   // When the embedder gets notified (above) that the new navigation has
   // committed, the embedder will drop the old Content Security Policy and
@@ -1050,7 +1044,7 @@
 void DocumentLoader::InstallNewDocument(
     const KURL& url,
     Document* owner_document,
-    bool should_reuse_default_view,
+    WebGlobalObjectReusePolicy global_object_reuse_policy,
     const AtomicString& mime_type,
     const AtomicString& encoding,
     InstallNewDocumentReason reason,
@@ -1058,7 +1052,6 @@
     const KURL& overriding_url) {
   DCHECK(!frame_->GetDocument() || !frame_->GetDocument()->IsActive());
   DCHECK_EQ(frame_->Tree().ChildCount(), 0u);
-
   if (GetFrameLoader().StateMachine()->IsDisplayingInitialEmptyDocument()) {
     GetFrameLoader().StateMachine()->AdvanceTo(
         FrameLoaderStateMachine::kCommittedFirstRealLoad);
@@ -1076,7 +1069,7 @@
   // commits. To make that happen, we "securely transition" the existing
   // LocalDOMWindow to the Document that results from the network load. See also
   // Document::IsSecureTransitionTo.
-  if (!should_reuse_default_view)
+  if (global_object_reuse_policy != WebGlobalObjectReusePolicy::kUseExisting)
     frame_->SetDOMWindow(LocalDOMWindow::Create(*frame_));
 
   bool user_gesture_bit_set = frame_->HasBeenActivated() ||
@@ -1122,7 +1115,7 @@
   // This must be called before the document is opened, otherwise HTML parser
   // will use stale values from HTMLParserOption.
   if (reason == InstallNewDocumentReason::kNavigation)
-    DidCommitNavigation();
+    DidCommitNavigation(global_object_reuse_policy);
 
   if (document->GetSettings()
           ->GetForceTouchEventFeatureDetectionForInspector()) {
@@ -1156,10 +1149,10 @@
 void DocumentLoader::ReplaceDocumentWhileExecutingJavaScriptURL(
     const KURL& url,
     Document* owner_document,
-    bool should_reuse_default_view,
+    WebGlobalObjectReusePolicy global_object_reuse_policy,
     const String& source) {
-  InstallNewDocument(url, owner_document, should_reuse_default_view, MimeType(),
-                     response_.TextEncodingName(),
+  InstallNewDocument(url, owner_document, global_object_reuse_policy,
+                     MimeType(), response_.TextEncodingName(),
                      InstallNewDocumentReason::kJavascriptURL,
                      kForceSynchronousParsing, NullURL());
 
diff --git a/third_party/WebKit/Source/core/loader/DocumentLoader.h b/third_party/WebKit/Source/core/loader/DocumentLoader.h
index 078a7cf1..18db203c 100644
--- a/third_party/WebKit/Source/core/loader/DocumentLoader.h
+++ b/third_party/WebKit/Source/core/loader/DocumentLoader.h
@@ -53,6 +53,7 @@
 #include "platform/loader/fetch/SubstituteData.h"
 #include "platform/wtf/HashSet.h"
 #include "public/platform/WebLoadingBehaviorFlag.h"
+#include "public/web/WebGlobalObjectReusePolicy.h"
 
 #include <memory>
 
@@ -100,11 +101,10 @@
 
   unsigned long MainResourceIdentifier() const;
 
-  void ReplaceDocumentWhileExecutingJavaScriptURL(
-      const KURL&,
-      Document* owner_document,
-      bool should_reuse_default_view,
-      const String& source);
+  void ReplaceDocumentWhileExecutingJavaScriptURL(const KURL&,
+                                                  Document* owner_document,
+                                                  WebGlobalObjectReusePolicy,
+                                                  const String& source);
 
   const AtomicString& MimeType() const;
 
@@ -257,7 +257,7 @@
   enum class InstallNewDocumentReason { kNavigation, kJavascriptURL };
   void InstallNewDocument(const KURL&,
                           Document* owner_document,
-                          bool should_reuse_default_view,
+                          WebGlobalObjectReusePolicy,
                           const AtomicString& mime_type,
                           const AtomicString& encoding,
                           InstallNewDocumentReason,
@@ -265,7 +265,7 @@
                           const KURL& overriding_url);
   void DidInstallNewDocument(Document*);
   void WillCommitNavigation();
-  void DidCommitNavigation();
+  void DidCommitNavigation(WebGlobalObjectReusePolicy);
 
   void CommitNavigation(const AtomicString& mime_type,
                         const KURL& overriding_url = KURL());
@@ -276,7 +276,6 @@
   LocalFrameClient& GetLocalFrameClient() const;
 
   void CommitData(const char* bytes, size_t length);
-  void ClearMainResourceHandle();
 
   bool MaybeCreateArchive();
 
@@ -316,7 +315,6 @@
   Member<LocalFrame> frame_;
   Member<ResourceFetcher> fetcher_;
 
-  Member<RawResource> main_resource_;
   Member<HistoryItem> history_item_;
 
   // The parser that was created when the current Document was installed.
diff --git a/third_party/WebKit/Source/core/loader/DocumentThreadableLoader.cpp b/third_party/WebKit/Source/core/loader/DocumentThreadableLoader.cpp
index 53fcf16..00ebec7 100644
--- a/third_party/WebKit/Source/core/loader/DocumentThreadableLoader.cpp
+++ b/third_party/WebKit/Source/core/loader/DocumentThreadableLoader.cpp
@@ -1379,7 +1379,7 @@
 void DocumentThreadableLoader::Trace(blink::Visitor* visitor) {
   visitor->Trace(loading_context_);
   ThreadableLoader::Trace(visitor);
-  ResourceOwner<RawResource>::Trace(visitor);
+  RawResourceClient::Trace(visitor);
 }
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/loader/DocumentThreadableLoader.h b/third_party/WebKit/Source/core/loader/DocumentThreadableLoader.h
index 8d9f588..958c3f5 100644
--- a/third_party/WebKit/Source/core/loader/DocumentThreadableLoader.h
+++ b/third_party/WebKit/Source/core/loader/DocumentThreadableLoader.h
@@ -39,7 +39,6 @@
 #include "platform/heap/Handle.h"
 #include "platform/loader/fetch/RawResource.h"
 #include "platform/loader/fetch/ResourceError.h"
-#include "platform/loader/fetch/ResourceOwner.h"
 #include "platform/network/HTTPHeaderMap.h"
 #include "platform/weborigin/Referrer.h"
 #include "platform/wtf/Forward.h"
@@ -57,9 +56,8 @@
 
 // TODO(horo): We are using this class not only in documents, but also in
 // workers. We should change the name to ThreadableLoaderImpl.
-class CORE_EXPORT DocumentThreadableLoader final
-    : public ThreadableLoader,
-      private ResourceOwner<RawResource> {
+class CORE_EXPORT DocumentThreadableLoader final : public ThreadableLoader,
+                                                   private RawResourceClient {
   USING_GARBAGE_COLLECTED_MIXIN(DocumentThreadableLoader);
 
  public:
diff --git a/third_party/WebKit/Source/core/loader/EmptyClients.h b/third_party/WebKit/Source/core/loader/EmptyClients.h
index 7627e66..c7116a032 100644
--- a/third_party/WebKit/Source/core/loader/EmptyClients.h
+++ b/third_party/WebKit/Source/core/loader/EmptyClients.h
@@ -261,7 +261,9 @@
                                        ResourceRequest&) override {}
   void DispatchDidReceiveTitle(const String&) override {}
   void DispatchDidChangeIcons(IconType) override {}
-  void DispatchDidCommitLoad(HistoryItem*, HistoryCommitType) override {}
+  void DispatchDidCommitLoad(HistoryItem*,
+                             HistoryCommitType,
+                             WebGlobalObjectReusePolicy) override {}
   void DispatchDidFailProvisionalLoad(const ResourceError&,
                                       HistoryCommitType) override {}
   void DispatchDidFailLoad(const ResourceError&, HistoryCommitType) override {}
diff --git a/third_party/WebKit/Source/core/loader/FrameLoader.cpp b/third_party/WebKit/Source/core/loader/FrameLoader.cpp
index be316ca58..f1b55be 100644
--- a/third_party/WebKit/Source/core/loader/FrameLoader.cpp
+++ b/third_party/WebKit/Source/core/loader/FrameLoader.cpp
@@ -429,7 +429,10 @@
 
   // Compute this before clearing the frame, because it may need to inherit an
   // aliased security context.
-  bool should_reuse_default_view = frame_->ShouldReuseDefaultView(url);
+  WebGlobalObjectReusePolicy global_object_reuse_policy =
+      frame_->ShouldReuseDefaultView(url)
+          ? WebGlobalObjectReusePolicy::kUseExisting
+          : WebGlobalObjectReusePolicy::kCreateNew;
 
   StopAllLoaders();
   // Don't allow any new child frames to load in this frame: attaching a new
@@ -446,7 +449,7 @@
   frame_->GetDocument()->Shutdown();
   Client()->TransitionToCommittedForNewPage();
   document_loader_->ReplaceDocumentWhileExecutingJavaScriptURL(
-      url, owner_document, should_reuse_default_view, source);
+      url, owner_document, global_object_reuse_policy, source);
 }
 
 void FrameLoader::FinishedParsing() {
diff --git a/third_party/WebKit/Source/core/loader/LinkLoader.h b/third_party/WebKit/Source/core/loader/LinkLoader.h
index 597e24bb..202fefc1 100644
--- a/third_party/WebKit/Source/core/loader/LinkLoader.h
+++ b/third_party/WebKit/Source/core/loader/LinkLoader.h
@@ -37,7 +37,7 @@
 #include "core/loader/LinkLoaderClient.h"
 #include "platform/CrossOriginAttributeValue.h"
 #include "platform/PrerenderClient.h"
-#include "platform/loader/fetch/ResourceOwner.h"
+#include "platform/loader/fetch/Resource.h"
 #include "platform/wtf/Optional.h"
 
 namespace blink {
diff --git a/third_party/WebKit/Source/core/loader/TextTrackLoader.cpp b/third_party/WebKit/Source/core/loader/TextTrackLoader.cpp
index f8d29d43..5e6c303 100644
--- a/third_party/WebKit/Source/core/loader/TextTrackLoader.cpp
+++ b/third_party/WebKit/Source/core/loader/TextTrackLoader.cpp
@@ -180,7 +180,7 @@
   visitor->Trace(client_);
   visitor->Trace(cue_parser_);
   visitor->Trace(document_);
-  ResourceOwner<RawResource>::Trace(visitor);
+  RawResourceClient::Trace(visitor);
   VTTParserClient::Trace(visitor);
 }
 
diff --git a/third_party/WebKit/Source/core/loader/TextTrackLoader.h b/third_party/WebKit/Source/core/loader/TextTrackLoader.h
index 3cb4dbd..a378b334 100644
--- a/third_party/WebKit/Source/core/loader/TextTrackLoader.h
+++ b/third_party/WebKit/Source/core/loader/TextTrackLoader.h
@@ -30,7 +30,6 @@
 #include "platform/CrossOriginAttributeValue.h"
 #include "platform/heap/Handle.h"
 #include "platform/loader/fetch/RawResource.h"
-#include "platform/loader/fetch/ResourceOwner.h"
 
 namespace blink {
 
@@ -46,7 +45,7 @@
 };
 
 class TextTrackLoader final : public GarbageCollectedFinalized<TextTrackLoader>,
-                              public ResourceOwner<RawResource>,
+                              public RawResourceClient,
                               private VTTParserClient {
   USING_GARBAGE_COLLECTED_MIXIN(TextTrackLoader);
 
diff --git a/third_party/WebKit/Source/core/loader/modulescript/DocumentModuleScriptFetcher.cpp b/third_party/WebKit/Source/core/loader/modulescript/DocumentModuleScriptFetcher.cpp
index 000b9da..2e73da8 100644
--- a/third_party/WebKit/Source/core/loader/modulescript/DocumentModuleScriptFetcher.cpp
+++ b/third_party/WebKit/Source/core/loader/modulescript/DocumentModuleScriptFetcher.cpp
@@ -118,7 +118,7 @@
 
 void DocumentModuleScriptFetcher::Trace(blink::Visitor* visitor) {
   visitor->Trace(fetcher_);
-  ResourceOwner<ScriptResource>::Trace(visitor);
+  ResourceClient::Trace(visitor);
   ModuleScriptFetcher::Trace(visitor);
 }
 
diff --git a/third_party/WebKit/Source/core/loader/modulescript/DocumentModuleScriptFetcher.h b/third_party/WebKit/Source/core/loader/modulescript/DocumentModuleScriptFetcher.h
index 55156ea..dfb26e7 100644
--- a/third_party/WebKit/Source/core/loader/modulescript/DocumentModuleScriptFetcher.h
+++ b/third_party/WebKit/Source/core/loader/modulescript/DocumentModuleScriptFetcher.h
@@ -11,7 +11,6 @@
 #include "core/loader/resource/ScriptResource.h"
 #include "platform/loader/fetch/FetchParameters.h"
 #include "platform/loader/fetch/ResourceFetcher.h"
-#include "platform/loader/fetch/ResourceOwner.h"
 #include "platform/weborigin/SecurityOrigin.h"
 #include "platform/wtf/Optional.h"
 
@@ -24,11 +23,10 @@
 //
 // DocumentModuleScriptFetcher emits FetchParameters to ResourceFetcher
 // (via ScriptResource::Fetch). Then, it keeps track of the fetch progress by
-// being a ResourceOwner. Finally, it returns its client a fetched resource as
+// being a ResourceClient. Finally, it returns its client a fetched resource as
 // ModuleScriptCreationParams.
-class CORE_EXPORT DocumentModuleScriptFetcher
-    : public ModuleScriptFetcher,
-      public ResourceOwner<ScriptResource> {
+class CORE_EXPORT DocumentModuleScriptFetcher : public ModuleScriptFetcher,
+                                                public ResourceClient {
   USING_GARBAGE_COLLECTED_MIXIN(DocumentModuleScriptFetcher);
 
  public:
@@ -36,7 +34,7 @@
 
   void Fetch(FetchParameters&, ModuleScriptFetcher::Client*) final;
 
-  // Implements ScriptResourceClient
+  // Implements ResourceClient
   void NotifyFinished(Resource*) final;
   String DebugName() const final { return "DocumentModuleScriptFetcher"; }
 
diff --git a/third_party/WebKit/Source/core/loader/resource/DocumentResource.h b/third_party/WebKit/Source/core/loader/resource/DocumentResource.h
index d917492..f00ea14 100644
--- a/third_party/WebKit/Source/core/loader/resource/DocumentResource.h
+++ b/third_party/WebKit/Source/core/loader/resource/DocumentResource.h
@@ -38,8 +38,6 @@
 
 class CORE_EXPORT DocumentResource final : public TextResource {
  public:
-  using ClientType = ResourceClient;
-
   static DocumentResource* FetchSVGDocument(FetchParameters&, ResourceFetcher*);
   ~DocumentResource() override;
   void Trace(blink::Visitor*) override;
diff --git a/third_party/WebKit/Source/core/loader/resource/FontResource.h b/third_party/WebKit/Source/core/loader/resource/FontResource.h
index 3879ad5..d75996f 100644
--- a/third_party/WebKit/Source/core/loader/resource/FontResource.h
+++ b/third_party/WebKit/Source/core/loader/resource/FontResource.h
@@ -43,8 +43,6 @@
 
 class CORE_EXPORT FontResource final : public Resource {
  public:
-  using ClientType = FontResourceClient;
-
   static FontResource* Fetch(FetchParameters&, ResourceFetcher*);
   ~FontResource() override;
 
diff --git a/third_party/WebKit/Source/core/loader/resource/ImageResource.h b/third_party/WebKit/Source/core/loader/resource/ImageResource.h
index 891d580..d0d426a 100644
--- a/third_party/WebKit/Source/core/loader/resource/ImageResource.h
+++ b/third_party/WebKit/Source/core/loader/resource/ImageResource.h
@@ -56,8 +56,6 @@
   USING_GARBAGE_COLLECTED_MIXIN(ImageResource);
 
  public:
-  using ClientType = ResourceClient;
-
   // Use ImageResourceContent::Fetch() unless ImageResource is required.
   // TODO(hiroshige): Make Fetch() private.
   static ImageResource* Fetch(FetchParameters&, ResourceFetcher*);
diff --git a/third_party/WebKit/Source/core/loader/resource/LinkFetchResource.h b/third_party/WebKit/Source/core/loader/resource/LinkFetchResource.h
index aa57dfc6..834df0bc 100644
--- a/third_party/WebKit/Source/core/loader/resource/LinkFetchResource.h
+++ b/third_party/WebKit/Source/core/loader/resource/LinkFetchResource.h
@@ -15,8 +15,6 @@
 
 class LinkFetchResource final : public Resource {
  public:
-  using ClientType = ResourceClient;
-
   static Resource* Fetch(Resource::Type, FetchParameters&, ResourceFetcher*);
   ~LinkFetchResource() override;
 
diff --git a/third_party/WebKit/Source/core/loader/resource/MockFontResourceClient.cpp b/third_party/WebKit/Source/core/loader/resource/MockFontResourceClient.cpp
index edb7b99..3d3e859 100644
--- a/third_party/WebKit/Source/core/loader/resource/MockFontResourceClient.cpp
+++ b/third_party/WebKit/Source/core/loader/resource/MockFontResourceClient.cpp
@@ -9,10 +9,9 @@
 namespace blink {
 
 MockFontResourceClient::MockFontResourceClient(Resource* resource)
-    : resource_(resource),
-      font_load_short_limit_exceeded_called_(false),
+    : font_load_short_limit_exceeded_called_(false),
       font_load_long_limit_exceeded_called_(false) {
-  resource_->AddClient(this);
+  SetResource(resource);
 }
 
 MockFontResourceClient::~MockFontResourceClient() {}
@@ -30,10 +29,7 @@
 }
 
 void MockFontResourceClient::Dispose() {
-  if (resource_) {
-    resource_->RemoveClient(this);
-    resource_ = nullptr;
-  }
+  ClearResource();
 }
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/loader/resource/MockFontResourceClient.h b/third_party/WebKit/Source/core/loader/resource/MockFontResourceClient.h
index b38e5309..c450a68b 100644
--- a/third_party/WebKit/Source/core/loader/resource/MockFontResourceClient.h
+++ b/third_party/WebKit/Source/core/loader/resource/MockFontResourceClient.h
@@ -34,7 +34,6 @@
   }
 
   void Trace(blink::Visitor* visitor) override {
-    visitor->Trace(resource_);
     FontResourceClient::Trace(visitor);
   }
 
@@ -43,7 +42,6 @@
  private:
   void Dispose();
 
-  Member<Resource> resource_;
   bool font_load_short_limit_exceeded_called_;
   bool font_load_long_limit_exceeded_called_;
 };
diff --git a/third_party/WebKit/Source/core/loader/resource/ScriptResource.h b/third_party/WebKit/Source/core/loader/resource/ScriptResource.h
index 5d7d9c1..b8dcd1d9 100644
--- a/third_party/WebKit/Source/core/loader/resource/ScriptResource.h
+++ b/third_party/WebKit/Source/core/loader/resource/ScriptResource.h
@@ -43,7 +43,6 @@
 
 class CORE_EXPORT ScriptResource final : public TextResource {
  public:
-  using ClientType = ResourceClient;
   static ScriptResource* Fetch(FetchParameters&, ResourceFetcher*);
 
   // Public for testing
diff --git a/third_party/WebKit/Source/core/loader/resource/TextResource.h b/third_party/WebKit/Source/core/loader/resource/TextResource.h
index ec41db1..2457ff2 100644
--- a/third_party/WebKit/Source/core/loader/resource/TextResource.h
+++ b/third_party/WebKit/Source/core/loader/resource/TextResource.h
@@ -15,8 +15,6 @@
 
 class CORE_EXPORT TextResource : public Resource {
  public:
-  using ClientType = ResourceClient;
-
   // Returns the decoded data in text form. The data has to be available at
   // call time.
   String DecodedText() const;
diff --git a/third_party/WebKit/Source/core/offscreencanvas/OffscreenCanvas.cpp b/third_party/WebKit/Source/core/offscreencanvas/OffscreenCanvas.cpp
index e49a2717..0fd473b 100644
--- a/third_party/WebKit/Source/core/offscreencanvas/OffscreenCanvas.cpp
+++ b/third_party/WebKit/Source/core/offscreencanvas/OffscreenCanvas.cpp
@@ -394,19 +394,11 @@
 
   ScriptPromiseResolver* resolver = ScriptPromiseResolver::Create(script_state);
   CanvasAsyncBlobCreator* async_creator = nullptr;
-  if (context_->Is3d() &&
-      !context_->CreationAttributes().premultipliedAlpha()) {
-    ImageData* image_data = context_->ToImageData(kSnapshotReasonUnknown);
-    async_creator = CanvasAsyncBlobCreator::Create(
-        image_data->data(), encoding_mime_type, image_data->Size(), start_time,
-        ExecutionContext::From(script_state), resolver);
-  } else {
-    scoped_refptr<StaticBitmapImage> snapshot =
-        context_->GetImage(kPreferNoAcceleration, kSnapshotReasonUnknown);
-    async_creator = CanvasAsyncBlobCreator::Create(
-        snapshot, encoding_mime_type, start_time,
-        ExecutionContext::From(script_state), resolver);
-  }
+  scoped_refptr<StaticBitmapImage> snapshot =
+      context_->GetImage(kPreferNoAcceleration, kSnapshotReasonUnknown);
+  async_creator = CanvasAsyncBlobCreator::Create(
+      snapshot, encoding_mime_type, start_time,
+      ExecutionContext::From(script_state), resolver);
   async_creator->ScheduleAsyncBlobCreation(options.quality());
   return resolver->Promise();
 }
diff --git a/third_party/WebKit/Source/core/paint/PaintLayer.cpp b/third_party/WebKit/Source/core/paint/PaintLayer.cpp
index 01cabfed..bcf46d1 100644
--- a/third_party/WebKit/Source/core/paint/PaintLayer.cpp
+++ b/third_party/WebKit/Source/core/paint/PaintLayer.cpp
@@ -124,9 +124,9 @@
 
 PaintLayerRareData::PaintLayerRareData()
     : enclosing_pagination_layer(nullptr),
-      potential_compositing_reasons_from_style(kCompositingReasonNone),
-      compositing_reasons(kCompositingReasonNone),
-      squashing_disallowed_reasons(kSquashingDisallowedReasonsNone),
+      potential_compositing_reasons_from_style(CompositingReason::kNone),
+      compositing_reasons(CompositingReason::kNone),
+      squashing_disallowed_reasons(SquashingDisallowedReason::kNone),
       grouped_mapping(nullptr) {}
 
 PaintLayerRareData::~PaintLayerRareData() {}
@@ -1101,11 +1101,11 @@
 void PaintLayer::SetCompositingReasons(CompositingReasons reasons,
                                        CompositingReasons mask) {
   CompositingReasons old_reasons =
-      rare_data_ ? rare_data_->compositing_reasons : kCompositingReasonNone;
+      rare_data_ ? rare_data_->compositing_reasons : CompositingReason::kNone;
   if ((old_reasons & mask) == (reasons & mask))
     return;
   CompositingReasons new_reasons = (reasons & mask) | (old_reasons & ~mask);
-  if (rare_data_ || new_reasons != kCompositingReasonNone)
+  if (rare_data_ || new_reasons != CompositingReason::kNone)
     EnsureRareData().compositing_reasons = new_reasons;
 }
 
@@ -1113,10 +1113,10 @@
     SquashingDisallowedReasons reasons) {
   SquashingDisallowedReasons old_reasons =
       rare_data_ ? rare_data_->squashing_disallowed_reasons
-                 : kSquashingDisallowedReasonsNone;
+                 : SquashingDisallowedReason::kNone;
   if (old_reasons == reasons)
     return;
-  if (rare_data_ || reasons != kSquashingDisallowedReasonsNone)
+  if (rare_data_ || reasons != SquashingDisallowedReason::kNone)
     EnsureRareData().squashing_disallowed_reasons = reasons;
 }
 
@@ -3137,8 +3137,8 @@
   // means that the inline transform actually triggered assumed overlap in
   // the overlap map.
   if (diff.TransformChanged() &&
-      (!rare_data_ ||
-       !(rare_data_->compositing_reasons & kCompositingReasonInlineTransform)))
+      (!rare_data_ || !(rare_data_->compositing_reasons &
+                        CompositingReason::kInlineTransform)))
     return false;
 
   // We composite transparent Layers differently from non-transparent
diff --git a/third_party/WebKit/Source/core/paint/PaintLayer.h b/third_party/WebKit/Source/core/paint/PaintLayer.h
index b65e0f3..a1bc4ba9 100644
--- a/third_party/WebKit/Source/core/paint/PaintLayer.h
+++ b/third_party/WebKit/Source/core/paint/PaintLayer.h
@@ -683,18 +683,18 @@
 
   CompositingReasons PotentialCompositingReasonsFromStyle() const {
     return rare_data_ ? rare_data_->potential_compositing_reasons_from_style
-                      : kCompositingReasonNone;
+                      : CompositingReason::kNone;
   }
   void SetPotentialCompositingReasonsFromStyle(CompositingReasons reasons) {
     DCHECK(reasons ==
-           (reasons & kCompositingReasonComboAllStyleDeterminedReasons));
-    if (rare_data_ || reasons != kCompositingReasonNone)
+           (reasons & CompositingReason::kComboAllStyleDeterminedReasons));
+    if (rare_data_ || reasons != CompositingReason::kNone)
       EnsureRareData().potential_compositing_reasons_from_style = reasons;
   }
 
   bool HasStyleDeterminedDirectCompositingReasons() const {
     return PotentialCompositingReasonsFromStyle() &
-           kCompositingReasonComboAllDirectStyleDeterminedReasons;
+           CompositingReason::kComboAllDirectStyleDeterminedReasons;
   }
 
   class AncestorDependentCompositingInputs {
@@ -843,15 +843,15 @@
   CompositingReasons GetCompositingReasons() const {
     DCHECK(IsAllowedToQueryCompositingState());
     return rare_data_ ? rare_data_->compositing_reasons
-                      : kCompositingReasonNone;
+                      : CompositingReason::kNone;
   }
   void SetCompositingReasons(CompositingReasons,
-                             CompositingReasons mask = kCompositingReasonAll);
+                             CompositingReasons mask = CompositingReason::kAll);
 
   SquashingDisallowedReasons GetSquashingDisallowedReasons() const {
     DCHECK(IsAllowedToQueryCompositingState());
     return rare_data_ ? rare_data_->squashing_disallowed_reasons
-                      : kSquashingDisallowedReasonsNone;
+                      : SquashingDisallowedReason::kNone;
   }
   void SetSquashingDisallowedReasons(SquashingDisallowedReasons);
 
diff --git a/third_party/WebKit/Source/core/paint/PaintPropertyTreeBuilder.cpp b/third_party/WebKit/Source/core/paint/PaintPropertyTreeBuilder.cpp
index 8ba9a2e..d8b26393 100644
--- a/third_party/WebKit/Source/core/paint/PaintPropertyTreeBuilder.cpp
+++ b/third_party/WebKit/Source/core/paint/PaintPropertyTreeBuilder.cpp
@@ -134,12 +134,12 @@
   if (auto* existing_scroll_translation = frame_view.ScrollTranslation()) {
     existing_scroll_translation->Update(
         std::move(parent), matrix, FloatPoint3D(), false, 0,
-        kCompositingReasonNone, CompositorElementId(), std::move(scroll));
+        CompositingReason::kNone, CompositorElementId(), std::move(scroll));
     return false;
   }
   frame_view.SetScrollTranslation(TransformPaintPropertyNode::Create(
       std::move(parent), matrix, FloatPoint3D(), false, 0,
-      kCompositingReasonNone, CompositorElementId(), std::move(scroll)));
+      CompositingReason::kNone, CompositorElementId(), std::move(scroll)));
   return true;
 }
 
@@ -472,22 +472,22 @@
 
 static CompositingReasons CompositingReasonsForTransform(const LayoutBox& box) {
   const ComputedStyle& style = box.StyleRef();
-  CompositingReasons compositing_reasons = kCompositingReasonNone;
+  CompositingReasons compositing_reasons = CompositingReason::kNone;
   if (CompositingReasonFinder::RequiresCompositingForTransform(box))
-    compositing_reasons |= kCompositingReason3DTransform;
+    compositing_reasons |= CompositingReason::k3DTransform;
 
   if (CompositingReasonFinder::RequiresCompositingForTransformAnimation(style))
-    compositing_reasons |= kCompositingReasonActiveAnimation;
+    compositing_reasons |= CompositingReason::kActiveAnimation;
 
   if (style.HasWillChangeCompositingHint() &&
       !style.SubtreeWillChangeContents())
-    compositing_reasons |= kCompositingReasonWillChangeCompositingHint;
+    compositing_reasons |= CompositingReason::kWillChangeCompositingHint;
 
   if (box.HasLayer() && box.Layer()->Has3DTransformedDescendant()) {
     if (style.HasPerspective())
-      compositing_reasons |= kCompositingReasonPerspectiveWith3DDescendants;
+      compositing_reasons |= CompositingReason::kPerspectiveWith3DDescendants;
     if (style.UsedTransformStyle3D() == ETransformStyle3D::kPreserve3d)
-      compositing_reasons |= kCompositingReasonPreserve3DWith3DDescendants;
+      compositing_reasons |= CompositingReason::kPreserve3DWith3DDescendants;
   }
 
   return compositing_reasons;
@@ -510,7 +510,7 @@
     return false;
   return object.StyleRef().HasTransform() || object.StyleRef().Preserves3D() ||
          CompositingReasonsForTransform(ToLayoutBox(object)) !=
-             kCompositingReasonNone;
+             CompositingReason::kNone;
 }
 
 void FragmentPaintPropertyTreeBuilder::UpdateTransform() {
@@ -681,10 +681,10 @@
       // We may begin to composite our subtree prior to an animation starts,
       // but a compositor element ID is only needed when an animation is
       // current.
-      CompositingReasons compositing_reasons = kCompositingReasonNone;
+      CompositingReasons compositing_reasons = CompositingReason::kNone;
       if (CompositingReasonFinder::RequiresCompositingForOpacityAnimation(
               style)) {
-        compositing_reasons = kCompositingReasonActiveAnimation;
+        compositing_reasons = CompositingReason::kActiveAnimation;
       }
 
       IntRect mask_clip;
@@ -726,7 +726,7 @@
         auto result = properties_->UpdateMask(
             properties_->Effect(), context_.current.transform, output_clip,
             mask_color_filter, CompositorFilterOperations(), 1.f,
-            SkBlendMode::kDstIn, kCompositingReasonNone,
+            SkBlendMode::kDstIn, CompositingReason::kNone,
             CompositorElementIdFromUniqueObjectId(
                 object_.UniqueId(), CompositorElementIdNamespace::kEffectMask));
         full_context_.force_subtree_update |= result.NewNodeCreated();
@@ -802,10 +802,10 @@
       // current.
       CompositingReasons compositing_reasons =
           CompositingReasonFinder::RequiresCompositingForFilterAnimation(style)
-              ? kCompositingReasonActiveAnimation
-              : kCompositingReasonNone;
+              ? CompositingReason::kActiveAnimation
+              : CompositingReason::kNone;
       DCHECK(!style.HasCurrentFilterAnimation() ||
-             compositing_reasons != kCompositingReasonNone);
+             compositing_reasons != CompositingReason::kNone);
 
       auto result = properties_->UpdateFilter(
           context_.current_effect, context_.current.transform, output_clip,
@@ -1186,7 +1186,7 @@
       auto result = properties_->UpdateScrollTranslation(
           context_.current.transform, scroll_offset_matrix, FloatPoint3D(),
           context_.current.should_flatten_inherited_transform,
-          context_.current.rendering_context_id, kCompositingReasonNone,
+          context_.current.rendering_context_id, CompositingReason::kNone,
           CompositorElementId(), properties_->Scroll());
       full_context_.force_subtree_update |= result.NewNodeCreated();
     } else {
diff --git a/third_party/WebKit/Source/core/paint/compositing/CompositedLayerMapping.cpp b/third_party/WebKit/Source/core/paint/compositing/CompositedLayerMapping.cpp
index ec91ffc..4a0e48f 100644
--- a/third_party/WebKit/Source/core/paint/compositing/CompositedLayerMapping.cpp
+++ b/third_party/WebKit/Source/core/paint/compositing/CompositedLayerMapping.cpp
@@ -499,7 +499,7 @@
 void CompositedLayerMapping::UpdateRasterizationPolicy() {
   bool transformed_rasterization_allowed =
       !(owning_layer_.GetCompositingReasons() &
-        kCompositingReasonComboAllDirectReasons);
+        CompositingReason::kComboAllDirectReasons);
   graphics_layer_->ContentLayer()->SetTransformedRasterizationAllowed(
       transformed_rasterization_allowed);
   if (squashing_layer_)
@@ -968,7 +968,7 @@
     if (RuntimeEnabledFeatures::PaintUnderInvalidationCheckingEnabled())
       SetContentsNeedDisplay();
     else if (!(owning_layer_.GetCompositingReasons() &
-               kCompositingReasonComboAllDirectReasons))
+               CompositingReason::kComboAllDirectReasons))
       SetContentsNeedDisplay();
   }
 
@@ -1990,7 +1990,7 @@
   if (needs_ancestor_clip) {
     if (!ancestor_clipping_layer_) {
       ancestor_clipping_layer_ =
-          CreateGraphicsLayer(kCompositingReasonLayerForAncestorClip);
+          CreateGraphicsLayer(CompositingReason::kLayerForAncestorClip);
       ancestor_clipping_layer_->SetMasksToBounds(true);
       ancestor_clipping_layer_->SetShouldFlattenTransform(false);
       layers_changed = true;
@@ -2009,7 +2009,7 @@
     DCHECK(ancestor_clipping_layer_);
     if (!ancestor_clipping_mask_layer_) {
       ancestor_clipping_mask_layer_ =
-          CreateGraphicsLayer(kCompositingReasonLayerForAncestorClippingMask);
+          CreateGraphicsLayer(CompositingReason::kLayerForAncestorClippingMask);
       ancestor_clipping_mask_layer_->SetPaintingPhase(
           kGraphicsLayerPaintAncestorClippingMask);
       ancestor_clipping_layer_->SetMaskLayer(
@@ -2029,7 +2029,7 @@
     // clipping.
     if (!child_containment_layer_ && !is_main_frame_layout_view_layer_) {
       child_containment_layer_ =
-          CreateGraphicsLayer(kCompositingReasonLayerForDescendantClip);
+          CreateGraphicsLayer(CompositingReason::kLayerForDescendantClip);
       child_containment_layer_->SetMasksToBounds(true);
       layers_changed = true;
     }
@@ -2049,7 +2049,7 @@
   if (needs_child_transform_layer) {
     if (!child_transform_layer_) {
       child_transform_layer_ =
-          CreateGraphicsLayer(kCompositingReasonLayerForPerspective);
+          CreateGraphicsLayer(CompositingReason::kLayerForPerspective);
       child_transform_layer_->SetDrawsContent(false);
       layers_changed = true;
     }
@@ -2080,10 +2080,10 @@
           owning_layer_.GetScrollableArea()) {
     if (ScrollingCoordinator* scrolling_coordinator =
             owning_layer_.GetScrollingCoordinator()) {
-      if (reason == kCompositingReasonLayerForHorizontalScrollbar) {
+      if (reason == CompositingReason::kLayerForHorizontalScrollbar) {
         scrolling_coordinator->ScrollableAreaScrollbarLayerDidChange(
             scrollable_area, kHorizontalScrollbar);
-      } else if (reason == kCompositingReasonLayerForVerticalScrollbar) {
+      } else if (reason == CompositingReason::kLayerForVerticalScrollbar) {
         scrolling_coordinator->ScrollableAreaScrollbarLayerDidChange(
             scrollable_area, kVerticalScrollbar);
       }
@@ -2105,12 +2105,13 @@
         scrollable_area->ShouldRebuildHorizontalScrollbarLayer()) {
       ToggleScrollbarLayerIfNeeded(
           layer_for_horizontal_scrollbar_, false,
-          kCompositingReasonLayerForHorizontalScrollbar);
+          CompositingReason::kLayerForHorizontalScrollbar);
     }
     if (layer_for_vertical_scrollbar_ && needs_vertical_scrollbar_layer &&
         scrollable_area->ShouldRebuildVerticalScrollbarLayer()) {
-      ToggleScrollbarLayerIfNeeded(layer_for_vertical_scrollbar_, false,
-                                   kCompositingReasonLayerForVerticalScrollbar);
+      ToggleScrollbarLayerIfNeeded(
+          layer_for_vertical_scrollbar_, false,
+          CompositingReason::kLayerForVerticalScrollbar);
     }
     scrollable_area->ResetRebuildScrollbarLayerFlags();
 
@@ -2136,25 +2137,26 @@
 
   bool horizontal_scrollbar_layer_changed = ToggleScrollbarLayerIfNeeded(
       layer_for_horizontal_scrollbar_, needs_horizontal_scrollbar_layer,
-      kCompositingReasonLayerForHorizontalScrollbar);
+      CompositingReason::kLayerForHorizontalScrollbar);
   bool vertical_scrollbar_layer_changed = ToggleScrollbarLayerIfNeeded(
       layer_for_vertical_scrollbar_, needs_vertical_scrollbar_layer,
-      kCompositingReasonLayerForVerticalScrollbar);
+      CompositingReason::kLayerForVerticalScrollbar);
   bool scroll_corner_layer_changed = ToggleScrollbarLayerIfNeeded(
       layer_for_scroll_corner_, needs_scroll_corner_layer,
-      kCompositingReasonLayerForScrollCorner);
+      CompositingReason::kLayerForScrollCorner);
 
   bool needs_overflow_controls_host_layer = needs_horizontal_scrollbar_layer ||
                                             needs_vertical_scrollbar_layer ||
                                             needs_scroll_corner_layer;
-  ToggleScrollbarLayerIfNeeded(overflow_controls_host_layer_,
-                               needs_overflow_controls_host_layer,
-                               kCompositingReasonLayerForOverflowControlsHost);
+  ToggleScrollbarLayerIfNeeded(
+      overflow_controls_host_layer_, needs_overflow_controls_host_layer,
+      CompositingReason::kLayerForOverflowControlsHost);
   bool needs_overflow_ancestor_clip_layer =
       needs_overflow_controls_host_layer && needs_ancestor_clip;
-  ToggleScrollbarLayerIfNeeded(overflow_controls_ancestor_clipping_layer_,
-                               needs_overflow_ancestor_clip_layer,
-                               kCompositingReasonLayerForOverflowControlsHost);
+  ToggleScrollbarLayerIfNeeded(
+      overflow_controls_ancestor_clipping_layer_,
+      needs_overflow_ancestor_clip_layer,
+      CompositingReason::kLayerForOverflowControlsHost);
 
   return horizontal_scrollbar_layer_changed ||
          vertical_scrollbar_layer_changed || scroll_corner_layer_changed;
@@ -2390,7 +2392,7 @@
   if (needs_foreground_layer) {
     if (!foreground_layer_) {
       foreground_layer_ =
-          CreateGraphicsLayer(kCompositingReasonLayerForForeground);
+          CreateGraphicsLayer(CompositingReason::kLayerForForeground);
       foreground_layer_->SetHitTestableWithoutDrawsContent(true);
       layer_changed = true;
     }
@@ -2409,7 +2411,7 @@
   if (needs_background_layer) {
     if (!background_layer_) {
       background_layer_ =
-          CreateGraphicsLayer(kCompositingReasonLayerForBackground);
+          CreateGraphicsLayer(CompositingReason::kLayerForBackground);
       background_layer_->SetTransformOrigin(FloatPoint3D());
       background_layer_->SetPaintingPhase(kGraphicsLayerPaintBackground);
       layer_changed = true;
@@ -2435,7 +2437,7 @@
   if (needs_decoration_outline_layer) {
     if (!decoration_outline_layer_) {
       decoration_outline_layer_ =
-          CreateGraphicsLayer(kCompositingReasonLayerForDecoration);
+          CreateGraphicsLayer(CompositingReason::kLayerForDecoration);
       decoration_outline_layer_->SetPaintingPhase(
           kGraphicsLayerPaintDecoration);
       layer_changed = true;
@@ -2452,7 +2454,7 @@
   bool layer_changed = false;
   if (needs_mask_layer) {
     if (!mask_layer_) {
-      mask_layer_ = CreateGraphicsLayer(kCompositingReasonLayerForMask);
+      mask_layer_ = CreateGraphicsLayer(CompositingReason::kLayerForMask);
       mask_layer_->SetPaintingPhase(kGraphicsLayerPaintMask);
       layer_changed = true;
     }
@@ -2469,7 +2471,7 @@
   if (needs_child_clipping_mask_layer) {
     if (!child_clipping_mask_layer_) {
       child_clipping_mask_layer_ =
-          CreateGraphicsLayer(kCompositingReasonLayerForClippingMask);
+          CreateGraphicsLayer(CompositingReason::kLayerForClippingMask);
       child_clipping_mask_layer_->SetPaintingPhase(
           kGraphicsLayerPaintChildClippingMask);
     }
@@ -2495,13 +2497,13 @@
     } else {
       // Outer layer which corresponds with the scroll view.
       scrolling_layer_ =
-          CreateGraphicsLayer(kCompositingReasonLayerForScrollingContainer);
+          CreateGraphicsLayer(CompositingReason::kLayerForScrollingContainer);
       scrolling_layer_->SetDrawsContent(false);
       scrolling_layer_->SetMasksToBounds(true);
 
       // Inner layer which renders the content that scrolls.
       scrolling_contents_layer_ =
-          CreateGraphicsLayer(kCompositingReasonLayerForScrollingContents);
+          CreateGraphicsLayer(CompositingReason::kLayerForScrollingContents);
       scrolling_contents_layer_->SetHitTestableWithoutDrawsContent(true);
 
       auto element_id = scrollable_area->GetCompositorElementId();
@@ -2638,7 +2640,7 @@
   if (needs_squashing_layers) {
     if (!squashing_layer_) {
       squashing_layer_ =
-          CreateGraphicsLayer(kCompositingReasonLayerForSquashingContents);
+          CreateGraphicsLayer(CompositingReason::kLayerForSquashingContents);
       squashing_layer_->SetDrawsContent(true);
       layers_changed = true;
     }
@@ -2652,7 +2654,7 @@
     } else {
       if (!squashing_containment_layer_) {
         squashing_containment_layer_ =
-            CreateGraphicsLayer(kCompositingReasonLayerForSquashingContainer);
+            CreateGraphicsLayer(CompositingReason::kLayerForSquashingContainer);
         squashing_containment_layer_->SetShouldFlattenTransform(false);
         layers_changed = true;
       }
diff --git a/third_party/WebKit/Source/core/paint/compositing/CompositedLayerMapping.h b/third_party/WebKit/Source/core/paint/compositing/CompositedLayerMapping.h
index 636c9cea..2ac8305 100644
--- a/third_party/WebKit/Source/core/paint/compositing/CompositedLayerMapping.h
+++ b/third_party/WebKit/Source/core/paint/compositing/CompositedLayerMapping.h
@@ -376,7 +376,7 @@
 
   std::unique_ptr<GraphicsLayer> CreateGraphicsLayer(
       CompositingReasons,
-      SquashingDisallowedReasons = kSquashingDisallowedReasonsNone);
+      SquashingDisallowedReasons = SquashingDisallowedReason::kNone);
   bool ToggleScrollbarLayerIfNeeded(std::unique_ptr<GraphicsLayer>&,
                                     bool needs_layer,
                                     CompositingReasons);
diff --git a/third_party/WebKit/Source/core/paint/compositing/CompositingLayerAssigner.cpp b/third_party/WebKit/Source/core/paint/compositing/CompositingLayerAssigner.cpp
index 6ba15f2..8b2267a 100644
--- a/third_party/WebKit/Source/core/paint/compositing/CompositingLayerAssigner.cpp
+++ b/third_party/WebKit/Source/core/paint/compositing/CompositingLayerAssigner.cpp
@@ -127,7 +127,7 @@
     const PaintLayer* layer,
     const CompositingLayerAssigner::SquashingState& squashing_state) {
   if (!squashing_state.have_assigned_backings_to_entire_squashing_layer_subtree)
-    return kSquashingDisallowedReasonWouldBreakPaintOrder;
+    return SquashingDisallowedReason::kWouldBreakPaintOrder;
 
   DCHECK(squashing_state.has_most_recent_mapping);
   const PaintLayer& squashing_layer =
@@ -142,21 +142,23 @@
   // compositing/video/video-controls-layer-creation.html
   if (layer->GetLayoutObject().IsVideo() ||
       squashing_layer.GetLayoutObject().IsVideo())
-    return kSquashingDisallowedReasonSquashingVideoIsDisallowed;
+    return SquashingDisallowedReason::kSquashingVideoIsDisallowed;
 
   // Don't squash iframes, frames or plugins.
   // FIXME: this is only necessary because there is frame code that assumes that
   // composited frames are not squashed.
   if (layer->GetLayoutObject().IsLayoutEmbeddedContent() ||
-      squashing_layer.GetLayoutObject().IsLayoutEmbeddedContent())
-    return kSquashingDisallowedReasonSquashingLayoutEmbeddedContentIsDisallowed;
+      squashing_layer.GetLayoutObject().IsLayoutEmbeddedContent()) {
+    return SquashingDisallowedReason::
+        kSquashingLayoutEmbeddedContentIsDisallowed;
+  }
 
   if (SquashingWouldExceedSparsityTolerance(layer, squashing_state))
-    return kSquashingDisallowedReasonSquashingSparsityExceeded;
+    return SquashingDisallowedReason::kSquashingSparsityExceeded;
 
   if (layer->GetLayoutObject().Style()->HasBlendMode() ||
       squashing_layer.GetLayoutObject().Style()->HasBlendMode())
-    return kSquashingDisallowedReasonSquashingBlendingIsDisallowed;
+    return SquashingDisallowedReason::kSquashingBlendingIsDisallowed;
 
   // FIXME: this is not efficient, since it walks up the tree. We should store
   // these values on the CompositingInputsCache.
@@ -164,36 +166,36 @@
       !squashing_layer.GetCompositedLayerMapping()->ContainingSquashedLayer(
           layer->ClippingContainer(),
           squashing_state.next_squashed_layer_index))
-    return kSquashingDisallowedReasonClippingContainerMismatch;
+    return SquashingDisallowedReason::kClippingContainerMismatch;
 
   // Composited descendants need to be clipped by a child containment graphics
   // layer, which would not be available if the layer is squashed (and therefore
   // has no CLM nor a child containment graphics layer).
   if (compositor_->ClipsCompositingDescendants(layer))
-    return kSquashingDisallowedReasonSquashedLayerClipsCompositingDescendants;
+    return SquashingDisallowedReason::kSquashedLayerClipsCompositingDescendants;
 
   if (layer->ScrollsWithRespectTo(&squashing_layer))
-    return kSquashingDisallowedReasonScrollsWithRespectToSquashingLayer;
+    return SquashingDisallowedReason::kScrollsWithRespectToSquashingLayer;
 
   if (layer->ScrollParent() && layer->HasCompositingDescendant())
-    return kSquashingDisallowedReasonScrollChildWithCompositedDescendants;
+    return SquashingDisallowedReason::kScrollChildWithCompositedDescendants;
 
   if (layer->OpacityAncestor() != squashing_layer.OpacityAncestor())
-    return kSquashingDisallowedReasonOpacityAncestorMismatch;
+    return SquashingDisallowedReason::kOpacityAncestorMismatch;
 
   if (layer->TransformAncestor() != squashing_layer.TransformAncestor())
-    return kSquashingDisallowedReasonTransformAncestorMismatch;
+    return SquashingDisallowedReason::kTransformAncestorMismatch;
 
   if (layer->RenderingContextRoot() != squashing_layer.RenderingContextRoot())
-    return kSquashingDisallowedReasonRenderingContextMismatch;
+    return SquashingDisallowedReason::kRenderingContextMismatch;
 
   if (layer->HasFilterInducingProperty() ||
       layer->FilterAncestor() != squashing_layer.FilterAncestor())
-    return kSquashingDisallowedReasonFilterMismatch;
+    return SquashingDisallowedReason::kFilterMismatch;
 
   if (layer->NearestFixedPositionLayer() !=
       squashing_layer.NearestFixedPositionLayer())
-    return kSquashingDisallowedReasonNearestFixedPositionMismatch;
+    return SquashingDisallowedReason::kNearestFixedPositionMismatch;
   DCHECK_NE(layer->GetLayoutObject().Style()->GetPosition(), EPosition::kFixed);
 
   if ((squashing_layer.GetLayoutObject().Style()->SubtreeWillChangeContents() &&
@@ -203,12 +205,12 @@
       squashing_layer.GetLayoutObject()
           .Style()
           ->ShouldCompositeForCurrentAnimations())
-    return kSquashingDisallowedReasonSquashingLayerIsAnimating;
+    return SquashingDisallowedReason::kSquashingLayerIsAnimating;
 
   if (layer->EnclosingPaginationLayer())
-    return kSquashingDisallowedReasonFragmentedContent;
+    return SquashingDisallowedReason::kFragmentedContent;
 
-  return kSquashingDisallowedReasonsNone;
+  return SquashingDisallowedReason::kNone;
 }
 
 void CompositingLayerAssigner::UpdateSquashingAssignment(
@@ -280,7 +282,7 @@
         GetReasonsPreventingSquashing(layer, squashing_state);
     if (reasons_preventing_squashing) {
       layer->SetCompositingReasons(layer->GetCompositingReasons() |
-                                   kCompositingReasonSquashingDisallowed);
+                                   CompositingReason::kSquashingDisallowed);
       layer->SetSquashingDisallowedReasons(reasons_preventing_squashing);
     }
   }
diff --git a/third_party/WebKit/Source/core/paint/compositing/CompositingReasonFinder.cpp b/third_party/WebKit/Source/core/paint/compositing/CompositingReasonFinder.cpp
index f2c6d25e..0f1db1d 100644
--- a/third_party/WebKit/Source/core/paint/compositing/CompositingReasonFinder.cpp
+++ b/third_party/WebKit/Source/core/paint/compositing/CompositingReasonFinder.cpp
@@ -41,13 +41,13 @@
     const PaintLayer* layer,
     bool ignore_lcd_text) const {
   if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled())
-    return kCompositingReasonNone;
+    return CompositingReason::kNone;
 
   DCHECK_EQ(PotentialCompositingReasonsFromStyle(layer->GetLayoutObject()),
             layer->PotentialCompositingReasonsFromStyle());
   CompositingReasons style_determined_direct_compositing_reasons =
       layer->PotentialCompositingReasonsFromStyle() &
-      kCompositingReasonComboAllDirectStyleDeterminedReasons;
+      CompositingReason::kComboAllDirectStyleDeterminedReasons;
 
   return style_determined_direct_compositing_reasons |
          NonStyleDeterminedDirectReasons(layer, ignore_lcd_text);
@@ -70,33 +70,33 @@
 CompositingReasonFinder::PotentialCompositingReasonsFromStyle(
     LayoutObject& layout_object) const {
   if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled())
-    return kCompositingReasonNone;
+    return CompositingReason::kNone;
 
-  CompositingReasons reasons = kCompositingReasonNone;
+  CompositingReasons reasons = CompositingReason::kNone;
 
   const ComputedStyle& style = layout_object.StyleRef();
 
   if (RequiresCompositingForTransform(layout_object))
-    reasons |= kCompositingReason3DTransform;
+    reasons |= CompositingReason::k3DTransform;
 
   if (style.BackfaceVisibility() == EBackfaceVisibility::kHidden)
-    reasons |= kCompositingReasonBackfaceVisibilityHidden;
+    reasons |= CompositingReason::kBackfaceVisibilityHidden;
 
   if (RequiresCompositingForAnimation(style))
-    reasons |= kCompositingReasonActiveAnimation;
+    reasons |= CompositingReason::kActiveAnimation;
 
   if (style.HasWillChangeCompositingHint() &&
       !style.SubtreeWillChangeContents())
-    reasons |= kCompositingReasonWillChangeCompositingHint;
+    reasons |= CompositingReason::kWillChangeCompositingHint;
 
   if (style.HasInlineTransform())
-    reasons |= kCompositingReasonInlineTransform;
+    reasons |= CompositingReason::kInlineTransform;
 
   if (style.UsedTransformStyle3D() == ETransformStyle3D::kPreserve3d)
-    reasons |= kCompositingReasonPreserve3DWith3DDescendants;
+    reasons |= CompositingReason::kPreserve3DWith3DDescendants;
 
   if (style.HasPerspective())
-    reasons |= kCompositingReasonPerspectiveWith3DDescendants;
+    reasons |= CompositingReason::kPerspectiveWith3DDescendants;
 
   // If the implementation of createsGroup changes, we need to be aware of that
   // in this part of code.
@@ -105,28 +105,28 @@
          layout_object.CreatesGroup());
 
   if (style.HasMask())
-    reasons |= kCompositingReasonMaskWithCompositedDescendants;
+    reasons |= CompositingReason::kMaskWithCompositedDescendants;
 
   if (style.HasFilterInducingProperty())
-    reasons |= kCompositingReasonFilterWithCompositedDescendants;
+    reasons |= CompositingReason::kFilterWithCompositedDescendants;
 
   if (style.HasBackdropFilter())
-    reasons |= kCompositingReasonBackdropFilter;
+    reasons |= CompositingReason::kBackdropFilter;
 
   // See Layer::updateTransform for an explanation of why we check both.
   if (layout_object.HasTransformRelatedProperty() && style.HasTransform())
-    reasons |= kCompositingReasonTransformWithCompositedDescendants;
+    reasons |= CompositingReason::kTransformWithCompositedDescendants;
 
   if (layout_object.IsTransparent())
-    reasons |= kCompositingReasonOpacityWithCompositedDescendants;
+    reasons |= CompositingReason::kOpacityWithCompositedDescendants;
 
   if (style.HasBlendMode())
-    reasons |= kCompositingReasonBlendingWithCompositedDescendants;
+    reasons |= CompositingReason::kBlendingWithCompositedDescendants;
 
   if (layout_object.HasReflection())
-    reasons |= kCompositingReasonReflectionWithCompositedDescendants;
+    reasons |= CompositingReason::kReflectionWithCompositedDescendants;
 
-  DCHECK(!(reasons & ~kCompositingReasonComboAllStyleDeterminedReasons));
+  DCHECK(!(reasons & ~CompositingReason::kComboAllStyleDeterminedReasons));
   return reasons;
 }
 
@@ -142,37 +142,38 @@
 CompositingReasons CompositingReasonFinder::NonStyleDeterminedDirectReasons(
     const PaintLayer* layer,
     bool ignore_lcd_text) const {
-  CompositingReasons direct_reasons = kCompositingReasonNone;
+  CompositingReasons direct_reasons = CompositingReason::kNone;
   LayoutObject& layout_object = layer->GetLayoutObject();
 
   // TODO(chrishtr): remove this hammer in favor of something more targeted.
   // See crbug.com/749349.
   if (layer->ClipParent() && layer->GetLayoutObject().IsOutOfFlowPositioned())
-    direct_reasons |= kCompositingReasonOutOfFlowClipping;
+    direct_reasons |= CompositingReason::kOutOfFlowClipping;
 
   if (layer->NeedsCompositedScrolling())
-    direct_reasons |= kCompositingReasonOverflowScrollingTouch;
+    direct_reasons |= CompositingReason::kOverflowScrollingTouch;
 
   // When RLS is disabled, the root layer may be the root scroller but
   // the FrameView/Compositor handles its scrolling so there's no need to
   // composite it.
   if (RootScrollerUtil::IsGlobal(*layer) && !layer->IsScrolledByFrameView())
-    direct_reasons |= kCompositingReasonRootScroller;
+    direct_reasons |= CompositingReason::kRootScroller;
 
   // Composite |layer| if it is inside of an ancestor scrolling layer, but that
   // scrolling layer is not on the stacking context ancestor chain of |layer|.
   // See the definition of the scrollParent property in Layer for more detail.
   if (const PaintLayer* scrolling_ancestor = layer->AncestorScrollingLayer()) {
     if (scrolling_ancestor->NeedsCompositedScrolling() && layer->ScrollParent())
-      direct_reasons |= kCompositingReasonOverflowScrollingParent;
+      direct_reasons |= CompositingReason::kOverflowScrollingParent;
   }
 
   if (RequiresCompositingForScrollDependentPosition(layer, ignore_lcd_text))
-    direct_reasons |= kCompositingReasonScrollDependentPosition;
+    direct_reasons |= CompositingReason::kScrollDependentPosition;
 
   direct_reasons |= layout_object.AdditionalCompositingReasons();
 
-  DCHECK(!(direct_reasons & kCompositingReasonComboAllStyleDeterminedReasons));
+  DCHECK(
+      !(direct_reasons & CompositingReason::kComboAllStyleDeterminedReasons));
   return direct_reasons;
 }
 
diff --git a/third_party/WebKit/Source/core/paint/compositing/CompositingRequirementsUpdater.cpp b/third_party/WebKit/Source/core/paint/compositing/CompositingRequirementsUpdater.cpp
index 5c703e9..b06a753 100644
--- a/third_party/WebKit/Source/core/paint/compositing/CompositingRequirementsUpdater.cpp
+++ b/third_party/WebKit/Source/core/paint/compositing/CompositingRequirementsUpdater.cpp
@@ -158,11 +158,11 @@
 
 static bool RequiresCompositingOrSquashing(CompositingReasons reasons) {
 #if DCHECK_IS_ON()
-  bool fast_answer = reasons != kCompositingReasonNone;
+  bool fast_answer = reasons != CompositingReason::kNone;
   bool slow_answer = RequiresCompositing(reasons) || RequiresSquashing(reasons);
   DCHECK_EQ(slow_answer, fast_answer);
 #endif
-  return reasons != kCompositingReasonNone;
+  return reasons != CompositingReason::kNone;
 }
 
 static CompositingReasons SubtreeReasonsForCompositing(
@@ -170,18 +170,18 @@
     PaintLayer* layer,
     bool has_composited_descendants,
     bool has3d_transformed_descendants) {
-  CompositingReasons subtree_reasons = kCompositingReasonNone;
+  CompositingReasons subtree_reasons = CompositingReason::kNone;
 
   // When a layer has composited descendants, some effects, like 2d transforms,
   // filters, masks etc must be implemented via compositing so that they also
   // apply to those composited descendants.
   if (has_composited_descendants) {
     subtree_reasons |= layer->PotentialCompositingReasonsFromStyle() &
-                       kCompositingReasonComboCompositedDescendants;
+                       CompositingReason::kComboCompositedDescendants;
 
     if (layer->ShouldIsolateCompositedDescendants()) {
       DCHECK(layer->StackingNode()->IsStackingContext());
-      subtree_reasons |= kCompositingReasonIsolateCompositedDescendants;
+      subtree_reasons |= CompositingReason::kIsolateCompositedDescendants;
     }
 
     // FIXME: This should move into
@@ -189,7 +189,7 @@
     // a poor interaction with LayoutTextControlSingleLine, which sets this
     // hasOverflowClip directly.
     if (layer->GetLayoutObject().HasClipRelatedProperty())
-      subtree_reasons |= kCompositingReasonClipsCompositingDescendants;
+      subtree_reasons |= CompositingReason::kClipsCompositingDescendants;
 
     // We ignore LCD text here because we are required to composite
     // scroll-dependant fixed position elements with composited descendants for
@@ -201,7 +201,7 @@
         compositing_reason_finder.RequiresCompositingForScrollDependentPosition(
             layer, ignore_lcd_text)) {
       subtree_reasons |=
-          kCompositingReasonPositionFixedOrStickyWithCompositedDescendants;
+          CompositingReason::kPositionFixedOrStickyWithCompositedDescendants;
     }
   }
 
@@ -210,7 +210,7 @@
   // perspective.
   if (has3d_transformed_descendants) {
     subtree_reasons |= layer->PotentialCompositingReasonsFromStyle() &
-                       kCompositingReasonCombo3DDescendants;
+                       CompositingReason::kCombo3DDescendants;
   }
 
   return subtree_reasons;
@@ -267,7 +267,7 @@
     // support it with grayscale AA text.
     layer->GetScrollableArea()->UpdateNeedsCompositedScrolling(true);
     if (layer->NeedsCompositedScrolling())
-      reasons |= kCompositingReasonOverflowScrollingTouch;
+      reasons |= CompositingReason::kOverflowScrollingTouch;
   }
 }
 
@@ -284,8 +284,8 @@
 
   layer->StackingNode()->UpdateLayerListsIfNeeded();
 
-  CompositingReasons reasons_to_composite = kCompositingReasonNone;
-  CompositingReasons direct_reasons = kCompositingReasonNone;
+  CompositingReasons reasons_to_composite = CompositingReason::kNone;
+  CompositingReasons direct_reasons = CompositingReason::kNone;
 
   // Video is special. It's the only PaintLayer type that can both have
   // PaintLayer children and whose children can't use its backing to render
@@ -293,13 +293,13 @@
   // own layers to draw on top of the accelerated video.
   if (current_recursion_data.compositing_ancestor_ &&
       current_recursion_data.compositing_ancestor_->GetLayoutObject().IsVideo())
-    direct_reasons |= kCompositingReasonVideoOverlay;
+    direct_reasons |= CompositingReason::kVideoOverlay;
 
   bool has_composited_scrolling_ancestor =
       layer->AncestorScrollingLayer() &&
       (compositing_reason_finder_.DirectReasons(layer->AncestorScrollingLayer(),
                                                 false) &
-       kCompositingReasonOverflowScrollingTouch);
+       CompositingReason::kOverflowScrollingTouch);
 
   bool use_clipped_bounding_rect =
       !has_composited_scrolling_ancestor ||
@@ -326,12 +326,12 @@
     reasons_to_composite |= direct_reasons;
 
     if (layer->IsRootLayer() && compositor->RootShouldAlwaysComposite())
-      reasons_to_composite |= kCompositingReasonRoot;
+      reasons_to_composite |= CompositingReason::kRoot;
 
     MaybeEnableCompositedScrolling(layer, reasons_to_composite);
   }
 
-  if ((reasons_to_composite & kCompositingReasonOverflowScrollingTouch) &&
+  if ((reasons_to_composite & CompositingReason::kOverflowScrollingTouch) &&
       !layer->IsRootLayer())
     current_recursion_data.has_composited_scrolling_ancestor_ = true;
 
@@ -341,8 +341,8 @@
   // composited behind us in paint-order.
   CompositingReasons overlap_compositing_reason =
       current_recursion_data.subtree_is_compositing_
-          ? kCompositingReasonAssumedOverlap
-          : kCompositingReasonNone;
+          ? CompositingReason::kAssumedOverlap
+          : CompositingReason::kNone;
 
   // TODO(chrishtr): use |hasCompositedScrollingAncestor| instead.
   if (current_recursion_data.has_composited_scrolling_ancestor_) {
@@ -359,7 +359,7 @@
         continue;
       }
       if (layer->ScrollsWithRespectTo(unclipped_descendant))
-        reasons_to_composite |= kCompositingReasonAssumedOverlap;
+        reasons_to_composite |= CompositingReason::kAssumedOverlap;
     }
 
     // Remove irrelevant unclipped descendants in reverse order so our stored
@@ -369,7 +369,7 @@
           unclipped_descendants_to_remove.size() - i - 1));
     }
 
-    if (reasons_to_composite & kCompositingReasonOutOfFlowClipping) {
+    if (reasons_to_composite & CompositingReason::kOutOfFlowClipping) {
       // TODO(schenney): We only need to promote when the clipParent is not a
       // descendant of the ancestor scroller, which we do not check for here.
       // Hence we might be promoting needlessly.
@@ -386,7 +386,7 @@
     bool overlaps =
         overlap_map.OverlapsLayers(abs_bounds, use_clipped_bounding_rect);
     overlap_compositing_reason =
-        overlaps ? kCompositingReasonOverlap : kCompositingReasonNone;
+        overlaps ? CompositingReason::kOverlap : CompositingReason::kNone;
   }
 
   reasons_to_composite |= overlap_compositing_reason;
@@ -436,7 +436,7 @@
       // a contents layer (since we need to ensure that the -ve z-order child
       // renders underneath our contents).
       if (child_recursion_data.subtree_is_compositing_) {
-        reasons_to_composite |= kCompositingReasonNegativeZIndexChildren;
+        reasons_to_composite |= CompositingReason::kNegativeZIndexChildren;
 
         if (!will_be_composited_or_squashed) {
           // make layer compositing
@@ -511,7 +511,7 @@
     if (child_recursion_data.subtree_is_compositing_ ||
         RequiresCompositingOrSquashing(reasons_to_composite) ||
         compositor->RootShouldAlwaysComposite()) {
-      reasons_to_composite |= kCompositingReasonRoot;
+      reasons_to_composite |= CompositingReason::kRoot;
       current_recursion_data.subtree_is_compositing_ = true;
       // Try again to enable composited scrolling if root became composited due
       // to subtree_is_compositing_ or overlap.
@@ -522,7 +522,7 @@
       MaybeEnableCompositedScrolling(layer, reasons_to_composite);
     } else {
       compositor->SetCompositingModeEnabled(false);
-      reasons_to_composite = kCompositingReasonNone;
+      reasons_to_composite = CompositingReason::kNone;
     }
   } else {
     // All layers (even ones that aren't being composited) need to get added to
@@ -555,7 +555,7 @@
 
     if (will_be_composited_or_squashed) {
       reasons_to_composite |= layer->PotentialCompositingReasonsFromStyle() &
-                              kCompositingReasonInlineTransform;
+                              CompositingReason::kInlineTransform;
     }
 
     if (will_be_composited_or_squashed &&
@@ -574,10 +574,10 @@
     // parent layers. That's because we know for sure the animation is contained
     // inside the clipping rectangle, which is already added to the overlap map.
     bool is_composited_clipping_layer =
-        can_be_composited &&
-        (reasons_to_composite & kCompositingReasonClipsCompositingDescendants);
+        can_be_composited && (reasons_to_composite &
+                              CompositingReason::kClipsCompositingDescendants);
     bool is_composited_with_inline_transform =
-        reasons_to_composite & kCompositingReasonInlineTransform;
+        reasons_to_composite & CompositingReason::kInlineTransform;
     if ((!child_recursion_data.testing_overlap_ &&
          !is_composited_clipping_layer) ||
         layer->GetLayoutObject().Style()->HasCurrentTransformAnimation() ||
@@ -594,15 +594,15 @@
   // At this point we have finished collecting all reasons to composite this
   // layer.
   layer->SetCompositingReasons(reasons_to_composite);
-  if (reasons_to_composite & kCompositingReasonOverlap)
+  if (reasons_to_composite & CompositingReason::kOverlap)
     compositing_reasons_stats.overlap_layers++;
-  if (reasons_to_composite & kCompositingReasonActiveAnimation)
+  if (reasons_to_composite & CompositingReason::kActiveAnimation)
     compositing_reasons_stats.active_animation_layers++;
-  if (reasons_to_composite & kCompositingReasonAssumedOverlap)
+  if (reasons_to_composite & CompositingReason::kAssumedOverlap)
     compositing_reasons_stats.assumed_overlap_layers++;
-  if (!(reasons_to_composite & kCompositingReasonComboAllDirectReasons))
+  if (!(reasons_to_composite & CompositingReason::kComboAllDirectReasons))
     compositing_reasons_stats.indirect_composited_layers++;
-  if (reasons_to_composite != kCompositingReasonNone)
+  if (reasons_to_composite != CompositingReason::kNone)
     compositing_reasons_stats.total_composited_layers++;
 }
 
diff --git a/third_party/WebKit/Source/core/style/CachedUAStyle.h b/third_party/WebKit/Source/core/style/CachedUAStyle.h
index f5c5401..53a51231 100644
--- a/third_party/WebKit/Source/core/style/CachedUAStyle.h
+++ b/third_party/WebKit/Source/core/style/CachedUAStyle.h
@@ -23,13 +23,13 @@
 #ifndef CachedUAStyle_h
 #define CachedUAStyle_h
 
+#include "base/macros.h"
 #include "core/css/StyleColor.h"
 #include "core/style/FillLayer.h"
 #include "core/style/NinePieceImage.h"
 #include "platform/LengthSize.h"
 #include "platform/graphics/Color.h"
 #include "platform/wtf/Allocator.h"
-#include "platform/wtf/Noncopyable.h"
 #include "platform/wtf/PtrUtil.h"
 
 namespace blink {
@@ -42,7 +42,6 @@
 // ApplyMatchedProperties for later use during AdjustComputedStyle.
 class CachedUAStyle {
   USING_FAST_MALLOC(CachedUAStyle);
-  WTF_MAKE_NONCOPYABLE(CachedUAStyle);
   friend class ComputedStyle;
 
  public:
@@ -81,6 +80,7 @@
 
  private:
   explicit CachedUAStyle(const ComputedStyle*);
+  DISALLOW_COPY_AND_ASSIGN(CachedUAStyle);
 };
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/style/FilterOperation.h b/third_party/WebKit/Source/core/style/FilterOperation.h
index 49df756..bc58fc0 100644
--- a/third_party/WebKit/Source/core/style/FilterOperation.h
+++ b/third_party/WebKit/Source/core/style/FilterOperation.h
@@ -26,6 +26,7 @@
 #ifndef FilterOperation_h
 #define FilterOperation_h
 
+#include "base/macros.h"
 #include "core/CoreExport.h"
 #include "core/style/ShadowData.h"
 #include "platform/Length.h"
@@ -33,7 +34,6 @@
 #include "platform/graphics/BoxReflection.h"
 #include "platform/graphics/Color.h"
 #include "platform/heap/Handle.h"
-#include "platform/wtf/Noncopyable.h"
 #include "platform/wtf/text/WTFString.h"
 
 namespace blink {
@@ -46,7 +46,6 @@
 
 class CORE_EXPORT FilterOperation
     : public GarbageCollectedFinalized<FilterOperation> {
-  WTF_MAKE_NONCOPYABLE(FilterOperation);
 
  public:
   enum OperationType {
@@ -121,6 +120,7 @@
  private:
   virtual FilterOperation* Blend(const FilterOperation* from,
                                  double progress) const = 0;
+  DISALLOW_COPY_AND_ASSIGN(FilterOperation);
 };
 
 #define DEFINE_FILTER_OPERATION_TYPE_CASTS(thisType, operationType)  \
diff --git a/third_party/WebKit/Source/core/svg/SVGElementProxy.cpp b/third_party/WebKit/Source/core/svg/SVGElementProxy.cpp
index 3b74d87..7ee8392 100644
--- a/third_party/WebKit/Source/core/svg/SVGElementProxy.cpp
+++ b/third_party/WebKit/Source/core/svg/SVGElementProxy.cpp
@@ -77,8 +77,10 @@
   if (id_.IsEmpty())
     return;
   if (!is_local_) {
-    if (document_)
-      document_->AddClient(client);
+    if (document_) {
+      DCHECK(!client->GetResource());
+      client->SetResource(document_);
+    }
     return;
   }
   TreeScope* client_scope = client->GetTreeScope();
@@ -113,8 +115,8 @@
   if (id_.IsEmpty())
     return;
   if (!is_local_) {
-    if (document_)
-      document_->RemoveClient(client);
+    DCHECK_EQ(client->GetResource(), document_);
+    client->ClearResource();
     return;
   }
   auto entry = clients_.find(client);
diff --git a/third_party/WebKit/Source/core/svg/SVGUseElement.cpp b/third_party/WebKit/Source/core/svg/SVGUseElement.cpp
index 280589f..65f5a510 100644
--- a/third_party/WebKit/Source/core/svg/SVGUseElement.cpp
+++ b/third_party/WebKit/Source/core/svg/SVGUseElement.cpp
@@ -89,7 +89,7 @@
 SVGUseElement::~SVGUseElement() {}
 
 void SVGUseElement::Dispose() {
-  SetDocumentResource(nullptr);
+  ClearResource();
 }
 
 void SVGUseElement::Trace(blink::Visitor* visitor) {
@@ -99,7 +99,6 @@
   visitor->Trace(height_);
   visitor->Trace(target_element_instance_);
   visitor->Trace(target_id_observer_);
-  visitor->Trace(resource_);
   SVGGraphicsElement::Trace(visitor);
   SVGURIReference::Trace(visitor);
   ResourceClient::Trace(visitor);
@@ -204,18 +203,18 @@
   element_url_ = GetDocument().CompleteURL(url_string);
   element_url_is_local_ = url_string.StartsWith('#');
   if (!IsStructurallyExternal()) {
-    SetDocumentResource(nullptr);
+    ClearResource();
     return;
   }
   if (!element_url_.HasFragmentIdentifier() ||
-      (resource_ &&
-       EqualIgnoringFragmentIdentifier(element_url_, resource_->Url())))
+      (GetResource() &&
+       EqualIgnoringFragmentIdentifier(element_url_, GetResource()->Url())))
     return;
 
   ResourceLoaderOptions options;
   options.initiator_info.name = localName();
   FetchParameters params(ResourceRequest(element_url_), options);
-  SetDocumentResource(
+  SetResource(
       DocumentResource::FetchSVGDocument(params, GetDocument().Fetcher()));
 }
 
@@ -317,7 +316,9 @@
   }
   if (!ResourceIsValid())
     return nullptr;
-  return resource_->GetDocument()->getElementById(element_identifier);
+  return ToDocumentResource(GetResource())
+      ->GetDocument()
+      ->getElementById(element_identifier);
 }
 
 void SVGUseElement::BuildPendingResource() {
@@ -704,7 +705,7 @@
 }
 
 void SVGUseElement::NotifyFinished(Resource* resource) {
-  DCHECK_EQ(resource_, resource);
+  DCHECK_EQ(GetResource(), resource);
   if (!isConnected())
     return;
 
@@ -727,12 +728,13 @@
 }
 
 bool SVGUseElement::ResourceIsStillLoading() const {
-  return resource_ && resource_->IsLoading();
+  return GetResource() && GetResource()->IsLoading();
 }
 
 bool SVGUseElement::ResourceIsValid() const {
-  return resource_ && resource_->IsLoaded() && !resource_->ErrorOccurred() &&
-         resource_->GetDocument();
+  return GetResource() && GetResource()->IsLoaded() &&
+         !GetResource()->ErrorOccurred() &&
+         ToDocumentResource(GetResource())->GetDocument();
 }
 
 bool SVGUseElement::InstanceTreeIsLoading() const {
@@ -744,16 +746,4 @@
   return false;
 }
 
-void SVGUseElement::SetDocumentResource(DocumentResource* resource) {
-  if (resource_ == resource)
-    return;
-
-  if (resource_)
-    resource_->RemoveClient(this);
-
-  resource_ = resource;
-  if (resource_)
-    resource_->AddClient(this);
-}
-
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/svg/SVGUseElement.h b/third_party/WebKit/Source/core/svg/SVGUseElement.h
index 526af58..8f225f6 100644
--- a/third_party/WebKit/Source/core/svg/SVGUseElement.h
+++ b/third_party/WebKit/Source/core/svg/SVGUseElement.h
@@ -120,7 +120,6 @@
   void NotifyFinished(Resource*) override;
   String DebugName() const override { return "SVGUseElement"; }
   void UpdateTargetReference();
-  void SetDocumentResource(DocumentResource*);
 
   Member<SVGAnimatedLength> x_;
   Member<SVGAnimatedLength> y_;
@@ -133,7 +132,6 @@
   bool needs_shadow_tree_recreation_;
   Member<SVGElement> target_element_instance_;
   Member<IdTargetObserver> target_id_observer_;
-  Member<DocumentResource> resource_;
 };
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/testing/DummyPageHolder.h b/third_party/WebKit/Source/core/testing/DummyPageHolder.h
index 47fa3b61..738c862 100644
--- a/third_party/WebKit/Source/core/testing/DummyPageHolder.h
+++ b/third_party/WebKit/Source/core/testing/DummyPageHolder.h
@@ -32,12 +32,12 @@
 #define DummyPageHolder_h
 
 #include <memory>
+#include "base/macros.h"
 #include "core/frame/LocalFrameClient.h"
 #include "core/page/Page.h"
 #include "platform/geometry/IntSize.h"
 #include "platform/heap/Handle.h"
 #include "platform/wtf/Allocator.h"
-#include "platform/wtf/Noncopyable.h"
 
 namespace blink {
 
@@ -63,7 +63,6 @@
 // references to the LocalFrame.
 
 class DummyPageHolder {
-  WTF_MAKE_NONCOPYABLE(DummyPageHolder);
   USING_FAST_MALLOC(DummyPageHolder);
 
  public:
@@ -95,6 +94,7 @@
   CrossThreadPersistent<LocalFrame> frame_;
 
   Persistent<LocalFrameClient> local_frame_client_;
+  DISALLOW_COPY_AND_ASSIGN(DummyPageHolder);
 };
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/testing/Internals.cpp b/third_party/WebKit/Source/core/testing/Internals.cpp
index da4de1ca..ee06dff 100644
--- a/third_party/WebKit/Source/core/testing/Internals.cpp
+++ b/third_party/WebKit/Source/core/testing/Internals.cpp
@@ -29,6 +29,7 @@
 #include <deque>
 #include <memory>
 
+#include "base/macros.h"
 #include "bindings/core/v8/ExceptionMessages.h"
 #include "bindings/core/v8/ExceptionState.h"
 #include "bindings/core/v8/ScriptFunction.h"
@@ -175,7 +176,6 @@
 namespace {
 
 class UseCounterObserverImpl final : public UseCounter::Observer {
-  WTF_MAKE_NONCOPYABLE(UseCounterObserverImpl);
 
  public:
   UseCounterObserverImpl(ScriptPromiseResolver* resolver, WebFeature feature)
@@ -196,6 +196,7 @@
  private:
   Member<ScriptPromiseResolver> resolver_;
   WebFeature feature_;
+  DISALLOW_COPY_AND_ASSIGN(UseCounterObserverImpl);
 };
 
 }  // namespace
diff --git a/third_party/WebKit/Source/core/timing/DOMHighResTimeStamp.idl b/third_party/WebKit/Source/core/timing/DOMHighResTimeStamp.idl
index e41c93a9..b031202 100644
--- a/third_party/WebKit/Source/core/timing/DOMHighResTimeStamp.idl
+++ b/third_party/WebKit/Source/core/timing/DOMHighResTimeStamp.idl
@@ -2,6 +2,6 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-// https://w3c.github.io/hr-time/#sec-DOMHighResTimeStamp
+// https://w3c.github.io/hr-time/#dom-domhighrestimestamp
 
 typedef double DOMHighResTimeStamp;
diff --git a/third_party/WebKit/Source/core/timing/DOMWindowPerformance.h b/third_party/WebKit/Source/core/timing/DOMWindowPerformance.h
index 45952fd..53a2bb14 100644
--- a/third_party/WebKit/Source/core/timing/DOMWindowPerformance.h
+++ b/third_party/WebKit/Source/core/timing/DOMWindowPerformance.h
@@ -5,10 +5,10 @@
 #ifndef DOMWindowPerformance_h
 #define DOMWindowPerformance_h
 
+#include "base/macros.h"
 #include "core/CoreExport.h"
 #include "platform/Supplementable.h"
 #include "platform/heap/Handle.h"
-#include "platform/wtf/Noncopyable.h"
 
 namespace blink {
 
@@ -19,7 +19,6 @@
     : public GarbageCollected<DOMWindowPerformance>,
       public Supplement<LocalDOMWindow> {
   USING_GARBAGE_COLLECTED_MIXIN(DOMWindowPerformance);
-  WTF_MAKE_NONCOPYABLE(DOMWindowPerformance);
 
  public:
   static DOMWindowPerformance& From(LocalDOMWindow&);
@@ -34,6 +33,7 @@
   Performance* performance();
 
   Member<Performance> performance_;
+  DISALLOW_COPY_AND_ASSIGN(DOMWindowPerformance);
 };
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/timing/MemoryInfo.cpp b/third_party/WebKit/Source/core/timing/MemoryInfo.cpp
index f8e1b9d..1d55f5e 100644
--- a/third_party/WebKit/Source/core/timing/MemoryInfo.cpp
+++ b/third_party/WebKit/Source/core/timing/MemoryInfo.cpp
@@ -32,6 +32,7 @@
 
 #include <limits>
 
+#include "base/macros.h"
 #include "core/frame/LocalFrame.h"
 #include "core/frame/Settings.h"
 #include "platform/runtime_enabled_features.h"
@@ -53,7 +54,6 @@
 }
 
 class HeapSizeCache {
-  WTF_MAKE_NONCOPYABLE(HeapSizeCache);
   USING_FAST_MALLOC(HeapSizeCache);
 
  public:
@@ -94,6 +94,7 @@
   double last_update_time_;
 
   HeapInfo info_;
+  DISALLOW_COPY_AND_ASSIGN(HeapSizeCache);
 };
 
 // We quantize the sizes to make it more difficult for an attacker to see
diff --git a/third_party/WebKit/Source/core/timing/PerformanceEntryList.idl b/third_party/WebKit/Source/core/timing/PerformanceEntryList.idl
index 7dea2f2..9d3ce8c 100644
--- a/third_party/WebKit/Source/core/timing/PerformanceEntryList.idl
+++ b/third_party/WebKit/Source/core/timing/PerformanceEntryList.idl
@@ -2,6 +2,6 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-// https://w3c.github.io/performance-timeline/#idl-def-PerformanceEntryList
+// https://w3c.github.io/performance-timeline/#dom-performanceentrylist
 
 typedef sequence<PerformanceEntry> PerformanceEntryList;
diff --git a/third_party/WebKit/Source/core/timing/PerformanceLongTaskTiming.idl b/third_party/WebKit/Source/core/timing/PerformanceLongTaskTiming.idl
index 9f7c9dc..b36f04b 100644
--- a/third_party/WebKit/Source/core/timing/PerformanceLongTaskTiming.idl
+++ b/third_party/WebKit/Source/core/timing/PerformanceLongTaskTiming.idl
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-// https://wicg.github.io/longtasks/#sec-PerformanceLongTaskTiming
+// https://w3c.github.io/longtasks/#sec-PerformanceLongTaskTiming
 interface PerformanceLongTaskTiming : PerformanceEntry {
     [SameObject, SaveSameObject] readonly attribute FrozenArray<TaskAttributionTiming> attribution;
 };
diff --git a/third_party/WebKit/Source/core/timing/PerformanceObserver.idl b/third_party/WebKit/Source/core/timing/PerformanceObserver.idl
index c253f6c5..d556573 100644
--- a/third_party/WebKit/Source/core/timing/PerformanceObserver.idl
+++ b/third_party/WebKit/Source/core/timing/PerformanceObserver.idl
@@ -2,10 +2,10 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-// https://w3c.github.io/performance-timeline/#idl-def-PerformanceObserverCallback
+// https://w3c.github.io/performance-timeline/#dom-performanceobservercallback
 callback PerformanceObserverCallback = void (PerformanceObserverEntryList entries, PerformanceObserver observer);
 
-// https://w3c.github.io/performance-timeline/#the-performance-observer-interface
+// https://w3c.github.io/performance-timeline/#the-performanceobserver-interface
 [
     ActiveScriptWrappable,
     Constructor(PerformanceObserverCallback callback),
diff --git a/third_party/WebKit/Source/core/timing/PerformanceObserverEntryList.idl b/third_party/WebKit/Source/core/timing/PerformanceObserverEntryList.idl
index 763a536c..c618ae839 100644
--- a/third_party/WebKit/Source/core/timing/PerformanceObserverEntryList.idl
+++ b/third_party/WebKit/Source/core/timing/PerformanceObserverEntryList.idl
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-// https://w3c.github.io/performance-timeline/#the-performance-observer-interface
+// https://w3c.github.io/performance-timeline/#performanceobserverentrylist-interface
 
 [
     Exposed=(Window,Worker)
diff --git a/third_party/WebKit/Source/core/timing/PerformanceObserverInit.idl b/third_party/WebKit/Source/core/timing/PerformanceObserverInit.idl
index bb4bfd7..acb2790 100644
--- a/third_party/WebKit/Source/core/timing/PerformanceObserverInit.idl
+++ b/third_party/WebKit/Source/core/timing/PerformanceObserverInit.idl
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-// https://w3c.github.io/performance-timeline/#the-performance-observer-interface
+// https://w3c.github.io/performance-timeline/#performanceobserverinit-dictionary
 
 dictionary PerformanceObserverInit {
     required sequence<DOMString> entryTypes;
diff --git a/third_party/WebKit/Source/core/timing/PerformancePaintTiming.idl b/third_party/WebKit/Source/core/timing/PerformancePaintTiming.idl
index 5289d47e..a09c5a021 100644
--- a/third_party/WebKit/Source/core/timing/PerformancePaintTiming.idl
+++ b/third_party/WebKit/Source/core/timing/PerformancePaintTiming.idl
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-// https://github.com/WICG/paint-timing
+// https://w3c.github.io/paint-timing/#sec-PerformancePaintTiming
 
 [
     RuntimeEnabled=PerformancePaintTiming
diff --git a/third_party/WebKit/Source/core/timing/PerformanceServerTiming.idl b/third_party/WebKit/Source/core/timing/PerformanceServerTiming.idl
index 3bc1dbd1..f96527f6 100644
--- a/third_party/WebKit/Source/core/timing/PerformanceServerTiming.idl
+++ b/third_party/WebKit/Source/core/timing/PerformanceServerTiming.idl
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-// https://w3c.github.io/server-timing/
+// https://w3c.github.io/server-timing/#dom-performanceservertiming
 
 [
     RuntimeEnabled=ServerTiming,
diff --git a/third_party/WebKit/Source/core/timing/TaskAttributionTiming.idl b/third_party/WebKit/Source/core/timing/TaskAttributionTiming.idl
index e1ee405..0ac8bb98 100644
--- a/third_party/WebKit/Source/core/timing/TaskAttributionTiming.idl
+++ b/third_party/WebKit/Source/core/timing/TaskAttributionTiming.idl
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-// https://github.com/wicg/longtasks
+// https://w3c.github.io/longtasks/#sec-TaskAttributionTiming
 interface TaskAttributionTiming : PerformanceEntry {
     [RuntimeEnabled=LongTaskV2] readonly attribute DOMString scriptURL;
     readonly attribute DOMString containerType;
diff --git a/third_party/WebKit/Source/core/timing/WindowPerformance.idl b/third_party/WebKit/Source/core/timing/WindowPerformance.idl
index e660507..efebb32 100644
--- a/third_party/WebKit/Source/core/timing/WindowPerformance.idl
+++ b/third_party/WebKit/Source/core/timing/WindowPerformance.idl
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-// https://w3c.github.io/hr-time/#the-performance-interface
+// https://w3c.github.io/hr-time/#the-performance-attribute
 
 // TODO(foolip): This should be a GlobalPerformance interface implemented by
 // Window and WorkerGlobalScope.
diff --git a/third_party/WebKit/Source/core/timing/WorkerGlobalScopePerformance.idl b/third_party/WebKit/Source/core/timing/WorkerGlobalScopePerformance.idl
index 2961d5f..eded72d1 100644
--- a/third_party/WebKit/Source/core/timing/WorkerGlobalScopePerformance.idl
+++ b/third_party/WebKit/Source/core/timing/WorkerGlobalScopePerformance.idl
@@ -28,7 +28,7 @@
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-// https://w3c.github.io/hr-time/#the-performance-interface
+// https://w3c.github.io/hr-time/#the-performance-attribute
 
 // TODO(foolip): This should be a GlobalPerformance interface implemented by
 // Window and WorkerGlobalScope.
diff --git a/third_party/WebKit/Source/devtools/front_end/color_picker/Spectrum.js b/third_party/WebKit/Source/devtools/front_end/color_picker/Spectrum.js
index 83977ab..f4e90fc 100644
--- a/third_party/WebKit/Source/devtools/front_end/color_picker/Spectrum.js
+++ b/third_party/WebKit/Source/devtools/front_end/color_picker/Spectrum.js
@@ -124,14 +124,15 @@
     this._palettes = new Map();
     this._palettePanel = this.contentElement.createChild('div', 'palette-panel');
     this._palettePanelShowing = false;
-    this._paletteContainer = this.contentElement.createChild('div', 'spectrum-palette');
+    this._paletteSectionContainer = this.contentElement.createChild('div', 'spectrum-palette-container');
+    this._paletteContainer = this._paletteSectionContainer.createChild('div', 'spectrum-palette');
     this._paletteContainer.addEventListener('contextmenu', this._showPaletteColorContextMenu.bind(this, -1));
-    this._paletteColorsContainer = this._paletteContainer.createChild('div', 'spectrum-palette-colors');
     this._shadesContainer = this.contentElement.createChild('div', 'palette-color-shades hidden');
     UI.installDragHandle(
-        this._paletteColorsContainer, this._paletteDragStart.bind(this), this._paletteDrag.bind(this),
+        this._paletteContainer, this._paletteDragStart.bind(this), this._paletteDrag.bind(this),
         this._paletteDragEnd.bind(this), 'default');
-    var paletteSwitcher = this._paletteContainer.createChild('div', 'spectrum-palette-switcher spectrum-switcher');
+    var paletteSwitcher =
+        this._paletteSectionContainer.createChild('div', 'spectrum-palette-switcher spectrum-switcher');
     appendSwitcherIcon(paletteSwitcher);
     paletteSwitcher.addEventListener('click', this._togglePalettePanel.bind(this, true));
 
@@ -258,7 +259,7 @@
    */
   _showPalette(palette, animate, event) {
     this._resizeForSelectedPalette();
-    this._paletteColorsContainer.removeChildren();
+    this._paletteContainer.removeChildren();
     for (var i = 0; i < palette.colors.length; i++) {
       var animationDelay = animate ? i * 100 / palette.colors.length : 0;
       var colorElement = this._createPaletteColor(palette.colors[i], animationDelay);
@@ -277,13 +278,13 @@
         colorElement.title = Common.UIString(palette.colors[i] + '. Long-click to show alternate shades.');
         new UI.LongClickController(colorElement, this._showLightnessShades.bind(this, colorElement, palette.colors[i]));
       }
-      this._paletteColorsContainer.appendChild(colorElement);
+      this._paletteContainer.appendChild(colorElement);
     }
     this._paletteContainerMutable = palette.mutable;
 
     if (palette.mutable) {
-      this._paletteColorsContainer.appendChild(this._addColorToolbar.element);
-      this._paletteColorsContainer.appendChild(this._deleteIconToolbar.element);
+      this._paletteContainer.appendChild(this._addColorToolbar.element);
+      this._paletteContainer.appendChild(this._deleteIconToolbar.element);
     } else {
       this._addColorToolbar.element.remove();
       this._deleteIconToolbar.element.remove();
@@ -318,8 +319,7 @@
     this._shadesContainer.animate(
         [{transform: 'scaleY(0)', opacity: '0'}, {transform: 'scaleY(1)', opacity: '1'}],
         {duration: 200, easing: 'cubic-bezier(0.4, 0, 0.2, 1)'});
-    var shadesTop =
-        this._paletteColorsContainer.offsetTop + colorElement.offsetTop + colorElement.parentElement.offsetTop;
+    var shadesTop = this._paletteContainer.offsetTop + colorElement.offsetTop + colorElement.parentElement.offsetTop;
     if (this._contrastDetails && this._contrastDetails.visible())
       shadesTop += this._contrastDetails.element().offsetHeight;
     this._shadesContainer.style.top = shadesTop + 'px';
diff --git a/third_party/WebKit/Source/devtools/front_end/color_picker/spectrum.css b/third_party/WebKit/Source/devtools/front_end/color_picker/spectrum.css
index 47195460..c5ebe9f 100644
--- a/third_party/WebKit/Source/devtools/front_end/color_picker/spectrum.css
+++ b/third_party/WebKit/Source/devtools/front_end/color_picker/spectrum.css
@@ -382,7 +382,7 @@
     cursor: pointer;
 }
 
-.spectrum-palette {
+.spectrum-palette-container {
     border-top: 1px solid #dadada;
     position: relative;
     width: 100%;
@@ -391,7 +391,7 @@
     flex-wrap: wrap;
 }
 
-.spectrum-palette-colors {
+.spectrum-palette {
     display: flex;
     flex-wrap: wrap;
     width: 198px;
@@ -441,7 +441,7 @@
     margin-left: -8px;
 }
 
-.spectrum-palette-colors > .spectrum-palette-color.spectrum-shades-shown {
+.spectrum-palette > .spectrum-palette-color.spectrum-shades-shown {
     z-index: 15;
 }
 
diff --git a/third_party/WebKit/Source/devtools/front_end/performance_test_runner/TimelineTestRunner.js b/third_party/WebKit/Source/devtools/front_end/performance_test_runner/TimelineTestRunner.js
index 72176f4..3e22bc3 100644
--- a/third_party/WebKit/Source/devtools/front_end/performance_test_runner/TimelineTestRunner.js
+++ b/third_party/WebKit/Source/devtools/front_end/performance_test_runner/TimelineTestRunner.js
@@ -135,66 +135,50 @@
   TestRunner.addSniffer(UI.panels.timeline, 'loadingComplete', () => callback());
 };
 
-PerformanceTestRunner.startTimeline = function(callback) {
-  return new Promise(resolve => {
-    var panel = UI.panels.timeline;
-    TestRunner.addSniffer(panel, '_recordingStarted', () => {
-      resolve();
-      if (callback)
-        callback();
-    });
-    panel._toggleRecording();
-  });
+PerformanceTestRunner.startTimeline = function() {
+  const panel = UI.panels.timeline;
+  panel._toggleRecording();
+  return TestRunner.addSnifferPromise(panel, '_recordingStarted');
 };
 
-PerformanceTestRunner.stopTimeline = function(callback) {
+PerformanceTestRunner.stopTimeline = function() {
   return new Promise(resolve => {
-    PerformanceTestRunner.runWhenTimelineIsReady(() => {
-      resolve();
-      if (callback)
-        callback();
-    });
+    PerformanceTestRunner.runWhenTimelineIsReady(resolve);
     UI.panels.timeline._toggleRecording();
   });
 };
 
-// TODO(alph): Replace callback with promise in all the tests.
-PerformanceTestRunner.evaluateWithTimeline = async function(actions, doneCallback) {
+PerformanceTestRunner.evaluateWithTimeline = async function(actions) {
   await PerformanceTestRunner.startTimeline();
   await TestRunner.evaluateInPageAnonymously(actions);
-  await PerformanceTestRunner.stopTimeline(doneCallback);
+  await PerformanceTestRunner.stopTimeline();
 };
 
-PerformanceTestRunner.invokeAsyncWithTimeline = async function(functionName, doneCallback) {
+PerformanceTestRunner.invokeAsyncWithTimeline = async function(functionName) {
   await PerformanceTestRunner.startTimeline();
   await TestRunner.callFunctionInPageAsync(functionName);
-  await PerformanceTestRunner.stopTimeline(doneCallback);
+  await PerformanceTestRunner.stopTimeline();
 };
 
-PerformanceTestRunner.performActionsAndPrint = function(actions, typeName, includeTimeStamps) {
-  function callback() {
-    PerformanceTestRunner.printTimelineRecordsWithDetails(typeName);
-
-    if (includeTimeStamps) {
-      TestRunner.addResult('Timestamp records: ');
-      PerformanceTestRunner.printTimestampRecords(typeName);
-    }
-
-    TestRunner.completeTest();
+PerformanceTestRunner.performActionsAndPrint = async function(actions, typeName, includeTimeStamps) {
+  await PerformanceTestRunner.evaluateWithTimeline(actions);
+  PerformanceTestRunner.printTimelineRecordsWithDetails(typeName);
+  if (includeTimeStamps) {
+    TestRunner.addResult('Timestamp records: ');
+    PerformanceTestRunner.printTimestampRecords(typeName);
   }
-
-  PerformanceTestRunner.evaluateWithTimeline(actions, callback);
+  TestRunner.completeTest();
 };
 
 PerformanceTestRunner.printTimelineRecords = function(name) {
-  for (let event of PerformanceTestRunner.timelineModel().inspectedTargetEvents()) {
+  for (const event of PerformanceTestRunner.timelineModel().inspectedTargetEvents()) {
     if (event.name === name)
       PerformanceTestRunner.printTraceEventProperties(event);
   }
 };
 
 PerformanceTestRunner.printTimelineRecordsWithDetails = function(name) {
-  for (let event of PerformanceTestRunner.timelineModel().inspectedTargetEvents()) {
+  for (const event of PerformanceTestRunner.timelineModel().inspectedTargetEvents()) {
     if (name === event.name)
       PerformanceTestRunner.printTraceEventPropertiesWithDetails(event);
   }
diff --git a/third_party/WebKit/Source/modules/canvas/canvas2d/BaseRenderingContext2D.cpp b/third_party/WebKit/Source/modules/canvas/canvas2d/BaseRenderingContext2D.cpp
index f480f20..d6bcf35 100644
--- a/third_party/WebKit/Source/modules/canvas/canvas2d/BaseRenderingContext2D.cpp
+++ b/third_party/WebKit/Source/modules/canvas/canvas2d/BaseRenderingContext2D.cpp
@@ -45,7 +45,7 @@
 const double BaseRenderingContext2D::kCDeviceScaleFactor = 1.0;
 
 BaseRenderingContext2D::BaseRenderingContext2D()
-    : clip_antialiasing_(kNotAntiAliased) {
+    : clip_antialiasing_(kNotAntiAliased), origin_tainted_by_content_(false) {
   state_stack_.push_back(CanvasRenderingContext2DState::Create());
 }
 
@@ -151,6 +151,7 @@
 #endif
   }
   ValidateStateStack();
+  origin_tainted_by_content_ = false;
 }
 
 static inline void ConvertCanvasStyleToUnionType(
@@ -195,10 +196,8 @@
   } else if (style.IsCanvasPattern()) {
     CanvasPattern* canvas_pattern = style.GetAsCanvasPattern();
 
-    if (OriginClean() && !canvas_pattern->OriginClean()) {
-      SetOriginTainted();
-      ClearResolvedFilters();
-    }
+    if (!origin_tainted_by_content_ && !canvas_pattern->OriginClean())
+      SetOriginTaintedByContent();
 
     canvas_style = CanvasStyle::CreateFromPattern(canvas_pattern);
   }
@@ -238,9 +237,8 @@
   } else if (style.IsCanvasPattern()) {
     CanvasPattern* canvas_pattern = style.GetAsCanvasPattern();
 
-    if (OriginClean() && !canvas_pattern->OriginClean()) {
-      SetOriginTainted();
-      ClearResolvedFilters();
+    if (!origin_tainted_by_content_ && !canvas_pattern->OriginClean()) {
+      SetOriginTaintedByContent();
     }
     if (canvas_pattern->GetPattern()->IsTextureBacked())
       DisableDeferral(kDisableDeferralReasonUsingTextureBackedPattern);
@@ -1107,7 +1105,9 @@
   return false;
 }
 
-void BaseRenderingContext2D::ClearResolvedFilters() {
+void BaseRenderingContext2D::SetOriginTaintedByContent() {
+  SetOriginTainted();
+  origin_tainted_by_content_ = true;
   for (auto& state : state_stack_)
     state->ClearResolvedFilter();
 }
@@ -1274,11 +1274,9 @@
 
   ValidateStateStack();
 
-  if (OriginClean() &&
-      WouldTaintOrigin(image_source, ExecutionContext::From(script_state))) {
-    SetOriginTainted();
-    ClearResolvedFilters();
-  }
+  if (!origin_tainted_by_content_ &&
+      WouldTaintOrigin(image_source, ExecutionContext::From(script_state)))
+    SetOriginTaintedByContent();
 
   Draw(
       [this, &image_source, &image, &src_rect, dst_rect](
diff --git a/third_party/WebKit/Source/modules/canvas/canvas2d/BaseRenderingContext2D.h b/third_party/WebKit/Source/modules/canvas/canvas2d/BaseRenderingContext2D.h
index 24ed25e..e9a04ca 100644
--- a/third_party/WebKit/Source/modules/canvas/canvas2d/BaseRenderingContext2D.h
+++ b/third_party/WebKit/Source/modules/canvas/canvas2d/BaseRenderingContext2D.h
@@ -410,9 +410,14 @@
 
   void ClearCanvas();
   bool RectContainsTransformedRect(const FloatRect&, const SkIRect&) const;
-  void ClearResolvedFilters();
+  // Sets the origin to be tainted by the content of the canvas, such
+  // as a cross-origin image. This is as opposed to some other reason
+  // such as tainting from a filter applied to the canvas.
+  void SetOriginTaintedByContent();
 
   ImageDataColorSettings GetColorSettingsAsImageDataColorSettings() const;
+
+  bool origin_tainted_by_content_;
 };
 
 template <typename DrawFunc, typename ContainsFunc>
diff --git a/third_party/WebKit/Source/modules/canvas/offscreencanvas2d/OffscreenCanvasRenderingContext2D.cpp b/third_party/WebKit/Source/modules/canvas/offscreencanvas2d/OffscreenCanvasRenderingContext2D.cpp
index a0861fa..e68d37f9 100644
--- a/third_party/WebKit/Source/modules/canvas/offscreencanvas2d/OffscreenCanvasRenderingContext2D.cpp
+++ b/third_party/WebKit/Source/modules/canvas/offscreencanvas2d/OffscreenCanvasRenderingContext2D.cpp
@@ -143,33 +143,6 @@
   return image;
 }
 
-// TODO(xlai): Handle error cases when, by any reason,
-// OffscreenCanvasRenderingContext2D fails to get ImageData.
-ImageData* OffscreenCanvasRenderingContext2D::ToImageData(
-    SnapshotReason reason) {
-  if (!GetImageBuffer())
-    return nullptr;
-  if (Host()->Size().IsEmpty())
-    return nullptr;
-  scoped_refptr<StaticBitmapImage> snapshot =
-      GetImageBuffer()->NewImageSnapshot(kPreferNoAcceleration, reason);
-  ImageData* image_data = nullptr;
-  if (snapshot) {
-    image_data = ImageData::Create(Host()->Size());
-    SkImageInfo image_info =
-        SkImageInfo::Make(this->Width(), this->Height(), kRGBA_8888_SkColorType,
-                          kUnpremul_SkAlphaType);
-    sk_sp<SkImage> sk_image =
-        snapshot->PaintImageForCurrentFrame().GetSkImage();
-    bool read_pixels_successful = sk_image->readPixels(
-        image_info, image_data->data()->Data(), image_info.minRowBytes(), 0, 0);
-    DCHECK(read_pixels_successful);
-    if (!read_pixels_successful)
-      return nullptr;
-  }
-  return image_data;
-}
-
 void OffscreenCanvasRenderingContext2D::SetOffscreenCanvasGetContextResult(
     OffscreenRenderingContext& result) {
   result.SetOffscreenCanvasRenderingContext2D(this);
diff --git a/third_party/WebKit/Source/modules/canvas/offscreencanvas2d/OffscreenCanvasRenderingContext2D.h b/third_party/WebKit/Source/modules/canvas/offscreencanvas2d/OffscreenCanvasRenderingContext2D.h
index c00b22d..8327ee61 100644
--- a/third_party/WebKit/Source/modules/canvas/offscreencanvas2d/OffscreenCanvasRenderingContext2D.h
+++ b/third_party/WebKit/Source/modules/canvas/offscreencanvas2d/OffscreenCanvasRenderingContext2D.h
@@ -62,7 +62,6 @@
   }
   scoped_refptr<StaticBitmapImage> GetImage(AccelerationHint,
                                             SnapshotReason) const final;
-  ImageData* ToImageData(SnapshotReason) override;
   void Reset() override;
   void RestoreCanvasMatrixClipStack(PaintCanvas* c) const override {
     RestoreMatrixClipStack(c);
diff --git a/third_party/WebKit/Source/modules/credentialmanager/CredentialManagerTypeConverters.cpp b/third_party/WebKit/Source/modules/credentialmanager/CredentialManagerTypeConverters.cpp
index 014d823..0e81ba2 100644
--- a/third_party/WebKit/Source/modules/credentialmanager/CredentialManagerTypeConverters.cpp
+++ b/third_party/WebKit/Source/modules/credentialmanager/CredentialManagerTypeConverters.cpp
@@ -32,6 +32,40 @@
 using webauth::mojom::blink::AuthenticatorTransport;
 
 // static
+blink::WebCredentialManagerError
+TypeConverter<blink::WebCredentialManagerError, AuthenticatorStatus>::Convert(
+    const AuthenticatorStatus& status) {
+  switch (status) {
+    case webauth::mojom::blink::AuthenticatorStatus::NOT_ALLOWED_ERROR:
+      return blink::WebCredentialManagerError::
+          kWebCredentialManagerNotAllowedError;
+    case webauth::mojom::blink::AuthenticatorStatus::PENDING_REQUEST:
+      return blink::WebCredentialManagerError::
+          kWebCredentialManagerPendingRequestError;
+    case webauth::mojom::blink::AuthenticatorStatus::NOT_SUPPORTED_ERROR:
+      return blink::WebCredentialManagerError::
+          kWebCredentialManagerNotSupportedError;
+    case webauth::mojom::blink::AuthenticatorStatus::SECURITY_ERROR:
+      return blink::WebCredentialManagerError::
+          kWebCredentialManagerSecurityError;
+    case webauth::mojom::blink::AuthenticatorStatus::UNKNOWN_ERROR:
+      return blink::WebCredentialManagerError::
+          kWebCredentialManagerUnknownError;
+    case webauth::mojom::blink::AuthenticatorStatus::CANCELLED:
+      return blink::WebCredentialManagerError::
+          kWebCredentialManagerCancelledError;
+    case webauth::mojom::blink::AuthenticatorStatus::NOT_IMPLEMENTED:
+      return blink::kWebCredentialManagerNotImplementedError;
+    case webauth::mojom::blink::AuthenticatorStatus::SUCCESS:
+      NOTREACHED();
+      break;
+  };
+
+  NOTREACHED();
+  return blink::WebCredentialManagerError::kWebCredentialManagerUnknownError;
+}
+
+// static
 Vector<uint8_t>
 TypeConverter<Vector<uint8_t>, blink::ArrayBufferOrArrayBufferView>::Convert(
     const blink::ArrayBufferOrArrayBufferView& buffer) {
diff --git a/third_party/WebKit/Source/modules/credentialmanager/CredentialManagerTypeConverters.h b/third_party/WebKit/Source/modules/credentialmanager/CredentialManagerTypeConverters.h
index 1ab677c..7c0ba27 100644
--- a/third_party/WebKit/Source/modules/credentialmanager/CredentialManagerTypeConverters.h
+++ b/third_party/WebKit/Source/modules/credentialmanager/CredentialManagerTypeConverters.h
@@ -7,6 +7,7 @@
 
 #include "platform/wtf/Vector.h"
 #include "platform/wtf/text/WTFString.h"
+#include "public/platform/WebCredentialManagerError.h"
 #include "public/platform/modules/webauth/authenticator.mojom-blink.h"
 
 namespace blink {
@@ -20,6 +21,12 @@
 namespace mojo {
 
 // webauth::mojom::blink::Authenticator ---------------------------------------
+template <>
+struct TypeConverter<blink::WebCredentialManagerError,
+                     webauth::mojom::blink::AuthenticatorStatus> {
+  static blink::WebCredentialManagerError Convert(
+      const webauth::mojom::blink::AuthenticatorStatus&);
+};
 
 template <>
 struct TypeConverter<Vector<uint8_t>, blink::ArrayBufferOrArrayBufferView> {
diff --git a/third_party/WebKit/Source/modules/credentialmanager/CredentialsContainer.cpp b/third_party/WebKit/Source/modules/credentialmanager/CredentialsContainer.cpp
index bfe88bd1..474bbc88 100644
--- a/third_party/WebKit/Source/modules/credentialmanager/CredentialsContainer.cpp
+++ b/third_party/WebKit/Source/modules/credentialmanager/CredentialsContainer.cpp
@@ -67,7 +67,7 @@
       break;
     case kWebCredentialManagerPendingRequestError:
       resolver->Reject(DOMException::Create(kInvalidStateError,
-                                            "A 'get()' request is pending."));
+                                            "A request is already pending."));
       break;
     case kWebCredentialManagerNotAllowedError:
       resolver->Reject(DOMException::Create(kNotAllowedError,
diff --git a/third_party/WebKit/Source/modules/credentialmanager/WebAuthenticationClient.cpp b/third_party/WebKit/Source/modules/credentialmanager/WebAuthenticationClient.cpp
index 87f6b502..56286bba 100644
--- a/third_party/WebKit/Source/modules/credentialmanager/WebAuthenticationClient.cpp
+++ b/third_party/WebKit/Source/modules/credentialmanager/WebAuthenticationClient.cpp
@@ -21,37 +21,13 @@
 namespace {
 using PublicKeyCallbacks = WebAuthenticationClient::PublicKeyCallbacks;
 
-WebCredentialManagerError GetWebCredentialManagerErrorFromStatus(
-    webauth::mojom::blink::AuthenticatorStatus status) {
-  switch (status) {
-    case webauth::mojom::blink::AuthenticatorStatus::NOT_ALLOWED_ERROR:
-      return WebCredentialManagerError::kWebCredentialManagerNotAllowedError;
-    case webauth::mojom::blink::AuthenticatorStatus::NOT_SUPPORTED_ERROR:
-      return WebCredentialManagerError::kWebCredentialManagerNotSupportedError;
-    case webauth::mojom::blink::AuthenticatorStatus::SECURITY_ERROR:
-      return WebCredentialManagerError::kWebCredentialManagerSecurityError;
-    case webauth::mojom::blink::AuthenticatorStatus::UNKNOWN_ERROR:
-      return WebCredentialManagerError::kWebCredentialManagerUnknownError;
-    case webauth::mojom::blink::AuthenticatorStatus::CANCELLED:
-      return WebCredentialManagerError::kWebCredentialManagerCancelledError;
-    case webauth::mojom::blink::AuthenticatorStatus::NOT_IMPLEMENTED:
-      return blink::kWebCredentialManagerNotImplementedError;
-    case webauth::mojom::blink::AuthenticatorStatus::SUCCESS:
-      NOTREACHED();
-      break;
-  };
-
-  NOTREACHED();
-  return blink::WebCredentialManagerError::kWebCredentialManagerUnknownError;
-}
-
 void RespondToPublicKeyCallback(
     std::unique_ptr<PublicKeyCallbacks> callbacks,
     webauth::mojom::blink::AuthenticatorStatus status,
     webauth::mojom::blink::PublicKeyCredentialInfoPtr credential) {
   if (status != webauth::mojom::AuthenticatorStatus::SUCCESS) {
     DCHECK(!credential);
-    callbacks->OnError(GetWebCredentialManagerErrorFromStatus(status));
+    callbacks->OnError(mojo::ConvertTo<WebCredentialManagerError>(status));
     return;
   }
 
diff --git a/third_party/WebKit/Source/modules/indexeddb/IDBObjectStore.cpp b/third_party/WebKit/Source/modules/indexeddb/IDBObjectStore.cpp
index 0cb5f4b..105fb15 100644
--- a/third_party/WebKit/Source/modules/indexeddb/IDBObjectStore.cpp
+++ b/third_party/WebKit/Source/modules/indexeddb/IDBObjectStore.cpp
@@ -529,13 +529,13 @@
   IDBRequest* request = IDBRequest::Create(
       script_state, source, transaction_.Get(), std::move(metrics));
 
+  value_wrapper.DoneCloning();
   value_wrapper.WrapIfBiggerThan(IDBValueWrapper::kWrapThreshold);
-  value_wrapper.ExtractBlobDataHandles(request->transit_blob_handles());
 
+  request->transit_blob_handles() = value_wrapper.TakeBlobDataHandles();
   BackendDB()->Put(
-      transaction_->Id(), Id(), WebData(value_wrapper.ExtractWireBytes()),
-      value_wrapper.WrappedBlobInfo(), key,
-      static_cast<WebIDBPutMode>(put_mode),
+      transaction_->Id(), Id(), WebData(value_wrapper.TakeWireBytes()),
+      value_wrapper.TakeBlobInfo(), key, static_cast<WebIDBPutMode>(put_mode),
       request->CreateWebCallbacks().release(), index_ids, index_keys);
 
   return request;
diff --git a/third_party/WebKit/Source/modules/indexeddb/IDBRequest.h b/third_party/WebKit/Source/modules/indexeddb/IDBRequest.h
index d4d0bf9..d8260d0 100644
--- a/third_party/WebKit/Source/modules/indexeddb/IDBRequest.h
+++ b/third_party/WebKit/Source/modules/indexeddb/IDBRequest.h
@@ -296,8 +296,8 @@
   // (which hangs onto the BlobDataHandle) may get garbage-collected. IDBRequest
   // needs to hang onto the BlobDataHandle as well, to avoid having the
   // browser-side Blob get destroyed before the IndexedDB request is processed.
-  inline Vector<scoped_refptr<BlobDataHandle>>* transit_blob_handles() {
-    return &transit_blob_handles_;
+  inline Vector<scoped_refptr<BlobDataHandle>>& transit_blob_handles() {
+    return transit_blob_handles_;
   }
 
 #if DCHECK_IS_ON()
diff --git a/third_party/WebKit/Source/modules/indexeddb/IDBTestHelper.cpp b/third_party/WebKit/Source/modules/indexeddb/IDBTestHelper.cpp
index 2a5b92aa..8f231ce4 100644
--- a/third_party/WebKit/Source/modules/indexeddb/IDBTestHelper.cpp
+++ b/third_party/WebKit/Source/modules/indexeddb/IDBTestHelper.cpp
@@ -28,19 +28,20 @@
   IDBValueWrapper wrapper(isolate, v8_array,
                           SerializedScriptValue::SerializeOptions::kSerialize,
                           non_throwable_exception_state);
+  wrapper.DoneCloning();
   wrapper.WrapIfBiggerThan(create_wrapped_value ? 0 : 1024 * element_count);
 
-  std::unique_ptr<Vector<scoped_refptr<BlobDataHandle>>> blob_data_handles =
-      std::make_unique<Vector<scoped_refptr<BlobDataHandle>>>();
-  wrapper.ExtractBlobDataHandles(blob_data_handles.get());
-  Vector<WebBlobInfo>& blob_infos = wrapper.WrappedBlobInfo();
-  scoped_refptr<SharedBuffer> wrapped_marker_buffer =
-      wrapper.ExtractWireBytes();
+  Vector<scoped_refptr<BlobDataHandle>> blob_data_handles =
+      wrapper.TakeBlobDataHandles();
+  Vector<WebBlobInfo> blob_infos = wrapper.TakeBlobInfo();
+  scoped_refptr<SharedBuffer> wrapped_marker_buffer = wrapper.TakeWireBytes();
   IDBKey* key = IDBKey::CreateNumber(42.0);
   IDBKeyPath key_path(String("primaryKey"));
 
   scoped_refptr<IDBValue> idb_value = IDBValue::Create(
-      std::move(wrapped_marker_buffer), std::move(blob_data_handles),
+      std::move(wrapped_marker_buffer),
+      std::make_unique<Vector<scoped_refptr<BlobDataHandle>>>(
+          blob_data_handles),
       std::make_unique<Vector<WebBlobInfo>>(blob_infos), key, key_path);
 
   DCHECK_EQ(create_wrapped_value,
diff --git a/third_party/WebKit/Source/modules/indexeddb/IDBValueWrapping.cpp b/third_party/WebKit/Source/modules/indexeddb/IDBValueWrapping.cpp
index 3ec52b11..3b9da4a 100644
--- a/third_party/WebKit/Source/modules/indexeddb/IDBValueWrapping.cpp
+++ b/third_party/WebKit/Source/modules/indexeddb/IDBValueWrapping.cpp
@@ -13,7 +13,6 @@
 #include "modules/indexeddb/IDBRequest.h"
 #include "modules/indexeddb/IDBValue.h"
 #include "platform/blob/BlobData.h"
-#include "platform/wtf/text/StringView.h"
 #include "platform/wtf/text/WTFString.h"
 
 namespace blink {
@@ -42,16 +41,15 @@
 // The SSV format version whose encoding hole is (ab)used for wrapping.
 const static uint8_t kRequiresProcessingSSVPseudoVersion = 17;
 
-// Identifies IndexedDB values that were wrapped in Blobs. The wrapper has the
-// following format:
+// SSV processing command replacing the SSV data bytes with a Blob's contents.
 //
 // 1) 0xFF - kVersionTag
 // 2) 0x11 - kRequiresProcessingSSVPseudoVersion
-// 3) 0x01 - kBlobWrappedValue
+// 3) 0x01 - kReplaceWithBlob
 // 4) varint - Blob size
 // 5) varint - the offset of the SSV-wrapping Blob in the IDBValue list of Blobs
 //             (should always be the last Blob)
-const static uint8_t kBlobWrappedValue = 1;
+const static uint8_t kReplaceWithBlob = 1;
 
 }  // namespace
 
@@ -68,8 +66,9 @@
 
   serialized_value_ = SerializedScriptValue::Serialize(isolate, value, options,
                                                        exception_state);
-  if (serialized_value_)
+  if (serialized_value_) {
     original_data_length_ = serialized_value_->DataLengthInBytes();
+  }
 #if DCHECK_IS_ON()
   if (exception_state.HadException())
     had_exception_ = true;
@@ -82,9 +81,9 @@
 
 void IDBValueWrapper::Clone(ScriptState* script_state, ScriptValue* clone) {
 #if DCHECK_IS_ON()
-  DCHECK(!had_exception_) << __FUNCTION__
+  DCHECK(!had_exception_) << __func__
                           << " called on wrapper with serialization exception";
-  DCHECK(!wrap_called_) << "Clone() called after WrapIfBiggerThan()";
+  DCHECK(!done_cloning_) << __func__ << " called after DoneCloning()";
 #endif  // DCHECK_IS_ON()
 
   bool read_wasm_from_stream = true;
@@ -95,7 +94,8 @@
                                   &blob_info_, read_wasm_from_stream);
 }
 
-void IDBValueWrapper::WriteVarint(unsigned value, Vector<char>& output) {
+// static
+void IDBValueWrapper::WriteVarInt(unsigned value, Vector<char>& output) {
   // Writes an unsigned integer as a base-128 varint.
   // The number is written, 7 bits at a time, from the least significant to
   // the most significant 7 bits. Each byte, except the last, has the MSB set.
@@ -107,22 +107,39 @@
   output.back() &= 0x7F;
 }
 
-bool IDBValueWrapper::WrapIfBiggerThan(unsigned max_bytes) {
+// static
+void IDBValueWrapper::WriteBytes(const Vector<uint8_t>& bytes,
+                                 Vector<char>& output) {
+  IDBValueWrapper::WriteVarInt(bytes.size(), output);
+  output.Append(bytes.data(), bytes.size());
+}
+
+void IDBValueWrapper::DoneCloning() {
 #if DCHECK_IS_ON()
-  DCHECK(!had_exception_) << __FUNCTION__
+  DCHECK(!had_exception_) << __func__
                           << " called on wrapper with serialization exception";
-  DCHECK(!wrap_called_) << __FUNCTION__ << " called twice on the same wrapper";
-  wrap_called_ = true;
+  DCHECK(!done_cloning_) << __func__ << " called twice";
+  done_cloning_ = true;
 #endif  // DCHECK_IS_ON()
 
-  StringView wire_data = serialized_value_->GetWireData();
-  DCHECK(wire_data.Is8Bit());
-  unsigned wire_data_size = wire_data.length();
-  if (wire_data_size <= max_bytes) {
-    wire_bytes_.ReserveInitialCapacity(wire_data_size);
-    wire_bytes_.Append(wire_data.Characters8(), wire_data_size);
+  wire_data_ = serialized_value_->GetWireData();
+  DCHECK(wire_data_.Is8Bit());
+  for (const auto& kvp : serialized_value_->BlobDataHandles())
+    blob_handles_.push_back(std::move(kvp.value));
+}
+
+bool IDBValueWrapper::WrapIfBiggerThan(unsigned max_bytes) {
+#if DCHECK_IS_ON()
+  DCHECK(done_cloning_) << __func__ << " called before DoneCloning()";
+  DCHECK(owns_blob_handles_)
+      << __func__ << " called after TakeBlobDataHandles()";
+  DCHECK(owns_blob_info_) << __func__ << " called after TakeBlobInfo()";
+  DCHECK(owns_wire_bytes_) << __func__ << " called after TakeWireBytes()";
+#endif  // DCHECK_IS_ON()
+
+  unsigned wire_data_size = wire_data_.length();
+  if (wire_data_size <= max_bytes)
     return false;
-  }
 
   // TODO(pwnall): The MIME type should probably be an atomic string.
   String mime_type(kWrapMimeType);
@@ -130,37 +147,48 @@
   //                         Blob::Create to avoid a buffer copy.
   std::unique_ptr<BlobData> wrapper_blob_data = BlobData::Create();
   wrapper_blob_data->SetContentType(String(kWrapMimeType));
-  wrapper_blob_data->AppendBytes(wire_data.Characters8(), wire_data_size);
-  wrapper_handle_ =
+  wrapper_blob_data->AppendBytes(wire_data_.Characters8(), wire_data_size);
+  scoped_refptr<BlobDataHandle> wrapper_handle =
       BlobDataHandle::Create(std::move(wrapper_blob_data), wire_data_size);
-  blob_info_.emplace_back(wrapper_handle_->Uuid(), wrapper_handle_->GetType(),
+  blob_info_.emplace_back(wrapper_handle->Uuid(), wrapper_handle->GetType(),
                           wire_data_size);
+  blob_handles_.push_back(std::move(wrapper_handle));
 
-  wire_bytes_.clear();
-  wire_bytes_.push_back(kVersionTag);
-  wire_bytes_.push_back(kRequiresProcessingSSVPseudoVersion);
-  wire_bytes_.push_back(kBlobWrappedValue);
-  IDBValueWrapper::WriteVarint(wrapper_handle_->size(), wire_bytes_);
-  IDBValueWrapper::WriteVarint(serialized_value_->BlobDataHandles().size(),
-                               wire_bytes_);
+  wire_data_buffer_.clear();
+  wire_data_buffer_.push_back(kVersionTag);
+  wire_data_buffer_.push_back(kRequiresProcessingSSVPseudoVersion);
+  wire_data_buffer_.push_back(kReplaceWithBlob);
+  IDBValueWrapper::WriteVarInt(wire_data_size, wire_data_buffer_);
+  IDBValueWrapper::WriteVarInt(serialized_value_->BlobDataHandles().size(),
+                               wire_data_buffer_);
+
+  wire_data_ = StringView(wire_data_buffer_.data(), wire_data_buffer_.size());
+  DCHECK(!wire_data_buffer_.IsEmpty());
+  DCHECK(wire_data_.Is8Bit());
   return true;
 }
 
-void IDBValueWrapper::ExtractBlobDataHandles(
-    Vector<scoped_refptr<BlobDataHandle>>* blob_data_handles) {
-  for (const auto& kvp : serialized_value_->BlobDataHandles())
-    blob_data_handles->push_back(kvp.value);
-  if (wrapper_handle_)
-    blob_data_handles->push_back(std::move(wrapper_handle_));
-}
-
-scoped_refptr<SharedBuffer> IDBValueWrapper::ExtractWireBytes() {
+scoped_refptr<SharedBuffer> IDBValueWrapper::TakeWireBytes() {
 #if DCHECK_IS_ON()
-  DCHECK(!had_exception_) << __FUNCTION__
-                          << " called on wrapper with serialization exception";
+  DCHECK(done_cloning_) << __func__ << " called before DoneCloning()";
+  DCHECK(owns_wire_bytes_) << __func__ << " called twice";
+  owns_wire_bytes_ = false;
 #endif  // DCHECK_IS_ON()
 
-  return SharedBuffer::AdoptVector(wire_bytes_);
+  if (wire_data_buffer_.IsEmpty()) {
+    // The wire bytes are coming directly from the SSV's GetWireData() call.
+    DCHECK_EQ(wire_data_.Characters8(),
+              serialized_value_->GetWireData().Characters8());
+    DCHECK_EQ(wire_data_.length(), serialized_value_->GetWireData().length());
+    return SharedBuffer::Create(wire_data_.Characters8(),
+                                static_cast<size_t>(wire_data_.length()));
+  }
+
+  // The wire bytes are coming from wire_data_buffer_, so we can avoid a copy.
+  DCHECK_EQ(wire_data_buffer_.data(),
+            reinterpret_cast<const char*>(wire_data_.Characters8()));
+  DCHECK_EQ(wire_data_buffer_.size(), wire_data_.length());
+  return SharedBuffer::AdoptVector(wire_data_buffer_);
 }
 
 IDBValueUnwrapper::IDBValueUnwrapper() {
@@ -176,7 +204,7 @@
 
   return header[0] == kVersionTag &&
          header[1] == kRequiresProcessingSSVPseudoVersion &&
-         header[2] == kBlobWrappedValue;
+         header[2] == kReplaceWithBlob;
 }
 
 bool IDBValueUnwrapper::IsWrapped(
@@ -225,11 +253,11 @@
   end_ = data + value->data_->size();
   current_ = data + 3;
 
-  if (!ReadVarint(blob_size_))
+  if (!ReadVarInt(blob_size_))
     return Reset();
 
   unsigned blob_offset;
-  if (!ReadVarint(blob_offset))
+  if (!ReadVarInt(blob_offset))
     return Reset();
 
   size_t value_blob_count = value->blob_data_->size();
@@ -249,7 +277,7 @@
   return std::move(blob_handle_);
 }
 
-bool IDBValueUnwrapper::ReadVarint(unsigned& value) {
+bool IDBValueUnwrapper::ReadVarInt(unsigned& value) {
   value = 0;
   unsigned shift = 0;
   bool has_another_byte;
@@ -269,6 +297,22 @@
   return true;
 }
 
+bool IDBValueUnwrapper::ReadBytes(Vector<uint8_t>& value) {
+  unsigned length;
+  if (!ReadVarInt(length))
+    return false;
+
+  DCHECK_LE(current_, end_);
+  if (end_ - current_ < static_cast<ptrdiff_t>(length))
+    return false;
+  Vector<uint8_t> result;
+  result.ReserveInitialCapacity(length);
+  result.Append(current_, length);
+  value = std::move(result);
+  current_ += length;
+  return true;
+}
+
 bool IDBValueUnwrapper::Reset() {
 #if DCHECK_IS_ON()
   blob_handle_ = nullptr;
diff --git a/third_party/WebKit/Source/modules/indexeddb/IDBValueWrapping.h b/third_party/WebKit/Source/modules/indexeddb/IDBValueWrapping.h
index ea1063c..8ff67bc 100644
--- a/third_party/WebKit/Source/modules/indexeddb/IDBValueWrapping.h
+++ b/third_party/WebKit/Source/modules/indexeddb/IDBValueWrapping.h
@@ -12,6 +12,7 @@
 #include "platform/SharedBuffer.h"
 #include "platform/wtf/Allocator.h"
 #include "platform/wtf/Vector.h"
+#include "platform/wtf/text/StringView.h"
 #include "public/platform/WebBlobInfo.h"
 #include "v8/include/v8.h"
 
@@ -28,6 +29,29 @@
 
 // Logic for serializing V8 values for storage in IndexedDB.
 //
+// An IDBValueWrapper instance drives the serialization of a single V8 value to
+// IndexedDB. An instance's lifecycle goes through the following stages:
+// 1) Cloning - Right after an instance is constructed, its internal
+//    representation is optimized for structured cloning via the Clone() method.
+//    This may be necessary when extracting the primary key and/or index keys
+//    for the serialized value.
+// 2) Wrapping - DoneCloning() transitions the instance to an internal
+//    reprensetation optimized for wrapping via WrapIfBiggerThan().
+// 3) Reading results - After any desired wrapping is performed, the Take*()
+//    methods yield the serialized value components passed to the backing store.
+//    To avoid unnecessary copies, the Take*() methods move out parts of the
+//    internal representation, so each Take*() method can be called at most
+//    once.
+//
+// Example usage:
+//     auto wrapper = new IDBValueWrapper();
+//     wrapper.Clone(...);  // Structured clone used to extract keys.
+//     wrapper.DoneCloning();
+//     wrapper.WrapIfBiggerThan(kWrapThreshold);
+//     wrapper.TakeWireBytes();
+//     wrapper.TakeBlobDataHandles();
+//     wrapper.TakeBlobInfo();
+//
 // V8 values are stored on disk using the format implemented in
 // SerializedScriptValue (SSV), which is essentialy a byte array plus an array
 // of attached Blobs. For "normal" (not too large) V8 values, the SSV output's
@@ -62,6 +86,10 @@
   //
   // The serialization process can throw an exception. The caller is responsible
   // for checking exception_state.
+  //
+  // The wrapper's internal representation is optimized for cloning the
+  // serialized value. DoneCloning() must be called to transition to an internal
+  // representation optimized for writing.
   IDBValueWrapper(
       v8::Isolate*,
       v8::Local<v8::Value>,
@@ -75,41 +103,55 @@
   // a value's key and index keys are extracted from a structured clone of the
   // value, which avoids the issue of side-effects in custom getters.
   //
-  // This method cannot be called after WrapIfBiggerThan().
+  // This method cannot be called after DoneCloning().
   void Clone(ScriptState*, ScriptValue* clone);
 
+  // Optimizes the serialized value's internal representation for writing to
+  // disk.
+  //
+  // This must be called before Take*() methods can be called. After this method
+  // is called, Clone() cannot be called anymore.
+  void DoneCloning();
+
   // Conditionally wraps the serialized value's byte array into a Blob.
   //
   // The byte array is wrapped if its size exceeds max_bytes. In production, the
   // max_bytes threshold is currently always kWrapThreshold.
   //
-  // This method must be called before ExtractWireBytes() and cannot be called
-  // after ExtractWireBytes().
+  // This method must be called before the Take*() methods are called.
   bool WrapIfBiggerThan(unsigned max_bytes);
 
-  // Obtains the BlobDataHandles from the serialized value's Blob array.
-  //
-  // This method must be called at most once, and must be called after
-  // WrapIfBiggerThan().
-  void ExtractBlobDataHandles(
-      Vector<scoped_refptr<BlobDataHandle>>* blob_data_handles);
-
   // Obtains the byte array for the serialized value.
   //
   // This method must be called at most once, and must be called after
   // WrapIfBiggerThan().
-  scoped_refptr<SharedBuffer> ExtractWireBytes();
+  scoped_refptr<SharedBuffer> TakeWireBytes();
+
+  // Obtains the BlobDataHandles from the serialized value's Blob array.
+  //
+  // This method must be called at most once, and must be called after
+  // DoneCloning().
+  Vector<scoped_refptr<BlobDataHandle>> TakeBlobDataHandles() {
+#if DCHECK_IS_ON()
+    DCHECK(done_cloning_) << __func__ << " called before DoneCloning()";
+    DCHECK(owns_blob_handles_) << __func__ << " called twice";
+    owns_blob_handles_ = false;
+#endif  // DCHECK_IS_ON()
+
+    return std::move(blob_handles_);
+  }
 
   // Obtains WebBlobInfos for the serialized value's Blob array.
   //
   // This method must be called at most once, and must be called after
-  // WrapIfBiggerThan().
-  inline Vector<WebBlobInfo>& WrappedBlobInfo() {
+  // DoneCloning().
+  inline Vector<WebBlobInfo> TakeBlobInfo() {
 #if DCHECK_IS_ON()
-    DCHECK(!had_exception_)
-        << "WrapBlobInfo() called on wrapper with serialization exception";
+    DCHECK(done_cloning_) << __func__ << " called before DoneCloning()";
+    DCHECK(owns_blob_info_) << __func__ << " called twice";
+    owns_blob_info_ = false;
 #endif  // DCHECK_IS_ON()
-    return blob_info_;
+    return std::move(blob_info_);
   }
 
   size_t DataLengthBeforeWrapInBytes() { return original_data_length_; }
@@ -128,17 +170,32 @@
       "application/vnd.blink-idb-value-wrapper";
 
   // Used to serialize the wrapped value. Exposed for testing.
-  static void WriteVarint(unsigned value, Vector<char>& output);
+  static void WriteVarInt(unsigned value, Vector<char>& output);
+  static void WriteBytes(const Vector<uint8_t>& bytes, Vector<char>& output);
 
  private:
+  // V8 value serialization state.
   scoped_refptr<SerializedScriptValue> serialized_value_;
-  scoped_refptr<BlobDataHandle> wrapper_handle_;
+  Vector<scoped_refptr<BlobDataHandle>> blob_handles_;
   Vector<WebBlobInfo> blob_info_;
-  Vector<char> wire_bytes_;
+
+  // Buffer for wire data that is not stored in SerializedScriptValue.
+  //
+  // This buffer ends up storing metadata generated by wrapping operations.
+  Vector<char> wire_data_buffer_;
+
+  // Points into SerializedScriptValue's data buffer, or into wire_data_buffer_.
+  StringView wire_data_;
+
   size_t original_data_length_ = 0;
+
 #if DCHECK_IS_ON()
+  // Accounting for lifecycle stages.
   bool had_exception_ = false;
-  bool wrap_called_ = false;
+  bool done_cloning_ = false;
+  bool owns_blob_handles_ = true;
+  bool owns_blob_info_ = true;
+  bool owns_wire_bytes_ = true;
 #endif  // DCHECK_IS_ON()
 };
 
@@ -189,10 +246,11 @@
 
  private:
   // Only present in tests.
-  friend class IDBValueUnwrapperReadVarintTestHelper;
+  friend class IDBValueUnwrapperReadTestHelper;
 
   // Used to deserialize the wrapped value.
-  bool ReadVarint(unsigned& value);
+  bool ReadVarInt(unsigned&);
+  bool ReadBytes(Vector<uint8_t>&);
 
   // Resets the parsing state.
   bool Reset();
diff --git a/third_party/WebKit/Source/modules/indexeddb/IDBValueWrappingTest.cpp b/third_party/WebKit/Source/modules/indexeddb/IDBValueWrappingTest.cpp
index c9d7318..1afd50e 100644
--- a/third_party/WebKit/Source/modules/indexeddb/IDBValueWrappingTest.cpp
+++ b/third_party/WebKit/Source/modules/indexeddb/IDBValueWrappingTest.cpp
@@ -4,6 +4,7 @@
 
 #include "modules/indexeddb/IDBValueWrapping.h"
 
+#include <algorithm>
 #include <limits>
 #include <memory>
 
@@ -20,65 +21,65 @@
 
 namespace blink {
 
-TEST(IDBValueWrapperTest, WriteVarintOneByte) {
+TEST(IDBValueWrapperTest, WriteVarIntOneByte) {
   Vector<char> output;
 
-  IDBValueWrapper::WriteVarint(0, output);
+  IDBValueWrapper::WriteVarInt(0, output);
   ASSERT_EQ(1U, output.size());
   EXPECT_EQ('\x00', output.data()[0]);
   output.clear();
 
-  IDBValueWrapper::WriteVarint(1, output);
+  IDBValueWrapper::WriteVarInt(1, output);
   ASSERT_EQ(1U, output.size());
   EXPECT_EQ('\x01', output.data()[0]);
   output.clear();
 
-  IDBValueWrapper::WriteVarint(0x34, output);
+  IDBValueWrapper::WriteVarInt(0x34, output);
   ASSERT_EQ(1U, output.size());
   EXPECT_EQ('\x34', output.data()[0]);
   output.clear();
 
-  IDBValueWrapper::WriteVarint(0x7f, output);
+  IDBValueWrapper::WriteVarInt(0x7f, output);
   ASSERT_EQ(1U, output.size());
   EXPECT_EQ('\x7f', output.data()[0]);
 }
 
-TEST(IDBValueWrapperTest, WriteVarintMultiByte) {
+TEST(IDBValueWrapperTest, WriteVarIntMultiByte) {
   Vector<char> output;
 
-  IDBValueWrapper::WriteVarint(0xff, output);
+  IDBValueWrapper::WriteVarInt(0xff, output);
   ASSERT_EQ(2U, output.size());
   EXPECT_EQ('\xff', output.data()[0]);
   EXPECT_EQ('\x01', output.data()[1]);
   output.clear();
 
-  IDBValueWrapper::WriteVarint(0x100, output);
+  IDBValueWrapper::WriteVarInt(0x100, output);
   ASSERT_EQ(2U, output.size());
   EXPECT_EQ('\x80', output.data()[0]);
   EXPECT_EQ('\x02', output.data()[1]);
   output.clear();
 
-  IDBValueWrapper::WriteVarint(0x1234, output);
+  IDBValueWrapper::WriteVarInt(0x1234, output);
   ASSERT_EQ(2U, output.size());
   EXPECT_EQ('\xb4', output.data()[0]);
   EXPECT_EQ('\x24', output.data()[1]);
   output.clear();
 
-  IDBValueWrapper::WriteVarint(0xabcd, output);
+  IDBValueWrapper::WriteVarInt(0xabcd, output);
   ASSERT_EQ(3U, output.size());
   EXPECT_EQ('\xcd', output.data()[0]);
   EXPECT_EQ('\xd7', output.data()[1]);
   EXPECT_EQ('\x2', output.data()[2]);
   output.clear();
 
-  IDBValueWrapper::WriteVarint(0x123456, output);
+  IDBValueWrapper::WriteVarInt(0x123456, output);
   ASSERT_EQ(3U, output.size());
   EXPECT_EQ('\xd6', output.data()[0]);
   EXPECT_EQ('\xe8', output.data()[1]);
   EXPECT_EQ('\x48', output.data()[2]);
   output.clear();
 
-  IDBValueWrapper::WriteVarint(0xabcdef, output);
+  IDBValueWrapper::WriteVarInt(0xabcdef, output);
   ASSERT_EQ(4U, output.size());
   EXPECT_EQ('\xef', output.data()[0]);
   EXPECT_EQ('\x9b', output.data()[1]);
@@ -87,36 +88,36 @@
   output.clear();
 }
 
-TEST(IDBValueWrapperTest, WriteVarintMultiByteEdgeCases) {
+TEST(IDBValueWrapperTest, WriteVarIntMultiByteEdgeCases) {
   Vector<char> output;
 
-  IDBValueWrapper::WriteVarint(0x80, output);
+  IDBValueWrapper::WriteVarInt(0x80, output);
   ASSERT_EQ(2U, output.size());
   EXPECT_EQ('\x80', output.data()[0]);
   EXPECT_EQ('\x01', output.data()[1]);
   output.clear();
 
-  IDBValueWrapper::WriteVarint(0x3fff, output);
+  IDBValueWrapper::WriteVarInt(0x3fff, output);
   ASSERT_EQ(2U, output.size());
   EXPECT_EQ('\xff', output.data()[0]);
   EXPECT_EQ('\x7f', output.data()[1]);
   output.clear();
 
-  IDBValueWrapper::WriteVarint(0x4000, output);
+  IDBValueWrapper::WriteVarInt(0x4000, output);
   ASSERT_EQ(3U, output.size());
   EXPECT_EQ('\x80', output.data()[0]);
   EXPECT_EQ('\x80', output.data()[1]);
   EXPECT_EQ('\x01', output.data()[2]);
   output.clear();
 
-  IDBValueWrapper::WriteVarint(0x1fffff, output);
+  IDBValueWrapper::WriteVarInt(0x1fffff, output);
   ASSERT_EQ(3U, output.size());
   EXPECT_EQ('\xff', output.data()[0]);
   EXPECT_EQ('\xff', output.data()[1]);
   EXPECT_EQ('\x7f', output.data()[2]);
   output.clear();
 
-  IDBValueWrapper::WriteVarint(0x200000, output);
+  IDBValueWrapper::WriteVarInt(0x200000, output);
   ASSERT_EQ(4U, output.size());
   EXPECT_EQ('\x80', output.data()[0]);
   EXPECT_EQ('\x80', output.data()[1]);
@@ -124,7 +125,7 @@
   EXPECT_EQ('\x01', output.data()[3]);
   output.clear();
 
-  IDBValueWrapper::WriteVarint(0xfffffff, output);
+  IDBValueWrapper::WriteVarInt(0xfffffff, output);
   ASSERT_EQ(4U, output.size());
   EXPECT_EQ('\xff', output.data()[0]);
   EXPECT_EQ('\xff', output.data()[1]);
@@ -132,7 +133,7 @@
   EXPECT_EQ('\x7f', output.data()[3]);
   output.clear();
 
-  IDBValueWrapper::WriteVarint(0x10000000, output);
+  IDBValueWrapper::WriteVarInt(0x10000000, output);
   ASSERT_EQ(5U, output.size());
   EXPECT_EQ('\x80', output.data()[0]);
   EXPECT_EQ('\x80', output.data()[1]);
@@ -142,7 +143,7 @@
   output.clear();
 
   // Maximum value of unsigned on 32-bit platforms.
-  IDBValueWrapper::WriteVarint(0xffffffff, output);
+  IDBValueWrapper::WriteVarInt(0xffffffff, output);
   ASSERT_EQ(5U, output.size());
   EXPECT_EQ('\xff', output.data()[0]);
   EXPECT_EQ('\xff', output.data()[1]);
@@ -152,216 +153,322 @@
   output.clear();
 }
 
+TEST(IDBValueWrapperTest, WriteBytes) {
+  Vector<char> output;
+
+  Vector<uint8_t> empty;
+  IDBValueWrapper::WriteBytes(empty, output);
+  ASSERT_EQ(1U, output.size());
+  EXPECT_EQ('\x00', output.data()[0]);
+  output.clear();
+
+  Vector<uint8_t> one_char;
+  one_char.Append("\x42", 1);
+  IDBValueWrapper::WriteBytes(one_char, output);
+  ASSERT_EQ(2U, output.size());
+  EXPECT_EQ('\x01', output.data()[0]);
+  EXPECT_EQ('\x42', output.data()[1]);
+  output.clear();
+
+  Vector<uint8_t> long_vector;
+  for (int i = 0; i < 256; ++i)
+    long_vector.push_back(static_cast<uint8_t>(i));
+  IDBValueWrapper::WriteBytes(long_vector, output);
+  ASSERT_EQ(258U, output.size());
+  EXPECT_EQ('\x80', output.data()[0]);
+  EXPECT_EQ('\x02', output.data()[1]);
+  EXPECT_TRUE(std::equal(long_vector.begin(), long_vector.end(),
+                         reinterpret_cast<const uint8_t*>(output.data() + 2)));
+  output.clear();
+}
+
 // Friend class of IDBValueUnwrapper with access to its internals.
-class IDBValueUnwrapperReadVarintTestHelper {
+class IDBValueUnwrapperReadTestHelper {
  public:
-  void ReadVarint(const char* start, size_t buffer_size) {
+  void ReadVarInt(const char* start, size_t buffer_size) {
     IDBValueUnwrapper unwrapper;
 
     const uint8_t* buffer_start = reinterpret_cast<const uint8_t*>(start);
     const uint8_t* buffer_end = buffer_start + buffer_size;
     unwrapper.current_ = buffer_start;
     unwrapper.end_ = buffer_end;
-    success_ = unwrapper.ReadVarint(read_value_);
+    success_ = unwrapper.ReadVarInt(read_varint_);
 
     ASSERT_EQ(unwrapper.end_, buffer_end)
-        << "ReadVarint should not change end_";
+        << "ReadVarInt should not change end_";
     ASSERT_LE(unwrapper.current_, unwrapper.end_)
-        << "ReadVarint should not move current_ past end_";
+        << "ReadVarInt should not move current_ past end_";
+    consumed_bytes_ = unwrapper.current_ - buffer_start;
+  }
+
+  void ReadBytes(const char* start, size_t buffer_size) {
+    IDBValueUnwrapper unwrapper;
+
+    const uint8_t* buffer_start = reinterpret_cast<const uint8_t*>(start);
+    const uint8_t* buffer_end = buffer_start + buffer_size;
+    unwrapper.current_ = buffer_start;
+    unwrapper.end_ = buffer_end;
+    success_ = unwrapper.ReadBytes(read_bytes_);
+
+    ASSERT_EQ(unwrapper.end_, buffer_end) << "ReadBytes should not change end_";
+    ASSERT_LE(unwrapper.current_, unwrapper.end_)
+        << "ReadBytes should not move current_ past end_";
     consumed_bytes_ = unwrapper.current_ - buffer_start;
   }
 
   bool success() { return success_; }
   unsigned consumed_bytes() { return consumed_bytes_; }
-  unsigned read_value() { return read_value_; }
+  unsigned read_varint() { return read_varint_; }
+  const Vector<uint8_t>& read_bytes() { return read_bytes_; }
 
  private:
   bool success_;
   unsigned consumed_bytes_;
-  unsigned read_value_;
+  unsigned read_varint_;
+  Vector<uint8_t> read_bytes_;
 };
 
-TEST(IDBValueUnwrapperTest, ReadVarintOneByte) {
-  IDBValueUnwrapperReadVarintTestHelper helper;
+TEST(IDBValueUnwrapperTest, ReadVarIntOneByte) {
+  IDBValueUnwrapperReadTestHelper helper;
 
   // Most test cases have an extra byte at the end of the input to verify that
   // the parser doesn't consume too much data.
 
-  helper.ReadVarint("\x00\x01", 2);
+  helper.ReadVarInt("\x00\x01", 2);
   EXPECT_TRUE(helper.success());
-  EXPECT_EQ(0U, helper.read_value());
+  EXPECT_EQ(0U, helper.read_varint());
   EXPECT_EQ(1U, helper.consumed_bytes());
 
-  helper.ReadVarint("\x01\x01", 2);
+  helper.ReadVarInt("\x01\x01", 2);
   EXPECT_TRUE(helper.success());
-  EXPECT_EQ(1U, helper.read_value());
+  EXPECT_EQ(1U, helper.read_varint());
   EXPECT_EQ(1U, helper.consumed_bytes());
 
-  helper.ReadVarint("\x7f\x01", 2);
+  helper.ReadVarInt("\x7f\x01", 2);
   EXPECT_TRUE(helper.success());
-  EXPECT_EQ(0x7fU, helper.read_value());
+  EXPECT_EQ(0x7fU, helper.read_varint());
   EXPECT_EQ(1U, helper.consumed_bytes());
 
-  helper.ReadVarint("\x7f\x01", 1);
+  helper.ReadVarInt("\x7f\x01", 1);
   EXPECT_TRUE(helper.success());
-  EXPECT_EQ(0x7fU, helper.read_value());
+  EXPECT_EQ(0x7fU, helper.read_varint());
   EXPECT_EQ(1U, helper.consumed_bytes());
 }
 
-TEST(IDBValueUnwrapperTest, ReadVarintMultiBytes) {
-  IDBValueUnwrapperReadVarintTestHelper helper;
+TEST(IDBValueUnwrapperTest, ReadVarIntMultiBytes) {
+  IDBValueUnwrapperReadTestHelper helper;
 
-  helper.ReadVarint("\xff\x01\x01", 3);
+  helper.ReadVarInt("\xff\x01\x01", 3);
   EXPECT_TRUE(helper.success());
-  EXPECT_EQ(0xffU, helper.read_value());
+  EXPECT_EQ(0xffU, helper.read_varint());
   EXPECT_EQ(2U, helper.consumed_bytes());
 
-  helper.ReadVarint("\x80\x02\x01", 3);
+  helper.ReadVarInt("\x80\x02\x01", 3);
   EXPECT_TRUE(helper.success());
-  EXPECT_EQ(0x100U, helper.read_value());
+  EXPECT_EQ(0x100U, helper.read_varint());
   EXPECT_EQ(2U, helper.consumed_bytes());
 
-  helper.ReadVarint("\xb4\x24\x01", 3);
+  helper.ReadVarInt("\xb4\x24\x01", 3);
   EXPECT_TRUE(helper.success());
-  EXPECT_EQ(0x1234U, helper.read_value());
+  EXPECT_EQ(0x1234U, helper.read_varint());
   EXPECT_EQ(2U, helper.consumed_bytes());
 
-  helper.ReadVarint("\xcd\xd7\x02\x01", 4);
+  helper.ReadVarInt("\xcd\xd7\x02\x01", 4);
   EXPECT_TRUE(helper.success());
-  EXPECT_EQ(0xabcdU, helper.read_value());
+  EXPECT_EQ(0xabcdU, helper.read_varint());
   EXPECT_EQ(3U, helper.consumed_bytes());
 
-  helper.ReadVarint("\xd6\xe8\x48\x01", 4);
+  helper.ReadVarInt("\xd6\xe8\x48\x01", 4);
   EXPECT_TRUE(helper.success());
-  EXPECT_EQ(0x123456U, helper.read_value());
+  EXPECT_EQ(0x123456U, helper.read_varint());
   EXPECT_EQ(3U, helper.consumed_bytes());
 
-  helper.ReadVarint("\xd6\xe8\x48\x01", 3);
+  helper.ReadVarInt("\xd6\xe8\x48\x01", 3);
   EXPECT_TRUE(helper.success());
-  EXPECT_EQ(0x123456U, helper.read_value());
+  EXPECT_EQ(0x123456U, helper.read_varint());
   EXPECT_EQ(3U, helper.consumed_bytes());
 
-  helper.ReadVarint("\xef\x9b\xaf\x05\x01", 5);
+  helper.ReadVarInt("\xef\x9b\xaf\x05\x01", 5);
   EXPECT_TRUE(helper.success());
-  EXPECT_EQ(0xabcdefU, helper.read_value());
+  EXPECT_EQ(0xabcdefU, helper.read_varint());
   EXPECT_EQ(4U, helper.consumed_bytes());
 
-  helper.ReadVarint("\xef\x9b\xaf\x05\x01", 4);
+  helper.ReadVarInt("\xef\x9b\xaf\x05\x01", 4);
   EXPECT_TRUE(helper.success());
-  EXPECT_EQ(0xabcdefU, helper.read_value());
+  EXPECT_EQ(0xabcdefU, helper.read_varint());
   EXPECT_EQ(4U, helper.consumed_bytes());
 }
 
-TEST(IDBValueUnwrapperTest, ReadVarintMultiByteEdgeCases) {
-  IDBValueUnwrapperReadVarintTestHelper helper;
+TEST(IDBValueUnwrapperTest, ReadVarIntMultiByteEdgeCases) {
+  IDBValueUnwrapperReadTestHelper helper;
 
-  helper.ReadVarint("\x80\x01\x01", 3);
+  helper.ReadVarInt("\x80\x01\x01", 3);
   EXPECT_TRUE(helper.success());
-  EXPECT_EQ(0x80U, helper.read_value());
+  EXPECT_EQ(0x80U, helper.read_varint());
   EXPECT_EQ(2U, helper.consumed_bytes());
 
-  helper.ReadVarint("\xff\x7f\x01", 3);
+  helper.ReadVarInt("\xff\x7f\x01", 3);
   EXPECT_TRUE(helper.success());
-  EXPECT_EQ(0x3fffU, helper.read_value());
+  EXPECT_EQ(0x3fffU, helper.read_varint());
   EXPECT_EQ(2U, helper.consumed_bytes());
 
-  helper.ReadVarint("\x80\x80\x01\x01", 4);
+  helper.ReadVarInt("\x80\x80\x01\x01", 4);
   EXPECT_TRUE(helper.success());
-  EXPECT_EQ(0x4000U, helper.read_value());
+  EXPECT_EQ(0x4000U, helper.read_varint());
   EXPECT_EQ(3U, helper.consumed_bytes());
 
-  helper.ReadVarint("\xff\xff\x7f\x01", 4);
+  helper.ReadVarInt("\xff\xff\x7f\x01", 4);
   EXPECT_TRUE(helper.success());
-  EXPECT_EQ(0x1fffffU, helper.read_value());
+  EXPECT_EQ(0x1fffffU, helper.read_varint());
   EXPECT_EQ(3U, helper.consumed_bytes());
 
-  helper.ReadVarint("\x80\x80\x80\x01\x01", 5);
+  helper.ReadVarInt("\x80\x80\x80\x01\x01", 5);
   EXPECT_TRUE(helper.success());
-  EXPECT_EQ(0x200000U, helper.read_value());
+  EXPECT_EQ(0x200000U, helper.read_varint());
   EXPECT_EQ(4U, helper.consumed_bytes());
 
-  helper.ReadVarint("\xff\xff\xff\x7f\x01", 5);
+  helper.ReadVarInt("\xff\xff\xff\x7f\x01", 5);
   EXPECT_TRUE(helper.success());
-  EXPECT_EQ(0xfffffffU, helper.read_value());
+  EXPECT_EQ(0xfffffffU, helper.read_varint());
   EXPECT_EQ(4U, helper.consumed_bytes());
 
-  helper.ReadVarint("\x80\x80\x80\x80\x01\x01", 6);
+  helper.ReadVarInt("\x80\x80\x80\x80\x01\x01", 6);
   EXPECT_TRUE(helper.success());
-  EXPECT_EQ(0x10000000U, helper.read_value());
+  EXPECT_EQ(0x10000000U, helper.read_varint());
   EXPECT_EQ(5U, helper.consumed_bytes());
 
-  helper.ReadVarint("\xff\xff\xff\xff\x0f\x01", 6);
+  helper.ReadVarInt("\xff\xff\xff\xff\x0f\x01", 6);
   EXPECT_TRUE(helper.success());
-  EXPECT_EQ(0xffffffffU, helper.read_value());
+  EXPECT_EQ(0xffffffffU, helper.read_varint());
   EXPECT_EQ(5U, helper.consumed_bytes());
 }
 
-TEST(IDBValueUnwrapperTest, ReadVarintTruncatedInput) {
-  IDBValueUnwrapperReadVarintTestHelper helper;
+TEST(IDBValueUnwrapperTest, ReadVarIntTruncatedInput) {
+  IDBValueUnwrapperReadTestHelper helper;
 
-  helper.ReadVarint("\x01", 0);
+  helper.ReadVarInt("\x01", 0);
   EXPECT_FALSE(helper.success());
 
-  helper.ReadVarint("\x80\x01", 1);
+  helper.ReadVarInt("\x80\x01", 1);
   EXPECT_FALSE(helper.success());
 
-  helper.ReadVarint("\xff\x01", 1);
+  helper.ReadVarInt("\xff\x01", 1);
   EXPECT_FALSE(helper.success());
 
-  helper.ReadVarint("\x80\x80\x01", 2);
+  helper.ReadVarInt("\x80\x80\x01", 2);
   EXPECT_FALSE(helper.success());
 
-  helper.ReadVarint("\xff\xff\x01", 2);
+  helper.ReadVarInt("\xff\xff\x01", 2);
   EXPECT_FALSE(helper.success());
 
-  helper.ReadVarint("\x80\x80\x80\x80\x01", 4);
+  helper.ReadVarInt("\x80\x80\x80\x80\x01", 4);
   EXPECT_FALSE(helper.success());
 
-  helper.ReadVarint("\xff\xff\xff\xff\x01", 4);
+  helper.ReadVarInt("\xff\xff\xff\xff\x01", 4);
   EXPECT_FALSE(helper.success());
 }
 
-TEST(IDBValueUnwrapperTest, ReadVarintDenormalizedInput) {
-  IDBValueUnwrapperReadVarintTestHelper helper;
+TEST(IDBValueUnwrapperTest, ReadVarIntDenormalizedInput) {
+  IDBValueUnwrapperReadTestHelper helper;
 
-  helper.ReadVarint("\x80\x00\x01", 3);
+  helper.ReadVarInt("\x80\x00\x01", 3);
   EXPECT_TRUE(helper.success());
-  EXPECT_EQ(0U, helper.read_value());
+  EXPECT_EQ(0U, helper.read_varint());
   EXPECT_EQ(2U, helper.consumed_bytes());
 
-  helper.ReadVarint("\xff\x00\x01", 3);
+  helper.ReadVarInt("\xff\x00\x01", 3);
   EXPECT_TRUE(helper.success());
-  EXPECT_EQ(0x7fU, helper.read_value());
+  EXPECT_EQ(0x7fU, helper.read_varint());
   EXPECT_EQ(2U, helper.consumed_bytes());
 
-  helper.ReadVarint("\x80\x80\x00\x01", 4);
+  helper.ReadVarInt("\x80\x80\x00\x01", 4);
   EXPECT_TRUE(helper.success());
-  EXPECT_EQ(0U, helper.read_value());
+  EXPECT_EQ(0U, helper.read_varint());
   EXPECT_EQ(3U, helper.consumed_bytes());
 
-  helper.ReadVarint("\x80\xff\x00\x01", 4);
+  helper.ReadVarInt("\x80\xff\x00\x01", 4);
   EXPECT_TRUE(helper.success());
-  EXPECT_EQ(0x3f80U, helper.read_value());
+  EXPECT_EQ(0x3f80U, helper.read_varint());
   EXPECT_EQ(3U, helper.consumed_bytes());
 
-  helper.ReadVarint("\x80\xff\x80\xff\x00\x01", 6);
+  helper.ReadVarInt("\x80\xff\x80\xff\x00\x01", 6);
   EXPECT_TRUE(helper.success());
-  EXPECT_EQ(0x0fe03f80U, helper.read_value());
+  EXPECT_EQ(0x0fe03f80U, helper.read_varint());
   EXPECT_EQ(5U, helper.consumed_bytes());
 }
 
-TEST(IDBValueUnwrapperTest, WriteVarintMaxUnsignedRoundtrip) {
+TEST(IDBValueUnwrapperTest, WriteVarIntMaxUnsignedRoundtrip) {
   unsigned max_value = std::numeric_limits<unsigned>::max();
   Vector<char> output;
-  IDBValueWrapper::WriteVarint(max_value, output);
+  IDBValueWrapper::WriteVarInt(max_value, output);
 
-  IDBValueUnwrapperReadVarintTestHelper helper;
-  helper.ReadVarint(output.data(), output.size());
+  IDBValueUnwrapperReadTestHelper helper;
+  helper.ReadVarInt(output.data(), output.size());
   EXPECT_TRUE(helper.success());
-  EXPECT_EQ(max_value, helper.read_value());
+  EXPECT_EQ(max_value, helper.read_varint());
   EXPECT_EQ(output.size(), helper.consumed_bytes());
 }
 
+TEST(IDBValueUnwrapperTest, ReadBytes) {
+  IDBValueUnwrapperReadTestHelper helper;
+
+  // Most test cases have an extra byte at the end of the input to verify that
+  // the parser doesn't consume too much data.
+
+  helper.ReadBytes("\x00\x01", 2);
+  EXPECT_TRUE(helper.success());
+  EXPECT_EQ(0U, helper.read_bytes().size());
+  EXPECT_EQ(1U, helper.consumed_bytes());
+
+  helper.ReadBytes("\x01\x42\x01", 3);
+  EXPECT_TRUE(helper.success());
+  ASSERT_EQ(1U, helper.read_bytes().size());
+  EXPECT_EQ('\x42', helper.read_bytes().data()[0]);
+  EXPECT_EQ(2U, helper.consumed_bytes());
+
+  Vector<uint8_t> long_output;
+  long_output.push_back(0x80);
+  long_output.push_back(0x02);
+  for (int i = 0; i < 256; ++i)
+    long_output.push_back(static_cast<unsigned char>(i));
+  long_output.push_back(0x01);
+  helper.ReadBytes(reinterpret_cast<char*>(long_output.data()),
+                   long_output.size());
+  EXPECT_TRUE(helper.success());
+  ASSERT_EQ(256U, helper.read_bytes().size());
+  ASSERT_EQ(long_output.size() - 1, helper.consumed_bytes());
+  EXPECT_TRUE(std::equal(helper.read_bytes().begin(), helper.read_bytes().end(),
+                         long_output.data() + 2));
+
+  helper.ReadBytes("\x01\x42\x01", 2);
+  EXPECT_TRUE(helper.success());
+  ASSERT_EQ(1U, helper.read_bytes().size());
+  EXPECT_EQ('\x42', helper.read_bytes().data()[0]);
+  EXPECT_EQ(2U, helper.consumed_bytes());
+}
+
+TEST(IDBValueUnwrapperTest, ReadBytesTruncatedInput) {
+  IDBValueUnwrapperReadTestHelper helper;
+
+  helper.ReadBytes("\x01\x42", 0);
+  EXPECT_FALSE(helper.success());
+
+  helper.ReadBytes("\x01\x42", 1);
+  EXPECT_FALSE(helper.success());
+
+  helper.ReadBytes("\x03\x42\x42\x42", 3);
+  EXPECT_FALSE(helper.success());
+}
+
+TEST(IDBValueUnwrapperTest, ReadBytesDenormalizedInput) {
+  IDBValueUnwrapperReadTestHelper helper;
+
+  helper.ReadBytes("\x80\x00\x01", 3);
+  EXPECT_TRUE(helper.success());
+  EXPECT_EQ(0U, helper.read_bytes().size());
+  EXPECT_EQ(2U, helper.consumed_bytes());
+}
+
 TEST(IDBValueUnwrapperTest, IsWrapped) {
   V8TestingScope scope;
   NonThrowableExceptionState non_throwable_exception_state;
@@ -369,12 +476,12 @@
   IDBValueWrapper wrapper(scope.GetIsolate(), v8_true,
                           SerializedScriptValue::SerializeOptions::kSerialize,
                           non_throwable_exception_state);
+  wrapper.DoneCloning();
   wrapper.WrapIfBiggerThan(0);
-  Vector<scoped_refptr<BlobDataHandle>> blob_data_handles;
-  wrapper.ExtractBlobDataHandles(&blob_data_handles);
-  Vector<WebBlobInfo>& blob_infos = wrapper.WrappedBlobInfo();
-  scoped_refptr<SharedBuffer> wrapped_marker_buffer =
-      wrapper.ExtractWireBytes();
+  Vector<scoped_refptr<BlobDataHandle>> blob_data_handles =
+      wrapper.TakeBlobDataHandles();
+  Vector<WebBlobInfo> blob_infos = wrapper.TakeBlobInfo();
+  scoped_refptr<SharedBuffer> wrapped_marker_buffer = wrapper.TakeWireBytes();
   IDBKey* key = IDBKey::CreateNumber(42.0);
   IDBKeyPath key_path(String("primaryKey"));
 
diff --git a/third_party/WebKit/Source/modules/media_controls/elements/MediaControlOverlayPlayButtonElement.cpp b/third_party/WebKit/Source/modules/media_controls/elements/MediaControlOverlayPlayButtonElement.cpp
index 9638f05..2b43094 100644
--- a/third_party/WebKit/Source/modules/media_controls/elements/MediaControlOverlayPlayButtonElement.cpp
+++ b/third_party/WebKit/Source/modules/media_controls/elements/MediaControlOverlayPlayButtonElement.cpp
@@ -6,17 +6,13 @@
 
 #include "core/dom/ElementShadow.h"
 #include "core/dom/events/Event.h"
-#include "core/events/MouseEvent.h"
-#include "core/geometry/DOMRect.h"
 #include "core/html/media/HTMLMediaElement.h"
 #include "core/html/media/HTMLMediaSource.h"
 #include "core/input_type_names.h"
 #include "modules/media_controls/MediaControlsImpl.h"
 #include "modules/media_controls/elements/MediaControlElementsHelper.h"
 #include "platform/runtime_enabled_features.h"
-#include "platform/wtf/Time.h"
 #include "public/platform/Platform.h"
-#include "public/platform/TaskType.h"
 #include "public/platform/WebSize.h"
 
 namespace {
@@ -24,24 +20,6 @@
 // The size of the inner circle button in pixels.
 constexpr int kInnerButtonSize = 56;
 
-// The touch padding of the inner circle button in pixels.
-constexpr int kInnerButtonTouchPaddingSize = 20;
-
-// Check if a point is based within the boundary of a DOMRect with a margin.
-bool IsPointInRect(blink::DOMRect& rect, int margin, int x, int y) {
-  return ((x >= (rect.left() - margin)) && (x <= (rect.right() + margin)) &&
-          (y >= (rect.top() - margin)) && (y <= (rect.bottom() + margin)));
-}
-
-// The delay if a touch is outside the internal button.
-constexpr WTF::TimeDelta kOutsideTouchDelay = TimeDelta::FromMilliseconds(300);
-
-// The delay if a touch is inside the internal button.
-constexpr WTF::TimeDelta kInsideTouchDelay = TimeDelta::FromMilliseconds(0);
-
-// The number of seconds to jump when double tapping.
-constexpr int kNumberOfSecondsToJump = 10;
-
 }  // namespace.
 
 namespace blink {
@@ -56,9 +34,6 @@
 MediaControlOverlayPlayButtonElement::MediaControlOverlayPlayButtonElement(
     MediaControlsImpl& media_controls)
     : MediaControlInputElement(media_controls, kMediaOverlayPlayButton),
-      tap_timer_(GetDocument().GetTaskRunner(TaskType::kMediaElementEvent),
-                 this,
-                 &MediaControlOverlayPlayButtonElement::TapTimerFired),
       internal_button_(nullptr) {
   setType(InputTypeNames::button);
   SetShadowPseudoId(AtomicString("-webkit-media-controls-overlay-play-button"));
@@ -80,99 +55,29 @@
   return "PlayOverlayButton";
 }
 
-void MediaControlOverlayPlayButtonElement::MaybePlayPause() {
-  if (MediaElement().paused()) {
-    Platform::Current()->RecordAction(
-        UserMetricsAction("Media.Controls.PlayOverlay"));
-  } else {
-    Platform::Current()->RecordAction(
-        UserMetricsAction("Media.Controls.PauseOverlay"));
-  }
-
-  // Allow play attempts for plain src= media to force a reload in the error
-  // state. This allows potential recovery for transient network and decoder
-  // resource issues.
-  const String& url = MediaElement().currentSrc().GetString();
-  if (MediaElement().error() && !HTMLMediaElement::IsMediaStreamURL(url) &&
-      !HTMLMediaSource::Lookup(url)) {
-    MediaElement().load();
-  }
-
-  MediaElement().TogglePlayState();
-
-  MaybeRecordInteracted();
-  UpdateDisplayType();
-}
-
-void MediaControlOverlayPlayButtonElement::MaybeJump(int seconds) {
-  double new_time = std::max(0.0, MediaElement().currentTime() + seconds);
-  new_time = std::min(new_time, MediaElement().duration());
-  MediaElement().setCurrentTime(new_time);
-}
-
-void MediaControlOverlayPlayButtonElement::HandlePlayPauseEvent(
-    Event* event,
-    WTF::TimeDelta delay) {
-  event->SetDefaultHandled();
-
-  if (tap_timer_.IsActive())
-    return;
-
-  tap_timer_.StartOneShot(delay, BLINK_FROM_HERE);
-}
-
 void MediaControlOverlayPlayButtonElement::DefaultEventHandler(Event* event) {
   if (event->type() == EventTypeNames::click) {
-    // Double tap to navigate should only be available on modern controls.
-    if (!MediaControlsImpl::IsModern() || !event->IsMouseEvent()) {
-      HandlePlayPauseEvent(event, kInsideTouchDelay);
-      return;
-    }
-
-    // If the event doesn't have position data we should just default to
-    // play/pause.
-    // TODO(beccahughes): Move to PointerEvent.
-    MouseEvent* mouse_event = ToMouseEvent(event);
-    if (!mouse_event->HasPosition()) {
-      HandlePlayPauseEvent(event, kInsideTouchDelay);
-      return;
-    }
-
-    // If the click happened on the internal button or a margin around it then
-    // we should play/pause.
-    if (IsPointInRect(*internal_button_->getBoundingClientRect(),
-                      kInnerButtonTouchPaddingSize, mouse_event->clientX(),
-                      mouse_event->clientY())) {
-      HandlePlayPauseEvent(event, kInsideTouchDelay);
-    } else if (!tap_timer_.IsActive()) {
-      // If there was not a previous touch and this was outside of the button
-      // then we should play/pause but with a small unnoticeable delay to allow
-      // for a secondary tap.
-      HandlePlayPauseEvent(event, kOutsideTouchDelay);
+    if (MediaElement().paused()) {
+      Platform::Current()->RecordAction(
+          UserMetricsAction("Media.Controls.PlayOverlay"));
     } else {
-      // Cancel the play pause event.
-      tap_timer_.Stop();
-
-      if (RuntimeEnabledFeatures::DoubleTapToJumpOnVideoEnabled()) {
-        // Jump forwards or backwards based on the position of the tap.
-        WebSize element_size =
-            MediaControlElementsHelper::GetSizeOrDefault(*this, WebSize(0, 0));
-
-        if (mouse_event->clientX() >= element_size.width / 2) {
-          MaybeJump(kNumberOfSecondsToJump);
-        } else {
-          MaybeJump(kNumberOfSecondsToJump * -1);
-        }
-      } else {
-        // Enter or exit fullscreen.
-        if (MediaElement().IsFullscreen())
-          GetMediaControls().ExitFullscreen();
-        else
-          GetMediaControls().EnterFullscreen();
-      }
-
-      event->SetDefaultHandled();
+      Platform::Current()->RecordAction(
+          UserMetricsAction("Media.Controls.PauseOverlay"));
     }
+
+    // Allow play attempts for plain src= media to force a reload in the error
+    // state. This allows potential recovery for transient network and decoder
+    // resource issues.
+    const String& url = MediaElement().currentSrc().GetString();
+    if (MediaElement().error() && !HTMLMediaElement::IsMediaStreamURL(url) &&
+        !HTMLMediaSource::Lookup(url)) {
+      MediaElement().load();
+    }
+
+    MediaElement().TogglePlayState();
+    UpdateDisplayType();
+    MaybeRecordInteracted();
+    event->SetDefaultHandled();
   }
 
   // TODO(mlamouri): should call MediaControlInputElement::DefaultEventHandler.
@@ -189,14 +94,6 @@
       *internal_button_, WebSize(kInnerButtonSize, kInnerButtonSize));
 }
 
-void MediaControlOverlayPlayButtonElement::TapTimerFired(TimerBase*) {
-  std::unique_ptr<UserGestureIndicator> user_gesture_scope =
-      Frame::NotifyUserActivation(GetDocument().GetFrame(),
-                                  UserGestureToken::kNewGesture);
-
-  MaybePlayPause();
-}
-
 void MediaControlOverlayPlayButtonElement::Trace(blink::Visitor* visitor) {
   MediaControlInputElement::Trace(visitor);
   visitor->Trace(internal_button_);
diff --git a/third_party/WebKit/Source/modules/media_controls/elements/MediaControlOverlayPlayButtonElement.h b/third_party/WebKit/Source/modules/media_controls/elements/MediaControlOverlayPlayButtonElement.h
index 6aa3a807..9572452 100644
--- a/third_party/WebKit/Source/modules/media_controls/elements/MediaControlOverlayPlayButtonElement.h
+++ b/third_party/WebKit/Source/modules/media_controls/elements/MediaControlOverlayPlayButtonElement.h
@@ -6,7 +6,6 @@
 #define MediaControlOverlayPlayButtonElement_h
 
 #include "modules/media_controls/elements/MediaControlInputElement.h"
-#include "platform/Timer.h"
 
 namespace blink {
 
@@ -30,18 +29,9 @@
   const char* GetNameForHistograms() const override;
 
  private:
-  void TapTimerFired(TimerBase*);
-
   void DefaultEventHandler(Event*) override;
   bool KeepEventInNode(Event*) override;
 
-  void MaybePlayPause();
-  void MaybeJump(int);
-
-  void HandlePlayPauseEvent(Event*, WTF::TimeDelta);
-
-  TaskRunnerTimer<MediaControlOverlayPlayButtonElement> tap_timer_;
-
   Member<HTMLDivElement> internal_button_;
 };
 
diff --git a/third_party/WebKit/Source/modules/payments/OWNERS b/third_party/WebKit/Source/modules/payments/OWNERS
index 2fe45e1..7444621 100644
--- a/third_party/WebKit/Source/modules/payments/OWNERS
+++ b/third_party/WebKit/Source/modules/payments/OWNERS
@@ -1,6 +1,7 @@
 # TEAM: paymentrequest@chromium.org
 # COMPONENT: Blink>Payments
 
+jinho.bang@samsung.com
 mathp@chromium.org
 mek@chromium.org
 rouslan@chromium.org
diff --git a/third_party/WebKit/Source/modules/quota/DeprecatedStorageQuota.cpp b/third_party/WebKit/Source/modules/quota/DeprecatedStorageQuota.cpp
index 15882667..3685910d 100644
--- a/third_party/WebKit/Source/modules/quota/DeprecatedStorageQuota.cpp
+++ b/third_party/WebKit/Source/modules/quota/DeprecatedStorageQuota.cpp
@@ -79,12 +79,11 @@
     return;
   }
 
-  KURL storage_partition = KURL(NullURL(), security_origin->ToString());
   StorageQuotaCallbacks* callbacks =
       DeprecatedStorageQuotaCallbacksImpl::Create(success_callback,
                                                   error_callback);
-  Platform::Current()->QueryStorageUsageAndQuota(storage_partition,
-                                                 storage_type, callbacks);
+  Platform::Current()->QueryStorageUsageAndQuota(
+      WrapRefCounted(security_origin), storage_type, callbacks);
 }
 
 void DeprecatedStorageQuota::requestQuota(
diff --git a/third_party/WebKit/Source/modules/quota/StorageManager.cpp b/third_party/WebKit/Source/modules/quota/StorageManager.cpp
index 01e2315..b247a21 100644
--- a/third_party/WebKit/Source/modules/quota/StorageManager.cpp
+++ b/third_party/WebKit/Source/modules/quota/StorageManager.cpp
@@ -127,9 +127,8 @@
     return promise;
   }
 
-  KURL storage_partition = KURL(NullURL(), security_origin->ToString());
   Platform::Current()->QueryStorageUsageAndQuota(
-      storage_partition, kWebStorageQuotaTypeTemporary,
+      WrapRefCounted(security_origin), kWebStorageQuotaTypeTemporary,
       new EstimateCallbacks(resolver));
   return promise;
 }
diff --git a/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.cpp b/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.cpp
index e246cc8..d5915d7 100644
--- a/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.cpp
+++ b/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.cpp
@@ -824,34 +824,6 @@
       surface->makeImageSnapshot(), std::move(shared_context_wrapper));
 }
 
-ImageData* WebGLRenderingContextBase::ToImageData(SnapshotReason reason) {
-  ImageData* image_data = nullptr;
-  // TODO(ccameron): WebGL should produce sRGB images.
-  // https://crbug.com/672299
-  if (GetDrawingBuffer()) {
-    // For un-premultiplied data
-    image_data = PaintRenderingResultsToImageData(kBackBuffer);
-    if (image_data) {
-      return image_data;
-    }
-
-    int width = GetDrawingBuffer()->Size().Width();
-    int height = GetDrawingBuffer()->Size().Height();
-    SkImageInfo image_info =
-        SkImageInfo::Make(width, height, kRGBA_8888_SkColorType,
-                          CreationAttributes().alpha() ? kPremul_SkAlphaType
-                                                       : kOpaque_SkAlphaType);
-    scoped_refptr<StaticBitmapImage> snapshot = MakeImageSnapshot(image_info);
-    if (snapshot) {
-      image_data = ImageData::Create(GetDrawingBuffer()->Size());
-      snapshot->PaintImageForCurrentFrame().GetSkImage()->readPixels(
-          image_info, image_data->data()->Data(), image_info.minRowBytes(), 0,
-          0);
-    }
-  }
-  return image_data;
-}
-
 namespace {
 
 // Exposed by GL_ANGLE_depth_texture
@@ -1513,27 +1485,15 @@
   return true;
 }
 
-ImageData* WebGLRenderingContextBase::PaintRenderingResultsToImageData(
+scoped_refptr<Uint8Array>
+WebGLRenderingContextBase::PaintRenderingResultsToDataArray(
     SourceDrawingBuffer source_buffer) {
   if (isContextLost())
     return nullptr;
-  if (CreationAttributes().premultipliedAlpha())
-    return nullptr;
-
   ClearIfComposited();
   GetDrawingBuffer()->ResolveAndBindForReadAndDraw();
   ScopedFramebufferRestorer restorer(this);
-  int width, height;
-  WTF::ArrayBufferContents contents;
-  if (!GetDrawingBuffer()->PaintRenderingResultsToImageData(
-          width, height, source_buffer, contents))
-    return nullptr;
-  DOMArrayBuffer* image_data_pixels = DOMArrayBuffer::Create(contents);
-
-  return ImageData::Create(
-      IntSize(width, height),
-      NotShared<DOMUint8ClampedArray>(DOMUint8ClampedArray::Create(
-          image_data_pixels, 0, image_data_pixels->ByteLength())));
+  return GetDrawingBuffer()->PaintRenderingResultsToDataArray(source_buffer);
 }
 
 void WebGLRenderingContextBase::Reshape(int width, int height) {
@@ -4427,7 +4387,7 @@
   Vector<uint8_t> data;
 
   IntRect sub_rect = source_image_rect;
-  if (sub_rect == SentinelEmptyRect()) {
+  if (sub_rect.IsValid() && sub_rect == SentinelEmptyRect()) {
     // Recalculate based on the size of the Image.
     sub_rect = SafeGetImageSize(image);
   }
@@ -5282,6 +5242,12 @@
     frame_metadata_ptr = &frame_metadata;
   }
 
+  if (!source_image_rect.IsValid()) {
+    SynthesizeGLError(GL_INVALID_OPERATION, func_name,
+                      "source sub-rectangle specified via pixel unpack "
+                      "parameters is invalid");
+    return;
+  }
   bool source_image_rect_is_default =
       source_image_rect == SentinelEmptyRect() ||
       source_image_rect ==
diff --git a/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.h b/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.h
index e07f94e..7af6289 100644
--- a/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.h
+++ b/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.h
@@ -560,7 +560,9 @@
   void Reshape(int width, int height) override;
 
   void MarkLayerComposited() override;
-  ImageData* PaintRenderingResultsToImageData(SourceDrawingBuffer) override;
+
+  scoped_refptr<Uint8Array> PaintRenderingResultsToDataArray(
+      SourceDrawingBuffer) override;
 
   unsigned MaxVertexAttribs() const { return max_vertex_attribs_; }
 
@@ -587,7 +589,6 @@
 
   scoped_refptr<StaticBitmapImage> GetImage(AccelerationHint,
                                             SnapshotReason) const override;
-  ImageData* ToImageData(SnapshotReason) override;
   void SetFilterQuality(SkFilterQuality) override;
   bool IsWebGL2OrHigher() { return Version() >= 2; }
 
@@ -1067,9 +1068,9 @@
         << ") @ (" << sub_rect.X() << ", " << sub_rect.Y() << "), image = ("
         << image_width << " x " << image_height << ")";
 
-    if (sub_rect.X() < 0 || sub_rect.Y() < 0 || sub_rect.MaxX() > image_width ||
-        sub_rect.MaxY() > image_height || sub_rect.Width() < 0 ||
-        sub_rect.Height() < 0) {
+    if (!sub_rect.IsValid() || sub_rect.X() < 0 || sub_rect.Y() < 0 ||
+        sub_rect.MaxX() > image_width || sub_rect.MaxY() > image_height ||
+        sub_rect.Width() < 0 || sub_rect.Height() < 0) {
       SynthesizeGLError(GL_INVALID_OPERATION, function_name,
                         "source sub-rectangle specified via pixel unpack "
                         "parameters is invalid");
diff --git a/third_party/WebKit/Source/platform/DEPS b/third_party/WebKit/Source/platform/DEPS
index 14d5cc6..e98e6245 100644
--- a/third_party/WebKit/Source/platform/DEPS
+++ b/third_party/WebKit/Source/platform/DEPS
@@ -4,8 +4,6 @@
     "+base/allocator/partition_allocator/oom.h",
     "+base/bind.h",
     "+base/bind_helpers.h",
-    "+base/callback.h",
-    "+base/callback_forward.h",
     "+base/feature_list.h",
     "+base/files",
     "+base/guid.h",
diff --git a/third_party/WebKit/Source/platform/WebTaskRunner.cpp b/third_party/WebKit/Source/platform/WebTaskRunner.cpp
index 5e2b383..5f71c87 100644
--- a/third_party/WebKit/Source/platform/WebTaskRunner.cpp
+++ b/third_party/WebKit/Source/platform/WebTaskRunner.cpp
@@ -137,13 +137,6 @@
                   base::TimeDelta());
 }
 
-void WebTaskRunner::PostDelayedTask(const WebTraceLocation& location,
-                                    WTF::Closure task,
-                                    TimeDelta delay) {
-  DCHECK(RunsTasksInCurrentSequence());
-  PostDelayedTask(location, ConvertToBaseCallback(std::move(task)), delay);
-}
-
 TaskHandle WebTaskRunner::PostCancellableTask(const WebTraceLocation& location,
                                               WTF::Closure task) {
   DCHECK(RunsTasksInCurrentSequence());
diff --git a/third_party/WebKit/Source/platform/WebTaskRunner.h b/third_party/WebKit/Source/platform/WebTaskRunner.h
index 08886f88..9883ddf 100644
--- a/third_party/WebKit/Source/platform/WebTaskRunner.h
+++ b/third_party/WebKit/Source/platform/WebTaskRunner.h
@@ -78,7 +78,6 @@
 
   // For same-thread posting. Must be called from the associated WebThread.
   void PostTask(const WebTraceLocation&, WTF::Closure);
-  void PostDelayedTask(const WebTraceLocation&, WTF::Closure, TimeDelta delay);
 
   // For same-thread cancellable task posting. Returns a TaskHandle object for
   // cancellation.
diff --git a/third_party/WebKit/Source/platform/geometry/IntRect.cpp b/third_party/WebKit/Source/platform/geometry/IntRect.cpp
index d253c46..3ae91cf 100644
--- a/third_party/WebKit/Source/platform/geometry/IntRect.cpp
+++ b/third_party/WebKit/Source/platform/geometry/IntRect.cpp
@@ -27,6 +27,7 @@
 
 #include "platform/geometry/FloatRect.h"
 #include "platform/geometry/LayoutRect.h"
+#include "platform/wtf/CheckedNumeric.h"
 #include "platform/wtf/Vector.h"
 #include "platform/wtf/text/WTFString.h"
 #include "third_party/skia/include/core/SkRect.h"
@@ -201,4 +202,14 @@
                         Size().ToString().Ascii().data());
 }
 
+bool IntRect::IsValid() const {
+  CheckedNumeric<int> max = location_.X();
+  max += size_.Width();
+  if (!max.IsValid())
+    return false;
+  max = location_.Y();
+  max += size_.Height();
+  return max.IsValid();
+}
+
 }  // namespace blink
diff --git a/third_party/WebKit/Source/platform/geometry/IntRect.h b/third_party/WebKit/Source/platform/geometry/IntRect.h
index e1d17567..eb6671e 100644
--- a/third_party/WebKit/Source/platform/geometry/IntRect.h
+++ b/third_party/WebKit/Source/platform/geometry/IntRect.h
@@ -185,6 +185,9 @@
 
   String ToString() const;
 
+  // Return false if x + width or y + height overflows.
+  bool IsValid() const;
+
  private:
   IntPoint location_;
   IntSize size_;
diff --git a/third_party/WebKit/Source/platform/graphics/CompositingReasons.cpp b/third_party/WebKit/Source/platform/graphics/CompositingReasons.cpp
index ae0d05c..dd0d919 100644
--- a/third_party/WebKit/Source/platform/graphics/CompositingReasons.cpp
+++ b/third_party/WebKit/Source/platform/graphics/CompositingReasons.cpp
@@ -9,155 +9,192 @@
 
 namespace blink {
 
-const CompositingReasonStringMap kCompositingReasonStringMap[] = {
-    {kCompositingReasonNone, "Unknown", "No reason given"},
-    {kCompositingReason3DTransform, "transform3D", "Has a 3d transform"},
-    {kCompositingReasonVideo, "video", "Is an accelerated video"},
-    {kCompositingReasonCanvas, "canvas",
+namespace {
+
+struct CompositingReasonStringMap {
+  CompositingReasons reason;
+  const char* short_name;
+  const char* description;
+};
+
+constexpr CompositingReasonStringMap kCompositingReasonsStringMap[] = {
+    {CompositingReason::k3DTransform, "transform3D", "Has a 3d transform"},
+    {CompositingReason::kVideo, "video", "Is an accelerated video"},
+    {CompositingReason::kCanvas, "canvas",
      "Is an accelerated canvas, or is a display list backed canvas that was "
      "promoted to a layer based on a performance heuristic."},
-    {kCompositingReasonPlugin, "plugin", "Is an accelerated plugin"},
-    {kCompositingReasonIFrame, "iFrame", "Is an accelerated iFrame"},
-    {kCompositingReasonBackfaceVisibilityHidden, "backfaceVisibilityHidden",
+    {CompositingReason::kPlugin, "plugin", "Is an accelerated plugin"},
+    {CompositingReason::kIFrame, "iFrame", "Is an accelerated iFrame"},
+    {CompositingReason::kBackfaceVisibilityHidden, "backfaceVisibilityHidden",
      "Has backface-visibility: hidden"},
-    {kCompositingReasonRootScroller, "rootScroller",
-     "Is the document.rootScroller"},
-    {kCompositingReasonActiveAnimation, "activeAnimation",
+    {CompositingReason::kActiveAnimation, "activeAnimation",
      "Has an active accelerated animation or transition"},
-    {kCompositingReasonTransitionProperty, "transitionProperty",
+    {CompositingReason::kTransitionProperty, "transitionProperty",
      "Has an acceleratable transition property (active or inactive)"},
-    {kCompositingReasonScrollDependentPosition, "scrollDependentPosition",
+    {CompositingReason::kScrollDependentPosition, "scrollDependentPosition",
      "Is fixed or sticky position"},
-    {kCompositingReasonOverflowScrollingTouch, "overflowScrollingTouch",
+    {CompositingReason::kOverflowScrollingTouch, "overflowScrollingTouch",
      "Is a scrollable overflow element"},
-    {kCompositingReasonOverflowScrollingParent, "overflowScrollingParent",
+    {CompositingReason::kOverflowScrollingParent, "overflowScrollingParent",
      "Scroll parent is not an ancestor"},
-    {kCompositingReasonOutOfFlowClipping, "outOfFlowClipping",
+    {CompositingReason::kOutOfFlowClipping, "outOfFlowClipping",
      "Has clipping ancestor"},
-    {kCompositingReasonVideoOverlay, "videoOverlay",
+    {CompositingReason::kVideoOverlay, "videoOverlay",
      "Is overlay controls for video"},
-    {kCompositingReasonWillChangeCompositingHint, "willChange",
+    {CompositingReason::kWillChangeCompositingHint, "willChange",
      "Has a will-change compositing hint"},
-    {kCompositingReasonBackdropFilter, "backdropFilter",
+    {CompositingReason::kBackdropFilter, "backdropFilter",
      "Has a backdrop filter"},
-    {kCompositingReasonAssumedOverlap, "assumedOverlap",
+    {CompositingReason::kRootScroller, "rootScroller",
+     "Is the document.rootScroller"},
+    {CompositingReason::kAssumedOverlap, "assumedOverlap",
      "Might overlap other composited content"},
-    {kCompositingReasonOverlap, "overlap", "Overlaps other composited content"},
-    {kCompositingReasonNegativeZIndexChildren, "negativeZIndexChildren",
+    {CompositingReason::kOverlap, "overlap",
+     "Overlaps other composited content"},
+    {CompositingReason::kNegativeZIndexChildren, "negativeZIndexChildren",
      "Parent with composited negative z-index content"},
-    {kCompositingReasonSquashingDisallowed, "squashingDisallowed",
+    {CompositingReason::kSquashingDisallowed, "squashingDisallowed",
      "Layer was separately composited because it could not be squashed."},
-    {kCompositingReasonTransformWithCompositedDescendants,
+    {CompositingReason::kTransformWithCompositedDescendants,
      "transformWithCompositedDescendants",
      "Has a transform that needs to be known by compositor because of "
      "composited descendants"},
-    {kCompositingReasonOpacityWithCompositedDescendants,
+    {CompositingReason::kOpacityWithCompositedDescendants,
      "opacityWithCompositedDescendants",
      "Has opacity that needs to be applied by compositor because of composited "
      "descendants"},
-    {kCompositingReasonMaskWithCompositedDescendants,
+    {CompositingReason::kMaskWithCompositedDescendants,
      "maskWithCompositedDescendants",
      "Has a mask that needs to be known by compositor because of composited "
      "descendants"},
-    {kCompositingReasonReflectionWithCompositedDescendants,
+    {CompositingReason::kReflectionWithCompositedDescendants,
      "reflectionWithCompositedDescendants",
      "Has a reflection that needs to be known by compositor because of "
      "composited descendants"},
-    {kCompositingReasonFilterWithCompositedDescendants,
+    {CompositingReason::kFilterWithCompositedDescendants,
      "filterWithCompositedDescendants",
      "Has a filter effect that needs to be known by compositor because of "
      "composited descendants"},
-    {kCompositingReasonBlendingWithCompositedDescendants,
+    {CompositingReason::kBlendingWithCompositedDescendants,
      "blendingWithCompositedDescendants",
      "Has a blending effect that needs to be known by compositor because of "
      "composited descendants"},
-    {kCompositingReasonClipsCompositingDescendants,
+    {CompositingReason::kClipsCompositingDescendants,
      "clipsCompositingDescendants",
      "Has a clip that needs to be known by compositor because of composited "
      "descendants"},
-    {kCompositingReasonPerspectiveWith3DDescendants,
+    {CompositingReason::kPerspectiveWith3DDescendants,
      "perspectiveWith3DDescendants",
      "Has a perspective transform that needs to be known by compositor because "
      "of 3d descendants"},
-    {kCompositingReasonPreserve3DWith3DDescendants,
+    {CompositingReason::kPreserve3DWith3DDescendants,
      "preserve3DWith3DDescendants",
      "Has a preserves-3d property that needs to be known by compositor because "
      "of 3d descendants"},
-    {kCompositingReasonReflectionOfCompositedParent,
+    {CompositingReason::kReflectionOfCompositedParent,
      "reflectionOfCompositedParent", "Is a reflection of a composited layer"},
-    {kCompositingReasonIsolateCompositedDescendants,
+    {CompositingReason::kIsolateCompositedDescendants,
      "isolateCompositedDescendants",
      "Should isolate descendants to apply a blend effect"},
-    {kCompositingReasonPositionFixedOrStickyWithCompositedDescendants,
+    {CompositingReason::kPositionFixedOrStickyWithCompositedDescendants,
      "positionFixedOrStickyWithCompositedDescendants"
      "Is a position:fixed or position:sticky element with composited "
      "descendants"},
-    {kCompositingReasonRoot, "root", "Is the root layer"},
-    {kCompositingReasonLayerForAncestorClip, "layerForAncestorClip",
+    {CompositingReason::kRoot, "root", "Is the root layer"},
+    {CompositingReason::kLayerForAncestorClip, "layerForAncestorClip",
      "Secondary layer, applies a clip due to a sibling in the compositing "
      "tree"},
-    {kCompositingReasonLayerForDescendantClip, "layerForDescendantClip",
+    {CompositingReason::kLayerForDescendantClip, "layerForDescendantClip",
      "Secondary layer, to clip descendants of the owning layer"},
-    {kCompositingReasonLayerForPerspective, "layerForPerspective",
+    {CompositingReason::kLayerForPerspective, "layerForPerspective",
      "Secondary layer, to house the perspective transform for all descendants"},
-    {kCompositingReasonLayerForHorizontalScrollbar,
+    {CompositingReason::kLayerForHorizontalScrollbar,
      "layerForHorizontalScrollbar",
      "Secondary layer, the horizontal scrollbar layer"},
-    {kCompositingReasonLayerForVerticalScrollbar, "layerForVerticalScrollbar",
+    {CompositingReason::kLayerForVerticalScrollbar, "layerForVerticalScrollbar",
      "Secondary layer, the vertical scrollbar layer"},
-    {kCompositingReasonLayerForOverflowControlsHost,
+    {CompositingReason::kLayerForOverflowControlsHost,
      "layerForOverflowControlsHost",
      "Secondary layer, the overflow controls host layer"},
-    {kCompositingReasonLayerForScrollCorner, "layerForScrollCorner",
+    {CompositingReason::kLayerForScrollCorner, "layerForScrollCorner",
      "Secondary layer, the scroll corner layer"},
-    {kCompositingReasonLayerForScrollingContents, "layerForScrollingContents",
+    {CompositingReason::kLayerForScrollingContents, "layerForScrollingContents",
      "Secondary layer, to house contents that can be scrolled"},
-    {kCompositingReasonLayerForScrollingContainer, "layerForScrollingContainer",
+    {CompositingReason::kLayerForScrollingContainer,
+     "layerForScrollingContainer",
      "Secondary layer, used to position the scrolling contents while "
      "scrolling"},
-    {kCompositingReasonLayerForSquashingContents, "layerForSquashingContents",
+    {CompositingReason::kLayerForSquashingContents, "layerForSquashingContents",
      "Secondary layer, home for a group of squashable content"},
-    {kCompositingReasonLayerForSquashingContainer, "layerForSquashingContainer",
+    {CompositingReason::kLayerForSquashingContainer,
+     "layerForSquashingContainer",
      "Secondary layer, no-op layer to place the squashing layer correctly in "
      "the composited layer tree"},
-    {kCompositingReasonLayerForForeground, "layerForForeground",
+    {CompositingReason::kLayerForForeground, "layerForForeground",
      "Secondary layer, to contain any normal flow and positive z-index "
      "contents on top of a negative z-index layer"},
-    {kCompositingReasonLayerForBackground, "layerForBackground",
+    {CompositingReason::kLayerForBackground, "layerForBackground",
      "Secondary layer, to contain acceleratable background content"},
-    {kCompositingReasonLayerForMask, "layerForMask",
+    {CompositingReason::kLayerForMask, "layerForMask",
      "Secondary layer, to contain the mask contents"},
-    {kCompositingReasonLayerForClippingMask, "layerForClippingMask",
+    {CompositingReason::kLayerForClippingMask, "layerForClippingMask",
      "Secondary layer, for clipping mask"},
-    {kCompositingReasonLayerForAncestorClippingMask,
+    {CompositingReason::kLayerForAncestorClippingMask,
      "layerForAncestorClippingMask",
      "Secondary layer, applies a clipping mask due to a sibling in the "
      "composited layer tree"},
-    {kCompositingReasonLayerForScrollingBlockSelection,
+    {CompositingReason::kLayerForScrollingBlockSelection,
      "layerForScrollingBlockSelection",
      "Secondary layer, to house block selection gaps for composited scrolling "
      "with no scrolling contents"},
-    {kCompositingReasonLayerForDecoration, "layerForDecoration",
+    {CompositingReason::kLayerForDecoration, "layerForDecoration",
      "Layer painted on top of other layers as decoration"},
-    {kCompositingReasonInlineTransform, "inlineTransform",
+    {CompositingReason::kInlineTransform, "inlineTransform",
      "Has an inline transform, which causes subsequent layers to assume "
      "overlap"},
+
 };
 
-const size_t kNumberOfCompositingReasons =
-    WTF_ARRAY_LENGTH(kCompositingReasonStringMap);
+}  // anonymous namespace
 
-String CompositingReasonsAsString(CompositingReasons reasons) {
-  if (!reasons)
-    return "none";
+Vector<const char*> CompositingReason::ShortNames(CompositingReasons reasons) {
+#define V(name)                                                             \
+  static_assert(                                                            \
+      CompositingReason::k##name ==                                         \
+          kCompositingReasonsStringMap[CompositingReason::kE##name].reason, \
+      "kCompositingReasonsStringMap needs update for "                      \
+      "CompositingReason::k" #name);                                        \
+  FOR_EACH_COMPOSITING_REASON(V)
+#undef V
 
+  Vector<const char*> result;
+  if (reasons == kNone)
+    return result;
+  for (auto& map : kCompositingReasonsStringMap) {
+    if (reasons & map.reason)
+      result.push_back(map.short_name);
+  }
+  return result;
+}
+
+Vector<const char*> CompositingReason::Descriptions(
+    CompositingReasons reasons) {
+  Vector<const char*> result;
+  if (reasons == kNone)
+    return result;
+  for (auto& map : kCompositingReasonsStringMap) {
+    if (reasons & map.reason)
+      result.push_back(map.description);
+  }
+  return result;
+}
+
+String CompositingReason::ToString(CompositingReasons reasons) {
   StringBuilder builder;
-  for (size_t i = 0; i < kNumberOfCompositingReasons; ++i) {
-    if (reasons & kCompositingReasonStringMap[i].reason) {
-      if (builder.length())
-        builder.Append(',');
-      builder.Append(kCompositingReasonStringMap[i].short_name);
-    }
+  for (const char* name : ShortNames(reasons)) {
+    if (builder.length())
+      builder.Append(',');
+    builder.Append(name);
   }
   return builder.ToString();
 }
diff --git a/third_party/WebKit/Source/platform/graphics/CompositingReasons.h b/third_party/WebKit/Source/platform/graphics/CompositingReasons.h
index 60ed7f48..b3b95155 100644
--- a/third_party/WebKit/Source/platform/graphics/CompositingReasons.h
+++ b/third_party/WebKit/Source/platform/graphics/CompositingReasons.h
@@ -7,168 +7,154 @@
 
 #include <stdint.h>
 #include "platform/PlatformExport.h"
-#include "platform/wtf/Allocator.h"
+#include "platform/wtf/Vector.h"
 #include "platform/wtf/text/WTFString.h"
 
 namespace blink {
 
-const uint64_t kCompositingReasonNone = 0;
-const uint64_t kCompositingReasonAll = ~static_cast<uint64_t>(0);
+using CompositingReasons = uint64_t;
 
-// Intrinsic reasons that can be known right away by the layer
-const uint64_t kCompositingReason3DTransform = UINT64_C(1) << 0;
-const uint64_t kCompositingReasonVideo = UINT64_C(1) << 1;
-const uint64_t kCompositingReasonCanvas = UINT64_C(1) << 2;
-const uint64_t kCompositingReasonPlugin = UINT64_C(1) << 3;
-const uint64_t kCompositingReasonIFrame = UINT64_C(1) << 4;
-const uint64_t kCompositingReasonBackfaceVisibilityHidden = UINT64_C(1) << 5;
-const uint64_t kCompositingReasonActiveAnimation = UINT64_C(1) << 6;
-const uint64_t kCompositingReasonTransitionProperty = UINT64_C(1) << 7;
-const uint64_t kCompositingReasonScrollDependentPosition = UINT64_C(1) << 8;
-const uint64_t kCompositingReasonOverflowScrollingTouch = UINT64_C(1) << 9;
-const uint64_t kCompositingReasonOverflowScrollingParent = UINT64_C(1) << 10;
-const uint64_t kCompositingReasonOutOfFlowClipping = UINT64_C(1) << 11;
-const uint64_t kCompositingReasonVideoOverlay = UINT64_C(1) << 12;
-const uint64_t kCompositingReasonWillChangeCompositingHint = UINT64_C(1) << 13;
-const uint64_t kCompositingReasonBackdropFilter = UINT64_C(1) << 14;
-const uint64_t kCompositingReasonRootScroller = UINT64_C(1) << 15;
+#define FOR_EACH_COMPOSITING_REASON(V)                                        \
+  /* Intrinsic reasons that can be known right away by the layer. */          \
+  V(3DTransform)                                                              \
+  V(Video)                                                                    \
+  V(Canvas)                                                                   \
+  V(Plugin)                                                                   \
+  V(IFrame)                                                                   \
+  V(BackfaceVisibilityHidden)                                                 \
+  V(ActiveAnimation)                                                          \
+  V(TransitionProperty)                                                       \
+  V(ScrollDependentPosition)                                                  \
+  V(OverflowScrollingTouch)                                                   \
+  V(OverflowScrollingParent)                                                  \
+  V(OutOfFlowClipping)                                                        \
+  V(VideoOverlay)                                                             \
+  V(WillChangeCompositingHint)                                                \
+  V(BackdropFilter)                                                           \
+  V(RootScroller)                                                             \
+                                                                              \
+  /* Overlap reasons that require knowing what's behind you in paint-order    \
+     before knowing the answer. */                                            \
+  V(AssumedOverlap)                                                           \
+  V(Overlap)                                                                  \
+  V(NegativeZIndexChildren)                                                   \
+  V(SquashingDisallowed)                                                      \
+                                                                              \
+  /* Subtree reasons that require knowing what the status of your subtree is  \
+     before knowing the answer. */                                            \
+  V(TransformWithCompositedDescendants)                                       \
+  V(OpacityWithCompositedDescendants)                                         \
+  V(MaskWithCompositedDescendants)                                            \
+  V(ReflectionWithCompositedDescendants)                                      \
+  V(FilterWithCompositedDescendants)                                          \
+  V(BlendingWithCompositedDescendants)                                        \
+  V(ClipsCompositingDescendants)                                              \
+  V(PerspectiveWith3DDescendants)                                             \
+  V(Preserve3DWith3DDescendants)                                              \
+  V(ReflectionOfCompositedParent)                                             \
+  V(IsolateCompositedDescendants)                                             \
+  V(PositionFixedOrStickyWithCompositedDescendants)                           \
+                                                                              \
+  /* The root layer is a special case. It may be forced to be a layer, but it \
+  also needs to be a layer if anything else in the subtree is composited. */  \
+  V(Root)                                                                     \
+                                                                              \
+  /* CompositedLayerMapping internal hierarchy reasons. */                    \
+  V(LayerForAncestorClip)                                                     \
+  V(LayerForDescendantClip)                                                   \
+  V(LayerForPerspective)                                                      \
+  V(LayerForHorizontalScrollbar)                                              \
+  V(LayerForVerticalScrollbar)                                                \
+  V(LayerForOverflowControlsHost)                                             \
+  V(LayerForScrollCorner)                                                     \
+  V(LayerForScrollingContents)                                                \
+  V(LayerForScrollingContainer)                                               \
+  V(LayerForSquashingContents)                                                \
+  V(LayerForSquashingContainer)                                               \
+  V(LayerForForeground)                                                       \
+  V(LayerForBackground)                                                       \
+  V(LayerForMask)                                                             \
+  V(LayerForClippingMask)                                                     \
+  V(LayerForAncestorClippingMask)                                             \
+  V(LayerForScrollingBlockSelection)                                          \
+  /* Composited layer painted on top of all other layers as decoration. */    \
+  V(LayerForDecoration)                                                       \
+                                                                              \
+  /* Composited elements with inline transforms trigger assumed overlap so    \
+  that we can update their transforms quickly. */                             \
+  V(InlineTransform)
 
-// Overlap reasons that require knowing what's behind you in paint-order before
-// knowing the answer.
-const uint64_t kCompositingReasonAssumedOverlap = UINT64_C(1) << 16;
-const uint64_t kCompositingReasonOverlap = UINT64_C(1) << 17;
-const uint64_t kCompositingReasonNegativeZIndexChildren = UINT64_C(1) << 18;
-const uint64_t kCompositingReasonSquashingDisallowed = UINT64_C(1) << 19;
+class PLATFORM_EXPORT CompositingReason {
+ private:
+  // This contains ordinal values for compositing reasons and will be used to
+  // generate the compositing reason bits.
+  enum {
+#define V(name) kE##name,
+    FOR_EACH_COMPOSITING_REASON(V)
+#undef V
+  };
 
-// Subtree reasons that require knowing what the status of your subtree is
-// before knowing the answer.
-const uint64_t kCompositingReasonTransformWithCompositedDescendants =
-    UINT64_C(1) << 20;
-const uint64_t kCompositingReasonOpacityWithCompositedDescendants = UINT64_C(1)
-                                                                    << 21;
-const uint64_t kCompositingReasonMaskWithCompositedDescendants = UINT64_C(1)
-                                                                 << 22;
-const uint64_t kCompositingReasonReflectionWithCompositedDescendants =
-    UINT64_C(1) << 23;
-const uint64_t kCompositingReasonFilterWithCompositedDescendants = UINT64_C(1)
-                                                                   << 24;
-const uint64_t kCompositingReasonBlendingWithCompositedDescendants = UINT64_C(1)
-                                                                     << 25;
-const uint64_t kCompositingReasonClipsCompositingDescendants = UINT64_C(1)
-                                                               << 26;
-const uint64_t kCompositingReasonPerspectiveWith3DDescendants = UINT64_C(1)
-                                                                << 27;
-const uint64_t kCompositingReasonPreserve3DWith3DDescendants = UINT64_C(1)
-                                                               << 28;
-const uint64_t kCompositingReasonReflectionOfCompositedParent = UINT64_C(1)
-                                                                << 29;
-const uint64_t kCompositingReasonIsolateCompositedDescendants = UINT64_C(1)
-                                                                << 30;
-const uint64_t
-    kCompositingReasonPositionFixedOrStickyWithCompositedDescendants =
-        UINT64_C(1) << 31;
+#define V(name) static_assert(kE##name < 64, "Should fit in 64 bits");
+  FOR_EACH_COMPOSITING_REASON(V)
+#undef V
 
-// The root layer is a special case. It may be forced to be a layer, but it also
-// needs to be a layer if anything else in the subtree is composited.
-const uint64_t kCompositingReasonRoot = UINT64_C(1) << 32;
+ public:
+  static Vector<const char*> ShortNames(CompositingReasons);
+  static Vector<const char*> Descriptions(CompositingReasons);
+  static String ToString(CompositingReasons);
 
-// CompositedLayerMapping internal hierarchy reasons
-const uint64_t kCompositingReasonLayerForAncestorClip = UINT64_C(1) << 33;
-const uint64_t kCompositingReasonLayerForDescendantClip = UINT64_C(1) << 34;
-const uint64_t kCompositingReasonLayerForPerspective = UINT64_C(1) << 35;
-const uint64_t kCompositingReasonLayerForHorizontalScrollbar = UINT64_C(1)
-                                                               << 36;
-const uint64_t kCompositingReasonLayerForVerticalScrollbar = UINT64_C(1) << 37;
-const uint64_t kCompositingReasonLayerForOverflowControlsHost = UINT64_C(1)
-                                                                << 38;
-const uint64_t kCompositingReasonLayerForScrollCorner = UINT64_C(1) << 39;
-const uint64_t kCompositingReasonLayerForScrollingContents = UINT64_C(1) << 40;
-const uint64_t kCompositingReasonLayerForScrollingContainer = UINT64_C(1) << 41;
-const uint64_t kCompositingReasonLayerForSquashingContents = UINT64_C(1) << 42;
-const uint64_t kCompositingReasonLayerForSquashingContainer = UINT64_C(1) << 43;
-const uint64_t kCompositingReasonLayerForForeground = UINT64_C(1) << 44;
-const uint64_t kCompositingReasonLayerForBackground = UINT64_C(1) << 45;
-const uint64_t kCompositingReasonLayerForMask = UINT64_C(1) << 46;
-const uint64_t kCompositingReasonLayerForClippingMask = UINT64_C(1) << 47;
-const uint64_t kCompositingReasonLayerForAncestorClippingMask = UINT64_C(1)
-                                                                << 48;
-const uint64_t kCompositingReasonLayerForScrollingBlockSelection = UINT64_C(1)
-                                                                   << 49;
-// Composited layer painted on top of all other layers as decoration
-const uint64_t kCompositingReasonLayerForDecoration = UINT64_C(1) << 50;
+  enum : CompositingReasons {
+    kNone = 0,
+    kAll = ~static_cast<CompositingReasons>(0),
+#define V(name) k##name = UINT64_C(1) << kE##name,
+    FOR_EACH_COMPOSITING_REASON(V)
+#undef V
 
-// Composited elements with inline transforms trigger assumed overlap so that
-// we can update their transforms quickly.
-const uint64_t kCompositingReasonInlineTransform = UINT64_C(1) << 51;
+    // Various combinations of compositing reasons are defined here also, for
+    // more intuitive and faster bitwise logic.
+    kComboAllDirectReasons =
+        k3DTransform | kVideo | kCanvas | kPlugin | kIFrame |
+        kBackfaceVisibilityHidden | kActiveAnimation | kTransitionProperty |
+        kScrollDependentPosition | kOverflowScrollingTouch |
+        kOverflowScrollingParent | kOutOfFlowClipping | kVideoOverlay |
+        kWillChangeCompositingHint | kBackdropFilter | kRootScroller,
 
-// Various combinations of compositing reasons are defined here also, for more
-// intutive and faster bitwise logic.
-const uint64_t kCompositingReasonComboAllDirectReasons =
-    kCompositingReason3DTransform | kCompositingReasonVideo |
-    kCompositingReasonCanvas | kCompositingReasonPlugin |
-    kCompositingReasonIFrame | kCompositingReasonBackfaceVisibilityHidden |
-    kCompositingReasonActiveAnimation | kCompositingReasonTransitionProperty |
-    kCompositingReasonScrollDependentPosition |
-    kCompositingReasonOverflowScrollingTouch |
-    kCompositingReasonOverflowScrollingParent |
-    kCompositingReasonOutOfFlowClipping | kCompositingReasonVideoOverlay |
-    kCompositingReasonWillChangeCompositingHint |
-    kCompositingReasonBackdropFilter | kCompositingReasonRootScroller;
+    kComboAllDirectStyleDeterminedReasons =
+        k3DTransform | kBackfaceVisibilityHidden | kActiveAnimation |
+        kTransitionProperty | kWillChangeCompositingHint | kBackdropFilter,
 
-const uint64_t kCompositingReasonComboAllDirectStyleDeterminedReasons =
-    kCompositingReason3DTransform | kCompositingReasonBackfaceVisibilityHidden |
-    kCompositingReasonActiveAnimation | kCompositingReasonTransitionProperty |
-    kCompositingReasonWillChangeCompositingHint |
-    kCompositingReasonBackdropFilter;
+    kComboCompositedDescendants =
+        kTransformWithCompositedDescendants | kIsolateCompositedDescendants |
+        kOpacityWithCompositedDescendants | kMaskWithCompositedDescendants |
+        kFilterWithCompositedDescendants | kBlendingWithCompositedDescendants |
+        kReflectionWithCompositedDescendants | kClipsCompositingDescendants |
+        kPositionFixedOrStickyWithCompositedDescendants,
 
-const uint64_t kCompositingReasonComboCompositedDescendants =
-    kCompositingReasonTransformWithCompositedDescendants |
-    kCompositingReasonIsolateCompositedDescendants |
-    kCompositingReasonOpacityWithCompositedDescendants |
-    kCompositingReasonMaskWithCompositedDescendants |
-    kCompositingReasonFilterWithCompositedDescendants |
-    kCompositingReasonBlendingWithCompositedDescendants |
-    kCompositingReasonReflectionWithCompositedDescendants |
-    kCompositingReasonClipsCompositingDescendants |
-    kCompositingReasonPositionFixedOrStickyWithCompositedDescendants;
+    kCombo3DDescendants =
+        kPreserve3DWith3DDescendants | kPerspectiveWith3DDescendants,
 
-const uint64_t kCompositingReasonCombo3DDescendants =
-    kCompositingReasonPreserve3DWith3DDescendants |
-    kCompositingReasonPerspectiveWith3DDescendants;
+    kComboAllStyleDeterminedReasons = kComboAllDirectStyleDeterminedReasons |
+                                      kComboCompositedDescendants |
+                                      kCombo3DDescendants | kInlineTransform,
 
-const uint64_t kCompositingReasonComboAllStyleDeterminedReasons =
-    kCompositingReasonComboAllDirectStyleDeterminedReasons |
-    kCompositingReasonComboCompositedDescendants |
-    kCompositingReasonCombo3DDescendants | kCompositingReasonInlineTransform;
-
-const uint64_t kCompositingReasonComboSquashableReasons =
-    kCompositingReasonOverlap | kCompositingReasonAssumedOverlap |
-    kCompositingReasonOverflowScrollingParent;
-
-typedef uint64_t CompositingReasons;
+    kComboSquashableReasons =
+        kOverlap | kAssumedOverlap | kOverflowScrollingParent,
+  };
+};
 
 // Any reasons other than overlap or assumed overlap will require the layer to
 // be separately compositing.
 inline bool RequiresCompositing(CompositingReasons reasons) {
-  return reasons & ~kCompositingReasonComboSquashableReasons;
+  return reasons & ~CompositingReason::kComboSquashableReasons;
 }
 
 // If the layer has overlap or assumed overlap, but no other reasons, then it
 // should be squashed.
 inline bool RequiresSquashing(CompositingReasons reasons) {
   return !RequiresCompositing(reasons) &&
-         (reasons & kCompositingReasonComboSquashableReasons);
+         (reasons & CompositingReason::kComboSquashableReasons);
 }
 
-struct CompositingReasonStringMap {
-  STACK_ALLOCATED();
-  CompositingReasons reason;
-  const char* short_name;
-  const char* description;
-};
-
-// crbug.com/754786: Track number of layer promotions due to various reasons.
-// Aggregate the reasons over all frames.
 struct CompositingReasonsStats {
   size_t overlap_layers = 0;
   size_t active_animation_layers = 0;
@@ -177,11 +163,6 @@
   size_t total_composited_layers = 0;
 };
 
-PLATFORM_EXPORT extern const CompositingReasonStringMap
-    kCompositingReasonStringMap[];
-PLATFORM_EXPORT extern const size_t kNumberOfCompositingReasons;
-PLATFORM_EXPORT String CompositingReasonsAsString(CompositingReasons);
-
 }  // namespace blink
 
 #endif  // CompositingReasons_h
diff --git a/third_party/WebKit/Source/platform/graphics/GraphicsLayer.cpp b/third_party/WebKit/Source/platform/graphics/GraphicsLayer.cpp
index 20fdd6d6..fa5796f 100644
--- a/third_party/WebKit/Source/platform/graphics/GraphicsLayer.cpp
+++ b/third_party/WebKit/Source/platform/graphics/GraphicsLayer.cpp
@@ -637,7 +637,7 @@
     }
 
     if (!layer.transform_.IsIdentity() || layer.rendering_context3d_ ||
-        layer.GetCompositingReasons() & kCompositingReason3DTransform) {
+        layer.GetCompositingReasons() & CompositingReason::k3DTransform) {
       if (position != FloatPoint()) {
         // Output position offset as a transform.
         auto* position_translate_json = AddTransformJSON(transform_id);
@@ -797,29 +797,26 @@
   if (flags &
       (kLayerTreeIncludesDebugInfo | kLayerTreeIncludesCompositingReasons)) {
     bool debug = flags & kLayerTreeIncludesDebugInfo;
-    std::unique_ptr<JSONArray> compositing_reasons_json = JSONArray::Create();
-    for (size_t i = 0; i < kNumberOfCompositingReasons; ++i) {
-      if (debug_info_.GetCompositingReasons() &
-          kCompositingReasonStringMap[i].reason) {
-        compositing_reasons_json->PushString(
-            debug ? kCompositingReasonStringMap[i].description
-                  : kCompositingReasonStringMap[i].short_name);
-      }
+    {
+      std::unique_ptr<JSONArray> compositing_reasons_json = JSONArray::Create();
+      auto reasons = debug_info_.GetCompositingReasons();
+      auto names = debug ? CompositingReason::Descriptions(reasons)
+                         : CompositingReason::ShortNames(reasons);
+      for (const char* name : names)
+        compositing_reasons_json->PushString(name);
+      json->SetArray("compositingReasons", std::move(compositing_reasons_json));
     }
-    json->SetArray("compositingReasons", std::move(compositing_reasons_json));
-
-    std::unique_ptr<JSONArray> squashing_disallowed_reasons_json =
-        JSONArray::Create();
-    for (size_t i = 0; i < kNumberOfSquashingDisallowedReasons; ++i) {
-      if (debug_info_.GetSquashingDisallowedReasons() &
-          kSquashingDisallowedReasonStringMap[i].reason) {
-        squashing_disallowed_reasons_json->PushString(
-            debug ? kSquashingDisallowedReasonStringMap[i].description
-                  : kSquashingDisallowedReasonStringMap[i].short_name);
-      }
+    {
+      std::unique_ptr<JSONArray> squashing_disallowed_reasons_json =
+          JSONArray::Create();
+      auto reasons = debug_info_.GetSquashingDisallowedReasons();
+      auto names = debug ? SquashingDisallowedReason::Descriptions(reasons)
+                         : SquashingDisallowedReason::ShortNames(reasons);
+      for (const char* name : names)
+        squashing_disallowed_reasons_json->PushString(name);
+      json->SetArray("squashingDisallowedReasons",
+                     std::move(squashing_disallowed_reasons_json));
     }
-    json->SetArray("squashingDisallowedReasons",
-                   std::move(squashing_disallowed_reasons_json));
   }
 
   if (mask_layer_) {
diff --git a/third_party/WebKit/Source/platform/graphics/GraphicsLayerDebugInfo.cpp b/third_party/WebKit/Source/platform/graphics/GraphicsLayerDebugInfo.cpp
index 4b3ef59..be55c45 100644
--- a/third_party/WebKit/Source/platform/graphics/GraphicsLayerDebugInfo.cpp
+++ b/third_party/WebKit/Source/platform/graphics/GraphicsLayerDebugInfo.cpp
@@ -25,8 +25,8 @@
 namespace blink {
 
 GraphicsLayerDebugInfo::GraphicsLayerDebugInfo()
-    : compositing_reasons_(kCompositingReasonNone),
-      squashing_disallowed_reasons_(kSquashingDisallowedReasonsNone),
+    : compositing_reasons_(CompositingReason::kNone),
+      squashing_disallowed_reasons_(SquashingDisallowedReason::kNone),
       owner_node_id_(0),
       main_thread_scrolling_reasons_(0) {}
 
@@ -66,24 +66,18 @@
 void GraphicsLayerDebugInfo::AppendCompositingReasons(
     base::trace_event::TracedValue* traced_value) const {
   traced_value->BeginArray("compositing_reasons");
-  for (size_t i = 0; i < kNumberOfCompositingReasons; ++i) {
-    if (!(compositing_reasons_ & kCompositingReasonStringMap[i].reason))
-      continue;
-    traced_value->AppendString(kCompositingReasonStringMap[i].description);
-  }
+  for (const char* description :
+       CompositingReason::Descriptions(compositing_reasons_))
+    traced_value->AppendString(description);
   traced_value->EndArray();
 }
 
 void GraphicsLayerDebugInfo::AppendSquashingDisallowedReasons(
     base::trace_event::TracedValue* traced_value) const {
   traced_value->BeginArray("squashing_disallowed_reasons");
-  for (size_t i = 0; i < kNumberOfSquashingDisallowedReasons; ++i) {
-    if (!(squashing_disallowed_reasons_ &
-          kSquashingDisallowedReasonStringMap[i].reason))
-      continue;
-    traced_value->AppendString(
-        kSquashingDisallowedReasonStringMap[i].description);
-  }
+  for (const char* description :
+       SquashingDisallowedReason::Descriptions(squashing_disallowed_reasons_))
+    traced_value->AppendString(description);
   traced_value->EndArray();
 }
 
diff --git a/third_party/WebKit/Source/platform/graphics/SquashingDisallowedReasons.cpp b/third_party/WebKit/Source/platform/graphics/SquashingDisallowedReasons.cpp
index 7f25de0..bb51a45 100644
--- a/third_party/WebKit/Source/platform/graphics/SquashingDisallowedReasons.cpp
+++ b/third_party/WebKit/Source/platform/graphics/SquashingDisallowedReasons.cpp
@@ -8,66 +8,107 @@
 
 namespace blink {
 
-const SquashingDisallowedReasonStringMap kSquashingDisallowedReasonStringMap[] =
-    {
-        {kSquashingDisallowedReasonScrollsWithRespectToSquashingLayer,
+namespace {
+
+struct SquashingDisallowedReasonStringMap {
+  SquashingDisallowedReasons reason;
+  const char* short_name;
+  const char* description;
+};
+
+constexpr SquashingDisallowedReasonStringMap
+    kSquashingDisallowedReasonsStringMap[] = {
+        {SquashingDisallowedReason::kScrollsWithRespectToSquashingLayer,
          "scrollsWithRespectToSquashingLayer",
          "Cannot be squashed since this layer scrolls with respect to the "
          "squashing layer"},
-        {kSquashingDisallowedReasonSquashingSparsityExceeded,
+        {SquashingDisallowedReason::kSquashingSparsityExceeded,
          "squashingSparsityExceeded",
          "Cannot be squashed as the squashing layer would become too sparse"},
-        {kSquashingDisallowedReasonClippingContainerMismatch,
+        {SquashingDisallowedReason::kClippingContainerMismatch,
          "squashingClippingContainerMismatch",
          "Cannot be squashed because this layer has a different clipping "
          "container than the squashing layer"},
-        {kSquashingDisallowedReasonOpacityAncestorMismatch,
+        {SquashingDisallowedReason::kOpacityAncestorMismatch,
          "squashingOpacityAncestorMismatch",
          "Cannot be squashed because this layer has a different opacity "
          "ancestor than the squashing layer"},
-        {kSquashingDisallowedReasonTransformAncestorMismatch,
+        {SquashingDisallowedReason::kTransformAncestorMismatch,
          "squashingTransformAncestorMismatch",
          "Cannot be squashed because this layer has a different transform "
          "ancestor than the squashing layer"},
-        {kSquashingDisallowedReasonFilterMismatch,
+        {SquashingDisallowedReason::kFilterMismatch,
          "squashingFilterAncestorMismatch",
          "Cannot be squashed because this layer has a different filter "
          "ancestor than the squashing layer, or this layer has a filter"},
-        {kSquashingDisallowedReasonWouldBreakPaintOrder,
+        {SquashingDisallowedReason::kWouldBreakPaintOrder,
          "squashingWouldBreakPaintOrder",
          "Cannot be squashed without breaking paint order"},
-        {kSquashingDisallowedReasonSquashingVideoIsDisallowed,
+        {SquashingDisallowedReason::kSquashingVideoIsDisallowed,
          "squashingVideoIsDisallowed", "Squashing video is not supported"},
-        {kSquashingDisallowedReasonSquashedLayerClipsCompositingDescendants,
-         "squashedLayerClipsCompositingDescendants",
+        {SquashingDisallowedReason::kSquashedLayerClipsCompositingDescendants,
+         "squashedLayerClipsSquashingDisallowedDescendants",
          "Squashing a layer that clips composited descendants is not "
          "supported."},
-        {kSquashingDisallowedReasonSquashingLayoutEmbeddedContentIsDisallowed,
+        {SquashingDisallowedReason::kSquashingLayoutEmbeddedContentIsDisallowed,
          "squashingLayoutEmbeddedContentIsDisallowed",
          "Squashing a frame, iframe or plugin is not supported."},
-        {kSquashingDisallowedReasonSquashingBlendingIsDisallowed,
+        {SquashingDisallowedReason::kSquashingBlendingIsDisallowed,
          "squashingBlendingDisallowed",
          "Squashing a layer with blending is not supported."},
-        {kSquashingDisallowedReasonNearestFixedPositionMismatch,
+        {SquashingDisallowedReason::kNearestFixedPositionMismatch,
          "squashingNearestFixedPositionMismatch",
          "Cannot be squashed because this layer has a different nearest fixed "
          "position layer than the squashing layer"},
-        {kSquashingDisallowedReasonScrollChildWithCompositedDescendants,
+        {SquashingDisallowedReason::kScrollChildWithCompositedDescendants,
          "scrollChildWithCompositedDescendants",
          "Squashing a scroll child with composited descendants is not "
          "supported."},
-        {kSquashingDisallowedReasonSquashingLayerIsAnimating,
+        {SquashingDisallowedReason::kSquashingLayerIsAnimating,
          "squashingLayerIsAnimating",
          "Cannot squash into a layer that is animating."},
-        {kSquashingDisallowedReasonRenderingContextMismatch,
+        {SquashingDisallowedReason::kRenderingContextMismatch,
          "squashingLayerRenderingContextMismatch",
          "Cannot squash layers with different 3D contexts."},
-        {kSquashingDisallowedReasonFragmentedContent,
+        {SquashingDisallowedReason::kFragmentedContent,
          "SquashingDisallowedReasonFragmentedContent",
          "Cannot squash layers that are inside fragmentation contexts."},
 };
 
-const size_t kNumberOfSquashingDisallowedReasons =
-    WTF_ARRAY_LENGTH(kSquashingDisallowedReasonStringMap);
+}  // anonymous namespace
+
+Vector<const char*> SquashingDisallowedReason::ShortNames(
+    SquashingDisallowedReasons reasons) {
+#define V(name)                                                          \
+  static_assert(SquashingDisallowedReason::k##name ==                    \
+                    kSquashingDisallowedReasonsStringMap                 \
+                        [SquashingDisallowedReason::kE##name]            \
+                            .reason,                                     \
+                "kSquashingDisallowedReasonsStringMap needs update for " \
+                "SquashingDisallowedReason::k" #name);                   \
+  FOR_EACH_COMPOSITING_REASON(V)
+#undef V
+
+  Vector<const char*> result;
+  if (reasons == kNone)
+    return result;
+  for (auto& map : kSquashingDisallowedReasonsStringMap) {
+    if (reasons & map.reason)
+      result.push_back(map.short_name);
+  }
+  return result;
+}
+
+Vector<const char*> SquashingDisallowedReason::Descriptions(
+    SquashingDisallowedReasons reasons) {
+  Vector<const char*> result;
+  if (reasons == kNone)
+    return result;
+  for (auto& map : kSquashingDisallowedReasonsStringMap) {
+    if (reasons & map.reason)
+      result.push_back(map.description);
+  }
+  return result;
+}
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/platform/graphics/SquashingDisallowedReasons.h b/third_party/WebKit/Source/platform/graphics/SquashingDisallowedReasons.h
index 70b346c..735d67e7 100644
--- a/third_party/WebKit/Source/platform/graphics/SquashingDisallowedReasons.h
+++ b/third_party/WebKit/Source/platform/graphics/SquashingDisallowedReasons.h
@@ -5,45 +5,57 @@
 #ifndef SquashingDisallowedReasons_h
 #define SquashingDisallowedReasons_h
 
-#include <stdint.h>
 #include "platform/PlatformExport.h"
-#include "platform/wtf/Allocator.h"
+#include "platform/wtf/Vector.h"
 
 namespace blink {
 
-enum SquashingDisallowedReason {
-  kSquashingDisallowedReasonsNone = 0,
-  kSquashingDisallowedReasonScrollsWithRespectToSquashingLayer = 1 << 0,
-  kSquashingDisallowedReasonSquashingSparsityExceeded = 1 << 1,
-  kSquashingDisallowedReasonClippingContainerMismatch = 1 << 2,
-  kSquashingDisallowedReasonOpacityAncestorMismatch = 1 << 3,
-  kSquashingDisallowedReasonTransformAncestorMismatch = 1 << 4,
-  kSquashingDisallowedReasonFilterMismatch = 1 << 5,
-  kSquashingDisallowedReasonWouldBreakPaintOrder = 1 << 6,
-  kSquashingDisallowedReasonSquashingVideoIsDisallowed = 1 << 7,
-  kSquashingDisallowedReasonSquashedLayerClipsCompositingDescendants = 1 << 8,
-  kSquashingDisallowedReasonSquashingLayoutEmbeddedContentIsDisallowed = 1 << 9,
-  kSquashingDisallowedReasonSquashingBlendingIsDisallowed = 1 << 10,
-  kSquashingDisallowedReasonNearestFixedPositionMismatch = 1 << 11,
-  kSquashingDisallowedReasonScrollChildWithCompositedDescendants = 1 << 12,
-  kSquashingDisallowedReasonSquashingLayerIsAnimating = 1 << 13,
-  kSquashingDisallowedReasonRenderingContextMismatch = 1 << 14,
-  kSquashingDisallowedReasonFragmentedContent = 1 << 15,
+using SquashingDisallowedReasons = unsigned;
+
+#define FOR_EACH_SQUASHING_DISALLOWED_REASON(V) \
+  V(ScrollsWithRespectToSquashingLayer)         \
+  V(SquashingSparsityExceeded)                  \
+  V(ClippingContainerMismatch)                  \
+  V(OpacityAncestorMismatch)                    \
+  V(TransformAncestorMismatch)                  \
+  V(FilterMismatch)                             \
+  V(WouldBreakPaintOrder)                       \
+  V(SquashingVideoIsDisallowed)                 \
+  V(SquashedLayerClipsCompositingDescendants)   \
+  V(SquashingLayoutEmbeddedContentIsDisallowed) \
+  V(SquashingBlendingIsDisallowed)              \
+  V(NearestFixedPositionMismatch)               \
+  V(ScrollChildWithCompositedDescendants)       \
+  V(SquashingLayerIsAnimating)                  \
+  V(RenderingContextMismatch)                   \
+  V(FragmentedContent)
+
+class PLATFORM_EXPORT SquashingDisallowedReason {
+ private:
+  // This contains ordinal values for squashing disallowed reasons and will be
+  // used to generate the squashing disallowed reason bits.
+  enum {
+#define V(name) kE##name,
+    FOR_EACH_SQUASHING_DISALLOWED_REASON(V)
+#undef V
+  };
+
+#define V(name) static_assert(kE##name < 32, "Should fit in 32 bits");
+  FOR_EACH_SQUASHING_DISALLOWED_REASON(V)
+#undef V
+
+ public:
+  static Vector<const char*> ShortNames(SquashingDisallowedReasons);
+  static Vector<const char*> Descriptions(SquashingDisallowedReasons);
+
+  enum : SquashingDisallowedReasons {
+    kNone = 0,
+#define V(name) k##name = 1u << kE##name,
+    FOR_EACH_SQUASHING_DISALLOWED_REASON(V)
+#undef V
+  };
 };
 
-typedef unsigned SquashingDisallowedReasons;
-
-struct SquashingDisallowedReasonStringMap {
-  STACK_ALLOCATED();
-  SquashingDisallowedReasons reason;
-  const char* short_name;
-  const char* description;
-};
-
-PLATFORM_EXPORT extern const SquashingDisallowedReasonStringMap
-    kSquashingDisallowedReasonStringMap[];
-PLATFORM_EXPORT extern const size_t kNumberOfSquashingDisallowedReasons;
-
 }  // namespace blink
 
 #endif  // SquashingDisallowedReasons_h
diff --git a/third_party/WebKit/Source/platform/graphics/StaticBitmapImage.cpp b/third_party/WebKit/Source/platform/graphics/StaticBitmapImage.cpp
index 2c5b3c8..4aa751f 100644
--- a/third_party/WebKit/Source/platform/graphics/StaticBitmapImage.cpp
+++ b/third_party/WebKit/Source/platform/graphics/StaticBitmapImage.cpp
@@ -32,6 +32,30 @@
   return UnacceleratedStaticBitmapImage::Create(std::move(image));
 }
 
+scoped_refptr<StaticBitmapImage> StaticBitmapImage::Create(
+    scoped_refptr<Uint8Array>&& image_pixels,
+    const SkImageInfo& info) {
+  SkPixmap pixmap(info, image_pixels->Data(), info.minRowBytes());
+
+  Uint8Array* pixels = image_pixels.get();
+  if (pixels) {
+    pixels->AddRef();
+    image_pixels = nullptr;
+  }
+
+  return Create(SkImage::MakeFromRaster(
+      pixmap,
+      [](const void*, void* p) { static_cast<Uint8Array*>(p)->Release(); },
+      pixels));
+}
+
+scoped_refptr<StaticBitmapImage> StaticBitmapImage::Create(
+    WTF::ArrayBufferContents& contents,
+    const SkImageInfo& info) {
+  SkPixmap pixmap(info, contents.Data(), info.minRowBytes());
+  return Create(SkImage::MakeFromRaster(pixmap, nullptr, nullptr));
+}
+
 void StaticBitmapImage::DrawHelper(PaintCanvas* canvas,
                                    const PaintFlags& flags,
                                    const FloatRect& dst_rect,
diff --git a/third_party/WebKit/Source/platform/graphics/StaticBitmapImage.h b/third_party/WebKit/Source/platform/graphics/StaticBitmapImage.h
index 867e241..1b64a155 100644
--- a/third_party/WebKit/Source/platform/graphics/StaticBitmapImage.h
+++ b/third_party/WebKit/Source/platform/graphics/StaticBitmapImage.h
@@ -10,6 +10,7 @@
 #include "gpu/command_buffer/common/sync_token.h"
 #include "platform/graphics/GraphicsTypes.h"
 #include "platform/graphics/Image.h"
+#include "platform/wtf/typed_arrays/Uint8Array.h"
 #include "third_party/khronos/GLES2/gl2.h"
 #include "third_party/skia/include/core/SkRefCnt.h"
 
@@ -28,6 +29,10 @@
       sk_sp<SkImage>,
       base::WeakPtr<WebGraphicsContext3DProviderWrapper> = nullptr);
   static scoped_refptr<StaticBitmapImage> Create(PaintImage);
+  static scoped_refptr<StaticBitmapImage> Create(scoped_refptr<Uint8Array>&&,
+                                                 const SkImageInfo&);
+  static scoped_refptr<StaticBitmapImage> Create(WTF::ArrayBufferContents&,
+                                                 const SkImageInfo&);
 
   bool IsStaticBitmapImage() const override { return true; }
 
diff --git a/third_party/WebKit/Source/platform/graphics/compositing/PaintArtifactCompositorTest.cpp b/third_party/WebKit/Source/platform/graphics/compositing/PaintArtifactCompositorTest.cpp
index 3097780..dfcf5f2 100644
--- a/third_party/WebKit/Source/platform/graphics/compositing/PaintArtifactCompositorTest.cpp
+++ b/third_party/WebKit/Source/platform/graphics/compositing/PaintArtifactCompositorTest.cpp
@@ -283,7 +283,7 @@
   scoped_refptr<TransformPaintPropertyNode> transform =
       TransformPaintPropertyNode::Create(
           TransformPaintPropertyNode::Root(), TransformationMatrix().Rotate(90),
-          FloatPoint3D(100, 100, 0), false, 0, kCompositingReason3DTransform);
+          FloatPoint3D(100, 100, 0), false, 0, CompositingReason::k3DTransform);
 
   TestPaintArtifact artifact;
   artifact
@@ -330,11 +330,11 @@
   scoped_refptr<TransformPaintPropertyNode> transform1 =
       TransformPaintPropertyNode::Create(
           TransformPaintPropertyNode::Root(), TransformationMatrix().Scale(2),
-          FloatPoint3D(10, 10, 0), false, 0, kCompositingReason3DTransform);
+          FloatPoint3D(10, 10, 0), false, 0, CompositingReason::k3DTransform);
   scoped_refptr<TransformPaintPropertyNode> transform2 =
       TransformPaintPropertyNode::Create(
           transform1, TransformationMatrix().Translate(5, 5), FloatPoint3D(),
-          false, 0, kCompositingReason3DTransform);
+          false, 0, CompositingReason::k3DTransform);
 
   TestPaintArtifact artifact;
   artifact
@@ -437,17 +437,17 @@
   scoped_refptr<TransformPaintPropertyNode> transform2 =
       TransformPaintPropertyNode::Create(transform1, TransformationMatrix(),
                                          FloatPoint3D(), false, 1,
-                                         kCompositingReason3DTransform);
+                                         CompositingReason::k3DTransform);
   // Extends the 3D rendering context of transform2.
   scoped_refptr<TransformPaintPropertyNode> transform3 =
       TransformPaintPropertyNode::Create(transform2, TransformationMatrix(),
                                          FloatPoint3D(), false, 1,
-                                         kCompositingReason3DTransform);
+                                         CompositingReason::k3DTransform);
   // Establishes a 3D rendering context distinct from transform2.
   scoped_refptr<TransformPaintPropertyNode> transform4 =
       TransformPaintPropertyNode::Create(transform2, TransformationMatrix(),
                                          FloatPoint3D(), false, 2,
-                                         kCompositingReason3DTransform);
+                                         CompositingReason::k3DTransform);
 
   TestPaintArtifact artifact;
   artifact
@@ -545,11 +545,11 @@
   scoped_refptr<ClipPaintPropertyNode> clip1 = ClipPaintPropertyNode::Create(
       ClipPaintPropertyNode::Root(), TransformPaintPropertyNode::Root(),
       FloatRoundedRect(100, 100, 700, 700),
-      kCompositingReasonOverflowScrollingTouch);
+      CompositingReason::kOverflowScrollingTouch);
   scoped_refptr<ClipPaintPropertyNode> clip2 =
       ClipPaintPropertyNode::Create(clip1, TransformPaintPropertyNode::Root(),
                                     FloatRoundedRect(200, 200, 700, 700),
-                                    kCompositingReasonOverflowScrollingTouch);
+                                    CompositingReason::kOverflowScrollingTouch);
 
   TestPaintArtifact artifact;
   artifact
@@ -734,19 +734,19 @@
           EffectPaintPropertyNode::Root(), TransformPaintPropertyNode::Root(),
           ClipPaintPropertyNode::Root(), kColorFilterNone,
           CompositorFilterOperations(), 0.5, SkBlendMode::kSrcOver,
-          kCompositingReasonAll, CompositorElementId(2));
+          CompositingReason::kAll, CompositorElementId(2));
   scoped_refptr<EffectPaintPropertyNode> effect2 =
       EffectPaintPropertyNode::Create(
           effect1, TransformPaintPropertyNode::Root(),
           ClipPaintPropertyNode::Root(), kColorFilterNone,
           CompositorFilterOperations(), 0.3, SkBlendMode::kSrcOver,
-          kCompositingReasonAll);
+          CompositingReason::kAll);
   scoped_refptr<EffectPaintPropertyNode> effect3 =
       EffectPaintPropertyNode::Create(
           EffectPaintPropertyNode::Root(), TransformPaintPropertyNode::Root(),
           ClipPaintPropertyNode::Root(), kColorFilterNone,
           CompositorFilterOperations(), 0.2, SkBlendMode::kSrcOver,
-          kCompositingReasonAll);
+          CompositingReason::kAll);
 
   TestPaintArtifact artifact;
   artifact
@@ -805,7 +805,7 @@
       TransformPaintPropertyNode::Create(
           TransformPaintPropertyNode::Root(),
           TransformationMatrix().Translate(7, 9), FloatPoint3D(), false, 0,
-          kCompositingReasonNone, CompositorElementId(), scroll);
+          CompositingReason::kNone, CompositorElementId(), scroll);
 
   TestPaintArtifact artifact;
   artifact
@@ -876,12 +876,12 @@
       TransformPaintPropertyNode::Create(
           TransformPaintPropertyNode::Root(),
           TransformationMatrix().Translate(7, 9), FloatPoint3D(), false, 0,
-          kCompositingReasonNone, CompositorElementId(), scroll);
+          CompositingReason::kNone, CompositorElementId(), scroll);
 
   scoped_refptr<TransformPaintPropertyNode> transform =
       TransformPaintPropertyNode::Create(
           scroll_translation, TransformationMatrix(), FloatPoint3D(), false, 0,
-          kCompositingReason3DTransform);
+          CompositingReason::k3DTransform);
 
   TestPaintArtifact artifact;
   artifact
@@ -939,7 +939,7 @@
       TransformPaintPropertyNode::Create(
           TransformPaintPropertyNode::Root(),
           TransformationMatrix().Translate(11, 13), FloatPoint3D(), false, 0,
-          kCompositingReasonLayerForScrollingContents, CompositorElementId(),
+          CompositingReason::kLayerForScrollingContents, CompositorElementId(),
           scroll_a);
 
   CompositorElementId scroll_element_id_b = ScrollElementId(3);
@@ -951,7 +951,7 @@
   scoped_refptr<TransformPaintPropertyNode> scroll_translation_b =
       TransformPaintPropertyNode::Create(
           scroll_translation_a, TransformationMatrix().Translate(37, 41),
-          FloatPoint3D(), false, 0, kCompositingReasonNone,
+          FloatPoint3D(), false, 0, CompositingReason::kNone,
           CompositorElementId(), scroll_b);
   TestPaintArtifact artifact;
   artifact.Chunk(scroll_translation_a, ClipPaintPropertyNode::Root(), effect)
@@ -1018,13 +1018,13 @@
       TransformPaintPropertyNode::Create(
           TransformPaintPropertyNode::Root(),
           TransformationMatrix().Translate(7, 9), FloatPoint3D(), false, 0,
-          kCompositingReasonWillChangeCompositingHint, CompositorElementId(),
+          CompositingReason::kWillChangeCompositingHint, CompositorElementId(),
           scroll);
 
   scoped_refptr<TransformPaintPropertyNode> transform =
       TransformPaintPropertyNode::Create(
           scroll_translation, TransformationMatrix().Translate(5, 5),
-          FloatPoint3D(), false, 0, kCompositingReason3DTransform);
+          FloatPoint3D(), false, 0, CompositingReason::k3DTransform);
 
   TestPaintArtifact artifact;
   artifact.Chunk(scroll_translation, clip, EffectPaintPropertyNode::Root())
@@ -1068,7 +1068,7 @@
       TransformPaintPropertyNode::Create(
           TransformPaintPropertyNode::Root(),
           TransformationMatrix().Translate(7, 9), FloatPoint3D(), false, 0,
-          kCompositingReasonWillChangeCompositingHint, CompositorElementId(),
+          CompositingReason::kWillChangeCompositingHint, CompositorElementId(),
           scroll_1);
 
   scoped_refptr<ClipPaintPropertyNode> clip_2 = ClipPaintPropertyNode::Create(
@@ -1083,7 +1083,7 @@
       TransformPaintPropertyNode::Create(
           TransformPaintPropertyNode::Root(),
           TransformationMatrix().Translate(0, 0), FloatPoint3D(), false, 0,
-          kCompositingReasonWillChangeCompositingHint, CompositorElementId(),
+          CompositingReason::kWillChangeCompositingHint, CompositorElementId(),
           scroll_2);
 
   TestPaintArtifact artifact;
@@ -1139,7 +1139,7 @@
       TransformPaintPropertyNode::Create(
           TransformPaintPropertyNode::Root(),
           TransformationMatrix().Translate(11, 13), FloatPoint3D(), false, 0,
-          kCompositingReasonLayerForScrollingContents, CompositorElementId(),
+          CompositingReason::kLayerForScrollingContents, CompositorElementId(),
           scroll_a);
 
   CompositorElementId scroll_element_id_b = ScrollElementId(3);
@@ -1151,7 +1151,7 @@
   scoped_refptr<TransformPaintPropertyNode> scroll_translation_b =
       TransformPaintPropertyNode::Create(
           scroll_translation_a, TransformationMatrix().Translate(37, 41),
-          FloatPoint3D(), false, 0, kCompositingReasonNone,
+          FloatPoint3D(), false, 0, CompositingReason::kNone,
           CompositorElementId(), scroll_b);
 
   TestPaintArtifact artifact;
@@ -1312,7 +1312,7 @@
   scoped_refptr<TransformPaintPropertyNode> transform =
       TransformPaintPropertyNode::Create(
           TransformPaintPropertyNode::Root(), TransformationMatrix(),
-          FloatPoint3D(), false, 0, kCompositingReason3DTransform);
+          FloatPoint3D(), false, 0, CompositingReason::k3DTransform);
 
   scoped_refptr<TransformPaintPropertyNode> transform2 =
       TransformPaintPropertyNode::Create(
@@ -1806,7 +1806,7 @@
       TransformPaintPropertyNode::Create(
           TransformPaintPropertyNode::Root(),
           TransformationMatrix().Translate(50, 50), FloatPoint3D(100, 100, 0),
-          false, 0, kCompositingReason3DTransform);
+          false, 0, CompositingReason::k3DTransform);
 
   TestPaintArtifact test_artifact;
   test_artifact.Chunk(DefaultPaintChunkProperties())
@@ -1969,7 +1969,7 @@
       EffectPaintPropertyNode::Root(), TransformPaintPropertyNode::Root(),
       ClipPaintPropertyNode::Root(), kColorFilterNone,
       CompositorFilterOperations(), opacity, SkBlendMode::kSrcOver,
-      kCompositingReasonActiveAnimation, expected_compositor_element_id);
+      CompositingReason::kActiveAnimation, expected_compositor_element_id);
 }
 
 scoped_refptr<TransformPaintPropertyNode>
@@ -1977,7 +1977,7 @@
   CompositorElementId expected_compositor_element_id(3);
   return TransformPaintPropertyNode::Create(
       TransformPaintPropertyNode::Root(), TransformationMatrix().Rotate(90),
-      FloatPoint3D(100, 100, 0), false, 0, kCompositingReason3DTransform,
+      FloatPoint3D(100, 100, 0), false, 0, CompositingReason::k3DTransform,
       expected_compositor_element_id);
 }
 
@@ -2014,13 +2014,13 @@
           EffectPaintPropertyNode::Root(), TransformPaintPropertyNode::Root(),
           ClipPaintPropertyNode::Root(), kColorFilterNone,
           CompositorFilterOperations(), 1.0, SkBlendMode::kSrcOver,
-          kCompositingReasonIsolateCompositedDescendants);
+          CompositingReason::kIsolateCompositedDescendants);
   scoped_refptr<EffectPaintPropertyNode> masking =
       EffectPaintPropertyNode::Create(
           masked, TransformPaintPropertyNode::Root(),
           ClipPaintPropertyNode::Root(), kColorFilterLuminanceToAlpha,
           CompositorFilterOperations(), 1.0, SkBlendMode::kDstIn,
-          kCompositingReasonSquashingDisallowed);
+          CompositingReason::kSquashingDisallowed);
 
   TestPaintArtifact artifact;
   artifact
@@ -2063,7 +2063,7 @@
   scoped_refptr<TransformPaintPropertyNode> transform =
       TransformPaintPropertyNode::Create(
           TransformPaintPropertyNode::Root(), TransformationMatrix().Rotate(90),
-          FloatPoint3D(100, 100, 0), false, 0, kCompositingReason3DTransform);
+          FloatPoint3D(100, 100, 0), false, 0, CompositingReason::k3DTransform);
 
   scoped_refptr<ClipPaintPropertyNode> clip = ClipPaintPropertyNode::Create(
       ClipPaintPropertyNode::Root(), TransformPaintPropertyNode::Root(),
@@ -2171,7 +2171,7 @@
           EffectPaintPropertyNode::Root(), TransformPaintPropertyNode::Root(),
           ClipPaintPropertyNode::Root(), kColorFilterNone,
           CompositorFilterOperations(), 0.5f, SkBlendMode::kSrcOver,
-          kCompositingReasonAll);
+          CompositingReason::kAll);
 
   TestPaintArtifact artifact;
   artifact
@@ -2219,7 +2219,7 @@
           effect1, TransformPaintPropertyNode::Root(),
           ClipPaintPropertyNode::Root(), kColorFilterNone,
           CompositorFilterOperations(), 0.2f, SkBlendMode::kSrcOver,
-          kCompositingReasonAll);
+          CompositingReason::kAll);
   scoped_refptr<EffectPaintPropertyNode> effect3 =
       CreateOpacityOnlyEffect(effect2, 0.3f);
 
@@ -2269,7 +2269,7 @@
   scoped_refptr<TransformPaintPropertyNode> transform =
       TransformPaintPropertyNode::Create(
           TransformPaintPropertyNode::Root(), TransformationMatrix(),
-          FloatPoint3D(), false, 0, kCompositingReason3DTransform);
+          FloatPoint3D(), false, 0, CompositingReason::k3DTransform);
 
   TestPaintArtifact artifact;
   artifact
@@ -2314,7 +2314,7 @@
   scoped_refptr<TransformPaintPropertyNode> transform =
       TransformPaintPropertyNode::Create(
           TransformPaintPropertyNode::Root(), TransformationMatrix(),
-          FloatPoint3D(), false, 0, kCompositingReason3DTransform);
+          FloatPoint3D(), false, 0, CompositingReason::k3DTransform);
   TestPaintArtifact artifact;
   artifact
       .Chunk(TransformPaintPropertyNode::Root(), ClipPaintPropertyNode::Root(),
@@ -2497,7 +2497,7 @@
 TEST_F(PaintArtifactCompositorTest,
        DontSkipChunkWithTinyOpacityAndDirectCompositingReason) {
   scoped_refptr<EffectPaintPropertyNode> effect =
-      CreateEffectWithOpacityAndReason(0.0001f, kCompositingReasonCanvas);
+      CreateEffectWithOpacityAndReason(0.0001f, CompositingReason::kCanvas);
   TestPaintArtifact artifact;
   artifact
       .Chunk(TransformPaintPropertyNode::Root(), ClipPaintPropertyNode::Root(),
@@ -2510,9 +2510,9 @@
 TEST_F(PaintArtifactCompositorTest,
        SkipChunkWithTinyOpacityAndVisibleChildEffectNode) {
   scoped_refptr<EffectPaintPropertyNode> tinyEffect =
-      CreateEffectWithOpacityAndReason(0.0001f, kCompositingReasonNone);
+      CreateEffectWithOpacityAndReason(0.0001f, CompositingReason::kNone);
   scoped_refptr<EffectPaintPropertyNode> visibleEffect =
-      CreateEffectWithOpacityAndReason(0.5f, kCompositingReasonNone,
+      CreateEffectWithOpacityAndReason(0.5f, CompositingReason::kNone,
                                        tinyEffect);
   TestPaintArtifact artifact;
   artifact
@@ -2527,9 +2527,9 @@
     PaintArtifactCompositorTest,
     DontSkipChunkWithTinyOpacityAndVisibleChildEffectNodeWithCompositingParent) {
   scoped_refptr<EffectPaintPropertyNode> tinyEffect =
-      CreateEffectWithOpacityAndReason(0.0001f, kCompositingReasonCanvas);
+      CreateEffectWithOpacityAndReason(0.0001f, CompositingReason::kCanvas);
   scoped_refptr<EffectPaintPropertyNode> visibleEffect =
-      CreateEffectWithOpacityAndReason(0.5f, kCompositingReasonNone,
+      CreateEffectWithOpacityAndReason(0.5f, CompositingReason::kNone,
                                        tinyEffect);
   TestPaintArtifact artifact;
   artifact
@@ -2543,9 +2543,9 @@
 TEST_F(PaintArtifactCompositorTest,
        SkipChunkWithTinyOpacityAndVisibleChildEffectNodeWithCompositingChild) {
   scoped_refptr<EffectPaintPropertyNode> tinyEffect =
-      CreateEffectWithOpacityAndReason(0.0001f, kCompositingReasonNone);
+      CreateEffectWithOpacityAndReason(0.0001f, CompositingReason::kNone);
   scoped_refptr<EffectPaintPropertyNode> visibleEffect =
-      CreateEffectWithOpacityAndReason(0.5f, kCompositingReasonCanvas,
+      CreateEffectWithOpacityAndReason(0.5f, CompositingReason::kCanvas,
                                        tinyEffect);
   TestPaintArtifact artifact;
   artifact
@@ -2589,7 +2589,7 @@
   FloatRoundedRect rrect(FloatRect(50, 50, 300, 200), corner, corner, corner,
                          corner);
   scoped_refptr<ClipPaintPropertyNode> c1 = ClipPaintPropertyNode::Create(
-      c0(), t0(), rrect, kCompositingReasonWillChangeCompositingHint);
+      c0(), t0(), rrect, CompositingReason::kWillChangeCompositingHint);
 
   TestPaintArtifact artifact;
   artifact.Chunk(t0(), c1, e0())
@@ -2639,13 +2639,13 @@
   scoped_refptr<TransformPaintPropertyNode> t1 =
       TransformPaintPropertyNode::Create(
           t0(), TransformationMatrix(), FloatPoint3D(), false, 0,
-          kCompositingReasonWillChangeCompositingHint);
+          CompositingReason::kWillChangeCompositingHint);
 
   FloatSize corner(5, 5);
   FloatRoundedRect rrect(FloatRect(50, 50, 300, 200), corner, corner, corner,
                          corner);
   scoped_refptr<ClipPaintPropertyNode> c1 = ClipPaintPropertyNode::Create(
-      c0(), t0(), rrect, kCompositingReasonWillChangeCompositingHint);
+      c0(), t0(), rrect, CompositingReason::kWillChangeCompositingHint);
 
   TestPaintArtifact artifact;
   artifact.Chunk(t0(), c1, e0())
@@ -2710,13 +2710,13 @@
   scoped_refptr<TransformPaintPropertyNode> t1 =
       TransformPaintPropertyNode::Create(
           t0(), TransformationMatrix(), FloatPoint3D(), false, 0,
-          kCompositingReasonWillChangeCompositingHint);
+          CompositingReason::kWillChangeCompositingHint);
 
   FloatSize corner(5, 5);
   FloatRoundedRect rrect(FloatRect(50, 50, 300, 200), corner, corner, corner,
                          corner);
   scoped_refptr<ClipPaintPropertyNode> c1 = ClipPaintPropertyNode::Create(
-      c0(), t0(), rrect, kCompositingReasonWillChangeCompositingHint);
+      c0(), t0(), rrect, CompositingReason::kWillChangeCompositingHint);
 
   TestPaintArtifact artifact;
   artifact.Chunk(t0(), c1, e0())
@@ -2805,11 +2805,11 @@
   FloatRoundedRect rrect(FloatRect(50, 50, 300, 200), corner, corner, corner,
                          corner);
   scoped_refptr<ClipPaintPropertyNode> c1 = ClipPaintPropertyNode::Create(
-      c0(), t0(), rrect, kCompositingReasonWillChangeCompositingHint);
+      c0(), t0(), rrect, CompositingReason::kWillChangeCompositingHint);
 
   scoped_refptr<EffectPaintPropertyNode> e1 = EffectPaintPropertyNode::Create(
       e0(), t0(), c1, ColorFilter(), CompositorFilterOperations(), 1,
-      SkBlendMode::kSrcOver, kCompositingReasonWillChangeCompositingHint);
+      SkBlendMode::kSrcOver, CompositingReason::kWillChangeCompositingHint);
 
   TestPaintArtifact artifact;
   artifact.Chunk(t0(), c1, e0())
@@ -2877,13 +2877,13 @@
   FloatRoundedRect rrect(FloatRect(50, 50, 300, 200), corner, corner, corner,
                          corner);
   scoped_refptr<ClipPaintPropertyNode> c1 = ClipPaintPropertyNode::Create(
-      c0(), t0(), rrect, kCompositingReasonWillChangeCompositingHint);
+      c0(), t0(), rrect, CompositingReason::kWillChangeCompositingHint);
 
   CompositorFilterOperations non_trivial_filter;
   non_trivial_filter.AppendBlurFilter(5);
   scoped_refptr<EffectPaintPropertyNode> e1 = EffectPaintPropertyNode::Create(
       e0(), t0(), c0(), ColorFilter(), non_trivial_filter, 1,
-      SkBlendMode::kSrcOver, kCompositingReasonWillChangeCompositingHint);
+      SkBlendMode::kSrcOver, CompositingReason::kWillChangeCompositingHint);
 
   TestPaintArtifact artifact;
   artifact.Chunk(t0(), c1, e0())
@@ -2983,11 +2983,11 @@
   FloatRoundedRect rrect(FloatRect(50, 50, 300, 200), corner, corner, corner,
                          corner);
   scoped_refptr<ClipPaintPropertyNode> c1 = ClipPaintPropertyNode::Create(
-      c0(), t0(), rrect, kCompositingReasonWillChangeCompositingHint);
+      c0(), t0(), rrect, CompositingReason::kWillChangeCompositingHint);
 
   scoped_refptr<EffectPaintPropertyNode> e1 = EffectPaintPropertyNode::Create(
       e0(), t0(), c1, ColorFilter(), CompositorFilterOperations(), 1,
-      SkBlendMode::kMultiply, kCompositingReasonWillChangeCompositingHint);
+      SkBlendMode::kMultiply, CompositingReason::kWillChangeCompositingHint);
 
   TestPaintArtifact artifact;
   artifact.Chunk(t0(), c1, e0())
@@ -3208,7 +3208,7 @@
       EffectPaintPropertyNode::Create(
           EffectPaintPropertyNode::Root(), TransformPaintPropertyNode::Root(),
           nullptr, kColorFilterNone, CompositorFilterOperations(), 0.5,
-          SkBlendMode::kSrcOver, kCompositingReasonAll);
+          SkBlendMode::kSrcOver, CompositingReason::kAll);
 
   TestPaintArtifact artifact;
   artifact
diff --git a/third_party/WebKit/Source/platform/graphics/gpu/DrawingBuffer.cpp b/third_party/WebKit/Source/platform/graphics/gpu/DrawingBuffer.cpp
index d19c4ecb..d4f7487 100644
--- a/third_party/WebKit/Source/platform/graphics/gpu/DrawingBuffer.cpp
+++ b/third_party/WebKit/Source/platform/graphics/gpu/DrawingBuffer.cpp
@@ -1108,26 +1108,28 @@
   gl_->BindFramebuffer(target, WantExplicitResolve() ? multisample_fbo_ : fbo_);
 }
 
-bool DrawingBuffer::PaintRenderingResultsToImageData(
-    int& width,
-    int& height,
-    SourceDrawingBuffer source_buffer,
-    WTF::ArrayBufferContents& contents) {
+scoped_refptr<Uint8Array> DrawingBuffer::PaintRenderingResultsToDataArray(
+    SourceDrawingBuffer source_buffer) {
   ScopedStateRestorer scoped_state_restorer(this);
 
-  DCHECK(!premultiplied_alpha_);
-  width = Size().Width();
-  height = Size().Height();
+  int width = Size().Width();
+  int height = Size().Height();
 
   CheckedNumeric<int> data_size = 4;
   data_size *= width;
   data_size *= height;
   if (!data_size.IsValid())
-    return false;
+    return nullptr;
 
-  WTF::ArrayBufferContents pixels(width * height, 4,
-                                  WTF::ArrayBufferContents::kNotShared,
-                                  WTF::ArrayBufferContents::kDontInitialize);
+  unsigned byte_length = width * height * 4;
+  scoped_refptr<ArrayBuffer> dst_buffer =
+      ArrayBuffer::CreateOrNull(byte_length, 1);
+  if (!dst_buffer)
+    return nullptr;
+  scoped_refptr<Uint8Array> data_array =
+      Uint8Array::Create(std::move(dst_buffer), 0, byte_length);
+  if (!data_array)
+    return nullptr;
 
   GLuint fbo = 0;
   state_restorer_->SetFramebufferBindingDirty();
@@ -1141,9 +1143,10 @@
     gl_->BindFramebuffer(GL_FRAMEBUFFER, fbo_);
   }
 
-  ReadBackFramebuffer(static_cast<unsigned char*>(pixels.Data()), width, height,
-                      kReadbackRGBA, WebGLImageConversion::kAlphaDoNothing);
-  FlipVertically(static_cast<uint8_t*>(pixels.Data()), width, height);
+  ReadBackFramebuffer(static_cast<unsigned char*>(data_array->Data()), width,
+                      height, kReadbackRGBA,
+                      WebGLImageConversion::kAlphaDoNothing);
+  FlipVertically(static_cast<uint8_t*>(data_array->Data()), width, height);
 
   if (fbo) {
     gl_->FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
@@ -1151,8 +1154,7 @@
     gl_->DeleteFramebuffers(1, &fbo);
   }
 
-  pixels.Transfer(contents);
-  return true;
+  return data_array;
 }
 
 void DrawingBuffer::ReadBackFramebuffer(unsigned char* pixels,
diff --git a/third_party/WebKit/Source/platform/graphics/gpu/DrawingBuffer.h b/third_party/WebKit/Source/platform/graphics/gpu/DrawingBuffer.h
index c5f8504..ff92729 100644
--- a/third_party/WebKit/Source/platform/graphics/gpu/DrawingBuffer.h
+++ b/third_party/WebKit/Source/platform/graphics/gpu/DrawingBuffer.h
@@ -61,10 +61,6 @@
 class SharedBitmap;
 }
 
-namespace WTF {
-class ArrayBufferContents;
-}
-
 namespace blink {
 class CanvasColorParams;
 class Extensions3DUtil;
@@ -215,10 +211,8 @@
                              const IntRect& src_sub_rectangle,
                              SourceDrawingBuffer);
 
-  bool PaintRenderingResultsToImageData(int&,
-                                        int&,
-                                        SourceDrawingBuffer,
-                                        WTF::ArrayBufferContents&);
+  scoped_refptr<Uint8Array> PaintRenderingResultsToDataArray(
+      SourceDrawingBuffer);
 
   int SampleCount() const { return sample_count_; }
   bool ExplicitResolveOfMultisampleData() const {
diff --git a/third_party/WebKit/Source/platform/graphics/paint/ClipPaintPropertyNode.cpp b/third_party/WebKit/Source/platform/graphics/paint/ClipPaintPropertyNode.cpp
index 874535a..a696ce0 100644
--- a/third_party/WebKit/Source/platform/graphics/paint/ClipPaintPropertyNode.cpp
+++ b/third_party/WebKit/Source/platform/graphics/paint/ClipPaintPropertyNode.cpp
@@ -24,9 +24,9 @@
   json->SetString("localTransformSpace",
                   String::Format("%p", local_transform_space_.get()));
   json->SetString("rect", clip_rect_.ToString());
-  if (direct_compositing_reasons_ != kCompositingReasonNone) {
+  if (direct_compositing_reasons_ != CompositingReason::kNone) {
     json->SetString("directCompositingReasons",
-                    CompositingReasonsAsString(direct_compositing_reasons_));
+                    CompositingReason::ToString(direct_compositing_reasons_));
   }
   return json;
 }
diff --git a/third_party/WebKit/Source/platform/graphics/paint/ClipPaintPropertyNode.h b/third_party/WebKit/Source/platform/graphics/paint/ClipPaintPropertyNode.h
index c8fa070..abed9ac 100644
--- a/third_party/WebKit/Source/platform/graphics/paint/ClipPaintPropertyNode.h
+++ b/third_party/WebKit/Source/platform/graphics/paint/ClipPaintPropertyNode.h
@@ -35,7 +35,8 @@
       scoped_refptr<const ClipPaintPropertyNode> parent,
       scoped_refptr<const TransformPaintPropertyNode> local_transform_space,
       const FloatRoundedRect& clip_rect,
-      CompositingReasons direct_compositing_reasons = kCompositingReasonNone) {
+      CompositingReasons direct_compositing_reasons =
+          CompositingReason::kNone) {
     return base::AdoptRef(new ClipPaintPropertyNode(
         std::move(parent), std::move(local_transform_space), clip_rect,
         direct_compositing_reasons));
@@ -86,7 +87,7 @@
   std::unique_ptr<JSONObject> ToJSON() const;
 
   bool HasDirectCompositingReasons() const {
-    return direct_compositing_reasons_ != kCompositingReasonNone;
+    return direct_compositing_reasons_ != CompositingReason::kNone;
   }
 
  private:
diff --git a/third_party/WebKit/Source/platform/graphics/paint/EffectPaintPropertyNode.cpp b/third_party/WebKit/Source/platform/graphics/paint/EffectPaintPropertyNode.cpp
index 7ac69844..32f7d7a 100644
--- a/third_party/WebKit/Source/platform/graphics/paint/EffectPaintPropertyNode.cpp
+++ b/third_party/WebKit/Source/platform/graphics/paint/EffectPaintPropertyNode.cpp
@@ -41,9 +41,9 @@
     json->SetDouble("opacity", opacity_);
   if (blend_mode_ != SkBlendMode::kSrcOver)
     json->SetString("blendMode", SkBlendMode_Name(blend_mode_));
-  if (direct_compositing_reasons_ != kCompositingReasonNone) {
+  if (direct_compositing_reasons_ != CompositingReason::kNone) {
     json->SetString("directCompositingReasons",
-                    CompositingReasonsAsString(direct_compositing_reasons_));
+                    CompositingReason::ToString(direct_compositing_reasons_));
   }
   if (compositor_element_id_) {
     json->SetString("compositorElementId",
diff --git a/third_party/WebKit/Source/platform/graphics/paint/EffectPaintPropertyNode.h b/third_party/WebKit/Source/platform/graphics/paint/EffectPaintPropertyNode.h
index 596271f..a6e9ede 100644
--- a/third_party/WebKit/Source/platform/graphics/paint/EffectPaintPropertyNode.h
+++ b/third_party/WebKit/Source/platform/graphics/paint/EffectPaintPropertyNode.h
@@ -38,7 +38,7 @@
       CompositorFilterOperations filter,
       float opacity,
       SkBlendMode blend_mode,
-      CompositingReasons direct_compositing_reasons = kCompositingReasonNone,
+      CompositingReasons direct_compositing_reasons = CompositingReason::kNone,
       const CompositorElementId& compositor_element_id = CompositorElementId(),
       const FloatPoint& paint_offset = FloatPoint()) {
     return base::AdoptRef(new EffectPaintPropertyNode(
@@ -56,7 +56,7 @@
       CompositorFilterOperations filter,
       float opacity,
       SkBlendMode blend_mode,
-      CompositingReasons direct_compositing_reasons = kCompositingReasonNone,
+      CompositingReasons direct_compositing_reasons = CompositingReason::kNone,
       const CompositorElementId& compositor_element_id = CompositorElementId(),
       const FloatPoint& paint_offset = FloatPoint()) {
     bool parent_changed = PaintPropertyNode::Update(std::move(parent));
@@ -132,11 +132,11 @@
   std::unique_ptr<JSONObject> ToJSON() const;
 
   bool HasDirectCompositingReasons() const {
-    return direct_compositing_reasons_ != kCompositingReasonNone;
+    return direct_compositing_reasons_ != CompositingReason::kNone;
   }
 
   bool RequiresCompositingForAnimation() const {
-    return direct_compositing_reasons_ & kCompositingReasonActiveAnimation;
+    return direct_compositing_reasons_ & CompositingReason::kActiveAnimation;
   }
 
   const CompositorElementId& GetCompositorElementId() const {
diff --git a/third_party/WebKit/Source/platform/graphics/paint/GeometryMapperTest.cpp b/third_party/WebKit/Source/platform/graphics/paint/GeometryMapperTest.cpp
index fe19a5c..df16b7b 100644
--- a/third_party/WebKit/Source/platform/graphics/paint/GeometryMapperTest.cpp
+++ b/third_party/WebKit/Source/platform/graphics/paint/GeometryMapperTest.cpp
@@ -621,7 +621,7 @@
   auto effect = EffectPaintPropertyNode::Create(
       EffectPaintPropertyNode::Root(), TransformPaintPropertyNode::Root(),
       ClipPaintPropertyNode::Root(), kColorFilterNone, filters, 1.0,
-      SkBlendMode::kSrcOver, kCompositingReasonNone, CompositorElementId(),
+      SkBlendMode::kSrcOver, CompositingReason::kNone, CompositorElementId(),
       FloatPoint(100, 100));
   local_state.SetEffect(effect);
 
diff --git a/third_party/WebKit/Source/platform/graphics/paint/PropertyTreeStateTest.cpp b/third_party/WebKit/Source/platform/graphics/paint/PropertyTreeStateTest.cpp
index a3af050..a128883b 100644
--- a/third_party/WebKit/Source/platform/graphics/paint/PropertyTreeStateTest.cpp
+++ b/third_party/WebKit/Source/platform/graphics/paint/PropertyTreeStateTest.cpp
@@ -23,7 +23,7 @@
   scoped_refptr<TransformPaintPropertyNode> transform =
       TransformPaintPropertyNode::Create(TransformPaintPropertyNode::Root(),
                                          TransformationMatrix(), FloatPoint3D(),
-                                         false, 0, kCompositingReasonNone,
+                                         false, 0, CompositingReason::kNone,
                                          expected_compositor_element_id);
   PropertyTreeState state(transform.get(), ClipPaintPropertyNode::Root(),
                           EffectPaintPropertyNode::Root());
@@ -38,7 +38,7 @@
           EffectPaintPropertyNode::Root(), TransformPaintPropertyNode::Root(),
           ClipPaintPropertyNode::Root(), kColorFilterNone,
           CompositorFilterOperations(), 1.0, SkBlendMode::kSrcOver,
-          kCompositingReasonNone, expected_compositor_element_id);
+          CompositingReason::kNone, expected_compositor_element_id);
   PropertyTreeState state(TransformPaintPropertyNode::Root(),
                           ClipPaintPropertyNode::Root(), effect.get());
   EXPECT_EQ(expected_compositor_element_id,
@@ -50,14 +50,14 @@
   scoped_refptr<TransformPaintPropertyNode> transform =
       TransformPaintPropertyNode::Create(TransformPaintPropertyNode::Root(),
                                          TransformationMatrix(), FloatPoint3D(),
-                                         false, 0, kCompositingReasonNone,
+                                         false, 0, CompositingReason::kNone,
                                          expected_compositor_element_id);
   scoped_refptr<EffectPaintPropertyNode> effect =
       EffectPaintPropertyNode::Create(
           EffectPaintPropertyNode::Root(), TransformPaintPropertyNode::Root(),
           ClipPaintPropertyNode::Root(), kColorFilterNone,
           CompositorFilterOperations(), 1.0, SkBlendMode::kSrcOver,
-          kCompositingReasonNone, expected_compositor_element_id);
+          CompositingReason::kNone, expected_compositor_element_id);
   PropertyTreeState state(transform.get(), ClipPaintPropertyNode::Root(),
                           effect.get());
   EXPECT_EQ(expected_compositor_element_id,
@@ -70,14 +70,14 @@
   scoped_refptr<TransformPaintPropertyNode> transform =
       TransformPaintPropertyNode::Create(TransformPaintPropertyNode::Root(),
                                          TransformationMatrix(), FloatPoint3D(),
-                                         false, 0, kCompositingReasonNone,
+                                         false, 0, CompositingReason::kNone,
                                          first_compositor_element_id);
   scoped_refptr<EffectPaintPropertyNode> effect =
       EffectPaintPropertyNode::Create(
           EffectPaintPropertyNode::Root(), TransformPaintPropertyNode::Root(),
           ClipPaintPropertyNode::Root(), kColorFilterNone,
           CompositorFilterOperations(), 1.0, SkBlendMode::kSrcOver,
-          kCompositingReasonNone, second_compositor_element_id);
+          CompositingReason::kNone, second_compositor_element_id);
   PropertyTreeState state(transform.get(), ClipPaintPropertyNode::Root(),
                           effect.get());
 
diff --git a/third_party/WebKit/Source/platform/graphics/paint/TransformPaintPropertyNode.cpp b/third_party/WebKit/Source/platform/graphics/paint/TransformPaintPropertyNode.cpp
index 9c673de..df204f636 100644
--- a/third_party/WebKit/Source/platform/graphics/paint/TransformPaintPropertyNode.cpp
+++ b/third_party/WebKit/Source/platform/graphics/paint/TransformPaintPropertyNode.cpp
@@ -14,7 +14,7 @@
   DEFINE_STATIC_REF(TransformPaintPropertyNode, root,
                     base::AdoptRef(new TransformPaintPropertyNode(
                         nullptr, TransformationMatrix(), FloatPoint3D(), false,
-                        0, kCompositingReasonNone, CompositorElementId(),
+                        0, CompositingReason::kNone, CompositorElementId(),
                         ScrollPaintPropertyNode::Root())));
   return root;
 }
@@ -45,9 +45,9 @@
     json->SetString("renderingContextId",
                     String::Format("%x", rendering_context_id_));
   }
-  if (direct_compositing_reasons_ != kCompositingReasonNone) {
+  if (direct_compositing_reasons_ != CompositingReason::kNone) {
     json->SetString("directCompositingReasons",
-                    CompositingReasonsAsString(direct_compositing_reasons_));
+                    CompositingReason::ToString(direct_compositing_reasons_));
   }
   if (compositor_element_id_) {
     json->SetString("compositorElementId",
diff --git a/third_party/WebKit/Source/platform/graphics/paint/TransformPaintPropertyNode.h b/third_party/WebKit/Source/platform/graphics/paint/TransformPaintPropertyNode.h
index 7ab2c5a..78a3a5b 100644
--- a/third_party/WebKit/Source/platform/graphics/paint/TransformPaintPropertyNode.h
+++ b/third_party/WebKit/Source/platform/graphics/paint/TransformPaintPropertyNode.h
@@ -40,7 +40,7 @@
       const FloatPoint3D& origin,
       bool flattens_inherited_transform = false,
       unsigned rendering_context_id = 0,
-      CompositingReasons direct_compositing_reasons = kCompositingReasonNone,
+      CompositingReasons direct_compositing_reasons = CompositingReason::kNone,
       const CompositorElementId& compositor_element_id = CompositorElementId(),
       scoped_refptr<const ScrollPaintPropertyNode> scroll = nullptr) {
     if (scroll) {
@@ -62,7 +62,7 @@
       const FloatPoint3D& origin,
       bool flattens_inherited_transform = false,
       unsigned rendering_context_id = 0,
-      CompositingReasons direct_compositing_reasons = kCompositingReasonNone,
+      CompositingReasons direct_compositing_reasons = CompositingReason::kNone,
       CompositorElementId compositor_element_id = CompositorElementId(),
       scoped_refptr<const ScrollPaintPropertyNode> scroll = nullptr) {
     bool parent_changed = PaintPropertyNode::Update(std::move(parent));
@@ -112,11 +112,11 @@
   }
 
   bool HasDirectCompositingReasons() const {
-    return direct_compositing_reasons_ != kCompositingReasonNone;
+    return direct_compositing_reasons_ != CompositingReason::kNone;
   }
 
   bool RequiresCompositingForAnimation() const {
-    return direct_compositing_reasons_ & kCompositingReasonActiveAnimation;
+    return direct_compositing_reasons_ & CompositingReason::kActiveAnimation;
   }
 
   const CompositorElementId& GetCompositorElementId() const {
diff --git a/third_party/WebKit/Source/platform/heap/Member.h b/third_party/WebKit/Source/platform/heap/Member.h
index dcb2c4d..d1f1e588 100644
--- a/third_party/WebKit/Source/platform/heap/Member.h
+++ b/third_party/WebKit/Source/platform/heap/Member.h
@@ -196,8 +196,12 @@
  public:
   Member() : Parent() {}
   Member(std::nullptr_t) : Parent(nullptr) {}
-  Member(T* raw) : Parent(raw) { WriteBarrier(this->raw_); }
-  Member(T& raw) : Parent(raw) { WriteBarrier(this->raw_); }
+  Member(T* raw) : Parent(raw) {
+    // No write barrier for initializing stores.
+  }
+  Member(T& raw) : Parent(raw) {
+    // No write barrier for initializing stores.
+  }
   Member(WTF::HashTableDeletedValueType x) : Parent(x) {}
 
   Member(const Member& other) : Parent(other) { WriteBarrier(this->raw_); }
diff --git a/third_party/WebKit/Source/platform/loader/BUILD.gn b/third_party/WebKit/Source/platform/loader/BUILD.gn
index 19b5508..873ce9e 100644
--- a/third_party/WebKit/Source/platform/loader/BUILD.gn
+++ b/third_party/WebKit/Source/platform/loader/BUILD.gn
@@ -64,7 +64,6 @@
     "fetch/ResourceLoader.h",
     "fetch/ResourceLoaderOptions.h",
     "fetch/ResourceLoadingLog.h",
-    "fetch/ResourceOwner.h",
     "fetch/ResourcePriority.h",
     "fetch/ResourceRequest.cpp",
     "fetch/ResourceRequest.h",
diff --git a/third_party/WebKit/Source/platform/loader/fetch/RawResource.h b/third_party/WebKit/Source/platform/loader/fetch/RawResource.h
index b81d484..8c085ec 100644
--- a/third_party/WebKit/Source/platform/loader/fetch/RawResource.h
+++ b/third_party/WebKit/Source/platform/loader/fetch/RawResource.h
@@ -41,8 +41,6 @@
 
 class PLATFORM_EXPORT RawResource final : public Resource {
  public:
-  using ClientType = RawResourceClient;
-
   static RawResource* FetchSynchronously(FetchParameters&, ResourceFetcher*);
   static RawResource* Fetch(FetchParameters&, ResourceFetcher*);
   static RawResource* FetchMainResource(FetchParameters&,
diff --git a/third_party/WebKit/Source/platform/loader/fetch/ResourceClient.h b/third_party/WebKit/Source/platform/loader/fetch/ResourceClient.h
index b588e08..2be8958 100644
--- a/third_party/WebKit/Source/platform/loader/fetch/ResourceClient.h
+++ b/third_party/WebKit/Source/platform/loader/fetch/ResourceClient.h
@@ -28,13 +28,15 @@
 
 #include "platform/PlatformExport.h"
 #include "platform/heap/Handle.h"
+#include "platform/loader/fetch/Resource.h"
 #include "platform/wtf/Forward.h"
 #include "platform/wtf/text/WTFString.h"
 
 namespace blink {
-class Resource;
 
 class PLATFORM_EXPORT ResourceClient : public GarbageCollectedMixin {
+  USING_PRE_FINALIZER(ResourceClient, ClearResource);
+
  public:
   enum ResourceClientType {
     kBaseResourceType,
@@ -62,13 +64,39 @@
     return kBaseResourceType;
   }
 
+  Resource* GetResource() const { return resource_; }
+
   // Name for debugging, e.g. shown in memory-infra.
   virtual String DebugName() const = 0;
 
-  void Trace(blink::Visitor* visitor) override {}
+  void Trace(blink::Visitor* visitor) override { visitor->Trace(resource_); }
 
  protected:
   ResourceClient() {}
+
+  // TODO(japhet): There isn't a clean way for SVGResourceClients to determine
+  // whether SVGElementProxy is holding a Resource that it should register with,
+  // so SVGElementProxy handles it for those clients. SVGResourceClients should
+  // have a better way to register themselves as clients. crbug.com/789198
+  friend class SVGElementProxy;
+
+  void ClearResource() { SetResource(nullptr); }
+
+  void SetResource(Resource* new_resource) {
+    if (new_resource == resource_)
+      return;
+
+    // Some ResourceClient implementations reenter this so
+    // we need to prevent double removal.
+    if (Resource* old_resource = resource_.Release())
+      old_resource->RemoveClient(this);
+    resource_ = new_resource;
+    if (resource_)
+      resource_->AddClient(this);
+  }
+
+ private:
+  Member<Resource> resource_;
 };
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/platform/loader/fetch/ResourceFetcherTest.cpp b/third_party/WebKit/Source/platform/loader/fetch/ResourceFetcherTest.cpp
index cd3d998..cd6a2d1 100644
--- a/third_party/WebKit/Source/platform/loader/fetch/ResourceFetcherTest.cpp
+++ b/third_party/WebKit/Source/platform/loader/fetch/ResourceFetcherTest.cpp
@@ -257,31 +257,31 @@
 
  public:
   explicit RequestSameResourceOnComplete(Resource* resource)
-      : resource_(resource), notify_finished_called_(false) {}
+      : notify_finished_called_(false) {
+    SetResource(resource);
+  }
 
   void NotifyFinished(Resource* resource) override {
-    EXPECT_EQ(resource_, resource);
+    EXPECT_EQ(GetResource(), resource);
     MockFetchContext* context =
         MockFetchContext::Create(MockFetchContext::kShouldLoadNewResource);
     ResourceFetcher* fetcher2 = ResourceFetcher::Create(context);
-    ResourceRequest resource_request2(resource_->Url());
+    ResourceRequest resource_request2(GetResource()->Url());
     resource_request2.SetCacheMode(mojom::FetchCacheMode::kValidateCache);
     FetchParameters fetch_params2(resource_request2);
     Resource* resource2 = MockResource::Fetch(fetch_params2, fetcher2);
-    EXPECT_EQ(resource_, resource2);
+    EXPECT_EQ(GetResource(), resource2);
     notify_finished_called_ = true;
   }
   bool NotifyFinishedCalled() const { return notify_finished_called_; }
 
   void Trace(blink::Visitor* visitor) override {
-    visitor->Trace(resource_);
     RawResourceClient::Trace(visitor);
   }
 
   String DebugName() const override { return "RequestSameResourceOnComplete"; }
 
  private:
-  Member<Resource> resource_;
   bool notify_finished_called_;
 };
 
diff --git a/third_party/WebKit/Source/platform/loader/fetch/ResourceOwner.h b/third_party/WebKit/Source/platform/loader/fetch/ResourceOwner.h
deleted file mode 100644
index bfd2599..0000000
--- a/third_party/WebKit/Source/platform/loader/fetch/ResourceOwner.h
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * Copyright (C) 2013 Google Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef ResourceOwner_h
-#define ResourceOwner_h
-
-#include "platform/heap/Handle.h"
-#include "platform/loader/fetch/Resource.h"
-
-namespace blink {
-
-template <class R, class C>
-class GC_PLUGIN_IGNORE("https://crbug.com/652966") ResourceOwner;
-
-template <class R, class C = typename R::ClientType>
-class ResourceOwner : public C {
-  USING_PRE_FINALIZER(ResourceOwner, ClearResource);
-
- public:
-  using ResourceType = R;
-  ~ResourceOwner() override {}
-  ResourceType* GetResource() const { return resource_; }
-
-  void Trace(blink::Visitor* visitor) {
-    visitor->Trace(resource_);
-    C::Trace(visitor);
-  }
-
- protected:
-  ResourceOwner() {}
-
-  void SetResource(ResourceType*);
-  void ClearResource() { SetResource(nullptr); }
-
- private:
-  Member<ResourceType> resource_;
-};
-
-template <class R, class C>
-inline void ResourceOwner<R, C>::SetResource(R* new_resource) {
-  if (new_resource == resource_)
-    return;
-
-  // Some ResourceClient implementations reenter this so
-  // we need to prevent double removal.
-  if (ResourceType* old_resource = resource_.Release())
-    old_resource->RemoveClient(this);
-
-  if (new_resource) {
-    resource_ = new_resource;
-    resource_->AddClient(this);
-  }
-}
-
-}  // namespace blink
-
-#endif
diff --git a/third_party/WebKit/Source/platform/runtime_enabled_features.json5 b/third_party/WebKit/Source/platform/runtime_enabled_features.json5
index b4abb8c4..f895a60 100644
--- a/third_party/WebKit/Source/platform/runtime_enabled_features.json5
+++ b/third_party/WebKit/Source/platform/runtime_enabled_features.json5
@@ -351,10 +351,6 @@
       name: "DocumentWrite",
     },
     {
-      name: "DoubleTapToJumpOnVideo",
-      settable_from_internals: true
-    },
-    {
       name: "EmbedderCSPEnforcement",
       status: "stable",
     },
diff --git a/third_party/WebKit/Source/platform/wtf/Functional.h b/third_party/WebKit/Source/platform/wtf/Functional.h
index 820f681..89955f3 100644
--- a/third_party/WebKit/Source/platform/wtf/Functional.h
+++ b/third_party/WebKit/Source/platform/wtf/Functional.h
@@ -327,44 +327,13 @@
 #endif
 
 template <typename Signature>
-class Function;
+using Function = base::OnceCallback<Signature>;
 
-template <typename R, typename... Args>
-class Function<R(Args...)> {
-  USING_FAST_MALLOC(Function);
-
- public:
-  Function() {}
-  Function(base::Callback<R(Args...)> callback)
-      : callback_(std::move(callback)) {}
-  ~Function() {}
-
-  Function(const Function&) = delete;
-  Function& operator=(const Function&) = delete;
-
-  Function(Function&& other) : callback_(std::move(other.callback_)) {}
-
-  Function& operator=(Function&& other) {
-    callback_ = std::move(other.callback_);
-    return *this;
-  }
-
-  R Run(Args... args) && {
-    return std::move(callback_).Run(std::forward<Args>(args)...);
-  }
-
-  bool IsCancelled() const { return callback_.IsCancelled(); }
-  void Reset() { callback_.Reset(); }
-  explicit operator bool() const { return static_cast<bool>(callback_); }
-
-  friend base::OnceCallback<R(Args...)> ConvertToBaseCallback(
-      Function function) {
-    return std::move(function.callback_);
-  }
-
- private:
-  base::Callback<R(Args...)> callback_;
-};
+template <typename Signature>
+base::OnceCallback<Signature> ConvertToBaseCallback(
+    Function<Signature> function) {
+  return function;
+}
 
 template <typename Signature>
 class CrossThreadFunction;
@@ -416,17 +385,17 @@
                     std::index_sequence_for<BoundParameters...>,
                     std::decay_t<BoundParameters>...>::ok,
                 "A bound argument uses a bad pattern.");
+  auto cb = base::BindOnce(function,
+                           std::forward<BoundParameters>(bound_parameters)...);
+#if DCHECK_IS_ON()
   using UnboundRunType =
       base::MakeUnboundRunType<FunctionType, BoundParameters...>;
-  auto cb =
-      base::Bind(function, std::forward<BoundParameters>(bound_parameters)...);
-#if DCHECK_IS_ON()
   using WrapperType =
-      ThreadCheckingCallbackWrapper<base::Callback<UnboundRunType>>;
-  cb = base::Bind(&WrapperType::Run,
-                  std::make_unique<WrapperType>(std::move(cb)));
+      ThreadCheckingCallbackWrapper<base::OnceCallback<UnboundRunType>>;
+  cb = base::BindOnce(&WrapperType::Run,
+                      std::make_unique<WrapperType>(std::move(cb)));
 #endif
-  return Function<UnboundRunType>(std::move(cb));
+  return cb;
 }
 
 template <typename FunctionType, typename... BoundParameters>
@@ -501,4 +470,6 @@
 using WTF::CrossThreadFunction;
 using WTF::CrossThreadClosure;
 
+using WTF::ConvertToBaseCallback;
+
 #endif  // WTF_Functional_h
diff --git a/third_party/WebKit/Tools/Scripts/audit-non-blink-usage.py b/third_party/WebKit/Tools/Scripts/audit-non-blink-usage.py
index 9b45fe63..30a550d 100755
--- a/third_party/WebKit/Tools/Scripts/audit-non-blink-usage.py
+++ b/third_party/WebKit/Tools/Scripts/audit-non-blink-usage.py
@@ -43,6 +43,13 @@
             'base::span',
             'logging::GetVlogLevel',
 
+            # //base/callback.h is allowed, but you need to use WTF::Bind or
+            # WTF::BindRepeating to create callbacks in Blink.
+            'base::OnceCallback',
+            'base::OnceClosure',
+            'base::RepeatingCallback',
+            'base::RepeatingClosure',
+
             # Debugging helpers from //base/debug are allowed everywhere.
             'base::debug::.+',
 
diff --git a/third_party/WebKit/Tools/Scripts/run-blink-websocketserver b/third_party/WebKit/Tools/Scripts/run-blink-websocketserver
index 974a2ad..8593d703 100755
--- a/third_party/WebKit/Tools/Scripts/run-blink-websocketserver
+++ b/third_party/WebKit/Tools/Scripts/run-blink-websocketserver
@@ -43,4 +43,4 @@
 from webkitpy.layout_tests.servers import cli_wrapper
 from webkitpy.layout_tests.servers import pywebsocket
 
-cli_wrapper.main(pywebsocket.PyWebSocket, description)
+cli_wrapper.main(pywebsocket.PyWebSocket, description=__doc__)
diff --git a/third_party/WebKit/common/BUILD.gn b/third_party/WebKit/common/BUILD.gn
index 773713e5..d84775e 100644
--- a/third_party/WebKit/common/BUILD.gn
+++ b/third_party/WebKit/common/BUILD.gn
@@ -111,6 +111,7 @@
     "blob/blob.mojom",
     "blob/blob_registry.mojom",
     "clipboard/clipboard.mojom",
+    "feature_policy/feature_policy.mojom",
     "page/page_visibility_state.mojom",
     "service_worker/navigation_preload_state.mojom",
     "service_worker/service_worker.mojom",
@@ -128,6 +129,7 @@
   public_deps = [
     "//mojo/common:common_custom_types",
     "//url/mojo:url_mojom_gurl",
+    "//url/mojo:url_mojom_origin",
   ]
 
   export_class_attribute = "BLINK_COMMON_EXPORT"
diff --git a/third_party/WebKit/common/feature_policy/OWNERS b/third_party/WebKit/common/feature_policy/OWNERS
index be293f8e..41960f51 100644
--- a/third_party/WebKit/common/feature_policy/OWNERS
+++ b/third_party/WebKit/common/feature_policy/OWNERS
@@ -3,3 +3,10 @@
 loonybear@chromium.org
 
 # COMPONENT: Blink>FeaturePolicy
+
+per-file *.mojom=set noparent
+per-file *.mojom=file://ipc/SECURITY_OWNERS
+per-file *_struct_traits*.*=set noparent
+per-file *_struct_traits*.*=file://ipc/SECURITY_OWNERS
+per-file *.typemap=set noparent
+per-file *.typemap=file://ipc/SECURITY_OWNERS
diff --git a/third_party/WebKit/common/feature_policy/feature_policy.mojom b/third_party/WebKit/common/feature_policy/feature_policy.mojom
new file mode 100644
index 0000000..f67a1a0
--- /dev/null
+++ b/third_party/WebKit/common/feature_policy/feature_policy.mojom
@@ -0,0 +1,86 @@
+// 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 "url/mojo/origin.mojom";
+
+// This mirrors blink::WebSandboxFlags enum bitfield.
+[Extensible]
+enum WebSandboxFlags {
+  kNone                                  =     0,
+  kNavigation                            =     1, // 1 << 0
+  kPlugins                               =     2, // 1 << 1
+  kOrigin                                =     4, // 1 << 2
+  kForms                                 =     8, // 1 << 3
+  kScripts                               =    16, // 1 << 4
+  kTopNavigation                         =    32, // 1 << 5
+  kPopups                                =    64, // 1 << 6
+  kAutomaticFeatures                     =   128, // 1 << 7
+  kPointerLock                           =   256, // 1 << 8
+  kDocumentDomain                        =   512, // 1 << 9
+  kOrientationLock                       =  1024, // 1 << 10
+  kPropagatesToAuxiliaryBrowsingContexts =  2048, // 1 << 11
+  kModals                                =  4096, // 1 << 12
+  kPresentationController                =  8192, // 1 << 13
+  kTopNavigationByUserActivation         = 16384, // 1 << 14
+  kDownloads                             = 32768, // 1 << 15
+};
+
+// These values map to the features which can be controlled by Feature Policy.
+//
+// Features are defined in
+// https://github.com/WICG/feature-policy/blob/gh-pages/features.md. Many of
+// these are still under development in blink behind the
+// featurePolicyExperimentalFeatures flag.
+// This enum is also defined in ./feature_policy_feature.h
+enum FeaturePolicyFeature {
+  kNotFound = 0,
+  // Controls access to media autoplay.
+  kAutoplay,
+  // Controls access to video input devices.
+  kCamera,
+  // Controls whether navigator.requestMediaKeySystemAccess is allowed.
+  kEncryptedMedia,
+  // Controls whether Element.requestFullscreen is allowed.
+  kFullscreen,
+  // Controls access to Geolocation interface.
+  kGeolocation,
+  // Controls access to audio input devices.
+  kMicrophone,
+  // Controls access to requestMIDIAccess method.
+  kMidiFeature,
+  // Controls access to PaymentRequest interface.
+  kPayment,
+  // Controls access to audio output devices.
+  kSpeaker,
+  // Controls access to navigator.vibrate method.
+  kVibrate,
+  // Controls access to document.cookie attribute.
+  kDocumentCookie,
+  // Contols access to document.domain attribute.
+  kDocumentDomain,
+  // Controls access to document.write and document.writeln methods.
+  kDocumentWrite,
+  // Controls whether synchronous script elements will run.
+  kSyncScript,
+  // Controls use of synchronous XMLHTTPRequest API.
+  kSyncXHR,
+  // Controls access to the WebUSB API.
+  kUsb,
+  // Controls access to AOM event listeners.
+  kAccessibilityEvents,
+  // Controls use of WebVR API.
+  kWebVr,
+};
+
+// This struct holds feature policy whitelist data that needs to be replicated
+// between a RenderFrame and any of its associated RenderFrameProxies. A list of
+// these form a ParsedFeaturePolicy.
+// NOTE: These types are used for replication frame state between processes.
+struct ParsedFeaturePolicyDeclaration {
+  FeaturePolicyFeature feature;
+  bool matches_all_origins;
+  array<url.mojom.Origin> origins;
+};
diff --git a/third_party/WebKit/common/feature_policy/feature_policy.typemap b/third_party/WebKit/common/feature_policy/feature_policy.typemap
new file mode 100644
index 0000000..9107d26
--- /dev/null
+++ b/third_party/WebKit/common/feature_policy/feature_policy.typemap
@@ -0,0 +1,21 @@
+# Copyright 2017 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+mojom = "//third_party/WebKit/common/feature_policy/feature_policy.mojom"
+public_headers = [
+  "//third_party/WebKit/common/feature_policy/feature_policy.h",
+  "//third_party/WebKit/common/feature_policy/feature_policy_feature.h",
+  "//third_party/WebKit/common/sandbox_flags.h",
+]
+traits_headers = [
+  "//third_party/WebKit/common/feature_policy/feature_policy_struct_traits.h",
+]
+sources = [
+  "//third_party/WebKit/common/feature_policy/feature_policy_struct_traits.cc",
+]
+type_mappings = [
+  "blink.mojom.FeaturePolicyFeature=blink::FeaturePolicyFeature",
+  "blink.mojom.ParsedFeaturePolicyDeclaration=blink::ParsedFeaturePolicyDeclaration",
+  "blink.mojom.WebSandboxFlags=blink::WebSandboxFlags",
+]
diff --git a/third_party/WebKit/common/feature_policy/feature_policy_struct_traits.cc b/third_party/WebKit/common/feature_policy/feature_policy_struct_traits.cc
new file mode 100644
index 0000000..ea208ef
--- /dev/null
+++ b/third_party/WebKit/common/feature_policy/feature_policy_struct_traits.cc
@@ -0,0 +1,20 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/WebKit/common/feature_policy/feature_policy_struct_traits.h"
+
+#include "url/mojo/origin_struct_traits.h"
+
+namespace mojo {
+
+bool StructTraits<blink::mojom::ParsedFeaturePolicyDeclarationDataView,
+                  blink::ParsedFeaturePolicyDeclaration>::
+    Read(blink::mojom::ParsedFeaturePolicyDeclarationDataView in,
+         blink::ParsedFeaturePolicyDeclaration* out) {
+  out->matches_all_origins = in.matches_all_origins();
+
+  return in.ReadOrigins(&out->origins) && in.ReadFeature(&out->feature);
+}
+
+}  // namespace mojo
diff --git a/third_party/WebKit/common/feature_policy/feature_policy_struct_traits.h b/third_party/WebKit/common/feature_policy/feature_policy_struct_traits.h
new file mode 100644
index 0000000..f4d9068
--- /dev/null
+++ b/third_party/WebKit/common/feature_policy/feature_policy_struct_traits.h
@@ -0,0 +1,150 @@
+// 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 THIRD_PARTY_WEBKIT_COMMON_FEATURE_POLICY_FEATURE_POLICY_STRUCT_TRAITS_H_
+#define THIRD_PARTY_WEBKIT_COMMON_FEATURE_POLICY_FEATURE_POLICY_STRUCT_TRAITS_H_
+
+#include <vector>
+
+#include "mojo/public/cpp/bindings/enum_traits.h"
+#include "third_party/WebKit/common/common_export.h"
+#include "third_party/WebKit/common/feature_policy/feature_policy.h"
+#include "third_party/WebKit/common/feature_policy/feature_policy.mojom-shared.h"
+#include "third_party/WebKit/common/feature_policy/feature_policy_feature.h"
+#include "third_party/WebKit/common/sandbox_flags.h"
+
+namespace mojo {
+
+#define STATIC_ASSERT_ENUM(a, b)                            \
+  static_assert(static_cast<int>(a) == static_cast<int>(b), \
+                "mismatching enum : " #a)
+
+// TODO(crbug.com/789818) - Merge these 2 FeaturePolicyFeature enums.
+STATIC_ASSERT_ENUM(::blink::FeaturePolicyFeature::kNotFound,
+                   ::blink::mojom::FeaturePolicyFeature::kNotFound);
+STATIC_ASSERT_ENUM(::blink::FeaturePolicyFeature::kAutoplay,
+                   ::blink::mojom::FeaturePolicyFeature::kAutoplay);
+STATIC_ASSERT_ENUM(::blink::FeaturePolicyFeature::kCamera,
+                   ::blink::mojom::FeaturePolicyFeature::kCamera);
+STATIC_ASSERT_ENUM(::blink::FeaturePolicyFeature::kEncryptedMedia,
+                   ::blink::mojom::FeaturePolicyFeature::kEncryptedMedia);
+STATIC_ASSERT_ENUM(::blink::FeaturePolicyFeature::kFullscreen,
+                   ::blink::mojom::FeaturePolicyFeature::kFullscreen);
+STATIC_ASSERT_ENUM(::blink::FeaturePolicyFeature::kGeolocation,
+                   ::blink::mojom::FeaturePolicyFeature::kGeolocation);
+STATIC_ASSERT_ENUM(::blink::FeaturePolicyFeature::kMicrophone,
+                   ::blink::mojom::FeaturePolicyFeature::kMicrophone);
+STATIC_ASSERT_ENUM(::blink::FeaturePolicyFeature::kMidiFeature,
+                   ::blink::mojom::FeaturePolicyFeature::kMidiFeature);
+STATIC_ASSERT_ENUM(::blink::FeaturePolicyFeature::kPayment,
+                   ::blink::mojom::FeaturePolicyFeature::kPayment);
+STATIC_ASSERT_ENUM(::blink::FeaturePolicyFeature::kSpeaker,
+                   ::blink::mojom::FeaturePolicyFeature::kSpeaker);
+STATIC_ASSERT_ENUM(::blink::FeaturePolicyFeature::kVibrate,
+                   ::blink::mojom::FeaturePolicyFeature::kVibrate);
+STATIC_ASSERT_ENUM(::blink::FeaturePolicyFeature::kDocumentCookie,
+                   ::blink::mojom::FeaturePolicyFeature::kDocumentCookie);
+STATIC_ASSERT_ENUM(::blink::FeaturePolicyFeature::kDocumentDomain,
+                   ::blink::mojom::FeaturePolicyFeature::kDocumentDomain);
+STATIC_ASSERT_ENUM(::blink::FeaturePolicyFeature::kDocumentWrite,
+                   ::blink::mojom::FeaturePolicyFeature::kDocumentWrite);
+STATIC_ASSERT_ENUM(::blink::FeaturePolicyFeature::kSyncScript,
+                   ::blink::mojom::FeaturePolicyFeature::kSyncScript);
+STATIC_ASSERT_ENUM(::blink::FeaturePolicyFeature::kSyncXHR,
+                   ::blink::mojom::FeaturePolicyFeature::kSyncXHR);
+STATIC_ASSERT_ENUM(::blink::FeaturePolicyFeature::kUsb,
+                   ::blink::mojom::FeaturePolicyFeature::kUsb);
+STATIC_ASSERT_ENUM(::blink::FeaturePolicyFeature::kWebVr,
+                   ::blink::mojom::FeaturePolicyFeature::kWebVr);
+
+// TODO(crbug.com/789818) - Merge these 2 WebSandboxFlags enums.
+STATIC_ASSERT_ENUM(::blink::WebSandboxFlags::kNone,
+                   ::blink::mojom::WebSandboxFlags::kNone);
+STATIC_ASSERT_ENUM(::blink::WebSandboxFlags::kNavigation,
+                   ::blink::mojom::WebSandboxFlags::kNavigation);
+STATIC_ASSERT_ENUM(::blink::WebSandboxFlags::kPlugins,
+                   ::blink::mojom::WebSandboxFlags::kPlugins);
+STATIC_ASSERT_ENUM(::blink::WebSandboxFlags::kOrigin,
+                   ::blink::mojom::WebSandboxFlags::kOrigin);
+STATIC_ASSERT_ENUM(::blink::WebSandboxFlags::kForms,
+                   ::blink::mojom::WebSandboxFlags::kForms);
+STATIC_ASSERT_ENUM(::blink::WebSandboxFlags::kScripts,
+                   ::blink::mojom::WebSandboxFlags::kScripts);
+STATIC_ASSERT_ENUM(::blink::WebSandboxFlags::kTopNavigation,
+                   ::blink::mojom::WebSandboxFlags::kTopNavigation);
+STATIC_ASSERT_ENUM(::blink::WebSandboxFlags::kPopups,
+                   ::blink::mojom::WebSandboxFlags::kPopups);
+STATIC_ASSERT_ENUM(::blink::WebSandboxFlags::kAutomaticFeatures,
+                   ::blink::mojom::WebSandboxFlags::kAutomaticFeatures);
+STATIC_ASSERT_ENUM(::blink::WebSandboxFlags::kPointerLock,
+                   ::blink::mojom::WebSandboxFlags::kPointerLock);
+STATIC_ASSERT_ENUM(::blink::WebSandboxFlags::kDocumentDomain,
+                   ::blink::mojom::WebSandboxFlags::kDocumentDomain);
+STATIC_ASSERT_ENUM(::blink::WebSandboxFlags::kOrientationLock,
+                   ::blink::mojom::WebSandboxFlags::kOrientationLock);
+STATIC_ASSERT_ENUM(
+    ::blink::WebSandboxFlags::kPropagatesToAuxiliaryBrowsingContexts,
+    ::blink::mojom::WebSandboxFlags::kPropagatesToAuxiliaryBrowsingContexts);
+STATIC_ASSERT_ENUM(::blink::WebSandboxFlags::kModals,
+                   ::blink::mojom::WebSandboxFlags::kModals);
+STATIC_ASSERT_ENUM(::blink::WebSandboxFlags::kPresentationController,
+                   ::blink::mojom::WebSandboxFlags::kPresentationController);
+STATIC_ASSERT_ENUM(
+    ::blink::WebSandboxFlags::kTopNavigationByUserActivation,
+    ::blink::mojom::WebSandboxFlags::kTopNavigationByUserActivation);
+STATIC_ASSERT_ENUM(::blink::WebSandboxFlags::kDownloads,
+                   ::blink::mojom::WebSandboxFlags::kDownloads);
+
+template <>
+struct BLINK_COMMON_EXPORT
+    EnumTraits<blink::mojom::WebSandboxFlags, blink::WebSandboxFlags> {
+  static blink::mojom::WebSandboxFlags ToMojom(blink::WebSandboxFlags flags) {
+    return static_cast<blink::mojom::WebSandboxFlags>(flags);
+  }
+  static bool FromMojom(blink::mojom::WebSandboxFlags in,
+                        blink::WebSandboxFlags* out) {
+    *out = static_cast<blink::WebSandboxFlags>(in);
+    return true;
+  }
+};
+
+template <>
+struct BLINK_COMMON_EXPORT EnumTraits<blink::mojom::FeaturePolicyFeature,
+                                      blink::FeaturePolicyFeature> {
+  static blink::mojom::FeaturePolicyFeature ToMojom(
+      blink::FeaturePolicyFeature feature) {
+    return static_cast<blink::mojom::FeaturePolicyFeature>(feature);
+  }
+  static bool FromMojom(blink::mojom::FeaturePolicyFeature in,
+                        blink::FeaturePolicyFeature* out) {
+    *out = static_cast<blink::FeaturePolicyFeature>(in);
+    return true;
+  }
+};
+
+template <>
+class BLINK_COMMON_EXPORT
+    StructTraits<blink::mojom::ParsedFeaturePolicyDeclarationDataView,
+                 blink::ParsedFeaturePolicyDeclaration> {
+ public:
+  static blink::FeaturePolicyFeature feature(
+      const blink::ParsedFeaturePolicyDeclaration& policy) {
+    return policy.feature;
+  }
+  static bool matches_all_origins(
+      const blink::ParsedFeaturePolicyDeclaration& policy) {
+    return policy.matches_all_origins;
+  }
+  static const std::vector<url::Origin>& origins(
+      const blink::ParsedFeaturePolicyDeclaration& policy) {
+    return policy.origins;
+  }
+
+  static bool Read(blink::mojom::ParsedFeaturePolicyDeclarationDataView in,
+                   blink::ParsedFeaturePolicyDeclaration* out);
+};
+
+}  // namespace mojo
+
+#endif  // THIRD_PARTY_WEBKIT_COMMON_FEATURE_POLICY_FEATURE_POLICY_STRUCT_TRAITS_H_
diff --git a/third_party/WebKit/common/typemaps.gni b/third_party/WebKit/common/typemaps.gni
index 88e1a26..015eb9f 100644
--- a/third_party/WebKit/common/typemaps.gni
+++ b/third_party/WebKit/common/typemaps.gni
@@ -5,4 +5,5 @@
 typemaps = [
   "//third_party/WebKit/common/message_port/cloneable_message.typemap",
   "//third_party/WebKit/common/message_port/transferable_message.typemap",
+  "//third_party/WebKit/common/feature_policy/feature_policy.typemap",
 ]
diff --git a/third_party/WebKit/public/BUILD.gn b/third_party/WebKit/public/BUILD.gn
index 45dbda7b..660acd8 100644
--- a/third_party/WebKit/public/BUILD.gn
+++ b/third_party/WebKit/public/BUILD.gn
@@ -516,6 +516,7 @@
     "web/WebFrameSerializerCacheControlPolicy.h",
     "web/WebFrameSerializerClient.h",
     "web/WebFrameWidget.h",
+    "web/WebGlobalObjectReusePolicy.h",
     "web/WebHeap.h",
     "web/WebHelperPlugin.h",
     "web/WebHistoryCommitType.h",
diff --git a/third_party/WebKit/public/platform/Platform.h b/third_party/WebKit/public/platform/Platform.h
index 09c2e15..17c9687 100644
--- a/third_party/WebKit/public/platform/Platform.h
+++ b/third_party/WebKit/public/platform/Platform.h
@@ -685,9 +685,10 @@
   // with the current usage and quota information for the partition. When
   // an error occurs WebStorageQuotaCallbacks::DidFail is called with an
   // error code.
-  virtual void QueryStorageUsageAndQuota(const WebURL& storage_partition,
-                                         WebStorageQuotaType,
-                                         WebStorageQuotaCallbacks) {}
+  virtual void QueryStorageUsageAndQuota(
+      const WebSecurityOrigin& storage_partition,
+      WebStorageQuotaType,
+      WebStorageQuotaCallbacks) {}
 
   // WebDatabase --------------------------------------------------------
 
diff --git a/third_party/WebKit/public/platform/modules/webauth/authenticator.mojom b/third_party/WebKit/public/platform/modules/webauth/authenticator.mojom
index 3cc5787..f7ab3b1 100644
--- a/third_party/WebKit/public/platform/modules/webauth/authenticator.mojom
+++ b/third_party/WebKit/public/platform/modules/webauth/authenticator.mojom
@@ -15,10 +15,11 @@
 enum AuthenticatorStatus {
   SUCCESS,
   CANCELLED,
-  UNKNOWN_ERROR,
+  PENDING_REQUEST,
   NOT_ALLOWED_ERROR,
   NOT_SUPPORTED_ERROR,
   SECURITY_ERROR,
+  UNKNOWN_ERROR,
   NOT_IMPLEMENTED,
 };
 
diff --git a/third_party/WebKit/public/platform/web_feature.mojom b/third_party/WebKit/public/platform/web_feature.mojom
index 8019ab8..9b650fb 100644
--- a/third_party/WebKit/public/platform/web_feature.mojom
+++ b/third_party/WebKit/public/platform/web_feature.mojom
@@ -1782,6 +1782,7 @@
   kAudioWorkletAddModule = 2261,
   kAudioWorkletGlobalScopeRegisterProcessor = 2262,
   kAudioWorkletNodeConstructor = 2263,
+  kHTMLMediaElementEmptyLoadWithFutureData = 2264,
 
   // Add new features immediately above this line. Don't change assigned
   // numbers of any item, and don't reuse removed slots.
diff --git a/third_party/WebKit/public/web/WebFrameClient.h b/third_party/WebKit/public/web/WebFrameClient.h
index 0b3750e2..e61816e 100644
--- a/third_party/WebKit/public/web/WebFrameClient.h
+++ b/third_party/WebKit/public/web/WebFrameClient.h
@@ -40,6 +40,7 @@
 #include "WebFormElement.h"
 #include "WebFrame.h"
 #include "WebFrameOwnerProperties.h"
+#include "WebGlobalObjectReusePolicy.h"
 #include "WebHistoryCommitType.h"
 #include "WebHistoryItem.h"
 #include "WebIconURL.h"
@@ -417,7 +418,8 @@
   // response body has been received, and the encoding of the response
   // body is known.
   virtual void DidCommitProvisionalLoad(const WebHistoryItem&,
-                                        WebHistoryCommitType) {}
+                                        WebHistoryCommitType,
+                                        WebGlobalObjectReusePolicy) {}
 
   // The frame's document has just been initialized.
   virtual void DidCreateNewDocument() {}
diff --git a/third_party/WebKit/public/web/WebGlobalObjectReusePolicy.h b/third_party/WebKit/public/web/WebGlobalObjectReusePolicy.h
new file mode 100644
index 0000000..475ca83b
--- /dev/null
+++ b/third_party/WebKit/public/web/WebGlobalObjectReusePolicy.h
@@ -0,0 +1,22 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef WebGlobalObjectReusePolicy_h
+#define WebGlobalObjectReusePolicy_h
+
+namespace blink {
+
+// Indicates whether the global object (i.e. Window instance) associated with
+// the previous document in a browsing context was replaced or reused for the
+// new Document corresponding to the just-committed navigation; effective in the
+// main world and all isolated worlds. WindowProxies are not affected.
+//
+// TODO(dcheng): Investigate removing the need for this by moving the
+// InterfaceProvider plumbing from DidCommitProvisionalLoad to
+// RenderFrameImpl::CommitNavigation.
+enum class WebGlobalObjectReusePolicy { kCreateNew, kUseExisting };
+
+}  // namespace blink
+
+#endif
diff --git a/third_party/closure_compiler/externs/developer_private.js b/third_party/closure_compiler/externs/developer_private.js
index 92baf8f3..9944e57 100644
--- a/third_party/closure_compiler/externs/developer_private.js
+++ b/third_party/closure_compiler/externs/developer_private.js
@@ -414,7 +414,8 @@
 
 /**
  * @typedef {{
- *   failQuietly: (boolean|undefined)
+ *   failQuietly: (boolean|undefined),
+ *   populateErrorForUnpacked: (boolean|undefined)
  * }}
  * @see https://developer.chrome.com/extensions/developerPrivate#type-ReloadOptions
  */
@@ -643,7 +644,8 @@
  * @param {string} extensionId The id of the extension to reload.
  * @param {!chrome.developerPrivate.ReloadOptions=} options Additional
  *     configuration parameters.
- * @param {function():void=} callback
+ * @param {function((!chrome.developerPrivate.LoadError|undefined)):void=}
+ *     callback
  * @see https://developer.chrome.com/extensions/developerPrivate#method-reload
  */
 chrome.developerPrivate.reload = function(extensionId, options, callback) {};
diff --git a/third_party/crashpad/README.chromium b/third_party/crashpad/README.chromium
index e1f39d0..d88b7b4f 100644
--- a/third_party/crashpad/README.chromium
+++ b/third_party/crashpad/README.chromium
@@ -36,3 +36,6 @@
 
 Local Modifications:
  - codereview.settings has been excluded.
+ - fix two -Wsign-compare warnings.
+ - ProcessInfo.OtherProcess disabled due to flake, investigation pending.
+   See https://crbug.com/792619.
diff --git a/third_party/crashpad/crashpad/minidump/minidump_file_writer.cc b/third_party/crashpad/crashpad/minidump/minidump_file_writer.cc
index b4f0a62..7226545 100644
--- a/third_party/crashpad/crashpad/minidump/minidump_file_writer.cc
+++ b/third_party/crashpad/crashpad/minidump/minidump_file_writer.cc
@@ -59,7 +59,7 @@
   DCHECK_EQ(state(), kStateMutable);
   DCHECK_EQ(header_.Signature, 0u);
   DCHECK_EQ(header_.TimeDateStamp, 0u);
-  DCHECK_EQ(header_.Flags, MiniDumpNormal);
+  DCHECK_EQ(static_cast<MINIDUMP_TYPE>(header_.Flags), MiniDumpNormal);
   DCHECK(streams_.empty());
 
   // This time is truncated to an integer number of seconds, not rounded, for
diff --git a/third_party/crashpad/crashpad/minidump/test/minidump_file_writer_test_util.cc b/third_party/crashpad/crashpad/minidump/test/minidump_file_writer_test_util.cc
index f372212b..aae357d 100644
--- a/third_party/crashpad/crashpad/minidump/test/minidump_file_writer_test_util.cc
+++ b/third_party/crashpad/crashpad/minidump/test/minidump_file_writer_test_util.cc
@@ -52,7 +52,7 @@
   ASSERT_EQ(header->StreamDirectoryRva, streams ? sizeof(MINIDUMP_HEADER) : 0u);
   EXPECT_EQ(header->CheckSum, 0u);
   EXPECT_EQ(header->TimeDateStamp, timestamp);
-  EXPECT_EQ(header->Flags, MiniDumpNormal);
+  EXPECT_EQ(static_cast<MINIDUMP_TYPE>(header->Flags), MiniDumpNormal);
 }
 
 }  // namespace test
diff --git a/third_party/crashpad/crashpad/util/win/process_info_test.cc b/third_party/crashpad/crashpad/util/win/process_info_test.cc
index 709536b..95d0cd45 100644
--- a/third_party/crashpad/crashpad/util/win/process_info_test.cc
+++ b/third_party/crashpad/crashpad/util/win/process_info_test.cc
@@ -188,7 +188,8 @@
   VerifyAddressInInCodePage(process_info, code_address);
 }
 
-TEST(ProcessInfo, OtherProcess) {
+// TODO(scottmg): https://crbug.com/792619.
+TEST(ProcessInfo, DISABLED_OtherProcess) {
   TestOtherProcess(TestPaths::Architecture::kDefault);
 }
 
diff --git a/third_party/errorprone/BUILD.gn b/third_party/errorprone/BUILD.gn
index 385b7f7a..3b7ee58 100644
--- a/third_party/errorprone/BUILD.gn
+++ b/third_party/errorprone/BUILD.gn
@@ -5,8 +5,14 @@
 import("//build/config/android/rules.gni")
 
 if (current_toolchain == default_toolchain) {
-  java_prebuilt("errorprone_java") {
+  java_library("errorprone_java") {
     jar_path = "lib/error_prone_ant-2.1.2.jar"
+  }
+
+  java_binary("errorprone") {
+    deps = [
+      ":errorprone_java",
+    ]
     main_class = "com.google.errorprone.ErrorProneCompiler"
     bootclasspath = "$root_build_dir/lib.java/third_party/errorprone/error_prone_ant-2.1.2.jar"
   }
diff --git a/tools/android/errorprone_plugin/BUILD.gn b/tools/android/errorprone_plugin/BUILD.gn
index b15ff20..54c9376 100644
--- a/tools/android/errorprone_plugin/BUILD.gn
+++ b/tools/android/errorprone_plugin/BUILD.gn
@@ -16,8 +16,12 @@
   # Necessary to avoid dependency cycle
   enable_errorprone = false
 
+  # TODO(agrieve): Make it so that you don't need to specify the full classpath
+  #     of annotation processors.
   deps = [
+    "//third_party/auto:auto_common_java",
     "//third_party/auto:auto_service_java",
     "//third_party/errorprone:errorprone_java",
+    "//third_party/guava:guava_java",
   ]
 }
diff --git a/tools/determinism/deterministic_build_whitelist.pyl b/tools/determinism/deterministic_build_whitelist.pyl
index 8a4c4e3..dad8a92 100644
--- a/tools/determinism/deterministic_build_whitelist.pyl
+++ b/tools/determinism/deterministic_build_whitelist.pyl
@@ -118,7 +118,6 @@
     'message_center_unittests',
     'midi_unittests',
     'mojo_common_unittests',
-    'mojo_js_unittests',
     'mojo_public_bindings_unittests',
     'mojo_public_system_unittests',
     'mojo_system_unittests',
@@ -273,7 +272,6 @@
     'midi_unittests.exe',
     'mini_installer.exe',
     'mksnapshot.exe',
-    'mojo_js_unittests.exe',
     'mojo_message_pipe_perftests.exe',
     'mojo_public_bindings_perftests.exe',
     'mojo_public_bindings_unittests.exe',
diff --git a/tools/media_engagement_preload/OWNERS b/tools/media_engagement_preload/OWNERS
deleted file mode 100644
index 9c383a5..0000000
--- a/tools/media_engagement_preload/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-beccahughes@chromium.org
-mlamouri@chromium.org
-
-# COMPONENT: Internals>Media
diff --git a/tools/media_engagement_preload/PRESUBMIT.py b/tools/media_engagement_preload/PRESUBMIT.py
deleted file mode 100644
index df19c77f..0000000
--- a/tools/media_engagement_preload/PRESUBMIT.py
+++ /dev/null
@@ -1,32 +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.
-
-
-"""Chromium presubmit script for src/tools/media_engagement_preload."""
-
-
-def _RunMakeDafsaTests(input_api, output_api):
-  """Runs unittest for make_dafsa if any related file has been modified."""
-  files = ('tools/media_engagement_preload/make_dafsa.py',
-           'tools/media_engagement_preload/make_dafsa_unittest.py')
-  if not any(f in input_api.LocalPaths() for f in files):
-    return []
-  test_path = input_api.os_path.join(input_api.PresubmitLocalPath(),
-                                     'make_dafsa_unittest.py')
-  cmd_name = 'make_dafsa_unittest'
-  cmd = [input_api.python_executable, test_path]
-  test_cmd = input_api.Command(
-    name=cmd_name,
-    cmd=cmd,
-    kwargs={},
-    message=output_api.PresubmitPromptWarning)
-  return input_api.RunTests([test_cmd])
-
-
-def CheckChangeOnUpload(input_api, output_api):
-  return _RunMakeDafsaTests(input_api, output_api)
-
-
-def CheckChangeOnCommit(input_api, output_api):
-  return _RunMakeDafsaTests(input_api, output_api)
diff --git a/tools/media_engagement_preload/build.sh b/tools/media_engagement_preload/build.sh
deleted file mode 100644
index f3f6ff1..0000000
--- a/tools/media_engagement_preload/build.sh
+++ /dev/null
@@ -1,6 +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.
-protoc --python_out . \
-  ../../chrome/browser/media/media_engagement_preload.proto \
-  --proto_path ../../chrome/browser/media
diff --git a/tools/media_engagement_preload/make_dafsa.py b/tools/media_engagement_preload/make_dafsa.py
deleted file mode 100755
index 2dcb615d..0000000
--- a/tools/media_engagement_preload/make_dafsa.py
+++ /dev/null
@@ -1,456 +0,0 @@
-#!/usr/bin/env python
-# Copyright 2017 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-import array
-import json
-
-import media_engagement_preload_pb2
-
-"""
-A Deterministic acyclic finite state automaton (DAFSA) is a compact
-representation of an unordered word list (dictionary).
-
-http://en.wikipedia.org/wiki/Deterministic_acyclic_finite_state_automaton
-
-This python program converts a list of strings to a byte array in C++.
-This python program fetches strings and return values from a gperf file
-and generates a C++ file with a byte array representing graph that can be
-used as a memory efficient replacement for the perfect hash table.
-
-The input strings are assumed to consist of printable 7-bit ASCII characters
-and the return values are assumed to be one digit integers.
-
-In this program a DAFSA is a diamond shaped graph starting at a common
-source node and ending at a common sink node. All internal nodes contain
-a label and each word is represented by the labels in one path from
-the source node to the sink node.
-
-The following python represention is used for nodes:
-
-  Source node: [ children ]
-  Internal node: (label, [ children ])
-  Sink node: None
-
-The graph is first compressed by prefixes like a trie. In the next step
-suffixes are compressed so that the graph gets diamond shaped. Finally
-one to one linked nodes are replaced by nodes with the labels joined.
-
-The order of the operations is crucial since lookups will be performed
-starting from the source with no backtracking. Thus a node must have at
-most one child with a label starting by the same character. The output
-is also arranged so that all jumps are to increasing addresses, thus forward
-in memory.
-
-The generated output has suffix free decoding so that the sign of leading
-bits in a link (a reference to a child node) indicate if it has a size of one,
-two or three bytes and if it is the last outgoing link from the actual node.
-A node label is terminated by a byte with the leading bit set.
-
-The generated byte array can described by the following BNF:
-
-<byte> ::= < 8-bit value in range [0x00-0xFF] >
-
-<char> ::= < printable 7-bit ASCII character, byte in range [0x20-0x7F] >
-<end_char> ::= < char + 0x80, byte in range [0xA0-0xFF] >
-<return value> ::= < value + 0x80, byte in range [0x80-0x8F] >
-
-<offset1> ::= < byte in range [0x00-0x3F] >
-<offset2> ::= < byte in range [0x40-0x5F] >
-<offset3> ::= < byte in range [0x60-0x7F] >
-
-<end_offset1> ::= < byte in range [0x80-0xBF] >
-<end_offset2> ::= < byte in range [0xC0-0xDF] >
-<end_offset3> ::= < byte in range [0xE0-0xFF] >
-
-<prefix> ::= <char>
-
-<label> ::= <end_char>
-          | <char> <label>
-
-<end_label> ::= <return_value>
-          | <char> <end_label>
-
-<offset> ::= <offset1>
-           | <offset2> <byte>
-           | <offset3> <byte> <byte>
-
-<end_offset> ::= <end_offset1>
-               | <end_offset2> <byte>
-               | <end_offset3> <byte> <byte>
-
-<offsets> ::= <end_offset>
-            | <offset> <offsets>
-
-<source> ::= <offsets>
-
-<node> ::= <label> <offsets>
-         | <prefix> <node>
-         | <end_label>
-
-<dafsa> ::= <source>
-          | <dafsa> <node>
-
-Decoding:
-
-<char> -> printable 7-bit ASCII character
-<end_char> & 0x7F -> printable 7-bit ASCII character
-<return value> & 0x0F -> integer
-<offset1 & 0x3F> -> integer
-((<offset2> & 0x1F>) << 8) + <byte> -> integer
-((<offset3> & 0x1F>) << 16) + (<byte> << 8) + <byte> -> integer
-
-end_offset1, end_offset2 and and_offset3 are decoded same as offset1,
-offset2 and offset3 respectively.
-
-The first offset in a list of offsets is the distance in bytes between the
-offset itself and the first child node. Subsequent offsets are the distance
-between previous child node and next child node. Thus each offset links a node
-to a child node. The distance is always counted between start addresses, i.e.
-first byte in decoded offset or first byte in child node.
-
-Example 1:
-
-%%
-aa, 1
-a, 2
-%%
-
-The input is first parsed to a list of words:
-["aa1", "a2"]
-
-A fully expanded graph is created from the words:
-source = [node1, node4]
-node1 = ("a", [node2])
-node2 = ("a", [node3])
-node3 = ("\x01", [sink])
-node4 = ("a", [node5])
-node5 = ("\x02", [sink])
-sink = None
-
-Compression results in the following graph:
-source = [node1]
-node1 = ("a", [node2, node3])
-node2 = ("\x02", [sink])
-node3 = ("a\x01", [sink])
-sink = None
-
-A C++ representation of the compressed graph is generated:
-
-const unsigned char dafsa[7] = {
-  0x81, 0xE1, 0x02, 0x81, 0x82, 0x61, 0x81,
-};
-
-The bytes in the generated array has the following meaning:
-
- 0: 0x81 <end_offset1>  child at position 0 + (0x81 & 0x3F) -> jump to 1
-
- 1: 0xE1 <end_char>     label character (0xE1 & 0x7F) -> match "a"
- 2: 0x02 <offset1>      child at position 2 + (0x02 & 0x3F) -> jump to 4
-
- 3: 0x81 <end_offset1>  child at position 4 + (0x81 & 0x3F) -> jump to 5
- 4: 0x82 <return_value> 0x82 & 0x0F -> return 2
-
- 5: 0x61 <char>         label character 0x61 -> match "a"
- 6: 0x81 <return_value> 0x81 & 0x0F -> return 1
-
-Example 2:
-
-%%
-aa, 1
-bbb, 2
-baa, 1
-%%
-
-The input is first parsed to a list of words:
-["aa1", "bbb2", "baa1"]
-
-Compression results in the following graph:
-source = [node1, node2]
-node1 = ("b", [node2, node3])
-node2 = ("aa\x01", [sink])
-node3 = ("bb\x02", [sink])
-sink = None
-
-A C++ representation of the compressed graph is generated:
-
-const unsigned char dafsa[11] = {
-  0x02, 0x83, 0xE2, 0x02, 0x83, 0x61, 0x61, 0x81, 0x62, 0x62, 0x82,
-};
-
-The bytes in the generated array has the following meaning:
-
- 0: 0x02 <offset1>      child at position 0 + (0x02 & 0x3F) -> jump to 2
- 1: 0x83 <end_offset1>  child at position 2 + (0x83 & 0x3F) -> jump to 5
-
- 2: 0xE2 <end_char>     label character (0xE2 & 0x7F) -> match "b"
- 3: 0x02 <offset1>      child at position 3 + (0x02 & 0x3F) -> jump to 5
- 4: 0x83 <end_offset1>  child at position 5 + (0x83 & 0x3F) -> jump to 8
-
- 5: 0x61 <char>         label character 0x61 -> match "a"
- 6: 0x61 <char>         label character 0x61 -> match "a"
- 7: 0x81 <return_value> 0x81 & 0x0F -> return 1
-
- 8: 0x62 <char>         label character 0x62 -> match "b"
- 9: 0x62 <char>         label character 0x62 -> match "b"
-10: 0x82 <return_value> 0x82 & 0x0F -> return 2
-"""
-
-import sys
-
-class InputError(Exception):
-  """Exception raised for errors in the input file."""
-
-
-def to_dafsa(words):
-  """Generates a DAFSA from a word list and returns the source node.
-
-  Each word is split into characters so that each character is represented by
-  a unique node. It is assumed the word list is not empty.
-  """
-  if not words:
-    raise InputError('The origin list must not be empty')
-  def ToNodes(word):
-    """Split words into characters"""
-    if not 0x1F < ord(word[0]) < 0x80:
-      raise InputError('Origins must be printable 7-bit ASCII')
-    if len(word) == 1:
-      return chr(ord(word[0]) & 0x0F), [None]
-    return word[0], [ToNodes(word[1:])]
-  return [ToNodes(word) for word in words]
-
-
-def to_words(node):
-  """Generates a word list from all paths starting from an internal node."""
-  if not node:
-    return ['']
-  return [(node[0] + word) for child in node[1] for word in to_words(child)]
-
-
-def reverse(dafsa):
-  """Generates a new DAFSA that is reversed, so that the old sink node becomes
-  the new source node.
-  """
-  sink = []
-  nodemap = {}
-
-  def dfs(node, parent):
-    """Creates reverse nodes.
-
-    A new reverse node will be created for each old node. The new node will
-    get a reversed label and the parents of the old node as children.
-    """
-    if not node:
-      sink.append(parent)
-    elif id(node) not in nodemap:
-      nodemap[id(node)] = (node[0][::-1], [parent])
-      for child in node[1]:
-        dfs(child, nodemap[id(node)])
-    else:
-      nodemap[id(node)][1].append(parent)
-
-  for node in dafsa:
-    dfs(node, None)
-  return sink
-
-
-def join_labels(dafsa):
-  """Generates a new DAFSA where internal nodes are merged if there is a one to
-  one connection.
-  """
-  parentcount = { id(None): 2 }
-  nodemap = { id(None): None }
-
-  def count_parents(node):
-    """Count incoming references"""
-    if id(node) in parentcount:
-      parentcount[id(node)] += 1
-    else:
-      parentcount[id(node)] = 1
-      for child in node[1]:
-        count_parents(child)
-
-  def join(node):
-    """Create new nodes"""
-    if id(node) not in nodemap:
-      children = [join(child) for child in node[1]]
-      if len(children) == 1 and parentcount[id(node[1][0])] == 1:
-        child = children[0]
-        nodemap[id(node)] = (node[0] + child[0], child[1])
-      else:
-        nodemap[id(node)] = (node[0], children)
-    return nodemap[id(node)]
-
-  for node in dafsa:
-    count_parents(node)
-  return [join(node) for node in dafsa]
-
-
-def join_suffixes(dafsa):
-  """Generates a new DAFSA where nodes that represent the same word lists
-  towards the sink are merged.
-  """
-  nodemap = { frozenset(('',)): None }
-
-  def join(node):
-    """Returns a macthing node. A new node is created if no matching node
-    exists. The graph is accessed in dfs order.
-    """
-    suffixes = frozenset(to_words(node))
-    if suffixes not in nodemap:
-      nodemap[suffixes] = (node[0], [join(child) for child in node[1]])
-    return nodemap[suffixes]
-
-  return [join(node) for node in dafsa]
-
-
-def top_sort(dafsa):
-  """Generates list of nodes in topological sort order."""
-  incoming = {}
-
-  def count_incoming(node):
-    """Counts incoming references."""
-    if node:
-      if id(node) not in incoming:
-        incoming[id(node)] = 1
-        for child in node[1]:
-          count_incoming(child)
-      else:
-        incoming[id(node)] += 1
-
-  for node in dafsa:
-    count_incoming(node)
-
-  for node in dafsa:
-    incoming[id(node)] -= 1
-
-  waiting = [node for node in dafsa if incoming[id(node)] == 0]
-  nodes = []
-
-  while waiting:
-    node = waiting.pop()
-    assert incoming[id(node)] == 0
-    nodes.append(node)
-    for child in node[1]:
-      if child:
-        incoming[id(child)] -= 1
-        if incoming[id(child)] == 0:
-          waiting.append(child)
-  return nodes
-
-
-def encode_links(children, offsets, current):
-  """Encodes a list of children as one, two or three byte offsets."""
-  if not children[0]:
-    # This is an <end_label> node and no links follow such nodes
-    assert len(children) == 1
-    return []
-  guess = 3 * len(children)
-  assert children
-  children = sorted(children, key = lambda x: -offsets[id(x)])
-  while True:
-    offset = current + guess
-    buf = []
-    for child in children:
-      last = len(buf)
-      distance = offset - offsets[id(child)]
-      assert distance > 0 and distance < (1 << 21)
-
-      if distance < (1 << 6):
-        # A 6-bit offset: "s0xxxxxx"
-        buf.append(distance)
-      elif distance < (1 << 13):
-        # A 13-bit offset: "s10xxxxxxxxxxxxx"
-        buf.append(0x40 | (distance >> 8))
-        buf.append(distance & 0xFF)
-      else:
-        # A 21-bit offset: "s11xxxxxxxxxxxxxxxxxxxxx"
-        buf.append(0x60 | (distance >> 16))
-        buf.append((distance >> 8) & 0xFF)
-        buf.append(distance & 0xFF)
-      # Distance in first link is relative to following record.
-      # Distance in other links are relative to previous link.
-      offset -= distance
-    if len(buf) == guess:
-      break
-    guess = len(buf)
-  # Set most significant bit to mark end of links in this node.
-  buf[last] |= (1 << 7)
-  buf.reverse()
-  return buf
-
-
-def encode_prefix(label):
-  """Encodes a node label as a list of bytes without a trailing high byte.
-
-  This method encodes a node if there is exactly one child  and the
-  child follows immidiately after so that no jump is needed. This label
-  will then be a prefix to the label in the child node.
-  """
-  assert label
-  return [ord(c) for c in reversed(label)]
-
-
-def encode_label(label):
-  """Encodes a node label as a list of bytes with a trailing high byte >0x80.
-  """
-  buf = encode_prefix(label)
-  # Set most significant bit to mark end of label in this node.
-  buf[0] |= (1 << 7)
-  return buf
-
-
-def encode(dafsa):
-  """Encodes a DAFSA to a list of bytes"""
-  output = []
-  offsets = {}
-
-  for node in reversed(top_sort(dafsa)):
-    if (len(node[1]) == 1 and node[1][0] and
-        (offsets[id(node[1][0])] == len(output))):
-      output.extend(encode_prefix(node[0]))
-    else:
-      output.extend(encode_links(node[1], offsets, len(output)))
-      output.extend(encode_label(node[0]))
-    offsets[id(node)] = len(output)
-
-  output.extend(encode_links(dafsa, offsets, len(output)))
-  output.reverse()
-  return output
-
-
-def to_proto(data):
-  """Generates protobuf from a list of encoded bytes."""
-  message = media_engagement_preload_pb2.PreloadedData()
-  message.dafsa = array.array('B', data).tostring()
-  return message.SerializeToString()
-
-
-def words_to_proto(words):
-  """Generates protobuf from a word list"""
-  dafsa = to_dafsa(words)
-  for fun in (reverse, join_suffixes, reverse, join_suffixes, join_labels):
-    dafsa = fun(dafsa)
-  return to_proto(encode(dafsa))
-
-
-def parse_json(infile):
-  """Parses the JSON input file and appends a 0."""
-  try:
-    return [entry.encode('ascii', 'ignore') + "0"
-            for entry in json.loads(infile)]
-  except ValueError:
-    raise InputError('Failed to parse JSON.')
-
-def main():
-  if len(sys.argv) != 3:
-    print('usage: %s infile outfile' % sys.argv[0])
-    return 1
-  with open(sys.argv[1], 'r') as infile, open(sys.argv[2], 'wb') as outfile:
-    outfile.write(words_to_proto(parse_json(infile.read())))
-  return 0
-
-
-if __name__ == '__main__':
-  sys.exit(main())
diff --git a/tools/media_engagement_preload/make_dafsa_unittest.py b/tools/media_engagement_preload/make_dafsa_unittest.py
deleted file mode 100755
index 18b35e2..0000000
--- a/tools/media_engagement_preload/make_dafsa_unittest.py
+++ /dev/null
@@ -1,700 +0,0 @@
-#!/usr/bin/env python
-# Copyright 2017 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-
-import sys
-import unittest
-import make_dafsa
-
-
-class ToDafsaTest(unittest.TestCase):
-  def testEmptyInput(self):
-    """Tests exception is thrown at empty input."""
-    words = ()
-    self.assertRaises(make_dafsa.InputError, make_dafsa.to_dafsa, words)
-
-  def testNonASCII(self):
-    """Tests exception is thrown if illegal characters are used."""
-    words1 = ( chr(0x1F) + 'a1', )
-    self.assertRaises(make_dafsa.InputError, make_dafsa.to_dafsa, words1)
-
-    words2 = ( 'a' + chr(0x1F) + '1', )
-    self.assertRaises(make_dafsa.InputError, make_dafsa.to_dafsa, words2)
-
-    words3 = ( chr(0x80) + 'a1', )
-    self.assertRaises(make_dafsa.InputError, make_dafsa.to_dafsa, words3)
-
-    words4 = ( 'a' + chr(0x80) + '1', )
-    self.assertRaises(make_dafsa.InputError, make_dafsa.to_dafsa, words4)
-
-  def testChar(self):
-    """Tests a DAFSA can be created from a single character domain name."""
-    words = [ 'a0' ]
-    node2 = ( chr(0), [ None ] )
-    node1 = ( 'a', [ node2 ] )
-    source = [ node1 ]
-    self.assertEqual(make_dafsa.to_dafsa(words), source)
-
-  def testChars(self):
-    """Tests a DAFSA can be created from a multi character domain name."""
-    words = [ 'ab0' ]
-    node3 = ( chr(0), [ None ] )
-    node2 = ( 'b', [ node3 ] )
-    node1 = ( 'a', [ node2 ] )
-    source = [ node1 ]
-    self.assertEqual(make_dafsa.to_dafsa(words), source)
-
-  def testWords(self):
-    """Tests a DAFSA can be created from a sequence of domain names."""
-    words = [ 'a0', 'b1' ]
-    node4 = ( chr(1), [ None ] )
-    node3 = ( 'b', [ node4 ] )
-    node2 = ( chr(0), [ None ] )
-    node1 = ( 'a', [ node2 ] )
-    source = [ node1, node3 ]
-    self.assertEqual(make_dafsa.to_dafsa(words), source)
-
-
-class ToWordsTest(unittest.TestCase):
-  def testSink(self):
-    """Tests the sink is exapnded to a list with an empty string."""
-    node1 = None
-    words = [ '' ]
-    self.assertEqual(make_dafsa.to_words(node1), words)
-
-  def testSingleNode(self):
-    """Tests a single node is expanded to a list with the label string."""
-
-    # 'ab' -> [ 'ab' ]
-
-    node1 = ( 'ab', [ None ] )
-    words = [ 'ab' ]
-    self.assertEqual(make_dafsa.to_words(node1), words)
-
-  def testChain(self):
-    """Tests a sequence of nodes are preoperly expanded."""
-
-    # 'ab' -> 'cd' => [ 'abcd' ]
-
-    node2 = ( 'cd', [ None ] )
-    node1 = ( 'ab', [ node2 ] )
-    words = [ 'abcd' ]
-    self.assertEqual(make_dafsa.to_words(node1), words)
-
-  def testInnerTerminator(self):
-    """Tests a sequence with an inner terminator is expanded to two strings."""
-
-    # 'a' -> 'b'
-    #   \       => [ 'ab', 'a' ]
-    #  {sink}
-
-    node2 = ( 'b', [ None ] )
-    node1 = ( 'a', [ node2, None ] )
-    words = [ 'ab', 'a' ]
-    self.assertEqual(make_dafsa.to_words(node1), words)
-
-  def testDiamond(self):
-    """Tests a diamond can be expanded to a word list."""
-
-    #   'cd'
-    #   /  \
-    # 'ab' 'gh'
-    #   \  /
-    #   'ef'
-
-    node4 = ( 'gh', [ None ] )
-    node3 = ( 'ef', [ node4 ] )
-    node2 = ( 'cd', [ node4 ] )
-    node1 = ( 'ab', [ node2, node3 ] )
-    words = [ 'abcdgh', 'abefgh' ]
-    self.assertEqual(make_dafsa.to_words(node1), words)
-
-
-class JoinLabelsTest(unittest.TestCase):
-  def testLabel(self):
-    """Tests a single label passes unchanged."""
-
-    # 'a'  =>  'a'
-
-    node1 = ( 'a', [ None ] )
-    source = [ node1 ]
-    self.assertEqual(make_dafsa.join_labels(source), source)
-
-  def testInnerTerminator(self):
-    """Tests a sequence with an inner terminator passes unchanged."""
-
-    # 'a' -> 'b'    'a' -> 'b'
-    #   \       =>    \
-    #  {sink}        {sink}
-
-    node2 = ( 'b', [ None ] )
-    node1 = ( 'a', [ node2, None ] )
-    source = [ node1 ]
-    self.assertEqual(make_dafsa.join_labels(source), source)
-
-  def testLabels(self):
-    """Tests a sequence of labels can be joined."""
-
-    # 'a' -> 'b'  =>  'ab'
-
-    node2 = ( 'b', [ None ] )
-    node1 = ( 'a', [ node2 ] )
-    source1 = [ node1 ]
-    node3 = ( 'ab', [ None ] )
-    source2 = [ node3 ]
-    self.assertEqual(make_dafsa.join_labels(source1), source2)
-
-  def testCompositeLabels(self):
-    """Tests a sequence of multi character labels can be joined."""
-
-    # 'ab' -> 'cd'  =>  'abcd'
-
-    node2 = ( 'cd', [ None ] )
-    node1 = ( 'ab', [ node2 ] )
-    source1 = [ node1 ]
-    node3 = ( 'abcd', [ None ] )
-    source2 = [ node3 ]
-    self.assertEqual(make_dafsa.join_labels(source1), source2)
-
-  def testAtomicTrie(self):
-    """Tests a trie formed DAFSA with atomic labels passes unchanged."""
-
-    #   'b'       'b'
-    #   /         /
-    # 'a'   =>  'a'
-    #   \         \
-    #   'c'       'c'
-
-    node3 = ( 'c', [ None ] )
-    node2 = ( 'b', [ None ] )
-    node1 = ( 'a', [ node2, node3 ] )
-    source = [ node1 ]
-    self.assertEqual(make_dafsa.join_labels(source), source)
-
-  def testReverseAtomicTrie(self):
-    """Tests a reverse trie formed DAFSA with atomic labels passes unchanged."""
-
-    # 'a'        'a'
-    #   \          \
-    #   'c'  =>    'c'
-    #   /          /
-    # 'b'        'b'
-
-    node3 = ( 'c', [ None ] )
-    node2 = ( 'b', [ node3 ] )
-    node1 = ( 'a', [ node3 ] )
-    source = [ node1, node2 ]
-    self.assertEqual(make_dafsa.join_labels(source), source)
-
-  def testChainedTrie(self):
-    """Tests a trie formed DAFSA with chained labels can be joined."""
-
-    #          'c' -> 'd'         'cd'
-    #          /                  /
-    # 'a' -> 'b'           =>  'ab'
-    #          \                  \
-    #          'e' -> 'f'         'ef'
-
-    node6 = ( 'f', [ None ] )
-    node5 = ( 'e', [ node6 ] )
-    node4 = ( 'd', [ None ] )
-    node3 = ( 'c', [ node4 ] )
-    node2 = ( 'b', [ node3, node5 ] )
-    node1 = ( 'a', [ node2 ] )
-    source1 = [ node1 ]
-    node9 = ( 'ef', [ None ] )
-    node8 = ( 'cd', [ None ] )
-    node7 = ( 'ab', [ node8, node9 ] )
-    source2 = [ node7 ]
-    self.assertEqual(make_dafsa.join_labels(source1), source2)
-
-  def testReverseChainedTrie(self):
-    """Tests a reverse trie formed DAFSA with chained labels can be joined."""
-
-    # 'a' -> 'b'               'ab'
-    #          \                  \
-    #          'e' -> 'f'  =>     'ef'
-    #          /                  /
-    # 'c' -> 'd'               'cd'
-
-    node6 = ( 'f', [ None ] )
-    node5 = ( 'e', [ node6 ] )
-    node4 = ( 'd', [ node5 ] )
-    node3 = ( 'c', [ node4 ] )
-    node2 = ( 'b', [ node5 ] )
-    node1 = ( 'a', [ node2 ] )
-    source1 = [ node1, node3 ]
-    node9 = ( 'ef', [ None ] )
-    node8 = ( 'cd', [ node9 ] )
-    node7 = ( 'ab', [ node9 ] )
-    source2 = [ node7, node8 ]
-    self.assertEqual(make_dafsa.join_labels(source1), source2)
-
-
-class JoinSuffixesTest(unittest.TestCase):
-  def testSingleLabel(self):
-    """Tests a single label passes unchanged."""
-
-    # 'a'  =>  'a'
-
-    node1 = ( 'a', [ None ] )
-    source = [ node1 ]
-    self.assertEqual(make_dafsa.join_suffixes(source), source)
-
-  def testInnerTerminator(self):
-    """Tests a sequence with an inner terminator passes unchanged."""
-
-    # 'a' -> 'b'    'a' -> 'b'
-    #   \       =>    \
-    #  {sink}        {sink}
-
-    node2 = ( 'b', [ None ] )
-    node1 = ( 'a', [ node2, None ] )
-    source = [ node1 ]
-    self.assertEqual(make_dafsa.join_suffixes(source), source)
-
-  def testDistinctTrie(self):
-    """Tests a trie formed DAFSA with distinct labels passes unchanged."""
-
-    #   'b'       'b'
-    #   /         /
-    # 'a'   =>  'a'
-    #   \         \
-    #   'c'       'c'
-
-    node3 = ( 'c', [ None ] )
-    node2 = ( 'b', [ None ] )
-    node1 = ( 'a', [ node2, node3 ] )
-    source = [ node1 ]
-    self.assertEqual(make_dafsa.join_suffixes(source), source)
-
-  def testReverseDistinctTrie(self):
-    """Tests a reverse trie formed DAFSA with distinct labels passes unchanged.
-    """
-
-    # 'a'        'a'
-    #   \          \
-    #   'c'  =>    'c'
-    #   /          /
-    # 'b'        'b'
-
-    node3 = ( 'c', [ None ] )
-    node2 = ( 'b', [ node3 ] )
-    node1 = ( 'a', [ node3 ] )
-    source = [ node1, node2 ]
-    self.assertEqual(make_dafsa.join_suffixes(source), source)
-
-  def testJoinTwoHeads(self):
-    """Tests two heads can be joined even if there is something else between."""
-
-    # 'a'       ------'a'
-    #                 /
-    # 'b'  =>  'b'   /
-    #               /
-    # 'a'       ---
-    #
-    # The picture above should shows that the new version should have just one
-    # instance of the node with label 'a'.
-
-    node3 = ( 'a', [ None ] )
-    node2 = ( 'b', [ None ] )
-    node1 = ( 'a', [ None ] )
-    source1 = [ node1, node2, node3 ]
-    source2 = make_dafsa.join_suffixes(source1)
-
-    # Both versions should expand to the same content.
-    self.assertEqual(source1, source2)
-    # But the new version should have just one instance of 'a'.
-    self.assertIs(source2[0], source2[2])
-
-  def testJoinTails(self):
-    """Tests tails can be joined."""
-
-    # 'a' -> 'c'      'a'
-    #                   \
-    #             =>    'c'
-    #                   /
-    # 'b' -> 'c'      'b'
-
-    node4 = ( 'c', [ None ] )
-    node3 = ( 'b', [ node4 ] )
-    node2 = ( 'c', [ None ] )
-    node1 = ( 'a', [ node2 ] )
-    source1 = [ node1, node3 ]
-    source2 = make_dafsa.join_suffixes(source1)
-
-    # Both versions should expand to the same content.
-    self.assertEqual(source1, source2)
-    # But the new version should have just one tail.
-    self.assertIs(source2[0][1][0], source2[1][1][0])
-
-  def testMakeRecursiveTrie(self):
-    """Tests recursive suffix join."""
-
-    # 'a' -> 'e' -> 'g'     'a'
-    #                         \
-    #                         'e'
-    #                         / \
-    # 'b' -> 'e' -> 'g'     'b'  \
-    #                             \
-    #                   =>        'g'
-    #                             /
-    # 'c' -> 'f' -> 'g'     'c'  /
-    #                         \ /
-    #                         'f'
-    #                         /
-    # 'd' -> 'f' -> 'g'     'd'
-
-    node7 = ( 'g', [ None ] )
-    node6 = ( 'f', [ node7 ] )
-    node5 = ( 'e', [ node7 ] )
-    node4 = ( 'd', [ node6 ] )
-    node3 = ( 'c', [ node6 ] )
-    node2 = ( 'b', [ node5 ] )
-    node1 = ( 'a', [ node5 ] )
-    source1 = [ node1, node2, node3, node4 ]
-    source2 = make_dafsa.join_suffixes(source1)
-
-    # Both versions should expand to the same content.
-    self.assertEqual(source1, source2)
-    # But the new version should have just one 'e'.
-    self.assertIs(source2[0][1][0], source2[1][1][0])
-    # And one 'f'.
-    self.assertIs(source2[2][1][0], source2[3][1][0])
-    # And one 'g'.
-    self.assertIs(source2[0][1][0][1][0], source2[2][1][0][1][0])
-
-  def testMakeDiamond(self):
-    """Test we can join suffixes of a trie."""
-
-    #   'b' -> 'd'        'b'
-    #   /                 / \
-    # 'a'           =>  'a' 'd'
-    #   \                 \ /
-    #   'c' -> 'd'        'c'
-
-    node5 = ( 'd', [ None ] )
-    node4 = ( 'c', [ node5 ] )
-    node3 = ( 'd', [ None ] )
-    node2 = ( 'b', [ node3 ] )
-    node1 = ( 'a', [ node2, node4 ] )
-    source1 = [ node1 ]
-    source2 = make_dafsa.join_suffixes(source1)
-
-    # Both versions should expand to the same content.
-    self.assertEqual(source1, source2)
-    # But the new version should have just one 'd'.
-    self.assertIs(source2[0][1][0][1][0], source2[0][1][1][1][0])
-
-  def testJoinOneChild(self):
-    """Tests that we can join some children but not all."""
-
-    #   'c'            ----'c'
-    #   /            /     /
-    # 'a'          'a'    /
-    #   \            \   /
-    #   'd'          'd'/
-    #          =>      /
-    #   'c'           /
-    #   /            /
-    # 'b'          'b'
-    #   \            \
-    #   'e'          'e'
-
-    node6 = ( 'e', [ None ] )
-    node5 = ( 'c', [ None ] )
-    node4 = ( 'b', [ node5, node6 ] )
-    node3 = ( 'd', [ None ] )
-    node2 = ( 'c', [ None ] )
-    node1 = ( 'a', [ node2, node3 ] )
-    source1 = [ node1, node4 ]
-    source2 = make_dafsa.join_suffixes(source1)
-
-    # Both versions should expand to the same content.
-    self.assertEqual(source1, source2)
-    # But the new version should have just one 'c'.
-    self.assertIs(source2[0][1][0], source2[1][1][0])
-
-
-class ReverseTest(unittest.TestCase):
-  def testAtomicLabel(self):
-    """Tests an atomic label passes unchanged."""
-
-    # 'a'  =>  'a'
-
-    node1 = ( 'a', [ None ] )
-    source = [ node1 ]
-    self.assertEqual(make_dafsa.reverse(source), source)
-
-  def testLabel(self):
-    """Tests that labels are reversed."""
-
-    # 'ab'  =>  'ba'
-
-    node1 = ( 'ab', [ None ] )
-    source1 = [ node1 ]
-    node2 = ( 'ba', [ None ] )
-    source2 = [ node2 ]
-    self.assertEqual(make_dafsa.reverse(source1), source2)
-
-  def testChain(self):
-    """Tests that edges are reversed."""
-
-    # 'a' -> 'b'  =>  'b' -> 'a'
-
-    node2 = ( 'b', [ None ] )
-    node1 = ( 'a', [ node2 ] )
-    source1 = [ node1 ]
-    node4 = ( 'a', [ None ] )
-    node3 = ( 'b', [ node4 ] )
-    source2 = [ node3 ]
-    self.assertEqual(make_dafsa.reverse(source1), source2)
-
-  def testInnerTerminator(self):
-    """Tests a sequence with an inner terminator can be reversed."""
-
-    # 'a' -> 'b'    'b' -> 'a'
-    #   \       =>         /
-    #  {sink}        ------
-
-    node2 = ( 'b', [ None ] )
-    node1 = ( 'a', [ node2, None ] )
-    source1 = [ node1 ]
-    node4 = ( 'a', [ None ] )
-    node3 = ( 'b', [ node4 ] )
-    source2 = [ node3, node4 ]
-    self.assertEqual(make_dafsa.reverse(source1), source2)
-
-  def testAtomicTrie(self):
-    """Tests a trie formed DAFSA can be reversed."""
-
-    #   'b'     'b'
-    #   /         \
-    # 'a'   =>    'a'
-    #   \         /
-    #   'c'     'c'
-
-    node3 = ( 'c', [ None ] )
-    node2 = ( 'b', [ None ] )
-    node1 = ( 'a', [ node2, node3 ] )
-    source1 = [ node1 ]
-    node6 = ( 'a', [ None ] )
-    node5 = ( 'c', [ node6 ] )
-    node4 = ( 'b', [ node6 ] )
-    source2 = [ node4, node5 ]
-    self.assertEqual(make_dafsa.reverse(source1), source2)
-
-  def testReverseAtomicTrie(self):
-    """Tests a reverse trie formed DAFSA can be reversed."""
-
-    # 'a'          'a'
-    #   \          /
-    #   'c'  =>  'c'
-    #   /          \
-    # 'b'          'b'
-
-    node3 = ( 'c', [ None ] )
-    node2 = ( 'b', [ node3 ] )
-    node1 = ( 'a', [ node3 ] )
-    source1 = [ node1, node2 ]
-    node6 = ( 'b', [ None ] )
-    node5 = ( 'a', [ None ] )
-    node4 = ( 'c', [ node5, node6 ] )
-    source2 = [ node4 ]
-    self.assertEqual(make_dafsa.reverse(source1), source2)
-
-  def testDiamond(self):
-    """Tests we can reverse both edges and nodes in a diamond."""
-
-    #   'cd'           'dc'
-    #   /  \           /  \
-    # 'ab' 'gh'  =>  'hg' 'ba'
-    #   \  /           \  /
-    #   'ef'           'fe'
-
-    node4 = ( 'gh', [ None ] )
-    node3 = ( 'ef', [ node4 ] )
-    node2 = ( 'cd', [ node4 ] )
-    node1 = ( 'ab', [ node2, node3 ] )
-    source1 = [ node1 ]
-    node8 = ( 'ba', [ None ] )
-    node7 = ( 'fe', [ node8 ] )
-    node6 = ( 'dc', [ node8 ] )
-    node5 = ( 'hg', [ node6, node7 ] )
-    source2 = [ node5 ]
-    self.assertEqual(make_dafsa.reverse(source1), source2)
-
-
-class TopSortTest(unittest.TestCase):
-  def testNode(self):
-    """Tests a DAFSA with one node can be sorted."""
-
-    # 'a'  =>  [ 'a' ]
-
-    node1 = ( 'a', [ None ] )
-    source = [ node1 ]
-    nodes = [ node1 ]
-    self.assertEqual(make_dafsa.top_sort(source), nodes)
-
-  def testDiamond(self):
-    """Tests nodes in a diamond can be sorted."""
-
-    #   'b'
-    #   / \
-    # 'a' 'd'
-    #   \ /
-    #   'c'
-
-    node4 = ( 'd', [ None ] )
-    node3 = ( 'c', [ node4 ] )
-    node2 = ( 'b', [ node4 ] )
-    node1 = ( 'a', [ node2, node3 ] )
-    source = [ node1 ]
-    nodes = make_dafsa.top_sort(source)
-    self.assertLess(nodes.index(node1), nodes.index(node2))
-    self.assertLess(nodes.index(node2), nodes.index(node4))
-    self.assertLess(nodes.index(node3), nodes.index(node4))
-
-
-class EncodePrefixTest(unittest.TestCase):
-  def testChar(self):
-    """Tests to encode a single character prefix."""
-    label = 'a'
-    bytes = [ ord('a') ]
-    self.assertEqual(make_dafsa.encode_prefix(label), bytes)
-
-  def testChars(self):
-    """Tests to encode a multi character prefix."""
-    label = 'ab'
-    bytes = [ ord('b'), ord('a') ]
-    self.assertEqual(make_dafsa.encode_prefix(label), bytes)
-
-
-class EncodeLabelTest(unittest.TestCase):
-  def testChar(self):
-    """Tests to encode a single character label."""
-    label = 'a'
-    bytes = [ ord('a') + 0x80 ]
-    self.assertEqual(make_dafsa.encode_label(label), bytes)
-
-  def testChars(self):
-    """Tests to encode a multi character label."""
-    label = 'ab'
-    bytes = [ ord('b') + 0x80, ord('a') ]
-    self.assertEqual(make_dafsa.encode_label(label), bytes)
-
-
-class EncodeLinksTest(unittest.TestCase):
-  def testEndLabel(self):
-    """Tests to encode link to the sink."""
-    children = [ None ]
-    offsets = {}
-    bytes = 0
-    output = []
-    self.assertEqual(make_dafsa.encode_links(children, offsets, bytes),
-                      output)
-
-  def testOneByteOffset(self):
-    """Tests to encode a single one byte offset."""
-    node = ( '', [ None ] )
-    children = [ node ]
-    offsets = { id(node) : 2 }
-    bytes = 5
-    output = [ 132 ]
-    self.assertEqual(make_dafsa.encode_links(children, offsets, bytes),
-                      output)
-
-  def testOneByteOffsets(self):
-    """Tests to encode a sequence of one byte offsets."""
-    node1 = ( '', [ None ] )
-    node2 = ( '', [ None ] )
-    children = [ node1, node2 ]
-    offsets = { id(node1) : 2, id(node2) : 1 }
-    bytes = 5
-    output = [ 129, 5 ]
-    self.assertEqual(make_dafsa.encode_links(children, offsets, bytes),
-                      output)
-
-  def testTwoBytesOffset(self):
-    """Tests to encode a single two byte offset."""
-    node = ( '', [ None ] )
-    children = [ node ]
-    offsets = { id(node) : 2 }
-    bytes = 1005
-    output = [ 237, 195]
-    self.assertEqual(make_dafsa.encode_links(children, offsets, bytes),
-                      output)
-
-  def testTwoBytesOffsets(self):
-    """Tests to encode a sequence of two byte offsets."""
-    node1 = ( '', [ None ] )
-    node2 = ( '', [ None ] )
-    node3 = ( '', [ None ] )
-    children = [ node1, node2, node3 ]
-    offsets = { id(node1) : 1002, id(node2) : 2, id(node3) : 2002 }
-    bytes = 3005
-    output = [ 232, 195, 232, 67, 241, 67 ]
-    self.assertEqual(make_dafsa.encode_links(children, offsets, bytes),
-                      output)
-
-  def testThreeBytesOffset(self):
-    """Tests to encode a single three byte offset."""
-    node = ( '', [ None ] )
-    children = [ node ]
-    offsets = { id(node) : 2 }
-    bytes = 100005
-    output = [ 166, 134, 225 ]
-    self.assertEqual(make_dafsa.encode_links(children, offsets, bytes),
-                      output)
-
-  def testThreeBytesOffsets(self):
-    """Tests to encode a sequence of three byte offsets."""
-    node1 = ( '', [ None ] )
-    node2 = ( '', [ None ] )
-    node3 = ( '', [ None ] )
-    children = [ node1, node2, node3 ]
-    offsets = { id(node1) : 100002, id(node2) : 2, id(node3) : 200002 }
-    bytes = 300005
-    output = [ 160, 134, 225, 160, 134, 97, 172, 134, 97 ]
-    self.assertEqual(make_dafsa.encode_links(children, offsets, bytes),
-                      output)
-
-  def testOneTwoThreeBytesOffsets(self):
-    """Tests to encode offsets of different sizes."""
-    node1 = ( '', [ None ] )
-    node2 = ( '', [ None ] )
-    node3 = ( '', [ None ] )
-    children = [ node1, node2, node3 ]
-    offsets = { id(node1) : 10003, id(node2) : 10002, id(node3) : 100002 }
-    bytes = 300005
-    output = [ 129, 143, 95, 97, 74, 13, 99 ]
-    self.assertEqual(make_dafsa.encode_links(children, offsets, bytes),
-                      output)
-
-
-class ExamplesTest(unittest.TestCase):
-  def testExample1(self):
-    """Tests Example 1 from make_dafsa.py."""
-    infile = '["https://www.example.com:8081", "http://www.example.org"]'
-    outfile = ("\n3\x81htt\xf0\x02\x93://www.example.or\xe7\x99"
-               "s://www.example.com:8081\x80")
-    self.assertEqual(make_dafsa.words_to_proto(make_dafsa.parse_json(infile)),
-                      outfile)
-
-  def testExample2(self):
-    """Tests Example 2 from make_dafsa.py."""
-    infile = '["https://www.example.org", "http://www.google.com"]'
-    outfile = ("\n-\x81htt\xf0\x02\x92://www.google.co\xed\x94"
-               "s://www.example.org\x80")
-    self.assertEqual(make_dafsa.words_to_proto(make_dafsa.parse_json(infile)),
-                      outfile)
-
-  def testExample3(self):
-    """Tests Example 3 from make_dafsa.py."""
-    self.assertRaises(make_dafsa.InputError, make_dafsa.parse_json, "badinput")
-
-
-if __name__ == '__main__':
-  unittest.main()
diff --git a/tools/media_engagement_preload/media_engagement_preload_pb2.py b/tools/media_engagement_preload/media_engagement_preload_pb2.py
deleted file mode 100644
index 0cde5091..0000000
--- a/tools/media_engagement_preload/media_engagement_preload_pb2.py
+++ /dev/null
@@ -1,63 +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.
-
-# Generated by the protocol buffer compiler.  DO NOT EDIT!
-# source: media_engagement_preload.proto
-
-from google.protobuf import descriptor as _descriptor
-from google.protobuf import message as _message
-from google.protobuf import reflection as _reflection
-from google.protobuf import descriptor_pb2
-# @@protoc_insertion_point(imports)
-
-
-
-
-DESCRIPTOR = _descriptor.FileDescriptor(
-  name='media_engagement_preload.proto',
-  package='chrome_browser_media',
-  serialized_pb='\n\x1emedia_engagement_preload.proto\x12\x14\x63hrome_browser_media\"\x1e\n\rPreloadedData\x12\r\n\x05\x64\x61\x66sa\x18\x01 \x01(\x0c\x42\x02H\x03')
-
-
-
-
-_PRELOADEDDATA = _descriptor.Descriptor(
-  name='PreloadedData',
-  full_name='chrome_browser_media.PreloadedData',
-  filename=None,
-  file=DESCRIPTOR,
-  containing_type=None,
-  fields=[
-    _descriptor.FieldDescriptor(
-      name='dafsa', full_name='chrome_browser_media.PreloadedData.dafsa', index=0,
-      number=1, type=12, cpp_type=9, label=1,
-      has_default_value=False, default_value="",
-      message_type=None, enum_type=None, containing_type=None,
-      is_extension=False, extension_scope=None,
-      options=None),
-  ],
-  extensions=[
-  ],
-  nested_types=[],
-  enum_types=[
-  ],
-  options=None,
-  is_extendable=False,
-  extension_ranges=[],
-  serialized_start=56,
-  serialized_end=86,
-)
-
-DESCRIPTOR.message_types_by_name['PreloadedData'] = _PRELOADEDDATA
-
-class PreloadedData(_message.Message):
-  __metaclass__ = _reflection.GeneratedProtocolMessageType
-  DESCRIPTOR = _PRELOADEDDATA
-
-  # @@protoc_insertion_point(class_scope:chrome_browser_media.PreloadedData)
-
-
-DESCRIPTOR.has_options = True
-DESCRIPTOR._options = _descriptor._ParseOptions(descriptor_pb2.FileOptions(), 'H\003')
-# @@protoc_insertion_point(module_scope)
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index 10c34ca..e8833fac 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -2830,6 +2830,8 @@
   <int value="185" label="WEBUI_BAD_SCHEME_ACCESS"/>
   <int value="186" label="CSDH_UNEXPECTED_OPERATION"/>
   <int value="187" label="RMF_BAD_URL_CACHEABLE_METADATA"/>
+  <int value="188" label="RFH_INTERFACE_PROVIDER_MISSING"/>
+  <int value="189" label="RFH_INTERFACE_PROVIDER_SUPERFLUOUS"/>
 </enum>
 
 <enum name="BadMessageReasonExtensions">
@@ -17151,6 +17153,7 @@
   <int value="2261" label="AudioWorkletAddModule"/>
   <int value="2262" label="AudioWorkletGlobalScopeRegisterProcessor"/>
   <int value="2263" label="AudioWorkletNodeConstructor"/>
+  <int value="2264" label="HTMLMediaElementEmptyLoadWithFutureData"/>
 </enum>
 
 <enum name="FeedbackSource">
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index 4c1f9c2..687e6c6 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -22425,6 +22425,31 @@
   </summary>
 </histogram>
 
+<histogram name="Extensions.BookmarkApp.GetAppForCurrentURLDuration" units="ms">
+  <owner>mgiuca@chromium.org</owner>
+  <owner>ortuno@chromium.org</owner>
+  <summary>
+    Time it takes to retrieve the app for the current URL during a navigation.
+  </summary>
+</histogram>
+
+<histogram name="Extensions.BookmarkApp.GetAppForWindowDuration" units="ms">
+  <owner>mgiuca@chromium.org</owner>
+  <owner>ortuno@chromium.org</owner>
+  <summary>
+    Time it takes to retrieve the app associated with the window during a
+    navigation.
+  </summary>
+</histogram>
+
+<histogram name="Extensions.BookmarkApp.GetTargetAppDuration" units="ms">
+  <owner>mgiuca@chromium.org</owner>
+  <owner>ortuno@chromium.org</owner>
+  <summary>
+    Time it takes to retrieve the app for the target url during a navigation.
+  </summary>
+</histogram>
+
 <histogram name="Extensions.BookmarkApp.NavigationResult"
     enum="BookmarkAppNavigationResult">
   <owner>mgiuca@chromium.org</owner>
@@ -22435,6 +22460,17 @@
   </summary>
 </histogram>
 
+<histogram name="Extensions.BookmarkApp.TimeBetweenOpenAppAndLastNavigation"
+    units="ms">
+  <owner>mgiuca@chromium.org</owner>
+  <owner>ortuno@chromium.org</owner>
+  <summary>
+    The time between the last navigation in the context and us opening a new app
+    window in response to a new navigation. If it is very small, the context
+    probably redirected immediately, which is a bad user experience.
+  </summary>
+</histogram>
+
 <histogram name="Extensions.BookmarkAppLaunchContainer"
     enum="AppLaunchContainer">
   <owner>benwells@chromium.org</owner>
@@ -36236,6 +36272,14 @@
   </summary>
 </histogram>
 
+<histogram name="Memory.Browser.PrivateSwapFootprint" units="MB">
+  <owner>mariakhomenko@chromium.org</owner>
+  <summary>
+    An amount of private memory of the browser process placed in swap (VmSwap).
+    Available only on Android and Linux.
+  </summary>
+</histogram>
+
 <histogram name="Memory.Browser.SharedMemoryFootprint" units="MB">
   <owner>erikchen@chromium.org</owner>
   <summary>
@@ -36755,6 +36799,14 @@
   </summary>
 </histogram>
 
+<histogram name="Memory.Gpu.PrivateSwapFootprint" units="MB">
+  <owner>mariakhomenko@chromium.org</owner>
+  <summary>
+    An amount of private memory of the GPU process placed in swap (VmSwap).
+    Available only on Android and Linux.
+  </summary>
+</histogram>
+
 <histogram name="Memory.Gpu.SharedMemoryFootprint" units="MB">
   <owner>erikchen@chromium.org</owner>
   <summary>
@@ -39282,6 +39334,14 @@
   </summary>
 </histogram>
 
+<histogram name="Navigation.Intercept.WillStart" units="microseconds">
+  <owner>csharrison@chromium.org</owner>
+  <summary>
+    The microseconds it takes for the InterceptNavigationThrottle to determine
+    if the navigation should be ignored, at WillStartRequest time.
+  </summary>
+</histogram>
+
 <histogram name="Navigation.IOSWKWebViewSlowFastBackForward"
     enum="BackForwardNavigationType">
   <owner>eugenebut@chromium.org</owner>
@@ -56932,6 +56992,15 @@
   </summary>
 </histogram>
 
+<histogram name="PageLoad.Clients.MultiTabLoading.NumTabsWithInflightLoad"
+    units="tabs">
+  <owner>ksakamoto@chromium.org</owner>
+  <summary>
+    Records the number of tabs with inflight loading activities. Recorded when a
+    new page load starts.
+  </summary>
+</histogram>
+
 <histogram name="PageLoad.Clients.SubresourceFilter.ActivationDecision"
     enum="SubresourceFilterActivationDecision">
   <owner>bmcquade@chromium.org</owner>
@@ -103191,6 +103260,23 @@
   <suffix name="Audio.EmbeddedExperience"
       label="Watch time for downloaded media on Android with only an audio
              track."/>
+  <suffix name="Audio.Background.All"
+      label="Background watch time for all media with only an audio track."/>
+  <suffix name="Audio.Background.AC"
+      label="Background watch time for all media with only an audio track on
+             AC power."/>
+  <suffix name="Audio.Background.Battery"
+      label="Background watch time for all media with only an audio track on
+             battery power."/>
+  <suffix name="Audio.Background.MSE"
+      label="Background watch time for MSE media with only an audio track."/>
+  <suffix name="Audio.Background.SRC"
+      label="Background watch time for SRC media with only an audio track."/>
+  <suffix name="Audio.Background.EME"
+      label="Background watch time for EME media with only an audio track."/>
+  <suffix name="Audio.Background.EmbeddedExperience"
+      label="Background watch time for downloaded media on Android with only
+             an audio track."/>
   <suffix name="AudioVideo.All"
       label="Watch time for all media with both an audio and video track."/>
   <suffix name="AudioVideo.AC"
@@ -107658,6 +107744,9 @@
   <suffix name="PartitionAlloc" label="Constrained to partition allocator."/>
   <suffix name="BlinkGC" label="Constrained to blink GC allocator."/>
   <suffix name="V8" label="Constrained to v8 allocator."/>
+  <suffix name="PrivateSwapFootprint"
+      label="Only counting private swapped memory. Available only on Android
+             and Linux."/>
   <affected-histogram name="Memory.Experimental.Extension2"/>
   <affected-histogram name="Memory.Experimental.Renderer2"/>
 </histogram_suffixes>
diff --git a/tools/metrics/ukm/ukm.xml b/tools/metrics/ukm/ukm.xml
index 903fb0a..a8102049 100644
--- a/tools/metrics/ukm/ukm.xml
+++ b/tools/metrics/ukm/ukm.xml
@@ -1058,6 +1058,12 @@
       Measure of total private memory consumed by process.
     </summary>
   </metric>
+  <metric name="PrivateSwapFootprint">
+    <summary>
+      Measure of private swap memory consumed by a process. Available on Linux
+      and Android.
+    </summary>
+  </metric>
   <metric name="ProcessType">
     <summary>
       Type of process (e.g. browser, renderer, GPU --- see
diff --git a/ui/app_list/app_list_model_unittest.cc b/ui/app_list/app_list_model_unittest.cc
index 564e66ed..1ab475fb 100644
--- a/ui/app_list/app_list_model_unittest.cc
+++ b/ui/app_list/app_list_model_unittest.cc
@@ -224,7 +224,6 @@
 class AppListModelFolderTest : public AppListModelTest {
  public:
   AppListModelFolderTest() {
-    model_.SetFoldersEnabled(true);
   }
   ~AppListModelFolderTest() override {}
 
@@ -541,15 +540,6 @@
   std::string oem_folder_id = oem_folder->id();
   model_.AddItemToFolder(oem_item, oem_folder_id);
   EXPECT_EQ("folder1,oem_folder", GetModelContents());
-
-  // Disable folders. Ensure non-oem folder is removed.
-  model_.SetFoldersEnabled(false);
-  ASSERT_FALSE(model_.FindFolderItem(folder_id));
-  ASSERT_TRUE(model_.FindFolderItem(oem_folder_id));
-  EXPECT_EQ("Item 0,Item 1,oem_folder", GetModelContents());
-
-  // Ensure folder creation fails.
-  EXPECT_EQ(std::string(), model_.MergeItems(item0->id(), item1->id()));
 }
 
 }  // namespace app_list
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 b8162448..da33577 100644
--- a/ui/app_list/test/app_list_test_view_delegate.cc
+++ b/ui/app_list/test/app_list_test_view_delegate.cc
@@ -19,7 +19,6 @@
 AppListTestViewDelegate::AppListTestViewDelegate()
     : model_(std::make_unique<AppListTestModel>()),
       search_model_(std::make_unique<SearchModel>()) {
-  model_->SetFoldersEnabled(true);
 }
 
 AppListTestViewDelegate::~AppListTestViewDelegate() {}
diff --git a/ui/app_list/views/app_list_item_view.cc b/ui/app_list/views/app_list_item_view.cc
index df07325..41e33ec 100644
--- a/ui/app_list/views/app_list_item_view.cc
+++ b/ui/app_list/views/app_list_item_view.cc
@@ -328,8 +328,6 @@
   }
 
   if (ui_state_ == UI_STATE_DROPPING_IN_FOLDER) {
-    DCHECK(apps_grid_view_->model()->folders_enabled());
-
     // Draw folder dropping preview circle.
     gfx::Point center = gfx::Point(icon_->x() + icon_->size().width() / 2,
                                    icon_->y() + icon_->size().height() / 2);
diff --git a/ui/app_list/views/app_list_main_view_unittest.cc b/ui/app_list/views/app_list_main_view_unittest.cc
index 7fbd2c571..4da8b83 100644
--- a/ui/app_list/views/app_list_main_view_unittest.cc
+++ b/ui/app_list/views/app_list_main_view_unittest.cc
@@ -88,7 +88,6 @@
     delegate_.reset(new AppListTestViewDelegate);
     main_view_ = new AppListMainView(delegate_.get(), nullptr);
     main_view_->SetPaintToLayer();
-    main_view_->model()->SetFoldersEnabled(true);
 
     search_box_view_ = new SearchBoxView(main_view_, delegate_.get());
     main_view_->Init(0, search_box_view_);
diff --git a/ui/app_list/views/apps_grid_view.cc b/ui/app_list/views/apps_grid_view.cc
index 604f067..1282ab6 100644
--- a/ui/app_list/views/apps_grid_view.cc
+++ b/ui/app_list/views/apps_grid_view.cc
@@ -2691,9 +2691,8 @@
 }
 
 bool AppsGridView::EnableFolderDragDropUI() {
-  // Enable drag and drop folder UI only if it is at the app list root level
-  // and the switch is on.
-  return model_->folders_enabled() && !folder_delegate_;
+  // Enable drag and drop folder UI only if it is at the app list root level.
+  return !folder_delegate_;
 }
 
 AppsGridView::Index AppsGridView::GetNearestTileIndexForPoint(
diff --git a/ui/app_list/views/apps_grid_view_unittest.cc b/ui/app_list/views/apps_grid_view_unittest.cc
index 8272b60..9486cd1 100644
--- a/ui/app_list/views/apps_grid_view_unittest.cc
+++ b/ui/app_list/views/apps_grid_view_unittest.cc
@@ -358,55 +358,6 @@
   EXPECT_TRUE(apps_grid_view_->IsSelectedView(view));
 }
 
-TEST_F(AppsGridViewTest, MouseDragWithFolderDisabled) {
-  model_->SetFoldersEnabled(false);
-  const int kTotalItems = 4;
-  model_->PopulateApps(kTotalItems);
-  EXPECT_EQ(std::string("Item 0,Item 1,Item 2,Item 3"),
-            model_->GetModelContent());
-
-  gfx::Point from = GetItemRectOnCurrentPageAt(0, 0).CenterPoint();
-  gfx::Point to = GetItemRectOnCurrentPageAt(0, 1).CenterPoint();
-
-  // Dragging changes model order.
-  SimulateDrag(AppsGridView::MOUSE, from, to);
-  apps_grid_view_->EndDrag(false);
-  EXPECT_EQ(std::string("Item 1,Item 0,Item 2,Item 3"),
-            model_->GetModelContent());
-  test_api_->LayoutToIdealBounds();
-
-  // Canceling drag should keep existing order.
-  SimulateDrag(AppsGridView::MOUSE, from, to);
-  apps_grid_view_->EndDrag(true);
-  EXPECT_EQ(std::string("Item 1,Item 0,Item 2,Item 3"),
-            model_->GetModelContent());
-  test_api_->LayoutToIdealBounds();
-
-  // Deleting an item keeps remaining intact.
-  SimulateDrag(AppsGridView::MOUSE, from, to);
-  model_->DeleteItem(model_->GetItemName(0));
-  apps_grid_view_->EndDrag(false);
-  EXPECT_EQ(std::string("Item 1,Item 2,Item 3"), model_->GetModelContent());
-  test_api_->LayoutToIdealBounds();
-
-  // Adding a launcher item cancels the drag and respects the order.
-  SimulateDrag(AppsGridView::MOUSE, from, to);
-  EXPECT_TRUE(apps_grid_view_->has_dragged_view());
-  model_->CreateAndAddItem("Extra");
-  // No need to EndDrag explicitly - adding an item should do this.
-  EXPECT_FALSE(apps_grid_view_->has_dragged_view());
-  // Even though cancelled, mouse move events can still arrive via the item
-  // view. Ensure that behaves sanely, and doesn't start a new drag.
-  ui::MouseEvent drag_event(ui::ET_MOUSE_DRAGGED, gfx::Point(1, 1),
-                            gfx::Point(2, 2), ui::EventTimeForNow(), 0, 0);
-  apps_grid_view_->UpdateDragFromItem(AppsGridView::MOUSE, drag_event);
-  EXPECT_FALSE(apps_grid_view_->has_dragged_view());
-
-  EXPECT_EQ(std::string("Item 1,Item 2,Item 3,Extra"),
-            model_->GetModelContent());
-  test_api_->LayoutToIdealBounds();
-}
-
 TEST_F(AppsGridViewTest, MouseDragItemIntoFolder) {
   size_t kTotalItems = 3;
   model_->PopulateApps(kTotalItems);
@@ -717,38 +668,6 @@
   apps_grid_view_->EndDrag(true);
 }
 
-TEST_F(AppsGridViewTest, SimultaneousDragWithFolderDisabled) {
-  model_->SetFoldersEnabled(false);
-  const int kTotalItems = 4;
-  model_->PopulateApps(kTotalItems);
-  EXPECT_EQ(std::string("Item 0,Item 1,Item 2,Item 3"),
-            model_->GetModelContent());
-
-  gfx::Point mouse_from = GetItemRectOnCurrentPageAt(0, 0).CenterPoint();
-  gfx::Point mouse_to = GetItemRectOnCurrentPageAt(0, 1).CenterPoint();
-
-  gfx::Point touch_from = GetItemRectOnCurrentPageAt(0, 2).CenterPoint();
-  gfx::Point touch_to = GetItemRectOnCurrentPageAt(0, 3).CenterPoint();
-
-  // Starts a mouse drag first then a touch drag.
-  SimulateDrag(AppsGridView::MOUSE, mouse_from, mouse_to);
-  SimulateDrag(AppsGridView::TOUCH, touch_from, touch_to);
-  // Finishes the drag and mouse drag wins.
-  apps_grid_view_->EndDrag(false);
-  EXPECT_EQ(std::string("Item 1,Item 0,Item 2,Item 3"),
-            model_->GetModelContent());
-  test_api_->LayoutToIdealBounds();
-
-  // Starts a touch drag first then a mouse drag.
-  SimulateDrag(AppsGridView::TOUCH, touch_from, touch_to);
-  SimulateDrag(AppsGridView::MOUSE, mouse_from, mouse_to);
-  // Finishes the drag and touch drag wins.
-  apps_grid_view_->EndDrag(false);
-  EXPECT_EQ(std::string("Item 1,Item 0,Item 3,Item 2"),
-            model_->GetModelContent());
-  test_api_->LayoutToIdealBounds();
-}
-
 TEST_F(AppsGridViewTest, UpdateFolderBackgroundOnCancelDrag) {
   const int kTotalItems = 4;
   TestAppsGridViewFolderDelegate folder_delegate;
diff --git a/ui/app_list/views/folder_header_view_unittest.cc b/ui/app_list/views/folder_header_view_unittest.cc
index 1e9ea456..d469a2d 100644
--- a/ui/app_list/views/folder_header_view_unittest.cc
+++ b/ui/app_list/views/folder_header_view_unittest.cc
@@ -61,7 +61,6 @@
   void SetUp() override {
     views::ViewsTestBase::SetUp();
     model_.reset(new AppListTestModel);
-    model_->SetFoldersEnabled(true);
 
     delegate_.reset(new TestFolderHeaderViewDelegate);
     folder_header_view_.reset(new FolderHeaderView(delegate_.get()));
diff --git a/ui/compositor/layer.cc b/ui/compositor/layer.cc
index bd08b3e4..ad78e69 100644
--- a/ui/compositor/layer.cc
+++ b/ui/compositor/layer.cc
@@ -912,8 +912,8 @@
   if (content_layer_ && deferred_paint_requests_)
     return;
 
-  for (cc::Region::Iterator iter(damaged_region_); iter.has_rect(); iter.next())
-    cc_layer_->SetNeedsDisplayRect(iter.rect());
+  for (gfx::Rect damaged_rect : damaged_region_)
+    cc_layer_->SetNeedsDisplayRect(damaged_rect);
   if (layer_mask_)
     layer_mask_->SendDamagedRects();
 
diff --git a/ui/gfx/generic_shared_memory_id.h b/ui/gfx/generic_shared_memory_id.h
index 5e73f5e..ed77e529 100644
--- a/ui/gfx/generic_shared_memory_id.h
+++ b/ui/gfx/generic_shared_memory_id.h
@@ -29,6 +29,8 @@
   GenericSharedMemoryId& operator=(const GenericSharedMemoryId& other) =
       default;
 
+  bool is_valid() const { return id >= 0; }
+
   bool operator==(const GenericSharedMemoryId& other) const {
     return id == other.id;
   }
diff --git a/ui/gfx/geometry/quaternion.cc b/ui/gfx/geometry/quaternion.cc
index 9da8f47..ef7fae0 100644
--- a/ui/gfx/geometry/quaternion.cc
+++ b/ui/gfx/geometry/quaternion.cc
@@ -80,8 +80,12 @@
   return (((1.0 - t) * *this) + (t * q)).Normalized();
 }
 
+double Quaternion::Length() const {
+  return x_ * x_ + y_ * y_ + z_ * z_ + w_ * w_;
+}
+
 Quaternion Quaternion::Normalized() const {
-  double length = x_ * x_ + y_ * y_ + z_ * z_ + w_ * w_;
+  double length = Length();
   if (length < kEpsilon)
     return *this;
   return *this / sqrt(length);
diff --git a/ui/gfx/geometry/quaternion.h b/ui/gfx/geometry/quaternion.h
index f4e124ce..7f65b796 100644
--- a/ui/gfx/geometry/quaternion.h
+++ b/ui/gfx/geometry/quaternion.h
@@ -59,6 +59,8 @@
   // and values outside that range will extrapolate beyond in either direction.
   Quaternion Lerp(const Quaternion& q, double t) const;
 
+  double Length() const;
+
   Quaternion Normalized() const;
 
   std::string ToString() const;
diff --git a/ui/gfx/geometry/quaternion_unittest.cc b/ui/gfx/geometry/quaternion_unittest.cc
index 38e192e1..5c8fa9b 100644
--- a/ui/gfx/geometry/quaternion_unittest.cc
+++ b/ui/gfx/geometry/quaternion_unittest.cc
@@ -99,6 +99,19 @@
   }
 }
 
+TEST(QuatTest, Normalization) {
+  Quaternion q(1, -1, 1, -1);
+  EXPECT_NEAR(q.Length(), 4, kEpsilon);
+
+  q = q.Normalized();
+
+  EXPECT_NEAR(q.Length(), 1, kEpsilon);
+  EXPECT_NEAR(q.x(), 0.5, kEpsilon);
+  EXPECT_NEAR(q.y(), -0.5, kEpsilon);
+  EXPECT_NEAR(q.z(), 0.5, kEpsilon);
+  EXPECT_NEAR(q.w(), -0.5, kEpsilon);
+}
+
 TEST(QuatTest, Lerp) {
   for (size_t i = 1; i < 100; ++i) {
     Quaternion a(0, 0, 0, 0);
diff --git a/ui/gfx/mac/io_surface.cc b/ui/gfx/mac/io_surface.cc
index c70980b..f53e01e3 100644
--- a/ui/gfx/mac/io_surface.cc
+++ b/ui/gfx/mac/io_surface.cc
@@ -126,7 +126,9 @@
 
 }  // namespace internal
 
-IOSurfaceRef CreateIOSurface(const gfx::Size& size, gfx::BufferFormat format) {
+IOSurfaceRef CreateIOSurface(const gfx::Size& size,
+                             gfx::BufferFormat format,
+                             bool should_clear) {
   TRACE_EVENT0("ui", "CreateIOSurface");
   base::TimeTicks start_time = base::TimeTicks::Now();
 
@@ -182,7 +184,8 @@
   // https://crbug.com/594343.
   // IOSurface clearing causes significant performance regression on about half
   // of all devices running Yosemite. https://crbug.com/606850#c22.
-  bool should_clear = !base::mac::IsOS10_9() && !base::mac::IsOS10_10();
+  if (base::mac::IsOS10_9() || base::mac::IsOS10_10())
+    should_clear = false;
 
   if (should_clear) {
     // Zero-initialize the IOSurface. Calling IOSurfaceLock/IOSurfaceUnlock
diff --git a/ui/gfx/mac/io_surface.h b/ui/gfx/mac/io_surface.h
index da8826a..04d844c 100644
--- a/ui/gfx/mac/io_surface.h
+++ b/ui/gfx/mac/io_surface.h
@@ -43,7 +43,12 @@
 using IOSurfaceId = GenericSharedMemoryId;
 
 // Helper function to create an IOSurface with a specified size and format.
-GFX_EXPORT IOSurfaceRef CreateIOSurface(const Size& size, BufferFormat format);
+// The surface is zero-initialized if |should_clear| is true. This is not
+// necessary for anonymous surfaces that are not exported to renderers and used
+// as render targets only.
+GFX_EXPORT IOSurfaceRef CreateIOSurface(const Size& size,
+                                        BufferFormat format,
+                                        bool should_clear = true);
 
 // A scoper for handling Mach port names that are send rights for IOSurfaces.
 // This scoper is both copyable and assignable, which will increase the kernel
diff --git a/ui/keyboard/keyboard_controller.cc b/ui/keyboard/keyboard_controller.cc
index 558f3ca5..da2bcd4 100644
--- a/ui/keyboard/keyboard_controller.cc
+++ b/ui/keyboard/keyboard_controller.cc
@@ -262,8 +262,8 @@
   if (ui_->HasContentsWindow() && ui_->GetContentsWindow()->IsVisible()) {
     notification_manager_.SendNotifications(
         container_behavior_->BoundsObscureUsableRegion(),
-        container_behavior_->BoundsAffectWorkspaceLayout(), new_bounds,
-        observer_list_);
+        container_behavior_->BoundsAffectWorkspaceLayout(), keyboard_locked(),
+        new_bounds, observer_list_);
 
     if (keyboard::IsKeyboardOverscrollEnabled())
       ui_->InitInsets(new_bounds);
diff --git a/ui/keyboard/keyboard_controller_observer.h b/ui/keyboard/keyboard_controller_observer.h
index e2e7dd424..ba1b6c4 100644
--- a/ui/keyboard/keyboard_controller_observer.h
+++ b/ui/keyboard/keyboard_controller_observer.h
@@ -14,6 +14,15 @@
 
 namespace keyboard {
 
+// Describes the various attributes of the keyboard's appearance and usability.
+struct KeyboardStateDescriptor {
+  bool is_available;
+  bool is_locked;
+  gfx::Rect visual_bounds;
+  gfx::Rect occluded_bounds;
+  gfx::Rect displaced_bounds;
+};
+
 // Observers to the KeyboardController are notified of significant events that
 // occur with the keyboard, such as the bounds or visiility changing.
 class KEYBOARD_EXPORT KeyboardControllerObserver {
@@ -42,6 +51,12 @@
   virtual void OnKeyboardWorkspaceDisplacingBoundsChanging(
       const gfx::Rect& new_bounds){};
 
+  // Redundant with other various notification methods. Use this if the state of
+  // multiple properties need to be conveyed simultaneously to observer
+  // implementations without the need to track multiple stateful properties.
+  virtual void OnKeyboardAppearanceChanging(
+      const KeyboardStateDescriptor& state){};
+
   // Called when the keyboard was closed.
   virtual void OnKeyboardClosed(){};
 
diff --git a/ui/keyboard/notification_manager.cc b/ui/keyboard/notification_manager.cc
index 4e1c944..0cf698a 100644
--- a/ui/keyboard/notification_manager.cc
+++ b/ui/keyboard/notification_manager.cc
@@ -29,6 +29,7 @@
 void NotificationManager::SendNotifications(
     bool bounds_obscure_usable_region,
     bool bounds_affect_layout,
+    bool is_locked,
     const gfx::Rect& bounds,
     const base::ObserverList<KeyboardControllerObserver>& observers) {
   bool is_available = !bounds.IsEmpty();
@@ -49,6 +50,13 @@
       ShouldSendWorkspaceDisplacementBoundsNotification(
           workspace_layout_offset_region);
 
+  KeyboardStateDescriptor state;
+  state.is_available = is_available;
+  state.is_locked = is_locked;
+  state.visual_bounds = bounds;
+  state.occluded_bounds = occluded_region;
+  state.displaced_bounds = workspace_layout_offset_region;
+
   for (KeyboardControllerObserver& observer : observers) {
     if (send_availability_notification)
       observer.OnKeyboardAvailabilityChanging(is_available);
@@ -64,6 +72,8 @@
           workspace_layout_offset_region);
     }
 
+    observer.OnKeyboardAppearanceChanging(state);
+
     // TODO(blakeo): remove this when all consumers have migrated to one of
     // the notifications above.
     observer.OnKeyboardBoundsChanging(bounds);
diff --git a/ui/keyboard/notification_manager.h b/ui/keyboard/notification_manager.h
index 6995bbb..88fc7750 100644
--- a/ui/keyboard/notification_manager.h
+++ b/ui/keyboard/notification_manager.h
@@ -40,6 +40,7 @@
   void SendNotifications(
       bool bounds_obscure_usable_region,
       bool bounds_affect_layout,
+      bool is_locked,
       const gfx::Rect& bounds,
       const base::ObserverList<KeyboardControllerObserver>& observers);
 
diff --git a/ui/latency/latency_info.cc b/ui/latency/latency_info.cc
index 80c613a1..52f2c1d 100644
--- a/ui/latency/latency_info.cc
+++ b/ui/latency/latency_info.cc
@@ -25,6 +25,12 @@
   switch (type) {
     CASE_TYPE(INPUT_EVENT_LATENCY_BEGIN_RWH_COMPONENT);
     CASE_TYPE(LATENCY_BEGIN_SCROLL_LISTENER_UPDATE_MAIN_COMPONENT);
+    CASE_TYPE(LATENCY_BEGIN_FRAME_RENDERER_MAIN_COMPONENT);
+    CASE_TYPE(LATENCY_BEGIN_FRAME_RENDERER_INVALIDATE_COMPONENT);
+    CASE_TYPE(LATENCY_BEGIN_FRAME_RENDERER_COMPOSITOR_COMPONENT);
+    CASE_TYPE(LATENCY_BEGIN_FRAME_UI_MAIN_COMPONENT);
+    CASE_TYPE(LATENCY_BEGIN_FRAME_UI_COMPOSITOR_COMPONENT);
+    CASE_TYPE(LATENCY_BEGIN_FRAME_DISPLAY_COMPOSITOR_COMPONENT);
     CASE_TYPE(INPUT_EVENT_LATENCY_SCROLL_UPDATE_ORIGINAL_COMPONENT);
     CASE_TYPE(INPUT_EVENT_LATENCY_FIRST_SCROLL_UPDATE_ORIGINAL_COMPONENT);
     CASE_TYPE(INPUT_EVENT_LATENCY_ORIGINAL_COMPONENT);
@@ -53,7 +59,16 @@
   return "unknown";
 }
 
-bool IsTerminalComponent(ui::LatencyComponentType type) {
+bool IsInputLatencyBeginComponent(ui::LatencyComponentType type) {
+  return type == ui::INPUT_EVENT_LATENCY_BEGIN_RWH_COMPONENT;
+}
+
+bool IsTraceBeginComponent(ui::LatencyComponentType type) {
+  return (IsInputLatencyBeginComponent(type) ||
+          type == ui::LATENCY_BEGIN_SCROLL_LISTENER_UPDATE_MAIN_COMPONENT);
+}
+
+bool IsTraceEndComponent(ui::LatencyComponentType type) {
   switch (type) {
     case ui::INPUT_EVENT_LATENCY_TERMINATED_NO_SWAP_COMPONENT:
     case ui::INPUT_EVENT_LATENCY_TERMINATED_FRAME_SWAP_COMPONENT:
@@ -66,15 +81,6 @@
   }
 }
 
-bool IsBeginComponent(ui::LatencyComponentType type) {
-  return (type == ui::INPUT_EVENT_LATENCY_BEGIN_RWH_COMPONENT ||
-          type == ui::LATENCY_BEGIN_SCROLL_LISTENER_UPDATE_MAIN_COMPONENT);
-}
-
-bool IsInputLatencyBeginComponent(ui::LatencyComponentType type) {
-  return type == ui::INPUT_EVENT_LATENCY_BEGIN_RWH_COMPONENT;
-}
-
 // This class is for converting latency info to trace buffer friendly format.
 class LatencyInfoTracedValue
     : public base::trace_event::ConvertableToTraceFormat {
@@ -165,6 +171,19 @@
   return true;
 }
 
+void LatencyInfo::TraceIntermediateFlowEvents(
+    const std::vector<LatencyInfo>& latency_info,
+    const char* event_name) {
+  for (auto& latency : latency_info) {
+    if (latency.trace_id() == -1)
+      continue;
+    TRACE_EVENT_WITH_FLOW1("input,benchmark", "LatencyInfo.Flow",
+                           TRACE_ID_DONT_MANGLE(latency.trace_id()),
+                           TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT,
+                           "step", event_name);
+  }
+}
+
 void LatencyInfo::CopyLatencyFrom(const LatencyInfo& other,
                                   LatencyComponentType type) {
   // Don't clobber an existing trace_id_ or ukm_source_id_.
@@ -263,7 +282,7 @@
   const unsigned char* latency_info_enabled =
       g_latency_info_enabled.Get().latency_info_enabled;
 
-  if (IsBeginComponent(component)) {
+  if (IsTraceBeginComponent(component)) {
     // Should only ever add begin component once.
     CHECK(!began_);
     began_ = true;
@@ -278,12 +297,9 @@
       // not when we actually issue the ASYNC_BEGIN trace event.
       LatencyComponent begin_component;
       base::TimeTicks ts;
-      if (FindLatency(INPUT_EVENT_LATENCY_ORIGINAL_COMPONENT,
-                      0,
+      if (FindLatency(INPUT_EVENT_LATENCY_ORIGINAL_COMPONENT, 0,
                       &begin_component) ||
-          FindLatency(INPUT_EVENT_LATENCY_UI_COMPONENT,
-                      0,
-                      &begin_component)) {
+          FindLatency(INPUT_EVENT_LATENCY_UI_COMPONENT, 0, &begin_component)) {
         ts = begin_component.event_time;
       } else {
         ts = base::TimeTicks::Now();
@@ -331,7 +347,7 @@
     }
   }
 
-  if (IsTerminalComponent(component) && began_) {
+  if (IsTraceEndComponent(component) && began_) {
     // Should only ever add terminal component once.
     CHECK(!terminated_);
     terminated_ = true;
diff --git a/ui/latency/latency_info.h b/ui/latency/latency_info.h
index e13747c..8cd5818 100644
--- a/ui/latency/latency_info.h
+++ b/ui/latency/latency_info.h
@@ -47,6 +47,13 @@
   // scroll processing in impl thread. This is the timestamp when we consider
   // the main thread scroll listener update is begun.
   LATENCY_BEGIN_SCROLL_LISTENER_UPDATE_MAIN_COMPONENT,
+  // The BeginFrame::frame_time of various frame sources.
+  LATENCY_BEGIN_FRAME_RENDERER_MAIN_COMPONENT,
+  LATENCY_BEGIN_FRAME_RENDERER_INVALIDATE_COMPONENT,
+  LATENCY_BEGIN_FRAME_RENDERER_COMPOSITOR_COMPONENT,
+  LATENCY_BEGIN_FRAME_UI_MAIN_COMPONENT,
+  LATENCY_BEGIN_FRAME_UI_COMPOSITOR_COMPONENT,
+  LATENCY_BEGIN_FRAME_DISPLAY_COMPOSITOR_COMPONENT,
   // ---------------------------NORMAL COMPONENT-------------------------------
   // The original timestamp of the touch event which converts to scroll update.
   INPUT_EVENT_LATENCY_SCROLL_UPDATE_ORIGINAL_COMPONENT,
@@ -111,6 +118,7 @@
   WHEEL,
   TOUCH,
   KEY_PRESS,
+  FRAME,
   OTHER,
   SOURCE_EVENT_TYPE_LAST = OTHER,
 };
@@ -157,6 +165,11 @@
   static bool Verify(const std::vector<LatencyInfo>& latency_info,
                      const char* referring_msg);
 
+  // Adds trace flow events only to LatencyInfos that are being traced.
+  static void TraceIntermediateFlowEvents(
+      const std::vector<LatencyInfo>& latency_info,
+      const char* trace_name);
+
   // Copy LatencyComponents with type |type| from |other| into |this|.
   void CopyLatencyFrom(const LatencyInfo& other, LatencyComponentType type);
 
diff --git a/ui/latency/mojo/latency_info.mojom b/ui/latency/mojo/latency_info.mojom
index cd18a7e..b806ddca 100644
--- a/ui/latency/mojo/latency_info.mojom
+++ b/ui/latency/mojo/latency_info.mojom
@@ -16,6 +16,13 @@
   // scroll processing in impl thread. This is the timestamp when we consider
   // the main thread scroll listener update is begun.
   LATENCY_BEGIN_SCROLL_LISTENER_UPDATE_MAIN_COMPONENT,
+  // The BeginFrame::frame_time of various frame sources.
+  LATENCY_BEGIN_FRAME_RENDERER_MAIN_COMPONENT,
+  LATENCY_BEGIN_FRAME_RENDERER_INVALIDATE_COMPONENT,
+  LATENCY_BEGIN_FRAME_RENDERER_COMPOSITOR_COMPONENT,
+  LATENCY_BEGIN_FRAME_UI_MAIN_COMPONENT,
+  LATENCY_BEGIN_FRAME_UI_COMPOSITOR_COMPONENT,
+  LATENCY_BEGIN_FRAME_DISPLAY_COMPOSITOR_COMPONENT,
   // ---------------------------NORMAL COMPONENT-------------------------------
   // The original timestamp of the touch event which converts to scroll update.
   INPUT_EVENT_LATENCY_SCROLL_UPDATE_ORIGINAL_COMPONENT,
@@ -80,6 +87,7 @@
   WHEEL,
   TOUCH,
   KEY_PRESS,
+  FRAME,
   OTHER,
   SOURCE_EVENT_TYPE_LAST = OTHER,
 };
diff --git a/ui/latency/mojo/latency_info_struct_traits.cc b/ui/latency/mojo/latency_info_struct_traits.cc
index 7c549e7a3..57d1270 100644
--- a/ui/latency/mojo/latency_info_struct_traits.cc
+++ b/ui/latency/mojo/latency_info_struct_traits.cc
@@ -19,6 +19,24 @@
     case ui::LATENCY_BEGIN_SCROLL_LISTENER_UPDATE_MAIN_COMPONENT:
       return ui::mojom::LatencyComponentType::
           LATENCY_BEGIN_SCROLL_LISTENER_UPDATE_MAIN_COMPONENT;
+    case ui::LATENCY_BEGIN_FRAME_RENDERER_MAIN_COMPONENT:
+      return ui::mojom::LatencyComponentType::
+          LATENCY_BEGIN_FRAME_RENDERER_MAIN_COMPONENT;
+    case ui::LATENCY_BEGIN_FRAME_RENDERER_INVALIDATE_COMPONENT:
+      return ui::mojom::LatencyComponentType::
+          LATENCY_BEGIN_FRAME_RENDERER_INVALIDATE_COMPONENT;
+    case ui::LATENCY_BEGIN_FRAME_RENDERER_COMPOSITOR_COMPONENT:
+      return ui::mojom::LatencyComponentType::
+          LATENCY_BEGIN_FRAME_RENDERER_COMPOSITOR_COMPONENT;
+    case ui::LATENCY_BEGIN_FRAME_UI_MAIN_COMPONENT:
+      return ui::mojom::LatencyComponentType::
+          LATENCY_BEGIN_FRAME_UI_MAIN_COMPONENT;
+    case ui::LATENCY_BEGIN_FRAME_UI_COMPOSITOR_COMPONENT:
+      return ui::mojom::LatencyComponentType::
+          LATENCY_BEGIN_FRAME_UI_COMPOSITOR_COMPONENT;
+    case ui::LATENCY_BEGIN_FRAME_DISPLAY_COMPOSITOR_COMPONENT:
+      return ui::mojom::LatencyComponentType::
+          LATENCY_BEGIN_FRAME_DISPLAY_COMPOSITOR_COMPONENT;
     case ui::INPUT_EVENT_LATENCY_SCROLL_UPDATE_ORIGINAL_COMPONENT:
       return ui::mojom::LatencyComponentType::
           INPUT_EVENT_LATENCY_SCROLL_UPDATE_ORIGINAL_COMPONENT;
@@ -92,6 +110,23 @@
         LATENCY_BEGIN_SCROLL_LISTENER_UPDATE_MAIN_COMPONENT:
       return ui::LATENCY_BEGIN_SCROLL_LISTENER_UPDATE_MAIN_COMPONENT;
     case ui::mojom::LatencyComponentType::
+        LATENCY_BEGIN_FRAME_RENDERER_MAIN_COMPONENT:
+      return ui::LATENCY_BEGIN_FRAME_RENDERER_MAIN_COMPONENT;
+    case ui::mojom::LatencyComponentType::
+        LATENCY_BEGIN_FRAME_RENDERER_INVALIDATE_COMPONENT:
+      return ui::LATENCY_BEGIN_FRAME_RENDERER_INVALIDATE_COMPONENT;
+    case ui::mojom::LatencyComponentType::
+        LATENCY_BEGIN_FRAME_RENDERER_COMPOSITOR_COMPONENT:
+      return ui::LATENCY_BEGIN_FRAME_RENDERER_COMPOSITOR_COMPONENT;
+    case ui::mojom::LatencyComponentType::LATENCY_BEGIN_FRAME_UI_MAIN_COMPONENT:
+      return ui::LATENCY_BEGIN_FRAME_UI_MAIN_COMPONENT;
+    case ui::mojom::LatencyComponentType::
+        LATENCY_BEGIN_FRAME_UI_COMPOSITOR_COMPONENT:
+      return ui::LATENCY_BEGIN_FRAME_UI_COMPOSITOR_COMPONENT;
+    case ui::mojom::LatencyComponentType::
+        LATENCY_BEGIN_FRAME_DISPLAY_COMPOSITOR_COMPONENT:
+      return ui::LATENCY_BEGIN_FRAME_DISPLAY_COMPOSITOR_COMPONENT;
+    case ui::mojom::LatencyComponentType::
         INPUT_EVENT_LATENCY_SCROLL_UPDATE_ORIGINAL_COMPONENT:
       return ui::INPUT_EVENT_LATENCY_SCROLL_UPDATE_ORIGINAL_COMPONENT;
     case ui::mojom::LatencyComponentType::
@@ -162,6 +197,8 @@
       return ui::mojom::SourceEventType::TOUCH;
     case ui::KEY_PRESS:
       return ui::mojom::SourceEventType::KEY_PRESS;
+    case ui::FRAME:
+      return ui::mojom::SourceEventType::FRAME;
     case ui::OTHER:
       return ui::mojom::SourceEventType::OTHER;
   }
@@ -179,6 +216,8 @@
       return ui::TOUCH;
     case ui::mojom::SourceEventType::KEY_PRESS:
       return ui::KEY_PRESS;
+    case ui::mojom::SourceEventType::FRAME:
+      return ui::FRAME;
     case ui::mojom::SourceEventType::OTHER:
       return ui::OTHER;
   }
diff --git a/ui/message_center/fake_message_center.cc b/ui/message_center/fake_message_center.cc
index 0d507fc..b3a492bc 100644
--- a/ui/message_center/fake_message_center.cc
+++ b/ui/message_center/fake_message_center.cc
@@ -102,6 +102,8 @@
 
 void FakeMessageCenter::ClickOnSettingsButton(const std::string& id) {}
 
+void FakeMessageCenter::DisableNotification(const std::string& id) {}
+
 void FakeMessageCenter::MarkSinglePopupAsShown(const std::string& id,
                                                bool mark_notification_as_read) {
 }
diff --git a/ui/message_center/fake_message_center.h b/ui/message_center/fake_message_center.h
index 2a89a1e..5548cf1 100644
--- a/ui/message_center/fake_message_center.h
+++ b/ui/message_center/fake_message_center.h
@@ -55,6 +55,7 @@
                                           int button_index,
                                           const base::string16& reply) override;
   void ClickOnSettingsButton(const std::string& id) override;
+  void DisableNotification(const std::string& id) override;
   void MarkSinglePopupAsShown(const std::string& id,
                               bool mark_notification_as_read) override;
   void DisplayedNotification(const std::string& id,
diff --git a/ui/message_center/message_center.h b/ui/message_center/message_center.h
index fab8ce5..9269871 100644
--- a/ui/message_center/message_center.h
+++ b/ui/message_center/message_center.h
@@ -144,6 +144,11 @@
   // center observers.
   virtual void ClickOnSettingsButton(const std::string& id) = 0;
 
+  // This should be called by UI classes when a user select from notification
+  // inline settings to disable notifications from the same origin of the
+  // notification.
+  virtual void DisableNotification(const std::string& id) = 0;
+
   // This should be called by UI classes after a visible notification popup
   // closes, indicating that the notification has been shown to the user.
   // |mark_notification_as_read|, if false, will unset the read bit on a
diff --git a/ui/message_center/message_center_impl.cc b/ui/message_center/message_center_impl.cc
index 80e10ed0c..cccfea1 100644
--- a/ui/message_center/message_center_impl.cc
+++ b/ui/message_center/message_center_impl.cc
@@ -541,6 +541,17 @@
   }
 }
 
+void MessageCenterImpl::DisableNotification(const std::string& id) {
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+  DCHECK(!iterating_);
+  Notification* notification = notification_list_->GetNotificationById(id);
+
+  if (notification && notification->delegate()) {
+    notification->delegate()->DisableNotification();
+    RemoveNotificationsForNotifierId(notification->notifier_id());
+  }
+}
+
 void MessageCenterImpl::MarkSinglePopupAsShown(const std::string& id,
                                                bool mark_notification_as_read) {
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
diff --git a/ui/message_center/message_center_impl.h b/ui/message_center/message_center_impl.h
index be7cbb87..3d2981b0 100644
--- a/ui/message_center/message_center_impl.h
+++ b/ui/message_center/message_center_impl.h
@@ -73,6 +73,7 @@
                                           int button_index,
                                           const base::string16& reply) override;
   void ClickOnSettingsButton(const std::string& id) override;
+  void DisableNotification(const std::string& id) override;
   void MarkSinglePopupAsShown(const std::string& id,
                               bool mark_notification_as_read) override;
   void DisplayedNotification(const std::string& id,
diff --git a/ui/message_center/views/notification_menu_model.cc b/ui/message_center/views/notification_menu_model.cc
index de4219d..28249fa 100644
--- a/ui/message_center/views/notification_menu_model.cc
+++ b/ui/message_center/views/notification_menu_model.cc
@@ -24,7 +24,7 @@
 }  // namespace
 
 NotificationMenuModel::NotificationMenuModel(const Notification& notification)
-    : ui::SimpleMenuModel(this), notification_(notification) {
+    : ui::SimpleMenuModel(this), notification_id_(notification.id()) {
   DCHECK(!notification.display_source().empty());
   AddItem(kTogglePermissionCommand,
           l10n_util::GetStringFUTF16(IDS_MESSAGE_CENTER_NOTIFIER_DISABLE,
@@ -53,13 +53,10 @@
 void NotificationMenuModel::ExecuteCommand(int command_id, int event_flags) {
   switch (command_id) {
     case kTogglePermissionCommand:
-      notification_.delegate()->DisableNotification();
-      // TODO(estade): this will not close other open notifications from the
-      // same site.
-      MessageCenter::Get()->RemoveNotification(notification_.id(), false);
+      MessageCenter::Get()->DisableNotification(notification_id_);
       break;
     case kShowSettingsCommand:
-      MessageCenter::Get()->ClickOnSettingsButton(notification_.id());
+      MessageCenter::Get()->ClickOnSettingsButton(notification_id_);
       break;
     default:
       NOTREACHED();
diff --git a/ui/message_center/views/notification_menu_model.h b/ui/message_center/views/notification_menu_model.h
index 324b989..867f1f1 100644
--- a/ui/message_center/views/notification_menu_model.h
+++ b/ui/message_center/views/notification_menu_model.h
@@ -26,7 +26,7 @@
   void ExecuteCommand(int command_id, int event_flags) override;
 
  private:
-  Notification notification_;
+  const std::string notification_id_;
   DISALLOW_COPY_AND_ASSIGN(NotificationMenuModel);
 };
 
diff --git a/ui/ozone/platform/x11/x11_cursor_factory_ozone.cc b/ui/ozone/platform/x11/x11_cursor_factory_ozone.cc
index 0354647..580ae4ae 100644
--- a/ui/ozone/platform/x11/x11_cursor_factory_ozone.cc
+++ b/ui/ozone/platform/x11/x11_cursor_factory_ozone.cc
@@ -49,6 +49,12 @@
   // resulting SkBitmap is empty and X crashes when creating a zero size cursor
   // image. Return invisible cursor here instead.
   if (bitmap.drawsNothing()) {
+    // The result of |invisible_cursor_| is owned by the caller, and will be
+    // Unref()ed by code far away. (Usually in web_cursor.cc in content, among
+    // others.) If we don't manually add another reference before we cast this
+    // to a void*, we can end up with |invisible_cursor_| being freed out from
+    // under us.
+    invisible_cursor_->AddRef();
     return ToPlatformCursor(invisible_cursor_.get());
   }